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
- Committer:
- avbotz
- Date:
- 2013-08-02
- Revision:
- 1:f69ec4c889ff
- Parent:
- 0:2381a319fc35
File content as of revision 1:f69ec4c889ff:
#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; }