60#include "ObjectFLED.h"
63#define MIN(a,b) ((a)<(b)?(a):(b))
67#define MAX(a,b) ((a)>(b)?(a):(b))
70volatile uint32_t framebuffer_index = 0;
71uint8_t* ObjectFLED::frameBuffer;
72uint32_t ObjectFLED::numbytes;
73uint8_t ObjectFLED::numpins;
74uint8_t ObjectFLED::pin_bitnum[NUM_DIGITAL_PINS];
75uint8_t ObjectFLED::pin_offset[NUM_DIGITAL_PINS];
76uint32_t ObjectFLED::bitdata[BYTES_PER_DMA * 64] __attribute__((used, aligned(32)));
77uint32_t ObjectFLED::bitmask[4] __attribute__((used, aligned(32)));
79DMASetting ObjectFLED::dma2next;
80DMAChannel ObjectFLED::dma1;
81DMAChannel ObjectFLED::dma2;
82DMAChannel ObjectFLED::dma3;
83volatile bool dma_first;
86ObjectFLED::ObjectFLED(uint16_t numLEDs,
void *drawBuf, uint8_t color_order, uint8_t numPins, \
87 const uint8_t *pinList, uint8_t serpentine) {
88 serpNumber = serpentine;
91 if (numPins > NUM_DIGITAL_PINS) numPins = NUM_DIGITAL_PINS;
93 stripLen = numLEDs / numpins;
94 memcpy(pinlist, pinList, numpins);
95 if ((params & 0x3F) < 6) {
96 frameBuffer =
new uint8_t[numLEDs * 3];
97 numbytes = stripLen * 3;
100 frameBuffer =
new uint8_t[numLEDs * 4];
101 numbytes = stripLen * 4;
104 numpinsLocal = numPins;
105 frameBufferLocal = frameBuffer;
106 numbytesLocal = numbytes;
110extern "C" void xbar_connect(
unsigned int input,
unsigned int output);
111static volatile uint32_t *standard_gpio_addr(
volatile uint32_t *fastgpio) {
112 return (
volatile uint32_t *)((uint32_t)fastgpio - 0x01E48000);
116void ObjectFLED::begin(
float OCF) {
122void ObjectFLED::begin(
float OCF, uint16_t latchDelay) {
124 LATCH_DELAY = latchDelay;
129void ObjectFLED::begin(
float OCF, uint16_t period, uint16_t t0h, uint16_t t1h, uint16_t latchDelay) {
134 LATCH_DELAY = latchDelay;
142void ObjectFLED::begin(
void) {
143 numpins = numpinsLocal;
145 memset(bitmask, 0,
sizeof(bitmask));
146 for (uint32_t i=0; i < numpins; i++) {
147 uint8_t pin = pinlist[i];
148 if (pin >= NUM_DIGITAL_PINS)
continue;
149 uint8_t bit = digitalPinToBit(pin);
151 uint8_t offset = ((uint32_t)portOutputRegister(pin) - (uint32_t)&GPIO6_DR) >> 14;
152 if (offset > 3)
continue;
154 pin_offset[i] = offset;
155 uint32_t mask = 1 << bit;
156 bitmask[offset] |= mask;
158 *portControlRegister(pin) &= ~0xF9;
159 *portControlRegister(pin) |= ((OUTPUT_PAD_SPEED & 0x3) << 6) | \
160 ((OUTPUT_PAD_DSE & 0x7) << 3);
162 *(&IOMUXC_GPR_GPR26 + offset) &= ~mask;
163 *standard_gpio_addr(portModeRegister(pin)) |= mask;
166 memcpy(bitmaskLocal, bitmask, 16);
167 memcpy(pin_bitnumLocal, pin_bitnum, numpins);
168 memcpy(pin_offsetLocal, pin_offset, numpins);
170 arm_dcache_flush_delete(bitmask,
sizeof(bitmask));
173 comp1load[0] = (uint16_t)((
float)F_BUS_ACTUAL / 1000000000.0 * (float)TH_TL / OC_FACTOR );
174 comp1load[1] = (uint16_t)((
float)F_BUS_ACTUAL / 1000000000.0 * (float)T0H / OC_FACTOR );
175 comp1load[2] = (uint16_t)((
float)F_BUS_ACTUAL / 1000000000.0 * (float)T1H / OC_FACTOR );
177 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
178 TMR4_CSCTRL0 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN;
181 TMR4_COMP10 = comp1load[0];
182 TMR4_CMPLD10 = comp1load[0];
183 TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3);
184 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
187 TMR4_COMP11 = comp1load[1];
188 TMR4_CMPLD11 = comp1load[1];
189 TMR4_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
190 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
193 TMR4_COMP12 = comp1load[2];
194 TMR4_CMPLD12 = comp1load[2];
195 TMR4_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
198 CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
199 xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_DMA_CH_MUX_REQ30);
200 xbar_connect(XBARA1_IN_QTIMER4_TIMER1, XBARA1_OUT_DMA_CH_MUX_REQ31);
201 xbar_connect(XBARA1_IN_QTIMER4_TIMER2, XBARA1_OUT_DMA_CH_MUX_REQ94);
202 XBARA1_CTRL0 = XBARA_CTRL_STS1 | XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1 |
203 XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
204 XBARA1_CTRL1 = XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
208 dma1.TCD->SADDR = bitmask;
212 dma1.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
213 dma1.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
214 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
215 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
217 dma1.TCD->DADDR = &GPIO1_DR_SET;
218 dma1.TCD->DOFF = 16384;
219 dma1.TCD->CITER_ELINKNO = numbytes * 8;
220 dma1.TCD->DLASTSGA = -65536;
221 dma1.TCD->BITER_ELINKNO = numbytes * 8;
222 dma1.TCD->CSR = DMA_TCD_CSR_DREQ;
223 dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);
225 dma2next.TCD->SADDR = bitdata;
226 dma2next.TCD->SOFF = 8;
227 dma2next.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_DSIZE(2);
228 dma2next.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
229 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
230 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
231 dma2next.TCD->SLAST = 0;
232 dma2next.TCD->DADDR = &GPIO1_DR_CLEAR;
233 dma2next.TCD->DOFF = 16384;
234 dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
235 dma2next.TCD->DLASTSGA = (int32_t)(dma2next.TCD);
236 dma2next.TCD->BITER_ELINKNO = BYTES_PER_DMA * 8;
237 dma2next.TCD->CSR = 0;
241 dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_1);
242 dma2.attachInterrupt(isr);
245 dma3.TCD->SADDR = bitmask;
247 dma3.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
248 dma3.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
249 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
250 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
252 dma3.TCD->DADDR = &GPIO1_DR_CLEAR;
253 dma3.TCD->DOFF = 16384;
254 dma3.TCD->CITER_ELINKNO = numbytes * 8;
255 dma3.TCD->DLASTSGA = -65536;
256 dma3.TCD->BITER_ELINKNO = numbytes * 8;
257 dma3.TCD->CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_DONE;
258 dma3.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_2);
266void fillbits(uint32_t *dest,
const uint8_t *pixels,
int n, uint32_t mask) {
268 uint8_t pix = *pixels++;
269 if (!(pix & 0x80)) *dest |= mask;
271 if (!(pix & 0x40)) *dest |= mask;
273 if (!(pix & 0x20)) *dest |= mask;
275 if (!(pix & 0x10)) *dest |= mask;
277 if (!(pix & 0x08)) *dest |= mask;
279 if (!(pix & 0x04)) *dest |= mask;
281 if (!(pix & 0x02)) *dest |= mask;
283 if (!(pix & 0x01)) *dest |= mask;
289void ObjectFLED::genFrameBuffer(uint32_t serp) {
293 switch (params & 0x3F) {
295 for (uint16_t i = 0; i < (numbytes * numpins); i += 4) {
296 uint8_t minRGB = MIN(*((uint8_t*)drawBuffer + j) * rLevel / 65025, \
297 *((uint8_t*)drawBuffer + j + 1) * rLevel / 65025);
298 minRGB = MIN(minRGB, *((uint8_t*)drawBuffer + j + 2) * rLevel / 65025);
299 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025 - minRGB;
300 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025 - minRGB;
301 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025 - minRGB;
302 *(frameBuffer + i + 3) = minRGB;
307 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
308 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
309 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
310 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
315 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
316 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
317 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
318 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
324 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
325 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
326 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
327 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
332 switch (params & 0x3F) {
334 for (uint16_t i = 0; i < (numbytes * numpins); i += 4) {
335 uint8_t minRGB = MIN(*((uint8_t*)drawBuffer + j) * rLevel / 65025, \
336 * ((uint8_t*)drawBuffer + j + 1) * rLevel / 65025);
337 minRGB = MIN(minRGB, *((uint8_t*)drawBuffer + j + 2) * rLevel / 65025);
338 if (i % (serp * 4) == 0) {
339 if (jChange < 0) { j = i / 4 * 3; jChange = 3; }
340 else { j = (i / 4 + serp - 1) * 3; jChange = -3; }
342 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025 - minRGB;
343 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025 - minRGB;
344 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025 - minRGB;
345 *(frameBuffer + i + 3) = minRGB;
350 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
351 if (i % (serp * 3) == 0) {
352 if (jChange < 0) { j = i; jChange = 3; }
353 else { j = i + (serp - 1) * 3; jChange = -3; }
355 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
356 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
357 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
362 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
363 if (i % (serp * 3) == 0) {
364 if (jChange < 0) { j = i; jChange = 3; }
365 else { j = i + (serp - 1) * 3; jChange = -3; }
367 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
368 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
369 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
375 for (uint16_t i = 0; i < (numbytes * numpins); i += 3) {
376 if (i % (serp * 3) == 0) {
377 if (jChange < 0) { j = i; jChange = 3; }
378 else { j = i + (serp - 1) * 3; jChange = -3; }
380 *(frameBuffer + i) = *((uint8_t*)drawBuffer + j) * rLevel / 65025;
381 *(frameBuffer + i + 1) = *((uint8_t*)drawBuffer + j + 1) * gLevel / 65025;
382 *(frameBuffer + i + 2) = *((uint8_t*)drawBuffer + j + 2) * bLevel / 65025;
395void ObjectFLED::show(
void) {
396 while (!dma3.complete());
399 if (frameBuffer != frameBufferLocal) {
400 numpins = numpinsLocal;
401 frameBuffer = frameBufferLocal;
402 numbytes = numbytesLocal;
403 memcpy(bitmask, bitmaskLocal, 16);
404 memcpy(pin_bitnum, pin_bitnumLocal, numpins);
405 memcpy(pin_offset, pin_offsetLocal, numpins);
406 arm_dcache_flush_delete(bitmask,
sizeof(bitmask));
408 TMR4_COMP10 = comp1load[0];
409 TMR4_CMPLD10 = comp1load[0];
410 TMR4_COMP11 = comp1load[1];
411 TMR4_CMPLD11 = comp1load[1];
412 TMR4_COMP12 = comp1load[2];
413 TMR4_CMPLD12 = comp1load[2];
415 dma1.TCD->CITER_ELINKNO = numbytes * 8;
416 dma1.TCD->BITER_ELINKNO = numbytes * 8;
417 dma3.TCD->CITER_ELINKNO = numbytes * 8;
418 dma3.TCD->BITER_ELINKNO = numbytes * 8;
421 genFrameBuffer(serpNumber);
424 uint16_t enable = TMR4_ENBL;
425 TMR4_ENBL = enable & ~7;
428 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
429 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
430 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
433 XBARA1_CTRL0 |= XBARA_CTRL_STS1 | XBARA_CTRL_STS0;
434 XBARA1_CTRL1 |= XBARA_CTRL_STS0;
437 memset(bitdata, 0,
sizeof(bitdata));
438 uint32_t count = numbytes;
439 if (count > BYTES_PER_DMA*2) count = BYTES_PER_DMA*2;
440 framebuffer_index = count;
443 for (uint32_t i=0; i < numpins; i++) {
444 fillbits(bitdata + pin_offset[i], (uint8_t *)frameBuffer + i*numbytes,
445 count, 1<<pin_bitnum[i]);
447 arm_dcache_flush_delete(bitdata, count * 128);
450 if (numbytes <= BYTES_PER_DMA*2) {
451 dma2.TCD->SADDR = bitdata;
452 dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
453 dma2.TCD->CITER_ELINKNO = count * 8;
454 dma2.TCD->CSR = DMA_TCD_CSR_DREQ;
456 dma2.TCD->SADDR = bitdata;
457 dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
458 dma2.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
460 dma2.TCD->CSR = DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_ESG;
461 dma2next.TCD->SADDR = bitdata + BYTES_PER_DMA*32;
462 dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
463 if (numbytes <= BYTES_PER_DMA*3) {
464 dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
466 dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
470 dma3.clearComplete();
477 TMR4_CNTR1 = comp1load[0] + 1;
478 TMR4_CNTR2 = comp1load[0] + 1;
481 while (micros() - update_begin_micros < numbytes * 8 * TH_TL / OC_FACTOR / 1000 + LATCH_DELAY);
484 TMR4_ENBL = enable | 7;
485 update_begin_micros = micros();
492void ObjectFLED::isr(
void)
495 dma2.clearInterrupt();
505 dest = bitdata + BYTES_PER_DMA*32;
507 memset(dest, 0,
sizeof(bitdata)/2);
508 uint32_t index = framebuffer_index;
509 uint32_t count = numbytes - framebuffer_index;
510 if (count > BYTES_PER_DMA) count = BYTES_PER_DMA;
511 framebuffer_index = index + count;
512 for (
int i=0; i < numpins; i++) {
513 fillbits(dest + pin_offset[i], (uint8_t *)frameBuffer + index + i*numbytes,
514 count, 1<<pin_bitnum[i]);
516 arm_dcache_flush_delete(dest, count * 128);
520 dma2next.TCD->SADDR = dest;
521 dma2next.TCD->CITER_ELINKNO = count * 8;
522 uint32_t remain = numbytes - (index + count);
524 dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
525 }
else if (remain <= BYTES_PER_DMA) {
526 dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
528 dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
533int ObjectFLED::busy(
void)
535 if (micros() - update_begin_micros < numbytes * TH_TL / OC_FACTOR / 1000 * 8 + LATCH_DELAY) {
542void ObjectFLED::setBrightness(uint8_t brightLevel) {
543 brightness = brightLevel;
544 rLevel = (brightness + 1) * (colorBalance >> 16);
545 gLevel = (brightness + 1) * ((colorBalance >> 8) & 0xFF);
546 bLevel = (brightness + 1) * (colorBalance & 0xFF);
550void ObjectFLED::setBalance(uint32_t balMask) {
551 colorBalance = balMask & 0xFFFFFF;
552 rLevel = (brightness + 1) * (colorBalance >> 16);
553 gLevel = (brightness + 1) * ((colorBalance >> 8) & 0xFF);
554 bLevel = (brightness + 1) * (colorBalance & 0xFF);
559void fadeToColorBy(
void* leds, uint16_t count, uint32_t color, uint8_t fadeAmt) {
560 for (uint32_t x = 0; x < count * 3; x += 3) {
562 *((uint8_t*)leds + x) = (( *((uint8_t*)leds + x) * (1 + (255 - fadeAmt))) >> 8) + \
563 (( ((color >> 16) & 0xFF) * (1 + fadeAmt)) >> 8);
565 *((uint8_t*)leds + x + 1) = (( *((uint8_t*)leds + x + 1) * (1 + (255 - fadeAmt))) >> 8) + \
566 (( ((color >> 8) & 0xFF) * (1 + fadeAmt)) >> 8);
568 *((uint8_t*)leds + x + 2) = (( *((uint8_t*)leds + x + 2) * (1 + (255 - fadeAmt))) >> 8) + \
569 (( (color & 0xFF) * (1 + fadeAmt)) >> 8);
575void drawSquare(
void* leds, uint16_t planeY, uint16_t planeX,
int yCorner,
int xCorner, uint32_t size, uint32_t color) {
576 if (size != 0) { size--; }
578 for (
int x = xCorner; x <= xCorner + (int)size; x++) {
580 if ((x >= 0) && (x < planeX)) {
581 if ((yCorner >= 0) && (yCorner < planeY)) {
582 *((uint8_t*)leds + (yCorner * planeX + x) * 3) = ((color >> 16) & 0xFF);
583 *((uint8_t*)leds + (yCorner * planeX + x) * 3 + 1) = ((color >> 8) & 0xFF);
584 *((uint8_t*)leds + (yCorner * planeX + x) * 3 + 2) = (color & 0xFF);
586 if ((yCorner + size >= 0) && (yCorner + size < planeY)) {
587 *((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3) = ((color >> 16) & 0xFF);
588 *((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3 + 1) = ((color >> 8) & 0xFF);
589 *((uint8_t*)leds + ((yCorner + size) * planeX + x) * 3 + 2) = (color & 0xFF);
593 for (
int y = yCorner; y <= yCorner + (int)size; y++) {
594 if ((y >= 0) && (y < planeY)) {
595 if ((xCorner >= 0) && (xCorner < planeX)) {
596 *((uint8_t*)leds + (xCorner + y * planeX) * 3) = ((color >> 16) & 0xFF);
597 *((uint8_t*)leds + (xCorner + y * planeX) * 3 + 1) = ((color >> 8) & 0xFF);
598 *((uint8_t*)leds + (xCorner + y * planeX) * 3 + 2) = (color & 0xFF);
600 if ((xCorner + size >= 0) && (xCorner + size < planeX)) {
601 *((uint8_t*)leds + (xCorner + size + y * planeX) * 3) = ((color >> 16) & 0xFF);
602 *((uint8_t*)leds + (xCorner + size + y * planeX) * 3 + 1) = ((color >> 8) & 0xFF);
603 *((uint8_t*)leds + (xCorner + size + y * planeX) * 3 + 2) = (color & 0xFF);