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

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;
+}