diff options
Diffstat (limited to 'platforms/arm/common/m0clockless.h')
-rw-r--r-- | platforms/arm/common/m0clockless.h | 149 |
1 files changed, 110 insertions, 39 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; } |