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
Diff: dma.cpp
- Revision:
- 0:2381a319fc35
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dma.cpp Fri Aug 02 02:23:36 2013 +0000 @@ -0,0 +1,222 @@ +#include "dma.h" + +DigitalOut test5(p5); +DigitalOut test6(p6); +DigitalOut test(p7); + +char buf[NUM_CHANNELS * 3]; // 3 bytes per sample +char dummy_buf[sizeof(buf) / sizeof(char)]; + +SPI ads1274(/*mosi, unconnected*/ p11, /*miso, dout*/ p12, /*sclk*/ p13); + +MODDMA_Cache dma; +MODDMA_Config* dma_conf = new MODDMA_Config; +MODDMA_Config* sclk_dummy_conf = new MODDMA_Config; + +//q15_t parsed[2][NUM_CHANNELS][BLOCK_SIZE]; +char parsed[2][NUM_CHANNELS][BLOCK_SIZE][3]; + + +char write_block = 0; +int buf_index = 0; +unsigned int read_blocks = 0; + +extern bool fresh_data; + +int setup_dma() +{ + ads1274.frequency(12 * 1000000); // Theoretical minimum 9.6MHz + ads1274.format(8, 3); // clock polarity cpol = 1; clock phase cpha = 1 + + memset(buf, 0, sizeof(buf)); + // stolen from moddma example 2 + dma_conf + ->channelNum ( MODDMA::Channel_1 ) + ->srcMemAddr ( 0 ) + ->dstMemAddr ( (uint32_t)buf ) + ->transferSize ( sizeof(buf) ) + ->transferType ( MODDMA::p2m ) + ->transferWidth ( MODDMA::word ) // 4 bytes at a time + ->srcConn ( MODDMA::SSP0_Rx ) // SSP0: pins 11-13. SSP1: pins 5-7. + ->dstConn ( 0 ) + ->dmaLLI ( 0 ) + ->attach_tc ( &parse_data ) // called when transferSize is reached + ->attach_err ( &dma_error_cb ) + ; + dma.Setup(dma_conf); + + memset(dummy_buf, 0x55, sizeof(dummy_buf)); + dummy_buf[sizeof(dummy_buf) - 1] = '\0'; + sclk_dummy_conf + ->channelNum ( MODDMA::Channel_0 ) // make this one the highest priority DMA + ->srcMemAddr ( (uint32_t)dummy_buf ) + ->dstMemAddr ( 0 ) + ->transferSize ( sizeof(dummy_buf) ) + ->transferType ( MODDMA::m2p ) + ->transferWidth ( MODDMA::word ) // 4 bytes at a time + ->srcConn ( 0 ) + ->dstConn ( MODDMA::SSP0_Tx ) // SSP0: pins 11-13. SSP1: pins 5-7. + ->dmaLLI ( 0 ) + ->attach_tc ( 0 ) // called when transferSize is reached + ->attach_err ( &dma_error_cb ) + ; + dma.Setup(sclk_dummy_conf); + + return 0; // success +} + +void teardown_dma() +{ + +} + +// Stolen from Andy Kirkham http://mbed.org/forum/mbed/topic/2326/ + +// "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." +// -- ANdy Kirkham, aka Daniel Naito in 20 years +/** EINT3_IRQHandler + */ +extern "C" void EINT3_IRQHandler() +{ + + // The "event" is connected to pin p8 which is LPC1768 P0_6 so lets trap + // that and ignore all other GPIO interrupts. + // Test for IRQ on Port0. + if (LPC_GPIOINT->IntStatus & 0x1) + { + // If P0_6/p8 rises, call get_data() + // The "R" means we're looking for the rising edge + if (LPC_GPIOINT->IO0IntStatR & (1 << 6)) + { + // We found what we're looking for + get_data(); + } + } + + // Clear all possible GPIO-generated interrupts as they don't concern us. + // Once we process the interrupt, we wipe out this interrupt and all the others + //LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF); + //LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF); + + // Clear only this interrupt + LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO0IntStatR & (1 << 6); +} + +void event_irq_init() +{ + // Use macro to set p8 as an input. + p8_AS_INPUT; + // Enable P0_6/p8 for rising edge interrupt generation. + LPC_GPIOINT->IO0IntEnR |= (1UL << 6); //hope this works + // Enable the interrupt. + NVIC_SetVector(EINT3_IRQn, (uint32_t)EINT3_IRQHandler); + NVIC_EnableIRQ(EINT3_IRQn); +} + +void dma_error_cb() +{ + +} + +// 6.80 us +inline void get_data() +{ + // Need to wait 4 mbed clock cycles here. Callback overhead (about 1.2 us) is more than enough. + + p7_TOGGLE; + #define USE_RESET + + #ifndef USE_RESET + dma.Setup(dma_conf); + dma.Setup(sclk_dummy_conf); + #else + dma.Reset(dma_conf); + dma.Reset(sclk_dummy_conf); + #endif + + dma.Enable(sclk_dummy_conf); + dma.Enable(dma_conf); + + // enable ssp0 fifo. Seems to be required for DMA to work. + LPC_SSP0->DMACR = 0x3; + //wait_ms(10); + //fresh_data = true; + + /* + for (int i = 0; i < sizeof(buf)/sizeof(char); i++) + { + buf[i] = ads1274.write(0); + } + parse_data(); + */ + + if (led2num > TARGET_SPS) + { + LED2_TOGGLE; + led2num = 0; + } + else + { + led2num++; + } + + p7_TOGGLE; +} + +// 310 ns +inline void parse_data() +{ + p5_TOGGLE; + // Assumes a little-endian CPU. Intel is always little-endian. ARM is + // configurable, but the LPC1768 is little-endian. + // We flip the byte order because the ADS1274 is big-endian. Also throw out + // the least significant byte for speed. + /* + parsed[write_block][0][buf_index] = buf[ 5] | (((uint16_t)buf[4]) << 8); + parsed[write_block][1][buf_index] = buf[ 9] | (((uint16_t)buf[8]) << 8); + parsed[write_block][2][buf_index] = buf[ 12] | (((uint16_t)buf[11]) << 8); + parsed[write_block][3][buf_index] = buf[ 15] | (((uint16_t)buf[14]) << 8); + */ + for (int i = 0; i < NUM_CHANNELS; i++) + { + for (int j = 0; j < 3; j++) + { + parsed[write_block][i][buf_index][j] = buf[3*i+j]; + } + } + + + /* + if (buf_index > 100) + { + for (int i = 0; i < NUM_CHANNELS*3; i++) + { + submarine.printf("%02x ", buf[i]); + } + while (true); + } + */ + bool valid = (parsed[write_block][0][buf_index] != 0); + + buf_index++; + + if (buf_index == BLOCK_SIZE) + { + fresh_data = true; + // Switch to the other half of this buffer. + write_block ^= 0x1; //toggle the last bit + read_blocks++; + buf_index = 0; + } + if (valid){ + if (led3num > TARGET_SPS) + { + LED3_TOGGLE; + led3num = 0; + } + else + { + led3num++; + }} + p5_TOGGLE; +}