1
0
mirror of https://github.com/esphome/esphome.git synced 2025-10-26 04:33:47 +00:00

[esp32] Use arduino as an idf component (#10647)

Co-authored-by: J. Nick Koston <nick@home-assistant.io>
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Jonathan Swoboda
2025-09-17 18:23:34 -04:00
committed by GitHub
parent ff2df278d6
commit b8cee477fe
26 changed files with 328 additions and 759 deletions

View File

@@ -16,7 +16,6 @@ from esphome.const import (
CONF_DUMMY_RECEIVER_ID,
CONF_ID,
CONF_INVERT,
CONF_INVERTED,
CONF_LAMBDA,
CONF_NUMBER,
CONF_PORT,
@@ -39,9 +38,6 @@ uart_ns = cg.esphome_ns.namespace("uart")
UARTComponent = uart_ns.class_("UARTComponent")
IDFUARTComponent = uart_ns.class_("IDFUARTComponent", UARTComponent, cg.Component)
ESP32ArduinoUARTComponent = uart_ns.class_(
"ESP32ArduinoUARTComponent", UARTComponent, cg.Component
)
ESP8266UartComponent = uart_ns.class_(
"ESP8266UartComponent", UARTComponent, cg.Component
)
@@ -53,7 +49,6 @@ HostUartComponent = uart_ns.class_("HostUartComponent", UARTComponent, cg.Compon
NATIVE_UART_CLASSES = (
str(IDFUARTComponent),
str(ESP32ArduinoUARTComponent),
str(ESP8266UartComponent),
str(RP2040UartComponent),
str(LibreTinyUARTComponent),
@@ -119,20 +114,6 @@ def validate_rx_pin(value):
return value
def validate_invert_esp32(config):
if (
CORE.is_esp32
and CORE.using_arduino
and CONF_TX_PIN in config
and CONF_RX_PIN in config
and config[CONF_TX_PIN][CONF_INVERTED] != config[CONF_RX_PIN][CONF_INVERTED]
):
raise cv.Invalid(
"Different invert values for TX and RX pin are not supported for ESP32 when using Arduino."
)
return config
def validate_host_config(config):
if CORE.is_host:
if CONF_TX_PIN in config or CONF_RX_PIN in config:
@@ -151,10 +132,7 @@ def _uart_declare_type(value):
if CORE.is_esp8266:
return cv.declare_id(ESP8266UartComponent)(value)
if CORE.is_esp32:
if CORE.using_arduino:
return cv.declare_id(ESP32ArduinoUARTComponent)(value)
if CORE.using_esp_idf:
return cv.declare_id(IDFUARTComponent)(value)
return cv.declare_id(IDFUARTComponent)(value)
if CORE.is_rp2040:
return cv.declare_id(RP2040UartComponent)(value)
if CORE.is_libretiny:
@@ -255,7 +233,6 @@ CONFIG_SCHEMA = cv.All(
}
).extend(cv.COMPONENT_SCHEMA),
cv.has_at_least_one_key(CONF_TX_PIN, CONF_RX_PIN, CONF_PORT),
validate_invert_esp32,
validate_host_config,
)
@@ -444,8 +421,10 @@ async def uart_write_to_code(config, action_id, template_arg, args):
FILTER_SOURCE_FILES = filter_source_files_from_platform(
{
"uart_component_esp32_arduino.cpp": {PlatformFramework.ESP32_ARDUINO},
"uart_component_esp_idf.cpp": {PlatformFramework.ESP32_IDF},
"uart_component_esp_idf.cpp": {
PlatformFramework.ESP32_IDF,
PlatformFramework.ESP32_ARDUINO,
},
"uart_component_esp8266.cpp": {PlatformFramework.ESP8266_ARDUINO},
"uart_component_host.cpp": {PlatformFramework.HOST_NATIVE},
"uart_component_rp2040.cpp": {PlatformFramework.RP2040_ARDUINO},

View File

@@ -1,214 +0,0 @@
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include "uart_component_esp32_arduino.h"
#include "esphome/core/application.h"
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#include "esphome/core/log.h"
#ifdef USE_LOGGER
#include "esphome/components/logger/logger.h"
#endif
namespace esphome {
namespace uart {
static const char *const TAG = "uart.arduino_esp32";
static const uint32_t UART_PARITY_EVEN = 0 << 0;
static const uint32_t UART_PARITY_ODD = 1 << 0;
static const uint32_t UART_PARITY_ENABLE = 1 << 1;
static const uint32_t UART_NB_BIT_5 = 0 << 2;
static const uint32_t UART_NB_BIT_6 = 1 << 2;
static const uint32_t UART_NB_BIT_7 = 2 << 2;
static const uint32_t UART_NB_BIT_8 = 3 << 2;
static const uint32_t UART_NB_STOP_BIT_1 = 1 << 4;
static const uint32_t UART_NB_STOP_BIT_2 = 3 << 4;
static const uint32_t UART_TICK_APB_CLOCK = 1 << 27;
uint32_t ESP32ArduinoUARTComponent::get_config() {
uint32_t config = 0;
/*
* All bits numbers below come from
* framework-arduinoespressif32/cores/esp32/esp32-hal-uart.h
* And more specifically conf0 union in uart_dev_t.
*
* Below is bit used from conf0 union.
* <name>:<bits position> <values>
* parity:0 0:even 1:odd
* parity_en:1 Set this bit to enable uart parity check.
* bit_num:2-4 0:5bits 1:6bits 2:7bits 3:8bits
* stop_bit_num:4-6 stop bit. 1:1bit 2:1.5bits 3:2bits
* tick_ref_always_on:27 select the clock.1apb clockref_tick
*/
if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
config |= UART_PARITY_EVEN | UART_PARITY_ENABLE;
} else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
config |= UART_PARITY_ODD | UART_PARITY_ENABLE;
}
switch (this->data_bits_) {
case 5:
config |= UART_NB_BIT_5;
break;
case 6:
config |= UART_NB_BIT_6;
break;
case 7:
config |= UART_NB_BIT_7;
break;
case 8:
config |= UART_NB_BIT_8;
break;
}
if (this->stop_bits_ == 1) {
config |= UART_NB_STOP_BIT_1;
} else {
config |= UART_NB_STOP_BIT_2;
}
config |= UART_TICK_APB_CLOCK;
return config;
}
void ESP32ArduinoUARTComponent::setup() {
// Use Arduino HardwareSerial UARTs if all used pins match the ones
// preconfigured by the platform. For example if RX disabled but TX pin
// is 1 we still want to use Serial.
bool is_default_tx, is_default_rx;
#ifdef CONFIG_IDF_TARGET_ESP32C3
is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 21;
is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 20;
#else
is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 1;
is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 3;
#endif
static uint8_t next_uart_num = 0;
if (is_default_tx && is_default_rx && next_uart_num == 0) {
#if ARDUINO_USB_CDC_ON_BOOT
this->hw_serial_ = &Serial0;
#else
this->hw_serial_ = &Serial;
#endif
next_uart_num++;
} else {
#ifdef USE_LOGGER
bool logger_uses_hardware_uart = true;
#ifdef USE_LOGGER_USB_CDC
if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_CDC) {
// this is not a hardware UART, ignore it
logger_uses_hardware_uart = false;
}
#endif // USE_LOGGER_USB_CDC
#ifdef USE_LOGGER_USB_SERIAL_JTAG
if (logger::global_logger->get_uart() == logger::UART_SELECTION_USB_SERIAL_JTAG) {
// this is not a hardware UART, ignore it
logger_uses_hardware_uart = false;
}
#endif // USE_LOGGER_USB_SERIAL_JTAG
if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
logger::global_logger->get_uart() == next_uart_num) {
next_uart_num++;
}
#endif // USE_LOGGER
if (next_uart_num >= SOC_UART_NUM) {
ESP_LOGW(TAG, "Maximum number of UART components created already.");
this->mark_failed();
return;
}
this->number_ = next_uart_num;
this->hw_serial_ = new HardwareSerial(next_uart_num++); // NOLINT(cppcoreguidelines-owning-memory)
}
this->load_settings(false);
}
void ESP32ArduinoUARTComponent::load_settings(bool dump_config) {
int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
bool invert = false;
if (tx_pin_ != nullptr && tx_pin_->is_inverted())
invert = true;
if (rx_pin_ != nullptr && rx_pin_->is_inverted())
invert = true;
this->hw_serial_->setRxBufferSize(this->rx_buffer_size_);
this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert);
if (dump_config) {
ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->number_);
this->dump_config();
}
}
void ESP32ArduinoUARTComponent::dump_config() {
ESP_LOGCONFIG(TAG, "UART Bus %d:", this->number_);
LOG_PIN(" TX Pin: ", tx_pin_);
LOG_PIN(" RX Pin: ", rx_pin_);
if (this->rx_pin_ != nullptr) {
ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
}
ESP_LOGCONFIG(TAG,
" Baud Rate: %u baud\n"
" Data Bits: %u\n"
" Parity: %s\n"
" Stop bits: %u",
this->baud_rate_, this->data_bits_, LOG_STR_ARG(parity_to_str(this->parity_)), this->stop_bits_);
this->check_logger_conflict();
}
void ESP32ArduinoUARTComponent::write_array(const uint8_t *data, size_t len) {
this->hw_serial_->write(data, len);
#ifdef USE_UART_DEBUGGER
for (size_t i = 0; i < len; i++) {
this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
}
#endif
}
bool ESP32ArduinoUARTComponent::peek_byte(uint8_t *data) {
if (!this->check_read_timeout_())
return false;
*data = this->hw_serial_->peek();
return true;
}
bool ESP32ArduinoUARTComponent::read_array(uint8_t *data, size_t len) {
if (!this->check_read_timeout_(len))
return false;
this->hw_serial_->readBytes(data, len);
#ifdef USE_UART_DEBUGGER
for (size_t i = 0; i < len; i++) {
this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
}
#endif
return true;
}
int ESP32ArduinoUARTComponent::available() { return this->hw_serial_->available(); }
void ESP32ArduinoUARTComponent::flush() {
ESP_LOGVV(TAG, " Flushing");
this->hw_serial_->flush();
}
void ESP32ArduinoUARTComponent::check_logger_conflict() {
#ifdef USE_LOGGER
if (this->hw_serial_ == nullptr || logger::global_logger->get_baud_rate() == 0) {
return;
}
if (this->hw_serial_ == logger::global_logger->get_hw_serial()) {
ESP_LOGW(TAG, " You're using the same serial port for logging and the UART component. Please "
"disable logging over the serial port by setting logger->baud_rate to 0.");
}
#endif
}
} // namespace uart
} // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ARDUINO

View File

@@ -1,60 +0,0 @@
#pragma once
#ifdef USE_ESP32_FRAMEWORK_ARDUINO
#include <driver/uart.h>
#include <HardwareSerial.h>
#include <vector>
#include "esphome/core/component.h"
#include "esphome/core/hal.h"
#include "esphome/core/log.h"
#include "uart_component.h"
namespace esphome {
namespace uart {
class ESP32ArduinoUARTComponent : public UARTComponent, public Component {
public:
void setup() override;
void dump_config() override;
float get_setup_priority() const override { return setup_priority::BUS; }
void write_array(const uint8_t *data, size_t len) override;
bool peek_byte(uint8_t *data) override;
bool read_array(uint8_t *data, size_t len) override;
int available() override;
void flush() override;
uint32_t get_config();
HardwareSerial *get_hw_serial() { return this->hw_serial_; }
uint8_t get_hw_serial_number() { return this->number_; }
/**
* Load the UART with the current settings.
* @param dump_config (Optional, default `true`): True for displaying new settings or
* false to change it quitely
*
* Example:
* ```cpp
* id(uart1).load_settings();
* ```
*
* This will load the current UART interface with the latest settings (baud_rate, parity, etc).
*/
void load_settings(bool dump_config) override;
void load_settings() override { this->load_settings(true); }
protected:
void check_logger_conflict() override;
HardwareSerial *hw_serial_{nullptr};
uint8_t number_{0};
};
} // namespace uart
} // namespace esphome
#endif // USE_ESP32_FRAMEWORK_ARDUINO

View File

@@ -1,4 +1,4 @@
#ifdef USE_ESP_IDF
#ifdef USE_ESP32
#include "uart_component_esp_idf.h"
#include <cinttypes>

View File

@@ -1,6 +1,6 @@
#pragma once
#ifdef USE_ESP_IDF
#ifdef USE_ESP32
#include <driver/uart.h>
#include "esphome/core/component.h"
@@ -55,4 +55,4 @@ class IDFUARTComponent : public UARTComponent, public Component {
} // namespace uart
} // namespace esphome
#endif // USE_ESP_IDF
#endif // USE_ESP32