Heroic Robotics / SD600A

Fork of SD600A by Heroic Robotics

SD600A.cpp

Committer:
heroic
Date:
2012-10-10
Revision:
14:908869a15f5a
Parent:
13:875eb971d6c6
Child:
15:2733cd5f34e4

File content as of revision 14:908869a15f5a:

// Mbed library to control SD600A-based RGB LED Strips
// Partially based on work (c) 2011 Jelmer Tiete
//
// Ported from Arduino by
// Jas Strong <jasmine@electronpusher.org>
/*****************************************************************************/

#include "rtos.h"
#include "LedStrip.h"
#include "SD600A.h"

void SD600A::idle_function(void) {
    dat = 0;
    clk = !clk;
}

SD600A::SD600A(PinName dataPin, PinName clockPin, int n) :
    dat(dataPin),
    clk(clockPin)  {
    // Allocate 3 bytes per pixel:
    numLEDs = n;
    if ((pixels = (uint8_t *)malloc(numLEDs * 3))) {
        memset(pixels, 0, numLEDs * 3); // Init to RGB 'off' state
    }
    idletoggle.attach_us(this, &SD600A::idle_function, IDLE_INTERVAL);
}

/*
 *  Soft SPI clock-out implementation (CPOL = 1, CPHA = 0).
 *  Certainly not the fastest in the world but it'll do.
 *  Gets about 3.6 MHz;  could get several times as much
 *  using the bitbands directly  - jas.
 */
 
void SD600A::write(uint8_t byte) {
    clk=1;
    for (int i=0; i<8; i++) {
        dat = !!(byte & (1 << (7 - i)));
    
        clk = 0;
       // dat = (byte & 0x80);
        #ifdef DELAY_PERIOD
        wait_us(DELAY_PERIOD);
        #endif
        clk = 1;
        #ifdef DELAY_PERIOD
        wait_us(DELAY_PERIOD);
        #endif
        //byte <<= 1;
    }
}

void SD600A::begin(void) {
    // Issue initial latch to 'wake up' strip (latch length varies w/numLEDs)
    idletoggle.detach();
    // set the Ticker interrupt to the highest possible priority; reduce ethernet irq priority
    NVIC_SetPriority(TIMER3_IRQn, 0);
    NVIC_SetPriority(ENET_IRQn, 1);
    for (int i=0; i<numLEDs; i++) {
        write(0);
        write(0);
        write(0);
    }
    writeguard();
    idletoggle.attach_us(this, &SD600A::idle_function, IDLE_INTERVAL);
}

uint16_t SD600A::numPixels(void) {
    return numLEDs;
}

void SD600A::writeguard(void) {
    // generate a 25-bit word of ones
    clk = 1;
    #ifdef DELAY_PERIOD
    wait_us(DELAY_PERIOD);
    #endif
    dat = 1;
    #ifdef DELAY_PERIOD
    wait_us(DELAY_PERIOD);
    #endif
    clk = 0;
    #ifdef DELAY_PERIOD
    wait_us(DELAY_PERIOD);
    #endif
    write(0xff);
    write(0xff);
    write(0xff);
}

void SD600A::blank(void) {
    memset(pixels, 0x00, numLEDs * 3);
}

void SD600A::show(void) {
    uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
    idletoggle.detach();

    for (i=nl3; i; i-- ) {
        write(pixels[i]);
    }

    // Write guard word
    writeguard();
    idletoggle.attach_us(this, &SD600A::idle_function, IDLE_INTERVAL);
}

// Convert R,G,B to combined 32-bit color
uint32_t SD600A::Color(uint8_t r, uint8_t g, uint8_t b) {
    // Take 23 bits of the value and append them end to end
    // We cannot drive all ones or it will make the part latch if the previous word ended in one!
    return 0xfefefe & ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
}

// store the rgb component in our array
void SD600A::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  ] = b & 0xfe;
    pixels[n*3+1] = g & 0xfe;
    pixels[n*3+2] = r & 0xfe;
}

void SD600A::setPixelR(uint16_t n, uint8_t r) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed

    pixels[n*3+2] = r & 0xfe;
}

void SD600A::setPixelG(uint16_t n, uint8_t g) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed

    pixels[n*3+1] = g & 0xfe;
}

void SD600A::setPixelB(uint16_t n, uint8_t b) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed

    pixels[n*3] = b & 0xfe;
}

void SD600A::setPixelColor(uint16_t n, uint32_t c) {
    if (n >= numLEDs) return; // '>=' because arrays are 0-indexed

    pixels[n*3  ] = (c >> 16) & 0xfe;
    pixels[n*3+1] = (c >>  8) & 0xfe;
    pixels[n*3+2] =  c        & 0xfe;
}