From 37612e56eb1bb0021b08a0cc365ea2d777579271 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Tue, 26 Aug 2025 22:57:19 -0400 Subject: [PATCH 1/5] Import RmtHI driver Pull the RMT High-priority Interrupt driver in to a vendored local library, pending inclusion in upstream NeoPixelBus. Driver is enabled only for XTensa chips; there's some unresolved issue with nested interrupts on RISCV. --- .../include/NeoEsp32RmtHIMethod.h | 562 ++++++++++++++++++ lib/NeoESP32RmtHI/library.json | 12 + lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S | 263 ++++++++ lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp | 505 ++++++++++++++++ platformio.ini | 2 +- wled00/bus_wrapper.h | 32 +- 6 files changed, 1363 insertions(+), 13 deletions(-) create mode 100644 lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h create mode 100644 lib/NeoESP32RmtHI/library.json create mode 100644 lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S create mode 100644 lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp diff --git a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h new file mode 100644 index 0000000000..0e4f71113a --- /dev/null +++ b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h @@ -0,0 +1,562 @@ +/*------------------------------------------------------------------------- +NeoPixel driver for ESP32 RMTs using High-priority Interrupt + +(NB. This cannot be mixed with the non-HI driver.) + +Written by Will M. Miles. + +I invest time and resources providing this open source code, +please support me by donating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#pragma once + +#if defined(ARDUINO_ARCH_ESP32) + +// Use the NeoEspRmtSpeed types from the driver-based implementation +#include + + +namespace NeoEsp32RmtHiMethodDriver { + // Install the driver for a specific channel, specifying timing properties + esp_err_t Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t resetDuration); + + // Remove the driver on a specific channel + esp_err_t Uninstall(rmt_channel_t channel); + + // Write a buffer of data to a specific channel. + // Buffer reference is held until write completes. + esp_err_t Write(rmt_channel_t channel, const uint8_t *src, size_t src_size); + + // Wait until transaction is complete. + esp_err_t WaitForTxDone(rmt_channel_t channel, TickType_t wait_time); +}; + +template class NeoEsp32RmtHIMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + _pin(pin) + { + construct(); + } + + NeoEsp32RmtHIMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + _pin(pin), + _channel(channel) + { + construct(); + } + + ~NeoEsp32RmtHIMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)); + + ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Uninstall(_channel.RmtChannelNumber)); + + gpio_matrix_out(_pin, SIG_GPIO_OUT_IDX, false, false); + pinMode(_pin, INPUT); + + free(_dataEditing); + free(_dataSending); + } + + bool IsReadyToUpdate() const + { + return (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT_SILENT_TIMEOUT(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 0))); + } + + void Initialize() + { + rmt_config_t config = {}; + + config.rmt_mode = RMT_MODE_TX; + config.channel = _channel.RmtChannelNumber; + config.gpio_num = static_cast(_pin); + config.mem_block_num = 1; + config.tx_config.loop_en = false; + + config.tx_config.idle_output_en = true; + config.tx_config.idle_level = T_SPEED::IdleLevel; + + config.tx_config.carrier_en = false; + config.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; + + config.clk_div = T_SPEED::RmtClockDivider; + + ESP_ERROR_CHECK(rmt_config(&config)); // Uses ESP library + ESP_ERROR_CHECK(NeoEsp32RmtHiMethodDriver::Install(_channel.RmtChannelNumber, T_SPEED::RmtBit0, T_SPEED::RmtBit1, T_SPEED::RmtDurationReset)); + } + + void Update(bool maintainBufferConsistency) + { + // 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(NeoEsp32RmtHiMethodDriver::WaitForTxDone(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS))) + { + // now start the RMT transmit with the editing buffer before we swap + ESP_ERROR_CHECK_WITHOUT_ABORT(NeoEsp32RmtHiMethodDriver::Write(_channel.RmtChannelNumber, _dataEditing, _sizeData)); + + if (maintainBufferConsistency) + { + // copy editing to sending, + // this maintains the contract that "colors present before will + // be the same after", otherwise GetPixelColor will be inconsistent + memcpy(_dataSending, _dataEditing, _sizeData); + } + + // swap so the user can modify without affecting the async operation + std::swap(_dataSending, _dataEditing); + } + } + + bool AlwaysUpdate() + { + // this method requires update to be called only if changes to buffer + return false; + } + + bool SwapBuffers() + { + std::swap(_dataSending, _dataEditing); + return true; + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings([[maybe_unused]] const SettingsObject& settings) + { + } + +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)); + // data cleared later in Begin() + + _dataSending = static_cast(malloc(_sizeData)); + // no need to initialize it, it gets overwritten on every send + } +}; + +// normal +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINSk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINApa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsMethod; +typedef NeoEsp32RmtNWs2805Method NeoEsp32RmtHINWs2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsMethod; +typedef NeoEsp32Rmt0Ws2805Method NeoEsp32RmtHI0Ws2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsMethod; +typedef NeoEsp32Rmt1Ws2805Method NeoEsp32RmtHI1Ws2814Method; + +#if !defined(CONFIG_IDF_TARGET_ESP32C3) + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsMethod; +typedef NeoEsp32Rmt2Ws2805Method NeoEsp32RmtHI2Ws2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsMethod; +typedef NeoEsp32Rmt3Ws2805Method NeoEsp32RmtHI3Ws2814Method; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsMethod; +typedef NeoEsp32Rmt4Ws2805Method NeoEsp32RmtHI4Ws2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsMethod; +typedef NeoEsp32Rmt5Ws2805Method NeoEsp32RmtHI5Ws2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsMethod; +typedef NeoEsp32Rmt6Ws2805Method NeoEsp32RmtHI6Ws2814Method; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2816Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2805Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Sk6812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1814Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1829Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1914Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Apa106Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tx1812Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903Method; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsMethod; +typedef NeoEsp32Rmt7Ws2805Method NeoEsp32RmtHI7Ws2814Method; + +#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) + +// inverted +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINWs2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINSk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINApa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINTx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsInvertedMethod; +typedef NeoEsp32RmtNWs2805InvertedMethod NeoEsp32RmtHINWs2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsInvertedMethod; +typedef NeoEsp32Rmt0Ws2805InvertedMethod NeoEsp32RmtHI0Ws2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsInvertedMethod; +typedef NeoEsp32Rmt1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32C3) + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsInvertedMethod; +typedef NeoEsp32Rmt2Ws2805InvertedMethod NeoEsp32RmtHI2Ws2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsInvertedMethod; +typedef NeoEsp32Rmt3Ws2805InvertedMethod NeoEsp32RmtHI3Ws2814InvertedMethod; + +#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsInvertedMethod; +typedef NeoEsp32Rmt4Ws2805InvertedMethod NeoEsp32RmtHI4Ws2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsInvertedMethod; +typedef NeoEsp32Rmt5Ws2805InvertedMethod NeoEsp32RmtHI5Ws2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsInvertedMethod; +typedef NeoEsp32Rmt6Ws2805InvertedMethod NeoEsp32RmtHI6Ws2814InvertedMethod; + +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2816InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2805InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Sk6812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1814InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1829InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tm1914InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Apa106InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Tx1812InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903InvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsInvertedMethod; +typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsInvertedMethod; +typedef NeoEsp32Rmt7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod; + +#endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) +#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) + + +#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) + +// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT +// will switch to use RMT as the default method +// The ESP32S2, ESP32S3, and ESP32C3 will always defualt to RMT + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) + +// RMT channel 1 method is the default method for ESP32S2, ESP32S3, and ESP32C3 +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt1800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2816Method; +typedef NeoEsp32Rmt1Ws2805Method NeoWs2805Method; +typedef NeoEsp32Rmt1Ws2814Method NeoWs2814Method; +typedef NeoEsp32Rmt1Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt1Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt1Tm1829Method NeoTm1829Method; +typedef NeoEsp32Rmt1Tm1914Method NeoTm1914Method; +typedef NeoEsp32Rmt1Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt1Apa106Method NeoApa106Method; +typedef NeoEsp32Rmt1Tx1812Method NeoTx1812Method; +typedef NeoEsp32Rmt1Gs1903Method NeoGs1903Method; + +typedef NeoEsp32Rmt1Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt1400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt1800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2816InvertedMethod; +typedef NeoEsp32Rmt1Ws2805InvertedMethod NeoWs2805InvertedMethod; +typedef NeoEsp32Rmt1Ws2814InvertedMethod NeoWs2814InvertedMethod; +typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt1Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt1Tm1829InvertedMethod NeoTm1829InvertedMethod; +typedef NeoEsp32Rmt1Tm1914InvertedMethod NeoTm1914InvertedMethod; +typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt1Apa106InvertedMethod NeoApa106InvertedMethod; +typedef NeoEsp32Rmt1Tx1812InvertedMethod NeoTx1812InvertedMethod; +typedef NeoEsp32Rmt1Gs1903InvertedMethod NeoGs1903InvertedMethod; + +typedef NeoEsp32Rmt1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt1400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#else // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) + +// RMT channel 6 method is the default method for Esp32 +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod; +typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method; +typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2816Method; +typedef NeoEsp32Rmt6Ws2805Method NeoWs2805Method; +typedef NeoEsp32Rmt6Ws2814Method NeoWs2814Method; +typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method; +typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method; +typedef NeoEsp32Rmt6Tm1829Method NeoTm1829Method; +typedef NeoEsp32Rmt6Tm1914Method NeoTm1914Method; +typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method; +typedef NeoEsp32Rmt6Apa106Method NeoApa106Method; +typedef NeoEsp32Rmt6Tx1812Method NeoTx1812Method; +typedef NeoEsp32Rmt6Gs1903Method NeoGs1903Method; + +typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod; +typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod; +typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod; +typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2816InvertedMethod; +typedef NeoEsp32Rmt6Ws2805InvertedMethod NeoWs2805InvertedMethod; +typedef NeoEsp32Rmt6Ws2814InvertedMethod NeoWs2814InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod; +typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod; +typedef NeoEsp32Rmt6Tm1829InvertedMethod NeoTm1829InvertedMethod; +typedef NeoEsp32Rmt6Tm1914InvertedMethod NeoTm1914InvertedMethod; +typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod; +typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod; +typedef NeoEsp32Rmt6Tx1812InvertedMethod NeoTx1812InvertedMethod; +typedef NeoEsp32Rmt6Gs1903InvertedMethod NeoGs1903InvertedMethod; + +typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod; +typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod; + +#endif // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + +#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) + +#endif diff --git a/lib/NeoESP32RmtHI/library.json b/lib/NeoESP32RmtHI/library.json new file mode 100644 index 0000000000..0608e59e12 --- /dev/null +++ b/lib/NeoESP32RmtHI/library.json @@ -0,0 +1,12 @@ +{ + "name": "NeoESP32RmtHI", + "build": { "libArchive": false }, + "platforms": ["espressif32"], + "dependencies": [ + { + "owner": "makuna", + "name": "NeoPixelBus", + "version": "^2.8.3" + } + ] +} diff --git a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S new file mode 100644 index 0000000000..0c60d2ebc9 --- /dev/null +++ b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHI.S @@ -0,0 +1,263 @@ +/* RMT ISR shim + * Bridges from a high-level interrupt to the C++ code. + * + * This code is largely derived from Espressif's 'hli_vector.S' Bluetooth ISR. + * + */ + +#if defined(__XTENSA__) && defined(ESP32) && !defined(CONFIG_BTDM_CTRL_HLI) + +#include +#include "sdkconfig.h" +#include "soc/soc.h" + +/* If the Bluetooth driver has hooked the high-priority interrupt, we piggyback on it and don't need this. */ +#ifndef CONFIG_BTDM_CTRL_HLI + +/* + Select interrupt based on system check level + - Base ESP32: could be 4 or 5, depends on platform config + - S2: 5 + - S3: 5 +*/ + +#if CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 +/* Use level 4 */ +#define RFI_X 4 +#define xt_highintx xt_highint4 +#else /* !CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */ +/* Use level 5 */ +#define RFI_X 5 +#define xt_highintx xt_highint5 +#endif /* CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5 */ + +// Register map, based on interrupt level +#define EPC_X (EPC + RFI_X) +#define EXCSAVE_X (EXCSAVE + RFI_X) + +// The sp mnemonic is used all over in ESP's assembly, though I'm not sure where it's expected to be defined? +#define sp a1 + +/* Interrupt stack size, for C code. */ +#define RMT_INTR_STACK_SIZE 512 + +/* Save area for the CPU state: + * - 64 words for the general purpose registers + * - 7 words for some of the special registers: + * - WINDOWBASE, WINDOWSTART — only WINDOWSTART is truly needed + * - SAR, LBEG, LEND, LCOUNT — since the C code might use these + * - EPC1 — since the C code might cause window overflow exceptions + * This is not laid out as standard exception frame structure + * for simplicity of the save/restore code. + */ +#define REG_FILE_SIZE (64 * 4) +#define SPECREG_OFFSET REG_FILE_SIZE +#define SPECREG_SIZE (7 * 4) +#define REG_SAVE_AREA_SIZE (SPECREG_OFFSET + SPECREG_SIZE) + + .data +_rmt_intr_stack: + .space RMT_INTR_STACK_SIZE +_rmt_save_ctx: + .space REG_SAVE_AREA_SIZE + + .section .iram1,"ax" + .global xt_highintx + .type xt_highintx,@function + .align 4 + +xt_highintx: + + movi a0, _rmt_save_ctx + /* save 4 lower registers */ + s32i a1, a0, 4 + s32i a2, a0, 8 + s32i a3, a0, 12 + rsr a2, EXCSAVE_X /* holds the value of a0 */ + s32i a2, a0, 0 + + /* Save special registers */ + addi a0, a0, SPECREG_OFFSET + rsr a2, WINDOWBASE + s32i a2, a0, 0 + rsr a2, WINDOWSTART + s32i a2, a0, 4 + rsr a2, SAR + s32i a2, a0, 8 + #if XCHAL_HAVE_LOOPS + rsr a2, LBEG + s32i a2, a0, 12 + rsr a2, LEND + s32i a2, a0, 16 + rsr a2, LCOUNT + s32i a2, a0, 20 + #endif + rsr a2, EPC1 + s32i a2, a0, 24 + + /* disable exception mode, window overflow */ + movi a0, PS_INTLEVEL(RFI_X+1) | PS_EXCM + wsr a0, PS + rsync + + /* Save the remaining physical registers. + * 4 registers are already saved, which leaves 60 registers to save. + * (FIXME: consider the case when the CPU is configured with physical 32 registers) + * These 60 registers are saved in 5 iterations, 12 registers at a time. + */ + movi a1, 5 + movi a3, _rmt_save_ctx + 4 * 4 + + /* This is repeated 5 times, each time the window is shifted by 12 registers. + * We come here with a1 = downcounter, a3 = save pointer, a2 and a0 unused. + */ +1: + s32i a4, a3, 0 + s32i a5, a3, 4 + s32i a6, a3, 8 + s32i a7, a3, 12 + s32i a8, a3, 16 + s32i a9, a3, 20 + s32i a10, a3, 24 + s32i a11, a3, 28 + s32i a12, a3, 32 + s32i a13, a3, 36 + s32i a14, a3, 40 + s32i a15, a3, 44 + + /* We are about to rotate the window, so that a12-a15 will become the new a0-a3. + * Copy a0-a3 to a12-15 to still have access to these values. + * At the same time we can decrement the counter and adjust the save area pointer + */ + + /* a0 is constant (_rmt_save_ctx), no need to copy */ + addi a13, a1, -1 /* copy and decrement the downcounter */ + /* a2 is scratch so no need to copy */ + addi a15, a3, 48 /* copy and adjust the save area pointer */ + beqz a13, 2f /* have saved all registers ? */ + rotw 3 /* rotate the window and go back */ + j 1b + + /* the loop is complete */ +2: + rotw 4 /* this brings us back to the original window */ + /* a0 still points to _rmt_save_ctx */ + + /* Can clear WINDOWSTART now, all registers are saved */ + rsr a2, WINDOWBASE + /* WINDOWSTART = (1 << WINDOWBASE) */ + movi a3, 1 + ssl a2 + sll a3, a3 + wsr a3, WINDOWSTART + +_highint_stack_switch: + movi a0, 0 + movi sp, _rmt_intr_stack + RMT_INTR_STACK_SIZE - 16 + s32e a0, sp, -12 /* For GDB: set null SP */ + s32e a0, sp, -16 /* For GDB: set null PC */ + movi a0, _highint_stack_switch /* For GDB: cosmetics, for the frame where stack switch happened */ + + /* Set up PS for C, disable all interrupts except NMI and debug, and clear EXCM. */ + movi a6, PS_INTLEVEL(RFI_X) | PS_UM | PS_WOE + wsr a6, PS + rsync + + /* Call C handler */ + mov a6, sp + call4 NeoEsp32RmtMethodIsr + + l32e sp, sp, -12 /* switch back to the original stack */ + + /* Done with C handler; re-enable exception mode, disabling window overflow */ + movi a2, PS_INTLEVEL(RFI_X+1) | PS_EXCM /* TOCHECK */ + wsr a2, PS + rsync + + /* Restore the special registers. + * WINDOWSTART will be restored near the end. + */ + movi a0, _rmt_save_ctx + SPECREG_OFFSET + l32i a2, a0, 8 + wsr a2, SAR + #if XCHAL_HAVE_LOOPS + l32i a2, a0, 12 + wsr a2, LBEG + l32i a2, a0, 16 + wsr a2, LEND + l32i a2, a0, 20 + wsr a2, LCOUNT + #endif + l32i a2, a0, 24 + wsr a2, EPC1 + + /* Restoring the physical registers. + * This is the reverse to the saving process above. + */ + + /* Rotate back to the final window, then start loading 12 registers at a time, + * in 5 iterations. + * Again, a1 is the downcounter and a3 is the save area pointer. + * After each rotation, a1 and a3 are copied from a13 and a15. + * To simplify the loop, we put the initial values into a13 and a15. + */ + rotw -4 + movi a15, _rmt_save_ctx + 64 * 4 /* point to the end of the save area */ + movi a13, 5 + +1: + /* Copy a1 and a3 from their previous location, + * at the same time decrementing and adjusting the save area pointer. + */ + addi a1, a13, -1 + addi a3, a15, -48 + + /* Load 12 registers */ + l32i a4, a3, 0 + l32i a5, a3, 4 + l32i a6, a3, 8 + l32i a7, a3, 12 + l32i a8, a3, 16 + l32i a9, a3, 20 + l32i a10, a3, 24 + l32i a11, a3, 28 /* ensure PS and EPC written */ + l32i a12, a3, 32 + l32i a13, a3, 36 + l32i a14, a3, 40 + l32i a15, a3, 44 + + /* Done with the loop? */ + beqz a1, 2f + /* If no, rotate the window and repeat */ + rotw -3 + j 1b + +2: + /* Done with the loop. Only 4 registers (a0-a3 in the original window) remain + * to be restored. Also need to restore WINDOWSTART, since all the general + * registers are now in place. + */ + movi a0, _rmt_save_ctx + + l32i a2, a0, SPECREG_OFFSET + 4 + wsr a2, WINDOWSTART + + l32i a1, a0, 4 + l32i a2, a0, 8 + l32i a3, a0, 12 + rsr a0, EXCSAVE_X /* holds the value of a0 before the interrupt handler */ + + /* Return from the interrupt, restoring PS from EPS_X */ + rfi RFI_X + + +/* The linker has no reason to link in this file; all symbols it exports are already defined + (weakly!) in the default int handler. Define a symbol here so we can use it to have the + linker inspect this anyway. */ + + .global ld_include_hli_vectors_rmt +ld_include_hli_vectors_rmt: + + +#endif // CONFIG_BTDM_CTRL_HLI +#endif // XTensa \ No newline at end of file diff --git a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp new file mode 100644 index 0000000000..bd63c4432d --- /dev/null +++ b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp @@ -0,0 +1,505 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +A BIG thanks to Andreas Merkle for the investigation and implementation of +a workaround to the GCC bug that drops method attributes from template methods + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by donating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is part of the Makuna/NeoPixelBus library. + +NeoPixelBus is free software: you can redistribute it and/or modify +it under the terms of the GNU Lesser General Public License as +published by the Free Software Foundation, either version 3 of +the License, or (at your option) any later version. + +NeoPixelBus is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with NeoPixel. If not, see +. +-------------------------------------------------------------------------*/ + +#include + +#if defined(ARDUINO_ARCH_ESP32) + +#include "NeoEsp32RmtHIMethod.h" +#include "soc/soc.h" +#include "soc/rmt_reg.h" + +#ifdef __riscv +#include "riscv/interrupt.h" +#endif + + +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) +#include "hal/rmt_ll.h" +#else +/* Shims for older ESP-IDF v3; we can safely assume original ESP32 */ +#include "soc/rmt_struct.h" + +// Selected RMT API functions borrowed from ESP-IDF v4.4.8 +// components/hal/esp32/include/hal/rmt_ll.h +// Copyright 2019 Espressif Systems (Shanghai) PTE LTD +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +__attribute__((always_inline)) +static inline void rmt_ll_tx_reset_pointer(rmt_dev_t *dev, uint32_t channel) +{ + dev->conf_ch[channel].conf1.mem_rd_rst = 1; + dev->conf_ch[channel].conf1.mem_rd_rst = 0; +} + +__attribute__((always_inline)) +static inline void rmt_ll_tx_start(rmt_dev_t *dev, uint32_t channel) +{ + dev->conf_ch[channel].conf1.tx_start = 1; +} + +__attribute__((always_inline)) +static inline void rmt_ll_tx_stop(rmt_dev_t *dev, uint32_t channel) +{ + RMTMEM.chan[channel].data32[0].val = 0; + dev->conf_ch[channel].conf1.tx_start = 0; + dev->conf_ch[channel].conf1.mem_rd_rst = 1; + dev->conf_ch[channel].conf1.mem_rd_rst = 0; +} + +__attribute__((always_inline)) +static inline void rmt_ll_tx_enable_pingpong(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->apb_conf.mem_tx_wrap_en = enable; +} + +__attribute__((always_inline)) +static inline void rmt_ll_tx_enable_loop(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->conf_ch[channel].conf1.tx_conti_mode = enable; +} + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_tx_get_channel_status(rmt_dev_t *dev, uint32_t channel) +{ + return dev->status_ch[channel]; +} + +__attribute__((always_inline)) +static inline void rmt_ll_tx_set_limit(rmt_dev_t *dev, uint32_t channel, uint32_t limit) +{ + dev->tx_lim_ch[channel].limit = limit; +} + +__attribute__((always_inline)) +static inline void rmt_ll_enable_interrupt(rmt_dev_t *dev, uint32_t mask, bool enable) +{ + if (enable) { + dev->int_ena.val |= mask; + } else { + dev->int_ena.val &= ~mask; + } +} + +__attribute__((always_inline)) +static inline void rmt_ll_enable_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->int_ena.val &= ~(1 << (channel * 3)); + dev->int_ena.val |= (enable << (channel * 3)); +} + +__attribute__((always_inline)) +static inline void rmt_ll_enable_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->int_ena.val &= ~(1 << (channel * 3 + 2)); + dev->int_ena.val |= (enable << (channel * 3 + 2)); +} + +__attribute__((always_inline)) +static inline void rmt_ll_enable_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel, bool enable) +{ + dev->int_ena.val &= ~(1 << (channel + 24)); + dev->int_ena.val |= (enable << (channel + 24)); +} + +__attribute__((always_inline)) +static inline void rmt_ll_clear_tx_end_interrupt(rmt_dev_t *dev, uint32_t channel) +{ + dev->int_clr.val = (1 << (channel * 3)); +} + +__attribute__((always_inline)) +static inline void rmt_ll_clear_tx_err_interrupt(rmt_dev_t *dev, uint32_t channel) +{ + dev->int_clr.val = (1 << (channel * 3 + 2)); +} + +__attribute__((always_inline)) +static inline void rmt_ll_clear_tx_thres_interrupt(rmt_dev_t *dev, uint32_t channel) +{ + dev->int_clr.val = (1 << (channel + 24)); +} + + +__attribute__((always_inline)) +static inline uint32_t rmt_ll_get_tx_thres_interrupt_status(rmt_dev_t *dev) +{ + uint32_t status = dev->int_st.val; + return (status & 0xFF000000) >> 24; +} +#endif + + +// ********************************* +// Select method for binding interrupt +// +// - If the Bluetooth driver has registered a high-level interrupt, piggyback on that API +// - If we're on a modern core, allocate the interrupt with the API (old cores are bugged) +// - Otherwise use the low-level hardware API to manually bind the interrupt + + +#if defined(CONFIG_BTDM_CTRL_HLI) +// Espressif's bluetooth driver offers a helpful sharing layer; bring in the interrupt management calls +#include "hal/interrupt_controller_hal.h" +extern "C" esp_err_t hli_intr_register(intr_handler_t handler, void* arg, uint32_t intr_reg, uint32_t intr_mask); + +#else /* !CONFIG_BTDM_CTRL_HLI*/ + +// Declare the our high-priority ISR handler +extern "C" void ld_include_hli_vectors_rmt(); // an object with an address, but no space + +#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32S3) || defined(CONFIG_IDF_TARGET_ESP32C3) +#include "soc/periph_defs.h" +#endif + +// Select level flag +#if defined(__riscv) +// RISCV chips don't block interrupts while scheduling; all we need to do is be higher than the WiFi ISR +#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL3 +#elif defined(CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5) +#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL4 +#else +#define INT_LEVEL_FLAG ESP_INTR_FLAG_LEVEL5 +#endif + +// ESP-IDF v3 cannot enable high priority interrupts through the API at all; +// and ESP-IDF v4 on XTensa cannot enable Level 5 due to incorrect interrupt descriptor tables +#if !defined(__XTENSA__) || (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)) || ((ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0) && CONFIG_ESP_SYSTEM_CHECK_INT_LEVEL_5)) +#define NEOESP32_RMT_CAN_USE_INTR_ALLOC + +// XTensa cores require the assembly bridge +#ifdef __XTENSA__ +#define HI_IRQ_HANDLER nullptr +#define HI_IRQ_HANDLER_ARG ld_include_hli_vectors_rmt +#else +#define HI_IRQ_HANDLER NeoEsp32RmtMethodIsr +#define HI_IRQ_HANDLER_ARG nullptr +#endif + +#else +/* !CONFIG_BTDM_CTRL_HLI && !NEOESP32_RMT_CAN_USE_INTR_ALLOC */ +// This is the index of the LV5 interrupt vector - see interrupt descriptor table in idf components/hal/esp32/interrupt_descriptor_table.c +#define ESP32_LV5_IRQ_INDEX 26 + +#endif /* NEOESP32_RMT_CAN_USE_INTR_ALLOC */ +#endif /* CONFIG_BTDM_CTRL_HLI */ + + +// RMT driver implementation +struct NeoEsp32RmtHIChannelState { + uint32_t rmtBit0, rmtBit1; + uint32_t resetDuration; + + const byte* txDataStart; // data array + const byte* txDataEnd; // one past end + const byte* txDataCurrent; // current location + size_t rmtOffset; +}; + +// Global variables +#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC) +static intr_handle_t isrHandle = nullptr; +#endif + +static NeoEsp32RmtHIChannelState** driverState = nullptr; +constexpr size_t rmtBatchSize = RMT_MEM_ITEM_NUM / 2; + +// Fill the RMT buffer memory +// This is implemented using many arguments instead of passing the structure object to ensure we do only one lookup +// All the arguments are passed in registers, so they don't need to be looked up again +static void IRAM_ATTR RmtFillBuffer(uint8_t channel, const byte** src_ptr, const byte* end, uint32_t bit0, uint32_t bit1, size_t* offset_ptr, size_t reserve) { + // We assume that (rmtToWrite % 8) == 0 + size_t rmtToWrite = rmtBatchSize - reserve; + rmt_item32_t* dest =(rmt_item32_t*) &RMTMEM.chan[channel].data32[*offset_ptr + reserve]; // write directly in to RMT memory + const byte* psrc = *src_ptr; + + *offset_ptr ^= rmtBatchSize; + + if (psrc != end) { + while (rmtToWrite > 0) { + uint8_t data = *psrc; + for (uint8_t bit = 0; bit < 8; bit++) + { + dest->val = (data & 0x80) ? bit1 : bit0; + dest++; + data <<= 1; + } + rmtToWrite -= 8; + psrc++; + + if (psrc == end) { + break; + } + } + + *src_ptr = psrc; + } + + if (rmtToWrite > 0) { + // Add end event + rmt_item32_t bit0_val = {{.val = bit0 }}; + *dest = rmt_item32_t {{{ .duration0 = 0, .level0 = bit0_val.level1, .duration1 = 0, .level1 = bit0_val.level1 }}}; + } +} + +static void IRAM_ATTR RmtStartWrite(uint8_t channel, NeoEsp32RmtHIChannelState& state) { + // Reset context state + state.rmtOffset = 0; + + // Fill the first part of the buffer with a reset event + // FUTURE: we could do timing analysis with the last interrupt on this channel + // Use 8 words to stay aligned with the buffer fill logic + rmt_item32_t bit0_val = {{.val = state.rmtBit0 }}; + rmt_item32_t fill = {{{ .duration0 = 100, .level0 = bit0_val.level1, .duration1 = 100, .level1 = bit0_val.level1 }}}; + rmt_item32_t* dest = (rmt_item32_t*) &RMTMEM.chan[channel].data32[0]; + for (auto i = 0; i < 7; ++i) dest[i] = fill; + fill.duration1 = state.resetDuration > 1400 ? (state.resetDuration - 1400) : 100; + dest[7] = fill; + + // Fill the remaining buffer with real data + RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 8); + RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0); + + // Start operation + rmt_ll_clear_tx_thres_interrupt(&RMT, channel); + rmt_ll_tx_reset_pointer(&RMT, channel); + rmt_ll_tx_start(&RMT, channel); +} + +extern "C" void IRAM_ATTR NeoEsp32RmtMethodIsr(void *arg) { + // Tx threshold interrupt + uint32_t status = rmt_ll_get_tx_thres_interrupt_status(&RMT); + while (status) { + uint8_t channel = __builtin_ffs(status) - 1; + if (driverState[channel]) { + // Normal case + NeoEsp32RmtHIChannelState& state = *driverState[channel]; + RmtFillBuffer(channel, &state.txDataCurrent, state.txDataEnd, state.rmtBit0, state.rmtBit1, &state.rmtOffset, 0); + } else { + // Danger - another driver got invoked? + rmt_ll_tx_stop(&RMT, channel); + } + rmt_ll_clear_tx_thres_interrupt(&RMT, channel); + status = rmt_ll_get_tx_thres_interrupt_status(&RMT); + } +}; + +// Wrapper around the register analysis defines +// For all currently supported chips, this is constant for all channels; but this is not true of *all* ESP32 +static inline bool _RmtStatusIsTransmitting(rmt_channel_t channel, uint32_t status) { + uint32_t v; + switch(channel) { +#ifdef RMT_STATE_CH0 + case 0: v = (status >> RMT_STATE_CH0_S) & RMT_STATE_CH0_V; break; +#endif +#ifdef RMT_STATE_CH1 + case 1: v = (status >> RMT_STATE_CH1_S) & RMT_STATE_CH1_V; break; +#endif +#ifdef RMT_STATE_CH2 + case 2: v = (status >> RMT_STATE_CH2_S) & RMT_STATE_CH2_V; break; +#endif +#ifdef RMT_STATE_CH3 + case 3: v = (status >> RMT_STATE_CH3_S) & RMT_STATE_CH3_V; break; +#endif +#ifdef RMT_STATE_CH4 + case 4: v = (status >> RMT_STATE_CH4_S) & RMT_STATE_CH4_V; break; +#endif +#ifdef RMT_STATE_CH5 + case 5: v = (status >> RMT_STATE_CH5_S) & RMT_STATE_CH5_V; break; +#endif +#ifdef RMT_STATE_CH6 + case 6: v = (status >> RMT_STATE_CH6_S) & RMT_STATE_CH6_V; break; +#endif +#ifdef RMT_STATE_CH7 + case 7: v = (status >> RMT_STATE_CH7_S) & RMT_STATE_CH7_V; break; +#endif + default: v = 0; + } + + return v != 0; +} + + +esp_err_t NeoEsp32RmtHiMethodDriver::Install(rmt_channel_t channel, uint32_t rmtBit0, uint32_t rmtBit1, uint32_t reset) { + // Validate channel number + if (channel >= RMT_CHANNEL_MAX) { + return ESP_ERR_INVALID_ARG; + } + + esp_err_t err = ESP_OK; + if (!driverState) { + // First time init + driverState = reinterpret_cast(heap_caps_calloc(RMT_CHANNEL_MAX, sizeof(NeoEsp32RmtHIChannelState*), MALLOC_CAP_INTERNAL)); + if (!driverState) return ESP_ERR_NO_MEM; + + // Ensure all interrupts are cleared before binding + RMT.int_ena.val = 0; + RMT.int_clr.val = 0xFFFFFFFF; + + // Bind interrupt handler +#if defined(CONFIG_BTDM_CTRL_HLI) + // Bluetooth driver has taken the empty high-priority interrupt. Fortunately, it allows us to + // hook up another handler. + err = hli_intr_register(NeoEsp32RmtMethodIsr, nullptr, (uintptr_t) &RMT.int_st, 0xFF000000); + // 25 is the magic number of the bluetooth ISR on ESP32 - see soc/soc.h. + intr_matrix_set(cpu_hal_get_core_id(), ETS_RMT_INTR_SOURCE, 25); + intr_cntrl_ll_enable_interrupts(1<<25); +#elif defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC) + // Use the platform code to allocate the interrupt + // If we need the additional assembly bridge, we pass it as the "arg" to the IDF so it gets linked in + err = esp_intr_alloc(ETS_RMT_INTR_SOURCE, INT_LEVEL_FLAG | ESP_INTR_FLAG_IRAM, HI_IRQ_HANDLER, (void*) HI_IRQ_HANDLER_ARG, &isrHandle); + //err = ESP_ERR_NOT_FINISHED; +#else + // Broken IDF API does not allow us to reserve the interrupt; do it manually + static volatile const void* __attribute__((used)) pleaseLinkAssembly = (void*) ld_include_hli_vectors_rmt; + intr_matrix_set(xPortGetCoreID(), ETS_RMT_INTR_SOURCE, ESP32_LV5_IRQ_INDEX); + ESP_INTR_ENABLE(ESP32_LV5_IRQ_INDEX); +#endif + + if (err != ESP_OK) { + heap_caps_free(driverState); + driverState = nullptr; + return err; + } + } + + if (driverState[channel] != nullptr) { + return ESP_ERR_INVALID_STATE; // already in use + } + + NeoEsp32RmtHIChannelState* state = reinterpret_cast(heap_caps_calloc(1, sizeof(NeoEsp32RmtHIChannelState), MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)); + if (state == nullptr) { + return ESP_ERR_NO_MEM; + } + + // Store timing information + state->rmtBit0 = rmtBit0; + state->rmtBit1 = rmtBit1; + state->resetDuration = reset; + + // Initialize hardware + rmt_ll_tx_stop(&RMT, channel); + rmt_ll_tx_reset_pointer(&RMT, channel); + rmt_ll_enable_tx_err_interrupt(&RMT, channel, false); + rmt_ll_enable_tx_end_interrupt(&RMT, channel, false); + rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false); + rmt_ll_clear_tx_err_interrupt(&RMT, channel); + rmt_ll_clear_tx_end_interrupt(&RMT, channel); + rmt_ll_clear_tx_thres_interrupt(&RMT, channel); + + rmt_ll_tx_enable_loop(&RMT, channel, false); + rmt_ll_tx_enable_pingpong(&RMT, channel, true); + rmt_ll_tx_set_limit(&RMT, channel, rmtBatchSize); + + driverState[channel] = state; + + rmt_ll_enable_tx_thres_interrupt(&RMT, channel, true); + + return err; +} + +esp_err_t NeoEsp32RmtHiMethodDriver::Uninstall(rmt_channel_t channel) { + if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG; + + NeoEsp32RmtHIChannelState* state = driverState[channel]; + + WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS); + + // Done or not, we're out of here + rmt_ll_tx_stop(&RMT, channel); + rmt_ll_enable_tx_thres_interrupt(&RMT, channel, false); + driverState[channel] = nullptr; + heap_caps_free(state); + +#if !defined(CONFIG_BTDM_CTRL_HLI) /* Cannot unbind from bluetooth ISR */ + // Turn off the driver ISR and release global state if none are left + for (uint8_t channelIndex = 0; channelIndex < RMT_CHANNEL_MAX; ++channelIndex) { + if (driverState[channelIndex]) return ESP_OK; // done + } + +#if defined(NEOESP32_RMT_CAN_USE_INTR_ALLOC) + esp_intr_free(isrHandle); +#else + ESP_INTR_DISABLE(ESP32_LV5_IRQ_INDEX); +#endif + + heap_caps_free(driverState); + driverState = nullptr; +#endif /* !defined(CONFIG_BTDM_CTRL_HLI) */ + + return ESP_OK; +} + +esp_err_t NeoEsp32RmtHiMethodDriver::Write(rmt_channel_t channel, const uint8_t *src, size_t src_size) { + if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG; + + NeoEsp32RmtHIChannelState& state = *driverState[channel]; + esp_err_t result = WaitForTxDone(channel, 10000 / portTICK_PERIOD_MS); + + if (result == ESP_OK) { + state.txDataStart = src; + state.txDataCurrent = src; + state.txDataEnd = src + src_size; + RmtStartWrite(channel, state); + } + return result; +} + +esp_err_t NeoEsp32RmtHiMethodDriver::WaitForTxDone(rmt_channel_t channel, TickType_t wait_time) { + if ((channel >= RMT_CHANNEL_MAX) || !driverState || !driverState[channel]) return ESP_ERR_INVALID_ARG; + + NeoEsp32RmtHIChannelState& state = *driverState[channel]; + // yield-wait until wait_time + esp_err_t rv = ESP_OK; + uint32_t status; + while(1) { + status = rmt_ll_tx_get_channel_status(&RMT, channel); + if (!_RmtStatusIsTransmitting(channel, status)) break; + if (wait_time == 0) { rv = ESP_ERR_TIMEOUT; break; }; + + TickType_t sleep = std::min(wait_time, (TickType_t) 5); + vTaskDelay(sleep); + wait_time -= sleep; + }; + + return rv; +} + +#endif \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 5aac5cb031..d229d7b0ca 100644 --- a/platformio.ini +++ b/platformio.ini @@ -139,7 +139,7 @@ lib_deps = fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.8.3 - #https://github.com/makuna/NeoPixelBus.git#CoreShaderBeta + NeoESPRmtHI https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2 # for I2C interface ;Wire diff --git a/wled00/bus_wrapper.h b/wled00/bus_wrapper.h index 5d8f306f5e..540004340a 100644 --- a/wled00/bus_wrapper.h +++ b/wled00/bus_wrapper.h @@ -244,53 +244,61 @@ typedef NeoEsp32I2s1Tm1914Method X1Tm1914Method; #endif +// RMT driver selection +#if !defined(WLED_USE_SHARED_RMT) && !defined(__riscv) +#include +#define NeoEsp32RmtMethod(x) NeoEsp32RmtHIN ## x ## Method +#else +#define NeoEsp32RmtMethod(x) NeoEsp32RmtN ## x ## Method +#endif + //RGB -#define B_32_RN_NEO_3 NeoPixelBusLg // ESP32, S2, S3, C3 +#define B_32_RN_NEO_3 NeoPixelBusLg // ESP32, S2, S3, C3 //#define B_32_IN_NEO_3 NeoPixelBusLg // ESP32 (dynamic I2S selection) #define B_32_I2_NEO_3 NeoPixelBusLg // ESP32, S2, S3 (automatic I2S selection, see typedef above) #define B_32_IP_NEO_3 NeoPixelBusLg // parallel I2S (ESP32, S2, S3) //RGBW -#define B_32_RN_NEO_4 NeoPixelBusLg +#define B_32_RN_NEO_4 NeoPixelBusLg #define B_32_I2_NEO_4 NeoPixelBusLg #define B_32_IP_NEO_4 NeoPixelBusLg // parallel I2S //400Kbps -#define B_32_RN_400_3 NeoPixelBusLg +#define B_32_RN_400_3 NeoPixelBusLg #define B_32_I2_400_3 NeoPixelBusLg #define B_32_IP_400_3 NeoPixelBusLg // parallel I2S //TM1814 (RGBW) -#define B_32_RN_TM1_4 NeoPixelBusLg +#define B_32_RN_TM1_4 NeoPixelBusLg #define B_32_I2_TM1_4 NeoPixelBusLg #define B_32_IP_TM1_4 NeoPixelBusLg // parallel I2S //TM1829 (RGB) -#define B_32_RN_TM2_3 NeoPixelBusLg +#define B_32_RN_TM2_3 NeoPixelBusLg #define B_32_I2_TM2_3 NeoPixelBusLg #define B_32_IP_TM2_3 NeoPixelBusLg // parallel I2S //UCS8903 -#define B_32_RN_UCS_3 NeoPixelBusLg +#define B_32_RN_UCS_3 NeoPixelBusLg #define B_32_I2_UCS_3 NeoPixelBusLg #define B_32_IP_UCS_3 NeoPixelBusLg // parallel I2S //UCS8904 -#define B_32_RN_UCS_4 NeoPixelBusLg +#define B_32_RN_UCS_4 NeoPixelBusLg #define B_32_I2_UCS_4 NeoPixelBusLg #define B_32_IP_UCS_4 NeoPixelBusLg// parallel I2S //APA106 -#define B_32_RN_APA106_3 NeoPixelBusLg +#define B_32_RN_APA106_3 NeoPixelBusLg #define B_32_I2_APA106_3 NeoPixelBusLg #define B_32_IP_APA106_3 NeoPixelBusLg // parallel I2S //FW1906 GRBCW -#define B_32_RN_FW6_5 NeoPixelBusLg +#define B_32_RN_FW6_5 NeoPixelBusLg #define B_32_I2_FW6_5 NeoPixelBusLg #define B_32_IP_FW6_5 NeoPixelBusLg // parallel I2S //WS2805 RGBWC -#define B_32_RN_2805_5 NeoPixelBusLg +#define B_32_RN_2805_5 NeoPixelBusLg #define B_32_I2_2805_5 NeoPixelBusLg #define B_32_IP_2805_5 NeoPixelBusLg // parallel I2S //TM1914 (RGB) -#define B_32_RN_TM1914_3 NeoPixelBusLg +#define B_32_RN_TM1914_3 NeoPixelBusLg #define B_32_I2_TM1914_3 NeoPixelBusLg #define B_32_IP_TM1914_3 NeoPixelBusLg // parallel I2S //Sm16825 (RGBWC) -#define B_32_RN_SM16825_5 NeoPixelBusLg +#define B_32_RN_SM16825_5 NeoPixelBusLg #define B_32_I2_SM16825_5 NeoPixelBusLg #define B_32_IP_SM16825_5 NeoPixelBusLg // parallel I2S #endif From b762704d37aba8b43448a04bdffacf54073be6a5 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 1 Sep 2025 21:50:57 -0400 Subject: [PATCH 2/5] RmtHI: Remove incorrect default selection block --- .../include/NeoEsp32RmtHIMethod.h | 93 ------------------- 1 file changed, 93 deletions(-) diff --git a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h index 0e4f71113a..3039622981 100644 --- a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h +++ b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h @@ -466,97 +466,4 @@ typedef NeoEsp32Rmt7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod; #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) - -#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) - -// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT -// will switch to use RMT as the default method -// The ESP32S2, ESP32S3, and ESP32C3 will always defualt to RMT - -#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) - -// RMT channel 1 method is the default method for ESP32S2, ESP32S3, and ESP32C3 -typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2813Method; -typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2812xMethod; -typedef NeoEsp32Rmt1800KbpsMethod NeoWs2812Method; -typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2811Method; -typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2816Method; -typedef NeoEsp32Rmt1Ws2805Method NeoWs2805Method; -typedef NeoEsp32Rmt1Ws2814Method NeoWs2814Method; -typedef NeoEsp32Rmt1Sk6812Method NeoSk6812Method; -typedef NeoEsp32Rmt1Tm1814Method NeoTm1814Method; -typedef NeoEsp32Rmt1Tm1829Method NeoTm1829Method; -typedef NeoEsp32Rmt1Tm1914Method NeoTm1914Method; -typedef NeoEsp32Rmt1Sk6812Method NeoLc8812Method; -typedef NeoEsp32Rmt1Apa106Method NeoApa106Method; -typedef NeoEsp32Rmt1Tx1812Method NeoTx1812Method; -typedef NeoEsp32Rmt1Gs1903Method NeoGs1903Method; - -typedef NeoEsp32Rmt1Ws2812xMethod Neo800KbpsMethod; -typedef NeoEsp32Rmt1400KbpsMethod Neo400KbpsMethod; - -typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2813InvertedMethod; -typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2812xInvertedMethod; -typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2811InvertedMethod; -typedef NeoEsp32Rmt1800KbpsInvertedMethod NeoWs2812InvertedMethod; -typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2816InvertedMethod; -typedef NeoEsp32Rmt1Ws2805InvertedMethod NeoWs2805InvertedMethod; -typedef NeoEsp32Rmt1Ws2814InvertedMethod NeoWs2814InvertedMethod; -typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoSk6812InvertedMethod; -typedef NeoEsp32Rmt1Tm1814InvertedMethod NeoTm1814InvertedMethod; -typedef NeoEsp32Rmt1Tm1829InvertedMethod NeoTm1829InvertedMethod; -typedef NeoEsp32Rmt1Tm1914InvertedMethod NeoTm1914InvertedMethod; -typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoLc8812InvertedMethod; -typedef NeoEsp32Rmt1Apa106InvertedMethod NeoApa106InvertedMethod; -typedef NeoEsp32Rmt1Tx1812InvertedMethod NeoTx1812InvertedMethod; -typedef NeoEsp32Rmt1Gs1903InvertedMethod NeoGs1903InvertedMethod; - -typedef NeoEsp32Rmt1Ws2812xInvertedMethod Neo800KbpsInvertedMethod; -typedef NeoEsp32Rmt1400KbpsInvertedMethod Neo400KbpsInvertedMethod; - -#else // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32S3) - -// RMT channel 6 method is the default method for Esp32 -typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method; -typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod; -typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method; -typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method; -typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2816Method; -typedef NeoEsp32Rmt6Ws2805Method NeoWs2805Method; -typedef NeoEsp32Rmt6Ws2814Method NeoWs2814Method; -typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method; -typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method; -typedef NeoEsp32Rmt6Tm1829Method NeoTm1829Method; -typedef NeoEsp32Rmt6Tm1914Method NeoTm1914Method; -typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method; -typedef NeoEsp32Rmt6Apa106Method NeoApa106Method; -typedef NeoEsp32Rmt6Tx1812Method NeoTx1812Method; -typedef NeoEsp32Rmt6Gs1903Method NeoGs1903Method; - -typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod; -typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod; - -typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod; -typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod; -typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod; -typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod; -typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2816InvertedMethod; -typedef NeoEsp32Rmt6Ws2805InvertedMethod NeoWs2805InvertedMethod; -typedef NeoEsp32Rmt6Ws2814InvertedMethod NeoWs2814InvertedMethod; -typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod; -typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod; -typedef NeoEsp32Rmt6Tm1829InvertedMethod NeoTm1829InvertedMethod; -typedef NeoEsp32Rmt6Tm1914InvertedMethod NeoTm1914InvertedMethod; -typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod; -typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod; -typedef NeoEsp32Rmt6Tx1812InvertedMethod NeoTx1812InvertedMethod; -typedef NeoEsp32Rmt6Gs1903InvertedMethod NeoGs1903InvertedMethod; - -typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod; -typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod; - -#endif // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) - -#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) - #endif From 139f4d949fe7f2b7d98b683b7c39c3cc5d880a78 Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 1 Sep 2025 21:51:36 -0400 Subject: [PATCH 3/5] RmtHI: Fix incorrect method typedefs --- .../include/NeoEsp32RmtHIMethod.h | 36 +++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h index 3039622981..02e066f741 100644 --- a/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h +++ b/lib/NeoESP32RmtHI/include/NeoEsp32RmtHIMethod.h @@ -194,7 +194,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsMethod; -typedef NeoEsp32RmtNWs2805Method NeoEsp32RmtHINWs2814Method; +typedef NeoEsp32RmtHINWs2805Method NeoEsp32RmtHINWs2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xMethod; @@ -209,7 +209,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsMethod; -typedef NeoEsp32Rmt0Ws2805Method NeoEsp32RmtHI0Ws2814Method; +typedef NeoEsp32RmtHI0Ws2805Method NeoEsp32RmtHI0Ws2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xMethod; @@ -224,7 +224,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsMethod; -typedef NeoEsp32Rmt1Ws2805Method NeoEsp32RmtHI1Ws2814Method; +typedef NeoEsp32RmtHI1Ws2805Method NeoEsp32RmtHI1Ws2814Method; #if !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -241,7 +241,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsMethod; -typedef NeoEsp32Rmt2Ws2805Method NeoEsp32RmtHI2Ws2814Method; +typedef NeoEsp32RmtHI2Ws2805Method NeoEsp32RmtHI2Ws2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xMethod; @@ -256,7 +256,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsMethod; -typedef NeoEsp32Rmt3Ws2805Method NeoEsp32RmtHI3Ws2814Method; +typedef NeoEsp32RmtHI3Ws2805Method NeoEsp32RmtHI3Ws2814Method; #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) @@ -273,7 +273,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsMethod; -typedef NeoEsp32Rmt4Ws2805Method NeoEsp32RmtHI4Ws2814Method; +typedef NeoEsp32RmtHI4Ws2805Method NeoEsp32RmtHI4Ws2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xMethod; @@ -288,7 +288,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsMethod; -typedef NeoEsp32Rmt5Ws2805Method NeoEsp32RmtHI5Ws2814Method; +typedef NeoEsp32RmtHI5Ws2805Method NeoEsp32RmtHI5Ws2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xMethod; @@ -303,7 +303,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsMethod; -typedef NeoEsp32Rmt6Ws2805Method NeoEsp32RmtHI6Ws2814Method; +typedef NeoEsp32RmtHI6Ws2805Method NeoEsp32RmtHI6Ws2814Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xMethod; @@ -318,7 +318,7 @@ typedef NeoEsp32RmtHIMethodBase Neo typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903Method; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsMethod; -typedef NeoEsp32Rmt7Ws2805Method NeoEsp32RmtHI7Ws2814Method; +typedef NeoEsp32RmtHI7Ws2805Method NeoEsp32RmtHI7Ws2814Method; #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -337,7 +337,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHINGs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHIN400KbpsInvertedMethod; -typedef NeoEsp32RmtNWs2805InvertedMethod NeoEsp32RmtHINWs2814InvertedMethod; +typedef NeoEsp32RmtHINWs2805InvertedMethod NeoEsp32RmtHINWs2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Ws2812xInvertedMethod; @@ -352,7 +352,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI0400KbpsInvertedMethod; -typedef NeoEsp32Rmt0Ws2805InvertedMethod NeoEsp32RmtHI0Ws2814InvertedMethod; +typedef NeoEsp32RmtHI0Ws2805InvertedMethod NeoEsp32RmtHI0Ws2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Ws2812xInvertedMethod; @@ -367,7 +367,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI1400KbpsInvertedMethod; -typedef NeoEsp32Rmt1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod; +typedef NeoEsp32RmtHI1Ws2805InvertedMethod NeoEsp32RmtHI1Ws2814InvertedMethod; #if !defined(CONFIG_IDF_TARGET_ESP32C3) @@ -384,7 +384,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI2400KbpsInvertedMethod; -typedef NeoEsp32Rmt2Ws2805InvertedMethod NeoEsp32RmtHI2Ws2814InvertedMethod; +typedef NeoEsp32RmtHI2Ws2805InvertedMethod NeoEsp32RmtHI2Ws2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Ws2812xInvertedMethod; @@ -399,7 +399,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI3400KbpsInvertedMethod; -typedef NeoEsp32Rmt3Ws2805InvertedMethod NeoEsp32RmtHI3Ws2814InvertedMethod; +typedef NeoEsp32RmtHI3Ws2805InvertedMethod NeoEsp32RmtHI3Ws2814InvertedMethod; #if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) @@ -416,7 +416,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI4400KbpsInvertedMethod; -typedef NeoEsp32Rmt4Ws2805InvertedMethod NeoEsp32RmtHI4Ws2814InvertedMethod; +typedef NeoEsp32RmtHI4Ws2805InvertedMethod NeoEsp32RmtHI4Ws2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Ws2812xInvertedMethod; @@ -431,7 +431,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI5400KbpsInvertedMethod; -typedef NeoEsp32Rmt5Ws2805InvertedMethod NeoEsp32RmtHI5Ws2814InvertedMethod; +typedef NeoEsp32RmtHI5Ws2805InvertedMethod NeoEsp32RmtHI5Ws2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Ws2812xInvertedMethod; @@ -446,7 +446,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI6400KbpsInvertedMethod; -typedef NeoEsp32Rmt6Ws2805InvertedMethod NeoEsp32RmtHI6Ws2814InvertedMethod; +typedef NeoEsp32RmtHI6Ws2805InvertedMethod NeoEsp32RmtHI6Ws2814InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2811InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Ws2812xInvertedMethod; @@ -461,7 +461,7 @@ typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7Gs1903InvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7800KbpsInvertedMethod; typedef NeoEsp32RmtHIMethodBase NeoEsp32RmtHI7400KbpsInvertedMethod; -typedef NeoEsp32Rmt7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod; +typedef NeoEsp32RmtHI7Ws2805InvertedMethod NeoEsp32RmtHI7Ws2814InvertedMethod; #endif // !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32S3) #endif // !defined(CONFIG_IDF_TARGET_ESP32C3) From 32fccb6a34210a2e898c78310242d3d40f7f523d Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 1 Sep 2025 22:00:24 -0400 Subject: [PATCH 4/5] Undo RMTHi change to platformio.ini PlatformIO's Library Dependency Finder will take care of it based on the #include. --- platformio.ini | 1 - 1 file changed, 1 deletion(-) diff --git a/platformio.ini b/platformio.ini index d229d7b0ca..e757490242 100644 --- a/platformio.ini +++ b/platformio.ini @@ -139,7 +139,6 @@ lib_deps = fastled/FastLED @ 3.6.0 IRremoteESP8266 @ 2.8.2 makuna/NeoPixelBus @ 2.8.3 - NeoESPRmtHI https://github.com/Aircoookie/ESPAsyncWebServer.git#v2.4.2 # for I2C interface ;Wire From 3e80c2ce40cfa1529a03ad526284a08dfbea953c Mon Sep 17 00:00:00 2001 From: Will Miles Date: Mon, 1 Sep 2025 22:03:18 -0400 Subject: [PATCH 5/5] RmtHI: Add missing includes While these were both fortunately included in Arduino.h, as @coderabbitai suggests, it's best practice to be explicit for anything one uses directly. --- lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp index bd63c4432d..8353201f08 100644 --- a/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp +++ b/lib/NeoESP32RmtHI/src/NeoEsp32RmtHIMethod.cpp @@ -31,6 +31,8 @@ License along with NeoPixel. If not, see #if defined(ARDUINO_ARCH_ESP32) +#include +#include "esp_idf_version.h" #include "NeoEsp32RmtHIMethod.h" #include "soc/soc.h" #include "soc/rmt_reg.h"