Shared tx/rx pins on 433mhz module, working on esp8266 not on esp32

So i decided to update a old project i had with a rfm69 module and esp8266 to transmit and receive 433mhz to use a esp32 instead, rfm69 only have 1 pin for transmit and receive changing the module to tx mode and then changing the pin to output worked just fine on esp8266 but on esp32 the esphome transmitter code refuse to transmit as soon as i change the transmitter pin pinMode, minimal example code to show the problem.

Is there any way i can re-initiate the esphome transmitter or something?


button:
  - platform: template
    name:  nexa off
    on_press:
       - remote_transmitter.transmit_nexa:
           transmitter_id: rf
           device: 0x38DDB4A
           state: 10
           group: 0
           channel: 15
           level: 0
           repeat:
             times: 7
             wait_time: 10ms           


remote_transmitter:
  pin:
    number: 1 
    allow_other_uses: false  ## i have this as true on complete code....
  id: rf
  carrier_duty_percent: 100% 
  on_transmit:
    then:
      - lambda: |-
          pinMode(1, OUTPUT);  //transmitter working with these on esp8266 not on esp32

               
  on_complete:
    then:
      - lambda: |-
          pinMode(1, INPUT);   //transmitter working with these on esp8266 not on esp32               

Ok - for starters GPIO01 is not a good choice if you want both tx and rx on ESP32. Read this:

Other than that - sorry cannot assist.

ah forgot to change the pin in the code i uploaded i used pin 1 on esp8266 esp01, on esp32 i used other pin but its not working no matter what pin i use thanks anyway.

How does the ESP32 YAML look really?

i use pin 4 instead of 1, but i have tried a few other pins too, if i remove “pinMode(4, OUTPUT);” and “pinMode(4, INPUT);” i can transmit and when i add it back i cant again…

esphome:
  name: rfm433
  platformio_options:  
    board_build.f_flash: 40000000L
    board_build.flash_mode: dio
    board_build.flash_size: 4MB
    board_build.mcu: esp32c3

esp32:
  board: esp32-c3-devkitm-1
  framework:
    type: arduino


wifi:
  fast_connect: true 
  ssid: "xxxxxx"
  password: "xxxxxx"
  power_save_mode: HIGH
  output_power: 18 #8.5-20  15
  #use_address: esp_nrf_esp32.local


logger:



sensor:

- platform: uptime
  name: Uptime
- platform: internal_temperature
  name: "temp"



api:
  reboot_timeout: 0s

ota:
  platform: esphome


button:
  - platform: restart
    name: "reboot"

  - platform: template
    name:  nexa off
    on_press:
       - remote_transmitter.transmit_nexa:
           transmitter_id: rf
           device: 0x38DDB4A
           state: 10
           group: 0
           channel: 15
           level: 0
           repeat:
             times: 7
             wait_time: 10ms           


remote_transmitter:
  pin:
    number: 4 # 
    allow_other_uses: false  ## i have this as true on complete code....
  id: rf
  carrier_duty_percent: 100% 
  on_transmit:
    then:
      - lambda: |-
          pinMode(4, OUTPUT);  

               
  on_complete:
    then:
      - lambda: |-
          pinMode(4, INPUT);                

I don’t think you can do it without full control of the RMT peripheral.

yes you are right after a few tries i managed to make the remote transmitter only activate rmt when i transmit and disable it directly afterward and also take care of the input output change. if anyone else needs this these are the changes i made, copied remote transmitter folder and used it as a external component with these changes in remote_transmitter_esp32.cpp

for some reason the first time you transmit nothing happens but after that its working just fine…
anyway thanks for the tip on where to start.

#include "remote_transmitter.h"
#include "esphome/core/log.h"
#include "esphome/core/application.h"

#ifdef USE_ESP32
#include <driver/gpio.h>

namespace esphome {
namespace remote_transmitter {

static const char *const TAG = "remote_transmitter";

void RemoteTransmitterComponent::setup() {
  this->inverted_ = this->pin_->is_inverted();
  //this->configure_rmt_();   //------------------------------removed
}

void RemoteTransmitterComponent::dump_config() {
  ESP_LOGCONFIG(TAG, "Remote Transmitter:");
  ESP_LOGCONFIG(TAG,
                "  Clock resolution: %" PRIu32 " hz\n"
                "  RMT symbols: %" PRIu32,
                this->clock_resolution_, this->rmt_symbols_);
  LOG_PIN("  Pin: ", this->pin_);

  if (this->current_carrier_frequency_ != 0 && this->carrier_duty_percent_ != 100) {
    ESP_LOGCONFIG(TAG, "    Carrier Duty: %u%%", this->carrier_duty_percent_);
  }

  if (this->is_failed()) {
    ESP_LOGE(TAG, "Configuring RMT driver failed: %s (%s)", esp_err_to_name(this->error_code_),
             this->error_string_.c_str());
  }
}

void RemoteTransmitterComponent::digital_write(bool value) {
  rmt_symbol_word_t symbol = {
      .duration0 = 1,
      .level0 = value,
      .duration1 = 0,
      .level1 = value,
  };
  rmt_transmit_config_t config;
  memset(&config, 0, sizeof(config));
  config.loop_count = 0;
  config.flags.eot_level = value;
  esp_err_t error = rmt_transmit(this->channel_, this->encoder_, &symbol, sizeof(symbol), &config);
  if (error != ESP_OK) {
    ESP_LOGW(TAG, "rmt_transmit failed: %s", esp_err_to_name(error));
    this->status_set_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();
  }
}

void RemoteTransmitterComponent::configure_rmt_() {
  esp_err_t error;

gpio_set_direction(gpio_num_t(this->pin_->get_pin()), GPIO_MODE_OUTPUT); //-----------------------------added

  if (!this->initialized_) {
    bool open_drain = (this->pin_->get_flags() & gpio::FLAG_OPEN_DRAIN) != 0;
    rmt_tx_channel_config_t channel;
    memset(&channel, 0, sizeof(channel));
    channel.clk_src = RMT_CLK_SRC_DEFAULT;
    channel.resolution_hz = this->clock_resolution_;
    channel.gpio_num = gpio_num_t(this->pin_->get_pin());
    channel.mem_block_symbols = this->rmt_symbols_;
    channel.trans_queue_depth = 1;
    channel.flags.io_loop_back = open_drain;
    channel.flags.io_od_mode = open_drain;
    channel.flags.invert_out = 0;
    channel.flags.with_dma = this->with_dma_;
    channel.intr_priority = 0;
    error = rmt_new_tx_channel(&channel, &this->channel_);
    if (error != ESP_OK) {
      this->error_code_ = error;
      if (error == ESP_ERR_NOT_FOUND) {
        this->error_string_ = "out of RMT symbol memory";
      } else {
        this->error_string_ = "in rmt_new_tx_channel";
      }
      this->mark_failed();
      return;
    }
    if (this->pin_->get_flags() & gpio::FLAG_PULLUP) {
      gpio_pullup_en(gpio_num_t(this->pin_->get_pin()));
    } else {
      gpio_pullup_dis(gpio_num_t(this->pin_->get_pin()));
    }

    rmt_copy_encoder_config_t encoder;
    memset(&encoder, 0, sizeof(encoder));
    error = rmt_new_copy_encoder(&encoder, &this->encoder_);
    if (error != ESP_OK) {
      this->error_code_ = error;
      this->error_string_ = "in rmt_new_copy_encoder";
      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;
    }
    this->digital_write(open_drain || this->inverted_);
    this->initialized_ = true;
  }

  if (this->current_carrier_frequency_ == 0 || this->carrier_duty_percent_ == 100) {
    error = rmt_apply_carrier(this->channel_, nullptr);
  } else {
    rmt_carrier_config_t carrier;
    memset(&carrier, 0, sizeof(carrier));
    carrier.frequency_hz = this->current_carrier_frequency_;
    carrier.duty_cycle = (float) this->carrier_duty_percent_ / 100.0f;
    carrier.flags.polarity_active_low = this->inverted_;
    carrier.flags.always_on = 1;
    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;
  }
}

void RemoteTransmitterComponent::send_internal(uint32_t send_times, uint32_t send_wait) {
  
  
  configure_rmt_();  //---------------------------added
  
  if (this->is_failed())
    return;

  if (this->current_carrier_frequency_ != this->temp_.get_carrier_frequency()) {
    this->current_carrier_frequency_ = this->temp_.get_carrier_frequency();
    this->configure_rmt_();
  }

  this->rmt_temp_.clear();
  this->rmt_temp_.reserve((this->temp_.get_data().size() + 1) / 2);
  uint32_t rmt_i = 0;
  rmt_symbol_word_t rmt_item;

  for (int32_t val : this->temp_.get_data()) {
    bool level = val >= 0;
    if (!level)
      val = -val;
    val = this->from_microseconds_(static_cast<uint32_t>(val));

    do {
      int32_t item = std::min(val, int32_t(32767));
      val -= item;

      if (rmt_i % 2 == 0) {
        rmt_item.level0 = static_cast<uint32_t>(level ^ this->inverted_);
        rmt_item.duration0 = static_cast<uint32_t>(item);
      } else {
        rmt_item.level1 = static_cast<uint32_t>(level ^ this->inverted_);
        rmt_item.duration1 = static_cast<uint32_t>(item);
        this->rmt_temp_.push_back(rmt_item);
      }
      rmt_i++;
    } while (val != 0);
  }

  if (rmt_i % 2 == 1) {
    rmt_item.level1 = 0;
    rmt_item.duration1 = 0;
    this->rmt_temp_.push_back(rmt_item);
  }

  if ((this->rmt_temp_.data() == nullptr) || this->rmt_temp_.empty()) {
    ESP_LOGE(TAG, "Empty data");
    return;
  }
  this->transmit_trigger_->trigger();
  for (uint32_t i = 0; i < send_times; i++) {
    rmt_transmit_config_t config;
    memset(&config, 0, sizeof(config));
    config.loop_count = 0;
    config.flags.eot_level = this->eot_level_;
    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_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();
    }
    if (i + 1 < send_times)
      delayMicroseconds(send_wait);
  }
//------------------------------------------------added--------------------
    if (this->channel_ != NULL) {
        rmt_disable(this->channel_); // Disable the channel first
        rmt_del_channel(this->channel_); // Delete the channel
        this->channel_ = NULL; // Optional: clear the handle to prevent double deletion
    }
        gpio_set_direction(gpio_num_t(this->pin_->get_pin()), GPIO_MODE_INPUT);
        this->initialized_ = false;
//--------------------------------------------------------------------------------

  this->complete_trigger_->trigger();
}

}  // namespace remote_transmitter
}  // namespace esphome

#endif

1 Like