ESPHome  2024.12.2
uart_component_esp32_arduino.cpp
Go to the documentation of this file.
1 #ifdef USE_ESP32_FRAMEWORK_ARDUINO
3 #include "esphome/core/defines.h"
4 #include "esphome/core/helpers.h"
5 #include "esphome/core/log.h"
7 
8 #ifdef USE_LOGGER
10 #endif
11 
12 namespace esphome {
13 namespace uart {
14 static const char *const TAG = "uart.arduino_esp32";
15 
16 static const uint32_t UART_PARITY_EVEN = 0 << 0;
17 static const uint32_t UART_PARITY_ODD = 1 << 0;
18 static const uint32_t UART_PARITY_ENABLE = 1 << 1;
19 static const uint32_t UART_NB_BIT_5 = 0 << 2;
20 static const uint32_t UART_NB_BIT_6 = 1 << 2;
21 static const uint32_t UART_NB_BIT_7 = 2 << 2;
22 static const uint32_t UART_NB_BIT_8 = 3 << 2;
23 static const uint32_t UART_NB_STOP_BIT_1 = 1 << 4;
24 static const uint32_t UART_NB_STOP_BIT_2 = 3 << 4;
25 static const uint32_t UART_TICK_APB_CLOCK = 1 << 27;
26 
28  uint32_t config = 0;
29 
30  /*
31  * All bits numbers below come from
32  * framework-arduinoespressif32/cores/esp32/esp32-hal-uart.h
33  * And more specifically conf0 union in uart_dev_t.
34  *
35  * Below is bit used from conf0 union.
36  * <name>:<bits position> <values>
37  * parity:0 0:even 1:odd
38  * parity_en:1 Set this bit to enable uart parity check.
39  * bit_num:2-4 0:5bits 1:6bits 2:7bits 3:8bits
40  * stop_bit_num:4-6 stop bit. 1:1bit 2:1.5bits 3:2bits
41  * tick_ref_always_on:27 select the clock.1:apb clock:ref_tick
42  */
43 
44  if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
45  config |= UART_PARITY_EVEN | UART_PARITY_ENABLE;
46  } else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
47  config |= UART_PARITY_ODD | UART_PARITY_ENABLE;
48  }
49 
50  switch (this->data_bits_) {
51  case 5:
52  config |= UART_NB_BIT_5;
53  break;
54  case 6:
55  config |= UART_NB_BIT_6;
56  break;
57  case 7:
58  config |= UART_NB_BIT_7;
59  break;
60  case 8:
61  config |= UART_NB_BIT_8;
62  break;
63  }
64 
65  if (this->stop_bits_ == 1) {
66  config |= UART_NB_STOP_BIT_1;
67  } else {
68  config |= UART_NB_STOP_BIT_2;
69  }
70 
71  config |= UART_TICK_APB_CLOCK;
72 
73  return config;
74 }
75 
77  ESP_LOGCONFIG(TAG, "Setting up UART...");
78  // Use Arduino HardwareSerial UARTs if all used pins match the ones
79  // preconfigured by the platform. For example if RX disabled but TX pin
80  // is 1 we still want to use Serial.
81  bool is_default_tx, is_default_rx;
82 #ifdef CONFIG_IDF_TARGET_ESP32C3
83  is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 21;
84  is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 20;
85 #else
86  is_default_tx = tx_pin_ == nullptr || tx_pin_->get_pin() == 1;
87  is_default_rx = rx_pin_ == nullptr || rx_pin_->get_pin() == 3;
88 #endif
89  static uint8_t next_uart_num = 0;
90  if (is_default_tx && is_default_rx && next_uart_num == 0) {
91 #if ARDUINO_USB_CDC_ON_BOOT
92  this->hw_serial_ = &Serial0;
93 #else
94  this->hw_serial_ = &Serial;
95 #endif
96  next_uart_num++;
97  } else {
98 #ifdef USE_LOGGER
99  bool logger_uses_hardware_uart = true;
100 
101 #ifdef USE_LOGGER_USB_CDC
103  // this is not a hardware UART, ignore it
104  logger_uses_hardware_uart = false;
105  }
106 #endif // USE_LOGGER_USB_CDC
107 
108 #ifdef USE_LOGGER_USB_SERIAL_JTAG
110  // this is not a hardware UART, ignore it
111  logger_uses_hardware_uart = false;
112  }
113 #endif // USE_LOGGER_USB_SERIAL_JTAG
114 
115  if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
116  logger::global_logger->get_uart() == next_uart_num) {
117  next_uart_num++;
118  }
119 #endif // USE_LOGGER
120 
121  if (next_uart_num >= UART_NUM_MAX) {
122  ESP_LOGW(TAG, "Maximum number of UART components created already.");
123  this->mark_failed();
124  return;
125  }
126 
127  this->number_ = next_uart_num;
128  this->hw_serial_ = new HardwareSerial(next_uart_num++); // NOLINT(cppcoreguidelines-owning-memory)
129  }
130 
131  this->load_settings(false);
132 }
133 
135  int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
136  int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
137  bool invert = false;
138  if (tx_pin_ != nullptr && tx_pin_->is_inverted())
139  invert = true;
140  if (rx_pin_ != nullptr && rx_pin_->is_inverted())
141  invert = true;
142  this->hw_serial_->setRxBufferSize(this->rx_buffer_size_);
143  this->hw_serial_->begin(this->baud_rate_, get_config(), rx, tx, invert);
144  if (dump_config) {
145  ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->number_);
146  this->dump_config();
147  }
148 }
149 
151  ESP_LOGCONFIG(TAG, "UART Bus %d:", this->number_);
152  LOG_PIN(" TX Pin: ", tx_pin_);
153  LOG_PIN(" RX Pin: ", rx_pin_);
154  if (this->rx_pin_ != nullptr) {
155  ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
156  }
157  ESP_LOGCONFIG(TAG, " Baud Rate: %u baud", this->baud_rate_);
158  ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
159  ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
160  ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
161  this->check_logger_conflict();
162 }
163 
164 void ESP32ArduinoUARTComponent::write_array(const uint8_t *data, size_t len) {
165  this->hw_serial_->write(data, len);
166 #ifdef USE_UART_DEBUGGER
167  for (size_t i = 0; i < len; i++) {
168  this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
169  }
170 #endif
171 }
172 
174  if (!this->check_read_timeout_())
175  return false;
176  *data = this->hw_serial_->peek();
177  return true;
178 }
179 
180 bool ESP32ArduinoUARTComponent::read_array(uint8_t *data, size_t len) {
181  if (!this->check_read_timeout_(len))
182  return false;
183  this->hw_serial_->readBytes(data, len);
184 #ifdef USE_UART_DEBUGGER
185  for (size_t i = 0; i < len; i++) {
186  this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
187  }
188 #endif
189  return true;
190 }
191 
192 int ESP32ArduinoUARTComponent::available() { return this->hw_serial_->available(); }
194  ESP_LOGVV(TAG, " Flushing...");
195  this->hw_serial_->flush();
196 }
197 
199 #ifdef USE_LOGGER
200  if (this->hw_serial_ == nullptr || logger::global_logger->get_baud_rate() == 0) {
201  return;
202  }
203 
205  ESP_LOGW(TAG, " You're using the same serial port for logging and the UART component. Please "
206  "disable logging over the serial port by setting logger->baud_rate to 0.");
207  }
208 #endif
209 }
210 
211 } // namespace uart
212 } // namespace esphome
213 #endif // USE_ESP32_FRAMEWORK_ARDUINO
uint32_t get_baud_rate() const
bool read_array(uint8_t *data, size_t len) override
virtual uint8_t get_pin() const =0
Logger * global_logger
Definition: logger.cpp:198
const char *const TAG
Definition: spi.cpp:8
void write_array(const uint8_t *data, size_t len) override
std::string size_t len
Definition: helpers.h:293
virtual void mark_failed()
Mark this component as failed.
Definition: component.cpp:118
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
bool check_read_timeout_(size_t len=1)
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
const LogString * parity_to_str(UARTParityOptions parity)
Definition: uart.cpp:33
virtual bool is_inverted() const =0