diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp b/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp index cb49b4ce589277049cf3b86be5cdfd8d4372c4c4..44d9ca381027dbd758070ac152300b3f93ce1c59 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.cpp @@ -46,7 +46,7 @@ #include "Adafruit_NeoPixel.h" #if defined(TARGET_LPC1768) - #include <time.h> +#include <time.h> #endif #if defined(NRF52) || defined(NRF52_SERIES) @@ -57,6 +57,14 @@ //#define NRF52_DISABLE_INT #endif +#if defined(ARDUINO_ARCH_NRF52840) +#if defined __has_include +#if __has_include(<pinDefinitions.h>) +#include <pinDefinitions.h> +#endif +#endif +#endif + /*! @brief NeoPixel constructor when length, pin and pixel type are known at compile-time. @@ -69,11 +77,21 @@ pixel. @return Adafruit_NeoPixel object. Call the begin() function before use. */ -Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint16_t p, neoPixelType t) : - begun(false), brightness(0), pixels(NULL), endTime(0) { +Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, int16_t p, neoPixelType t) + : begun(false), brightness(0), pixels(NULL), endTime(0) { updateType(t); updateLength(n); setPin(p); +#if defined(ARDUINO_ARCH_RP2040) + // Find a free SM on one of the PIO's + sm = pio_claim_unused_sm(pio, false); // don't panic + // Try pio1 if SM not found + if (sm < 0) { + pio = pio1; + sm = pio_claim_unused_sm(pio, true); // panic if no SM is free + } + init = true; +#endif } /*! @@ -86,12 +104,13 @@ Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, uint16_t p, neoPixelType t) : 'new' keyword with the first constructor syntax (length, pin, type). */ -Adafruit_NeoPixel::Adafruit_NeoPixel() : +Adafruit_NeoPixel::Adafruit_NeoPixel() + : #if defined(NEO_KHZ400) - is800KHz(true), + is800KHz(true), #endif - begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), pixels(NULL), - rOffset(1), gOffset(0), bOffset(2), wOffset(1), endTime(0) { + begun(false), numLEDs(0), numBytes(0), pin(-1), brightness(0), + pixels(NULL), rOffset(1), gOffset(0), bOffset(2), wOffset(1), endTime(0) { } /*! @@ -99,14 +118,15 @@ Adafruit_NeoPixel::Adafruit_NeoPixel() : */ Adafruit_NeoPixel::~Adafruit_NeoPixel() { free(pixels); - if(pin >= 0) pinMode(pin, INPUT); + if (pin >= 0) + pinMode(pin, INPUT); } /*! @brief Configure NeoPixel pin for output. */ void Adafruit_NeoPixel::begin(void) { - if(pin >= 0) { + if (pin >= 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } @@ -128,7 +148,7 @@ void Adafruit_NeoPixel::updateLength(uint16_t n) { // Allocate new data -- note: ALL PIXELS ARE CLEARED numBytes = n * ((wOffset == rOffset) ? 3 : 4); - if((pixels = (uint8_t *)malloc(numBytes))) { + if ((pixels = (uint8_t *)malloc(numBytes))) { memset(pixels, 0, numBytes); numLEDs = n; } else { @@ -159,36 +179,71 @@ void Adafruit_NeoPixel::updateType(neoPixelType t) { wOffset = (t >> 6) & 0b11; // See notes in header file rOffset = (t >> 4) & 0b11; // regarding R/G/B/W offsets gOffset = (t >> 2) & 0b11; - bOffset = t & 0b11; + bOffset = t & 0b11; #if defined(NEO_KHZ400) - is800KHz = (t < 256); // 400 KHz flag is 1<<8 + is800KHz = (t < 256); // 400 KHz flag is 1<<8 #endif // If bytes-per-pixel has changed (and pixel data was previously // allocated), re-allocate to new size. Will clear any data. - if(pixels) { + if (pixels) { bool newThreeBytesPerPixel = (wOffset == rOffset); - if(newThreeBytesPerPixel != oldThreeBytesPerPixel) updateLength(numLEDs); + if (newThreeBytesPerPixel != oldThreeBytesPerPixel) + updateLength(numLEDs); + } +} + +// RP2040 specific driver +#if defined(ARDUINO_ARCH_RP2040) +void Adafruit_NeoPixel::rp2040Init(uint8_t pin, bool is800KHz) +{ + uint offset = pio_add_program(pio, &ws2812_program); + + if (is800KHz) + { + // 800kHz, 8 bit transfers + ws2812_program_init(pio, sm, offset, pin, 800000, 8); + } + else + { + // 400kHz, 8 bit transfers + ws2812_program_init(pio, sm, offset, pin, 400000, 8); } } +// Not a user API +void Adafruit_NeoPixel::rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) +{ + if (this->init) + { + // On first pass through initialise the PIO + rp2040Init(pin, is800KHz); + this->init = false; + } + + while(numBytes--) + // Bits for transmission must be shifted to top 8 bits + pio_sm_put_blocking(pio, sm, ((uint32_t)*pixels++)<< 24); +} + +#endif #if defined(ESP8266) // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution -extern "C" void ICACHE_RAM_ATTR espShow( - uint16_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); +extern "C" IRAM_ATTR void espShow(uint16_t pin, uint8_t *pixels, + uint32_t numBytes, uint8_t type); #elif defined(ESP32) -extern "C" void espShow( - uint16_t pin, uint8_t *pixels, uint32_t numBytes, uint8_t type); +extern "C" void espShow(uint16_t pin, uint8_t *pixels, uint32_t numBytes, + uint8_t type); #endif // ESP8266 -#if defined(K210) +#if defined(K210) #define KENDRYTE_K210 1 #endif #if defined(KENDRYTE_K210) -extern "C" void k210Show( - uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz); -#endif //KENDRYTE_K210 +extern "C" void k210Show(uint8_t pin, uint8_t *pixels, uint32_t numBytes, + boolean is800KHz); +#endif // KENDRYTE_K210 /*! @brief Transmit pixel data in RAM to NeoPixels. @note On most architectures, interrupts are temporarily disabled in @@ -202,7 +257,8 @@ extern "C" void k210Show( */ void Adafruit_NeoPixel::show(void) { - if(!pixels) return; + if (!pixels) + return; // Data latch = 300+ microsecond pause in the output stream. Rather than // put a delay at the end of the function, the ending time is noted and @@ -210,36 +266,35 @@ void Adafruit_NeoPixel::show(void) { // subsequent round of data until the latch time has elapsed. This // allows the mainline code to start generating the next frame of data // rather than stalling for the latch. - while(!canShow()); - // endTime is a private member (rather than global var) so that multiple - // instances on different pins can be quickly issued in succession (each - // instance doesn't delay the next). - - // In order to make this code runtime-configurable to work with any pin, - // SBI/CBI instructions are eschewed in favor of full PORT writes via the - // OUT or ST instructions. It relies on two facts: that peripheral - // functions (such as PWM) take precedence on output pins, so our PORT- - // wide writes won't interfere, and that interrupts are globally disabled - // while data is being issued to the LEDs, so no other code will be - // accessing the PORT. The code takes an initial 'snapshot' of the PORT - // state, computes 'pin high' and 'pin low' values, and writes these back - // to the PORT register as needed. - - // NRF52 may use PWM + DMA (if available), may not need to disable interrupt -#if !( defined(NRF52) || defined(NRF52_SERIES) ) + while (!canShow()) + ; + // endTime is a private member (rather than global var) so that multiple + // instances on different pins can be quickly issued in succession (each + // instance doesn't delay the next). + + // In order to make this code runtime-configurable to work with any pin, + // SBI/CBI instructions are eschewed in favor of full PORT writes via the + // OUT or ST instructions. It relies on two facts: that peripheral + // functions (such as PWM) take precedence on output pins, so our PORT- + // wide writes won't interfere, and that interrupts are globally disabled + // while data is being issued to the LEDs, so no other code will be + // accessing the PORT. The code takes an initial 'snapshot' of the PORT + // state, computes 'pin high' and 'pin low' values, and writes these back + // to the PORT register as needed. + + // NRF52 may use PWM + DMA (if available), may not need to disable interrupt +#if !(defined(NRF52) || defined(NRF52_SERIES)) noInterrupts(); // Need 100% focus on instruction timing #endif #if defined(__AVR__) -// AVR MCUs -- ATmega & ATtiny (no XMEGA) --------------------------------- + // AVR MCUs -- ATmega & ATtiny (no XMEGA) --------------------------------- - volatile uint16_t - i = numBytes; // Loop counter - volatile uint8_t - *ptr = pixels, // Pointer to next byte - b = *ptr++, // Current byte value - hi, // PORT w/output bit set high - lo; // PORT w/output bit set low + volatile uint16_t i = numBytes; // Loop counter + volatile uint8_t *ptr = pixels, // Pointer to next byte + b = *ptr++, // Current byte value + hi, // PORT w/output bit set high + lo; // PORT w/output bit set low // Hand-tuned assembly code issues data to the LED drivers at a specific // rate. There's separate code for different CPU speeds (8, 12, 16 MHz) @@ -259,10 +314,10 @@ void Adafruit_NeoPixel::show(void) { #if (F_CPU >= 7400000UL) && (F_CPU <= 9500000UL) #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - volatile uint8_t n1, n2 = 0; // First, next bits out + volatile uint8_t n1, n2 = 0; // First, next bits out // Squeezing an 800 KHz stream out of an 8 MHz chip requires code // specific to each PORT register. @@ -273,14 +328,15 @@ void Adafruit_NeoPixel::show(void) { // PORTD OUTPUT ---------------------------------------------------- #if defined(PORTD) - #if defined(PORTB) || defined(PORTC) || defined(PORTF) - if(port == &PORTD) { - #endif // defined(PORTB/C/F) +#if defined(PORTB) || defined(PORTC) || defined(PORTF) + if (port == &PORTD) { +#endif // defined(PORTB/C/F) - hi = PORTD | pinMask; + hi = PORTD | pinMask; lo = PORTD & ~pinMask; n1 = lo; - if(b & 0x80) n1 = hi; + if (b & 0x80) + n1 = hi; // Dirty trick: RJMPs proceeding to the next instruction are used // to delay two clock cycles in one instruction word (rather than @@ -289,360 +345,618 @@ void Adafruit_NeoPixel::show(void) { // relative branch. asm volatile( - "headD:" "\n\t" // Clk Pseudocode - // Bit 7: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 6" "\n\t" // 1-2 if(b & 0x40) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 6: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 5" "\n\t" // 1-2 if(b & 0x20) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 5: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 4" "\n\t" // 1-2 if(b & 0x10) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 4: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 3" "\n\t" // 1-2 if(b & 0x08) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 3: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 2" "\n\t" // 1-2 if(b & 0x04) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 2: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 1" "\n\t" // 1-2 if(b & 0x02) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "rjmp .+0" "\n\t" // 2 nop nop - // Bit 1: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n2] , %[lo]" "\n\t" // 1 n2 = lo - "out %[port] , %[n1]" "\n\t" // 1 PORT = n1 - "rjmp .+0" "\n\t" // 2 nop nop - "sbrc %[byte] , 0" "\n\t" // 1-2 if(b & 0x01) - "mov %[n2] , %[hi]" "\n\t" // 0-1 n2 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "sbiw %[count], 1" "\n\t" // 2 i-- (don't act on Z flag yet) - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi - "mov %[n1] , %[lo]" "\n\t" // 1 n1 = lo - "out %[port] , %[n2]" "\n\t" // 1 PORT = n2 - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) - "mov %[n1] , %[hi]" "\n\t" // 0-1 n1 = hi - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo - "brne headD" "\n" // 2 while(i) (Z flag set above) - : [byte] "+r" (b), - [n1] "+r" (n1), - [n2] "+r" (n2), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTB) || defined(PORTC) || defined(PORTF) + "headD:" + "\n\t" // Clk Pseudocode + // Bit 7: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" + "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" + "\n\t" // 1 PORT = n1 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 6" + "\n\t" // 1-2 if(b & 0x40) + "mov %[n2] , %[hi]" + "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 6: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" + "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" + "\n\t" // 1 PORT = n2 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 5" + "\n\t" // 1-2 if(b & 0x20) + "mov %[n1] , %[hi]" + "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 5: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" + "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" + "\n\t" // 1 PORT = n1 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 4" + "\n\t" // 1-2 if(b & 0x10) + "mov %[n2] , %[hi]" + "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 4: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" + "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" + "\n\t" // 1 PORT = n2 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 3" + "\n\t" // 1-2 if(b & 0x08) + "mov %[n1] , %[hi]" + "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 3: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" + "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" + "\n\t" // 1 PORT = n1 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 2" + "\n\t" // 1-2 if(b & 0x04) + "mov %[n2] , %[hi]" + "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 2: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" + "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" + "\n\t" // 1 PORT = n2 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 1" + "\n\t" // 1-2 if(b & 0x02) + "mov %[n1] , %[hi]" + "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "rjmp .+0" + "\n\t" // 2 nop nop + // Bit 1: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n2] , %[lo]" + "\n\t" // 1 n2 = lo + "out %[port] , %[n1]" + "\n\t" // 1 PORT = n1 + "rjmp .+0" + "\n\t" // 2 nop nop + "sbrc %[byte] , 0" + "\n\t" // 1-2 if(b & 0x01) + "mov %[n2] , %[hi]" + "\n\t" // 0-1 n2 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "sbiw %[count], 1" + "\n\t" // 2 i-- (don't act on Z flag yet) + // Bit 0: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi + "mov %[n1] , %[lo]" + "\n\t" // 1 n1 = lo + "out %[port] , %[n2]" + "\n\t" // 1 PORT = n2 + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ + "sbrc %[byte] , 7" + "\n\t" // 1-2 if(b & 0x80) + "mov %[n1] , %[hi]" + "\n\t" // 0-1 n1 = hi + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo + "brne headD" + "\n" // 2 while(i) (Z flag set above) + : [byte] "+r"(b), [n1] "+r"(n1), [n2] "+r"(n2), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTD)), [ptr] "e"(ptr), [hi] "r"(hi), + [lo] "r"(lo)); + +#if defined(PORTB) || defined(PORTC) || defined(PORTF) } else // other PORT(s) - #endif // defined(PORTB/C/F) +#endif // defined(PORTB/C/F) #endif // defined(PORTD) // PORTB OUTPUT ---------------------------------------------------- #if defined(PORTB) - #if defined(PORTD) || defined(PORTC) || defined(PORTF) - if(port == &PORTB) { - #endif // defined(PORTD/C/F) +#if defined(PORTD) || defined(PORTC) || defined(PORTF) + if (port == &PORTB) { +#endif // defined(PORTD/C/F) // Same as above, just switched to PORTB and stripped of comments. - hi = PORTB | pinMask; + hi = PORTB | pinMask; lo = PORTB & ~pinMask; n1 = lo; - if(b & 0x80) n1 = hi; + if (b & 0x80) + n1 = hi; asm volatile( - "headB:" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 6" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 5" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 4" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 3" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 2" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 1" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 0" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "brne headB" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTC) || defined(PORTF) + "headB:" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 6" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 5" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 4" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 3" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 2" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 1" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 0" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "brne headB" + "\n" + : [byte] "+r"(b), [n1] "+r"(n1), [n2] "+r"(n2), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTB)), [ptr] "e"(ptr), [hi] "r"(hi), + [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTC) || defined(PORTF) } - #endif - #if defined(PORTC) || defined(PORTF) +#endif +#if defined(PORTC) || defined(PORTF) else - #endif // defined(PORTC/F) +#endif // defined(PORTC/F) #endif // defined(PORTB) // PORTC OUTPUT ---------------------------------------------------- #if defined(PORTC) - #if defined(PORTD) || defined(PORTB) || defined(PORTF) - if(port == &PORTC) { - #endif // defined(PORTD/B/F) +#if defined(PORTD) || defined(PORTB) || defined(PORTF) + if (port == &PORTC) { +#endif // defined(PORTD/B/F) // Same as above, just switched to PORTC and stripped of comments. - hi = PORTC | pinMask; + hi = PORTC | pinMask; lo = PORTC & ~pinMask; n1 = lo; - if(b & 0x80) n1 = hi; + if (b & 0x80) + n1 = hi; asm volatile( - "headC:" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 6" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 5" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 4" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 3" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 2" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 1" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 0" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "brne headC" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTB) || defined(PORTF) + "headC:" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 6" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 5" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 4" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 3" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 2" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 1" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 0" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "brne headC" + "\n" + : [byte] "+r"(b), [n1] "+r"(n1), [n2] "+r"(n2), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTC)), [ptr] "e"(ptr), [hi] "r"(hi), + [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTB) || defined(PORTF) } - #endif // defined(PORTD/B/F) - #if defined(PORTF) +#endif // defined(PORTD/B/F) +#if defined(PORTF) else - #endif +#endif #endif // defined(PORTC) // PORTF OUTPUT ---------------------------------------------------- #if defined(PORTF) - #if defined(PORTD) || defined(PORTB) || defined(PORTC) - if(port == &PORTF) { - #endif // defined(PORTD/B/C) +#if defined(PORTD) || defined(PORTB) || defined(PORTC) + if (port == &PORTF) { +#endif // defined(PORTD/B/C) - hi = PORTF | pinMask; + hi = PORTF | pinMask; lo = PORTF & ~pinMask; n1 = lo; - if(b & 0x80) n1 = hi; + if (b & 0x80) + n1 = hi; asm volatile( - "headF:" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 6" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 5" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 4" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 3" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 2" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 1" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "rjmp .+0" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n2] , %[lo]" "\n\t" - "out %[port] , %[n1]" "\n\t" - "rjmp .+0" "\n\t" - "sbrc %[byte] , 0" "\n\t" - "mov %[n2] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "out %[port] , %[hi]" "\n\t" - "mov %[n1] , %[lo]" "\n\t" - "out %[port] , %[n2]" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[n1] , %[hi]" "\n\t" - "out %[port] , %[lo]" "\n\t" - "brne headF" "\n" - : [byte] "+r" (b), [n1] "+r" (n1), [n2] "+r" (n2), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTB) || defined(PORTC) + "headF:" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 6" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 5" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 4" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 3" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 2" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 1" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "rjmp .+0" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n2] , %[lo]" + "\n\t" + "out %[port] , %[n1]" + "\n\t" + "rjmp .+0" + "\n\t" + "sbrc %[byte] , 0" + "\n\t" + "mov %[n2] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "mov %[n1] , %[lo]" + "\n\t" + "out %[port] , %[n2]" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[n1] , %[hi]" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "brne headF" + "\n" + : [byte] "+r"(b), [n1] "+r"(n1), [n2] "+r"(n2), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTF)), [ptr] "e"(ptr), [hi] "r"(hi), + [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTB) || defined(PORTC) } - #endif // defined(PORTD/B/C) +#endif // defined(PORTD/B/C) #endif // defined(PORTF) #if defined(NEO_KHZ400) @@ -660,41 +974,56 @@ void Adafruit_NeoPixel::show(void) { volatile uint8_t next, bit; - hi = *port | pinMask; - lo = *port & ~pinMask; + hi = *port | pinMask; + lo = *port & ~pinMask; next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "dec %[bit]" "\n\t" // 1 bit-- (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 14) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); + bit = 8; + + asm volatile("head20:" + "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" + "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" + "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" + "\n\t" // 0-1 next = hi (T = 4) + "st %a[port], %[next]" + "\n\t" // 2 PORT = next (T = 6) + "mov %[next] , %[lo]" + "\n\t" // 1 next = lo (T = 7) + "dec %[bit]" + "\n\t" // 1 bit-- (T = 8) + "breq nextbyte20" + "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" + "\n\t" // 1 b <<= 1 (T = 10) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 12) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 18) + "rjmp head20" + "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" + "\n\t" // (T = 10) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 12) + "nop" + "\n\t" // 1 nop (T = 13) + "ldi %[bit] , 8" + "\n\t" // 1 bit = 8 (T = 14) + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ (T = 16) + "sbiw %[count], 1" + "\n\t" // 2 i-- (T = 18) + "brne head20" + "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e"(port), [byte] "+r"(b), [bit] "+r"(bit), + [next] "+r"(next), [count] "+w"(i) + : [hi] "r"(hi), [lo] "r"(lo), [ptr] "e"(ptr)); } #endif // NEO_KHZ400 @@ -702,7 +1031,7 @@ void Adafruit_NeoPixel::show(void) { #elif (F_CPU >= 11100000UL) && (F_CPU <= 14300000UL) #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif // In the 12 MHz case, an optimized 800 KHz datastream (no dead time @@ -717,253 +1046,397 @@ void Adafruit_NeoPixel::show(void) { // PORTD OUTPUT ---------------------------------------------------- #if defined(PORTD) - #if defined(PORTB) || defined(PORTC) || defined(PORTF) - if(port == &PORTD) { - #endif // defined(PORTB/C/F) +#if defined(PORTB) || defined(PORTC) || defined(PORTF) + if (port == &PORTD) { +#endif // defined(PORTB/C/F) - hi = PORTD | pinMask; - lo = PORTD & ~pinMask; + hi = PORTD | pinMask; + lo = PORTD & ~pinMask; next = lo; - if(b & 0x80) next = hi; + if (b & 0x80) + next = hi; // Don't "optimize" the OUT calls into the bitTime subroutine; // we're exploiting the RCALL and RET as 3- and 4-cycle NOPs! - asm volatile( - "headD:" "\n\t" // (T = 0) - "out %[port], %[hi]" "\n\t" // (T = 1) - "rcall bitTimeD" "\n\t" // Bit 7 (T = 15) - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 6 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 5 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 4 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 3 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 2 - "out %[port], %[hi]" "\n\t" - "rcall bitTimeD" "\n\t" // Bit 1 - // Bit 0: - "out %[port] , %[hi]" "\n\t" // 1 PORT = hi (T = 1) - "rjmp .+0" "\n\t" // 2 nop nop (T = 3) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 5) - "out %[port] , %[next]" "\n\t" // 1 PORT = next (T = 6) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 7) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port] , %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 13) - "brne headD" "\n\t" // 2 if(i != 0) -> (next byte) - "rjmp doneD" "\n\t" - "bitTimeD:" "\n\t" // nop nop nop (T = 4) - "out %[port], %[next]" "\n\t" // 1 PORT = next (T = 5) - "mov %[next], %[lo]" "\n\t" // 1 next = lo (T = 6) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 7) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 0x80) (T = 8) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 9) - "nop" "\n\t" // 1 (T = 10) - "out %[port], %[lo]" "\n\t" // 1 PORT = lo (T = 11) - "ret" "\n\t" // 4 nop nop nop nop (T = 15) - "doneD:" "\n" - : [byte] "+r" (b), - [next] "+r" (next), - [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTD)), - [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTB) || defined(PORTC) || defined(PORTF) + asm volatile("headD:" + "\n\t" // (T = 0) + "out %[port], %[hi]" + "\n\t" // (T = 1) + "rcall bitTimeD" + "\n\t" // Bit 7 (T = 15) + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 6 + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 5 + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 4 + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 3 + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 2 + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeD" + "\n\t" // Bit 1 + // Bit 0: + "out %[port] , %[hi]" + "\n\t" // 1 PORT = hi (T = 1) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 3) + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ (T = 5) + "out %[port] , %[next]" + "\n\t" // 1 PORT = next (T = 6) + "mov %[next] , %[lo]" + "\n\t" // 1 next = lo (T = 7) + "sbrc %[byte] , 7" + "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next] , %[hi]" + "\n\t" // 0-1 next = hi (T = 9) + "nop" + "\n\t" // 1 (T = 10) + "out %[port] , %[lo]" + "\n\t" // 1 PORT = lo (T = 11) + "sbiw %[count], 1" + "\n\t" // 2 i-- (T = 13) + "brne headD" + "\n\t" // 2 if(i != 0) -> (next byte) + "rjmp doneD" + "\n\t" + "bitTimeD:" + "\n\t" // nop nop nop (T = 4) + "out %[port], %[next]" + "\n\t" // 1 PORT = next (T = 5) + "mov %[next], %[lo]" + "\n\t" // 1 next = lo (T = 6) + "rol %[byte]" + "\n\t" // 1 b <<= 1 (T = 7) + "sbrc %[byte], 7" + "\n\t" // 1-2 if(b & 0x80) (T = 8) + "mov %[next], %[hi]" + "\n\t" // 0-1 next = hi (T = 9) + "nop" + "\n\t" // 1 (T = 10) + "out %[port], %[lo]" + "\n\t" // 1 PORT = lo (T = 11) + "ret" + "\n\t" // 4 nop nop nop nop (T = 15) + "doneD:" + "\n" + : [byte] "+r"(b), [next] "+r"(next), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTD)), [ptr] "e"(ptr), + [hi] "r"(hi), [lo] "r"(lo)); + +#if defined(PORTB) || defined(PORTC) || defined(PORTF) } else // other PORT(s) - #endif // defined(PORTB/C/F) +#endif // defined(PORTB/C/F) #endif // defined(PORTD) // PORTB OUTPUT ---------------------------------------------------- #if defined(PORTB) - #if defined(PORTD) || defined(PORTC) || defined(PORTF) - if(port == &PORTB) { - #endif // defined(PORTD/C/F) +#if defined(PORTD) || defined(PORTC) || defined(PORTF) + if (port == &PORTB) { +#endif // defined(PORTD/C/F) - hi = PORTB | pinMask; - lo = PORTB & ~pinMask; + hi = PORTB | pinMask; + lo = PORTB & ~pinMask; next = lo; - if(b & 0x80) next = hi; + if (b & 0x80) + next = hi; // Same as above, just set for PORTB & stripped of comments - asm volatile( - "headB:" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeB" "\n\t" - "out %[port] , %[hi]" "\n\t" - "rjmp .+0" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "out %[port] , %[next]" "\n\t" - "mov %[next] , %[lo]" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[next] , %[hi]" "\n\t" - "nop" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "brne headB" "\n\t" - "rjmp doneB" "\n\t" - "bitTimeB:" "\n\t" - "out %[port], %[next]" "\n\t" - "mov %[next], %[lo]" "\n\t" - "rol %[byte]" "\n\t" - "sbrc %[byte], 7" "\n\t" - "mov %[next], %[hi]" "\n\t" - "nop" "\n\t" - "out %[port], %[lo]" "\n\t" - "ret" "\n\t" - "doneB:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTB)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTC) || defined(PORTF) + asm volatile("headB:" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeB" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "rjmp .+0" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "out %[port] , %[next]" + "\n\t" + "mov %[next] , %[lo]" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[next] , %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "brne headB" + "\n\t" + "rjmp doneB" + "\n\t" + "bitTimeB:" + "\n\t" + "out %[port], %[next]" + "\n\t" + "mov %[next], %[lo]" + "\n\t" + "rol %[byte]" + "\n\t" + "sbrc %[byte], 7" + "\n\t" + "mov %[next], %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port], %[lo]" + "\n\t" + "ret" + "\n\t" + "doneB:" + "\n" + : [byte] "+r"(b), [next] "+r"(next), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTB)), [ptr] "e"(ptr), + [hi] "r"(hi), [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTC) || defined(PORTF) } - #endif - #if defined(PORTC) || defined(PORTF) +#endif +#if defined(PORTC) || defined(PORTF) else - #endif // defined(PORTC/F) +#endif // defined(PORTC/F) #endif // defined(PORTB) // PORTC OUTPUT ---------------------------------------------------- #if defined(PORTC) - #if defined(PORTD) || defined(PORTB) || defined(PORTF) - if(port == &PORTC) { - #endif // defined(PORTD/B/F) +#if defined(PORTD) || defined(PORTB) || defined(PORTF) + if (port == &PORTC) { +#endif // defined(PORTD/B/F) - hi = PORTC | pinMask; - lo = PORTC & ~pinMask; + hi = PORTC | pinMask; + lo = PORTC & ~pinMask; next = lo; - if(b & 0x80) next = hi; + if (b & 0x80) + next = hi; // Same as above, just set for PORTC & stripped of comments - asm volatile( - "headC:" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port] , %[hi]" "\n\t" - "rjmp .+0" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "out %[port] , %[next]" "\n\t" - "mov %[next] , %[lo]" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[next] , %[hi]" "\n\t" - "nop" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "brne headC" "\n\t" - "rjmp doneC" "\n\t" - "bitTimeC:" "\n\t" - "out %[port], %[next]" "\n\t" - "mov %[next], %[lo]" "\n\t" - "rol %[byte]" "\n\t" - "sbrc %[byte], 7" "\n\t" - "mov %[next], %[hi]" "\n\t" - "nop" "\n\t" - "out %[port], %[lo]" "\n\t" - "ret" "\n\t" - "doneC:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTC)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTB) || defined(PORTF) + asm volatile("headC:" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "rjmp .+0" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "out %[port] , %[next]" + "\n\t" + "mov %[next] , %[lo]" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[next] , %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "brne headC" + "\n\t" + "rjmp doneC" + "\n\t" + "bitTimeC:" + "\n\t" + "out %[port], %[next]" + "\n\t" + "mov %[next], %[lo]" + "\n\t" + "rol %[byte]" + "\n\t" + "sbrc %[byte], 7" + "\n\t" + "mov %[next], %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port], %[lo]" + "\n\t" + "ret" + "\n\t" + "doneC:" + "\n" + : [byte] "+r"(b), [next] "+r"(next), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTC)), [ptr] "e"(ptr), + [hi] "r"(hi), [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTB) || defined(PORTF) } - #endif // defined(PORTD/B/F) - #if defined(PORTF) +#endif // defined(PORTD/B/F) +#if defined(PORTF) else - #endif +#endif #endif // defined(PORTC) // PORTF OUTPUT ---------------------------------------------------- #if defined(PORTF) - #if defined(PORTD) || defined(PORTB) || defined(PORTC) - if(port == &PORTF) { - #endif // defined(PORTD/B/C) +#if defined(PORTD) || defined(PORTB) || defined(PORTC) + if (port == &PORTF) { +#endif // defined(PORTD/B/C) - hi = PORTF | pinMask; - lo = PORTF & ~pinMask; + hi = PORTF | pinMask; + lo = PORTF & ~pinMask; next = lo; - if(b & 0x80) next = hi; + if (b & 0x80) + next = hi; // Same as above, just set for PORTF & stripped of comments - asm volatile( - "headF:" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port], %[hi]" "\n\t" - "rcall bitTimeC" "\n\t" - "out %[port] , %[hi]" "\n\t" - "rjmp .+0" "\n\t" - "ld %[byte] , %a[ptr]+" "\n\t" - "out %[port] , %[next]" "\n\t" - "mov %[next] , %[lo]" "\n\t" - "sbrc %[byte] , 7" "\n\t" - "mov %[next] , %[hi]" "\n\t" - "nop" "\n\t" - "out %[port] , %[lo]" "\n\t" - "sbiw %[count], 1" "\n\t" - "brne headF" "\n\t" - "rjmp doneC" "\n\t" - "bitTimeC:" "\n\t" - "out %[port], %[next]" "\n\t" - "mov %[next], %[lo]" "\n\t" - "rol %[byte]" "\n\t" - "sbrc %[byte], 7" "\n\t" - "mov %[next], %[hi]" "\n\t" - "nop" "\n\t" - "out %[port], %[lo]" "\n\t" - "ret" "\n\t" - "doneC:" "\n" - : [byte] "+r" (b), [next] "+r" (next), [count] "+w" (i) - : [port] "I" (_SFR_IO_ADDR(PORTF)), [ptr] "e" (ptr), [hi] "r" (hi), - [lo] "r" (lo)); - - #if defined(PORTD) || defined(PORTB) || defined(PORTC) + asm volatile("headF:" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port], %[hi]" + "\n\t" + "rcall bitTimeC" + "\n\t" + "out %[port] , %[hi]" + "\n\t" + "rjmp .+0" + "\n\t" + "ld %[byte] , %a[ptr]+" + "\n\t" + "out %[port] , %[next]" + "\n\t" + "mov %[next] , %[lo]" + "\n\t" + "sbrc %[byte] , 7" + "\n\t" + "mov %[next] , %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port] , %[lo]" + "\n\t" + "sbiw %[count], 1" + "\n\t" + "brne headF" + "\n\t" + "rjmp doneC" + "\n\t" + "bitTimeC:" + "\n\t" + "out %[port], %[next]" + "\n\t" + "mov %[next], %[lo]" + "\n\t" + "rol %[byte]" + "\n\t" + "sbrc %[byte], 7" + "\n\t" + "mov %[next], %[hi]" + "\n\t" + "nop" + "\n\t" + "out %[port], %[lo]" + "\n\t" + "ret" + "\n\t" + "doneC:" + "\n" + : [byte] "+r"(b), [next] "+r"(next), [count] "+w"(i) + : [port] "I"(_SFR_IO_ADDR(PORTF)), [ptr] "e"(ptr), + [hi] "r"(hi), [lo] "r"(lo)); + +#if defined(PORTD) || defined(PORTB) || defined(PORTC) } - #endif // defined(PORTD/B/C) +#endif // defined(PORTD/B/C) #endif // defined(PORTF) #if defined(NEO_KHZ400) @@ -974,45 +1447,64 @@ void Adafruit_NeoPixel::show(void) { volatile uint8_t next, bit; - hi = *port | pinMask; - lo = *port & ~pinMask; + hi = *port | pinMask; + lo = *port & ~pinMask; next = lo; - bit = 8; - - asm volatile( - "head30:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 8) - "rjmp .+0" "\n\t" // 2 nop nop (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "nop" "\n\t" // 1 nop (T = 15) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 17) - "rjmp .+0" "\n\t" // 2 nop nop (T = 19) - "dec %[bit]" "\n\t" // 1 bit-- (T = 20) - "breq nextbyte30" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 22) - "rjmp .+0" "\n\t" // 2 nop nop (T = 24) - "rjmp .+0" "\n\t" // 2 nop nop (T = 26) - "rjmp .+0" "\n\t" // 2 nop nop (T = 28) - "rjmp head30" "\n\t" // 2 -> head30 (next bit out) - "nextbyte30:" "\n\t" // (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 24) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 26) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 28) - "brne head30" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [hi] "r" (hi), - [lo] "r" (lo), - [ptr] "e" (ptr)); + bit = 8; + + asm volatile("head30:" + "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" + "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" + "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" + "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 6) + "st %a[port], %[next]" + "\n\t" // 2 PORT = next (T = 8) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 10) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 14) + "nop" + "\n\t" // 1 nop (T = 15) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 17) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 19) + "dec %[bit]" + "\n\t" // 1 bit-- (T = 20) + "breq nextbyte30" + "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" + "\n\t" // 1 b <<= 1 (T = 22) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 24) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 26) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 28) + "rjmp head30" + "\n\t" // 2 -> head30 (next bit out) + "nextbyte30:" + "\n\t" // (T = 22) + "nop" + "\n\t" // 1 nop (T = 23) + "ldi %[bit] , 8" + "\n\t" // 1 bit = 8 (T = 24) + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ (T = 26) + "sbiw %[count], 1" + "\n\t" // 2 i-- (T = 28) + "brne head30" + "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e"(port), [byte] "+r"(b), [bit] "+r"(bit), + [next] "+r"(next), [count] "+w"(i) + : [hi] "r"(hi), [lo] "r"(lo), [ptr] "e"(ptr)); } #endif // NEO_KHZ400 @@ -1020,7 +1512,7 @@ void Adafruit_NeoPixel::show(void) { #elif (F_CPU >= 15400000UL) && (F_CPU <= 19000000L) #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif // WS2811 and WS2812 have different hi/lo duty cycles; this is @@ -1031,42 +1523,58 @@ void Adafruit_NeoPixel::show(void) { volatile uint8_t next, bit; - hi = *port | pinMask; - lo = *port & ~pinMask; + hi = *port | pinMask; + lo = *port & ~pinMask; next = lo; - bit = 8; - - asm volatile( - "head20:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte], 7" "\n\t" // 1-2 if(b & 128) - "mov %[next], %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "dec %[bit]" "\n\t" // 1 bit-- (T = 5) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 7) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 8) - "breq nextbyte20" "\n\t" // 1-2 if(bit == 0) (from dec above) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "nop" "\n\t" // 1 nop (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp head20" "\n\t" // 2 -> head20 (next bit out) - "nextbyte20:" "\n\t" // (T = 10) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 11) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 13) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 15) - "nop" "\n\t" // 1 nop (T = 16) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 18) - "brne head20" "\n" // 2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); + bit = 8; + + asm volatile("head20:" + "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" + "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte], 7" + "\n\t" // 1-2 if(b & 128) + "mov %[next], %[hi]" + "\n\t" // 0-1 next = hi (T = 4) + "dec %[bit]" + "\n\t" // 1 bit-- (T = 5) + "st %a[port], %[next]" + "\n\t" // 2 PORT = next (T = 7) + "mov %[next] , %[lo]" + "\n\t" // 1 next = lo (T = 8) + "breq nextbyte20" + "\n\t" // 1-2 if(bit == 0) (from dec above) + "rol %[byte]" + "\n\t" // 1 b <<= 1 (T = 10) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 12) + "nop" + "\n\t" // 1 nop (T = 13) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 15) + "nop" + "\n\t" // 1 nop (T = 16) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 18) + "rjmp head20" + "\n\t" // 2 -> head20 (next bit out) + "nextbyte20:" + "\n\t" // (T = 10) + "ldi %[bit] , 8" + "\n\t" // 1 bit = 8 (T = 11) + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ (T = 13) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 15) + "nop" + "\n\t" // 1 nop (T = 16) + "sbiw %[count], 1" + "\n\t" // 2 i-- (T = 18) + "brne head20" + "\n" // 2 if(i != 0) -> (next byte) + : [port] "+e"(port), [byte] "+r"(b), [bit] "+r"(bit), + [next] "+r"(next), [count] "+w"(i) + : [ptr] "e"(ptr), [hi] "r"(hi), [lo] "r"(lo)); #if defined(NEO_KHZ400) } else { // 400 KHz @@ -1078,269 +1586,368 @@ void Adafruit_NeoPixel::show(void) { volatile uint8_t next, bit; - hi = *port | pinMask; - lo = *port & ~pinMask; + hi = *port | pinMask; + lo = *port & ~pinMask; next = lo; - bit = 8; - - asm volatile( - "head40:" "\n\t" // Clk Pseudocode (T = 0) - "st %a[port], %[hi]" "\n\t" // 2 PORT = hi (T = 2) - "sbrc %[byte] , 7" "\n\t" // 1-2 if(b & 128) - "mov %[next] , %[hi]" "\n\t" // 0-1 next = hi (T = 4) - "rjmp .+0" "\n\t" // 2 nop nop (T = 6) - "rjmp .+0" "\n\t" // 2 nop nop (T = 8) - "st %a[port], %[next]" "\n\t" // 2 PORT = next (T = 10) - "rjmp .+0" "\n\t" // 2 nop nop (T = 12) - "rjmp .+0" "\n\t" // 2 nop nop (T = 14) - "rjmp .+0" "\n\t" // 2 nop nop (T = 16) - "rjmp .+0" "\n\t" // 2 nop nop (T = 18) - "rjmp .+0" "\n\t" // 2 nop nop (T = 20) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 22) - "nop" "\n\t" // 1 nop (T = 23) - "mov %[next] , %[lo]" "\n\t" // 1 next = lo (T = 24) - "dec %[bit]" "\n\t" // 1 bit-- (T = 25) - "breq nextbyte40" "\n\t" // 1-2 if(bit == 0) - "rol %[byte]" "\n\t" // 1 b <<= 1 (T = 27) - "nop" "\n\t" // 1 nop (T = 28) - "rjmp .+0" "\n\t" // 2 nop nop (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "rjmp .+0" "\n\t" // 2 nop nop (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "rjmp .+0" "\n\t" // 2 nop nop (T = 38) - "rjmp head40" "\n\t" // 2 -> head40 (next bit out) - "nextbyte40:" "\n\t" // (T = 27) - "ldi %[bit] , 8" "\n\t" // 1 bit = 8 (T = 28) - "ld %[byte] , %a[ptr]+" "\n\t" // 2 b = *ptr++ (T = 30) - "rjmp .+0" "\n\t" // 2 nop nop (T = 32) - "st %a[port], %[lo]" "\n\t" // 2 PORT = lo (T = 34) - "rjmp .+0" "\n\t" // 2 nop nop (T = 36) - "sbiw %[count], 1" "\n\t" // 2 i-- (T = 38) - "brne head40" "\n" // 1-2 if(i != 0) -> (next byte) - : [port] "+e" (port), - [byte] "+r" (b), - [bit] "+r" (bit), - [next] "+r" (next), - [count] "+w" (i) - : [ptr] "e" (ptr), - [hi] "r" (hi), - [lo] "r" (lo)); + bit = 8; + + asm volatile("head40:" + "\n\t" // Clk Pseudocode (T = 0) + "st %a[port], %[hi]" + "\n\t" // 2 PORT = hi (T = 2) + "sbrc %[byte] , 7" + "\n\t" // 1-2 if(b & 128) + "mov %[next] , %[hi]" + "\n\t" // 0-1 next = hi (T = 4) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 6) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 8) + "st %a[port], %[next]" + "\n\t" // 2 PORT = next (T = 10) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 12) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 14) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 16) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 18) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 20) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 22) + "nop" + "\n\t" // 1 nop (T = 23) + "mov %[next] , %[lo]" + "\n\t" // 1 next = lo (T = 24) + "dec %[bit]" + "\n\t" // 1 bit-- (T = 25) + "breq nextbyte40" + "\n\t" // 1-2 if(bit == 0) + "rol %[byte]" + "\n\t" // 1 b <<= 1 (T = 27) + "nop" + "\n\t" // 1 nop (T = 28) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 30) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 32) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 34) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 36) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 38) + "rjmp head40" + "\n\t" // 2 -> head40 (next bit out) + "nextbyte40:" + "\n\t" // (T = 27) + "ldi %[bit] , 8" + "\n\t" // 1 bit = 8 (T = 28) + "ld %[byte] , %a[ptr]+" + "\n\t" // 2 b = *ptr++ (T = 30) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 32) + "st %a[port], %[lo]" + "\n\t" // 2 PORT = lo (T = 34) + "rjmp .+0" + "\n\t" // 2 nop nop (T = 36) + "sbiw %[count], 1" + "\n\t" // 2 i-- (T = 38) + "brne head40" + "\n" // 1-2 if(i != 0) -> (next byte) + : [port] "+e"(port), [byte] "+r"(b), [bit] "+r"(bit), + [next] "+r"(next), [count] "+w"(i) + : [ptr] "e"(ptr), [hi] "r"(hi), [lo] "r"(lo)); } #endif // NEO_KHZ400 #else - #error "CPU SPEED NOT SUPPORTED" +#error "CPU SPEED NOT SUPPORTED" #endif // end F_CPU ifdefs on __AVR__ -// END AVR ---------------------------------------------------------------- - + // END AVR ---------------------------------------------------------------- #elif defined(__arm__) -// ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due --------------------------- + // ARM MCUs -- Teensy 3.0, 3.1, LC, Arduino Due, RP2040 ------------------- + +#if defined(ARDUINO_ARCH_RP2040) + // Use PIO + rp2040Show(pin, pixels, numBytes, is800KHz); -#if defined(TEENSYDUINO) && defined(KINETISK) // Teensy 3.0, 3.1, 3.2, 3.5, 3.6 -#define CYCLES_800_T0H (F_CPU / 4000000) -#define CYCLES_800_T1H (F_CPU / 1250000) -#define CYCLES_800 (F_CPU / 800000) -#define CYCLES_400_T0H (F_CPU / 2000000) -#define CYCLES_400_T1H (F_CPU / 833333) -#define CYCLES_400 (F_CPU / 400000) +#elif defined(TEENSYDUINO) && \ + defined(KINETISK) // Teensy 3.0, 3.1, 3.2, 3.5, 3.6 +#define CYCLES_800_T0H (F_CPU / 4000000) +#define CYCLES_800_T1H (F_CPU / 1250000) +#define CYCLES_800 (F_CPU / 800000) +#define CYCLES_400_T0H (F_CPU / 2000000) +#define CYCLES_400_T1H (F_CPU / 833333) +#define CYCLES_400 (F_CPU / 400000) - uint8_t *p = pixels, - *end = p + numBytes, pix, mask; - volatile uint8_t *set = portSetRegister(pin), - *clr = portClearRegister(pin); - uint32_t cyc; + uint8_t *p = pixels, *end = p + numBytes, pix, mask; + volatile uint8_t *set = portSetRegister(pin), *clr = portClearRegister(pin); + uint32_t cyc; - ARM_DEMCR |= ARM_DEMCR_TRCENA; + ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif cyc = ARM_DWT_CYCCNT + CYCLES_800; - while(p < end) { + while (p < end) { pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); - cyc = ARM_DWT_CYCCNT; + for (mask = 0x80; mask; mask >>= 1) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_800) + ; + cyc = ARM_DWT_CYCCNT; *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); + if (pix & mask) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H) + ; } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); + while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H) + ; } *clr = 1; } } - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); + while (ARM_DWT_CYCCNT - cyc < CYCLES_800) + ; #if defined(NEO_KHZ400) } else { // 400 kHz bitstream cyc = ARM_DWT_CYCCNT + CYCLES_400; - while(p < end) { + while (p < end) { pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - cyc = ARM_DWT_CYCCNT; + for (mask = 0x80; mask; mask >>= 1) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_400) + ; + cyc = ARM_DWT_CYCCNT; *set = 1; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); + if (pix & mask) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H) + ; } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); + while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H) + ; } *clr = 1; } } - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + while (ARM_DWT_CYCCNT - cyc < CYCLES_400) + ; } #endif // NEO_KHZ400 #elif defined(TEENSYDUINO) && (defined(__IMXRT1052__) || defined(__IMXRT1062__)) -#define CYCLES_800_T0H (F_CPU_ACTUAL / 4000000) -#define CYCLES_800_T1H (F_CPU_ACTUAL / 1250000) -#define CYCLES_800 (F_CPU_ACTUAL / 800000) -#define CYCLES_400_T0H (F_CPU_ACTUAL / 2000000) -#define CYCLES_400_T1H (F_CPU_ACTUAL / 833333) -#define CYCLES_400 (F_CPU_ACTUAL / 400000) - - uint8_t *p = pixels, - *end = p + numBytes, pix, mask; - volatile uint32_t *set = portSetRegister(pin), - *clr = portClearRegister(pin); - uint32_t cyc, - msk = digitalPinToBitMask(pin); - - ARM_DEMCR |= ARM_DEMCR_TRCENA; +#define CYCLES_800_T0H (F_CPU_ACTUAL / 4000000) +#define CYCLES_800_T1H (F_CPU_ACTUAL / 1250000) +#define CYCLES_800 (F_CPU_ACTUAL / 800000) +#define CYCLES_400_T0H (F_CPU_ACTUAL / 2000000) +#define CYCLES_400_T1H (F_CPU_ACTUAL / 833333) +#define CYCLES_400 (F_CPU_ACTUAL / 400000) + + uint8_t *p = pixels, *end = p + numBytes, pix, mask; + volatile uint32_t *set = portSetRegister(pin), *clr = portClearRegister(pin); + uint32_t cyc, msk = digitalPinToBitMask(pin); + + ARM_DEMCR |= ARM_DEMCR_TRCENA; ARM_DWT_CTRL |= ARM_DWT_CTRL_CYCCNTENA; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif cyc = ARM_DWT_CYCCNT + CYCLES_800; - while(p < end) { + while (p < end) { pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); - cyc = ARM_DWT_CYCCNT; + for (mask = 0x80; mask; mask >>= 1) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_800) + ; + cyc = ARM_DWT_CYCCNT; *set = msk; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H); + if (pix & mask) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T1H) + ; } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H); + while (ARM_DWT_CYCCNT - cyc < CYCLES_800_T0H) + ; } *clr = msk; } } - while(ARM_DWT_CYCCNT - cyc < CYCLES_800); + while (ARM_DWT_CYCCNT - cyc < CYCLES_800) + ; #if defined(NEO_KHZ400) } else { // 400 kHz bitstream cyc = ARM_DWT_CYCCNT + CYCLES_400; - while(p < end) { + while (p < end) { pix = *p++; - for(mask = 0x80; mask; mask >>= 1) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); - cyc = ARM_DWT_CYCCNT; + for (mask = 0x80; mask; mask >>= 1) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_400) + ; + cyc = ARM_DWT_CYCCNT; *set = msk; - if(pix & mask) { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H); + if (pix & mask) { + while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T1H) + ; } else { - while(ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H); + while (ARM_DWT_CYCCNT - cyc < CYCLES_400_T0H) + ; } *clr = msk; } } - while(ARM_DWT_CYCCNT - cyc < CYCLES_400); + while (ARM_DWT_CYCCNT - cyc < CYCLES_400) + ; } #endif // NEO_KHZ400 #elif defined(TEENSYDUINO) && defined(__MKL26Z64__) // Teensy-LC #if F_CPU == 48000000 - uint8_t *p = pixels, - pix, count, dly, - bitmask = digitalPinToBitMask(pin); + uint8_t *p = pixels, pix, count, dly, bitmask = digitalPinToBitMask(pin); volatile uint8_t *reg = portSetRegister(pin); - uint32_t num = numBytes; - asm volatile( - "L%=_begin:" "\n\t" - "ldrb %[pix], [%[p], #0]" "\n\t" - "lsl %[pix], #24" "\n\t" - "movs %[count], #7" "\n\t" - "L%=_loop:" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_loop_one" "\n\t" - "L%=_loop_zero:" "\n\t" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T0L" "\n\t" - "b L%=_next" "\n\t" - "L%=_loop_one:" "\n\t" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_loop_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_loop_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_loop_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_next:" "\n\t" - "sub %[count], #1" "\n\t" - "bne L%=_loop" "\n\t" - "lsl %[pix], #1" "\n\t" - "bcs L%=_last_one" "\n\t" - "L%=_last_zero:" "\n\t" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #4" "\n\t" - "L%=_last_delay_T0H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #10" "\n\t" - "L%=_last_delay_T0L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T0L" "\n\t" - "b L%=_repeat" "\n\t" - "L%=_last_one:" "\n\t" - "strb %[bitmask], [%[reg], #0]" "\n\t" - "movs %[dly], #13" "\n\t" - "L%=_last_delay_T1H:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1H" "\n\t" - "strb %[bitmask], [%[reg], #4]" "\n\t" - "movs %[dly], #1" "\n\t" - "L%=_last_delay_T1L:" "\n\t" - "sub %[dly], #1" "\n\t" - "bne L%=_last_delay_T1L" "\n\t" - "nop" "\n\t" - "L%=_repeat:" "\n\t" - "add %[p], #1" "\n\t" - "sub %[num], #1" "\n\t" - "bne L%=_begin" "\n\t" - "L%=_done:" "\n\t" - : [p] "+r" (p), - [pix] "=&r" (pix), - [count] "=&r" (count), - [dly] "=&r" (dly), - [num] "+r" (num) - : [bitmask] "r" (bitmask), - [reg] "r" (reg) - ); + uint32_t num = numBytes; + asm volatile("L%=_begin:" + "\n\t" + "ldrb %[pix], [%[p], #0]" + "\n\t" + "lsl %[pix], #24" + "\n\t" + "movs %[count], #7" + "\n\t" + "L%=_loop:" + "\n\t" + "lsl %[pix], #1" + "\n\t" + "bcs L%=_loop_one" + "\n\t" + "L%=_loop_zero:" + "\n\t" + "strb %[bitmask], [%[reg], #0]" + "\n\t" + "movs %[dly], #4" + "\n\t" + "L%=_loop_delay_T0H:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_loop_delay_T0H" + "\n\t" + "strb %[bitmask], [%[reg], #4]" + "\n\t" + "movs %[dly], #13" + "\n\t" + "L%=_loop_delay_T0L:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_loop_delay_T0L" + "\n\t" + "b L%=_next" + "\n\t" + "L%=_loop_one:" + "\n\t" + "strb %[bitmask], [%[reg], #0]" + "\n\t" + "movs %[dly], #13" + "\n\t" + "L%=_loop_delay_T1H:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_loop_delay_T1H" + "\n\t" + "strb %[bitmask], [%[reg], #4]" + "\n\t" + "movs %[dly], #4" + "\n\t" + "L%=_loop_delay_T1L:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_loop_delay_T1L" + "\n\t" + "nop" + "\n\t" + "L%=_next:" + "\n\t" + "sub %[count], #1" + "\n\t" + "bne L%=_loop" + "\n\t" + "lsl %[pix], #1" + "\n\t" + "bcs L%=_last_one" + "\n\t" + "L%=_last_zero:" + "\n\t" + "strb %[bitmask], [%[reg], #0]" + "\n\t" + "movs %[dly], #4" + "\n\t" + "L%=_last_delay_T0H:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_last_delay_T0H" + "\n\t" + "strb %[bitmask], [%[reg], #4]" + "\n\t" + "movs %[dly], #10" + "\n\t" + "L%=_last_delay_T0L:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_last_delay_T0L" + "\n\t" + "b L%=_repeat" + "\n\t" + "L%=_last_one:" + "\n\t" + "strb %[bitmask], [%[reg], #0]" + "\n\t" + "movs %[dly], #13" + "\n\t" + "L%=_last_delay_T1H:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_last_delay_T1H" + "\n\t" + "strb %[bitmask], [%[reg], #4]" + "\n\t" + "movs %[dly], #1" + "\n\t" + "L%=_last_delay_T1L:" + "\n\t" + "sub %[dly], #1" + "\n\t" + "bne L%=_last_delay_T1L" + "\n\t" + "nop" + "\n\t" + "L%=_repeat:" + "\n\t" + "add %[p], #1" + "\n\t" + "sub %[num], #1" + "\n\t" + "bne L%=_begin" + "\n\t" + "L%=_done:" + "\n\t" + : [p] "+r"(p), [pix] "=&r"(pix), [count] "=&r"(count), + [dly] "=&r"(dly), [num] "+r"(num) + : [bitmask] "r"(bitmask), [reg] "r"(reg)); #else #error "Sorry, only 48 MHz is supported, please set Tools > CPU Speed to 48 MHz" #endif // F_CPU == 48000000 -// Begin of support for nRF52 based boards ------------------------- + // Begin of support for nRF52 based boards ------------------------- #elif defined(NRF52) || defined(NRF52_SERIES) // [[[Begin of the Neopixel NRF52 EasyDMA implementation @@ -1369,16 +1976,16 @@ void Adafruit_NeoPixel::show(void) { //#define MAGIC_T1H 12UL | (0x8000) // 0.75us // WS2812B (rev B) timing is 0.4 and 0.8 us -#define MAGIC_T0H 6UL | (0x8000) // 0.375us -#define MAGIC_T1H 13UL | (0x8000) // 0.8125us +#define MAGIC_T0H 6UL | (0x8000) // 0.375us +#define MAGIC_T1H 13UL | (0x8000) // 0.8125us // WS2811 (400 khz) timing is 0.5 and 1.2 -#define MAGIC_T0H_400KHz 8UL | (0x8000) // 0.5us -#define MAGIC_T1H_400KHz 19UL | (0x8000) // 1.1875us +#define MAGIC_T0H_400KHz 8UL | (0x8000) // 0.5us +#define MAGIC_T1H_400KHz 19UL | (0x8000) // 1.1875us // For 400Khz, we double value of CTOPVAL -#define CTOPVAL 20UL // 1.25us -#define CTOPVAL_400KHz 40UL // 2.5us +#define CTOPVAL 20UL // 1.25us +#define CTOPVAL_400KHz 40UL // 2.5us // ---------- END Constants for the EasyDMA implementation ------------- // @@ -1390,14 +1997,14 @@ void Adafruit_NeoPixel::show(void) { // The number of cycles was hand picked and is guaranteed to be 100% // organic to preserve freshness and high accuracy. // ---------- BEGIN Constants for cycle counter implementation --------- -#define CYCLES_800_T0H 18 // ~0.36 uS -#define CYCLES_800_T1H 41 // ~0.76 uS -#define CYCLES_800 71 // ~1.25 uS +#define CYCLES_800_T0H 18 // ~0.36 uS +#define CYCLES_800_T1H 41 // ~0.76 uS +#define CYCLES_800 71 // ~1.25 uS -#define CYCLES_400_T0H 26 // ~0.50 uS -#define CYCLES_400_T1H 70 // ~1.26 uS -#define CYCLES_400 156 // ~2.50 uS -// ---------- END of Constants for cycle counter implementation -------- +#define CYCLES_400_T0H 26 // ~0.50 uS +#define CYCLES_400_T1H 70 // ~1.26 uS +#define CYCLES_400 156 // ~2.50 uS + // ---------- END of Constants for cycle counter implementation -------- // To support both the SoftDevice + Neopixels we use the EasyDMA // feature from the NRF25. However this technique implies to @@ -1409,55 +2016,60 @@ void Adafruit_NeoPixel::show(void) { // // If there is not enough memory, we will fall back to cycle counter // using DWT - uint32_t pattern_size = numBytes*8*sizeof(uint16_t)+2*sizeof(uint16_t); - uint16_t* pixels_pattern = NULL; + uint32_t pattern_size = + numBytes * 8 * sizeof(uint16_t) + 2 * sizeof(uint16_t); + uint16_t *pixels_pattern = NULL; - NRF_PWM_Type* pwm = NULL; + NRF_PWM_Type *pwm = NULL; // Try to find a free PWM device, which is not enabled // and has no connected pins - NRF_PWM_Type* PWM[] = { - NRF_PWM0, NRF_PWM1, NRF_PWM2 + NRF_PWM_Type *PWM[] = { + NRF_PWM0, + NRF_PWM1, + NRF_PWM2 #if defined(NRF_PWM3) - ,NRF_PWM3 + , + NRF_PWM3 #endif }; - for(unsigned int device = 0; device < (sizeof(PWM)/sizeof(PWM[0])); device++) { - if( (PWM[device]->ENABLE == 0) && + for (unsigned int device = 0; device < (sizeof(PWM) / sizeof(PWM[0])); + device++) { + if ((PWM[device]->ENABLE == 0) && (PWM[device]->PSEL.OUT[0] & PWM_PSEL_OUT_CONNECT_Msk) && (PWM[device]->PSEL.OUT[1] & PWM_PSEL_OUT_CONNECT_Msk) && (PWM[device]->PSEL.OUT[2] & PWM_PSEL_OUT_CONNECT_Msk) && - (PWM[device]->PSEL.OUT[3] & PWM_PSEL_OUT_CONNECT_Msk) - ) { + (PWM[device]->PSEL.OUT[3] & PWM_PSEL_OUT_CONNECT_Msk)) { pwm = PWM[device]; break; } } // only malloc if there is PWM device available - if ( pwm != NULL ) { - #if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe malloc - pixels_pattern = (uint16_t *) rtos_malloc(pattern_size); - #else - pixels_pattern = (uint16_t *) malloc(pattern_size); - #endif + if (pwm != NULL) { +#if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe malloc + pixels_pattern = (uint16_t *)rtos_malloc(pattern_size); +#else + pixels_pattern = (uint16_t *)malloc(pattern_size); +#endif } // Use the identified device to choose the implementation // If a PWM device is available use DMA - if( (pixels_pattern != NULL) && (pwm != NULL) ) { + if ((pixels_pattern != NULL) && (pwm != NULL)) { uint16_t pos = 0; // bit position - for(uint16_t n=0; n<numBytes; n++) { + for (uint16_t n = 0; n < numBytes; n++) { uint8_t pix = pixels[n]; - for(uint8_t mask=0x80; mask>0; mask >>= 1) { - #if defined(NEO_KHZ400) - if( !is800KHz ) { - pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H_400KHz : MAGIC_T0H_400KHz; - }else - #endif + for (uint8_t mask = 0x80; mask > 0; mask >>= 1) { +#if defined(NEO_KHZ400) + if (!is800KHz) { + pixels_pattern[pos] = + (pix & mask) ? MAGIC_T1H_400KHz : MAGIC_T0H_400KHz; + } else +#endif { pixels_pattern[pos] = (pix & mask) ? MAGIC_T1H : MAGIC_T0H; } @@ -1474,15 +2086,16 @@ void Adafruit_NeoPixel::show(void) { pwm->MODE = (PWM_MODE_UPDOWN_Up << PWM_MODE_UPDOWN_Pos); // Set the PWM to use the 16MHz clock - pwm->PRESCALER = (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); + pwm->PRESCALER = + (PWM_PRESCALER_PRESCALER_DIV_1 << PWM_PRESCALER_PRESCALER_Pos); // Setting of the maximum count // but keeping it on 16Mhz allows for more granularity just // in case someone wants to do more fine-tuning of the timing. #if defined(NEO_KHZ400) - if( !is800KHz ) { + if (!is800KHz) { pwm->COUNTERTOP = (CTOPVAL_400KHz << PWM_COUNTERTOP_COUNTERTOP_Pos); - }else + } else #endif { pwm->COUNTERTOP = (CTOPVAL << PWM_COUNTERTOP_COUNTERTOP_Pos); @@ -1501,10 +2114,10 @@ void Adafruit_NeoPixel::show(void) { pwm->SEQ[0].PTR = (uint32_t)(pixels_pattern) << PWM_SEQ_PTR_PTR_Pos; // Calculation of the number of steps loaded from memory. - pwm->SEQ[0].CNT = (pattern_size/sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos; + pwm->SEQ[0].CNT = (pattern_size / sizeof(uint16_t)) << PWM_SEQ_CNT_CNT_Pos; // The following settings are ignored with the current config. - pwm->SEQ[0].REFRESH = 0; + pwm->SEQ[0].REFRESH = 0; pwm->SEQ[0].ENDDELAY = 0; // The Neopixel implementation is a blocking algorithm. DMA @@ -1512,29 +2125,28 @@ void Adafruit_NeoPixel::show(void) { // operation we enable the interruption for the end of sequence // and block the execution thread until the event flag is set by // the peripheral. -// pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<<PWM_INTEN_SEQEND0_Pos); + // pwm->INTEN |= (PWM_INTEN_SEQEND0_Enabled<<PWM_INTEN_SEQEND0_Pos); - // PSEL must be configured before enabling PWM - #if defined(ARDUINO_ARCH_NRF52840) +// PSEL must be configured before enabling PWM +#if defined(ARDUINO_ARCH_NRF52840) pwm->PSEL.OUT[0] = g_APinDescription[pin].name; - #else +#else pwm->PSEL.OUT[0] = g_ADigitalPinMap[pin]; - #endif +#endif // Enable the PWM pwm->ENABLE = 1; // After all of this and many hours of reading the documentation // we are ready to start the sequence... - pwm->EVENTS_SEQEND[0] = 0; + pwm->EVENTS_SEQEND[0] = 0; pwm->TASKS_SEQSTART[0] = 1; // But we have to wait for the flag to be set. - while(!pwm->EVENTS_SEQEND[0]) - { - #if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_NRF52840) + while (!pwm->EVENTS_SEQEND[0]) { +#if defined(ARDUINO_NRF52_ADAFRUIT) || defined(ARDUINO_ARCH_NRF52840) yield(); - #endif +#endif } // Before leave we clear the flag for the event. @@ -1548,40 +2160,39 @@ void Adafruit_NeoPixel::show(void) { pwm->PSEL.OUT[0] = 0xFFFFFFFFUL; - #if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe free - rtos_free(pixels_pattern); - #else - free(pixels_pattern); - #endif - }// End of DMA implementation +#if defined(ARDUINO_NRF52_ADAFRUIT) // use thread-safe free + rtos_free(pixels_pattern); +#else + free(pixels_pattern); +#endif + } // End of DMA implementation // --------------------------------------------------------------------- - else{ -#ifndef ARDUINO_ARCH_NRF52840 - // Fall back to DWT - #if defined(ARDUINO_NRF52_ADAFRUIT) - // Bluefruit Feather 52 uses freeRTOS - // Critical Section is used since it does not block SoftDevice execution - taskENTER_CRITICAL(); - #elif defined(NRF52_DISABLE_INT) - // If you are using the Bluetooth SoftDevice we advise you to not disable - // the interrupts. Disabling the interrupts even for short periods of time - // causes the SoftDevice to stop working. - // Disable the interrupts only in cases where you need high performance for - // the LEDs and if you are not using the EasyDMA feature. - __disable_irq(); - #endif - - NRF_GPIO_Type* nrf_port = (NRF_GPIO_Type*) digitalPinToPort(pin); + else { +#ifndef ARDUINO_ARCH_NRF52840 +// Fall back to DWT +#if defined(ARDUINO_NRF52_ADAFRUIT) + // Bluefruit Feather 52 uses freeRTOS + // Critical Section is used since it does not block SoftDevice execution + taskENTER_CRITICAL(); +#elif defined(NRF52_DISABLE_INT) + // If you are using the Bluetooth SoftDevice we advise you to not disable + // the interrupts. Disabling the interrupts even for short periods of time + // causes the SoftDevice to stop working. + // Disable the interrupts only in cases where you need high performance for + // the LEDs and if you are not using the EasyDMA feature. + __disable_irq(); +#endif + + NRF_GPIO_Type *nrf_port = (NRF_GPIO_Type *)digitalPinToPort(pin); uint32_t pinMask = digitalPinToBitMask(pin); - uint32_t CYCLES_X00 = CYCLES_800; + uint32_t CYCLES_X00 = CYCLES_800; uint32_t CYCLES_X00_T1H = CYCLES_800_T1H; uint32_t CYCLES_X00_T0H = CYCLES_800_T0H; #if defined(NEO_KHZ400) - if( !is800KHz ) - { - CYCLES_X00 = CYCLES_400; + if (!is800KHz) { + CYCLES_X00 = CYCLES_400; CYCLES_X00_T1H = CYCLES_400_T1H; CYCLES_X00_T0H = CYCLES_400_T0H; } @@ -1592,36 +2203,39 @@ void Adafruit_NeoPixel::show(void) { DWT->CTRL |= DWT_CTRL_CYCCNTENA_Msk; // Tries to re-send the frame if is interrupted by the SoftDevice. - while(1) { + while (1) { uint8_t *p = pixels; uint32_t cycStart = DWT->CYCCNT; uint32_t cyc = 0; - for(uint16_t n=0; n<numBytes; n++) { + for (uint16_t n = 0; n < numBytes; n++) { uint8_t pix = *p++; - for(uint8_t mask = 0x80; mask; mask >>= 1) { - while(DWT->CYCCNT - cyc < CYCLES_X00); - cyc = DWT->CYCCNT; + for (uint8_t mask = 0x80; mask; mask >>= 1) { + while (DWT->CYCCNT - cyc < CYCLES_X00) + ; + cyc = DWT->CYCCNT; nrf_port->OUTSET |= pinMask; - if(pix & mask) { - while(DWT->CYCCNT - cyc < CYCLES_X00_T1H); + if (pix & mask) { + while (DWT->CYCCNT - cyc < CYCLES_X00_T1H) + ; } else { - while(DWT->CYCCNT - cyc < CYCLES_X00_T0H); + while (DWT->CYCCNT - cyc < CYCLES_X00_T0H) + ; } nrf_port->OUTCLR |= pinMask; } } - while(DWT->CYCCNT - cyc < CYCLES_X00); - + while (DWT->CYCCNT - cyc < CYCLES_X00) + ; // If total time longer than 25%, resend the whole data. // Since we are likely to be interrupted by SoftDevice - if ( (DWT->CYCCNT - cycStart) < ( 8*numBytes*((CYCLES_X00*5)/4) ) ) { + if ((DWT->CYCCNT - cycStart) < (8 * numBytes * ((CYCLES_X00 * 5) / 4))) { break; } @@ -1629,40 +2243,43 @@ void Adafruit_NeoPixel::show(void) { delayMicroseconds(300); } - // Enable interrupts again - #if defined(ARDUINO_NRF52_ADAFRUIT) - taskEXIT_CRITICAL(); - #elif defined(NRF52_DISABLE_INT) - __enable_irq(); - #endif +// Enable interrupts again +#if defined(ARDUINO_NRF52_ADAFRUIT) + taskEXIT_CRITICAL(); +#elif defined(NRF52_DISABLE_INT) + __enable_irq(); +#endif #endif } -// END of NRF52 implementation + // END of NRF52 implementation -#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__) // Arduino Zero, Gemma/Trinket M0, SODAQ Autonomo and others +#elif defined(__SAMD21E17A__) || defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__) // Arduino Zero, Gemma/Trinket M0, SODAQ Autonomo + // and others // Tried this with a timer/counter, couldn't quite get adequate // resolution. So yay, you get a load of goofball NOPs... - uint8_t *ptr, *end, p, bitMask, portNum; - uint32_t pinMask; + uint8_t *ptr, *end, p, bitMask, portNum; + uint32_t pinMask; - portNum = g_APinDescription[pin].ulPort; - pinMask = 1ul << g_APinDescription[pin].ulPin; - ptr = pixels; - end = ptr + numBytes; - p = *ptr++; - bitMask = 0x80; + portNum = g_APinDescription[pin].ulPort; + pinMask = 1ul << g_APinDescription[pin].ulPin; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg), *clr = &(PORT->Group[portNum].OUTCLR.reg); #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - for(;;) { + for (;;) { *set = pinMask; asm("nop; nop; nop; nop; nop; nop; nop; nop;"); - if(p & bitMask) { + if (p & bitMask) { asm("nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop;"); @@ -1673,20 +2290,21 @@ void Adafruit_NeoPixel::show(void) { "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop;"); } - if(bitMask >>= 1) { + if (bitMask >>= 1) { asm("nop; nop; nop; nop; nop; nop; nop; nop; nop;"); } else { - if(ptr >= end) break; - p = *ptr++; + if (ptr >= end) + break; + p = *ptr++; bitMask = 0x80; } } #if defined(NEO_KHZ400) } else { // 400 KHz bitstream - for(;;) { + for (;;) { *set = pinMask; asm("nop; nop; nop; nop; nop; nop; nop; nop; nop; nop; nop;"); - if(p & bitMask) { + if (p & bitMask) { asm("nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop; nop; nop; nop; nop;" @@ -1703,29 +2321,195 @@ void Adafruit_NeoPixel::show(void) { "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop; nop; nop; nop; nop;"); - if(bitMask >>= 1) { + if (bitMask >>= 1) { asm("nop; nop; nop; nop; nop; nop; nop;"); } else { - if(ptr >= end) break; - p = *ptr++; + if (ptr >= end) + break; + p = *ptr++; bitMask = 0x80; } } } #endif -#elif defined (__SAMD51__) // M4 +//---- +#elif defined(XMC1100_XMC2GO) || defined(XMC1100_H_BRIDGE2GO) || defined(XMC1100_Boot_Kit) || defined(XMC1300_Boot_Kit) + + // XMC1100/1200/1300 with ARM Cortex M0 are running with 32MHz, XMC1400 runs with 48MHz so may not work + // Tried this with a timer/counter, couldn't quite get adequate + // resolution. So yay, you get a load of goofball NOPs... - uint8_t *ptr, *end, p, bitMask, portNum, bit; + uint8_t *ptr, *end, p, bitMask, portNum; uint32_t pinMask; - portNum = g_APinDescription[pin].ulPort; - pinMask = 1ul << g_APinDescription[pin].ulPin; ptr = pixels; end = ptr + numBytes; p = *ptr++; bitMask = 0x80; + XMC_GPIO_PORT_t* XMC_port = mapping_port_pin[ pin ].port; + uint8_t XMC_pin = mapping_port_pin[ pin ].pin; + + uint32_t omrhigh = (uint32_t)XMC_GPIO_OUTPUT_LEVEL_HIGH << XMC_pin; + uint32_t omrlow = (uint32_t)XMC_GPIO_OUTPUT_LEVEL_LOW << XMC_pin; + +#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled + if(is800KHz) { +#endif + for(;;) { + XMC_port->OMR = omrhigh; + asm("nop; nop; nop; nop;"); + if(p & bitMask) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop;"); + XMC_port->OMR = omrlow; + } else { + XMC_port->OMR = omrlow; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop;"); + } + if(bitMask >>= 1) { + asm("nop; nop; nop; nop; nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } +#ifdef NEO_KHZ400 // untested code + } else { // 400 KHz bitstream + for(;;) { + XMC_port->OMR = omrhigh; + asm("nop; nop; nop; nop; nop;"); + if(p & bitMask) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop;"); + XMC_port->OMR = omrlow; + } else { + XMC_port->OMR = omrlow; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop;"); + } + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;"); + if(bitMask >>= 1) { + asm("nop; nop; nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } + } + +#endif +//---- + +//---- +#elif defined(XMC4700_Relax_Kit) || defined(XMC4800_Relax_Kit) + +// XMC4700 and XMC4800 with ARM Cortex M4 are running with 144MHz +// Tried this with a timer/counter, couldn't quite get adequate +// resolution. So yay, you get a load of goofball NOPs... + +uint8_t *ptr, *end, p, bitMask, portNum; +uint32_t pinMask; + +ptr = pixels; +end = ptr + numBytes; +p = *ptr++; +bitMask = 0x80; + +XMC_GPIO_PORT_t* XMC_port = mapping_port_pin[ pin ].port; +uint8_t XMC_pin = mapping_port_pin[ pin ].pin; + +uint32_t omrhigh = (uint32_t)XMC_GPIO_OUTPUT_LEVEL_HIGH << XMC_pin; +uint32_t omrlow = (uint32_t)XMC_GPIO_OUTPUT_LEVEL_LOW << XMC_pin; + +#ifdef NEO_KHZ400 // 800 KHz check needed only if 400 KHz support enabled +if(is800KHz) { +#endif + + for(;;) { + XMC_port->OMR = omrhigh; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop;"); + if(p & bitMask) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;"); + XMC_port->OMR = omrlow; + } else { + XMC_port->OMR = omrlow; + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;"); + } + if(bitMask >>= 1) { + asm("nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;" + "nop; nop; nop; nop; nop; nop; nop; nop;"); + } else { + if(ptr >= end) break; + p = *ptr++; + bitMask = 0x80; + } + } + + +#ifdef NEO_KHZ400 + } else { // 400 KHz bitstream + // ToDo! + } +#endif +//---- + +#elif defined(__SAMD51__) // M4 + + uint8_t *ptr, *end, p, bitMask, portNum, bit; + uint32_t pinMask; + + portNum = g_APinDescription[pin].ulPort; + pinMask = 1ul << g_APinDescription[pin].ulPin; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; + volatile uint32_t *set = &(PORT->Group[portNum].OUTSET.reg), *clr = &(PORT->Group[portNum].OUTCLR.reg); @@ -1745,65 +2529,67 @@ void Adafruit_NeoPixel::show(void) { // seems to work just well enough. When finished, the SysTick // peripheral is set back to its original state. - uint32_t t0, t1, top, ticks, - saveLoad = SysTick->LOAD, saveVal = SysTick->VAL; + uint32_t t0, t1, top, ticks, saveLoad = SysTick->LOAD, saveVal = SysTick->VAL; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - top = (uint32_t)(F_CPU * 0.00000125); // Bit hi + lo = 1.25 uS - t0 = top - (uint32_t)(F_CPU * 0.00000040); // 0 = 0.4 uS hi - t1 = top - (uint32_t)(F_CPU * 0.00000080); // 1 = 0.8 uS hi + top = (uint32_t)(F_CPU * 0.00000125); // Bit hi + lo = 1.25 uS + t0 = top - (uint32_t)(F_CPU * 0.00000040); // 0 = 0.4 uS hi + t1 = top - (uint32_t)(F_CPU * 0.00000080); // 1 = 0.8 uS hi #if defined(NEO_KHZ400) - } else { // 400 KHz bitstream - top = (uint32_t)(F_CPU * 0.00000250); // Bit hi + lo = 2.5 uS - t0 = top - (uint32_t)(F_CPU * 0.00000050); // 0 = 0.5 uS hi - t1 = top - (uint32_t)(F_CPU * 0.00000120); // 1 = 1.2 uS hi + } else { // 400 KHz bitstream + top = (uint32_t)(F_CPU * 0.00000250); // Bit hi + lo = 2.5 uS + t0 = top - (uint32_t)(F_CPU * 0.00000050); // 0 = 0.5 uS hi + t1 = top - (uint32_t)(F_CPU * 0.00000120); // 1 = 1.2 uS hi } #endif - SysTick->LOAD = top; // Config SysTick for NeoPixel bit freq - SysTick->VAL = top; // Set to start value (counts down) - (void)SysTick->VAL; // Dummy read helps sync up 1st bit + SysTick->LOAD = top; // Config SysTick for NeoPixel bit freq + SysTick->VAL = top; // Set to start value (counts down) + (void)SysTick->VAL; // Dummy read helps sync up 1st bit - for(;;) { - *set = pinMask; // Set output high + for (;;) { + *set = pinMask; // Set output high ticks = (p & bitMask) ? t1 : t0; // SysTick threshold, - while(SysTick->VAL > ticks); // wait for it - *clr = pinMask; // Set output low - if(!(bitMask >>= 1)) { // Next bit for this byte...done? - if(ptr >= end) break; // If last byte sent, exit loop - p = *ptr++; // Fetch next byte - bitMask = 0x80; // Reset bitmask + while (SysTick->VAL > ticks) + ; // wait for it + *clr = pinMask; // Set output low + if (!(bitMask >>= 1)) { // Next bit for this byte...done? + if (ptr >= end) + break; // If last byte sent, exit loop + p = *ptr++; // Fetch next byte + bitMask = 0x80; // Reset bitmask } - while(SysTick->VAL <= ticks); // Wait for rollover to 'top' + while (SysTick->VAL <= ticks) + ; // Wait for rollover to 'top' } - SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms - SysTick->VAL = saveVal; // Restore SysTick value + SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms + SysTick->VAL = saveVal; // Restore SysTick value -#elif defined (ARDUINO_STM32_FEATHER) // FEATHER WICED (120MHz) +#elif defined(ARDUINO_STM32_FEATHER) // FEATHER WICED (120MHz) // Tried this with a timer/counter, couldn't quite get adequate // resolution. So yay, you get a load of goofball NOPs... - uint8_t *ptr, *end, p, bitMask; - uint32_t pinMask; + uint8_t *ptr, *end, p, bitMask; + uint32_t pinMask; - pinMask = BIT(PIN_MAP[pin].gpio_bit); - ptr = pixels; - end = ptr + numBytes; - p = *ptr++; - bitMask = 0x80; + pinMask = BIT(PIN_MAP[pin].gpio_bit); + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; volatile uint16_t *set = &(PIN_MAP[pin].gpio_device->regs->BSRRL); volatile uint16_t *clr = &(PIN_MAP[pin].gpio_device->regs->BSRRH); #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - for(;;) { - if(p & bitMask) { // ONE + for (;;) { + if (p & bitMask) { // ONE // High 800ns *set = pinMask; asm("nop; nop; nop; nop; nop; nop; nop; nop;" @@ -1849,12 +2635,13 @@ void Adafruit_NeoPixel::show(void) { "nop; nop; nop; nop; nop; nop; nop; nop;" "nop; nop; nop; nop;"); } - if(bitMask >>= 1) { + if (bitMask >>= 1) { // Move on to the next pixel asm("nop;"); } else { - if(ptr >= end) break; - p = *ptr++; + if (ptr >= end) + break; + p = *ptr++; bitMask = 0x80; } } @@ -1865,17 +2652,17 @@ void Adafruit_NeoPixel::show(void) { #endif #elif defined(TARGET_LPC1768) - uint8_t *ptr, *end, p, bitMask; - ptr = pixels; - end = ptr + numBytes; - p = *ptr++; - bitMask = 0x80; + uint8_t *ptr, *end, p, bitMask; + ptr = pixels; + end = ptr + numBytes; + p = *ptr++; + bitMask = 0x80; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - for(;;) { - if(p & bitMask) { + for (;;) { + if (p & bitMask) { // data ONE high // min: 550 typ: 700 max: 5,500 gpio_set(pin); @@ -1893,12 +2680,13 @@ void Adafruit_NeoPixel::show(void) { gpio_clear(pin); time::delay_ns(450); } - if(bitMask >>= 1) { + if (bitMask >>= 1) { // Move on to the next pixel asm("nop;"); } else { - if(ptr >= end) break; - p = *ptr++; + if (ptr >= end) + break; + p = *ptr++; bitMask = 0x80; } } @@ -1908,204 +2696,229 @@ void Adafruit_NeoPixel::show(void) { } #endif #elif defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) - uint8_t *p = pixels, *end = p + numBytes, - pix = *p++, mask = 0x80; - uint32_t cyc; + uint8_t *p = pixels, *end = p + numBytes, pix = *p++, mask = 0x80; + uint32_t cyc; uint32_t saveLoad = SysTick->LOAD, saveVal = SysTick->VAL; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - uint32_t top = (F_CPU / 800000); // 1.25µs - uint32_t t0 = top - (F_CPU / 2500000); // 0.4µs - uint32_t t1 = top - (F_CPU / 1250000); // 0.8µs + uint32_t top = (F_CPU / 800000); // 1.25µs + uint32_t t0 = top - (F_CPU / 2500000); // 0.4µs + uint32_t t1 = top - (F_CPU / 1250000); // 0.8µs SysTick->LOAD = top - 1; // Config SysTick for NeoPixel bit freq - SysTick->VAL = 0; // Set to start value - for(;;) { + SysTick->VAL = 0; // Set to start value + for (;;) { LL_GPIO_SetOutputPin(gpioPort, gpioPin); cyc = (pix & mask) ? t1 : t0; - while(SysTick->VAL > cyc); + while (SysTick->VAL > cyc) + ; LL_GPIO_ResetOutputPin(gpioPort, gpioPin); - if(!(mask >>= 1)) { - if(p >= end) break; - pix = *p++; + if (!(mask >>= 1)) { + if (p >= end) + break; + pix = *p++; mask = 0x80; } - while(SysTick->VAL <= cyc); + while (SysTick->VAL <= cyc) + ; } #if defined(NEO_KHZ400) - } else { // 400 kHz bitstream - uint32_t top = (F_CPU / 400000); // 2.5µs - uint32_t t0 = top - (F_CPU / 2000000); // 0.5µs - uint32_t t1 = top - (F_CPU / 833333); // 1.2µs + } else { // 400 kHz bitstream + uint32_t top = (F_CPU / 400000); // 2.5µs + uint32_t t0 = top - (F_CPU / 2000000); // 0.5µs + uint32_t t1 = top - (F_CPU / 833333); // 1.2µs SysTick->LOAD = top - 1; // Config SysTick for NeoPixel bit freq - SysTick->VAL = 0; // Set to start value - for(;;) { + SysTick->VAL = 0; // Set to start value + for (;;) { LL_GPIO_SetOutputPin(gpioPort, gpioPin); cyc = (pix & mask) ? t1 : t0; - while(SysTick->VAL > cyc); + while (SysTick->VAL > cyc) + ; LL_GPIO_ResetOutputPin(gpioPort, gpioPin); - if(!(mask >>= 1)) { - if(p >= end) break; - pix = *p++; + if (!(mask >>= 1)) { + if (p >= end) + break; + pix = *p++; mask = 0x80; } - while(SysTick->VAL <= cyc); + while (SysTick->VAL <= cyc) + ; } } #endif // NEO_KHZ400 - SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms - SysTick->VAL = saveVal; // Restore SysTick value -#elif defined (NRF51) - uint8_t *p = pixels, - pix, count, mask; - int32_t num = numBytes; - unsigned int bitmask = ( 1 << g_ADigitalPinMap[pin] ); -// https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/variants/BBCmicrobit/variant.cpp + SysTick->LOAD = saveLoad; // Restore SysTick rollover to 1 ms + SysTick->VAL = saveVal; // Restore SysTick value +#elif defined(NRF51) + uint8_t *p = pixels, pix, count, mask; + int32_t num = numBytes; + unsigned int bitmask = (1 << g_ADigitalPinMap[pin]); + // https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/variants/BBCmicrobit/variant.cpp - volatile unsigned int *reg = (unsigned int *) (0x50000000UL + 0x508); + volatile unsigned int *reg = (unsigned int *)(0x50000000UL + 0x508); -// https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/cores/nRF5/SDK/components/device/nrf51.h -// http://www.iot-programmer.com/index.php/books/27-micro-bit-iot-in-c/chapters-micro-bit-iot-in-c/47-micro-bit-iot-in-c-fast-memory-mapped-gpio?showall=1 -// https://github.com/Microsoft/pxt-neopixel/blob/master/sendbuffer.asm + // https://github.com/sandeepmistry/arduino-nRF5/blob/dc53980c8bac27898fca90d8ecb268e11111edc1/cores/nRF5/SDK/components/device/nrf51.h + // http://www.iot-programmer.com/index.php/books/27-micro-bit-iot-in-c/chapters-micro-bit-iot-in-c/47-micro-bit-iot-in-c-fast-memory-mapped-gpio?showall=1 + // https://github.com/Microsoft/pxt-neopixel/blob/master/sendbuffer.asm asm volatile( - // "cpsid i" ; disable irq - - // b .start - "b L%=_start" "\n\t" - // .nextbit: ; C0 - "L%=_nextbit:" "\n\t" //; C0 - // str r1, [r3, #0] ; pin := hi C2 - "strb %[bitmask], [%[reg], #0]" "\n\t" //; pin := hi C2 - // tst r6, r0 ; C3 - "tst %[mask], %[pix]" "\n\t"// ; C3 - // bne .islate ; C4 - "bne L%=_islate" "\n\t" //; C4 - // str r1, [r2, #0] ; pin := lo C6 - "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo C6 - // .islate: - "L%=_islate:" "\n\t" - // lsrs r6, r6, #1 ; r6 >>= 1 C7 - "lsr %[mask], %[mask], #1" "\n\t" //; r6 >>= 1 C7 - // bne .justbit ; C8 - "bne L%=_justbit" "\n\t" //; C8 - - // ; not just a bit - need new byte - // adds r4, #1 ; r4++ C9 - "add %[p], #1" "\n\t" //; r4++ C9 - // subs r5, #1 ; r5-- C10 - "sub %[num], #1" "\n\t" //; r5-- C10 - // bcc .stop ; if (r5<0) goto .stop C11 - "bcc L%=_stop" "\n\t" //; if (r5<0) goto .stop C11 - // .start: - "L%=_start:" - // movs r6, #0x80 ; reset mask C12 - "movs %[mask], #0x80" "\n\t" //; reset mask C12 - // nop ; C13 - "nop" "\n\t" //; C13 - - // .common: ; C13 - "L%=_common:" "\n\t" //; C13 - // str r1, [r2, #0] ; pin := lo C15 - "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo C15 - // ; always re-load byte - it just fits with the cycles better this way - // ldrb r0, [r4, #0] ; r0 := *r4 C17 - "ldrb %[pix], [%[p], #0]" "\n\t" //; r0 := *r4 C17 - // b .nextbit ; C20 - "b L%=_nextbit" "\n\t" //; C20 - - // .justbit: ; C10 - "L%=_justbit:" "\n\t" //; C10 - // ; no nops, branch taken is already 3 cycles - // b .common ; C13 - "b L%=_common" "\n\t" //; C13 - - // .stop: - "L%=_stop:" "\n\t" - // str r1, [r2, #0] ; pin := lo - "strb %[bitmask], [%[reg], #4]" "\n\t" //; pin := lo - // cpsie i ; enable irq - - : [p] "+r" (p), - [pix] "=&r" (pix), - [count] "=&r" (count), - [mask] "=&r" (mask), - [num] "+r" (num) - : [bitmask] "r" (bitmask), - [reg] "r" (reg) - ); + // "cpsid i" ; disable irq + + // b .start + "b L%=_start" + "\n\t" + // .nextbit: ; C0 + "L%=_nextbit:" + "\n\t" //; C0 + // str r1, [r3, #0] ; pin := hi C2 + "strb %[bitmask], [%[reg], #0]" + "\n\t" //; pin := hi C2 + // tst r6, r0 ; C3 + "tst %[mask], %[pix]" + "\n\t" // ; C3 + // bne .islate ; C4 + "bne L%=_islate" + "\n\t" //; C4 + // str r1, [r2, #0] ; pin := lo C6 + "strb %[bitmask], [%[reg], #4]" + "\n\t" //; pin := lo C6 + // .islate: + "L%=_islate:" + "\n\t" + // lsrs r6, r6, #1 ; r6 >>= 1 C7 + "lsr %[mask], %[mask], #1" + "\n\t" //; r6 >>= 1 C7 + // bne .justbit ; C8 + "bne L%=_justbit" + "\n\t" //; C8 + + // ; not just a bit - need new byte + // adds r4, #1 ; r4++ C9 + "add %[p], #1" + "\n\t" //; r4++ C9 + // subs r5, #1 ; r5-- C10 + "sub %[num], #1" + "\n\t" //; r5-- C10 + // bcc .stop ; if (r5<0) goto .stop C11 + "bcc L%=_stop" + "\n\t" //; if (r5<0) goto .stop C11 + // .start: + "L%=_start:" + // movs r6, #0x80 ; reset mask C12 + "movs %[mask], #0x80" + "\n\t" //; reset mask C12 + // nop ; C13 + "nop" + "\n\t" //; C13 + + // .common: ; C13 + "L%=_common:" + "\n\t" //; C13 + // str r1, [r2, #0] ; pin := lo C15 + "strb %[bitmask], [%[reg], #4]" + "\n\t" //; pin := lo C15 + // ; always re-load byte - it just fits with the cycles better this way + // ldrb r0, [r4, #0] ; r0 := *r4 C17 + "ldrb %[pix], [%[p], #0]" + "\n\t" //; r0 := *r4 C17 + // b .nextbit ; C20 + "b L%=_nextbit" + "\n\t" //; C20 + + // .justbit: ; C10 + "L%=_justbit:" + "\n\t" //; C10 + // ; no nops, branch taken is already 3 cycles + // b .common ; C13 + "b L%=_common" + "\n\t" //; C13 + + // .stop: + "L%=_stop:" + "\n\t" + // str r1, [r2, #0] ; pin := lo + "strb %[bitmask], [%[reg], #4]" + "\n\t" //; pin := lo + // cpsie i ; enable irq + + : [p] "+r"(p), [pix] "=&r"(pix), [count] "=&r"(count), [mask] "=&r"(mask), + [num] "+r"(num) + : [bitmask] "r"(bitmask), [reg] "r"(reg)); #elif defined(__SAM3X8E__) // Arduino Due - #define SCALE VARIANT_MCK / 2UL / 1000000UL - #define INST (2UL * F_CPU / VARIANT_MCK) - #define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) - #define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) - #define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) - #define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) - - int pinMask, time0, time1, period, t; - Pio *port; +#define SCALE VARIANT_MCK / 2UL / 1000000UL +#define INST (2UL * F_CPU / VARIANT_MCK) +#define TIME_800_0 ((int)(0.40 * SCALE + 0.5) - (5 * INST)) +#define TIME_800_1 ((int)(0.80 * SCALE + 0.5) - (5 * INST)) +#define PERIOD_800 ((int)(1.25 * SCALE + 0.5) - (5 * INST)) +#define TIME_400_0 ((int)(0.50 * SCALE + 0.5) - (5 * INST)) +#define TIME_400_1 ((int)(1.20 * SCALE + 0.5) - (5 * INST)) +#define PERIOD_400 ((int)(2.50 * SCALE + 0.5) - (5 * INST)) + + int pinMask, time0, time1, period, t; + Pio *port; volatile WoReg *portSet, *portClear, *timeValue, *timeReset; - uint8_t *p, *end, pix, mask; + uint8_t *p, *end, pix, mask; pmc_set_writeprotect(false); pmc_enable_periph_clk((uint32_t)TC3_IRQn); TC_Configure(TC1, 0, - TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); + TC_CMR_WAVE | TC_CMR_WAVSEL_UP | TC_CMR_TCCLKS_TIMER_CLOCK1); TC_Start(TC1, 0); - pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into - port = g_APinDescription[pin].pPort; // declarations above. Want to - portSet = &(port->PIO_SODR); // burn a few cycles after - portClear = &(port->PIO_CODR); // starting timer to minimize - timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. + pinMask = g_APinDescription[pin].ulPin; // Don't 'optimize' these into + port = g_APinDescription[pin].pPort; // declarations above. Want to + portSet = &(port->PIO_SODR); // burn a few cycles after + portClear = &(port->PIO_CODR); // starting timer to minimize + timeValue = &(TC1->TC_CHANNEL[0].TC_CV); // the initial 'while'. timeReset = &(TC1->TC_CHANNEL[0].TC_CCR); - p = pixels; - end = p + numBytes; - pix = *p++; - mask = 0x80; + p = pixels; + end = p + numBytes; + pix = *p++; + mask = 0x80; #if defined(NEO_KHZ400) // 800 KHz check needed only if 400 KHz support enabled - if(is800KHz) { + if (is800KHz) { #endif - time0 = TIME_800_0; - time1 = TIME_800_1; + time0 = TIME_800_0; + time1 = TIME_800_1; period = PERIOD_800; #if defined(NEO_KHZ400) } else { // 400 KHz bitstream - time0 = TIME_400_0; - time1 = TIME_400_1; + time0 = TIME_400_0; + time1 = TIME_400_1; period = PERIOD_400; } #endif - for(t = time0;; t = time0) { - if(pix & mask) t = time1; - while(*timeValue < (unsigned)period); - *portSet = pinMask; + for (t = time0;; t = time0) { + if (pix & mask) + t = time1; + while (*timeValue < (unsigned)period) + ; + *portSet = pinMask; *timeReset = TC_CCR_CLKEN | TC_CCR_SWTRG; - while(*timeValue < (unsigned)t); + while (*timeValue < (unsigned)t) + ; *portClear = pinMask; - if(!(mask >>= 1)) { // This 'inside-out' loop logic utilizes - if(p >= end) break; // idle time to minimize inter-byte delays. + if (!(mask >>= 1)) { // This 'inside-out' loop logic utilizes + if (p >= end) + break; // idle time to minimize inter-byte delays. pix = *p++; mask = 0x80; } } - while(*timeValue < (unsigned)period); // Wait for last bit + while (*timeValue < (unsigned)period) + ; // Wait for last bit TC_Stop(TC1, 0); #endif // end Due -// END ARM ---------------------------------------------------------------- - + // END ARM ---------------------------------------------------------------- #elif defined(ESP8266) || defined(ESP32) -// ESP8266 ---------------------------------------------------------------- + // ESP8266 ---------------------------------------------------------------- // ESP8266 show() is external to enforce ICACHE_RAM_ATTR execution espShow(pin, pixels, numBytes, is800KHz); @@ -2113,94 +2926,97 @@ void Adafruit_NeoPixel::show(void) { #elif defined(KENDRYTE_K210) k210Show(pin, pixels, numBytes, is800KHz); - -#elif defined(__ARDUINO_ARC__) -// Arduino 101 ----------------------------------------------------------- +#elif defined(__ARDUINO_ARC__) -#define NOPx7 { __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); \ - __builtin_arc_nop(); __builtin_arc_nop(); } + // Arduino 101 ----------------------------------------------------------- + +#define NOPx7 \ + { \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + __builtin_arc_nop(); \ + } PinDescription *pindesc = &g_APinDescription[pin]; - register uint32_t loop = 8 * numBytes; // one loop to handle all bytes and all bits + register uint32_t loop = + 8 * numBytes; // one loop to handle all bytes and all bits register uint8_t *p = pixels; - register uint32_t currByte = (uint32_t) (*p); + register uint32_t currByte = (uint32_t)(*p); register uint32_t currBit = 0x80 & currByte; register uint32_t bitCounter = 0; register uint32_t first = 1; - // The loop is unusual. Very first iteration puts all the way LOW to the wire - - // constant LOW does not affect NEOPIXEL, so there is no visible effect displayed. - // During that very first iteration CPU caches instructions in the loop. - // Because of the caching process, "CPU slows down". NEOPIXEL pulse is very time sensitive - // that's why we let the CPU cache first and we start regular pulse from 2nd iteration + // The loop is unusual. Very first iteration puts all the way LOW to the wire + // - constant LOW does not affect NEOPIXEL, so there is no visible effect + // displayed. During that very first iteration CPU caches instructions in the + // loop. Because of the caching process, "CPU slows down". NEOPIXEL pulse is + // very time sensitive that's why we let the CPU cache first and we start + // regular pulse from 2nd iteration if (pindesc->ulGPIOType == SS_GPIO) { register uint32_t reg = pindesc->ulGPIOBase + SS_GPIO_SWPORTA_DR; uint32_t reg_val = __builtin_arc_lr((volatile uint32_t)reg); register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); - register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); + register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); loop += 1; // include first, special iteration - while(loop--) { - if(!first) { + while (loop--) { + if (!first) { currByte <<= 1; bitCounter++; } // 1 is >550ns high and >450ns low; 0 is 200..500ns high and >450ns low - __builtin_arc_sr(first ? reg_bit_low : reg_bit_high, (volatile uint32_t)reg); - if(currBit) { // ~400ns HIGH (740ns overall) - NOPx7 - NOPx7 + __builtin_arc_sr(first ? reg_bit_low : reg_bit_high, + (volatile uint32_t)reg); + if (currBit) { // ~400ns HIGH (740ns overall) + NOPx7 NOPx7 } // ~340ns HIGH - NOPx7 - __builtin_arc_nop(); + NOPx7 __builtin_arc_nop(); // 820ns LOW; per spec, max allowed low here is 5000ns */ __builtin_arc_sr(reg_bit_low, (volatile uint32_t)reg); - NOPx7 - NOPx7 + NOPx7 NOPx7 - if(bitCounter >= 8) { + if (bitCounter >= 8) { bitCounter = 0; - currByte = (uint32_t) (*++p); + currByte = (uint32_t)(*++p); } currBit = 0x80 & currByte; first = 0; } - } else if(pindesc->ulGPIOType == SOC_GPIO) { + } else if (pindesc->ulGPIOType == SOC_GPIO) { register uint32_t reg = pindesc->ulGPIOBase + SOC_GPIO_SWPORTA_DR; uint32_t reg_val = MMIO_REG_VAL(reg); register uint32_t reg_bit_high = reg_val | (1 << pindesc->ulGPIOId); - register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); + register uint32_t reg_bit_low = reg_val & ~(1 << pindesc->ulGPIOId); loop += 1; // include first, special iteration - while(loop--) { - if(!first) { + while (loop--) { + if (!first) { currByte <<= 1; bitCounter++; } MMIO_REG_VAL(reg) = first ? reg_bit_low : reg_bit_high; - if(currBit) { // ~430ns HIGH (740ns overall) - NOPx7 - NOPx7 - __builtin_arc_nop(); + if (currBit) { // ~430ns HIGH (740ns overall) + NOPx7 NOPx7 __builtin_arc_nop(); } // ~310ns HIGH NOPx7 - // 850ns LOW; per spec, max allowed low here is 5000ns */ - MMIO_REG_VAL(reg) = reg_bit_low; - NOPx7 - NOPx7 + // 850ns LOW; per spec, max allowed low here is 5000ns */ + MMIO_REG_VAL(reg) = reg_bit_low; + NOPx7 NOPx7 - if(bitCounter >= 8) { + if (bitCounter >= 8) { bitCounter = 0; - currByte = (uint32_t) (*++p); + currByte = (uint32_t)(*++p); } currBit = 0x80 & currByte; @@ -2212,10 +3028,9 @@ void Adafruit_NeoPixel::show(void) { #error Architecture not supported #endif + // END ARCHITECTURE SELECT ------------------------------------------------ -// END ARCHITECTURE SELECT ------------------------------------------------ - -#if !( defined(NRF52) || defined(NRF52_SERIES) ) +#if !(defined(NRF52) || defined(NRF52_SERIES)) interrupts(); #endif @@ -2227,15 +3042,16 @@ void Adafruit_NeoPixel::show(void) { if any, is set to INPUT and the new pin is set to OUTPUT. @param p Arduino pin number (-1 = no pin). */ -void Adafruit_NeoPixel::setPin(uint16_t p) { - if(begun && (pin >= 0)) pinMode(pin, INPUT); +void Adafruit_NeoPixel::setPin(int16_t p) { + if (begun && (pin >= 0)) + pinMode(pin, INPUT); // Disable existing out pin pin = p; - if(begun) { + if (begun) { pinMode(p, OUTPUT); digitalWrite(p, LOW); } #if defined(__AVR__) - port = portOutputRegister(digitalPinToPort(p)); + port = portOutputRegister(digitalPinToPort(p)); pinMask = digitalPinToBitMask(p); #endif #if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) @@ -2252,23 +3068,23 @@ void Adafruit_NeoPixel::setPin(uint16_t p) { @param g Green brightness, 0 = minimum (off), 255 = maximum. @param b Blue brightness, 0 = minimum (off), 255 = maximum. */ -void Adafruit_NeoPixel::setPixelColor( - uint16_t n, uint8_t r, uint8_t g, uint8_t b) { +void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint8_t r, uint8_t g, + uint8_t b) { - if(n < numLEDs) { - if(brightness) { // See notes in setBrightness() + if (n < numLEDs) { + if (brightness) { // See notes in setBrightness() r = (r * brightness) >> 8; g = (g * brightness) >> 8; b = (b * brightness) >> 8; } uint8_t *p; - if(wOffset == rOffset) { // Is an RGB-type strip - p = &pixels[n * 3]; // 3 bytes per pixel - } else { // Is a WRGB-type strip - p = &pixels[n * 4]; // 4 bytes per pixel - p[wOffset] = 0; // But only R,G,B passed -- set W to 0 + if (wOffset == rOffset) { // Is an RGB-type strip + p = &pixels[n * 3]; // 3 bytes per pixel + } else { // Is a WRGB-type strip + p = &pixels[n * 4]; // 4 bytes per pixel + p[wOffset] = 0; // But only R,G,B passed -- set W to 0 } - p[rOffset] = r; // R,G,B always stored + p[rOffset] = r; // R,G,B always stored p[gOffset] = g; p[bOffset] = b; } @@ -2284,24 +3100,24 @@ void Adafruit_NeoPixel::setPixelColor( @param w White brightness, 0 = minimum (off), 255 = maximum, ignored if using RGB pixels. */ -void Adafruit_NeoPixel::setPixelColor( - uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w) { +void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint8_t r, uint8_t g, + uint8_t b, uint8_t w) { - if(n < numLEDs) { - if(brightness) { // See notes in setBrightness() + if (n < numLEDs) { + if (brightness) { // See notes in setBrightness() r = (r * brightness) >> 8; g = (g * brightness) >> 8; b = (b * brightness) >> 8; w = (w * brightness) >> 8; } uint8_t *p; - if(wOffset == rOffset) { // Is an RGB-type strip - p = &pixels[n * 3]; // 3 bytes per pixel (ignore W) - } else { // Is a WRGB-type strip - p = &pixels[n * 4]; // 4 bytes per pixel - p[wOffset] = w; // Store W + if (wOffset == rOffset) { // Is an RGB-type strip + p = &pixels[n * 3]; // 3 bytes per pixel (ignore W) + } else { // Is a WRGB-type strip + p = &pixels[n * 4]; // 4 bytes per pixel + p[wOffset] = w; // Store W } - p[rOffset] = r; // Store R,G,B + p[rOffset] = r; // Store R,G,B p[gOffset] = g; p[bOffset] = b; } @@ -2315,17 +3131,14 @@ void Adafruit_NeoPixel::setPixelColor( and least significant byte is blue. */ void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { - if(n < numLEDs) { - uint8_t *p, - r = (uint8_t)(c >> 16), - g = (uint8_t)(c >> 8), - b = (uint8_t)c; - if(brightness) { // See notes in setBrightness() + if (n < numLEDs) { + uint8_t *p, r = (uint8_t)(c >> 16), g = (uint8_t)(c >> 8), b = (uint8_t)c; + if (brightness) { // See notes in setBrightness() r = (r * brightness) >> 8; g = (g * brightness) >> 8; b = (b * brightness) >> 8; } - if(wOffset == rOffset) { + if (wOffset == rOffset) { p = &pixels[n * 3]; } else { p = &pixels[n * 4]; @@ -2352,21 +3165,22 @@ void Adafruit_NeoPixel::setPixelColor(uint16_t n, uint32_t c) { void Adafruit_NeoPixel::fill(uint32_t c, uint16_t first, uint16_t count) { uint16_t i, end; - if(first >= numLEDs) { + if (first >= numLEDs) { return; // If first LED is past end of strip, nothing to do } // Calculate the index ONE AFTER the last pixel to fill - if(count == 0) { + if (count == 0) { // Fill to end of strip end = numLEDs; } else { // Ensure that the loop won't go past the last pixel end = first + count; - if(end > numLEDs) end = numLEDs; + if (end > numLEDs) + end = numLEDs; } - for(i = first; i < end; i++) { + for (i = first; i < end; i++) { this->setPixelColor(i, c); } } @@ -2429,45 +3243,45 @@ uint32_t Adafruit_NeoPixel::ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) { // the constants below are not the multiples of 256 you might expect. // Convert hue to R,G,B (nested ifs faster than divide+mod+switch): - if(hue < 510) { // Red to Green-1 + if (hue < 510) { // Red to Green-1 b = 0; - if(hue < 255) { // Red to Yellow-1 + if (hue < 255) { // Red to Yellow-1 r = 255; - g = hue; // g = 0 to 254 - } else { // Yellow to Green-1 - r = 510 - hue; // r = 255 to 1 + g = hue; // g = 0 to 254 + } else { // Yellow to Green-1 + r = 510 - hue; // r = 255 to 1 g = 255; } - } else if(hue < 1020) { // Green to Blue-1 + } else if (hue < 1020) { // Green to Blue-1 r = 0; - if(hue < 765) { // Green to Cyan-1 + if (hue < 765) { // Green to Cyan-1 g = 255; - b = hue - 510; // b = 0 to 254 - } else { // Cyan to Blue-1 - g = 1020 - hue; // g = 255 to 1 + b = hue - 510; // b = 0 to 254 + } else { // Cyan to Blue-1 + g = 1020 - hue; // g = 255 to 1 b = 255; } - } else if(hue < 1530) { // Blue to Red-1 + } else if (hue < 1530) { // Blue to Red-1 g = 0; - if(hue < 1275) { // Blue to Magenta-1 - r = hue - 1020; // r = 0 to 254 + if (hue < 1275) { // Blue to Magenta-1 + r = hue - 1020; // r = 0 to 254 b = 255; - } else { // Magenta to Red-1 + } else { // Magenta to Red-1 r = 255; - b = 1530 - hue; // b = 255 to 1 + b = 1530 - hue; // b = 255 to 1 } - } else { // Last 0.5 Red (quicker than % operator) + } else { // Last 0.5 Red (quicker than % operator) r = 255; g = b = 0; } // Apply saturation and value to R,G,B, pack into 32-bit result: - uint32_t v1 = 1 + val; // 1 to 256; allows >>8 instead of /255 - uint16_t s1 = 1 + sat; // 1 to 256; same reason - uint8_t s2 = 255 - sat; // 255 to 0 + uint32_t v1 = 1 + val; // 1 to 256; allows >>8 instead of /255 + uint16_t s1 = 1 + sat; // 1 to 256; same reason + uint8_t s2 = 255 - sat; // 255 to 0 return ((((((r * s1) >> 8) + s2) * v1) & 0xff00) << 8) | - (((((g * s1) >> 8) + s2) * v1) & 0xff00) | - ( ((((b * s1) >> 8) + s2) * v1) >> 8); + (((((g * s1) >> 8) + s2) * v1) & 0xff00) | + (((((b * s1) >> 8) + s2) * v1) >> 8); } /*! @@ -2482,44 +3296,41 @@ uint32_t Adafruit_NeoPixel::ColorHSV(uint16_t hue, uint8_t sat, uint8_t val) { This gets more pronounced at lower brightness levels. */ uint32_t Adafruit_NeoPixel::getPixelColor(uint16_t n) const { - if(n >= numLEDs) return 0; // Out of bounds, return no color. + if (n >= numLEDs) + return 0; // Out of bounds, return no color. uint8_t *p; - if(wOffset == rOffset) { // Is RGB-type device + if (wOffset == rOffset) { // Is RGB-type device p = &pixels[n * 3]; - if(brightness) { + if (brightness) { // Stored color was decimated by setBrightness(). Returned value // attempts to scale back to an approximation of the original 24-bit // value used when setting the pixel color, but there will always be // some error -- those bits are simply gone. Issue is most // pronounced at low brightness levels. return (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | - (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | - ( (uint32_t)(p[bOffset] << 8) / brightness ); + (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | + ((uint32_t)(p[bOffset] << 8) / brightness); } else { // No brightness adjustment has been made -- return 'raw' color - return ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; + return ((uint32_t)p[rOffset] << 16) | ((uint32_t)p[gOffset] << 8) | + (uint32_t)p[bOffset]; } - } else { // Is RGBW-type device + } else { // Is RGBW-type device p = &pixels[n * 4]; - if(brightness) { // Return scaled color + if (brightness) { // Return scaled color return (((uint32_t)(p[wOffset] << 8) / brightness) << 24) | (((uint32_t)(p[rOffset] << 8) / brightness) << 16) | - (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | - ( (uint32_t)(p[bOffset] << 8) / brightness ); + (((uint32_t)(p[gOffset] << 8) / brightness) << 8) | + ((uint32_t)(p[bOffset] << 8) / brightness); } else { // Return raw color - return ((uint32_t)p[wOffset] << 24) | - ((uint32_t)p[rOffset] << 16) | - ((uint32_t)p[gOffset] << 8) | - (uint32_t)p[bOffset]; + return ((uint32_t)p[wOffset] << 24) | ((uint32_t)p[rOffset] << 16) | + ((uint32_t)p[gOffset] << 8) | (uint32_t)p[bOffset]; } } } - /*! @brief Adjust output brightness. Does not immediately affect what's currently displayed on the LEDs. The next call to show() will @@ -2543,7 +3354,7 @@ void Adafruit_NeoPixel::setBrightness(uint8_t b) { // (color values are interpreted literally; no scaling), 1 = min // brightness (off), 255 = just below max brightness. uint8_t newBrightness = b + 1; - if(newBrightness != brightness) { // Compare against prior value + if (newBrightness != brightness) { // Compare against prior value // Brightness has changed -- re-scale existing data in RAM, // This process is potentially "lossy," especially when increasing // brightness. The tight timing in the WS2811/WS2812 code means there @@ -2554,15 +3365,17 @@ void Adafruit_NeoPixel::setBrightness(uint8_t b) { // the limited number of steps (quantization) in the old data will be // quite visible in the re-scaled version. For a non-destructive // change, you'll need to re-render the full strip data. C'est la vie. - uint8_t c, - *ptr = pixels, - oldBrightness = brightness - 1; // De-wrap old brightness value + uint8_t c, *ptr = pixels, + oldBrightness = brightness - 1; // De-wrap old brightness value uint16_t scale; - if(oldBrightness == 0) scale = 0; // Avoid /0 - else if(b == 255) scale = 65535 / oldBrightness; - else scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; - for(uint16_t i=0; i<numBytes; i++) { - c = *ptr; + if (oldBrightness == 0) + scale = 0; // Avoid /0 + else if (b == 255) + scale = 65535 / oldBrightness; + else + scale = (((uint16_t)newBrightness << 8) - 1) / oldBrightness; + for (uint16_t i = 0; i < numBytes; i++) { + c = *ptr; *ptr++ = (c * scale) >> 8; } brightness = newBrightness; @@ -2573,16 +3386,12 @@ void Adafruit_NeoPixel::setBrightness(uint8_t b) { @brief Retrieve the last-set brightness value for the strip. @return Brightness value: 0 = minimum (off), 255 = maximum. */ -uint8_t Adafruit_NeoPixel::getBrightness(void) const { - return brightness - 1; -} +uint8_t Adafruit_NeoPixel::getBrightness(void) const { return brightness - 1; } /*! @brief Fill the whole NeoPixel strip with 0 / black / off. */ -void Adafruit_NeoPixel::clear(void) { - memset(pixels, 0, numBytes); -} +void Adafruit_NeoPixel::clear(void) { memset(pixels, 0, numBytes); } // A 32-bit variant of gamma8() that applies the same function // to all components of a packed RGB or WRGB value. @@ -2596,6 +3405,35 @@ uint32_t Adafruit_NeoPixel::gamma32(uint32_t x) { // someone's storing information in the unused most significant byte // of an RGB value, but this seems exceedingly rare and if it's // encountered in reality they can mask values going in or coming out. - for(uint8_t i=0; i<4; i++) y[i] = gamma8(y[i]); + for (uint8_t i = 0; i < 4; i++) + y[i] = gamma8(y[i]); return x; // Packed 32-bit return } + +/*! + @brief Fill NeoPixel strip with one or more cycles of hues. + Everyone loves the rainbow swirl so much, now it's canon! + @param first_hue Hue of first pixel, 0-65535, representing one full + cycle of the color wheel. Each subsequent pixel will + be offset to complete one or more cycles over the + length of the strip. + @param reps Number of cycles of the color wheel over the length + of the strip. Default is 1. Negative values can be + used to reverse the hue order. + @param saturation Saturation (optional), 0-255 = gray to pure hue, + default = 255. + @param brightness Brightness/value (optional), 0-255 = off to max, + default = 255. This is distinct and in combination + with any configured global strip brightness. + @param gammify If true (default), apply gamma correction to colors + for better appearance. +*/ +void Adafruit_NeoPixel::rainbow(uint16_t first_hue, int8_t reps, + uint8_t saturation, uint8_t brightness, bool gammify) { + for (uint16_t i=0; i<numLEDs; i++) { + uint16_t hue = first_hue + (i * reps * 65536) / numLEDs; + uint32_t color = ColorHSV(hue, saturation, brightness); + if (gammify) color = gamma32(color); + setPixelColor(i, color); + } +} diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h b/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h index 955be39a23b107845a821cdf6763d25c92b9f9bc..53d29f7ccc536a2d99aecaeb5cdab6ad9e3fb6d8 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/Adafruit_NeoPixel.h @@ -37,16 +37,28 @@ #define ADAFRUIT_NEOPIXEL_H #ifdef ARDUINO - #if (ARDUINO >= 100) - #include <Arduino.h> - #else - #include <WProgram.h> - #include <pins_arduino.h> - #endif +#if (ARDUINO >= 100) +#include <Arduino.h> +#else +#include <WProgram.h> +#include <pins_arduino.h> +#endif + +#ifdef USE_TINYUSB // For Serial when selecting TinyUSB +#include <Adafruit_TinyUSB.h> +#endif + #endif #ifdef TARGET_LPC1768 - #include <Arduino.h> +#include <Arduino.h> +#endif + +#if defined(ARDUINO_ARCH_RP2040) +#include <stdlib.h> +#include "hardware/pio.h" +#include "hardware/clocks.h" +#include "rp2040_pio.h" #endif // The order of primary colors in the NeoPixel data stream can vary among @@ -76,42 +88,42 @@ // RGB NeoPixel permutations; white and red offsets are always same // Offset: W R G B -#define NEO_RGB ((0<<6) | (0<<4) | (1<<2) | (2)) ///< Transmit as R,G,B -#define NEO_RBG ((0<<6) | (0<<4) | (2<<2) | (1)) ///< Transmit as R,B,G -#define NEO_GRB ((1<<6) | (1<<4) | (0<<2) | (2)) ///< Transmit as G,R,B -#define NEO_GBR ((2<<6) | (2<<4) | (0<<2) | (1)) ///< Transmit as G,B,R -#define NEO_BRG ((1<<6) | (1<<4) | (2<<2) | (0)) ///< Transmit as B,R,G -#define NEO_BGR ((2<<6) | (2<<4) | (1<<2) | (0)) ///< Transmit as B,G,R +#define NEO_RGB ((0 << 6) | (0 << 4) | (1 << 2) | (2)) ///< Transmit as R,G,B +#define NEO_RBG ((0 << 6) | (0 << 4) | (2 << 2) | (1)) ///< Transmit as R,B,G +#define NEO_GRB ((1 << 6) | (1 << 4) | (0 << 2) | (2)) ///< Transmit as G,R,B +#define NEO_GBR ((2 << 6) | (2 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,R +#define NEO_BRG ((1 << 6) | (1 << 4) | (2 << 2) | (0)) ///< Transmit as B,R,G +#define NEO_BGR ((2 << 6) | (2 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,R // RGBW NeoPixel permutations; all 4 offsets are distinct // Offset: W R G B -#define NEO_WRGB ((0<<6) | (1<<4) | (2<<2) | (3)) ///< Transmit as W,R,G,B -#define NEO_WRBG ((0<<6) | (1<<4) | (3<<2) | (2)) ///< Transmit as W,R,B,G -#define NEO_WGRB ((0<<6) | (2<<4) | (1<<2) | (3)) ///< Transmit as W,G,R,B -#define NEO_WGBR ((0<<6) | (3<<4) | (1<<2) | (2)) ///< Transmit as W,G,B,R -#define NEO_WBRG ((0<<6) | (2<<4) | (3<<2) | (1)) ///< Transmit as W,B,R,G -#define NEO_WBGR ((0<<6) | (3<<4) | (2<<2) | (1)) ///< Transmit as W,B,G,R +#define NEO_WRGB ((0 << 6) | (1 << 4) | (2 << 2) | (3)) ///< Transmit as W,R,G,B +#define NEO_WRBG ((0 << 6) | (1 << 4) | (3 << 2) | (2)) ///< Transmit as W,R,B,G +#define NEO_WGRB ((0 << 6) | (2 << 4) | (1 << 2) | (3)) ///< Transmit as W,G,R,B +#define NEO_WGBR ((0 << 6) | (3 << 4) | (1 << 2) | (2)) ///< Transmit as W,G,B,R +#define NEO_WBRG ((0 << 6) | (2 << 4) | (3 << 2) | (1)) ///< Transmit as W,B,R,G +#define NEO_WBGR ((0 << 6) | (3 << 4) | (2 << 2) | (1)) ///< Transmit as W,B,G,R -#define NEO_RWGB ((1<<6) | (0<<4) | (2<<2) | (3)) ///< Transmit as R,W,G,B -#define NEO_RWBG ((1<<6) | (0<<4) | (3<<2) | (2)) ///< Transmit as R,W,B,G -#define NEO_RGWB ((2<<6) | (0<<4) | (1<<2) | (3)) ///< Transmit as R,G,W,B -#define NEO_RGBW ((3<<6) | (0<<4) | (1<<2) | (2)) ///< Transmit as R,G,B,W -#define NEO_RBWG ((2<<6) | (0<<4) | (3<<2) | (1)) ///< Transmit as R,B,W,G -#define NEO_RBGW ((3<<6) | (0<<4) | (2<<2) | (1)) ///< Transmit as R,B,G,W +#define NEO_RWGB ((1 << 6) | (0 << 4) | (2 << 2) | (3)) ///< Transmit as R,W,G,B +#define NEO_RWBG ((1 << 6) | (0 << 4) | (3 << 2) | (2)) ///< Transmit as R,W,B,G +#define NEO_RGWB ((2 << 6) | (0 << 4) | (1 << 2) | (3)) ///< Transmit as R,G,W,B +#define NEO_RGBW ((3 << 6) | (0 << 4) | (1 << 2) | (2)) ///< Transmit as R,G,B,W +#define NEO_RBWG ((2 << 6) | (0 << 4) | (3 << 2) | (1)) ///< Transmit as R,B,W,G +#define NEO_RBGW ((3 << 6) | (0 << 4) | (2 << 2) | (1)) ///< Transmit as R,B,G,W -#define NEO_GWRB ((1<<6) | (2<<4) | (0<<2) | (3)) ///< Transmit as G,W,R,B -#define NEO_GWBR ((1<<6) | (3<<4) | (0<<2) | (2)) ///< Transmit as G,W,B,R -#define NEO_GRWB ((2<<6) | (1<<4) | (0<<2) | (3)) ///< Transmit as G,R,W,B -#define NEO_GRBW ((3<<6) | (1<<4) | (0<<2) | (2)) ///< Transmit as G,R,B,W -#define NEO_GBWR ((2<<6) | (3<<4) | (0<<2) | (1)) ///< Transmit as G,B,W,R -#define NEO_GBRW ((3<<6) | (2<<4) | (0<<2) | (1)) ///< Transmit as G,B,R,W +#define NEO_GWRB ((1 << 6) | (2 << 4) | (0 << 2) | (3)) ///< Transmit as G,W,R,B +#define NEO_GWBR ((1 << 6) | (3 << 4) | (0 << 2) | (2)) ///< Transmit as G,W,B,R +#define NEO_GRWB ((2 << 6) | (1 << 4) | (0 << 2) | (3)) ///< Transmit as G,R,W,B +#define NEO_GRBW ((3 << 6) | (1 << 4) | (0 << 2) | (2)) ///< Transmit as G,R,B,W +#define NEO_GBWR ((2 << 6) | (3 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,W,R +#define NEO_GBRW ((3 << 6) | (2 << 4) | (0 << 2) | (1)) ///< Transmit as G,B,R,W -#define NEO_BWRG ((1<<6) | (2<<4) | (3<<2) | (0)) ///< Transmit as B,W,R,G -#define NEO_BWGR ((1<<6) | (3<<4) | (2<<2) | (0)) ///< Transmit as B,W,G,R -#define NEO_BRWG ((2<<6) | (1<<4) | (3<<2) | (0)) ///< Transmit as B,R,W,G -#define NEO_BRGW ((3<<6) | (1<<4) | (2<<2) | (0)) ///< Transmit as B,R,G,W -#define NEO_BGWR ((2<<6) | (3<<4) | (1<<2) | (0)) ///< Transmit as B,G,W,R -#define NEO_BGRW ((3<<6) | (2<<4) | (1<<2) | (0)) ///< Transmit as B,G,R,W +#define NEO_BWRG ((1 << 6) | (2 << 4) | (3 << 2) | (0)) ///< Transmit as B,W,R,G +#define NEO_BWGR ((1 << 6) | (3 << 4) | (2 << 2) | (0)) ///< Transmit as B,W,G,R +#define NEO_BRWG ((2 << 6) | (1 << 4) | (3 << 2) | (0)) ///< Transmit as B,R,W,G +#define NEO_BRGW ((3 << 6) | (1 << 4) | (2 << 2) | (0)) ///< Transmit as B,R,G,W +#define NEO_BGWR ((2 << 6) | (3 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,W,R +#define NEO_BGRW ((3 << 6) | (2 << 4) | (1 << 2) | (0)) ///< Transmit as B,G,R,W // Add NEO_KHZ400 to the color order value to indicate a 400 KHz device. // All but the earliest v1 NeoPixels expect an 800 KHz data stream, this is @@ -134,7 +146,7 @@ #ifdef NEO_KHZ400 typedef uint16_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor #else -typedef uint8_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor +typedef uint8_t neoPixelType; ///< 3rd arg to Adafruit_NeoPixel constructor #endif // These two tables are declared outside the Adafruit_NeoPixel class @@ -149,22 +161,24 @@ for x in range(256): if x&15 == 15: print */ static const uint8_t PROGMEM _NeoPixelSineTable[256] = { - 128,131,134,137,140,143,146,149,152,155,158,162,165,167,170,173, - 176,179,182,185,188,190,193,196,198,201,203,206,208,211,213,215, - 218,220,222,224,226,228,230,232,234,235,237,238,240,241,243,244, - 245,246,248,249,250,250,251,252,253,253,254,254,254,255,255,255, - 255,255,255,255,254,254,254,253,253,252,251,250,250,249,248,246, - 245,244,243,241,240,238,237,235,234,232,230,228,226,224,222,220, - 218,215,213,211,208,206,203,201,198,196,193,190,188,185,182,179, - 176,173,170,167,165,162,158,155,152,149,146,143,140,137,134,131, - 128,124,121,118,115,112,109,106,103,100, 97, 93, 90, 88, 85, 82, - 79, 76, 73, 70, 67, 65, 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, - 37, 35, 33, 31, 29, 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, - 10, 9, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, - 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, - 10, 11, 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, - 37, 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, - 79, 82, 85, 88, 90, 93, 97,100,103,106,109,112,115,118,121,124}; + 128, 131, 134, 137, 140, 143, 146, 149, 152, 155, 158, 162, 165, 167, 170, + 173, 176, 179, 182, 185, 188, 190, 193, 196, 198, 201, 203, 206, 208, 211, + 213, 215, 218, 220, 222, 224, 226, 228, 230, 232, 234, 235, 237, 238, 240, + 241, 243, 244, 245, 246, 248, 249, 250, 250, 251, 252, 253, 253, 254, 254, + 254, 255, 255, 255, 255, 255, 255, 255, 254, 254, 254, 253, 253, 252, 251, + 250, 250, 249, 248, 246, 245, 244, 243, 241, 240, 238, 237, 235, 234, 232, + 230, 228, 226, 224, 222, 220, 218, 215, 213, 211, 208, 206, 203, 201, 198, + 196, 193, 190, 188, 185, 182, 179, 176, 173, 170, 167, 165, 162, 158, 155, + 152, 149, 146, 143, 140, 137, 134, 131, 128, 124, 121, 118, 115, 112, 109, + 106, 103, 100, 97, 93, 90, 88, 85, 82, 79, 76, 73, 70, 67, 65, + 62, 59, 57, 54, 52, 49, 47, 44, 42, 40, 37, 35, 33, 31, 29, + 27, 25, 23, 21, 20, 18, 17, 15, 14, 12, 11, 10, 9, 7, 6, + 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 9, 10, 11, + 12, 14, 15, 17, 18, 20, 21, 23, 25, 27, 29, 31, 33, 35, 37, + 40, 42, 44, 47, 49, 52, 54, 57, 59, 62, 65, 67, 70, 73, 76, + 79, 82, 85, 88, 90, 93, 97, 100, 103, 106, 109, 112, 115, 118, 121, + 124}; /* Similar to above, but for an 8-bit gamma-correction table. Copy & paste this snippet into a Python REPL to regenerate: @@ -175,49 +189,49 @@ for x in range(256): if x&15 == 15: print */ static const uint8_t PROGMEM _NeoPixelGammaTable[256] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, - 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, - 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, - 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, - 20, 21, 21, 22, 22, 23, 24, 24, 25, 25, 26, 27, 27, 28, 29, 29, - 30, 31, 31, 32, 33, 34, 34, 35, 36, 37, 38, 38, 39, 40, 41, 42, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, - 58, 59, 60, 61, 62, 63, 64, 65, 66, 68, 69, 70, 71, 72, 73, 75, - 76, 77, 78, 80, 81, 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, - 97, 99,100,102,103,105,106,108,109,111,112,114,115,117,119,120, - 122,124,125,127,129,130,132,134,136,137,139,141,143,145,146,148, - 150,152,154,156,158,160,162,164,166,168,170,172,174,176,178,180, - 182,184,186,188,191,193,195,197,199,202,204,206,209,211,213,215, - 218,220,223,225,227,230,232,235,237,240,242,245,247,250,252,255}; + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, + 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6, + 6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 10, + 11, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 16, 16, 17, + 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 24, 24, 25, + 25, 26, 27, 27, 28, 29, 29, 30, 31, 31, 32, 33, 34, 34, 35, + 36, 37, 38, 38, 39, 40, 41, 42, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 66, 68, 69, 70, 71, 72, 73, 75, 76, 77, 78, 80, 81, + 82, 84, 85, 86, 88, 89, 90, 92, 93, 94, 96, 97, 99, 100, 102, + 103, 105, 106, 108, 109, 111, 112, 114, 115, 117, 119, 120, 122, 124, 125, + 127, 129, 130, 132, 134, 136, 137, 139, 141, 143, 145, 146, 148, 150, 152, + 154, 156, 158, 160, 162, 164, 166, 168, 170, 172, 174, 176, 178, 180, 182, + 184, 186, 188, 191, 193, 195, 197, 199, 202, 204, 206, 209, 211, 213, 215, + 218, 220, 223, 225, 227, 230, 232, 235, 237, 240, 242, 245, 247, 250, 252, + 255}; -/*! +/*! @brief Class that stores state and functions for interacting with Adafruit NeoPixels and compatible devices. */ class Adafruit_NeoPixel { - public: - +public: // Constructor: number of LEDs, pin number, LED type - Adafruit_NeoPixel(uint16_t n, uint16_t pin=6, - neoPixelType type=NEO_GRB + NEO_KHZ800); + Adafruit_NeoPixel(uint16_t n, int16_t pin = 6, + neoPixelType type = NEO_GRB + NEO_KHZ800); Adafruit_NeoPixel(void); ~Adafruit_NeoPixel(); - void begin(void); - void show(void); - void setPin(uint16_t p); - void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b); - void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, - uint8_t w); - void setPixelColor(uint16_t n, uint32_t c); - void fill(uint32_t c=0, uint16_t first=0, uint16_t count=0); - void setBrightness(uint8_t); - void clear(void); - void updateLength(uint16_t n); - void updateType(neoPixelType t); + void begin(void); + void show(void); + void setPin(int16_t p); + void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b); + void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b, uint8_t w); + void setPixelColor(uint16_t n, uint32_t c); + void fill(uint32_t c = 0, uint16_t first = 0, uint16_t count = 0); + void setBrightness(uint8_t); + void clear(void); + void updateLength(uint16_t n); + void updateType(neoPixelType t); /*! @brief Check whether a call to show() will start sending data immediately or will 'block' for a required interval. NeoPixels @@ -232,10 +246,26 @@ class Adafruit_NeoPixel { if show() would block (meaning some idle time is available). */ bool canShow(void) { - if (endTime > micros()) { - endTime = micros(); + // It's normal and possible for endTime to exceed micros() if the + // 32-bit clock counter has rolled over (about every 70 minutes). + // Since both are uint32_t, a negative delta correctly maps back to + // positive space, and it would seem like the subtraction below would + // suffice. But a problem arises if code invokes show() very + // infrequently...the micros() counter may roll over MULTIPLE times in + // that interval, the delta calculation is no longer correct and the + // next update may stall for a very long time. The check below resets + // the latch counter if a rollover has occurred. This can cause an + // extra delay of up to 300 microseconds in the rare case where a + // show() call happens precisely around the rollover, but that's + // neither likely nor especially harmful, vs. other code that might + // stall for 30+ minutes, or having to document and frequently remind + // and/or provide tech support explaining an unintuitive need for + // show() calls at least once an hour. + uint32_t now = micros(); + if (endTime > now) { + endTime = now; } - return (micros() - endTime) >= 300L; + return (now - endTime) >= 300L; } /*! @brief Get a pointer directly to the NeoPixel data buffer in RAM. @@ -251,19 +281,19 @@ class Adafruit_NeoPixel { writes past the ends of the buffer. Great power, great responsibility and all that. */ - uint8_t *getPixels(void) const { return pixels; }; - uint8_t getBrightness(void) const; + uint8_t *getPixels(void) const { return pixels; }; + uint8_t getBrightness(void) const; /*! @brief Retrieve the pin number used for NeoPixel data output. @return Arduino pin number (-1 if not set). */ - int16_t getPin(void) const { return pin; }; + int16_t getPin(void) const { return pin; }; /*! @brief Return the number of pixels in an Adafruit_NeoPixel strip object. @return Pixel count (0 if not set). */ - uint16_t numPixels(void) const { return numLEDs; } - uint32_t getPixelColor(uint16_t n) const; + uint16_t numPixels(void) const { return numLEDs; } + uint32_t getPixelColor(uint16_t n) const; /*! @brief An 8-bit integer sine wave function, not directly compatible with standard trigonometric units like radians or degrees. @@ -276,7 +306,7 @@ class Adafruit_NeoPixel { a signed int8_t, but you'll most likely want unsigned as this output is often used for pixel brightness in animation effects. */ - static uint8_t sine8(uint8_t x) { + static uint8_t sine8(uint8_t x) { return pgm_read_byte(&_NeoPixelSineTable[x]); // 0-255 in, 0-255 out } /*! @@ -290,7 +320,7 @@ class Adafruit_NeoPixel { NeoPixels in average tasks. If you need finer control you'll need to provide your own gamma-correction function instead. */ - static uint8_t gamma8(uint8_t x) { + static uint8_t gamma8(uint8_t x) { return pgm_read_byte(&_NeoPixelGammaTable[x]); // 0-255 in, 0-255 out } /*! @@ -304,8 +334,8 @@ class Adafruit_NeoPixel { function. Packed RGB format is predictable, regardless of LED strand color order. */ - static uint32_t Color(uint8_t r, uint8_t g, uint8_t b) { - return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b) { + return ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } /*! @brief Convert separate red, green, blue and white values into a @@ -319,10 +349,10 @@ class Adafruit_NeoPixel { function. Packed WRGB format is predictable, regardless of LED strand color order. */ - static uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { - return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; + static uint32_t Color(uint8_t r, uint8_t g, uint8_t b, uint8_t w) { + return ((uint32_t)w << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b; } - static uint32_t ColorHSV(uint16_t hue, uint8_t sat=255, uint8_t val=255); + static uint32_t ColorHSV(uint16_t hue, uint8_t sat = 255, uint8_t val = 255); /*! @brief A gamma-correction function for 32-bit packed RGB or WRGB colors. Makes color transitions appear more perceptially @@ -335,31 +365,45 @@ class Adafruit_NeoPixel { control you'll need to provide your own gamma-correction function instead. */ - static uint32_t gamma32(uint32_t x); + static uint32_t gamma32(uint32_t x); - protected: + void rainbow(uint16_t first_hue = 0, int8_t reps = 1, + uint8_t saturation = 255, uint8_t brightness = 255, + bool gammify = true); -#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled... - bool is800KHz; ///< true if 800 KHz pixels +private: +#if defined(ARDUINO_ARCH_RP2040) + void rp2040Init(uint8_t pin, bool is800KHz); + void rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz); #endif - bool begun; ///< true if begin() previously called - uint16_t numLEDs; ///< Number of RGB LEDs in strip - uint16_t numBytes; ///< Size of 'pixels' buffer below - int16_t pin; ///< Output pin number (-1 if not yet set) - uint8_t brightness; ///< Strip brightness 0-255 (stored as +1) - uint8_t *pixels; ///< Holds LED color values (3 or 4 bytes each) - uint8_t rOffset; ///< Red index within each 3- or 4-byte pixel - uint8_t gOffset; ///< Index of green byte - uint8_t bOffset; ///< Index of blue byte - uint8_t wOffset; ///< Index of white (==rOffset if no white) - uint32_t endTime; ///< Latch timing reference + +protected: +#ifdef NEO_KHZ400 // If 400 KHz NeoPixel support enabled... + bool is800KHz; ///< true if 800 KHz pixels +#endif + bool begun; ///< true if begin() previously called + uint16_t numLEDs; ///< Number of RGB LEDs in strip + uint16_t numBytes; ///< Size of 'pixels' buffer below + int16_t pin; ///< Output pin number (-1 if not yet set) + uint8_t brightness; ///< Strip brightness 0-255 (stored as +1) + uint8_t *pixels; ///< Holds LED color values (3 or 4 bytes each) + uint8_t rOffset; ///< Red index within each 3- or 4-byte pixel + uint8_t gOffset; ///< Index of green byte + uint8_t bOffset; ///< Index of blue byte + uint8_t wOffset; ///< Index of white (==rOffset if no white) + uint32_t endTime; ///< Latch timing reference #ifdef __AVR__ - volatile uint8_t *port; ///< Output PORT register - uint8_t pinMask; ///< Output PORT bitmask + volatile uint8_t *port; ///< Output PORT register + uint8_t pinMask; ///< Output PORT bitmask #endif #if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) - GPIO_TypeDef *gpioPort; ///< Output GPIO PORT - uint32_t gpioPin; ///< Output GPIO PIN + GPIO_TypeDef *gpioPort; ///< Output GPIO PORT + uint32_t gpioPin; ///< Output GPIO PIN +#endif +#if defined(ARDUINO_ARCH_RP2040) + PIO pio = pio0; + int sm = 0; + bool init = true; #endif }; diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/README.md b/ampel-firmware/src/lib/Adafruit_NeoPixel/README.md index 8c150501f30d226305021e7f0814616924402fea..eff1337119a105870cb989b97dd10648066c2e90 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/README.md +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/README.md @@ -56,6 +56,10 @@ Compatibility notes: Port A is not supported on any AVR processors at this time - ESP8266 any speed - ESP32 any speed - Nordic nRF52 (Adafruit Feather nRF52), nRF51 (micro:bit) + - Infineon XMC1100 BootKit @ 32 MHz + - Infineon XMC1100 2Go @ 32 MHz + - Infineon XMC1300 BootKit @ 32 MHz + - Infineon XMC4700 RelaxKit, XMC4800 RelaxKit, XMC4800 IoT Amazon FreeRTOS Kit @ 144 MHz Check forks for other architectures not listed here! diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/esp.c b/ampel-firmware/src/lib/Adafruit_NeoPixel/esp.c index 9d2853ff6631264a7e9a3ce68cc3f8f5c5f9683d..c480a20501c7cf6d5786dbd6fff0e45864c5faf5 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/esp.c +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/esp.c @@ -22,6 +22,12 @@ #include <Arduino.h> #include "driver/rmt.h" +#if defined(ESP_IDF_VERSION) +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) +#define HAS_ESP_IDF_4 +#endif +#endif + // This code is adapted from the ESP-IDF v3.4 RMT "led_strip" example, altered // to work with the Arduino version of the ESP-IDF (3.2) @@ -89,6 +95,7 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) if (!rmt_reserved_channels[i]) { rmt_reserved_channels[i] = true; channel = i; + break; } } if (channel == ADAFRUIT_RMT_CHANNEL_MAX) { @@ -96,6 +103,10 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) return; } +#if defined(HAS_ESP_IDF_4) + rmt_config_t config = RMT_DEFAULT_CONFIG_TX(pin, channel); + config.clk_div = 2; +#else // Match default TX config from ESP-IDF version 3.4 rmt_config_t config = { .rmt_mode = RMT_MODE_TX, @@ -113,12 +124,16 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) .idle_output_en = true, } }; +#endif rmt_config(&config); rmt_driver_install(config.channel, 0, 0); // Convert NS timings to ticks uint32_t counter_clk_hz = 0; +#if defined(HAS_ESP_IDF_4) + rmt_get_counter_clock(channel, &counter_clk_hz); +#else // this emulates the rmt_get_counter_clock() function from ESP-IDF 3.4 if (RMT_LL_HW_BASE->conf_ch[config.channel].conf1.ref_always_on == RMT_BASECLK_REF) { uint32_t div_cnt = RMT_LL_HW_BASE->conf_ch[config.channel].conf0.div_cnt; @@ -129,6 +144,7 @@ void espShow(uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) uint32_t div = div_cnt == 0 ? 256 : div_cnt; counter_clk_hz = APB_CLK_FREQ / (div); } +#endif // NS to tick converter float ratio = (float)counter_clk_hz / 1e9; diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/esp8266.c b/ampel-firmware/src/lib/Adafruit_NeoPixel/esp8266.c index bdfa1050669412da0cba1eba318929bda54a9533..51c3f3c8a34f4856f9c2636da364bed5081d2918 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/esp8266.c +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/esp8266.c @@ -17,16 +17,16 @@ static inline uint32_t _getCycleCount(void) { } #ifdef ESP8266 -void ICACHE_RAM_ATTR espShow( - uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { +IRAM_ATTR void espShow( + uint8_t pin, uint8_t *pixels, uint32_t numBytes, __attribute__((unused)) boolean is800KHz) { #else void espShow( uint8_t pin, uint8_t *pixels, uint32_t numBytes, boolean is800KHz) { #endif -#define CYCLES_800_T0H (F_CPU / 2500000) // 0.4us -#define CYCLES_800_T1H (F_CPU / 1250000) // 0.8us -#define CYCLES_800 (F_CPU / 800000) // 1.25us per bit +#define CYCLES_800_T0H (F_CPU / 2500001) // 0.4us +#define CYCLES_800_T1H (F_CPU / 1250001) // 0.8us +#define CYCLES_800 (F_CPU / 800001) // 1.25us per bit #define CYCLES_400_T0H (F_CPU / 2000000) // 0.5uS #define CYCLES_400_T1H (F_CPU / 833333) // 1.2us #define CYCLES_400 (F_CPU / 400000) // 2.5us per bit diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/library.properties b/ampel-firmware/src/lib/Adafruit_NeoPixel/library.properties index 445fa4891a5661846da99b0e5fb8bee8a851c9fb..b1554cd30b69174beb6b286eac7741d8e28746df 100644 --- a/ampel-firmware/src/lib/Adafruit_NeoPixel/library.properties +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/library.properties @@ -1,5 +1,5 @@ name=Adafruit NeoPixel -version=1.7.0 +version=1.10.3 author=Adafruit maintainer=Adafruit <info@adafruit.com> sentence=Arduino library for controlling single-wire-based LED pixels and strip. diff --git a/ampel-firmware/src/lib/Adafruit_NeoPixel/rp2040_pio.h b/ampel-firmware/src/lib/Adafruit_NeoPixel/rp2040_pio.h new file mode 100644 index 0000000000000000000000000000000000000000..f7ccd46de0a5cc8510f86b10069c6417b57fdde4 --- /dev/null +++ b/ampel-firmware/src/lib/Adafruit_NeoPixel/rp2040_pio.h @@ -0,0 +1,63 @@ +// -------------------------------------------------- // +// This file is autogenerated by pioasm; do not edit! // +// -------------------------------------------------- // + +// Unless you know what you are doing... +// Lines 47 and 52 have been edited to set transmit bit count + +#if !PICO_NO_HARDWARE +#include "hardware/pio.h" +#endif + +// ------ // +// ws2812 // +// ------ // + +#define ws2812_wrap_target 0 +#define ws2812_wrap 3 + +#define ws2812_T1 2 +#define ws2812_T2 5 +#define ws2812_T3 3 + +static const uint16_t ws2812_program_instructions[] = { + // .wrap_target + 0x6221, // 0: out x, 1 side 0 [2] + 0x1123, // 1: jmp !x, 3 side 1 [1] + 0x1400, // 2: jmp 0 side 1 [4] + 0xa442, // 3: nop side 0 [4] + // .wrap +}; + +#if !PICO_NO_HARDWARE +static const struct pio_program ws2812_program = { + .instructions = ws2812_program_instructions, + .length = 4, + .origin = -1, +}; + +static inline pio_sm_config ws2812_program_get_default_config(uint offset) { + pio_sm_config c = pio_get_default_sm_config(); + sm_config_set_wrap(&c, offset + ws2812_wrap_target, offset + ws2812_wrap); + sm_config_set_sideset(&c, 1, false, false); + return c; +} + +#include "hardware/clocks.h" +static inline void ws2812_program_init(PIO pio, uint sm, uint offset, uint pin, + float freq, uint bits) { + pio_gpio_init(pio, pin); + pio_sm_set_consecutive_pindirs(pio, sm, pin, 1, true); + pio_sm_config c = ws2812_program_get_default_config(offset); + sm_config_set_sideset_pins(&c, pin); + sm_config_set_out_shift(&c, false, true, + bits); // <----<<< Length changed to "bits" + sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX); + int cycles_per_bit = ws2812_T1 + ws2812_T2 + ws2812_T3; + float div = clock_get_hz(clk_sys) / (freq * cycles_per_bit); + sm_config_set_clkdiv(&c, div); + pio_sm_init(pio, sm, offset, &c); + pio_sm_set_enabled(pio, sm, true); +} + +#endif