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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dma.cpp Source File

dma.cpp

00001 #include "dma.h"
00002 
00003 DigitalOut test5(p5);
00004 DigitalOut test6(p6);
00005 DigitalOut test(p7);
00006 
00007 char buf[NUM_CHANNELS * 3]; // 3 bytes per sample
00008 char dummy_buf[sizeof(buf) / sizeof(char)];
00009 
00010 SPI ads1274(/*mosi, unconnected*/ p11, /*miso, dout*/ p12, /*sclk*/ p13);
00011 
00012 MODDMA_Cache dma;
00013 MODDMA_Config* dma_conf = new MODDMA_Config;
00014 MODDMA_Config* sclk_dummy_conf = new MODDMA_Config;
00015 
00016 //q15_t parsed[2][NUM_CHANNELS][BLOCK_SIZE];
00017 char parsed[2][NUM_CHANNELS][BLOCK_SIZE][3];
00018 
00019 
00020 char write_block = 0;
00021 int buf_index = 0;
00022 unsigned int read_blocks = 0;
00023 
00024 extern bool fresh_data;
00025 
00026 int setup_dma()
00027 {
00028     ads1274.frequency(12 * 1000000); // Theoretical minimum 9.6MHz
00029     ads1274.format(8, 3); // clock polarity cpol = 1; clock phase cpha = 1
00030     
00031     memset(buf, 0, sizeof(buf));
00032     // stolen from moddma example 2
00033     dma_conf
00034      ->channelNum    ( MODDMA::Channel_1 )
00035      ->srcMemAddr    ( 0 )
00036      ->dstMemAddr    ( (uint32_t)buf )
00037      ->transferSize  ( sizeof(buf) )
00038      ->transferType  ( MODDMA::p2m )
00039      ->transferWidth ( MODDMA::word )   // 4 bytes at a time
00040      ->srcConn       ( MODDMA::SSP0_Rx ) // SSP0: pins 11-13. SSP1: pins 5-7.
00041      ->dstConn       ( 0 )
00042      ->dmaLLI        ( 0 )
00043      ->attach_tc     ( &parse_data ) // called when transferSize is reached
00044      ->attach_err    ( &dma_error_cb )
00045     ;
00046     dma.Setup(dma_conf);
00047     
00048     memset(dummy_buf, 0x55, sizeof(dummy_buf));
00049     dummy_buf[sizeof(dummy_buf) - 1] = '\0';
00050     sclk_dummy_conf
00051      ->channelNum    ( MODDMA::Channel_0 ) // make this one the highest priority DMA
00052      ->srcMemAddr    ( (uint32_t)dummy_buf )
00053      ->dstMemAddr    ( 0 )
00054      ->transferSize  ( sizeof(dummy_buf) )
00055      ->transferType  ( MODDMA::m2p )
00056      ->transferWidth ( MODDMA::word )   // 4 bytes at a time
00057      ->srcConn       ( 0 )
00058      ->dstConn       ( MODDMA::SSP0_Tx ) // SSP0: pins 11-13. SSP1: pins 5-7.
00059      ->dmaLLI        ( 0 )
00060      ->attach_tc     ( 0 ) // called when transferSize is reached
00061      ->attach_err    ( &dma_error_cb )
00062     ;
00063     dma.Setup(sclk_dummy_conf);
00064     
00065     return 0;   // success
00066 }
00067 
00068 void teardown_dma()
00069 {
00070     
00071 }
00072 
00073 // Stolen from Andy Kirkham http://mbed.org/forum/mbed/topic/2326/
00074 
00075 // "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."
00076 // -- ANdy Kirkham, aka Daniel Naito in 20 years
00077 /** EINT3_IRQHandler
00078  */
00079 extern "C" void EINT3_IRQHandler()
00080 {
00081 
00082     // The "event" is connected to pin p8 which is LPC1768 P0_6 so lets trap
00083     // that and ignore all other GPIO interrupts.    
00084     // Test for IRQ on Port0.
00085     if (LPC_GPIOINT->IntStatus & 0x1)
00086     {
00087         // If P0_6/p8 rises, call get_data()
00088         // The "R" means we're looking for the rising edge
00089         if (LPC_GPIOINT->IO0IntStatR & (1 << 6))
00090         {
00091             // We found what we're looking for
00092             get_data();
00093         }
00094     }
00095     
00096     // Clear all possible GPIO-generated interrupts as they don't concern us.
00097     // Once we process the interrupt, we wipe out this interrupt and all the others
00098     //LPC_GPIOINT->IO2IntClr = (LPC_GPIOINT->IO2IntStatR | LPC_GPIOINT->IO2IntStatF);
00099     //LPC_GPIOINT->IO0IntClr = (LPC_GPIOINT->IO0IntStatR | LPC_GPIOINT->IO0IntStatF);
00100     
00101     // Clear only this interrupt
00102     LPC_GPIOINT->IO0IntClr = LPC_GPIOINT->IO0IntStatR & (1 << 6);
00103 }
00104 
00105 void event_irq_init()
00106 {
00107     // Use macro to set p8 as an input.
00108     p8_AS_INPUT;
00109     // Enable P0_6/p8 for rising edge interrupt generation.
00110     LPC_GPIOINT->IO0IntEnR |= (1UL << 6); //hope this works
00111     // Enable the interrupt.
00112     NVIC_SetVector(EINT3_IRQn, (uint32_t)EINT3_IRQHandler);
00113     NVIC_EnableIRQ(EINT3_IRQn);
00114 }
00115 
00116 void dma_error_cb()
00117 {
00118     
00119 }
00120 
00121 // 6.80 us
00122 inline void get_data()
00123 {
00124     // Need to wait 4 mbed clock cycles here. Callback overhead (about 1.2 us) is more than enough.
00125     
00126     p7_TOGGLE;
00127     #define USE_RESET
00128     
00129     #ifndef USE_RESET
00130     dma.Setup(dma_conf);
00131     dma.Setup(sclk_dummy_conf);
00132     #else
00133     dma.Reset(dma_conf);
00134     dma.Reset(sclk_dummy_conf);
00135     #endif
00136     
00137     dma.Enable(sclk_dummy_conf);
00138     dma.Enable(dma_conf);
00139     
00140     // enable ssp0 fifo. Seems to be required for DMA to work.
00141     LPC_SSP0->DMACR = 0x3;
00142     //wait_ms(10);
00143     //fresh_data = true;
00144     
00145     /*
00146     for (int i = 0; i < sizeof(buf)/sizeof(char); i++)
00147     {
00148         buf[i] = ads1274.write(0);
00149     }
00150     parse_data();
00151     */
00152     
00153     if (led2num > TARGET_SPS)
00154     {
00155         LED2_TOGGLE;
00156         led2num = 0;
00157     }
00158     else
00159     {
00160         led2num++;
00161     }
00162     
00163     p7_TOGGLE;
00164 }
00165 
00166 // 310 ns
00167 inline void parse_data()
00168 {
00169     p5_TOGGLE;
00170     // Assumes a little-endian CPU. Intel is always little-endian. ARM is
00171     // configurable, but the LPC1768 is little-endian.
00172     // We flip the byte order because the ADS1274 is big-endian. Also throw out
00173     // the least significant byte for speed.
00174     /*
00175     parsed[write_block][0][buf_index] = buf[ 5] | (((uint16_t)buf[4]) << 8);
00176     parsed[write_block][1][buf_index] = buf[ 9] | (((uint16_t)buf[8]) << 8);
00177     parsed[write_block][2][buf_index] = buf[ 12] | (((uint16_t)buf[11]) << 8);
00178     parsed[write_block][3][buf_index] = buf[ 15] | (((uint16_t)buf[14]) << 8);
00179     */
00180     for (int i = 0; i < NUM_CHANNELS; i++)
00181     {
00182         for (int j = 0; j < 3; j++)
00183         {
00184             parsed[write_block][i][buf_index][j] = buf[3*i+j];
00185         }
00186     }
00187     
00188     
00189     /*
00190     if (buf_index > 100)
00191     {
00192         for (int i = 0; i < NUM_CHANNELS*3; i++)
00193         {
00194             submarine.printf("%02x ", buf[i]);
00195         }
00196         while (true);
00197     }
00198     */
00199     bool valid = (parsed[write_block][0][buf_index] != 0);
00200     
00201     buf_index++;
00202     
00203     if (buf_index == BLOCK_SIZE)
00204     {
00205         fresh_data = true;
00206         // Switch to the other half of this buffer.
00207         write_block ^= 0x1; //toggle the last bit
00208         read_blocks++;
00209         buf_index = 0;
00210     }
00211     if (valid){
00212     if (led3num > TARGET_SPS)
00213     {
00214         LED3_TOGGLE;
00215         led3num = 0;
00216     }
00217     else
00218     {
00219         led3num++;
00220     }}
00221     p5_TOGGLE;
00222 }