mirror of
https://github.com/esphome/esphome.git
synced 2026-10-15 02:32:49 +00:00
Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb5982a2f7 | ||
|
|
8052d7dd4e | ||
|
|
b9c2986f51 | ||
|
|
49e52dd896 | ||
|
|
fbdca59a85 | ||
|
|
09789d540c | ||
|
|
bdf0066d12 | ||
|
|
7e1a6f57c1 | ||
|
|
c137382793 |
@@ -1,4 +1,5 @@
|
||||
#include "led_strip.h"
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
|
||||
#ifdef USE_ESP32
|
||||
@@ -14,6 +15,8 @@ namespace esphome::esp32_rmt_led_strip {
|
||||
ESPHOME_LOG_TAG(TAG, "esp32_rmt_led_strip");
|
||||
|
||||
static const size_t RMT_SYMBOLS_PER_BYTE = 8;
|
||||
// Idle time the line must stay low between frames so the strip latches
|
||||
static const uint32_t RESET_GAP_US = 50;
|
||||
|
||||
// Query the RMT default clock source frequency. This varies by variant:
|
||||
// APB (80MHz) on ESP32/S2/S3/C3, PLL_F80M (80MHz) on C6/P4, XTAL (32MHz) on H2.
|
||||
@@ -91,10 +94,20 @@ void ESP32RMTLEDStripLightOutput::setup() {
|
||||
this->rmt_buf_ = rmt_allocator.allocate(buffer_size * 8 + 1);
|
||||
#endif
|
||||
|
||||
const uint32_t resolution_hz = rmt_resolution_hz();
|
||||
// Longest wire time of one frame; write_state() defers instead of blocking until it has elapsed
|
||||
uint32_t bit_ticks = std::max(this->params_.bit0.duration0 + this->params_.bit0.duration1,
|
||||
this->params_.bit1.duration0 + this->params_.bit1.duration1);
|
||||
uint64_t frame_ticks = (uint64_t) bit_ticks * buffer_size * RMT_SYMBOLS_PER_BYTE + this->params_.reset.duration0 +
|
||||
this->params_.reset.duration1;
|
||||
this->frame_time_us_ = frame_ticks * 1000000 / resolution_hz + RESET_GAP_US;
|
||||
// Seed with the interval write_state() gates on, so the first frame is not deferred
|
||||
this->last_refresh_ = micros() - std::max(this->frame_time_us_, this->max_refresh_rate_);
|
||||
|
||||
rmt_tx_channel_config_t channel;
|
||||
memset(&channel, 0, sizeof(channel));
|
||||
channel.clk_src = RMT_CLK_SRC_DEFAULT;
|
||||
channel.resolution_hz = rmt_resolution_hz();
|
||||
channel.resolution_hz = resolution_hz;
|
||||
channel.gpio_num = gpio_num_t(this->pin_);
|
||||
channel.mem_block_symbols = this->rmt_symbols_;
|
||||
channel.trans_queue_depth = 1;
|
||||
@@ -157,27 +170,16 @@ void ESP32RMTLEDStripLightOutput::set_led_params(uint32_t bit0_high, uint32_t bi
|
||||
}
|
||||
|
||||
void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||
// protect from refreshing too often
|
||||
uint32_t now = micros();
|
||||
auto rate = this->max_refresh_rate_.value_or(0);
|
||||
if (rate != 0 && (now - this->last_refresh_) < rate) {
|
||||
// try again next loop iteration, so that this change won't get lost
|
||||
// Previous frame still on the wire, inside its reset gap, or refreshing too often:
|
||||
// try again next loop iteration instead of blocking, so that this change won't get lost
|
||||
if (micros() - this->last_refresh_ < std::max(this->frame_time_us_, this->max_refresh_rate_)) {
|
||||
this->schedule_show();
|
||||
return;
|
||||
}
|
||||
this->last_refresh_ = now;
|
||||
this->mark_shown_();
|
||||
|
||||
ESP_LOGVV(TAG, "Writing RGB values to bus");
|
||||
|
||||
esp_err_t error = rmt_tx_wait_all_done(this->channel_, 1000);
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "RMT TX timeout");
|
||||
this->status_set_warning();
|
||||
return;
|
||||
}
|
||||
delayMicroseconds(50);
|
||||
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
memcpy(this->rmt_buf_, this->buf_, this->get_buffer_size_());
|
||||
#else
|
||||
@@ -208,15 +210,20 @@ void ESP32RMTLEDStripLightOutput::write_state(light::LightState *state) {
|
||||
rmt_transmit_config_t config;
|
||||
memset(&config, 0, sizeof(config));
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 3, 0)
|
||||
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config);
|
||||
esp_err_t error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, this->get_buffer_size_(), &config);
|
||||
#else
|
||||
error = rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config);
|
||||
esp_err_t error =
|
||||
rmt_transmit(this->channel_, this->encoder_, this->rmt_buf_, len * sizeof(rmt_symbol_word_t), &config);
|
||||
#endif
|
||||
if (error != ESP_OK) {
|
||||
ESP_LOGE(TAG, "RMT TX error");
|
||||
this->status_set_warning();
|
||||
// retry next loop iteration so the frame is not lost
|
||||
this->schedule_show();
|
||||
return;
|
||||
}
|
||||
// Stamped after the transfer started so the gate above stays conservative
|
||||
this->last_refresh_ = micros();
|
||||
this->status_clear_warning();
|
||||
}
|
||||
|
||||
@@ -242,7 +249,7 @@ void ESP32RMTLEDStripLightOutput::dump_config() {
|
||||
" Channel colors: %s\n"
|
||||
" Max refresh rate: %" PRIu32 "\n"
|
||||
" Number of LEDs: %u",
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_.value_or(0), this->num_leds_);
|
||||
this->channel_colors_.to_string(channel_colors), this->max_refresh_rate_, this->num_leds_);
|
||||
}
|
||||
|
||||
float ESP32RMTLEDStripLightOutput::get_setup_priority() const { return setup_priority::HARDWARE; }
|
||||
|
||||
@@ -86,7 +86,9 @@ class ESP32RMTLEDStripLightOutput final : public light::AddressableLight {
|
||||
light::ChannelColors channel_colors_{0, 1, 2, light::ChannelColors::NO_WHITE};
|
||||
|
||||
uint32_t last_refresh_{0};
|
||||
optional<uint32_t> max_refresh_rate_{};
|
||||
uint32_t max_refresh_rate_{0};
|
||||
// Worst-case wire time of one frame plus the reset gap, computed in setup()
|
||||
uint32_t frame_time_us_{0};
|
||||
};
|
||||
|
||||
} // namespace esphome::esp32_rmt_led_strip
|
||||
|
||||
Reference in New Issue
Block a user