mirror of
https://github.com/arendst/Tasmota.git
synced 2025-07-19 08:46:32 +00:00
Neopixel add SPI driver for C2 and some minor updates (#19372)
This commit is contained in:
parent
8861e779e3
commit
65a1a4feeb
@ -105,7 +105,11 @@ License along with NeoPixel. If not, see
|
|||||||
#include "internal/NeoEsp32I2sMethod.h"
|
#include "internal/NeoEsp32I2sMethod.h"
|
||||||
#include "internal/NeoEsp32RmtMethod.h"
|
#include "internal/NeoEsp32RmtMethod.h"
|
||||||
#else
|
#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
|
#endif // ESP_IDF_VERSION_MAJOR
|
||||||
#include "internal/NeoEspBitBangMethod.h"
|
#include "internal/NeoEspBitBangMethod.h"
|
||||||
#include "internal/DotStarEsp32DmaSpiMethod.h"
|
#include "internal/DotStarEsp32DmaSpiMethod.h"
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
// ESP32C3/S3 I2S is not supported yet due to significant changes to interface
|
// 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
|
#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 <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
#ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1
|
#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
|
// 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
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -32,7 +32,7 @@ License along with NeoPixel. If not, see
|
|||||||
#include "NeoBusChannel.h"
|
#include "NeoBusChannel.h"
|
||||||
#include "NeoEsp32RmtMethod.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
|
// translate NeoPixelBuffer into RMT buffer
|
||||||
|
@ -29,7 +29,7 @@ License along with NeoPixel. If not, see
|
|||||||
|
|
||||||
#pragma once
|
#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
|
/* General Reference documentation for the APIs used in this implementation
|
||||||
LOW LEVEL: (what is actually used)
|
LOW LEVEL: (what is actually used)
|
||||||
|
@ -45,7 +45,7 @@ Esp32-hal-rmt.c
|
|||||||
|
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
|
|
||||||
// extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
|
||||||
|
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
@ -55,7 +55,7 @@ extern "C"
|
|||||||
#include "esp_check.h"
|
#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 {
|
typedef struct {
|
||||||
uint32_t resolution; /*!< Encoder resolution, in Hz */
|
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;
|
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;
|
esp_err_t ret = ESP_OK;
|
||||||
rmt_led_strip_encoder_t *led_encoder = NULL;
|
rmt_led_strip_encoder_t *led_encoder = NULL;
|
||||||
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
|
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.encode = rmt_encode_led_strip;
|
||||||
led_encoder->base.del = rmt_del_led_strip_encoder;
|
led_encoder->base.del = rmt_del_led_strip_encoder;
|
||||||
led_encoder->base.reset = rmt_led_strip_encoder_reset;
|
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.val = bit0;
|
||||||
bytes_encoder_config.bit0.duration0 = 0.3 * config->resolution / 1000000; // T0H=0.3us
|
bytes_encoder_config.bit1.val = bit1;
|
||||||
bytes_encoder_config.bit0.level1 = 0;
|
|
||||||
bytes_encoder_config.bit0.duration1 = 0.9 * config->resolution / 1000000; // T0L=0.9us
|
bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks
|
||||||
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
|
|
||||||
|
|
||||||
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_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");
|
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
|
class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase
|
||||||
{
|
{
|
||||||
public:
|
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 uint32_t RmtBit1 = Item32Val(900, 350);
|
||||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||||
};
|
};
|
||||||
@ -234,8 +229,8 @@ public:
|
|||||||
class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase
|
class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
const uint32_t RmtBit0 = Item32Val(400, 850);
|
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
|
||||||
const uint32_t RmtBit1 = Item32Val(800, 450);
|
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
|
||||||
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -530,11 +525,11 @@ public:
|
|||||||
|
|
||||||
_tx_config.loop_count = 0; //no loop
|
_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");
|
// ESP_LOGI(TAG, "Enable RMT TX channel");
|
||||||
ret += rmt_enable(_channel.RmtChannelNumber);
|
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)
|
void Update(bool maintainBufferConsistency)
|
||||||
@ -548,9 +543,7 @@ public:
|
|||||||
{
|
{
|
||||||
// AddLog(2,"__ %u", _sizeData);
|
// AddLog(2,"__ %u", _sizeData);
|
||||||
// now start the RMT transmit with the editing buffer before we swap
|
// 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, _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);
|
// AddLog(2,"rmt_transmit: %u", ret);
|
||||||
if (maintainBufferConsistency)
|
if (maintainBufferConsistency)
|
||||||
{
|
{
|
||||||
|
504
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h
Normal file
504
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h
Normal file
@ -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
|
||||||
|
<http://www.gnu.org/licenses/>.
|
||||||
|
-------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
#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 <Arduino.h>
|
||||||
|
|
||||||
|
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); // TODO: Remove all Addlogs
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
#include <rom/gpio.h>
|
||||||
|
#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<typename T_SPEED, typename T_CHANNEL> 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<uint8_t*>(malloc(_sizeData));
|
||||||
|
// data cleared later in Begin()
|
||||||
|
|
||||||
|
_dataSending = static_cast<uint8_t*>(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<NeoEsp32SpiSpeedWs2812x, NeoEsp32SpiChannel> NeoEsp32SpiN800KbpsMethod;
|
||||||
|
typedef NeoEsp32SpiMethodBase<NeoEsp32SpiSpeedSk6812, NeoEsp32SpiChannel> 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
|
@ -119,14 +119,12 @@ build_unflags = ${env:arduino30.build_unflags}
|
|||||||
-mtarget-align
|
-mtarget-align
|
||||||
build_flags = ${env:arduino30.build_flags}
|
build_flags = ${env:arduino30.build_flags}
|
||||||
-DFIRMWARE_ARDUINO30
|
-DFIRMWARE_ARDUINO30
|
||||||
-DNO_NEOPIXEL
|
|
||||||
-DUSE_MI_HOMEKIT=0 ; 1 to enable; 0 to disable
|
-DUSE_MI_HOMEKIT=0 ; 1 to enable; 0 to disable
|
||||||
-DUSE_MI_ESP32
|
-DUSE_MI_ESP32
|
||||||
-fno-lto
|
-fno-lto
|
||||||
-DOTA_URL='""'
|
-DOTA_URL='""'
|
||||||
monitor_filters = esp32_exception_decoder
|
monitor_filters = esp32_exception_decoder
|
||||||
lib_ignore = ${env:arduino30.lib_ignore}
|
lib_ignore = ${env:arduino30.lib_ignore}
|
||||||
NeoPixelBus
|
|
||||||
|
|
||||||
[env:tasmota32c3-arduino30]
|
[env:tasmota32c3-arduino30]
|
||||||
extends = env:arduino30
|
extends = env:arduino30
|
||||||
|
@ -238,8 +238,8 @@
|
|||||||
#undef USE_SONOFF_D1 // Disable support for Sonoff D1 Dimmer (+0k7 code)
|
#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_SHELLY_DIMMER // Disable support for Shelly Dimmer (+3k code)
|
||||||
|
|
||||||
#undef USE_LIGHT // Disable support for lights
|
// #undef USE_LIGHT // Disable support for lights
|
||||||
#undef USE_WS2812
|
// #undef USE_WS2812
|
||||||
|
|
||||||
#undef USE_DS18x20 // Disable DS18x20 sensor
|
#undef USE_DS18x20 // Disable DS18x20 sensor
|
||||||
|
|
||||||
|
@ -33,8 +33,13 @@ enum {
|
|||||||
neopixel_type_end
|
neopixel_type_end
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef CONFIG_IDF_TARGET_ESP32C2
|
||||||
|
typedef NeoPixelBus<NeoGrbFeature, NeoEsp32SpiN800KbpsMethod> neopixel_ws2812_grb_t;
|
||||||
|
typedef NeoPixelBus<NeoGrbwFeature, NeoEsp32SpiNSk6812Method> neopixel_sk6812_grbw_t;
|
||||||
|
#else
|
||||||
typedef NeoPixelBus<NeoGrbFeature, NeoEsp32RmtN800KbpsMethod> neopixel_ws2812_grb_t;
|
typedef NeoPixelBus<NeoGrbFeature, NeoEsp32RmtN800KbpsMethod> neopixel_ws2812_grb_t;
|
||||||
typedef NeoPixelBus<NeoGrbwFeature, NeoEsp32RmtNSk6812Method> neopixel_sk6812_grbw_t;
|
typedef NeoPixelBus<NeoGrbwFeature, NeoEsp32RmtNSk6812Method> neopixel_sk6812_grbw_t;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#ifdef USE_LIGHT
|
#ifdef USE_LIGHT
|
||||||
#ifdef USE_WS2812
|
#ifdef USE_WS2812
|
||||||
|
|
||||||
/*********************************************************************************************\
|
/*********************************************************************************************\
|
||||||
* WS2812 RGB / RGBW Leds using NeopixelBus library
|
* 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)
|
#if defined(ESP8266) && defined(USE_WS2812_DMA)
|
||||||
typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_INV,NEO_HW,Method) selectedNeoSpeedType;
|
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
|
#else // Dma : different naming scheme
|
||||||
typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_HW,NEO_INV,Method) selectedNeoSpeedType;
|
typedef CONCAT6(NEO_NEO,NEO_CHIP,NEO_PROTO,NEO_HW,NEO_INV,Method) selectedNeoSpeedType;
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
x
Reference in New Issue
Block a user