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) {
91 Serial.printf(
"ObjectFLED: numPins=%u exceeds NUM_DIGITAL_PINS=%u; truncating\r\n",
92 numPins, NUM_DIGITAL_PINS);
93 numPins = NUM_DIGITAL_PINS;
98 Serial.printf(
"ObjectFLED: numPins=0 is invalid; abandoning init\r\n");
109 Serial.printf(
"ObjectFLED: numLEDs=%u not divisible by numpins=%u; last %u LED(s) ignored\r\n",
113 if ((
params & 0x3F) < 6) {
124extern "C" void xbar_connect(
unsigned int input,
unsigned int output);
129static void force_pin_to_gpio_mux(
uint8_t pin) {
137#ifdef FASTLED_OBJECTFLED_PROBE_INPUT
138 *portConfigRegister(pin) = 5 | 0x10;
140 *portConfigRegister(pin) = 5;
144static void configure_objectfled_xbar_dma_edges() {
148 constexpr uint16_t ctrl0ConfigMask =
149 XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0 |
150 XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1;
151 constexpr uint16_t ctrl1ConfigMask =
152 XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
155 ctrl0 &= ~(ctrl0ConfigMask | XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
156 ctrl0 |= XBARA_CTRL_STS1 | XBARA_CTRL_EDGE1(3) | XBARA_CTRL_DEN1 |
157 XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
158 XBARA1_CTRL0 = ctrl0;
161 ctrl1 &= ~(ctrl1ConfigMask | XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
162 ctrl1 |= XBARA_CTRL_STS0 | XBARA_CTRL_EDGE0(3) | XBARA_CTRL_DEN0;
163 XBARA1_CTRL1 = ctrl1;
166static void clear_objectfled_xbar_dma_status() {
168 ctrl0 &= ~(XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
169 XBARA1_CTRL0 = ctrl0 | XBARA_CTRL_STS1 | XBARA_CTRL_STS0;
172 ctrl1 &= ~(XBARA_CTRL_STS0 | XBARA_CTRL_STS1);
173 XBARA1_CTRL1 = ctrl1 | XBARA_CTRL_STS0;
176static bool objectfled_has_dma_tcds(
const ObjectFLEDDmaManager& dma) {
177 return dma.dma1.TCD !=
nullptr &&
178 dma.dma2.TCD !=
nullptr &&
179 dma.dma3.TCD !=
nullptr &&
180 dma.dma2next.TCD !=
nullptr;
215 auto& dma = ObjectFLEDDmaManager::getInstance();
226 if (!validation.valid) {
227 FL_WARN(
"================================================================================");
228 FL_WARN(
"FASTLED ERROR: Pin %s is INVALID and has been disabled", (
int)pin);
229 FL_WARN(
"%s", validation.error_message);
230 FL_WARN(
"================================================================================");
235 if (validation.error_message !=
nullptr) {
236 FL_WARN(
"================================================================================");
237 FL_WARN(
"FASTLED WARNING: Pin %s may have issues", (
int)pin);
238 FL_WARN(
"%s", validation.error_message);
239 FL_WARN(
"================================================================================");
242 uint8_t bit = digitalPinToBit(pin);
246 FL_WARN(
"================================================================================");
247 FL_WARN(
"FASTLED ERROR: Pin %s does not map to GPIO6-9 (offset=%s)", (
int)pin, (
int)
offset);
248 FL_WARN(
"This pin may be a ground/power/read-only pin - strip disabled");
249 FL_WARN(
"================================================================================");
257 tempBitmask[
offset] |= mask;
258 force_pin_to_gpio_mux(pin);
260 *portControlRegister(pin) &= ~0xF9;
264 *(&IOMUXC_GPR_GPR26 +
offset) &= ~mask;
265 *standard_gpio_addr(portModeRegister(pin)) |= mask;
269 if (validPinCount == 0) {
270 FL_WARN(
"================================================================================");
271 FL_WARN(
"FASTLED CRITICAL ERROR: No valid pins configured!");
273 FL_WARN(
"ObjectFLED driver is disabled - no LEDs will be updated.");
274 FL_WARN(
"================================================================================");
280 FL_WARN(
"================================================================================");
281 FL_WARN(
"FASTLED WARNING: Only %s of %s pins are valid", (
int)validPinCount, (
int)
numpinsLocal);
282 FL_WARN(
"Strips on invalid pins will not function.");
283 FL_WARN(
"================================================================================");
306 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
307 TMR4_CSCTRL0 = TMR_CSCTRL_CL1(1) | TMR_CSCTRL_TCF1EN;
312 TMR4_CTRL0 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_LENGTH | TMR_CTRL_OUTMODE(3);
313 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
318 TMR4_CTRL1 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
319 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
324 TMR4_CTRL2 = TMR_CTRL_CM(1) | TMR_CTRL_PCS(8) | TMR_CTRL_COINIT | TMR_CTRL_OUTMODE(3);
327 CCM_CCGR2 |= CCM_CCGR2_XBAR1(CCM_CCGR_ON);
333 xbar_connect(XBARA1_IN_QTIMER4_TIMER0, XBARA1_OUT_DMA_CH_MUX_REQ30);
334 xbar_connect(XBARA1_IN_QTIMER4_TIMER1, XBARA1_OUT_DMA_CH_MUX_REQ31);
335 xbar_connect(XBARA1_IN_QTIMER4_TIMER2, XBARA1_OUT_DMA_CH_MUX_REQ94);
346 if (!dma.dma1.TCD || !dma.dma2.TCD || !dma.dma3.TCD) {
352 if (!objectfled_has_dma_tcds(dma)) {
357 configure_objectfled_xbar_dma_edges();
359 dma.dma1.TCD->SADDR = dma.bitmask;
360 dma.dma1.TCD->SOFF = 8;
363 dma.dma1.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
364 dma.dma1.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
365 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
366 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
367 dma.dma1.TCD->SLAST = 0;
368 dma.dma1.TCD->DADDR = &GPIO1_DR_SET;
369 dma.dma1.TCD->DOFF = 16384;
371 dma.dma1.TCD->DLASTSGA = -65536;
373 dma.dma1.TCD->CSR = DMA_TCD_CSR_DREQ;
374 dma.dma1.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_0);
376 dma.dma2next.TCD->SADDR = dma.bitdata;
377 dma.dma2next.TCD->SOFF = 8;
378 dma.dma2next.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_DSIZE(2);
379 dma.dma2next.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
380 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
381 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
382 dma.dma2next.TCD->SLAST = 0;
383 dma.dma2next.TCD->DADDR = &GPIO1_DR_CLEAR;
384 dma.dma2next.TCD->DOFF = 16384;
385 dma.dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
386 dma.dma2next.TCD->DLASTSGA = (
int32_t)(dma.dma2next.TCD);
387 dma.dma2next.TCD->BITER_ELINKNO = BYTES_PER_DMA * 8;
388 dma.dma2next.TCD->CSR = 0;
390 dma.dma2 = dma.dma2next;
397 dma.dma2.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_1);
401 dma.dma2.detachInterrupt();
402 dma.dma2.attachInterrupt(
isr);
404 dma.dma3.TCD->SADDR = dma.bitmask;
405 dma.dma3.TCD->SOFF = 8;
406 dma.dma3.TCD->ATTR = DMA_TCD_ATTR_SSIZE(3) | DMA_TCD_ATTR_SMOD(4) | DMA_TCD_ATTR_DSIZE(2);
407 dma.dma3.TCD->NBYTES_MLOFFYES = DMA_TCD_NBYTES_DMLOE |
408 DMA_TCD_NBYTES_MLOFFYES_MLOFF(-65536) |
409 DMA_TCD_NBYTES_MLOFFYES_NBYTES(16);
410 dma.dma3.TCD->SLAST = 0;
411 dma.dma3.TCD->DADDR = &GPIO1_DR_CLEAR;
412 dma.dma3.TCD->DOFF = 16384;
414 dma.dma3.TCD->DLASTSGA = -65536;
422 dma.dma3.TCD->CSR = DMA_TCD_CSR_DREQ | DMA_TCD_CSR_DONE;
423 dma.dma3.triggerAtHardwareEvent(DMAMUX_SOURCE_XBAR1_2);
435 if (!(pix & 0x80)) *dest |= mask;
437 if (!(pix & 0x40)) *dest |= mask;
439 if (!(pix & 0x20)) *dest |= mask;
441 if (!(pix & 0x10)) *dest |= mask;
443 if (!(pix & 0x08)) *dest |= mask;
445 if (!(pix & 0x04)) *dest |= mask;
447 if (!(pix & 0x02)) *dest |= mask;
449 if (!(pix & 0x01)) *dest |= mask;
520 if (i % (serp * 4) == 0) {
521 if (jChange < 0) { j = i / 4 * 3; jChange = 3; }
522 else { j = (i / 4 + serp - 1) * 3; jChange = -3; }
533 if (i % (serp * 3) == 0) {
534 if (jChange < 0) { j = i; jChange = 3; }
535 else { j = i + (serp - 1) * 3; jChange = -3; }
545 if (i % (serp * 3) == 0) {
546 if (jChange < 0) { j = i; jChange = 3; }
547 else { j = i + (serp - 1) * 3; jChange = -3; }
557 if (i % (serp * 3) == 0) {
558 if (jChange < 0) { j = i; jChange = 3; }
559 else { j = i + (serp - 1) * 3; jChange = -3; }
569 if (i % (serp * 3) == 0) {
570 if (jChange < 0) { j = i; jChange = 3; }
571 else { j = i + (serp - 1) * 3; jChange = -3; }
582 if (i % (serp * 3) == 0) {
583 if (jChange < 0) { j = i; jChange = 3; }
584 else { j = i + (serp - 1) * 3; jChange = -3; }
614 auto& dma = ObjectFLEDDmaManager::getInstance();
627 arm_dcache_flush_delete(dma.bitmask,
sizeof(dma.bitmask));
636 dma.dma1.TCD->CITER_ELINKNO = dma.numbytes * 8;
637 dma.dma1.TCD->BITER_ELINKNO = dma.numbytes * 8;
638 dma.dma3.TCD->CITER_ELINKNO = dma.numbytes * 8;
639 dma.dma3.TCD->BITER_ELINKNO = dma.numbytes * 8;
642 if (regenerateFrameBuffer) {
648 TMR4_ENBL = enable & ~7;
651 TMR4_SCTRL0 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE | TMR_SCTRL_MSTR;
652 TMR4_SCTRL1 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
653 TMR4_SCTRL2 = TMR_SCTRL_OEN | TMR_SCTRL_FORCE;
656 clear_objectfled_xbar_dma_status();
659 memset(dma.bitdata, 0,
sizeof(dma.bitdata));
661 if (count > BYTES_PER_DMA*2) count = BYTES_PER_DMA*2;
662 dma.framebuffer_index = count;
665 for (
uint32_t i=0; i < dma.numpins; i++) {
666 fillbits(dma.bitdata + dma.pin_offset[i], (
uint8_t *)dma.frameBuffer + i*dma.numbytes,
667 count, 1<<dma.pin_bitnum[i]);
669 arm_dcache_flush_delete(dma.bitdata, count * 128);
672 if (dma.numbytes <= BYTES_PER_DMA*2) {
673 dma.dma2.TCD->SADDR = dma.bitdata;
674 dma.dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
675 dma.dma2.TCD->CITER_ELINKNO = count * 8;
676 dma.dma2.TCD->CSR = DMA_TCD_CSR_DREQ;
678 dma.dma2.TCD->SADDR = dma.bitdata;
679 dma.dma2.TCD->DADDR = &GPIO1_DR_CLEAR;
680 dma.dma2.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
686 dma.dma2.TCD->CSR = DMA_TCD_CSR_INTMAJOR | DMA_TCD_CSR_ESG;
687 dma.dma2next.TCD->SADDR = dma.bitdata + BYTES_PER_DMA*32;
688 dma.dma2next.TCD->CITER_ELINKNO = BYTES_PER_DMA * 8;
689 if (dma.numbytes <= BYTES_PER_DMA*3) {
690 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
692 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
703 asm volatile(
"dmb" :::
"memory");
704 dma.dma3.clearComplete();
708 asm volatile(
"dsb" :::
"memory");
719 TMR4_ENBL = enable | 7;
732 auto& dma = ObjectFLEDDmaManager::getInstance();
735 dma.dma2.clearInterrupt();
736 asm volatile(
"dsb" :::
"memory");
741 uint32_t index_check = dma.framebuffer_index;
742 uint32_t remain_check = dma.numbytes - index_check;
750 dest = dma.bitdata + BYTES_PER_DMA*32;
753 if (remain_check == 0) {
759 dma.dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
769 memset(dest, 0,
sizeof(dma.bitdata)/2);
770 uint32_t index = dma.framebuffer_index;
771 uint32_t count = dma.numbytes - dma.framebuffer_index;
772 if (count > BYTES_PER_DMA) count = BYTES_PER_DMA;
773 dma.framebuffer_index = index + count;
774 for (
int i=0; i < dma.numpins; i++) {
775 fillbits(dest + dma.pin_offset[i], (
uint8_t *)dma.frameBuffer + index + i*dma.numbytes,
776 count, 1<<dma.pin_bitnum[i]);
778 arm_dcache_flush_delete(dest, count * 128);
782 dma.dma2next.TCD->SADDR = dest;
783 dma.dma2next.TCD->CITER_ELINKNO = count * 8;
784 uint32_t remain = dma.numbytes - (index + count);
786 dma.dma2next.TCD->CSR = DMA_TCD_CSR_DREQ;
787 }
else if (remain <= BYTES_PER_DMA) {
788 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG;
790 dma.dma2next.TCD->CSR = DMA_TCD_CSR_ESG | DMA_TCD_CSR_INTMAJOR;
800 auto& dma = ObjectFLEDDmaManager::getInstance();
829 (( ((
color >> 16) & 0xFF) * (1 + fadeAmt)) >> 8);
832 (( ((
color >> 8) & 0xFF) * (1 + fadeAmt)) >> 8);
835 (( (
color & 0xFF) * (1 + fadeAmt)) >> 8);
842 if (size != 0) { size--; }
844 for (
int x = xCorner;
x <= xCorner + (int)size;
x++) {
846 if ((
x >= 0) && (
x < planeX)) {
847 if ((yCorner >= 0) && (yCorner < planeY)) {
857 if ((yCorner + (
int)size >= 0) && (yCorner + (
int)size < planeY)) {
858 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3) = ((
color >> 16) & 0xFF);
859 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3 + 1) = ((
color >> 8) & 0xFF);
860 *((
uint8_t*)
leds + ((yCorner + (
int)size) * planeX +
x) * 3 + 2) = (
color & 0xFF);
864 for (
int y = yCorner;
y <= yCorner + (int)size;
y++) {
865 if ((
y >= 0) && (
y < planeY)) {
866 if ((xCorner >= 0) && (xCorner < planeX)) {
872 if ((xCorner + (
int)size >= 0) && (xCorner + (
int)size < planeX)) {
873 *((
uint8_t*)
leds + (xCorner + (
int)size +
y * planeX) * 3) = ((
color >> 16) & 0xFF);
874 *((
uint8_t*)
leds + (xCorner + (
int)size +
y * planeX) * 3 + 1) = ((
color >> 8) & 0xFF);
896 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.
void * memcpy(void *dest, const void *src, size_t n) FL_NO_EXCEPT
fl::u32 micros()
Universal microsecond timer - returns microseconds since system startup.
void drawSquare(void *, uint16_t, uint16_t, int, int, uint32_t, uint32_t)
void * memset(void *s, int c, 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)