ESPHome 2025.5.0
Loading...
Searching...
No Matches
uart_component_esp_idf.cpp
Go to the documentation of this file.
1#ifdef USE_ESP_IDF
2
4#include <cinttypes>
8#include "esphome/core/log.h"
9
10#ifdef USE_LOGGER
12#endif
13
14namespace esphome {
15namespace uart {
16static const char *const TAG = "uart.idf";
17
19 uart_parity_t parity = UART_PARITY_DISABLE;
20 if (this->parity_ == UART_CONFIG_PARITY_EVEN) {
21 parity = UART_PARITY_EVEN;
22 } else if (this->parity_ == UART_CONFIG_PARITY_ODD) {
23 parity = UART_PARITY_ODD;
24 }
25
26 uart_word_length_t data_bits;
27 switch (this->data_bits_) {
28 case 5:
29 data_bits = UART_DATA_5_BITS;
30 break;
31 case 6:
32 data_bits = UART_DATA_6_BITS;
33 break;
34 case 7:
35 data_bits = UART_DATA_7_BITS;
36 break;
37 case 8:
38 data_bits = UART_DATA_8_BITS;
39 break;
40 default:
41 data_bits = UART_DATA_BITS_MAX;
42 break;
43 }
44
45 uart_config_t uart_config;
46 uart_config.baud_rate = this->baud_rate_;
47 uart_config.data_bits = data_bits;
48 uart_config.parity = parity;
49 uart_config.stop_bits = this->stop_bits_ == 1 ? UART_STOP_BITS_1 : UART_STOP_BITS_2;
50 uart_config.flow_ctrl = UART_HW_FLOWCTRL_DISABLE;
51#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0)
52 uart_config.source_clk = UART_SCLK_DEFAULT;
53#else
54 uart_config.source_clk = UART_SCLK_APB;
55#endif
56 uart_config.rx_flow_ctrl_thresh = 122;
57
58 return uart_config;
59}
60
62 static uint8_t next_uart_num = 0;
63
64#ifdef USE_LOGGER
65 bool logger_uses_hardware_uart = true;
66
67#ifdef USE_LOGGER_USB_CDC
69 // this is not a hardware UART, ignore it
70 logger_uses_hardware_uart = false;
71 }
72#endif // USE_LOGGER_USB_CDC
73
74#ifdef USE_LOGGER_USB_SERIAL_JTAG
76 // this is not a hardware UART, ignore it
77 logger_uses_hardware_uart = false;
78 }
79#endif // USE_LOGGER_USB_SERIAL_JTAG
80
81 if (logger_uses_hardware_uart && logger::global_logger->get_baud_rate() > 0 &&
82 logger::global_logger->get_uart_num() == next_uart_num) {
83 next_uart_num++;
84 }
85#endif // USE_LOGGER
86
87 if (next_uart_num >= SOC_UART_NUM) {
88 ESP_LOGW(TAG, "Maximum number of UART components created already.");
89 this->mark_failed();
90 return;
91 }
92 this->uart_num_ = static_cast<uart_port_t>(next_uart_num++);
93 ESP_LOGCONFIG(TAG, "Setting up UART %u...", this->uart_num_);
94
95 this->lock_ = xSemaphoreCreateMutex();
96
97 xSemaphoreTake(this->lock_, portMAX_DELAY);
98
99 uart_config_t uart_config = this->get_config_();
100 esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
101 if (err != ESP_OK) {
102 ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
103 this->mark_failed();
104 return;
105 }
106
107 int8_t tx = this->tx_pin_ != nullptr ? this->tx_pin_->get_pin() : -1;
108 int8_t rx = this->rx_pin_ != nullptr ? this->rx_pin_->get_pin() : -1;
109
110 uint32_t invert = 0;
111 if (this->tx_pin_ != nullptr && this->tx_pin_->is_inverted())
112 invert |= UART_SIGNAL_TXD_INV;
113 if (this->rx_pin_ != nullptr && this->rx_pin_->is_inverted())
114 invert |= UART_SIGNAL_RXD_INV;
115
116 err = uart_set_line_inverse(this->uart_num_, invert);
117 if (err != ESP_OK) {
118 ESP_LOGW(TAG, "uart_set_line_inverse failed: %s", esp_err_to_name(err));
119 this->mark_failed();
120 return;
121 }
122
123 err = uart_set_pin(this->uart_num_, tx, rx, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
124 if (err != ESP_OK) {
125 ESP_LOGW(TAG, "uart_set_pin failed: %s", esp_err_to_name(err));
126 this->mark_failed();
127 return;
128 }
129
130 err = uart_driver_install(this->uart_num_, /* UART RX ring buffer size. */ this->rx_buffer_size_,
131 /* UART TX ring buffer size. If set to zero, driver will not use TX buffer, TX function will
132 block task until all data have been sent out.*/
133 0,
134 /* UART event queue size/depth. */ 20, &(this->uart_event_queue_),
135 /* Flags used to allocate the interrupt. */ 0);
136 if (err != ESP_OK) {
137 ESP_LOGW(TAG, "uart_driver_install failed: %s", esp_err_to_name(err));
138 this->mark_failed();
139 return;
140 }
141
142 xSemaphoreGive(this->lock_);
143}
144
145void IDFUARTComponent::load_settings(bool dump_config) {
146 uart_config_t uart_config = this->get_config_();
147 esp_err_t err = uart_param_config(this->uart_num_, &uart_config);
148 if (err != ESP_OK) {
149 ESP_LOGW(TAG, "uart_param_config failed: %s", esp_err_to_name(err));
150 this->mark_failed();
151 return;
152 } else if (dump_config) {
153 ESP_LOGCONFIG(TAG, "UART %u was reloaded.", this->uart_num_);
154 this->dump_config();
155 }
156}
157
159 ESP_LOGCONFIG(TAG, "UART Bus %u:", this->uart_num_);
160 LOG_PIN(" TX Pin: ", tx_pin_);
161 LOG_PIN(" RX Pin: ", rx_pin_);
162 if (this->rx_pin_ != nullptr) {
163 ESP_LOGCONFIG(TAG, " RX Buffer Size: %u", this->rx_buffer_size_);
164 }
165 ESP_LOGCONFIG(TAG, " Baud Rate: %" PRIu32 " baud", this->baud_rate_);
166 ESP_LOGCONFIG(TAG, " Data Bits: %u", this->data_bits_);
167 ESP_LOGCONFIG(TAG, " Parity: %s", LOG_STR_ARG(parity_to_str(this->parity_)));
168 ESP_LOGCONFIG(TAG, " Stop bits: %u", this->stop_bits_);
169 this->check_logger_conflict();
170}
171
172void IDFUARTComponent::write_array(const uint8_t *data, size_t len) {
173 xSemaphoreTake(this->lock_, portMAX_DELAY);
174 uart_write_bytes(this->uart_num_, data, len);
175 xSemaphoreGive(this->lock_);
176#ifdef USE_UART_DEBUGGER
177 for (size_t i = 0; i < len; i++) {
178 this->debug_callback_.call(UART_DIRECTION_TX, data[i]);
179 }
180#endif
181}
182
183bool IDFUARTComponent::peek_byte(uint8_t *data) {
184 if (!this->check_read_timeout_())
185 return false;
186 xSemaphoreTake(this->lock_, portMAX_DELAY);
187 if (this->has_peek_) {
188 *data = this->peek_byte_;
189 } else {
190 int len = uart_read_bytes(this->uart_num_, data, 1, 20 / portTICK_PERIOD_MS);
191 if (len == 0) {
192 *data = 0;
193 } else {
194 this->has_peek_ = true;
195 this->peek_byte_ = *data;
196 }
197 }
198 xSemaphoreGive(this->lock_);
199 return true;
200}
201
202bool IDFUARTComponent::read_array(uint8_t *data, size_t len) {
203 size_t length_to_read = len;
204 if (!this->check_read_timeout_(len))
205 return false;
206 xSemaphoreTake(this->lock_, portMAX_DELAY);
207 if (this->has_peek_) {
208 length_to_read--;
209 *data = this->peek_byte_;
210 data++;
211 this->has_peek_ = false;
212 }
213 if (length_to_read > 0)
214 uart_read_bytes(this->uart_num_, data, length_to_read, 20 / portTICK_PERIOD_MS);
215 xSemaphoreGive(this->lock_);
216#ifdef USE_UART_DEBUGGER
217 for (size_t i = 0; i < len; i++) {
218 this->debug_callback_.call(UART_DIRECTION_RX, data[i]);
219 }
220#endif
221 return true;
222}
223
225 size_t available;
226
227 xSemaphoreTake(this->lock_, portMAX_DELAY);
228 uart_get_buffered_data_len(this->uart_num_, &available);
229 if (this->has_peek_)
230 available++;
231 xSemaphoreGive(this->lock_);
232
233 return available;
234}
235
237 ESP_LOGVV(TAG, " Flushing...");
238 xSemaphoreTake(this->lock_, portMAX_DELAY);
239 uart_wait_tx_done(this->uart_num_, portMAX_DELAY);
240 xSemaphoreGive(this->lock_);
241}
242
244
245} // namespace uart
246} // namespace esphome
247
248#endif // USE_ESP32
virtual void mark_failed()
Mark this component as failed.
virtual uint8_t get_pin() const =0
virtual bool is_inverted() const =0
bool peek_byte(uint8_t *data) override
void write_array(const uint8_t *data, size_t len) override
bool read_array(uint8_t *data, size_t len) override
bool check_read_timeout_(size_t len=1)
CallbackManager< void(UARTDirection, uint8_t)> debug_callback_
@ UART_SELECTION_USB_SERIAL_JTAG
Definition logger.h:79
@ UART_SELECTION_USB_CDC
Definition logger.h:76
Logger * global_logger
Definition logger.cpp:251
const char *const TAG
Definition spi.cpp:8
const LogString * parity_to_str(UARTParityOptions parity)
Definition uart.cpp:33
Providing packet encoding functions for exchanging data with a remote host.
Definition a01nyub.cpp:7
std::string size_t len
Definition helpers.h:301