60#include "platforms/arm/teensy/is_teensy.h"
62#ifndef FL_IS_TEENSY_4X
71#define MIN(a,b) ((a)<(b)?(a):(b))
75#define MAX(a,b) ((a)>(b)?(a):(b))
80volatile bool dma_first;
88 if (numPins > NUM_DIGITAL_PINS) {
93 Serial.print(
"ObjectFLED: numPins=");
94 Serial.print((
unsigned)numPins);
95 Serial.print(
" exceeds NUM_DIGITAL_PINS=");
96 Serial.print((
unsigned)NUM_DIGITAL_PINS);
97 Serial.print(
"; truncating\r\n");
98 numPins = NUM_DIGITAL_PINS;
103 Serial.print(
"ObjectFLED: numPins=0 is invalid; abandoning init\r\n");
114 Serial.print(
"ObjectFLED: numLEDs=");
115 Serial.print((
unsigned)numLEDs);
116 Serial.print(
" not divisible by numpins=");
120 Serial.print(
" LED(s) ignored\r\n");
123 if ((
params & 0x3F) < 6) {
134extern "C" void xbar_connect(
unsigned int input,
unsigned int output);
139static void force_pin_to_gpio_mux(
uint8_t pin) {
147#ifdef FASTLED_OBJECTFLED_PROBE_INPUT
148 *portConfigRegister(pin) = 5 | 0x10;
150 *portConfigRegister(pin) = 5;
154static void configure_objectfled_xbar_dma_edges() {
158 constexpr uint16_t ctrl0ConfigMask =
159 XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0 |
160 XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1;
161 constexpr uint16_t ctrl1ConfigMask =
162 XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
165 ctrl0 &= ~(ctrl0ConfigMask | XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
166 ctrl0 |= XBARA_CTRL_STS1 | XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1 |
167 XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
168 XBARA1_CTRL0 = ctrl0;
171 ctrl1 &= ~(ctrl1ConfigMask | XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
172 ctrl1 |= XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
173 XBARA1_CTRL1 = ctrl1;
176static void clear_objectfled_xbar_dma_status() {
178 ctrl0 &= ~(XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
179 XBARA1_CTRL0 = ctrl0 | XBARA_CTRL_STS1 | XBARA_CTRL_STS0;
182 ctrl1 &= ~(XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
183 XBARA1_CTRL1 = ctrl1 | XBARA_CTRL_STS0;
186static bool objectfled_has_dma_tcds(
const ObjectFLEDDmaManager& dma) {
187 return dma.dma1.TCD !=
nullptr &&
188 dma.dma2.TCD !=
nullptr &&
189 dma.dma3.TCD !=
nullptr &&
190 dma.dma2next.TCD !=
nullptr;
225 auto& dma = ObjectFLEDDmaManager::getInstance();
236 if (!validation.valid) {
237 FL_WARN(
"================================================================================");
238 FL_WARN(
"FASTLED ERROR: Pin " << (
int)pin <<
" is INVALID and has been disabled");
239 FL_WARN(validation.error_message);
240 FL_WARN(
"================================================================================");
245 if (validation.error_message !=
nullptr) {
246 FL_WARN(
"================================================================================");
247 FL_WARN(
"FASTLED WARNING: Pin " << (
int)pin <<
" may have issues");
248 FL_WARN(validation.error_message);
249 FL_WARN(
"================================================================================");
252 uint8_t bit = digitalPinToBit(pin);
256 FL_WARN(
"================================================================================");
257 FL_WARN(
"FASTLED ERROR: Pin " << (
int)pin <<
" does not map to GPIO6-9 (offset=" << (
int)
offset <<
")");
258 FL_WARN(
"This pin may be a ground/power/read-only pin - strip disabled");
259 FL_WARN(
"================================================================================");
267 tempBitmask[
offset] |= mask;
268 force_pin_to_gpio_mux(pin);
270 *portControlRegister(pin) &= ~0xF9;
274 *(&IOMUXC_GPR_GPR26 +
offset) &= ~mask;
275 *standard_gpio_addr(portModeRegister(pin)) |= mask;
279 if (validPinCount == 0) {
280 FL_WARN(
"================================================================================");
281 FL_WARN(
"FASTLED CRITICAL ERROR: No valid pins configured!");
283 FL_WARN(
"ObjectFLED driver is disabled - no LEDs will be updated.");
284 FL_WARN(
"================================================================================");
290 FL_WARN(
"================================================================================");
291 FL_WARN(
"FASTLED WARNING: Only " << (
int)validPinCount <<
" of " << (
int)
numpinsLocal <<
" pins are valid");
292 FL_WARN(
"Strips on invalid pins will not function.");
293 FL_WARN(
"================================================================================");
316 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
317 TMR4_CSCTRL0 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN;
322 TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3);
323 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
328 TMR4_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
329 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
334 TMR4_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
337 CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
343 xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_DMA_CH_MUX_REQ30);
344 xbar_connect(XBARA1_IN_QTIMER4_TIMER1, XBARA1_OUT_DMA_CH_MUX_REQ31);
345 xbar_connect(XBARA1_IN_QTIMER4_TIMER2, XBARA1_OUT_DMA_CH_MUX_REQ94);
356 if (!dma.dma1.TCD || !dma.dma2.TCD || !dma.dma3.TCD) {
362 if (!objectfled_has_dma_tcds(dma)) {
367 configure_objectfled_xbar_dma_edges();
369 dma.dma1.TCD->SADDR = dma.bitmask;
370 dma.dma1.TCD->SOFF = 8;
373 dma.dma1.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
374 dma.dma1.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
375 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
376 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
377 dma.dma1.TCD->SLAST = 0;
378 dma.dma1.TCD->DADDR = &GPIO1_DR_SET;
379 dma.dma1.TCD->DOFF = 16384;
381 dma.dma1.TCD->DLASTSGA = -65536;
383 dma.dma1.TCD->CSR = DMA_TCD_CSR_DREQ;
384 dma.dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);
386 dma.dma2next.TCD->SADDR = dma.bitdata;
387 dma.dma2next.TCD->SOFF = 8;
388 dma.dma2next.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_DSIZE(2);
389 dma.dma2next.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
390 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
391 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
392 dma.dma2next.TCD->SLAST = 0;
393 dma.dma2next.TCD->DADDR = &GPIO1_DR_CLEAR;
394 dma.dma2next.TCD->DOFF = 16384;
395 dma.dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
396 dma.dma2next.TCD->DLASTSGA = (
int32_t)(dma.dma2next.TCD);
397 dma.dma2next.TCD->BITER_ELINKNO = BYTES_PER_DMA * 8;
398 dma.dma2next.TCD->CSR = 0;
400 dma.dma2 = dma.dma2next;
407 dma.dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_1);
411 dma.dma2.detachInterrupt();
412 dma.dma2.attachInterrupt(
isr);
414 dma.dma3.TCD->SADDR = dma.bitmask;
415 dma.dma3.TCD->SOFF = 8;
416 dma.dma3.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
417 dma.dma3.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
418 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
419 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
420 dma.dma3.TCD->SLAST = 0;
421 dma.dma3.TCD->DADDR = &GPIO1_DR_CLEAR;
422 dma.dma3.TCD->DOFF = 16384;
424 dma.dma3.TCD->DLASTSGA = -65536;
432 dma.dma3.TCD->CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_DONE;
433 dma.dma3.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_2);
445 if (!(pix & 0x80)) *dest |= mask;
447 if (!(pix & 0x40)) *dest |= mask;
449 if (!(pix & 0x20)) *dest |= mask;
451 if (!(pix & 0x10)) *dest |= mask;
453 if (!(pix & 0x08)) *dest |= mask;
455 if (!(pix & 0x04)) *dest |= mask;
457 if (!(pix & 0x02)) *dest |= mask;
459 if (!(pix & 0x01)) *dest |= mask;
530 if (i % (serp * 4) == 0) {
531 if (jChange < 0) { j = i / 4 * 3; jChange = 3; }
532 else { j = (i / 4 + serp - 1) * 3; jChange = -3; }
543 if (i % (serp * 3) == 0) {
544 if (jChange < 0) { j = i; jChange = 3; }
545 else { j = i + (serp - 1) * 3; jChange = -3; }
555 if (i % (serp * 3) == 0) {
556 if (jChange < 0) { j = i; jChange = 3; }
557 else { j = i + (serp - 1) * 3; jChange = -3; }
567 if (i % (serp * 3) == 0) {
568 if (jChange < 0) { j = i; jChange = 3; }
569 else { j = i + (serp - 1) * 3; jChange = -3; }
579 if (i % (serp * 3) == 0) {
580 if (jChange < 0) { j = i; jChange = 3; }
581 else { j = i + (serp - 1) * 3; jChange = -3; }
592 if (i % (serp * 3) == 0) {
593 if (jChange < 0) { j = i; jChange = 3; }
594 else { j = i + (serp - 1) * 3; jChange = -3; }
624 auto& dma = ObjectFLEDDmaManager::getInstance();
637 arm_dcache_flush_delete(dma.bitmask,
sizeof(dma.bitmask));
646 dma.dma1.TCD->CITER_ELINKNO = dma.numbytes * 8;
647 dma.dma1.TCD->BITER_ELINKNO = dma.numbytes * 8;
648 dma.dma3.TCD->CITER_ELINKNO = dma.numbytes * 8;
649 dma.dma3.TCD->BITER_ELINKNO = dma.numbytes * 8;
655 if (!dma.ensureBitdata(dma.numbytes)) {
656 static bool warned =
false;
659 FL_WARN(
"ObjectFLED: out of memory for the DMA bit buffer ("
660 << dma.numbytes <<
" bytes/strip); frames dropped");
666 if (regenerateFrameBuffer) {
672 TMR4_ENBL = enable & ~7;
675 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
676 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
677 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
680 clear_objectfled_xbar_dma_status();
684 if (count > BYTES_PER_DMA*2) count = BYTES_PER_DMA*2;
688 dma.framebuffer_index = count;
691 for (
uint32_t i=0; i < dma.numpins; i++) {
692 fillbits(dma.bitdata + dma.pin_offset[i], (
uint8_t *)dma.frameBuffer + i*dma.numbytes,
693 count, 1<<dma.pin_bitnum[i]);
695 arm_dcache_flush_delete(dma.bitdata, count * 128);
698 if (dma.numbytes <= BYTES_PER_DMA*2) {
699 dma.dma2.TCD->SADDR = dma.bitdata;
700 dma.dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
701 dma.dma2.TCD->CITER_ELINKNO = count * 8;
702 dma.dma2.TCD->CSR = DMA_TCD_CSR_DREQ;
704 dma.dma2.TCD->SADDR = dma.bitdata;
705 dma.dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
706 dma.dma2.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
720 dma.dma2.clearComplete();
721 dma.dma2.TCD->CSR = DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_ESG;
722 dma.dma2next.TCD->SADDR = dma.bitdata + BYTES_PER_DMA*32;
723 dma.dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
724 if (dma.numbytes <= BYTES_PER_DMA*3) {
725 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
727 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
738 asm volatile(
"dmb" :::
"memory");
739 dma.dma3.clearComplete();
743 asm volatile(
"dsb" :::
"memory");
754 TMR4_ENBL = enable | 7;
767 auto& dma = ObjectFLEDDmaManager::getInstance();
770 dma.dma2.clearInterrupt();
771 asm volatile(
"dsb" :::
"memory");
776 uint32_t index_check = dma.framebuffer_index;
777 uint32_t remain_check = dma.numbytes - index_check;
785 dest = dma.bitdata + BYTES_PER_DMA*32;
788 if (remain_check == 0) {
794 dma.dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
807 uint32_t index = dma.framebuffer_index;
808 uint32_t count = dma.numbytes - dma.framebuffer_index;
809 if (count > BYTES_PER_DMA) count = BYTES_PER_DMA;
810 dma.framebuffer_index = index + count;
811 for (
int i=0; i < dma.numpins; i++) {
812 fillbits(dest + dma.pin_offset[i], (
uint8_t *)dma.frameBuffer + index + i*dma.numbytes,
813 count, 1<<dma.pin_bitnum[i]);
815 arm_dcache_flush_delete(dest, count * 128);
819 dma.dma2next.TCD->SADDR = dest;
820 dma.dma2next.TCD->CITER_ELINKNO = count * 8;
821 uint32_t remain = dma.numbytes - (index + count);
823 dma.dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
824 }
else if (remain <= BYTES_PER_DMA) {
825 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
827 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
837 auto& dma = ObjectFLEDDmaManager::getInstance();
866 (( ((
color >> 16) & 0xFF) * (1 + fadeAmt)) >> 8);
869 (( ((
color >> 8) & 0xFF) * (1 + fadeAmt)) >> 8);
872 (( (
color & 0xFF) * (1 + fadeAmt)) >> 8);
879 if (size != 0) { size--; }
881 for (
int x = xCorner;
x <= xCorner + (int)size;
x++) {
883 if ((
x >= 0) && (
x < planeX)) {
884 if ((yCorner >= 0) && (yCorner < planeY)) {
894 if ((yCorner + (
int)size >= 0) && (yCorner + (
int)size < planeY)) {
895 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3) = ((
color >> 16) & 0xFF);
896 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3 + 1) = ((
color >> 8) & 0xFF);
897 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3 + 2) = (
color & 0xFF);
901 for (
int y = yCorner;
y <= yCorner + (int)size;
y++) {
902 if ((
y >= 0) && (
y < planeY)) {
903 if ((xCorner >= 0) && (xCorner < planeX)) {
909 if ((xCorner + (
int)size >= 0) && (xCorner + (
int)size < planeX)) {
910 *((
uint8_t*)
leds + (xCorner + (
int)size +
y * planeX) * 3) = ((
color >> 16) & 0xFF);
911 *((
uint8_t*)
leds + (xCorner + (
int)size +
y * planeX) * 3 + 1) = ((
color >> 8) & 0xFF);
936 auto& dma = ObjectFLEDDmaManager::getInstance();
938 dma.frameBuffer =
nullptr;
944 ObjectFLEDDmaManager::getInstance().waitForCompletion();
uint8_t * frameBufferLocal
uint8_t pin_bitnumLocal[NUM_DIGITAL_PINS]
uint8_t pinlist[NUM_DIGITAL_PINS]
uint32_t update_begin_micros
void setBalance(uint32_t)
void genFrameBuffer(uint32_t)
ObjectFLED(uint16_t numLEDs, void *drawBuf, uint8_t config, uint8_t numPins, const uint8_t *pinList, uint8_t serpentine=0)
void waitForDmaToFinish()
void setBrightness(uint8_t)
void showRawFrameBuffer(void)
void beginInternal(uint16_t, uint16_t, uint16_t, uint16_t=300)
uint8_t pin_offsetLocal[NUM_DIGITAL_PINS]
void showInternal(bool regenerateFrameBuffer)
fl::UISlider offset("Offset", 0.0f, 0.0f, 1.0f, 0.01f)
Centralized logging categories for FastLED hardware interfaces and subsystems.
fl::u32 micros() FL_NO_EXCEPT
Universal microsecond timer - returns microseconds since system startup.
FASTLED_FORCE_INLINE void * memset(void *s, int c, size_t n) FL_NO_EXCEPT
void drawSquare(void *, uint16_t, uint16_t, int, int, uint32_t, uint32_t)
FASTLED_FORCE_INLINE void * memcpy(void *dest, const void *src, size_t n) FL_NO_EXCEPT
void fadeToColorBy(void *, uint16_t, uint32_t, uint8_t)
Base definition for an LED controller.
PinValidationResult validate_teensy4_pin(uint8_t pin)
constexpr uint32_t bitdataWordsFor(uint32_t numbytes, uint32_t bytesPerDma)
Words of bitdata a frame of numbytes bytes per strip needs.