diff --git a/Adafruit_NeoPixel.cpp b/Adafruit_NeoPixel.cpp index a555438..d900a81 100644 --- a/Adafruit_NeoPixel.cpp +++ b/Adafruit_NeoPixel.cpp @@ -83,14 +83,11 @@ Adafruit_NeoPixel::Adafruit_NeoPixel(uint16_t n, int16_t p, neoPixelType 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; + #ifdef NEO_KHZ400 + rp2040Init(p, is800KHz); + #else + rp2040Init(p, true); + #endif #endif } @@ -117,6 +114,13 @@ Adafruit_NeoPixel::Adafruit_NeoPixel() @brief Deallocate Adafruit_NeoPixel object, set data pin back to INPUT. */ Adafruit_NeoPixel::~Adafruit_NeoPixel() { + #if defined(ARDUINO_ARCH_RP2040) + if (!init) { + pio_sm_set_enabled(pio, pio_sm, false); + pio_sm_unclaim(pio, pio_sm); + pio_remove_program(pio, &ws2812_program, pio_program_offset); + } + #endif free(pixels); if (pin >= 0) pinMode(pin, INPUT); @@ -197,19 +201,32 @@ void Adafruit_NeoPixel::updateType(neoPixelType t) { #if defined(ARDUINO_ARCH_RP2040) void Adafruit_NeoPixel::rp2040Init(uint8_t pin, bool is800KHz) { - uint offset = pio_add_program(pio, &ws2812_program); + // Find a PIO with enough available space in its instruction memory + pio = pio0; + if (!pio_can_add_program(this->pio, &ws2812_program)) { + pio = pio1; + } + + // Will PANIC if not enough space in either PIO's instruction memory + pio_program_offset = pio_add_program(pio, &ws2812_program); + // Find a free SM on one of the PIO's + pio_sm = pio_claim_unused_sm(pio, true); // panic if no SM is free + if (is800KHz) { // 800kHz, 8 bit transfers - ws2812_program_init(pio, sm, offset, pin, 800000, 8); + ws2812_program_init(pio, pio_sm, pio_program_offset, pin, 800000, 8); } else { // 400kHz, 8 bit transfers - ws2812_program_init(pio, sm, offset, pin, 400000, 8); + ws2812_program_init(pio, pio_sm, pio_program_offset, pin, 400000, 8); } + + this->init = false; } + // Not a user API void Adafruit_NeoPixel::rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBytes, bool is800KHz) { @@ -217,12 +234,11 @@ void Adafruit_NeoPixel::rp2040Show(uint8_t pin, uint8_t *pixels, uint32_t numBy { // 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); + pio_sm_put_blocking(pio, pio_sm, ((uint32_t)*pixels++)<< 24); } #endif diff --git a/Adafruit_NeoPixel.h b/Adafruit_NeoPixel.h index ba022f6..4eabca6 100644 --- a/Adafruit_NeoPixel.h +++ b/Adafruit_NeoPixel.h @@ -404,7 +404,8 @@ class Adafruit_NeoPixel { #endif #if defined(ARDUINO_ARCH_RP2040) PIO pio = pio0; - int sm = 0; + int pio_sm = -1; + uint pio_program_offset = 0; bool init = true; #endif };