diff --git a/esphome/components/remote_base/remote_base.cpp b/esphome/components/remote_base/remote_base.cpp index fdfd0b43cc..987286b345 100644 --- a/esphome/components/remote_base/remote_base.cpp +++ b/esphome/components/remote_base/remote_base.cpp @@ -8,27 +8,6 @@ namespace remote_base { static const char *const TAG = "remote_base"; -#ifdef USE_ESP32 -RemoteRMTChannel::RemoteRMTChannel(uint8_t mem_block_num) : mem_block_num_(mem_block_num) { - static rmt_channel_t next_rmt_channel = RMT_CHANNEL_0; - this->channel_ = next_rmt_channel; - next_rmt_channel = rmt_channel_t(int(next_rmt_channel) + mem_block_num); -} - -RemoteRMTChannel::RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num) - : channel_(channel), mem_block_num_(mem_block_num) {} - -void RemoteRMTChannel::config_rmt(rmt_config_t &rmt) { - if (rmt_channel_t(int(this->channel_) + this->mem_block_num_) > RMT_CHANNEL_MAX) { - this->mem_block_num_ = int(RMT_CHANNEL_MAX) - int(this->channel_); - ESP_LOGW(TAG, "Not enough RMT memory blocks available, reduced to %i blocks.", this->mem_block_num_); - } - rmt.channel = this->channel_; - rmt.clk_div = this->clock_divider_; - rmt.mem_block_num = this->mem_block_num_; -} -#endif - /* RemoteReceiveData */ bool RemoteReceiveData::peek_mark(uint32_t length, uint32_t offset) const { diff --git a/esphome/components/remote_base/remote_base.h b/esphome/components/remote_base/remote_base.h index c31127735a..8e4866a41f 100644 --- a/esphome/components/remote_base/remote_base.h +++ b/esphome/components/remote_base/remote_base.h @@ -8,10 +8,6 @@ #include "esphome/core/component.h" #include "esphome/core/hal.h" -#ifdef USE_ESP32 -#include -#endif - namespace esphome { namespace remote_base { @@ -112,10 +108,7 @@ class RemoteComponentBase { #ifdef USE_ESP32 class RemoteRMTChannel { public: - explicit RemoteRMTChannel(uint8_t mem_block_num = 1); - explicit RemoteRMTChannel(rmt_channel_t channel, uint8_t mem_block_num = 1); - - void config_rmt(rmt_config_t &rmt); + explicit RemoteRMTChannel(uint8_t mem_block_num = 1) : mem_block_num_(mem_block_num) {} void set_clock_divider(uint8_t clock_divider) { this->clock_divider_ = clock_divider; } protected: @@ -128,7 +121,6 @@ class RemoteRMTChannel { return (ticks * 10) / ticks_per_ten_us; } RemoteComponentBase *remote_base_; - rmt_channel_t channel_{RMT_CHANNEL_0}; uint8_t mem_block_num_; uint8_t clock_divider_{80}; }; diff --git a/esphome/components/remote_receiver/remote_receiver.h b/esphome/components/remote_receiver/remote_receiver.h index 773f8cf636..cafd67707a 100644 --- a/esphome/components/remote_receiver/remote_receiver.h +++ b/esphome/components/remote_receiver/remote_receiver.h @@ -5,11 +5,15 @@ #include +#ifdef USE_ESP32 +#include +#endif + namespace esphome { namespace remote_receiver { -#if defined(USE_ESP8266) || defined(USE_LIBRETINY) struct RemoteReceiverComponentStore { +#if defined(USE_ESP8266) || defined(USE_LIBRETINY) static void gpio_intr(RemoteReceiverComponentStore *arg); /// Stores the time (in micros) that the leading/falling edge happened at @@ -24,8 +28,14 @@ struct RemoteReceiverComponentStore { uint32_t buffer_size{1000}; uint32_t filter_us{10}; ISRInternalGPIOPin pin; -}; +#elif defined(USE_ESP32) + volatile bool error{false}; + volatile bool done{false}; + uint32_t *buffer{nullptr}; + rmt_rx_done_event_data_t data; + rmt_receive_config_t config; #endif +}; class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, public Component @@ -33,14 +43,12 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, , public remote_base::RemoteRMTChannel #endif + { public: #ifdef USE_ESP32 RemoteReceiverComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} - - RemoteReceiverComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) - : RemoteReceiverBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} #else RemoteReceiverComponent(InternalGPIOPin *pin) : RemoteReceiverBase(pin) {} #endif @@ -55,16 +63,14 @@ class RemoteReceiverComponent : public remote_base::RemoteReceiverBase, protected: #ifdef USE_ESP32 - void decode_rmt_(rmt_item32_t *item, size_t len); - RingbufHandle_t ringbuf_; + void decode_rmt_(rmt_symbol_word_t *item, size_t item_count); + rmt_channel_handle_t channel_{NULL}; esp_err_t error_code_{ESP_OK}; std::string error_string_{""}; #endif -#if defined(USE_ESP8266) || defined(USE_LIBRETINY) RemoteReceiverComponentStore store_; HighFrequencyLoopRequester high_freq_; -#endif uint32_t buffer_size_{}; uint32_t filter_us_{10}; diff --git a/esphome/components/remote_receiver/remote_receiver_esp32.cpp b/esphome/components/remote_receiver/remote_receiver_esp32.cpp index 91295871e2..4147725318 100644 --- a/esphome/components/remote_receiver/remote_receiver_esp32.cpp +++ b/esphome/components/remote_receiver/remote_receiver_esp32.cpp @@ -2,64 +2,71 @@ #include "esphome/core/log.h" #ifdef USE_ESP32 -#include namespace esphome { namespace remote_receiver { static const char *const TAG = "remote_receiver.esp32"; +static bool IRAM_ATTR HOT rmt_callback(rmt_channel_handle_t channel, const rmt_rx_done_event_data_t *data, + void *user_data) { + RemoteReceiverComponentStore *store = (RemoteReceiverComponentStore *) user_data; + store->data = *data; + store->done = true; + return false; +} + void RemoteReceiverComponent::setup() { ESP_LOGCONFIG(TAG, "Setting up Remote Receiver..."); this->pin_->setup(); - rmt_config_t rmt{}; - this->config_rmt(rmt); - rmt.gpio_num = gpio_num_t(this->pin_->get_pin()); - rmt.rmt_mode = RMT_MODE_RX; if (this->filter_us_ == 0) { - rmt.rx_config.filter_en = false; + this->store_.config.signal_range_min_ns = 0; } else { - rmt.rx_config.filter_en = true; - rmt.rx_config.filter_ticks_thresh = static_cast( - std::min(this->from_microseconds_(this->filter_us_) * this->clock_divider_, (uint32_t) 255)); + this->store_.config.signal_range_min_ns = 500; // std::min(this->filter_us_, (uint32_t) 255) * 1000; } - rmt.rx_config.idle_threshold = - static_cast(std::min(this->from_microseconds_(this->idle_us_), (uint32_t) 65535)); + this->store_.config.signal_range_max_ns = std::min(this->idle_us_, (uint32_t) 65535) * 1000; - esp_err_t error = rmt_config(&rmt); + rmt_rx_channel_config_t rmt{}; + rmt.clk_src = RMT_CLK_SRC_DEFAULT; + rmt.resolution_hz = 1 * 1000 * 1000; + rmt.mem_block_symbols = 64 * this->mem_block_num_; + rmt.gpio_num = gpio_num_t(this->pin_->get_pin()); + esp_err_t error = rmt_new_rx_channel(&rmt, &this->channel_); if (error != ESP_OK) { this->error_code_ = error; - this->error_string_ = "in rmt_config"; + this->error_string_ = "in rmt_new_rx_channel"; + this->mark_failed(); + return; + } + error = rmt_enable(this->channel_); + if (error != ESP_OK) { + this->error_code_ = error; + this->error_string_ = "in rmt_enable"; this->mark_failed(); return; } - error = rmt_driver_install(this->channel_, this->buffer_size_, 0); + rmt_rx_event_callbacks_t callbacks{}; + callbacks.on_recv_done = rmt_callback; + error = rmt_rx_register_event_callbacks(this->channel_, &callbacks, &this->store_); if (error != ESP_OK) { this->error_code_ = error; - if (error == ESP_ERR_INVALID_STATE) { - this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); - } else { - this->error_string_ = "in rmt_driver_install"; - } + this->error_string_ = "in rmt_rx_register_event_callbacks"; this->mark_failed(); return; } - error = rmt_get_ringbuf_handle(this->channel_, &this->ringbuf_); + + this->store_.buffer = new uint32_t[this->buffer_size_ / 4]; + error = rmt_receive(this->channel_, this->store_.buffer, 64 * this->mem_block_num_ * sizeof(rmt_symbol_word_t), + &this->store_.config); if (error != ESP_OK) { this->error_code_ = error; - this->error_string_ = "in rmt_get_ringbuf_handle"; - this->mark_failed(); - return; - } - error = rmt_rx_start(this->channel_, true); - if (error != ESP_OK) { - this->error_code_ = error; - this->error_string_ = "in rmt_rx_start"; + this->error_string_ = "in rmt_receive"; this->mark_failed(); return; } } + void RemoteReceiverComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Receiver:"); LOG_PIN(" Pin: ", this->pin_); @@ -67,7 +74,6 @@ void RemoteReceiverComponent::dump_config() { ESP_LOGW(TAG, "Remote Receiver Signal starts with a HIGH value. Usually this means you have to " "invert the signal using 'inverted: True' in the pin schema!"); } - ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); ESP_LOGCONFIG(TAG, " Tolerance: %" PRIu32 "%s", this->tolerance_, @@ -81,25 +87,22 @@ void RemoteReceiverComponent::dump_config() { } void RemoteReceiverComponent::loop() { - size_t len = 0; - auto *item = (rmt_item32_t *) xRingbufferReceive(this->ringbuf_, &len, 0); - if (item != nullptr) { - this->decode_rmt_(item, len); - vRingbufferReturnItem(this->ringbuf_, item); - - if (this->temp_.empty()) - return; - - this->temp_.push_back(-this->idle_us_); - this->call_listeners_dumpers_(); + if (this->store_.done) { + this->decode_rmt_((rmt_symbol_word_t *) this->store_.buffer, this->store_.data.num_symbols); + this->store_.done = false; + rmt_receive(this->channel_, this->store_.buffer, sizeof(rmt_symbol_word_t) * 64 * 4, &this->store_.config); + if (!this->temp_.empty()) { + this->temp_.push_back(-this->idle_us_); + this->call_listeners_dumpers_(); + } } } -void RemoteReceiverComponent::decode_rmt_(rmt_item32_t *item, size_t len) { + +void RemoteReceiverComponent::decode_rmt_(rmt_symbol_word_t *item, size_t item_count) { bool prev_level = false; uint32_t prev_length = 0; this->temp_.clear(); int32_t multiplier = this->pin_->is_inverted() ? -1 : 1; - size_t item_count = len / sizeof(rmt_item32_t); uint32_t filter_ticks = this->from_microseconds_(this->filter_us_); ESP_LOGVV(TAG, "START:"); diff --git a/esphome/components/remote_transmitter/remote_transmitter.h b/esphome/components/remote_transmitter/remote_transmitter.h index 4abe687d23..76b758b0ec 100644 --- a/esphome/components/remote_transmitter/remote_transmitter.h +++ b/esphome/components/remote_transmitter/remote_transmitter.h @@ -5,6 +5,10 @@ #include +#ifdef USE_ESP32 +#include +#endif + namespace esphome { namespace remote_transmitter { @@ -19,9 +23,6 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, #ifdef USE_ESP32 RemoteTransmitterComponent(InternalGPIOPin *pin, uint8_t mem_block_num = 1) : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(mem_block_num) {} - - RemoteTransmitterComponent(InternalGPIOPin *pin, rmt_channel_t channel, uint8_t mem_block_num = 1) - : remote_base::RemoteTransmitterBase(pin), remote_base::RemoteRMTChannel(channel, mem_block_num) {} #else explicit RemoteTransmitterComponent(InternalGPIOPin *pin) : remote_base::RemoteTransmitterBase(pin) {} #endif @@ -54,7 +55,9 @@ class RemoteTransmitterComponent : public remote_base::RemoteTransmitterBase, uint32_t current_carrier_frequency_{38000}; bool initialized_{false}; - std::vector rmt_temp_; + rmt_channel_handle_t channel_{NULL}; + rmt_encoder_handle_t encoder_{NULL}; + std::vector rmt_temp_; esp_err_t error_code_{ESP_OK}; std::string error_string_{""}; bool inverted_{false}; diff --git a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp index bce2408723..eda2d039b3 100644 --- a/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp +++ b/esphome/components/remote_transmitter/remote_transmitter_esp32.cpp @@ -13,7 +13,6 @@ void RemoteTransmitterComponent::setup() { this->configure_rmt_(); } void RemoteTransmitterComponent::dump_config() { ESP_LOGCONFIG(TAG, "Remote Transmitter..."); - ESP_LOGCONFIG(TAG, " Channel: %d", this->channel_); ESP_LOGCONFIG(TAG, " RMT memory blocks: %d", this->mem_block_num_); ESP_LOGCONFIG(TAG, " Clock divider: %u", this->clock_divider_); LOG_PIN(" Pin: ", this->pin_); @@ -29,53 +28,50 @@ void RemoteTransmitterComponent::dump_config() { } void RemoteTransmitterComponent::configure_rmt_() { - rmt_config_t c{}; + rmt_tx_channel_config_t config{}; + config.clk_src = RMT_CLK_SRC_DEFAULT; + config.resolution_hz = 1 * 1000 * 1000, // 1 MHz resolution + config.gpio_num = gpio_num_t(this->pin_->get_pin()); + config.mem_block_symbols = 64 * this->mem_block_num_; + config.trans_queue_depth = 1; - this->config_rmt(c); - c.rmt_mode = RMT_MODE_TX; - c.gpio_num = gpio_num_t(this->pin_->get_pin()); - c.tx_config.loop_en = false; - - if (this->current_carrier_frequency_ == 0 || this->carrier_duty_percent_ == 100) { - c.tx_config.carrier_en = false; - } else { - c.tx_config.carrier_en = true; - c.tx_config.carrier_freq_hz = this->current_carrier_frequency_; - c.tx_config.carrier_duty_percent = this->carrier_duty_percent_; - } - - c.tx_config.idle_output_en = true; - if (!this->pin_->is_inverted()) { - c.tx_config.carrier_level = RMT_CARRIER_LEVEL_HIGH; - c.tx_config.idle_level = RMT_IDLE_LEVEL_LOW; - } else { - c.tx_config.carrier_level = RMT_CARRIER_LEVEL_LOW; - c.tx_config.idle_level = RMT_IDLE_LEVEL_HIGH; - this->inverted_ = true; - } - - esp_err_t error = rmt_config(&c); + esp_err_t error = rmt_new_tx_channel(&config, &this->channel_); if (error != ESP_OK) { this->error_code_ = error; - this->error_string_ = "in rmt_config"; + this->error_string_ = "in rmt_new_tx_channel"; this->mark_failed(); return; } - if (!this->initialized_) { - error = rmt_driver_install(this->channel_, 0, 0); - if (error != ESP_OK) { - this->error_code_ = error; - if (error == ESP_ERR_INVALID_STATE) { - this->error_string_ = str_sprintf("RMT channel %i is already in use by another component", this->channel_); - } else { - this->error_string_ = "in rmt_driver_install"; - } - this->mark_failed(); - return; - } - this->initialized_ = true; + rmt_copy_encoder_config_t asdf; + error = rmt_new_copy_encoder(&asdf, &this->encoder_); + if (error != ESP_OK) { + this->error_code_ = error; + this->error_string_ = "in rmt_new_copy_encoder"; + this->mark_failed(); + return; } + + rmt_carrier_config_t carrier{}; + carrier.frequency_hz = 0; + carrier.duty_cycle = 100.0; + error = rmt_apply_carrier(this->channel_, &carrier); + if (error != ESP_OK) { + this->error_code_ = error; + this->error_string_ = "in rmt_apply_carrier"; + this->mark_failed(); + return; + } + + error = rmt_enable(this->channel_); + if (error != ESP_OK) { + this->error_code_ = error; + this->error_string_ = "in rmt_enable"; + this->mark_failed(); + return; + } + + // TODO: Carrier } void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) { @@ -90,7 +86,7 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen this->rmt_temp_.clear(); this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2); uint32_t rmt_i = 0; - rmt_item32_t rmt_item; + rmt_symbol_word_t rmt_item; for (int32_t val : this->temp_.get_data()) { bool level = val >= 0; @@ -126,9 +122,18 @@ void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t sen } this->transmit_trigger_->trigger(); for (uint32_t i = 0; i < send_times; i++) { - esp_err_t error = rmt_write_items(this->channel_, this->rmt_temp_.data(), this->rmt_temp_.size(), true); + rmt_transmit_config_t config{}; + esp_err_t error = rmt_transmit(this->channel_, this->encoder_, this->rmt_temp_.data(), + this->rmt_temp_.size() * sizeof(rmt_symbol_word_t), &config); if (error != ESP_OK) { - ESP_LOGW(TAG, "rmt_write_items failed: %s", esp_err_to_name(error)); + ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error)); + this->status_set_warning(); + } else { + this->status_clear_warning(); + } + error = rmt_tx_wait_all_done(this->channel_, -1); + if (error != ESP_OK) { + ESP_LOGW(TAG, "rmt_tx_wait_all_done failed: %s", esp_err_to_name(error)); this->status_set_warning(); } else { this->status_clear_warning();