Heroic Robotics / SD600A

Fork of SD600A by Heroic Robotics

SD600A.cpp

Committer:
heroic
Date:
2012-10-08
Revision:
7:cda3ca93e5a1
Parent:
6:aacceefab2ea
Child:
8:78ba2917bfd9

File content as of revision 7:cda3ca93e5a1:

// 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 idle_function(void const *argument) {
    while (1) {
        ((SD600A *)argument)->threadlock.lock();
        ((SD600A *)argument)->dat = 0;
        ((SD600A *)argument)->clk = 1;
        ((SD600A *)argument)->clk = 0;
        ((SD600A *)argument)->clk = 1;
        ((SD600A *)argument)->clk = 0;
        ((SD600A *)argument)->threadlock.unlock();
        Thread::yield();
    }
}

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

/*
 *  Soft SPI clock-out implementation (CPOL = 0, 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) {
    for (int i=0; i<8; i++) {
        clk = 0;
        dat = (byte & 0x80);
        clk = 1;
        byte <<= 1;
    }
    clk = 0;
}

void SD600A::begin(void) {

    // Issue initial latch to 'wake up' strip (latch length varies w/numLEDs)
    threadlock.lock();
    for (int i=0; i<numLEDs; i++) {
        write(0);
        write(0);
        write(0);
    }
    writeguard();
    threadlock.unlock();
}

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

void SD600A::writeguard(void) {
    // generate a 25-bit word of zeros
    clk = 1;
    dat = 0;
    clk = 0;
    write(0x00);
    write(0x00);
    write(0x00);
}

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

// This is how data is pushed to the strip.  Unfortunately, the company
// that makes the chip didnt release the  protocol document or you need
// to sign an NDA or something stupid like that, but we reverse engineered
// this from a strip controller and it seems to work very nicely!
void SD600A::show(void) {
    uint16_t i, nl3 = numLEDs * 3; // 3 bytes per LED
    threadlock.lock();

    for (i=0; i<nl3; i++ ) {
        write(pixels[i]);
    }

    // Write guard word
    writeguard();
    threadlock.unlock();
}

// 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 zero!
    return 0xfffffe & ((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  ] = g & 0xff;
    pixels[n*3+1] = r & 0xff;
    pixels[n*3+2] = b & 0xfe;
}

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

    pixels[n*3+1] = r & 0xff;
}

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

    pixels[n*3] = g & 0xff;
}

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

    pixels[n*3+2] = 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) & 0xff;
    pixels[n*3+1] = (c >>  8) & 0xff;
    pixels[n*3+2] =  c        & 0xfe;
}