mirror of
https://github.com/esphome/esphome.git
synced 2024-11-30 10:44:13 +01:00
Initial port of remote base/tx/rx to new RMT drivers
This commit is contained in:
parent
b61577b68b
commit
0ff29636e4
6 changed files with 116 additions and 128 deletions
|
@ -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 {
|
||||
|
|
|
@ -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};
|
||||
};
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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;
|
||||
|
||||
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:");
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -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);
|
||||
rmt_copy_encoder_config_t asdf;
|
||||
error = rmt_new_copy_encoder(&asdf, &this->encoder_);
|
||||
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_new_copy_encoder";
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
this->initialized_ = true;
|
||||
|
||||
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();
|
||||
|
|
Loading…
Reference in a new issue