3#if defined(USE_ESP32) && SOC_I2S_SUPPORTS_TDM
10#include <driver/i2s_tdm.h>
50 : color_data_bytes_(num_leds * channel_colors.bytes_per_led()),
51 channel_colors_(channel_colors),
57 "I2S Clockless LED Strip:\n"
60 char channel_colors[5];
62 " Channel colors: %s\n"
63 " Number of LEDs: %" PRIu16
"\n"
64 " DMA buffer: %" PRIuPTR
" samples (%" PRIu32
" us)",
77 i2s_chan_config_t chan_config = {
79 .role = I2S_ROLE_MASTER,
82 .auto_clear_after_cb =
false,
83 .auto_clear_before_cb =
false,
87 esp_err_t err = i2s_new_channel(&chan_config, &this->
tx_handle_, NULL);
89 ESP_LOGE(TAG,
"Error in i2s_new_channel: %s", esp_err_to_name(err));
91 i2s_tdm_config_t tdm_config = {
95 .clk_src = I2S_CLK_SRC_DEFAULT,
96 .mclk_multiple = I2S_MCLK_MULTIPLE_384,
100 .data_bit_width = I2S_DATA_BIT_WIDTH_24BIT,
101 .slot_bit_width = I2S_SLOT_BIT_WIDTH_AUTO,
102 .slot_mode = I2S_SLOT_MODE_MONO,
103 .slot_mask = I2S_TDM_SLOT0,
106 .total_slot = I2S_TDM_AUTO_SLOT_NUM,
110 .mclk = I2S_GPIO_UNUSED,
111 .bclk = I2S_GPIO_UNUSED,
112 .ws = I2S_GPIO_UNUSED,
113 .dout = gpio_num_t(this->
pin_),
114 .din = I2S_GPIO_UNUSED,
123 err = i2s_channel_init_tdm_mode(this->
tx_handle_, &tdm_config);
125 ESP_LOGE(TAG,
"Error in i2s_channel_init_tdm_mode: %s", esp_err_to_name(err));
127 i2s_event_callbacks_t event_callbacks = {
130 err = i2s_channel_register_event_callback(this->
tx_handle_, &event_callbacks,
this);
132 ESP_LOGE(TAG,
"Error in i2s_channel_register_event_callback: %s", esp_err_to_name(err));
137 ESP_LOGE(TAG,
"Error in i2s_channel_enable: %s", esp_err_to_name(err));
156 memset(this->
i2s_data_, 0, i2s_data_bytes);
193 for (
size_t i = 0; i < color_data_bytes; i++) {
194 const uint8_t color_byte = *(color_data++);
195 *(i2s_data++) = 0b10010010 | ((color_byte & 0x80) >> 1) | ((color_byte & 0x40) >> 3) | ((color_byte & 0x20) >> 5);
196 *(i2s_data++) = 0b01001001 | ((color_byte & 0x10) << 1) | ((color_byte & 0x08) >> 1);
197 *(i2s_data++) = 0b00100100 | ((color_byte & 0x04) << 5) | ((color_byte & 0x02) << 3) | ((color_byte & 0x01) << 1);
209 auto *
const dma_buf =
static_cast<uint8_t *
>(
event->dma_buf);
210 const size_t dma_buf_size =
event->
size;
212 bool dma_buf_filled =
false;
213 if (self->i2s_data_ready_.load(std::memory_order_acquire)) {
215 if (self->i2s_data_sent_ < i2s_data_bytes) {
216 const size_t i2s_data_remaining = i2s_data_bytes - self->i2s_data_sent_;
217 if (i2s_data_remaining >= dma_buf_size) {
218 memcpy(dma_buf, self->i2s_data_ + self->i2s_data_sent_, dma_buf_size);
220 memcpy(dma_buf, self->i2s_data_ + self->i2s_data_sent_, i2s_data_remaining);
221 memset(dma_buf + i2s_data_remaining, 0, dma_buf_size - i2s_data_remaining);
223 dma_buf_filled =
true;
225 self->i2s_data_sent_ += dma_buf_size;
227 self->i2s_data_ready_.store(
false, std::memory_order_release);
233 if (!dma_buf_filled && dma_buf[0] != 0) {
234 memset(dma_buf, 0, dma_buf_size);
244 return {led + colors.
r,
247 colors.
has_white() ? led + colors.
w :
nullptr,
void mark_failed()
Mark this component as failed.
An STL allocator that uses SPI or internal RAM.
void deallocate(T *p, size_t n)
std::atomic< bool > i2s_data_ready_
void clear_effect_data() override
int32_t size() const override
void dump_config() override
const light::ChannelColors channel_colors_
i2s_chan_handle_t tx_handle_
void write_state(light::LightState *state) override
const size_t color_data_bytes_
light::ESPColorView get_view_internal(int32_t index) const override
float get_setup_priority() const override
light::LightTraits get_traits() override
I2SClocklessLedStrip(uint8_t pin, uint16_t num_leds, light::ChannelColors channel_colors)
static bool i2s_on_sent_callback(i2s_chan_handle_t handle, i2s_event_data_t *event, void *user_ctx)
ESPColorCorrection correction_
This class represents the communication layer between the front-end MQTT layer and the hardware outpu...
This class is used to represent the capabilities of a light.
ESPHOME_LOG_TAG(TAG, "i2s_clockless_led_strip")
constexpr size_t I2S_RESET_SAMPLES
constexpr uint32_t I2S_BUFFER_DURATION_US_ACTUAL
constexpr uint32_t num_i2s_samples_to_duration_us(size_t samples)
constexpr uint32_t I2S_SAMPLE_RATE_HZ
constexpr size_t I2S_BYTES_PER_SAMPLE
constexpr uint32_t I2S_BUFFER_DURATION_US_IDEAL
constexpr size_t I2S_RESET_BYTES
constexpr const char *const ERROR_I2S
constexpr size_t num_i2s_samples_from_duration_us(uint32_t duration_us)
constexpr uint32_t I2S_RESET_DURATION_US
constexpr const char *const ERROR_ALLOCATION
constexpr size_t I2S_BUFFER_SAMPLES
@ RGB_WHITE
RGB color output and a separate white output.
@ WHITE
White output only (use only if the light also has another color mode such as RGB).
constexpr float IO
For components that represent GPIO pins like PCF8573.
Which byte of an addressable LED's data carries each colour.
const char * to_string(char *buf) const
Write the order back out as text, e.g.
uint8_t bytes_per_led() const
spi_device_handle_t handle