modification of Andrew Kirkhams MODDMA code to send packets over Ethernet and using multiple ADC channels
Dependencies: EthernetInterface MODDMA mbed-rtos mbed
main.cpp@0:68a1564919d0, 2014-08-05 (annotated)
- Committer:
- michaelcoe
- Date:
- Tue Aug 05 22:06:11 2014 +0000
- Revision:
- 0:68a1564919d0
Initial Commit
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
michaelcoe | 0:68a1564919d0 | 1 | /*This code is based off of Andy Kirkham's |
michaelcoe | 0:68a1564919d0 | 2 | *work making MODDMA. |
michaelcoe | 0:68a1564919d0 | 3 | *http://mbed.org/users/AjK/code/MODDMA/ |
michaelcoe | 0:68a1564919d0 | 4 | */ |
michaelcoe | 0:68a1564919d0 | 5 | #include "mbed.h" |
michaelcoe | 0:68a1564919d0 | 6 | #include "MODDMA.h" |
michaelcoe | 0:68a1564919d0 | 7 | #include "string.h" |
michaelcoe | 0:68a1564919d0 | 8 | #include "EthernetInterface.h" |
michaelcoe | 0:68a1564919d0 | 9 | |
michaelcoe | 0:68a1564919d0 | 10 | #define NUM_SAMPLES 1024 |
michaelcoe | 0:68a1564919d0 | 11 | #define BYTES_PER_SAMPLE sizeof(uint16_t) / sizeof(char) |
michaelcoe | 0:68a1564919d0 | 12 | #define NUM_CHANNELS 4 |
michaelcoe | 0:68a1564919d0 | 13 | #define SAMPLE_BUFF_LEN NUM_SAMPLES*NUM_CHANNELS |
michaelcoe | 0:68a1564919d0 | 14 | #define SAMPLE_BUFF_BYTES SAMPLE_BUFF_LEN * BYTES_PER_SAMPLE |
michaelcoe | 0:68a1564919d0 | 15 | |
michaelcoe | 0:68a1564919d0 | 16 | DigitalOut led1(LED1); |
michaelcoe | 0:68a1564919d0 | 17 | DigitalOut led2(LED2); |
michaelcoe | 0:68a1564919d0 | 18 | |
michaelcoe | 0:68a1564919d0 | 19 | MODDMA dma; |
michaelcoe | 0:68a1564919d0 | 20 | const int BROADCAST_PORT = 58083; |
michaelcoe | 0:68a1564919d0 | 21 | |
michaelcoe | 0:68a1564919d0 | 22 | // ISR set's this when transfer complete. |
michaelcoe | 0:68a1564919d0 | 23 | bool dmaTransferComplete = false; |
michaelcoe | 0:68a1564919d0 | 24 | |
michaelcoe | 0:68a1564919d0 | 25 | // Function prototypes for IRQ callbacks. |
michaelcoe | 0:68a1564919d0 | 26 | // See definitions following main() below. |
michaelcoe | 0:68a1564919d0 | 27 | void TC0_callback(void); |
michaelcoe | 0:68a1564919d0 | 28 | void ERR0_callback(void); |
michaelcoe | 0:68a1564919d0 | 29 | |
michaelcoe | 0:68a1564919d0 | 30 | int main() { |
michaelcoe | 0:68a1564919d0 | 31 | //Set up the ethernet to broadcast |
michaelcoe | 0:68a1564919d0 | 32 | EthernetInterface eth; |
michaelcoe | 0:68a1564919d0 | 33 | eth.init(); //Use DHCP |
michaelcoe | 0:68a1564919d0 | 34 | eth.connect(); |
michaelcoe | 0:68a1564919d0 | 35 | |
michaelcoe | 0:68a1564919d0 | 36 | UDPSocket sock; |
michaelcoe | 0:68a1564919d0 | 37 | sock.init(); |
michaelcoe | 0:68a1564919d0 | 38 | sock.set_broadcasting(); |
michaelcoe | 0:68a1564919d0 | 39 | |
michaelcoe | 0:68a1564919d0 | 40 | Endpoint broadcast; |
michaelcoe | 0:68a1564919d0 | 41 | broadcast.set_address("255.255.255.255", BROADCAST_PORT); |
michaelcoe | 0:68a1564919d0 | 42 | |
michaelcoe | 0:68a1564919d0 | 43 | // Create a buffer to hold the ADC samples and clear it. |
michaelcoe | 0:68a1564919d0 | 44 | // Note, we are going to sample two ADC inputs so they |
michaelcoe | 0:68a1564919d0 | 45 | // end up in this buffer "interleaved". So you will want |
michaelcoe | 0:68a1564919d0 | 46 | // a buffer twice this size to a real life given sample |
michaelcoe | 0:68a1564919d0 | 47 | // frequency. See the printf() output for details. |
michaelcoe | 0:68a1564919d0 | 48 | uint16_t adcInputBuffer[SAMPLE_BUFF_LEN]; |
michaelcoe | 0:68a1564919d0 | 49 | memset(adcInputBuffer, 0, SAMPLE_BUFF_BYTES); |
michaelcoe | 0:68a1564919d0 | 50 | |
michaelcoe | 0:68a1564919d0 | 51 | // We use the ADC irq to trigger DMA and the manual says |
michaelcoe | 0:68a1564919d0 | 52 | // that in this case the NVIC for ADC must be disabled. |
michaelcoe | 0:68a1564919d0 | 53 | NVIC_DisableIRQ(ADC_IRQn); |
michaelcoe | 0:68a1564919d0 | 54 | |
michaelcoe | 0:68a1564919d0 | 55 | // Power up the ADC and set PCLK |
michaelcoe | 0:68a1564919d0 | 56 | LPC_SC->PCONP |= (1UL << 12); |
michaelcoe | 0:68a1564919d0 | 57 | LPC_SC->PCLKSEL0 &= ~(3UL << 24); // PCLK = CCLK/4 96M/4 = 24MHz |
michaelcoe | 0:68a1564919d0 | 58 | |
michaelcoe | 0:68a1564919d0 | 59 | // Enable the ADC, 12MHz, ADC0.0 & .1 |
michaelcoe | 0:68a1564919d0 | 60 | //LPC_ADC->ADCR = (1UL << 21) | (1UL << 8) | (3UL << 0); |
michaelcoe | 0:68a1564919d0 | 61 | LPC_ADC->ADCR = (1UL << 21) | (1UL << 8) | (15UL << 0); |
michaelcoe | 0:68a1564919d0 | 62 | |
michaelcoe | 0:68a1564919d0 | 63 | // Set the pin functions to ADC |
michaelcoe | 0:68a1564919d0 | 64 | LPC_PINCON->PINSEL1 &= ~(3UL << 14); /* P0.23, Mbed p15. */ |
michaelcoe | 0:68a1564919d0 | 65 | LPC_PINCON->PINSEL1 |= (1UL << 14); |
michaelcoe | 0:68a1564919d0 | 66 | LPC_PINCON->PINSEL1 &= ~(3UL << 16); /* P0.24, Mbed p16. */ |
michaelcoe | 0:68a1564919d0 | 67 | LPC_PINCON->PINSEL1 |= (1UL << 16); |
michaelcoe | 0:68a1564919d0 | 68 | LPC_PINCON->PINSEL1 &= ~(3UL << 18); /* P0.25, Mbed p17. */ |
michaelcoe | 0:68a1564919d0 | 69 | LPC_PINCON->PINSEL1 |= (1UL << 18); |
michaelcoe | 0:68a1564919d0 | 70 | LPC_PINCON->PINSEL1 &= ~(3UL << 20); /* P0.26, Mbed p18. */ |
michaelcoe | 0:68a1564919d0 | 71 | LPC_PINCON->PINSEL1 |= (1UL << 20); |
michaelcoe | 0:68a1564919d0 | 72 | |
michaelcoe | 0:68a1564919d0 | 73 | // Prepare an ADC configuration. |
michaelcoe | 0:68a1564919d0 | 74 | MODDMA_Config *conf = new MODDMA_Config; |
michaelcoe | 0:68a1564919d0 | 75 | conf |
michaelcoe | 0:68a1564919d0 | 76 | ->channelNum ( MODDMA::Channel_0 ) |
michaelcoe | 0:68a1564919d0 | 77 | ->srcMemAddr ( 0 ) |
michaelcoe | 0:68a1564919d0 | 78 | ->dstMemAddr ( (uint32_t)adcInputBuffer ) //NOT a dereference, just storing a 32bit pointer value as int |
michaelcoe | 0:68a1564919d0 | 79 | ->transferSize ( SAMPLE_BUFF_LEN ) |
michaelcoe | 0:68a1564919d0 | 80 | ->transferType ( MODDMA::p2m ) |
michaelcoe | 0:68a1564919d0 | 81 | ->transferWidth ( MODDMA::word ) |
michaelcoe | 0:68a1564919d0 | 82 | ->srcConn ( MODDMA::ADC ) |
michaelcoe | 0:68a1564919d0 | 83 | ->dstConn ( 0 ) |
michaelcoe | 0:68a1564919d0 | 84 | ->dmaLLI ( 0 ) |
michaelcoe | 0:68a1564919d0 | 85 | ->attach_tc ( &TC0_callback ) |
michaelcoe | 0:68a1564919d0 | 86 | ->attach_err ( &ERR0_callback ) |
michaelcoe | 0:68a1564919d0 | 87 | ; // end conf. |
michaelcoe | 0:68a1564919d0 | 88 | |
michaelcoe | 0:68a1564919d0 | 89 | // Prepare configuration. |
michaelcoe | 0:68a1564919d0 | 90 | dma.Setup( conf ); |
michaelcoe | 0:68a1564919d0 | 91 | |
michaelcoe | 0:68a1564919d0 | 92 | // Enable configuration. |
michaelcoe | 0:68a1564919d0 | 93 | dma.Enable( conf ); |
michaelcoe | 0:68a1564919d0 | 94 | |
michaelcoe | 0:68a1564919d0 | 95 | // Enable ADC irq flag (to DMA). |
michaelcoe | 0:68a1564919d0 | 96 | // Note, don't set the individual flags, |
michaelcoe | 0:68a1564919d0 | 97 | // just set the global flag. |
michaelcoe | 0:68a1564919d0 | 98 | LPC_ADC->ADINTEN = 0x100; |
michaelcoe | 0:68a1564919d0 | 99 | |
michaelcoe | 0:68a1564919d0 | 100 | // Enable burst mode on inputs 0 and 1. |
michaelcoe | 0:68a1564919d0 | 101 | LPC_ADC->ADCR |= (1UL << 16); |
michaelcoe | 0:68a1564919d0 | 102 | |
michaelcoe | 0:68a1564919d0 | 103 | |
michaelcoe | 0:68a1564919d0 | 104 | while (1) { |
michaelcoe | 0:68a1564919d0 | 105 | // When transfer complete do this block. |
michaelcoe | 0:68a1564919d0 | 106 | if (dmaTransferComplete) { |
michaelcoe | 0:68a1564919d0 | 107 | delete conf; // No memory leaks, delete the configuration. |
michaelcoe | 0:68a1564919d0 | 108 | dmaTransferComplete = false; |
michaelcoe | 0:68a1564919d0 | 109 | } |
michaelcoe | 0:68a1564919d0 | 110 | //sock.sendTo(broadcast, out_buffer, sizeof(out_buffer)); |
michaelcoe | 0:68a1564919d0 | 111 | sock.sendTo(broadcast, (char*)adcInputBuffer, SAMPLE_BUFF_BYTES); |
michaelcoe | 0:68a1564919d0 | 112 | wait(0.25); |
michaelcoe | 0:68a1564919d0 | 113 | } |
michaelcoe | 0:68a1564919d0 | 114 | } |
michaelcoe | 0:68a1564919d0 | 115 | |
michaelcoe | 0:68a1564919d0 | 116 | // Configuration callback on TC |
michaelcoe | 0:68a1564919d0 | 117 | void TC0_callback(void) { |
michaelcoe | 0:68a1564919d0 | 118 | |
michaelcoe | 0:68a1564919d0 | 119 | MODDMA_Config *config = dma.getConfig(); |
michaelcoe | 0:68a1564919d0 | 120 | |
michaelcoe | 0:68a1564919d0 | 121 | // Disbale burst mode and switch off the IRQ flag. |
michaelcoe | 0:68a1564919d0 | 122 | LPC_ADC->ADCR &= ~(1UL << 16); |
michaelcoe | 0:68a1564919d0 | 123 | LPC_ADC->ADINTEN = 0; |
michaelcoe | 0:68a1564919d0 | 124 | |
michaelcoe | 0:68a1564919d0 | 125 | // Finish the DMA cycle by shutting down the channel. |
michaelcoe | 0:68a1564919d0 | 126 | dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum()); |
michaelcoe | 0:68a1564919d0 | 127 | dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); |
michaelcoe | 0:68a1564919d0 | 128 | |
michaelcoe | 0:68a1564919d0 | 129 | // Tell main() while(1) loop to print the results. |
michaelcoe | 0:68a1564919d0 | 130 | dmaTransferComplete = true; |
michaelcoe | 0:68a1564919d0 | 131 | |
michaelcoe | 0:68a1564919d0 | 132 | // Switch on LED2 to show transfer complete. |
michaelcoe | 0:68a1564919d0 | 133 | led2 = 1; |
michaelcoe | 0:68a1564919d0 | 134 | |
michaelcoe | 0:68a1564919d0 | 135 | // Clear DMA IRQ flags. |
michaelcoe | 0:68a1564919d0 | 136 | if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); |
michaelcoe | 0:68a1564919d0 | 137 | if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq(); |
michaelcoe | 0:68a1564919d0 | 138 | } |
michaelcoe | 0:68a1564919d0 | 139 | |
michaelcoe | 0:68a1564919d0 | 140 | // Configuration callback on Error |
michaelcoe | 0:68a1564919d0 | 141 | void ERR0_callback(void) { |
michaelcoe | 0:68a1564919d0 | 142 | // Switch off burst conversions. |
michaelcoe | 0:68a1564919d0 | 143 | LPC_ADC->ADCR |= ~(1UL << 16); |
michaelcoe | 0:68a1564919d0 | 144 | LPC_ADC->ADINTEN = 0; |
michaelcoe | 0:68a1564919d0 | 145 | error("Oh no! My Mbed EXPLODED! :( Only kidding, go find the problem"); |
michaelcoe | 0:68a1564919d0 | 146 | } |