Initial port of remote base/tx/rx to new RMT drivers

This commit is contained in:
Jonathan Swoboda 2024-11-11 14:25:52 -05:00
parent b61577b68b
commit 0ff29636e4
6 changed files with 116 additions and 128 deletions

View file

@ -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 {

View file

@ -8,10 +8,6 @@
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#ifdef USE_ESP32
#include <driver/rmt.h>
#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};
};

View file

@ -5,11 +5,15 @@
#include <cinttypes>
#ifdef USE_ESP32
#include <driver/rmt_rx.h>
#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};

View file

@ -2,64 +2,71 @@
#include "esphome/core/log.h"
#ifdef USE_ESP32
#include <driver/rmt.h>
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<uint8_t>(
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<uint16_t>(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:");

View file

@ -5,6 +5,10 @@
#include <vector>
#ifdef USE_ESP32
#include <driver/rmt_tx.h>
#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_item32_t> rmt_temp_;
rmt_channel_handle_t channel_{NULL};
rmt_encoder_handle_t encoder_{NULL};
std::vector<rmt_symbol_word_t> rmt_temp_;
esp_err_t error_code_{ESP_OK};
std::string error_string_{""};
bool inverted_{false};

View file

@ -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();