diff --git a/Adafruit_NeoPixel.cpp b/Adafruit_NeoPixel.cpp index 960b59a..edb8eb4 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); @@ -140,13 +138,29 @@ Adafruit_NeoPixel::~Adafruit_NeoPixel() { /*! @brief Configure NeoPixel pin for output. + @returns False if we weren't able to claim resources required */ -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 +223,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 +1892,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 +3366,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..d741372 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; + uint pio_sm = -1; + uint 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..7349b1f --- /dev/null +++ b/Adafruit_Neopixel_RP2.cpp @@ -0,0 +1,51 @@ +#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 = 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 + } + + // 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_and_unclaim_sm(&ws2812_program, pio, pio_sm, pio_program_offset); +} + + +// 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 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.