Programming an array of NeoPixels using the GPDMA for maximum performance.

Dependencies:   MODDMA mbed

main.cpp

Committer:
tohu
Date:
2014-12-10
Revision:
5:6981fbf08586
Parent:
4:f2ef03b37a66

File content as of revision 5:6981fbf08586:

#include "mbed.h"
#include "MODDMA.h"

Serial pc(USBTX, USBRX);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

#define IMAGE_SIZE 123

//
// IMAGE AND RENDER BUFFER
//

#if 1
// OK
uint8_t  smiley [IMAGE_SIZE] = {
    0x0,  0xFF, 0x0, 0xFF,  0xFF, 0xFF, 0xFF,  0xFF, 0xFF, 0x0,  0xFF, 0x0, 0x0,  0xFF, 0x0, 0xFF, 0xFF, 0xFF, 0x0,  0xFF, 0x0,  0xFF, 0xFF, 0xFF,
    0xFF, 0xFF, 0xFF, 0x3F, 0xBE, 0x0, 0x3F, 0xBE, 0x0, 0xFF, 0xFF, 0xFF, 0x3F, 0xBE, 0x0, 0xFF, 0xFF, 0xFF, 0x3F, 0xBE, 0x0,  0xFF, 0xFF, 0xFF, 
    0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x0, 0x7F, 0x7F, 0x0, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x7F, 0x0, 
    0xFF, 0xFF, 0xFF, 0xBE, 0x3F, 0x0, 0xBE, 0x3F, 0x0, 0xFF, 0xFF, 0xFF, 0xBE, 0x3F, 0x0, 0xFF, 0xFF, 0xFF, 0xBE, 0x3F, 0x0,  0xFF, 0xFF, 0xFF, 
    0xFF, 0x0,  0x0, 0xFF, 0xFF,  0xFF, 0xFF, 0xFF,  0xFF, 0xFF, 0x0,  0x0, 0xFF, 0x0,  0x0, 0xFF, 0xFF, 0xFF, 0xFF, 0x0,  0x0,  0xFF, 0xFF, 0xFF,
    0x0,  0x0, 0x0
    };
#endif

uint8_t *renderBuffer;
#if 0
[IMAGE_SIZE*4];
#endif

void copyImageToRender(uint8_t *image, uint8_t *buffer, size_t len);

//
// DMA STUFF
//

MODDMA dma;
MODDMA_Config *dmaConfig;

void TC_callback(void);
void ERR_callback(void);

bool flgCompleted = false;
bool flgFailed = false;

SPI spi(p11, NC, p13);

Timer dmaTimer;

int main()
{
    // Setup the serial port to print out results.
    pc.baud(115200);

    led1 = false;
    led2 = false;
    led3 = false;
    led4 = false;

    renderBuffer = (uint8_t *) malloc(IMAGE_SIZE*4);

    // Set up the image to render
    copyImageToRender(smiley, renderBuffer, IMAGE_SIZE);

    spi.format(8,3); // spi.format(8,0) har fungerat!!
    spi.frequency(3000000); // 3200000 har fungerat!!!

    // TODO: THIS COULD POSSIBLY FUCK UP THE AMOUNT OF DATA MOVED TO THE SSP IN EACH BURST
    // Configure the DMA
    dmaConfig = new MODDMA_Config;
    dmaConfig
    ->channelNum    ( MODDMA::Channel_0 )
    ->srcMemAddr    ( (uint32_t) renderBuffer )
    ->dstMemAddr    ( MODDMA::SSP0_Tx )
    ->transferSize  ( IMAGE_SIZE*4 )
    ->transferType  ( MODDMA::m2p )
    ->dstConn       ( MODDMA::SSP0_Tx )
    ->attach_tc     ( &TC_callback )
    ->attach_err    ( &ERR_callback )
    ;
    LPC_SSP0->DMACR = (1<<1)|(1<<0); // TX,RXDMAE

    if(!dma.Prepare(dmaConfig)) {
        error("Failed to prepare dma configuration!");
    }

    dmaTimer.start();

    dma.Enable(dmaConfig);

    while(1) {

        if(!flgCompleted) {
            led1 = !led1;
        } else {
            pc.printf("Time spend in dma: %d us\n", dmaTimer.read_us());


            led2 = !led2;
        }
        if(flgFailed) {
            wait(0.1);
            led2 = !led2;
        }

        uint8_t in[2] = { 0x99, 0x33 };
        uint8_t out[8];

        copyImageToRender(in, out, 2);

        pc.printf("RENDER white: %02x %02x %02x %02x\n", out[0],out[1],out[2],out[3]);
        pc.printf("RENDER black: %02x %02x %02x %02x\n", out[4],out[5],out[6],out[7]);

        wait(1);
        led4 = !led4;
    }
}

void TC_callback(void)
{
    LPC_SSP0->CR1 = 0; // Diable the SSP0    ?

    // Just show sending buffer0 complete.
    led3 = !led3;

    // Get configuration pointer.
    MODDMA_Config *config = dma.getConfig();

    // Finish the DMA cycle by shutting down the channel.
    dma.haltAndWaitChannelComplete( (MODDMA::CHANNELS)config->channelNum());
    dma.Disable( (MODDMA::CHANNELS)config->channelNum() );

    dmaTimer.stop();

    flgCompleted = true;

    // Clear DMA IRQ flags.
    if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq();
    if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq();
}

void ERR_callback(void)
{
    error("Something failed!!!!");

    flgFailed = true;
}

void copyImageToRender(uint8_t *image, uint8_t *buffer, size_t len)
{
    Timer timer;

    timer.start();

    int outIndex;

    for(int i = 0; i < len; i++) {

        outIndex = i*4;

#if 0
        // 11001100
        buffer[outIndex] = 0xCC | image[i]&128>>2 | image[i]&64>>5;

        // 11001100
        buffer[outIndex+1] = 0xCC | image[i]&32 | image[i]&16>>3;

        // 11001100
        buffer[outIndex+2] = 0xCC |image[i]&8<<2 | image[i]&4>>1;

        // 11001100
        buffer[outIndex+3] = 0xCC |image[i]&2<<4 | image[i]&1<<1;
#else
        // 10001000
        buffer[outIndex++] = 0x88 | (image[i]&128)>>1 | (image[i]&64)>>4;

        // 10001000
        buffer[outIndex++] = 0x88 | (image[i]&32)<<1 | (image[i]&16)>>2;

        // 10001000
        buffer[outIndex++] = 0x88 |(image[i]&8)<<3 | (image[i]&4);

        // 10001000
        buffer[outIndex] = 0x88 | (image[i]&2)<<5 | (image[i]&1)<<2;
#endif
    }

    timer.stop();

    pc.printf("Time spend copying image: %d us\n", timer.read_us());
}