DSP program for the Surfboard hardware (PCB to be open sourced) http://www.avbotz.com/ourauv/electrical/signal-processing/
Dependencies: MODDMA SimpleIOMacros mbed-dsp mbed
dma.cpp@1:f69ec4c889ff, 2013-08-02 (annotated)
- Committer:
- avbotz
- Date:
- Fri Aug 02 02:25:12 2013 +0000
- Revision:
- 1:f69ec4c889ff
- Parent:
- 0:2381a319fc35
Initial commit. Not working. MODDMA makes DMA setup slow, and the mbed SPI peripheral corrupts data sometimes. I will write my own SPI and DMA classes and see how it goes.
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
avbotz | 0:2381a319fc35 | 1 | #include "dma.h" |
avbotz | 0:2381a319fc35 | 2 | |
avbotz | 0:2381a319fc35 | 3 | DigitalOut test5(p5); |
avbotz | 0:2381a319fc35 | 4 | DigitalOut test6(p6); |
avbotz | 0:2381a319fc35 | 5 | DigitalOut test(p7); |
avbotz | 0:2381a319fc35 | 6 | |
avbotz | 0:2381a319fc35 | 7 | char buf[NUM_CHANNELS * 3]; // 3 bytes per sample |
avbotz | 0:2381a319fc35 | 8 | char dummy_buf[sizeof(buf) / sizeof(char)]; |
avbotz | 0:2381a319fc35 | 9 | |
avbotz | 0:2381a319fc35 | 10 | SPI ads1274(/*mosi, unconnected*/ p11, /*miso, dout*/ p12, /*sclk*/ p13); |
avbotz | 0:2381a319fc35 | 11 | |
avbotz | 0:2381a319fc35 | 12 | MODDMA_Cache dma; |
avbotz | 0:2381a319fc35 | 13 | MODDMA_Config* dma_conf = new MODDMA_Config; |
avbotz | 0:2381a319fc35 | 14 | MODDMA_Config* sclk_dummy_conf = new MODDMA_Config; |
avbotz | 0:2381a319fc35 | 15 | |
avbotz | 0:2381a319fc35 | 16 | //q15_t parsed[2][NUM_CHANNELS][BLOCK_SIZE]; |
avbotz | 0:2381a319fc35 | 17 | char parsed[2][NUM_CHANNELS][BLOCK_SIZE][3]; |
avbotz | 0:2381a319fc35 | 18 | |
avbotz | 0:2381a319fc35 | 19 | |
avbotz | 0:2381a319fc35 | 20 | char write_block = 0; |
avbotz | 0:2381a319fc35 | 21 | int buf_index = 0; |
avbotz | 0:2381a319fc35 | 22 | unsigned int read_blocks = 0; |
avbotz | 0:2381a319fc35 | 23 | |
avbotz | 0:2381a319fc35 | 24 | extern bool fresh_data; |
avbotz | 0:2381a319fc35 | 25 | |
avbotz | 0:2381a319fc35 | 26 | int setup_dma() |
avbotz | 0:2381a319fc35 | 27 | { |
avbotz | 0:2381a319fc35 | 28 | ads1274.frequency(12 * 1000000); // Theoretical minimum 9.6MHz |
avbotz | 0:2381a319fc35 | 29 | ads1274.format(8, 3); // clock polarity cpol = 1; clock phase cpha = 1 |
avbotz | 0:2381a319fc35 | 30 | |
avbotz | 0:2381a319fc35 | 31 | memset(buf, 0, sizeof(buf)); |
avbotz | 0:2381a319fc35 | 32 | // stolen from moddma example 2 |
avbotz | 0:2381a319fc35 | 33 | dma_conf |
avbotz | 0:2381a319fc35 | 34 | ->channelNum ( MODDMA::Channel_1 ) |
avbotz | 0:2381a319fc35 | 35 | ->srcMemAddr ( 0 ) |
avbotz | 0:2381a319fc35 | 36 | ->dstMemAddr ( (uint32_t)buf ) |
avbotz | 0:2381a319fc35 | 37 | ->transferSize ( sizeof(buf) ) |
avbotz | 0:2381a319fc35 | 38 | ->transferType ( MODDMA::p2m ) |
avbotz | 0:2381a319fc35 | 39 | ->transferWidth ( MODDMA::word ) // 4 bytes at a time |
avbotz | 0:2381a319fc35 | 40 | ->srcConn ( MODDMA::SSP0_Rx ) // SSP0: pins 11-13. SSP1: pins 5-7. |
avbotz | 0:2381a319fc35 | 41 | ->dstConn ( 0 ) |
avbotz | 0:2381a319fc35 | 42 | ->dmaLLI ( 0 ) |
avbotz | 0:2381a319fc35 | 43 | ->attach_tc ( &parse_data ) // called when transferSize is reached |
avbotz | 0:2381a319fc35 | 44 | ->attach_err ( &dma_error_cb ) |
avbotz | 0:2381a319fc35 | 45 | ; |
avbotz | 0:2381a319fc35 | 46 | dma.Setup(dma_conf); |
avbotz | 0:2381a319fc35 | 47 | |
avbotz | 0:2381a319fc35 | 48 | memset(dummy_buf, 0x55, sizeof(dummy_buf)); |
avbotz | 0:2381a319fc35 | 49 | dummy_buf[sizeof(dummy_buf) - 1] = '\0'; |
avbotz | 0:2381a319fc35 | 50 | sclk_dummy_conf |
avbotz | 0:2381a319fc35 | 51 | ->channelNum ( MODDMA::Channel_0 ) // make this one the highest priority DMA |
avbotz | 0:2381a319fc35 | 52 | ->srcMemAddr ( (uint32_t)dummy_buf ) |
avbotz | 0:2381a319fc35 | 53 | ->dstMemAddr ( 0 ) |
avbotz | 0:2381a319fc35 | 54 | ->transferSize ( sizeof(dummy_buf) ) |
avbotz | 0:2381a319fc35 | 55 | ->transferType ( MODDMA::m2p ) |
avbotz | 0:2381a319fc35 | 56 | ->transferWidth ( MODDMA::word ) // 4 bytes at a time |
avbotz | 0:2381a319fc35 | 57 | ->srcConn ( 0 ) |
avbotz | 0:2381a319fc35 | 58 | ->dstConn ( MODDMA::SSP0_Tx ) // SSP0: pins 11-13. SSP1: pins 5-7. |
avbotz | 0:2381a319fc35 | 59 | ->dmaLLI ( 0 ) |
avbotz | 0:2381a319fc35 | 60 | ->attach_tc ( 0 ) // called when transferSize is reached |
avbotz | 0:2381a319fc35 | 61 | ->attach_err ( &dma_error_cb ) |
avbotz | 0:2381a319fc35 | 62 | ; |
avbotz | 0:2381a319fc35 | 63 | dma.Setup(sclk_dummy_conf); |
avbotz | 0:2381a319fc35 | 64 | |
avbotz | 0:2381a319fc35 | 65 | return 0; // success |
avbotz | 0:2381a319fc35 | 66 | } |
avbotz | 0:2381a319fc35 | 67 | |
avbotz | 0:2381a319fc35 | 68 | void teardown_dma() |
avbotz | 0:2381a319fc35 | 69 | { |
avbotz | 0:2381a319fc35 | 70 | |
avbotz | 0:2381a319fc35 | 71 | } |
avbotz | 0:2381a319fc35 | 72 | |
avbotz | 0:2381a319fc35 | 73 | // Stolen from Andy Kirkham http://mbed.org/forum/mbed/topic/2326/ |
avbotz | 0:2381a319fc35 | 74 | |
avbotz | 0:2381a319fc35 | 75 | // "One last piece of advice...You have to be careful when you start doing 'neat things' directly with the peripherals to ensure you don't break other things that previously worked fine." |
avbotz | 0:2381a319fc35 | 76 | // -- ANdy Kirkham, aka Daniel Naito in 20 years |
avbotz | 0:2381a319fc35 | 77 | /** EINT3_IRQHandler |
avbotz | 0:2381a319fc35 | 78 | */ |
avbotz | 0:2381a319fc35 | 79 | extern "C" void EINT3_IRQHandler() |
avbotz | 0:2381a319fc35 | 80 | { |
avbotz | 0:2381a319fc35 | 81 | |
avbotz | 0:2381a319fc35 | 82 | // The "event" is connected to pin p8 which is LPC1768 P0_6 so lets trap |
avbotz | 0:2381a319fc35 | 83 | // that and ignore all other GPIO interrupts. |
avbotz | 0:2381a319fc35 | 84 | // Test for IRQ on Port0. |
avbotz | 0:2381a319fc35 | 85 | if (LPC_GPIOINT->IntStatus & 0x1) |
avbotz | 0:2381a319fc35 | 86 | { |
avbotz | 0:2381a319fc35 | 87 | // If P0_6/p8 rises, call get_data() |
avbotz | 0:2381a319fc35 | 88 | // The "R" means we're looking for the rising edge |
avbotz | 0:2381a319fc35 | 89 | if (LPC_GPIOINT->IO0IntStatR & (1 << 6)) |
avbotz | 0:2381a319fc35 | 90 | { |
avbotz | 0:2381a319fc35 | 91 | // We found what we're looking for |
avbotz | 0:2381a319fc35 | 92 | get_data(); |
avbotz | 0:2381a319fc35 | 93 | } |
avbotz | 0:2381a319fc35 | 94 | } |
avbotz | 0:2381a319fc35 | 95 | |
avbotz | 0:2381a319fc35 | 96 | // Clear all possible GPIO-generated interrupts as they don't concern us. |
avbotz | 0:2381a319fc35 | 97 | // Once we process the interrupt, we wipe out this interrupt and all the others |
avbotz | 0:2381a319fc35 | 98 | //LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); |
avbotz | 0:2381a319fc35 | 99 | //LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF); |
avbotz | 0:2381a319fc35 | 100 | |
avbotz | 0:2381a319fc35 | 101 | // Clear only this interrupt |
avbotz | 0:2381a319fc35 | 102 | LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO0IntStatR & (1 << 6); |
avbotz | 0:2381a319fc35 | 103 | } |
avbotz | 0:2381a319fc35 | 104 | |
avbotz | 0:2381a319fc35 | 105 | void event_irq_init() |
avbotz | 0:2381a319fc35 | 106 | { |
avbotz | 0:2381a319fc35 | 107 | // Use macro to set p8 as an input. |
avbotz | 0:2381a319fc35 | 108 | p8_AS_INPUT; |
avbotz | 0:2381a319fc35 | 109 | // Enable P0_6/p8 for rising edge interrupt generation. |
avbotz | 0:2381a319fc35 | 110 | LPC_GPIOINT->IO0IntEnR |= (1UL << 6); //hope this works |
avbotz | 0:2381a319fc35 | 111 | // Enable the interrupt. |
avbotz | 0:2381a319fc35 | 112 | NVIC_SetVector(EINT3_IRQn, (uint32_t)EINT3_IRQHandler); |
avbotz | 0:2381a319fc35 | 113 | NVIC_EnableIRQ(EINT3_IRQn); |
avbotz | 0:2381a319fc35 | 114 | } |
avbotz | 0:2381a319fc35 | 115 | |
avbotz | 0:2381a319fc35 | 116 | void dma_error_cb() |
avbotz | 0:2381a319fc35 | 117 | { |
avbotz | 0:2381a319fc35 | 118 | |
avbotz | 0:2381a319fc35 | 119 | } |
avbotz | 0:2381a319fc35 | 120 | |
avbotz | 0:2381a319fc35 | 121 | // 6.80 us |
avbotz | 0:2381a319fc35 | 122 | inline void get_data() |
avbotz | 0:2381a319fc35 | 123 | { |
avbotz | 0:2381a319fc35 | 124 | // Need to wait 4 mbed clock cycles here. Callback overhead (about 1.2 us) is more than enough. |
avbotz | 0:2381a319fc35 | 125 | |
avbotz | 0:2381a319fc35 | 126 | p7_TOGGLE; |
avbotz | 0:2381a319fc35 | 127 | #define USE_RESET |
avbotz | 0:2381a319fc35 | 128 | |
avbotz | 0:2381a319fc35 | 129 | #ifndef USE_RESET |
avbotz | 0:2381a319fc35 | 130 | dma.Setup(dma_conf); |
avbotz | 0:2381a319fc35 | 131 | dma.Setup(sclk_dummy_conf); |
avbotz | 0:2381a319fc35 | 132 | #else |
avbotz | 0:2381a319fc35 | 133 | dma.Reset(dma_conf); |
avbotz | 0:2381a319fc35 | 134 | dma.Reset(sclk_dummy_conf); |
avbotz | 0:2381a319fc35 | 135 | #endif |
avbotz | 0:2381a319fc35 | 136 | |
avbotz | 0:2381a319fc35 | 137 | dma.Enable(sclk_dummy_conf); |
avbotz | 0:2381a319fc35 | 138 | dma.Enable(dma_conf); |
avbotz | 0:2381a319fc35 | 139 | |
avbotz | 0:2381a319fc35 | 140 | // enable ssp0 fifo. Seems to be required for DMA to work. |
avbotz | 0:2381a319fc35 | 141 | LPC_SSP0->DMACR = 0x3; |
avbotz | 0:2381a319fc35 | 142 | //wait_ms(10); |
avbotz | 0:2381a319fc35 | 143 | //fresh_data = true; |
avbotz | 0:2381a319fc35 | 144 | |
avbotz | 0:2381a319fc35 | 145 | /* |
avbotz | 0:2381a319fc35 | 146 | for (int i = 0; i < sizeof(buf)/sizeof(char); i++) |
avbotz | 0:2381a319fc35 | 147 | { |
avbotz | 0:2381a319fc35 | 148 | buf[i] = ads1274.write(0); |
avbotz | 0:2381a319fc35 | 149 | } |
avbotz | 0:2381a319fc35 | 150 | parse_data(); |
avbotz | 0:2381a319fc35 | 151 | */ |
avbotz | 0:2381a319fc35 | 152 | |
avbotz | 0:2381a319fc35 | 153 | if (led2num > TARGET_SPS) |
avbotz | 0:2381a319fc35 | 154 | { |
avbotz | 0:2381a319fc35 | 155 | LED2_TOGGLE; |
avbotz | 0:2381a319fc35 | 156 | led2num = 0; |
avbotz | 0:2381a319fc35 | 157 | } |
avbotz | 0:2381a319fc35 | 158 | else |
avbotz | 0:2381a319fc35 | 159 | { |
avbotz | 0:2381a319fc35 | 160 | led2num++; |
avbotz | 0:2381a319fc35 | 161 | } |
avbotz | 0:2381a319fc35 | 162 | |
avbotz | 0:2381a319fc35 | 163 | p7_TOGGLE; |
avbotz | 0:2381a319fc35 | 164 | } |
avbotz | 0:2381a319fc35 | 165 | |
avbotz | 0:2381a319fc35 | 166 | // 310 ns |
avbotz | 0:2381a319fc35 | 167 | inline void parse_data() |
avbotz | 0:2381a319fc35 | 168 | { |
avbotz | 0:2381a319fc35 | 169 | p5_TOGGLE; |
avbotz | 0:2381a319fc35 | 170 | // Assumes a little-endian CPU. Intel is always little-endian. ARM is |
avbotz | 0:2381a319fc35 | 171 | // configurable, but the LPC1768 is little-endian. |
avbotz | 0:2381a319fc35 | 172 | // We flip the byte order because the ADS1274 is big-endian. Also throw out |
avbotz | 0:2381a319fc35 | 173 | // the least significant byte for speed. |
avbotz | 0:2381a319fc35 | 174 | /* |
avbotz | 0:2381a319fc35 | 175 | parsed[write_block][0][buf_index] = buf[ 5] | (((uint16_t)buf[4]) << 8); |
avbotz | 0:2381a319fc35 | 176 | parsed[write_block][1][buf_index] = buf[ 9] | (((uint16_t)buf[8]) << 8); |
avbotz | 0:2381a319fc35 | 177 | parsed[write_block][2][buf_index] = buf[ 12] | (((uint16_t)buf[11]) << 8); |
avbotz | 0:2381a319fc35 | 178 | parsed[write_block][3][buf_index] = buf[ 15] | (((uint16_t)buf[14]) << 8); |
avbotz | 0:2381a319fc35 | 179 | */ |
avbotz | 0:2381a319fc35 | 180 | for (int i = 0; i < NUM_CHANNELS; i++) |
avbotz | 0:2381a319fc35 | 181 | { |
avbotz | 0:2381a319fc35 | 182 | for (int j = 0; j < 3; j++) |
avbotz | 0:2381a319fc35 | 183 | { |
avbotz | 0:2381a319fc35 | 184 | parsed[write_block][i][buf_index][j] = buf[3*i+j]; |
avbotz | 0:2381a319fc35 | 185 | } |
avbotz | 0:2381a319fc35 | 186 | } |
avbotz | 0:2381a319fc35 | 187 | |
avbotz | 0:2381a319fc35 | 188 | |
avbotz | 0:2381a319fc35 | 189 | /* |
avbotz | 0:2381a319fc35 | 190 | if (buf_index > 100) |
avbotz | 0:2381a319fc35 | 191 | { |
avbotz | 0:2381a319fc35 | 192 | for (int i = 0; i < NUM_CHANNELS*3; i++) |
avbotz | 0:2381a319fc35 | 193 | { |
avbotz | 0:2381a319fc35 | 194 | submarine.printf("%02x ", buf[i]); |
avbotz | 0:2381a319fc35 | 195 | } |
avbotz | 0:2381a319fc35 | 196 | while (true); |
avbotz | 0:2381a319fc35 | 197 | } |
avbotz | 0:2381a319fc35 | 198 | */ |
avbotz | 0:2381a319fc35 | 199 | bool valid = (parsed[write_block][0][buf_index] != 0); |
avbotz | 0:2381a319fc35 | 200 | |
avbotz | 0:2381a319fc35 | 201 | buf_index++; |
avbotz | 0:2381a319fc35 | 202 | |
avbotz | 0:2381a319fc35 | 203 | if (buf_index == BLOCK_SIZE) |
avbotz | 0:2381a319fc35 | 204 | { |
avbotz | 0:2381a319fc35 | 205 | fresh_data = true; |
avbotz | 0:2381a319fc35 | 206 | // Switch to the other half of this buffer. |
avbotz | 0:2381a319fc35 | 207 | write_block ^= 0x1; //toggle the last bit |
avbotz | 0:2381a319fc35 | 208 | read_blocks++; |
avbotz | 0:2381a319fc35 | 209 | buf_index = 0; |
avbotz | 0:2381a319fc35 | 210 | } |
avbotz | 0:2381a319fc35 | 211 | if (valid){ |
avbotz | 0:2381a319fc35 | 212 | if (led3num > TARGET_SPS) |
avbotz | 0:2381a319fc35 | 213 | { |
avbotz | 0:2381a319fc35 | 214 | LED3_TOGGLE; |
avbotz | 0:2381a319fc35 | 215 | led3num = 0; |
avbotz | 0:2381a319fc35 | 216 | } |
avbotz | 0:2381a319fc35 | 217 | else |
avbotz | 0:2381a319fc35 | 218 | { |
avbotz | 0:2381a319fc35 | 219 | led3num++; |
avbotz | 0:2381a319fc35 | 220 | }} |
avbotz | 0:2381a319fc35 | 221 | p5_TOGGLE; |
avbotz | 0:2381a319fc35 | 222 | } |