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