From 903703b8664c3f612864c0a5808cc58ba7916a98 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 24 May 2025 16:20:15 -0400 Subject: [PATCH 1/5] clean up and hand-add some of https://github.com/adafruit/Adafruit_NeoPixel/pull/381 --- Adafruit_NeoPixel.cpp | 72 +++++++++++++++------------------------ Adafruit_NeoPixel.h | 32 +++++++++-------- Adafruit_Neopixel_RP2.cpp | 72 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 60 deletions(-) create mode 100644 Adafruit_Neopixel_RP2.cpp diff --git a/Adafruit_NeoPixel.cpp b/Adafruit_NeoPixel.cpp index 6be7196..30acd2c 100644 --- a/Adafruit_NeoPixel.cpp +++ b/Adafruit_NeoPixel.cpp @@ -86,16 +86,7 @@ Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, int16_t p, neoPixelType t) 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 + #if defined(ESP32) #if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0) espInit(); @@ -133,6 +124,13 @@ Adafruit_NeoPixel::~Adafruit_NeoPixel() { numLEDs = numBytes = 0; show(); #endif + + +#if defined(ARDUINO_ARCH_RP2040) + // Release any PIO + rp2040releasePIO(); +#endif + free(pixels); if (pin >= 0) pinMode(pin, INPUT); @@ -141,12 +139,27 @@ Adafruit_NeoPixel::~Adafruit_NeoPixel() { /*! @brief Configure NeoPixel pin for output. */ -void Adafruit_NeoPixel::begin(void) { +bool Adafruit_NeoPixel::begin(void) { if (pin >= 0) { pinMode(pin, OUTPUT); digitalWrite(pin, LOW); + } else { + begun = false; + return false; } + +#if defined(ARDUINO_ARCH_RP2040) + // if we're calling begin() again, unclaim any existing PIO resc. + rp2040releasePIO(); + if (! rp2040claimPIO()) { + begun = false; + return false; + } + +#endif + begun = true; + return true; } /*! @@ -209,38 +222,8 @@ void Adafruit_NeoPixel::updateType(neoPixelType t) { } } -// 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); -} -#elif defined(ARDUINO_ARCH_CH32) +#if defined(ARDUINO_ARCH_CH32) // F_CPU is defined to SystemCoreClock (not constant number) #if SYSCLK_FREQ_144MHz_HSE == 144000000 || SYSCLK_FREQ_HSE == 144000000 || \ @@ -1908,7 +1891,7 @@ void Adafruit_NeoPixel::show(void) { #elif defined(ARDUINO_ARCH_RP2040) // Use PIO - rp2040Show(pin, pixels, numBytes, is800KHz); + rp2040Show(pixels, numBytes); #elif defined(TEENSYDUINO) && \ defined(KINETISK) // Teensy 3.0, 3.1, 3.2, 3.5, 3.6 @@ -3382,8 +3365,7 @@ if(is800KHz) { #elif defined(ARDUINO_ARCH_CH32) ch32Show(gpioPort, gpioPin, pixels, numBytes, is800KHz); #elif defined(ARDUINO_ARCH_RP2040) && defined(__riscv) - // Use PIO - rp2040Show(pin, pixels, numBytes, is800KHz); + rp2040Show(pixels, numBytes); // Use PIO #else #error Architecture not supported #endif diff --git a/Adafruit_NeoPixel.h b/Adafruit_NeoPixel.h index 6f38a56..3b00222 100644 --- a/Adafruit_NeoPixel.h +++ b/Adafruit_NeoPixel.h @@ -37,12 +37,7 @@ #define ADAFRUIT_NEOPIXEL_H #ifdef ARDUINO -#if (ARDUINO >= 100) #include -#else -#include -#include -#endif #ifdef USE_TINYUSB // For Serial when selecting TinyUSB #include @@ -235,7 +230,7 @@ class Adafruit_NeoPixel { Adafruit_NeoPixel(void); ~Adafruit_NeoPixel(); - void begin(void); + bool begin(void); void show(void); void setPin(int16_t p); void setPixelColor(uint16_t n, uint8_t r, uint8_t g, uint8_t b); @@ -389,15 +384,20 @@ class Adafruit_NeoPixel { 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); + bool rp2040claimPIO(void); + void rp2040releasePIO(void); + void rp2040Show(uint8_t *pixels, uint32_t numBytes); + PIO pio = NULL; + int8_t pio_sm = -1; + uint32_t pio_program_offset = 0; #endif 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 + + bool begun; ///< true if begin() previously called successfully 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) @@ -408,22 +408,24 @@ class Adafruit_NeoPixel { 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 #endif -#if defined(ARDUINO_ARCH_STM32) || defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) || defined(ARDUINO_ARCH_CH32) || defined(_PY32_DEF_) + +#if defined(ARDUINO_ARCH_STM32) || \ + defined(ARDUINO_ARCH_ARDUINO_CORE_STM32) || \ + defined(ARDUINO_ARCH_CH32) || \ + defined(_PY32_DEF_) GPIO_TypeDef *gpioPort; ///< Output GPIO PORT uint32_t gpioPin; ///< Output GPIO PIN #endif + #if defined(TARGET_GIGA) || defined(TARGET_M4) mbed::DigitalInOut *gpio; #endif -#if defined(ARDUINO_ARCH_RP2040) - PIO pio = pio0; - int sm = 0; - bool init = true; -#endif + }; #endif // ADAFRUIT_NEOPIXEL_H diff --git a/Adafruit_Neopixel_RP2.cpp b/Adafruit_Neopixel_RP2.cpp new file mode 100644 index 0000000..aa96203 --- /dev/null +++ b/Adafruit_Neopixel_RP2.cpp @@ -0,0 +1,72 @@ +#if defined(ARDUINO_ARCH_RP2040)// RP2040 specific driver + +#include "Adafruit_NeoPixel.h" + +bool Adafruit_NeoPixel::rp2040claimPIO(void) { + // Find a PIO with enough available space in its instruction memory + pio = pio0; + if (pio_can_add_program(pio, &ws2812_program)) { + pio_program_offset = pio_add_program(pio, &ws2812_program); + } else { + // ok try pio1 + pio = pio1; + if (pio_can_add_program(pio, &ws2812_program)) { + pio_program_offset = pio_add_program(pio, &ws2812_program); + } else { + // ok try pio2 (RP2350) + pio = pio2; + if (pio_can_add_program(pio, &ws2812_program)) { + pio_program_offset = pio_add_program(pio, &ws2812_program); + } else { + pio = NULL; + return false; + } + } + } + + // Find a free SM on one of the PIO's + pio_sm = pio_claim_unused_sm(pio, false); // don't panic + if (pio_sm < 0) { + return false; + } + + // yay ok! + + if (is800KHz) { + // 800kHz, 8 bit transfers + ws2812_program_init(pio, pio_sm, pio_program_offset, pin, 800000, 8); + } else { + // 400kHz, 8 bit transfers + ws2812_program_init(pio, pio_sm, pio_program_offset, pin, 400000, 8); + } + + return true; +} + +void Adafruit_NeoPixel::rp2040releasePIO(void) { + if (pio == NULL) + return; + + pio_remove_program(pio, &ws2812_program, pio_program_offset); + + if (pio_sm < 0) + return; + + pio_sm_set_enabled(pio, pio_sm, false); + pio_sm_unclaim(pio, pio_sm); +} + + +// Private, called from show() +void Adafruit_NeoPixel::rp2040Show(uint8_t *pixels, uint32_t numBytes) +{ + // verify we have a valid PIO and state machine + if (! pio || (pio_sm < 0)) { + return; + } + + while(numBytes--) + // Bits for transmission must be shifted to top 8 bits + pio_sm_put_blocking(pio, pio_sm, ((uint32_t)*pixels++)<< 24); +} +#endif From 8567eb05c858fdf35f35be41ff811463a2e52143 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 24 May 2025 16:24:41 -0400 Subject: [PATCH 2/5] fix pio selection --- Adafruit_Neopixel_RP2.cpp | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/Adafruit_Neopixel_RP2.cpp b/Adafruit_Neopixel_RP2.cpp index aa96203..2be620e 100644 --- a/Adafruit_Neopixel_RP2.cpp +++ b/Adafruit_Neopixel_RP2.cpp @@ -4,25 +4,28 @@ bool Adafruit_NeoPixel::rp2040claimPIO(void) { // Find a PIO with enough available space in its instruction memory - pio = pio0; - if (pio_can_add_program(pio, &ws2812_program)) { - pio_program_offset = pio_add_program(pio, &ws2812_program); - } else { - // ok try pio1 - pio = pio1; - if (pio_can_add_program(pio, &ws2812_program)) { - pio_program_offset = pio_add_program(pio, &ws2812_program); - } else { - // ok try pio2 (RP2350) - pio = pio2; - if (pio_can_add_program(pio, &ws2812_program)) { + pio = NULL; + +#ifdef pio2 + // RP2350 - has 3 PIOs + PIO pios[] = {pio0, pio1, pio2}; +#else + // RP2040 - has 2 PIOs + PIO pios[] = {pio0, pio1}; +#endif + + uint8_t pio_count = sizeof(pios) / sizeof(pios[0]); + + for (uint8_t i = 0; i < pio_count; i++) { + if (pio_can_add_program(pios[i], &ws2812_program)) { + pio = pios[i]; pio_program_offset = pio_add_program(pio, &ws2812_program); - } else { - pio = NULL; - return false; - } + break; } } + if (pio == NULL) { + return false; // No PIO available + } // Find a free SM on one of the PIO's pio_sm = pio_claim_unused_sm(pio, false); // don't panic From 6b4ffe36a920bdfc080ca0ae997b6e6d87e5576b Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 24 May 2025 16:35:34 -0400 Subject: [PATCH 3/5] doxy --- Adafruit_NeoPixel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Adafruit_NeoPixel.cpp b/Adafruit_NeoPixel.cpp index 30acd2c..08f3c78 100644 --- a/Adafruit_NeoPixel.cpp +++ b/Adafruit_NeoPixel.cpp @@ -138,6 +138,7 @@ Adafruit_NeoPixel::~Adafruit_NeoPixel() { /*! @brief Configure NeoPixel pin for output. + @returns False if we weren't able to claim resources required */ bool Adafruit_NeoPixel::begin(void) { if (pin >= 0) { From c2e104673660f765f7c8ff997e7a858a11766e87 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 24 May 2025 16:53:36 -0400 Subject: [PATCH 4/5] use modern API --- Adafruit_NeoPixel.h | 4 ++-- Adafruit_Neopixel_RP2.cpp | 38 +++++++------------------------------- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/Adafruit_NeoPixel.h b/Adafruit_NeoPixel.h index 3b00222..d741372 100644 --- a/Adafruit_NeoPixel.h +++ b/Adafruit_NeoPixel.h @@ -388,8 +388,8 @@ class Adafruit_NeoPixel { void rp2040releasePIO(void); void rp2040Show(uint8_t *pixels, uint32_t numBytes); PIO pio = NULL; - int8_t pio_sm = -1; - uint32_t pio_program_offset = 0; + uint pio_sm = -1; + uint pio_program_offset = 0; #endif protected: diff --git a/Adafruit_Neopixel_RP2.cpp b/Adafruit_Neopixel_RP2.cpp index 2be620e..7349b1f 100644 --- a/Adafruit_Neopixel_RP2.cpp +++ b/Adafruit_Neopixel_RP2.cpp @@ -6,33 +6,15 @@ bool Adafruit_NeoPixel::rp2040claimPIO(void) { // Find a PIO with enough available space in its instruction memory pio = NULL; -#ifdef pio2 - // RP2350 - has 3 PIOs - PIO pios[] = {pio0, pio1, pio2}; -#else - // RP2040 - has 2 PIOs - PIO pios[] = {pio0, pio1}; -#endif - - uint8_t pio_count = sizeof(pios) / sizeof(pios[0]); - - for (uint8_t i = 0; i < pio_count; i++) { - if (pio_can_add_program(pios[i], &ws2812_program)) { - pio = pios[i]; - pio_program_offset = pio_add_program(pio, &ws2812_program); - break; - } - } - if (pio == NULL) { + if (! pio_claim_free_sm_and_add_program_for_gpio_range(&ws2812_program, + &pio, &pio_sm, &pio_program_offset, + pin, 1, true)) { + pio = NULL; + pio_sm = -1; + pio_program_offset = 0; return false; // No PIO available } - // Find a free SM on one of the PIO's - pio_sm = pio_claim_unused_sm(pio, false); // don't panic - if (pio_sm < 0) { - return false; - } - // yay ok! if (is800KHz) { @@ -50,13 +32,7 @@ void Adafruit_NeoPixel::rp2040releasePIO(void) { if (pio == NULL) return; - pio_remove_program(pio, &ws2812_program, pio_program_offset); - - if (pio_sm < 0) - return; - - pio_sm_set_enabled(pio, pio_sm, false); - pio_sm_unclaim(pio, pio_sm); + pio_remove_program_and_unclaim_sm(&ws2812_program, pio, pio_sm, pio_program_offset); } From 70d02aae78fa83d8517c9fb4679a3aa2038369a5 Mon Sep 17 00:00:00 2001 From: Tyeth Gundry Date: Wed, 28 May 2025 15:50:56 +0100 Subject: [PATCH 5/5] Update library.properties - bump version to 1.15.1 --- library.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library.properties b/library.properties index e7ead18..39c66a5 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=Adafruit NeoPixel -version=1.15.0 +version=1.15.1 author=Adafruit maintainer=Adafruit sentence=Arduino library for controlling single-wire-based LED pixels and strip.