Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/FastLED/FastLED.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorademuri <adam.demuri@gmail.com>2019-04-06 05:16:05 +0300
committerDaniel Garcia <danielgarcia@gmail.com>2019-04-06 05:16:05 +0300
commit403464a499a8feffa48f6f85d205550b9bc9c89b (patch)
treef04d42f56a83800d71f4c444d6d3944f221f09d2
parent55359644ef0d6d13fefc23a6e23d6b0df7d68b57 (diff)
Re-enable interrupts in between writing LED data for ARM M0. (#751)
* Fix breakage in NRF51 support introduced by #dba8825 * Re-enable interrupts in between writing LED data for ARM M0. This adds support for FASTLED_ALLOW_INTERRUPTS to ARM M0-based platforms (e.g. SAMD21). This fixes the clock getting off when using more than ~30 LEDs, since Arduino uses an interrupt to increment the millis clock. This uses SysTick->VAL to determine whether more than 45uSecs have elapsed while interrupts were enabled. This isn't as correct as using a dedicated timer, but it does work on all ARM M0 platforms.
-rw-r--r--platforms/arm/common/m0clockless.h149
-rw-r--r--platforms/arm/d21/led_sysdefs_arm_d21.h2
2 files changed, 111 insertions, 40 deletions
diff --git a/platforms/arm/common/m0clockless.h b/platforms/arm/common/m0clockless.h
index 4798c6fa..d5a0cf6f 100644
--- a/platforms/arm/common/m0clockless.h
+++ b/platforms/arm/common/m0clockless.h
@@ -225,16 +225,17 @@ showLedData(volatile uint32_t *_port, uint32_t _bitmask, const uint8_t *_leds, u
#define CMPLOOP5 " cmploop5 %[counter], loop_%=;"
#define NOTHING ""
-#if !(defined(SEI_CHK) && (FASTLED_ALLOW_INTERRUPTS == 1))
- // We're not allowing interrupts - run the entire loop in asm to keep things
- // as tight as possible. In an ideal world, we should be pushing out ws281x
- // leds (or other 3-wire leds) with zero gaps between pixels.
+#if (defined(SEI_CHK) && (FASTLED_ALLOW_INTERRUPTS == 1))
+ // We're allowing interrupts and have hardware timer support defined -
+ // track the loop outside the asm code, to allow inserting the interrupt
+ // overrun checks.
asm __volatile__ (
// pre-load byte 0
- LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
+ LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
+ M0_ASM_ARGS);
- // loop over writing out the data
- LOOP
+ do {
+ asm __volatile__ (
// Write out byte 0, prepping byte 1
HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
HI2 _D1 QLO4 LOADLEDS3(1) _D2(3) LO2 _D3(0)
@@ -252,24 +253,26 @@ showLedData(volatile uint32_t *_port, uint32_t _bitmask, const uint8_t *_leds, u
HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
HI2 _D1 QLO4 SCALE4(2) _D2(4) LO2 _D3(0)
HI2 _D1 QLO4 ADJDITHER7(2) _D2(7) LO2 _D3(0)
- HI2 _D1 QLO4 INCLEDS3 _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(0)
// Write out byte 2, prepping byte 0
- HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 INCLEDS3 _D2(3) LO2 _D3(0)
HI2 _D1 QLO4 LOADLEDS3(0) _D2(3) LO2 _D3(0)
HI2 _D1 QLO4 LOADDITHER7(0) _D2(7) LO2 _D3(0)
HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
HI2 _D1 QLO4 SCALE4(0) _D2(4) LO2 _D3(0)
HI2 _D1 QLO4 ADJDITHER7(0) _D2(7) LO2 _D3(0)
HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
- HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(5) CMPLOOP5
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(5)
M0_ASM_ARGS
- );
-#else
- // We're allowing interrupts - track the loop outside the asm code, to allow
- // inserting the interrupt overrun checks.
+ );
+ SEI_CHK; INNER_SEI; --counter; CLI_CHK;
+ } while(counter);
+#elif (FASTLED_ALLOW_INTERRUPTS == 1)
+ // We're allowing interrupts - track the loop outside the asm code, and
+ // re-enable interrupts in between each iteration.
asm __volatile__ (
// pre-load byte 0
LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
@@ -278,39 +281,107 @@ showLedData(volatile uint32_t *_port, uint32_t _bitmask, const uint8_t *_leds, u
do {
asm __volatile__ (
// Write out byte 0, prepping byte 1
- HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
- HI2 D1 QLO4 LOADLEDS3(1) D2(3) LO2 D3(0)
- HI2 D1 QLO4 LOADDITHER7(1) D2(7) LO2 D3(0)
- HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
- HI2 D1 QLO4 SCALE4(1) D2(4) LO2 D3(0)
- HI2 D1 QLO4 ADJDITHER7(1) D2(7) LO2 D3(0)
- HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
- HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(1) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(1) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(1) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(1) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(0)
// Write out byte 1, prepping byte 2
- HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
- HI2 D1 QLO4 LOADLEDS3(2) D2(3) LO2 D3(0)
- HI2 D1 QLO4 LOADDITHER7(2) D2(7) LO2 D3(0)
- HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
- HI2 D1 QLO4 SCALE4(2) D2(4) LO2 D3(0)
- HI2 D1 QLO4 ADJDITHER7(2) D2(7) LO2 D3(0)
- HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
- HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(2) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(2) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(2) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(2) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 INCLEDS3 _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(0)
// Write out byte 2, prepping byte 0
- HI2 D1 QLO4 INCLEDS3 D2(3) LO2 D3(0)
- HI2 D1 QLO4 LOADLEDS3(0) D2(3) LO2 D3(0)
- HI2 D1 QLO4 LOADDITHER7(0) D2(7) LO2 D3(0)
- HI2 D1 QLO4 DITHER5 D2(5) LO2 D3(0)
- HI2 D1 QLO4 SCALE4(0) D2(4) LO2 D3(0)
- HI2 D1 QLO4 ADJDITHER7(0) D2(7) LO2 D3(0)
- HI2 D1 QLO4 NOTHING D2(0) LO2 D3(0)
- HI2 D1 QLO4 SWAPBBN1 D2(1) LO2 D3(5)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(0) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(0) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(0) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(0) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(5)
M0_ASM_ARGS
);
- SEI_CHK; INNER_SEI; --counter; CLI_CHK;
+
+ uint32_t ticksBeforeInterrupts = SysTick->VAL;
+ sei();
+ --counter;
+ cli();
+
+ // If more than 45 uSecs have elapsed, give up on this frame and start over.
+ // Note: this isn't completely correct. It's possible that more than one
+ // millisecond will elapse, and so SysTick->VAL will lap
+ // ticksBeforeInterrupts.
+ // Note: ticksBeforeInterrupts DECREASES
+ const uint32_t kTicksPerMs = VARIANT_MCK / 1000;
+ const uint32_t kTicksPerUs = kTicksPerMs / 1000;
+ const uint32_t kTicksIn45us = kTicksPerUs * 45;
+
+ const uint32_t currentTicks = SysTick->VAL;
+
+ if (ticksBeforeInterrupts < currentTicks) {
+ // Timer started over
+ if ((ticksBeforeInterrupts + (kTicksPerMs - currentTicks)) > kTicksIn45us) {
+ return 0;
+ }
+ } else {
+ if ((ticksBeforeInterrupts - currentTicks) > kTicksIn45us) {
+ return 0;
+ }
+ }
} while(counter);
+#else
+ // We're not allowing interrupts - run the entire loop in asm to keep things
+ // as tight as possible. In an ideal world, we should be pushing out ws281x
+ // leds (or other 3-wire leds) with zero gaps between pixels.
+ asm __volatile__ (
+ // pre-load byte 0
+ LOADLEDS3(0) LOADDITHER7(0) DITHER5 SCALE4(0) ADJDITHER7(0) SWAPBBN1
+
+ // loop over writing out the data
+ LOOP
+ // Write out byte 0, prepping byte 1
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(1) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(1) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(1) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(1) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(0)
+
+ // Write out byte 1, prepping byte 2
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(2) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(2) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(2) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(2) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 INCLEDS3 _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(0)
+
+ // Write out byte 2, prepping byte 0
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADLEDS3(0) _D2(3) LO2 _D3(0)
+ HI2 _D1 QLO4 LOADDITHER7(0) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 DITHER5 _D2(5) LO2 _D3(0)
+ HI2 _D1 QLO4 SCALE4(0) _D2(4) LO2 _D3(0)
+ HI2 _D1 QLO4 ADJDITHER7(0) _D2(7) LO2 _D3(0)
+ HI2 _D1 QLO4 NOTHING _D2(0) LO2 _D3(0)
+ HI2 _D1 QLO4 SWAPBBN1 _D2(1) LO2 _D3(5) CMPLOOP5
+
+ M0_ASM_ARGS
+ );
#endif
return num_leds;
}
diff --git a/platforms/arm/d21/led_sysdefs_arm_d21.h b/platforms/arm/d21/led_sysdefs_arm_d21.h
index b343d3f2..a48db10a 100644
--- a/platforms/arm/d21/led_sysdefs_arm_d21.h
+++ b/platforms/arm/d21/led_sysdefs_arm_d21.h
@@ -11,7 +11,7 @@
// Default to allowing interrupts
#ifndef FASTLED_ALLOW_INTERRUPTS
-#define FASTLED_ALLOW_INTERRUPTS 0
+#define FASTLED_ALLOW_INTERRUPTS 1
#endif
#if FASTLED_ALLOW_INTERRUPTS == 1