Subversion Repositories Projects

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1882 - 1
#include "SPI.h"
2
#include "LPD8806_kopterlight_ext.h"
3
 
4
// Arduino library to control LPD8806-based RGB LED Strips
5
// (c) Adafruit industries
6
// MIT license
7
 
8
/*****************************************************************************/
9
// This library has been modified to fix the red and green issue with the strips
10
// used by "MikroKopter-Forum" Users, because the design of these stripes is 
11
// different and red and green are inverted !!
12
// Additionally this library has been modified and extended to provide light 
13
// sequence requirements on multikopter for up to 8 rigger and user selected
14
// number of LEDs per rigger to calculate offset on strip.
15
//
16
//  http://http://www.mikrokopter.de/ucwiki/KopterLight-EXT
17
//                          Magomora 
18
/*****************************************************************************/
19
 
20
// Constructor for use with hardware SPI (specific clock/data pins):
21
LPD8806::LPD8806(uint16_t n, uint8_t rig) {
22
  pixels = NULL;
23
  begun  = false;
24
  updateLength(n,rig);
25
  updatePins();
26
  rigger = rig; // Number of rigger
27
}
28
 
29
// via Michael Vogt/neophob: empty constructor is used when strip length
30
// isn't known at compile-time; situations where program config might be
31
// read from internal flash memory or an SD card, or arrive via serial
32
// command.  If using this constructor, MUST follow up with updateLength()
33
// and updatePins() to establish the strip length and output pins!
34
LPD8806::LPD8806(void) {
35
  numLEDs = 0;
36
  pixels  = NULL;
37
  begun   = false;
38
  updatePins(); // Must assume hardware SPI until pins are set
39
}
40
 
41
// Activate hard/soft SPI as appropriate:
42
void LPD8806::begin(void) {
43
   startSPI();
44
//   if(hardwareSPI == true) startSPI();
45
//   else                    startBitbang();
46
  begun = true;
47
}
48
 
49
// Change pin assignments post-constructor, switching to hardware SPI:
50
void LPD8806::updatePins(void) {
51
  hardwareSPI = true;
52
  datapin     = clkpin = 0;
53
  // If begin() was previously invoked, init the SPI hardware now:
54
  if(begun == true) startSPI();
55
  // Otherwise, SPI is NOT initted until begin() is explicitly called.
56
 
57
  // Note: any prior clock/data pin directions are left as-is and are
58
  // NOT restored as inputs!
59
}
60
 
61
 
62
// Enable SPI hardware and set up protocol details:
63
void LPD8806::startSPI(void) {
64
  SPI.begin();
65
  SPI.setBitOrder(MSBFIRST);
66
  SPI.setDataMode(SPI_MODE0);
67
  SPI.setClockDivider(SPI_CLOCK_DIV2);  // 8 MHz
68
  // SPI bus is run at 2MHz.  Although the LPD8806 should, in theory,
69
  // work up to 20MHz, the unshielded wiring from the Arduino is more
70
  // susceptible to interference.  Experiment and see what you get.
71
 
72
  SPDR = 0; // 'Prime' the SPI bus with initial latch (no wait)
73
}
74
 
75
// Change strip length (see notes with empty constructor, above):
76
void LPD8806::updateLength(uint16_t n, uint8_t rig) {
77
  if(pixels != NULL) free(pixels); // Free existing data (if any)
78
  numLEDs = n;
79
  n      *= 3; // 3 bytes per pixel
80
  if(NULL != (pixels = (uint8_t *)malloc(n + 1))) { // Alloc new data
81
    memset(pixels, 0x80, n); // Init to RGB 'off' state
82
    pixels[n]    = 0;        // Last byte is always zero for latch
83
  } else numLEDs = 0;        // else malloc failed
84
  // 'begun' state does not change -- pins retain prior modes
85
  rigger = rig; // Number of rigger
86
}
87
 
88
// This is how data is pushed to the strip.  Unfortunately, the company
89
// that makes the chip didnt release the protocol document or you need
90
// to sign an NDA or something stupid like that, but we reverse engineered
91
// this from a strip controller and it seems to work very nicely!
92
void LPD8806::show(void) {
93
  uint16_t i, n3 = numLEDs * 3 + 1; // 3 bytes per LED + 1 for latch
94
 
95
  // write 24 bits per pixel
96
    for (i=0; i<n3; i++ ) {
97
      while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
98
      SPDR = pixels[i];           // Issue new byte
99
    }
100
      while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
101
      SPDR = 0;           // Issue new byte
102
      while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
103
      SPDR = 0;           // Issue new byte
104
      while(!(SPSR & (1<<SPIF))); // Wait for prior byte out
105
      SPDR = 0;           // Issue new byte
106
}
107
 
108
// Convert separate R,G,B into combined 32-bit GRB color:
109
uint32_t LPD8806::Color(byte g, byte r, byte b) {
110
  return 0x808080 | ((uint32_t)g << 16) | ((uint32_t)r << 8) | (uint32_t)b;
111
}
112
 
113
// Set pixel color from separate 7-bit R, G, B components:
114
// Only on selected rigger
115
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) {
116
  int i;
117
  int pix;
118
  uint16_t z;
119
 
120
// Select rigger to set LEDs
121
  for (i=1; i<=rigger; i++){
122
  if (i == 1 && r1 == 1){
123
      z = ((numLEDs/rigger)*1)+n-(numLEDs/rigger);
124
      pix = 1;
125
     }    
126
  if (i == 2 && r2 == 1){
127
      z = ((numLEDs/rigger)*2)+n-(numLEDs/rigger);
128
      pix = 1;
129
     }    
130
  if (i == 3 && r3 == 1){
131
      z = ((numLEDs/rigger)*3)+n-(numLEDs/rigger);
132
      pix = 1;
133
     }    
134
  if (i == 4 && r4 == 1){
135
      z = ((numLEDs/rigger)*4)+(n-(numLEDs/rigger));
136
      pix = 1;
137
     }    
138
  if (i == 5 && r5 == 1){
139
      z = ((numLEDs/rigger)*5)+n-(numLEDs/rigger);
140
      pix = 1;
141
     }    
142
  if (i == 6 && r6 == 1){
143
      z = ((numLEDs/rigger)*6)+n-(numLEDs/rigger);
144
      pix = 1;
145
     }    
146
  if (i == 7 && r7 == 1){
147
      z = ((numLEDs/rigger)*7)+n-(numLEDs/rigger);
148
      pix = 1;
149
     }    
150
  if (i == 8 && r8 == 1){
151
      z = ((numLEDs/rigger)*8)+n-(numLEDs/rigger);
152
      pix = 1;
153
     }    
154
   if((pix == 1) && (z < numLEDs)) { // Arrays are 0-indexed, thus NOT '<='
155
     uint8_t *p = &pixels[z * 3];
156
     *p++ = g | 0x80; // LPD8806 color order is GRB,
157
     *p++ = r | 0x80; // not the more common RGB,
158
     *p++ = b | 0x80; // so the order here is intentional; don't "fix"
159
   }
160
      pix = 0;
161
  }
162
}
163
 
164
// Set pixel color from 'packed' 32-bit RGB value:
165
// Only on selected rigger's
166
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) {
167
  int i;
168
  int pix;
169
  uint16_t z;
170
 
171
// Select rigger to set LEDs
172
  for (i=1; i<=rigger; i++){
173
  if (i == 1 && r1 == 1){
174
      z = ((numLEDs/rigger)*1)+n-(numLEDs/rigger);
175
      pix = 1;
176
     }    
177
  if (i == 2 && r2 == 1){
178
      z = ((numLEDs/rigger)*2)+n-(numLEDs/rigger);
179
      pix = 1;
180
     }    
181
  if (i == 3 && r3 == 1){
182
      z = ((numLEDs/rigger)*3)+n-(numLEDs/rigger);
183
      pix = 1;
184
     }    
185
  if (i == 4 && r4 == 1){
186
      z = ((numLEDs/rigger)*4)+n-(numLEDs/rigger);
187
      pix = 1;
188
     }    
189
  if (i == 5 && r5 == 1){
190
      z = ((numLEDs/rigger)*5)+n-(numLEDs/rigger);
191
      pix = 1;
192
     }    
193
  if (i == 6 && r6 == 1){
194
      z = ((numLEDs/rigger)*6)+n-(numLEDs/rigger);
195
      pix = 1;
196
     }    
197
  if (i == 7 && r7 == 1){
198
      z = ((numLEDs/rigger)*7)+n-(numLEDs/rigger);
199
      pix = 1;
200
     }    
201
  if (i == 8 && r8 == 1){
202
      z = ((numLEDs/rigger)*8)+n-(numLEDs/rigger);
203
      pix = 1;
204
     }    
205
   if((pix == 1) && (z < numLEDs)) { // Arrays are 0-indexed, thus NOT '<='
206
    uint8_t *p = &pixels[z * 3];
207
    *p++ = (c >> 16) | 0x80;
208
    *p++ = (c >>  8) | 0x80;
209
    *p++ =  c        | 0x80;
210
   }
211
      pix = 0;
212
  }
213
 
214
}
215