diff --git a/keywords.txt b/keywords.txt index 285d3ad..6e3a9fa 100644 --- a/keywords.txt +++ b/keywords.txt @@ -188,6 +188,13 @@ NeoEsp32I2s1Tm1814InvertedMethod KEYWORD1 NeoEsp32I2s1800KbpsInvertedMethod KEYWORD1 NeoEsp32I2s1400KbpsInvertedMethod KEYWORD1 NeoEsp32I2s1Apa106InvertedMethod KEYWORD1 +NeoEsp32RmtNWs2811Method KEYWORD1 +NeoEsp32RmtNWs2812xMethod KEYWORD1 +NeoEsp32RmtNSk6812Method KEYWORD1 +NeoEsp32RmtNTm1814Method KEYWORD1 +NeoEsp32RmtNApa106Method KEYWORD1 +NeoEsp32RmtN800KbpsMethod KEYWORD1 +NeoEsp32RmtN400KbpsMethod KEYWORD1 NeoEsp32Rmt0Ws2811Method KEYWORD1 NeoEsp32Rmt0Ws2812xMethod KEYWORD1 NeoEsp32Rmt0Sk6812Method KEYWORD1 @@ -244,6 +251,13 @@ NeoEsp32Rmt7Tm1814Method KEYWORD1 NeoEsp32Rmt7Apa106Method KEYWORD1 NeoEsp32Rmt7800KbpsMethod KEYWORD1 NeoEsp32Rmt7400KbpsMethod KEYWORD1 +NeoEsp32RmtNWs2811InvertedMethod KEYWORD1 +NeoEsp32RmtNWs2812xInvertedMethod KEYWORD1 +NeoEsp32RmtNSk6812InvertedMethod KEYWORD1 +NeoEsp32RmtNTm1814InvertedMethod KEYWORD1 +NeoEsp32RmtNApa106InvertedMethod KEYWORD1 +NeoEsp32RmtN800KbpsInvertedMethod KEYWORD1 +NeoEsp32RmtN400KbpsInvertedMethod KEYWORD1 NeoEsp32Rmt0Ws2811InvertedMethod KEYWORD1 NeoEsp32Rmt0Ws2812xInvertedMethod KEYWORD1 NeoEsp32Rmt0Sk6812InvertedMethod KEYWORD1 @@ -320,6 +334,12 @@ NeoEsp32BitBangLc8812InvertedMethod KEYWORD1 NeoEsp32BitBangApa106InvertedMethod KEYWORD1 NeoEsp32BitBang800KbpsInvertedMethod KEYWORD1 NeoEsp32BitBang400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwmNWs2812xMethod KEYWORD1 +NeoNrf52xPwmNSk6812Method KEYWORD1 +NeoNrf52xPwmNTm1814Method KEYWORD1 +NeoNrf52xPwmN800KbpsMethod KEYWORD1 +NeoNrf52xPwmN400KbpsMethod KEYWORD1 +NeoNrf52xPwmNApa106Method KEYWORD1 NeoNrf52xPwm0Ws2812xMethod KEYWORD1 NeoNrf52xPwm0Sk6812Method KEYWORD1 NeoNrf52xPwm0Tm1814Method KEYWORD1 @@ -344,6 +364,12 @@ NeoNrf52xPwm3Tm1814Method KEYWORD1 NeoNrf52xPwm3800KbpsMethod KEYWORD1 NeoNrf52xPwm3400KbpsMethod KEYWORD1 NeoNrf52xPwm3Apa106Method KEYWORD1 +NeoNrf52xPwmNWs2812xInvertedMethod KEYWORD1 +NeoNrf52xPwmNSk6812InvertedMethod KEYWORD1 +NeoNrf52xPwmNTm1814InvertedMethod KEYWORD1 +NeoNrf52xPwmN800KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwmN400KbpsInvertedMethod KEYWORD1 +NeoNrf52xPwmNApa106InvertedMethod KEYWORD1 NeoNrf52xPwm0Ws2812xInvertedMethod KEYWORD1 NeoNrf52xPwm0Sk6812InvertedMethod KEYWORD1 NeoNrf52xPwm0Tm1814InvertedMethod KEYWORD1 diff --git a/src/NeoPixelBus.h b/src/NeoPixelBus.h index 277c963..5380428 100644 --- a/src/NeoPixelBus.h +++ b/src/NeoPixelBus.h @@ -85,6 +85,8 @@ License along with NeoPixel. If not, see #include "internal/NeoEase.h" #include "internal/NeoGamma.h" +#include "internal/NeoBusChannel.h" + #include "internal/DotStarGenericMethod.h" #include "internal/Lpd8806GenericMethod.h" #include "internal/Lpd6803GenericMethod.h" @@ -120,8 +122,6 @@ License along with NeoPixel. If not, see #endif - - template class NeoPixelBus { public: @@ -135,6 +135,13 @@ public: { } + NeoPixelBus(uint16_t countPixels, uint8_t pin, NeoBusChannel channel) : + _countPixels(countPixels), + _state(0), + _method(pin, countPixels, T_COLOR_FEATURE::PixelSize, T_COLOR_FEATURE::SettingsSize, channel) + { + } + NeoPixelBus(uint16_t countPixels, uint8_t pinClock, uint8_t pinData) : _countPixels(countPixels), _state(0), diff --git a/src/internal/NeoBusChannel.h b/src/internal/NeoBusChannel.h new file mode 100644 index 0000000..2743bff --- /dev/null +++ b/src/internal/NeoBusChannel.h @@ -0,0 +1,29 @@ +#pragma once + +// For those platforms/methods that support dynamic channel setting +enum NeoBusChannel +{ + NeoBusChannel_0, + NeoBusChannel_1, + NeoBusChannel_2, + +// NRF52x has only 3 or 4 channels of PWM +#if defined(ARDUINO_ARCH_NRF52840) + +#if defined(NRF_PWM3) + NeoBusChannel_3 +#endif + +// ESP32 has either 8 or 4 channels (S2 has only 4) +#elif defined(ARDUINO_ARCH_ESP32) + + NeoBusChannel_3, + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) + NeoBusChannel_4, + NeoBusChannel_5, + NeoBusChannel_6, + NeoBusChannel_7, +#endif // CONFIG_IDF_TARGET_ESP32S2 +#endif // ARDUINO_ARCH_ESP32 +}; \ No newline at end of file diff --git a/src/internal/NeoEsp32RmtMethod.cpp b/src/internal/NeoEsp32RmtMethod.cpp index 278d56d..4bea928 100644 --- a/src/internal/NeoEsp32RmtMethod.cpp +++ b/src/internal/NeoEsp32RmtMethod.cpp @@ -27,6 +27,7 @@ License along with NeoPixel. If not, see . -------------------------------------------------------------------------*/ +#include "NeoBusChannel.h" #include "NeoEsp32RmtMethod.h" #ifdef ARDUINO_ARCH_ESP32 diff --git a/src/internal/NeoEsp32RmtMethod.h b/src/internal/NeoEsp32RmtMethod.h index 3f33958..d626e99 100644 --- a/src/internal/NeoEsp32RmtMethod.h +++ b/src/internal/NeoEsp32RmtMethod.h @@ -322,24 +322,32 @@ public: class NeoEsp32RmtChannel0 { public: + NeoEsp32RmtChannel0() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_0; }; class NeoEsp32RmtChannel1 { public: + NeoEsp32RmtChannel1() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_1; }; class NeoEsp32RmtChannel2 { public: + NeoEsp32RmtChannel2() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_2; }; class NeoEsp32RmtChannel3 { public: + NeoEsp32RmtChannel3() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3; }; @@ -348,29 +356,50 @@ public: class NeoEsp32RmtChannel4 { public: + NeoEsp32RmtChannel4() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_4; }; class NeoEsp32RmtChannel5 { public: + NeoEsp32RmtChannel5() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_5; }; class NeoEsp32RmtChannel6 { public: + NeoEsp32RmtChannel6() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_6; }; class NeoEsp32RmtChannel7 { public: + NeoEsp32RmtChannel7() {}; + const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_7; }; #endif +// dynamic channel support +class NeoEsp32RmtChannelN +{ +public: + NeoEsp32RmtChannelN(NeoBusChannel channel) : + RmtChannelNumber(static_cast(channel)) + { + } + NeoEsp32RmtChannelN() = delete; // no default constructor + + const rmt_channel_t RmtChannelNumber; +}; + template class NeoEsp32RmtMethodBase { public: @@ -378,20 +407,24 @@ public: _sizeData(pixelCount * elementSize + settingsSize), _pin(pin) { - _dataEditing = static_cast(malloc(_sizeData)); - memset(_dataEditing, 0x00, _sizeData); + construct(); + } - _dataSending = static_cast(malloc(_sizeData)); - // no need to initialize it, it gets overwritten on every send + NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + _pin(pin), + _channel(channel) + { + construct(); } ~NeoEsp32RmtMethodBase() { // wait until the last send finishes before destructing everything // arbitrary time out of 10 seconds - ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS)); + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)); - ESP_ERROR_CHECK(rmt_driver_uninstall(T_CHANNEL::RmtChannelNumber)); + ESP_ERROR_CHECK(rmt_driver_uninstall(_channel.RmtChannelNumber)); free(_dataEditing); free(_dataSending); @@ -400,7 +433,7 @@ public: bool IsReadyToUpdate() const { - return (ESP_OK == rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 0)); + return (ESP_OK == rmt_wait_tx_done(_channel.RmtChannelNumber, 0)); } void Initialize() @@ -408,7 +441,7 @@ public: rmt_config_t config; config.rmt_mode = RMT_MODE_TX; - config.channel = T_CHANNEL::RmtChannelNumber; + config.channel = _channel.RmtChannelNumber; config.gpio_num = static_cast(_pin); config.mem_block_num = 1; config.tx_config.loop_en = false; @@ -422,8 +455,8 @@ public: config.clk_div = T_SPEED::RmtClockDivider; ESP_ERROR_CHECK(rmt_config(&config)); - ESP_ERROR_CHECK(rmt_driver_install(T_CHANNEL::RmtChannelNumber, 0, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1)); - ESP_ERROR_CHECK(rmt_translator_init(T_CHANNEL::RmtChannelNumber, T_SPEED::Translate)); + ESP_ERROR_CHECK(rmt_driver_install(_channel.RmtChannelNumber, 0, ESP_INTR_FLAG_IRAM | ESP_INTR_FLAG_LEVEL1)); + ESP_ERROR_CHECK(rmt_translator_init(_channel.RmtChannelNumber, T_SPEED::Translate)); } void Update(bool maintainBufferConsistency) @@ -431,10 +464,10 @@ public: // wait for not actively sending data // this will time out at 10 seconds, an arbitrarily long period of time // and do nothing if this happens - if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(T_CHANNEL::RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) + if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_wait_tx_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) { // now start the RMT transmit with the editing buffer before we swap - ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(T_CHANNEL::RmtChannelNumber, _dataEditing, _sizeData, false)); + ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_write_sample(_channel.RmtChannelNumber, _dataEditing, _sizeData, false)); if (maintainBufferConsistency) { @@ -462,13 +495,32 @@ public: private: const size_t _sizeData; // Size of '_data*' buffers const uint8_t _pin; // output pin number + const T_CHANNEL _channel; // holds instance for multi channel support // Holds data stream which include LED color values and other settings as needed uint8_t* _dataEditing; // exposed for get and set uint8_t* _dataSending; // used for async send using RMT + + + void construct() + { + _dataEditing = static_cast(malloc(_sizeData)); + memset(_dataEditing, 0x00, _sizeData); + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } }; // normal +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2811Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2812xMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNSk6812Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1814Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNApa106Method; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN800KbpsMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN400KbpsMethod; + typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811Method; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812Method; @@ -539,6 +591,14 @@ typedef NeoEsp32RmtMethodBase NeoE #endif // inverted +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2811InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNWs2812xInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNSk6812InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNTm1814InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtNApa106InvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN800KbpsInvertedMethod; +typedef NeoEsp32RmtMethodBase NeoEsp32RmtN400KbpsInvertedMethod; + typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2811InvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Ws2812xInvertedMethod; typedef NeoEsp32RmtMethodBase NeoEsp32Rmt0Sk6812InvertedMethod; diff --git a/src/internal/NeoNrf52xMethod.h b/src/internal/NeoNrf52xMethod.h index 41f19a6..bf98808 100644 --- a/src/internal/NeoNrf52xMethod.h +++ b/src/internal/NeoNrf52xMethod.h @@ -229,6 +229,34 @@ public: }; #endif +// dynamic channel support +class NeoNrf52xPwmN +{ +public: + NeoNrf52xPwmN(NeoBusChannel channel) + { + NRF_PWM_Type* PWM[] = { + NRF_PWM0, + NRF_PWM1, + NRF_PWM2 +#ifdef NRF_PWM3 + ,NRF_PWM3 +#endif + }; + _pwm = PWM[channel]; + } + + inline NRF_PWM_Type* Pwm() const + { + return _pwm; + } + +protected: + NRF_PWM_Type* _pwm; + + NeoNrf52xPwmN() {}; +}; + template class NeoNrf52xMethodBase { public: @@ -236,13 +264,15 @@ public: _sizeData(pixelCount * elementSize + settingsSize), _pin(pin) { - pinMode(pin, OUTPUT); + construct(); + } - _data = static_cast(malloc(_sizeData)); - memset(_data, 0, _sizeData); - - _dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t); - _dmaBuffer = static_cast(malloc(_dmaBufferSize)); + NeoNrf52xMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + _pin(pin), + _bus(channel) + { + construct(); } ~NeoNrf52xMethodBase() @@ -262,7 +292,7 @@ public: bool IsReadyToUpdate() const { - return (T_BUS::Pwm()->EVENTS_STOPPED); + return (_bus.Pwm()->EVENTS_STOPPED); } void Initialize() @@ -307,50 +337,62 @@ public: private: const size_t _sizeData; // Size of '_data' buffer below const uint8_t _pin; // output pin number + const T_BUS _bus; // holds instance for multi channel support uint8_t* _data; // Holds LED color values size_t _dmaBufferSize; // total size of _dmaBuffer nrf_pwm_values_common_t* _dmaBuffer; // Holds pixel data in native format for PWM hardware + void construct() + { + pinMode(_pin, OUTPUT); + + _data = static_cast(malloc(_sizeData)); + memset(_data, 0, _sizeData); + + _dmaBufferSize = c_dmaBytesPerDataByte * _sizeData + sizeof(nrf_pwm_values_common_t); + _dmaBuffer = static_cast(malloc(_dmaBufferSize)); + } + void dmaInit() { // only use channel zero - T_BUS::Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin); - T_BUS::Pwm()->PSEL.OUT[1] = NC; - T_BUS::Pwm()->PSEL.OUT[2] = NC; - T_BUS::Pwm()->PSEL.OUT[3] = NC; + _bus.Pwm()->PSEL.OUT[0] = digitalPinToPinName(_pin); + _bus.Pwm()->PSEL.OUT[1] = NC; + _bus.Pwm()->PSEL.OUT[2] = NC; + _bus.Pwm()->PSEL.OUT[3] = NC; - T_BUS::Pwm()->ENABLE = 1; - T_BUS::Pwm()->MODE = NRF_PWM_MODE_UP; - T_BUS::Pwm()->PRESCALER = NRF_PWM_CLK_16MHz; - T_BUS::Pwm()->COUNTERTOP = T_SPEED::CountTop; - T_BUS::Pwm()->LOOP = 1; // single fire so events get set - T_BUS::Pwm()->DECODER = NRF_PWM_LOAD_COMMON; + _bus.Pwm()->ENABLE = 1; + _bus.Pwm()->MODE = NRF_PWM_MODE_UP; + _bus.Pwm()->PRESCALER = NRF_PWM_CLK_16MHz; + _bus.Pwm()->COUNTERTOP = T_SPEED::CountTop; + _bus.Pwm()->LOOP = 1; // single fire so events get set + _bus.Pwm()->DECODER = NRF_PWM_LOAD_COMMON; // sequence zero is the primary data with a BitReset entry on the end for // the delay repeating - T_BUS::Pwm()->SEQ[0].PTR = reinterpret_cast(_dmaBuffer); - T_BUS::Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t); - T_BUS::Pwm()->SEQ[0].REFRESH = 0; // ignored - T_BUS::Pwm()->SEQ[0].ENDDELAY = T_SPEED::CountReset; // ignored still? + _bus.Pwm()->SEQ[0].PTR = reinterpret_cast(_dmaBuffer); + _bus.Pwm()->SEQ[0].CNT = _dmaBufferSize / sizeof(nrf_pwm_values_common_t); + _bus.Pwm()->SEQ[0].REFRESH = 0; // ignored + _bus.Pwm()->SEQ[0].ENDDELAY = T_SPEED::CountReset; // ignored still? // sequence one is pointing to the BitReset entry at the end of the primary data - T_BUS::Pwm()->SEQ[1].PTR = reinterpret_cast(_dmaBuffer + (T_BUS::Pwm()->SEQ[0].CNT - 1)); - T_BUS::Pwm()->SEQ[1].CNT = 1; - T_BUS::Pwm()->SEQ[1].REFRESH = 0; // ignored - T_BUS::Pwm()->SEQ[1].ENDDELAY = 0; // ignored + _bus.Pwm()->SEQ[1].PTR = reinterpret_cast(_dmaBuffer + (_bus.Pwm()->SEQ[0].CNT - 1)); + _bus.Pwm()->SEQ[1].CNT = 1; + _bus.Pwm()->SEQ[1].REFRESH = 0; // ignored + _bus.Pwm()->SEQ[1].ENDDELAY = 0; // ignored // stop when the loop finishes - T_BUS::Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk; - T_BUS::Pwm()->INTEN = 0; + _bus.Pwm()->SHORTS = PWM_SHORTS_LOOPSDONE_STOP_Msk; + _bus.Pwm()->INTEN = 0; dmaResetEvents(); } void dmaDeinit() { - T_BUS::Pwm()->ENABLE = 0; - T_BUS::Pwm()->PSEL.OUT[0] = NC; + _bus.Pwm()->ENABLE = 0; + _bus.Pwm()->PSEL.OUT[0] = NC; } void FillBuffer() @@ -380,20 +422,28 @@ private: void dmaResetEvents() { - T_BUS::Pwm()->EVENTS_LOOPSDONE = 0; - T_BUS::Pwm()->EVENTS_SEQEND[0] = 0; - T_BUS::Pwm()->EVENTS_SEQEND[1] = 0; - T_BUS::Pwm()->EVENTS_STOPPED = 0; + _bus.Pwm()->EVENTS_LOOPSDONE = 0; + _bus.Pwm()->EVENTS_SEQEND[0] = 0; + _bus.Pwm()->EVENTS_SEQEND[1] = 0; + _bus.Pwm()->EVENTS_STOPPED = 0; } void dmaStart() { dmaResetEvents(); - T_BUS::Pwm()->TASKS_SEQSTART[0] = 1; + _bus.Pwm()->TASKS_SEQSTART[0] = 1; } }; // normal +typedef NeoNrf52xMethodBase NeoNrf52xPwmNWs2811Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNWs2812xMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNSk6812Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNTm1814Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNApa106Method; +typedef NeoNrf52xMethodBase NeoNrf52xPwmN800KbpsMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmN400KbpsMethod; + typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2811Method; typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2812xMethod; typedef NeoNrf52xMethodBase NeoNrf52xPwm0Sk6812Method; @@ -429,6 +479,14 @@ typedef NeoNrf52xMethodBase NeoNrf52xPw #endif // inverted +typedef NeoNrf52xMethodBase NeoNrf52xPwmNWs2811InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNWs2812xInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNSk6812InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNTm1814InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmNApa106InvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmN800KbpsInvertedMethod; +typedef NeoNrf52xMethodBase NeoNrf52xPwmN400KbpsInvertedMethod; + typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2811InvertedMethod; typedef NeoNrf52xMethodBase NeoNrf52xPwm0Ws2812xInvertedMethod; typedef NeoNrf52xMethodBase NeoNrf52xPwm0Sk6812InvertedMethod;