DMA-enabled high data rate driver for Heroic Robotics LED strips.
Diff: LPD8806_fast.cpp
- Revision:
- 10:5b3be78ce6bd
- Parent:
- 9:9038105d14bc
--- a/LPD8806_fast.cpp Sun Mar 09 22:34:04 2014 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,216 +0,0 @@ -// Mbed library to control LPD8806-based RGB LED Strips -// (c) 2011 Jelmer Tiete -// This library is ported from the Arduino implementation of Adafruit Industries -// found at: http://github.com/adafruit/LPD8806 -// and their strips: http://www.adafruit.com/products/306 -// Released under the MIT License: http://mbed.org/license/mit -// -// Parameterized and modified to use soft SPI. -// Jas Strong <jasmine@electronpusher.org> -// Then remonstered to use hardware SPI for blast mode. -// -/*****************************************************************************/ - -#include "LedStrip.h" -#include "LPD8806_fast.h" -#include "board_variant.h" - -#include "MODDMA.h" - -#define LATCHNUMBER 32 - -// DMA controller and frequency setting -extern MODDMA dma; -extern int turbo_mode; -extern int current_strip_fill; - -/* - PixelPusher 3 pin names: - - STRIP1C = P2_9, - STRIP1D = P4_29, - STRIP2C = P0_18, - STRIP2D = P2_1, - STRIP3C = P2_6, - STRIP3D = P0_8, - STRIP4C = P2_8, - STRIP4D = P0_7, - STRIP5C = P0_15, - STRIP5D = P2_0, - STRIP6C = P0_17, - STRIP6D = P2_4, - STRIP7C = P2_5, - STRIP7D = P0_9, - STRIP8C = P2_7, - STRIP8D = P0_6, - -*/ - -/* - * STRIP7D is P0[9] which is SSP1 MOSI - * STRIP4D is P0[7] which is SSP1 SCK - * - * STRIP2C is P0[18] which is SSP0 MOSI - * STRIP5C is P0[15] which is SSP0 SCK - */ - - // when the transfer is complete, kill the channel. -void dma_complete_callback() { - MODDMA_Config *config = dma.getConfig(); - dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); - - // clear the IRQ flags - if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); - if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq(); -} - -void dma_err_callback() { - MODDMA_Config *config = dma.getConfig(); - dma.Disable( (MODDMA::CHANNELS)config->channelNum() ); - - // clear the IRQ flags - if (dma.irqType() == MODDMA::TcIrq) dma.clearTcIrq(); - if (dma.irqType() == MODDMA::ErrIrq) dma.clearErrIrq(); -} - -LPD8806_fast::LPD8806_fast(PinName dataPin, PinName clockPin, int n) : - _spi(dataPin, NC, clockPin) - { - // Allocate 3 bytes per pixel plus latch bytes - numLEDs = n; - pixels = (uint8_t *)malloc(numLEDs * 3 + ((numLEDs + LATCHNUMBER-1) / LATCHNUMBER)); - if (pixels) { - memset(pixels, 0x80, numLEDs * 3); // Init to RGB 'off' state - memset(pixels+numLEDs*3, 0x0, (numLEDs + LATCHNUMBER-1) / LATCHNUMBER); // latch data - } - - _spi.format(8,0); - _spi.frequency(turbo_mode*1000000); - - // remember which strip we are - strip_num = current_strip_fill; - - // make a new DMA config - dma_config = new MODDMA_Config; -} - -inline void LPD8806_fast::write(uint8_t byte) { - _spi.write(byte); -} - -/* -inline void LPD8806_fast::write(uint8_t byte) { - for (int i=0; i<8; i++) { - clk = 0; - dat = (byte & 0x80); - clk = 1; - byte <<= 1; - } - clk = 0; -}*/ - -void LPD8806_fast::begin(void) { - - blank(); - show(); - show(); -} - -uint16_t LPD8806_fast::numPixels(void) { - return numLEDs; -} - -void LPD8806_fast::blank(void) { - memset(pixels, 0x80, numLEDs * 3); -} - -// Set up the DMA controller; we only have two SSP peripherals, so only two strips. - -void LPD8806_fast::show(void) { - if (strip_num == 0) { - dma_config -> channelNum (MODDMA::Channel_0) - -> srcMemAddr ( (uint32_t) pixels ) - -> dstMemAddr ( MODDMA::SSP0_Tx ) - -> transferSize (numLEDs * 3 + ((numLEDs + LATCHNUMBER-1) / LATCHNUMBER)) - -> transferType (MODDMA::m2p) - -> dstConn (MODDMA::SSP0_Tx) - -> attach_tc (&dma_complete_callback) - -> attach_err (&dma_err_callback); - LPC_SSP0->DMACR = (1<<1)|(1<<0); // TX,RXDMAE - } else { - dma_config -> channelNum (MODDMA::Channel_1) - -> srcMemAddr ( (uint32_t) pixels ) - -> dstMemAddr ( MODDMA::SSP1_Tx ) - -> transferSize (numLEDs * 3 + ((numLEDs +LATCHNUMBER-1) / LATCHNUMBER)) - -> transferType (MODDMA::m2p) - -> dstConn (MODDMA::SSP1_Tx) - -> attach_tc (&dma_complete_callback) - -> attach_err (&dma_err_callback); - LPC_SSP1->DMACR = (1<<1)|(1<<0); // TX,RXDMAE - } - while (dma.Enabled(dma_config->channelNum())) { - __nop(); - } - dma.Setup(dma_config); - dma.Enable(dma_config); -} - -// LPD8806 is 7-bit, so we shift to normalize to 256 PWM steps. -uint32_t LPD8806_fast::total_luminance(void) { - uint32_t running_total; - running_total = 0; - for (int i=0; i<numLEDs*3; i++) - running_total += ((pixels[i] & 0x7f) <<1); - return running_total; -} - -// Convert R,G,B to combined 32-bit color -uint32_t LPD8806_fast::Color(uint8_t r, uint8_t g, uint8_t b) { - // Take the lowest 7 bits of each value and append them end to end - // We have the top bit set high (its a 'parity-like' bit in the protocol - // and must be set!) - return 0x808080 | ((uint32_t)(g>>1) << 16) | ((uint32_t)(r>>1) << 8) | (uint32_t)(b>>1); -} - -// store the rgb component in our array -void LPD8806_fast::setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b) { - if (n >= numLEDs) return; // '>=' because arrays are 0-indexed - - pixels[n*3 ] = (g>>1) | 0x80; - pixels[n*3+1] = (r>>1) | 0x80; - pixels[n*3+2] = (b>>1) | 0x80; -} - -void LPD8806_fast::setPixelR(uint16_t n, uint8_t r) { - if (n >= numLEDs) return; // '>=' because arrays are 0-indexed - - pixels[n*3+1] = (r>>1) | 0x80; -} - -void LPD8806_fast::setPixelG(uint16_t n, uint8_t g) { - if (n >= numLEDs) return; // '>=' because arrays are 0-indexed - - pixels[n*3] = (g>>1) | 0x80; -} - -void LPD8806_fast::setPixelB(uint16_t n, uint8_t b) { - if (n >= numLEDs) return; // '>=' because arrays are 0-indexed - - pixels[n*3+2] = (b>>1) | 0x80; -} - -// Set all in one function call, assuming GRB ordering -void LPD8806_fast::setPackedPixels(uint8_t * buffer, uint32_t n) { - if (n >= numLEDs) return; - for (int i=0; i<n*3; i++) - buffer[i] = (buffer[i] >> 1) | 0x80; - memcpy(pixels, buffer, (size_t) (n*3)); -} - -void LPD8806_fast::setPixelColor(uint16_t n, uint32_t c) { - if (n >= numLEDs) return; // '>=' because arrays are 0-indexed - - pixels[n*3 ] = (c >> 16) | 0x80; - pixels[n*3+1] = (c >> 8) | 0x80; - pixels[n*3+2] = c | 0x80; -}