diff --git a/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h b/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h index 3b6918318..d810e2a94 100644 --- a/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h +++ b/lib/lib_basic/NeoPixelBus/src/NeoPixelBus.h @@ -105,7 +105,11 @@ License along with NeoPixel. If not, see #include "internal/NeoEsp32I2sMethod.h" #include "internal/NeoEsp32RmtMethod.h" #else -#include "internal/NeoEsp32RmtMethod_idf5.h" +#if !defined(CONFIG_IDF_TARGET_ESP32C2) +#include "internal/NeoEsp32RmtMethod_idf5.h" // every other SOC +#else //CONFIG_IDF_TARGET_ESP32C2 +#include "internal/NeoEsp32SpiMethod_idf5.h" // ESP32C2 +#endif //CONFIG_IDF_TARGET_ESP32C2 #endif // ESP_IDF_VERSION_MAJOR #include "internal/NeoEspBitBangMethod.h" #include "internal/DotStarEsp32DmaSpiMethod.h" diff --git a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c index 5c1943ec9..5823b1875 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c +++ b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.c @@ -21,7 +21,7 @@ // ESP32C3/S3 I2S is not supported yet due to significant changes to interface #ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 -#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) +#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #include #include diff --git a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h index b9ab41920..bfc024a8c 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/Esp32_i2s.h @@ -4,7 +4,7 @@ #ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1 // ESP32C3 I2S is not supported yet due to significant changes to interface -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) #ifdef __cplusplus extern "C" { diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp index fd94321ea..c8525e09d 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.cpp @@ -32,7 +32,7 @@ License along with NeoPixel. If not, see #include "NeoBusChannel.h" #include "NeoEsp32RmtMethod.h" -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2) // translate NeoPixelBuffer into RMT buffer diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h index faded6b3f..e804cc2a7 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod.h @@ -29,7 +29,7 @@ License along with NeoPixel. If not, see #pragma once -#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) +#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2) /* General Reference documentation for the APIs used in this implementation LOW LEVEL: (what is actually used) diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h index a7bfa3c72..905710254 100644 --- a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h @@ -45,7 +45,7 @@ Esp32-hal-rmt.c #include -// extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); extern "C" { @@ -55,7 +55,7 @@ extern "C" #include "esp_check.h" } -#define RMT_LED_STRIP_RESOLUTION_HZ 10000000 // 10MHz resolution, 1 tick = 0.1us (led strip needs a high resolution) +#define RMT_LED_STRIP_RESOLUTION_HZ 40000000 // 40MHz resolution - setting of the "old" driver typedef struct { uint32_t resolution; /*!< Encoder resolution, in Hz */ @@ -124,9 +124,9 @@ static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder) return ESP_OK; } -esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder/*, uint32_t bit0, uint32_t bit1*/) +esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder, uint32_t bit0, uint32_t bit1) { - const char* TAG = "TEST_RMT"; + const char* TAG = "TEST_RMT"; //TODO: Remove later esp_err_t ret = ESP_OK; rmt_led_strip_encoder_t *led_encoder = NULL; uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us @@ -141,16 +141,11 @@ esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rm led_encoder->base.encode = rmt_encode_led_strip; led_encoder->base.del = rmt_del_led_strip_encoder; led_encoder->base.reset = rmt_led_strip_encoder_reset; - // different led strip might have its own timing requirements, following parameter is for WS2812 - bytes_encoder_config.bit0.level0 = 1; - bytes_encoder_config.bit0.duration0 = 0.3 * config->resolution / 1000000; // T0H=0.3us - bytes_encoder_config.bit0.level1 = 0; - bytes_encoder_config.bit0.duration1 = 0.9 * config->resolution / 1000000; // T0L=0.9us - bytes_encoder_config.bit1.level0 = 1; - bytes_encoder_config.bit1.duration0 = 0.9 * config->resolution / 1000000; // T0H=0.3us - bytes_encoder_config.bit1.level1 = 0; - bytes_encoder_config.bit1.duration1 = 0.3 * config->resolution / 1000000; // T0L=0.9us - bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 + + bytes_encoder_config.bit0.val = bit0; + bytes_encoder_config.bit1.val = bit1; + + bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed"); ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(©_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed"); @@ -226,7 +221,7 @@ public: class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase { public: - const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); // TODO: DRAM_ATTR debatable everywhere const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350); const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us }; @@ -234,8 +229,8 @@ public: class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase { public: - const uint32_t RmtBit0 = Item32Val(400, 850); - const uint32_t RmtBit1 = Item32Val(800, 450); + const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850); + const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450); const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us }; @@ -530,11 +525,11 @@ public: _tx_config.loop_count = 0; //no loop - ret += rmt_new_led_strip_encoder(&encoder_config, &_led_encoder); + ret += rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, T_SPEED::RmtBit0, T_SPEED::RmtBit1); // ESP_LOGI(TAG, "Enable RMT TX channel"); ret += rmt_enable(_channel.RmtChannelNumber); - // AddLog(2,"RMT:initialized with error code: %u on pin: %u",ret, _pin); + AddLog(2,"RMT:initialized with error code: %u on pin: %u",ret, _pin); } void Update(bool maintainBufferConsistency) @@ -548,9 +543,7 @@ public: { // AddLog(2,"__ %u", _sizeData); // now start the RMT transmit with the editing buffer before we swap - // const uint8_t pixels[3] = {100,100,100}; esp_err_t ret = rmt_transmit(_channel.RmtChannelNumber, _led_encoder, _dataEditing, _sizeData, &_tx_config); // 3 for _sizeData - // esp_err_t ret = rmt_transmit(_channel.RmtChannelNumber, _led_encoder, pixels, 3, &_tx_config); // AddLog(2,"rmt_transmit: %u", ret); if (maintainBufferConsistency) { diff --git a/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h new file mode 100644 index 000000000..826d6ef99 --- /dev/null +++ b/lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h @@ -0,0 +1,504 @@ +/*------------------------------------------------------------------------- +NeoPixel library helper functions for Esp32. + +Adaption of Espressif's component library code by Christian Baars + +Written by Michael C. Miller. + +I invest time and resources providing this open source code, +please support me by dontating (see https://github.com/Makuna/NeoPixelBus) + +------------------------------------------------------------------------- +This file is not yet 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) + +#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST) +// HSPI_HOST depreciated in C3 +#define HSPI_HOST SPI2_HOST +#endif + +#include + +extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); // TODO: Remove all Addlogs + +extern "C" +{ +#include +#include "esp_rom_gpio.h" +#include "driver/spi_master.h" +#include "esp_check.h" +} + +#define LED_STRIP_SPI_DEFAULT_RESOLUTION (25 * 100 * 1000) // 2.5MHz resolution +#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4 + +#define SPI_BYTES_PER_COLOR_BYTE 3 +#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8) + +static const char *TAG = "led_strip_spi"; // TODO: Remove all TAG log stuff + +typedef enum { + LED_MODEL_WS2812, /*!< LED strip model: WS2812 */ + LED_MODEL_SK6812, /*!< LED strip model: SK6812 */ + LED_MODEL_INVALID /*!< Invalid LED strip model */ +} led_model_t; + +typedef enum { + LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */ + LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */ + LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */ +} led_pixel_format_t; + +typedef struct { + spi_host_device_t spi_host; + spi_device_handle_t spi_device; + uint32_t strip_len; + uint8_t bytes_per_pixel; + uint8_t pixel_buf[]; +} led_strip_spi_obj; + +/** + * @brief LED Strip Configuration + */ +typedef struct { + int strip_gpio_num; /*!< GPIO number that used by LED strip */ + uint32_t max_leds; /*!< Maximum LEDs in a single strip */ + led_pixel_format_t led_pixel_format; /*!< LED pixel format */ + led_model_t led_model; /*!< LED model */ + + struct { + uint32_t invert_out: 1; /*!< Invert output signal */ + } flags; +} led_strip_config_t; + +typedef struct { + spi_clock_source_t clk_src; /*!< SPI clock source */ + spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */ + struct { + uint32_t with_dma: 1; /*!< Use DMA to transmit data */ + } flags; +} led_strip_spi_config_t; + + +class NeoEsp32SpiSpeed +{ +public: + + +protected: + +// end of deprecated section + +}; + +class NeoEsp32SpiSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedBase : public NeoEsp32SpiSpeed +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2811 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedWs2812x : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 3; + +}; + +class NeoEsp32SpiSpeedSk6812 : public NeoEsp32SpiSpeedBase +{ +public: + static const uint8_t bytes_per_pixel = 4; + +}; + +class NeoEsp32SpiSpeed400Kbps : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedApa106 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiSpeedTx1812 : public NeoEsp32SpiSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2811 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedWs2812x : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedSk6812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed800Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeed400Kbps : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedApa106 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiInvertedSpeedTx1812 : public NeoEsp32SpiInvertedSpeedBase +{ +public: + +}; + +class NeoEsp32SpiChannel +{ +public: + +}; + + +template class NeoEsp32SpiMethodBase +{ +public: + typedef NeoNoSettings SettingsObject; + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) : + _sizeData(pixelCount * elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + { + _pixelCount = pixelCount; + construct(); + } + + NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) : + _sizeData(pixelCount* elementSize + settingsSize), + // _pixelCount(pixelCount), + _pin(pin) + // _channel(channel) // TODO: Refactor this somehow + { + _pixelCount = pixelCount; + construct(); + } + + ~NeoEsp32SpiMethodBase() + { + // wait until the last send finishes before destructing everything + // arbitrary time out of 10 seconds + + gpio_matrix_out(_pin, 0x100, false, false); + pinMode(_pin, INPUT); + + spi_bus_remove_device(_spi_strip->spi_device); + spi_bus_free(_spi_strip->spi_host); + free(_spi_strip); + + free(_dataEditing); + free(_dataSending); + } + + + bool IsReadyToUpdate() const + { + return true; // TODO + } + + void Initialize() + { + esp_err_t ret = ESP_OK; + uint8_t bytes_per_pixel = T_SPEED::bytes_per_pixel; + uint32_t mem_caps = MALLOC_CAP_DEFAULT; + spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT; + spi_bus_config_t spi_bus_cfg; + spi_device_interface_config_t spi_dev_cfg; + bool with_dma = true; /// TODO: pass value or compute based on pixelcount + int clock_resolution_khz = 0; + + // ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument"); + // ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format"); + + // if ( LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRBW) { // TODO + // bytes_per_pixel = 4; + // } else if (LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRB) { + // bytes_per_pixel = 3; + // } else { + // assert(false); + // } + + if (with_dma) { // TODO + // DMA buffer must be placed in internal SRAM + mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA; + } + _spi_strip = (led_strip_spi_obj *)heap_caps_calloc(1, sizeof(led_strip_spi_obj) + _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps); + + ESP_GOTO_ON_FALSE(_spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip"); + + _spi_strip->spi_host = SPI2_HOST; + + // for backward compatibility, if the user does not set the clk_src, use the default value + // if (clk_src) { + // clk_src = spi_config->clk_src; + // } + + spi_bus_cfg = { + .mosi_io_num = _pin, + //Only use MOSI to generate the signal, set -1 when other pins are not used. + .miso_io_num = -1, + .sclk_io_num = -1, + .quadwp_io_num = -1, + .quadhd_io_num = -1, + .max_transfer_sz = _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, + }; + ESP_GOTO_ON_ERROR(spi_bus_initialize(_spi_strip->spi_host, &spi_bus_cfg, with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed"); + + // if (led_config->flags.invert_out == true) { + // esp_rom_gpio_connect_out_signal(_pin, spi_periph_signal[_spi_strip->spi_host].spid_out, true, false); + // } + + spi_dev_cfg = { + .command_bits = 0, + .address_bits = 0, + .dummy_bits = 0, + .mode = 0, + //set -1 when CS is not used + .clock_source = clk_src, + .clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION, + .spics_io_num = -1, + .queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE, + }; + + ESP_GOTO_ON_ERROR(spi_bus_add_device(_spi_strip->spi_host, &spi_dev_cfg, &_spi_strip->spi_device), err, TAG, "Failed to add spi device"); + + spi_device_get_actual_freq(_spi_strip->spi_device, &clock_resolution_khz); + // TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution + // But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION + ESP_GOTO_ON_FALSE(clock_resolution_khz == LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000, ESP_ERR_NOT_SUPPORTED, err, + TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz); + + _spi_strip->bytes_per_pixel = bytes_per_pixel; + _spi_strip->strip_len = _pixelCount; + + AddLog(2,"SPI:initialized with error code: %u on pin: %u",ret, _pin); + return; + err: + if (_spi_strip) { + if (_spi_strip->spi_device) { + spi_bus_remove_device(_spi_strip->spi_device); + } + if (_spi_strip->spi_host) { + spi_bus_free(_spi_strip->spi_host); + } + free(_spi_strip); + } + AddLog(2,"SPI-Error:initialized with error code: %u on pin: %u",ret, _pin); + return; + } + + void Update(bool maintainBufferConsistency) + { + // AddLog(2,".."); + // 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 READY + { + // AddLog(2,"__ %u", _sizeData); + // now start the SPI transmit with the editing buffer before we swap + led_strip_transmit_RGB_buffer(_dataEditing, _sizeData, T_SPEED::bytes_per_pixel); + + 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); + } + } + + uint8_t* getData() const + { + return _dataEditing; + }; + + size_t getDataSize() const + { + return _sizeData; + } + + void applySettings(const SettingsObject& settings) + { + } + +private: + const size_t _sizeData; // Size of '_data*' buffers + int16_t _pixelCount; + const uint8_t _pin; // output pin number + T_CHANNEL _channel; // not really used here + + led_strip_spi_obj *_spi_strip; + + + // 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 - TODO: Check if this useful for SPI + + + 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 + } + + // please make sure to zero-initialize the buf before calling this function + + void __led_strip_spi_bit(uint8_t data, uint8_t *buf) + { + // Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110 + // So a color byte occupies 3 bytes of SPI. + *(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2); + *(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5); + *(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00; + *(buf + 1) |= BIT(0); + *(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3); + *(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6); + *(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1); + *(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4); + *(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7); + } + + esp_err_t led_strip_spi_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue) + { + if(index >= _spi_strip->strip_len) return ESP_FAIL; + // LED_PIXEL_FORMAT_GRB takes 72bits(9bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + if (_spi_strip->bytes_per_pixel > 3) { + __led_strip_spi_bit(0, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + } + return ESP_OK; + } + + esp_err_t led_strip_spi_set_pixel_rgbw(uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white) + { + // LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes) + uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE; + // SK6812 component order is GRBW + memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + __led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]); + __led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]); + __led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]); + __led_strip_spi_bit(white, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]); + + return ESP_OK; + } + + esp_err_t led_strip_spi_clear() + { + //Write zero to turn off all leds + memset(_spi_strip->pixel_buf, 0, _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE); + uint8_t *buf = _spi_strip->pixel_buf; + for (int index = 0; index < _spi_strip->strip_len * _spi_strip->bytes_per_pixel; index++) { + __led_strip_spi_bit(0, buf); + buf += SPI_BYTES_PER_COLOR_BYTE; + } + return led_strip_spi_refresh(); + } + + esp_err_t led_strip_spi_refresh() + { + spi_transaction_t tx_conf; + memset(&tx_conf, 0, sizeof(tx_conf)); + + tx_conf.length = _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE; + tx_conf.tx_buffer = _spi_strip->pixel_buf; + tx_conf.rx_buffer = NULL; + spi_device_transmit(_spi_strip->spi_device, &tx_conf); // TODO -check + return ESP_OK; + } + + void led_strip_transmit_RGB_buffer(uint8_t * buffer, size_t size, uint8_t bytes_per_pixel) + { + for (int i = 0; i < size; i+=bytes_per_pixel) { + led_strip_spi_set_pixel(i/bytes_per_pixel, buffer[i+1], buffer[i], buffer[i+2]); //GRB -> RGB + } + /* Refresh the strip to send data */ + led_strip_spi_refresh(); + } +}; + +// normal +typedef NeoEsp32SpiMethodBase NeoEsp32SpiN800KbpsMethod; +typedef NeoEsp32SpiMethodBase NeoEsp32SpiNSk6812Method; + + +// SPI channel method is the default method for Esp32C2 +#ifdef CONFIG_IDF_TARGET_ESP32C2 +typedef NeoEsp32SpiSpeedWs2812x NeoWs2813Method; +typedef NeoEsp32SpiSpeedWs2812x NeoWs2812xMethod; +typedef NeoEsp32SpiSpeedSk6812 NeoSk6812Method; + +#endif //CONFIG_IDF_TARGET_ESP32C2 + +#endif diff --git a/platformio_tasmota_core3_env_sample.ini b/platformio_tasmota_core3_env_sample.ini index ada11afac..c5e738589 100644 --- a/platformio_tasmota_core3_env_sample.ini +++ b/platformio_tasmota_core3_env_sample.ini @@ -119,14 +119,12 @@ build_unflags = ${env:arduino30.build_unflags} -mtarget-align build_flags = ${env:arduino30.build_flags} -DFIRMWARE_ARDUINO30 - -DNO_NEOPIXEL -DUSE_MI_HOMEKIT=0 ; 1 to enable; 0 to disable -DUSE_MI_ESP32 -fno-lto -DOTA_URL='""' monitor_filters = esp32_exception_decoder lib_ignore = ${env:arduino30.lib_ignore} - NeoPixelBus [env:tasmota32c3-arduino30] extends = env:arduino30 diff --git a/tasmota/include/tasmota_configurations_ESP32.h b/tasmota/include/tasmota_configurations_ESP32.h index 21fc5c0ce..3e705fa06 100644 --- a/tasmota/include/tasmota_configurations_ESP32.h +++ b/tasmota/include/tasmota_configurations_ESP32.h @@ -238,8 +238,8 @@ #undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code) #undef USE_SHELLY_DIMMER // Disable support for Shelly Dimmer (+3k code) -#undef USE_LIGHT // Disable support for lights -#undef USE_WS2812 +// #undef USE_LIGHT // Disable support for lights +// #undef USE_WS2812 #undef USE_DS18x20 // Disable DS18x20 sensor diff --git a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino index c62f3bc30..249553a87 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_52_3_berry_leds.ino @@ -33,8 +33,13 @@ enum { neopixel_type_end }; +#ifdef CONFIG_IDF_TARGET_ESP32C2 +typedef NeoPixelBus neopixel_ws2812_grb_t; +typedef NeoPixelBus neopixel_sk6812_grbw_t; +#else typedef NeoPixelBus neopixel_ws2812_grb_t; typedef NeoPixelBus neopixel_sk6812_grbw_t; +#endif /*********************************************************************************************\ diff --git a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino index 9ddeb4928..e87d393f7 100644 --- a/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino +++ b/tasmota/tasmota_xlgt_light/xlgt_01_ws2812.ino @@ -19,6 +19,7 @@ #ifdef USE_LIGHT #ifdef USE_WS2812 + /*********************************************************************************************\ * WS2812 RGB / RGBW Leds using NeopixelBus library * @@ -146,6 +147,8 @@ typedef CONCAT3(NEO_FEATURE_NEO,NEO_FEATURE_TYPE,NEO_FEATURE_FEATURE) selectedNe #if defined(ESP8266) && defined(USE_WS2812_DMA) typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_INV,NEO_HW,Method) selectedNeoSpeedType; +#elif defined(CONFIG_IDF_TARGET_ESP32C2) +typedef NeoEsp32SpiN800KbpsMethod selectedNeoSpeedType; #else // Dma : different naming scheme typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_HW,NEO_INV,Method) selectedNeoSpeedType; #endif