Subversion Repositories Projects

Compare Revisions

Ignore whitespace Rev 1881 → Rev 1882

/Digital_RGB_LED_Stripes/tags/KopterLightEXT_1_00/lib/LPD8806_kopterlight_EXT.cpp
0,0 → 1,215
#include "SPI.h"
#include "LPD8806_kopterlight_ext.h"
 
// Arduino library to control LPD8806-based RGB LED Strips
// (c) Adafruit industries
// MIT license
 
/*****************************************************************************/
// This library has been modified to fix the red and green issue with the strips
// used by "MikroKopter-Forum" Users, because the design of these stripes is
// different and red and green are inverted !!
// Additionally this library has been modified and extended to provide light
// sequence requirements on multikopter for up to 8 rigger and user selected
// number of LEDs per rigger to calculate offset on strip.
//
// http://http://www.mikrokopter.de/ucwiki/KopterLight-EXT
// Magomora
/*****************************************************************************/
 
// Constructor for use with hardware SPI (specific clock/data pins):
LPD8806::LPD8806(uint16_t n, uint8_t rig) {
pixels = NULL;
begun = false;
updateLength(n,rig);
updatePins();
rigger = rig; // Number of rigger
}
 
// via Michael Vogt/neophob: empty constructor is used when strip length
// isn't known at compile-time; situations where program config might be
// read from internal flash memory or an SD card, or arrive via serial
// command. If using this constructor, MUST follow up with updateLength()
// and updatePins() to establish the strip length and output pins!
LPD8806::LPD8806(void) {
numLEDs = 0;
pixels = NULL;
begun = false;
updatePins(); // Must assume hardware SPI until pins are set
}
 
// Activate hard/soft SPI as appropriate:
void LPD8806::begin(void) {
startSPI();
// if(hardwareSPI == true) startSPI();
// else startBitbang();
begun = true;
}
 
// Change pin assignments post-constructor, switching to hardware SPI:
void LPD8806::updatePins(void) {
hardwareSPI = true;
datapin = clkpin = 0;
// If begin() was previously invoked, init the SPI hardware now:
if(begun == true) startSPI();
// Otherwise, SPI is NOT initted until begin() is explicitly called.
 
// Note: any prior clock/data pin directions are left as-is and are
// NOT restored as inputs!
}
 
 
// Enable SPI hardware and set up protocol details:
void LPD8806::startSPI(void) {
SPI.begin();
SPI.setBitOrder(MSBFIRST);
SPI.setDataMode(SPI_MODE0);
SPI.setClockDivider(SPI_CLOCK_DIV2); // 8 MHz
// SPI bus is run at 2MHz. Although the LPD8806 should, in theory,
// work up to 20MHz, the unshielded wiring from the Arduino is more
// susceptible to interference. Experiment and see what you get.
 
SPDR = 0; // 'Prime' the SPI bus with initial latch (no wait)
}
 
// Change strip length (see notes with empty constructor, above):
void LPD8806::updateLength(uint16_t n, uint8_t rig) {
if(pixels != NULL) free(pixels); // Free existing data (if any)
numLEDs = n;
n *= 3; // 3 bytes per pixel
if(NULL != (pixels = (uint8_t *)malloc(n + 1))) { // Alloc new data
memset(pixels, 0x80, n); // Init to RGB 'off' state
pixels[n] = 0; // Last byte is always zero for latch
} else numLEDs = 0; // else malloc failed
// 'begun' state does not change -- pins retain prior modes
rigger = rig; // Number of rigger
}
 
// 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 LPD8806::show(void) {
uint16_t i, n3 = numLEDs * 3 + 1; // 3 bytes per LED + 1 for latch
// write 24 bits per pixel
for (i=0; i<n3; i++ ) {
while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
SPDR = pixels[i]; // Issue new byte
}
while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
SPDR = 0; // Issue new byte
while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
SPDR = 0; // Issue new byte
while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
SPDR = 0; // Issue new byte
}
 
// Convert separate R,G,B into combined 32-bit GRB color:
uint32_t LPD8806::Color(byte g, byte r, byte b) {
return 0x808080 | ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
}
 
// Set pixel color from separate 7-bit R, G, B components:
// Only on selected rigger
void LPD8806::setPixelColor(uint16_t n, uint8_t g, uint8_t r, uint8_t b, uint8_t r1, uint8_t r2, uint8_t r3, uint8_t r4, uint8_t r5, uint8_t r6, uint8_t r7, uint8_t r8) {
int i;
int pix;
uint16_t z;
 
// Select rigger to set LEDs
for (i=1; i<=rigger; i++){
if (i == 1 && r1 == 1){
z = ((numLEDs/rigger)*1)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 2 && r2 == 1){
z = ((numLEDs/rigger)*2)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 3 && r3 == 1){
z = ((numLEDs/rigger)*3)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 4 && r4 == 1){
z = ((numLEDs/rigger)*4)+(n-(numLEDs/rigger));
pix = 1;
}
if (i == 5 && r5 == 1){
z = ((numLEDs/rigger)*5)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 6 && r6 == 1){
z = ((numLEDs/rigger)*6)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 7 && r7 == 1){
z = ((numLEDs/rigger)*7)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 8 && r8 == 1){
z = ((numLEDs/rigger)*8)+n-(numLEDs/rigger);
pix = 1;
}
if((pix == 1) && (z < numLEDs)) { // Arrays are 0-indexed, thus NOT '<='
uint8_t *p = &pixels[z * 3];
*p++ = g | 0x80; // LPD8806 color order is GRB,
*p++ = r | 0x80; // not the more common RGB,
*p++ = b | 0x80; // so the order here is intentional; don't "fix"
}
pix = 0;
}
}
 
// Set pixel color from 'packed' 32-bit RGB value:
// Only on selected rigger's
void LPD8806::setPixelColor(uint16_t n, uint32_t c, uint8_t r1, uint8_t r2, uint8_t r3, uint8_t r4, uint8_t r5, uint8_t r6, uint8_t r7, uint8_t r8) {
int i;
int pix;
uint16_t z;
 
// Select rigger to set LEDs
for (i=1; i<=rigger; i++){
if (i == 1 && r1 == 1){
z = ((numLEDs/rigger)*1)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 2 && r2 == 1){
z = ((numLEDs/rigger)*2)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 3 && r3 == 1){
z = ((numLEDs/rigger)*3)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 4 && r4 == 1){
z = ((numLEDs/rigger)*4)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 5 && r5 == 1){
z = ((numLEDs/rigger)*5)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 6 && r6 == 1){
z = ((numLEDs/rigger)*6)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 7 && r7 == 1){
z = ((numLEDs/rigger)*7)+n-(numLEDs/rigger);
pix = 1;
}
if (i == 8 && r8 == 1){
z = ((numLEDs/rigger)*8)+n-(numLEDs/rigger);
pix = 1;
}
if((pix == 1) && (z < numLEDs)) { // Arrays are 0-indexed, thus NOT '<='
uint8_t *p = &pixels[z * 3];
*p++ = (c >> 16) | 0x80;
*p++ = (c >> 8) | 0x80;
*p++ = c | 0x80;
}
pix = 0;
}
 
}