8#include "esp_clk_tree.h"
10#include "esp_heap_caps.h"
11#include "esp_private/periph_ctrl.h"
12#include "esp_rom_gpio.h"
13#include "hal/uart_ll.h"
14#include "soc/gpio_sig_map.h"
15#include "soc/uart_periph.h"
19constexpr uint32_t kUartRxIntrMask =
20 UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF;
21constexpr uint32_t kUartTxIntrMask = UART_INTR_TXFIFO_EMPTY;
23constexpr uint8_t kRxToutThreshold = 2;
24constexpr uint16_t kTxEmptyThreshold = 24;
26bool IsConsoleUartInUse(uart_port_t uart_num)
28#if defined(CONFIG_ESP_CONSOLE_UART) && CONFIG_ESP_CONSOLE_UART
29 return static_cast<int>(uart_num) == CONFIG_ESP_CONSOLE_UART_NUM;
40uint8_t* ESP32UART::AllocateTxStorage(
size_t size)
42 void* aligned = heap_caps_aligned_alloc(
43 4, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
44 if (aligned !=
nullptr)
46 return static_cast<uint8_t*
>(aligned);
49 return static_cast<uint8_t*
>(
50 heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT));
53ErrorCode ESP32UART::ResolveUartPeriph(uart_port_t uart_num, periph_module_t& out)
58 out = PERIPH_UART0_MODULE;
61 out = PERIPH_UART1_MODULE;
63#if SOC_UART_HP_NUM > 2
65 out = PERIPH_UART2_MODULE;
73ESP32UART::ESP32UART(uart_port_t uart_num,
int tx_pin,
int rx_pin,
int rts_pin,
74 int cts_pin,
size_t rx_buffer_size,
size_t tx_buffer_size,
75 uint32_t tx_queue_size, UART::Configuration config,
bool enable_dma)
76 : UART(&_read_port, &_write_port),
83 rx_isr_buffer_(new (std::nothrow) uint8_t[rx_buffer_size]),
84 rx_isr_buffer_size_(rx_buffer_size),
85 tx_storage_(AllocateTxStorage(tx_buffer_size * 2)),
86 tx_storage_size_(tx_buffer_size * 2),
87 tx_buffer_size_(tx_buffer_size),
88 dma_requested_(enable_dma),
89 _read_port(rx_buffer_size),
90 _write_port(tx_queue_size, tx_buffer_size)
92 ASSERT(!IsConsoleUartInUse(uart_num_));
93 ASSERT(uart_num_ < UART_NUM_MAX);
94 ASSERT(uart_num_ < SOC_UART_HP_NUM);
95 ASSERT(rx_isr_buffer_size_ > 0);
96 ASSERT(tx_buffer_size_ > 0);
97 ASSERT(rx_isr_buffer_ !=
nullptr);
98 ASSERT(tx_storage_ !=
nullptr);
99 ASSERT(tx_storage_size_ >= (tx_buffer_size_ * 2U));
101 tx_active_buffer_ = tx_storage_;
102 tx_pending_buffer_ = tx_storage_ + tx_buffer_size_;
103 tx_active_length_ = 0;
104 tx_pending_length_ = 0;
109 if (InitUartHardware() != ErrorCode::OK)
115#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
118 if (InitDmaBackend() != ErrorCode::OK)
125 if (!dma_backend_enabled_)
127 if (InstallUartIsr() != ErrorCode::OK)
132 ConfigureRxInterruptPath();
135 if (InstallUartIsr() != ErrorCode::OK)
140 ConfigureRxInterruptPath();
144void ESP32UART::ConfigureRxInterruptPath()
146 const size_t rx_full_floor = 16;
147 const size_t rx_full_ceil = std::max<size_t>(rx_full_floor, SOC_UART_FIFO_LEN / 4);
148 const uint16_t full_thr =
static_cast<uint16_t
>(std::min<size_t>(
149 rx_full_ceil, std::max<size_t>(rx_full_floor, rx_isr_buffer_size_ / 16)));
151 uart_hal_set_rxfifo_full_thr(&uart_hal_, full_thr);
152 uart_hal_set_rx_timeout(&uart_hal_, kRxToutThreshold);
153 uart_hal_clr_intsts_mask(&uart_hal_, kUartRxIntrMask);
154 uart_hal_ena_intr_mask(&uart_hal_, kUartRxIntrMask);
159 if (!uart_hw_enabled_)
161 return ErrorCode::STATE_ERR;
164 uart_word_length_t word_length = UART_DATA_8_BITS;
165 uart_stop_bits_t stop_bits = UART_STOP_BITS_1;
167 if (!ResolveWordLength(config.
data_bits, word_length))
169 return ErrorCode::ARG_ERR;
172 if (!ResolveStopBits(config.
stop_bits, stop_bits))
174 return ErrorCode::ARG_ERR;
177 const uart_sclk_t sclk = UART_SCLK_DEFAULT;
178 uart_hal_set_sclk(&uart_hal_,
static_cast<soc_module_clk_t
>(sclk));
180 uint32_t sclk_hz = 0;
181 if ((esp_clk_tree_src_get_freq_hz(
static_cast<soc_module_clk_t
>(sclk),
182 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
183 &sclk_hz) != ESP_OK) ||
186 return ErrorCode::INIT_ERR;
189 if (!uart_hal_set_baudrate(&uart_hal_, config.
baudrate, sclk_hz))
191 return ErrorCode::INIT_ERR;
194 uart_hal_set_data_bit_num(&uart_hal_, word_length);
195 uart_hal_set_stop_bits(&uart_hal_, stop_bits);
196 uart_hal_set_parity(&uart_hal_, ResolveParity(config.
parity));
197 uart_hal_set_hw_flow_ctrl(&uart_hal_, UART_HW_FLOWCTRL_DISABLE, 0);
198 uart_hal_set_mode(&uart_hal_, UART_MODE_UART);
199 uart_hal_set_txfifo_empty_thr(&uart_hal_, kTxEmptyThreshold);
202 uart_hal_rxfifo_rst(&uart_hal_);
203 uart_hal_clr_intsts_mask(&uart_hal_, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
205#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
206 if (dma_backend_enabled_)
216 if (tx_busy_.IsSet() && tx_active_valid_)
218#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
219 if (dma_backend_enabled_)
226 uart_hal_clr_intsts_mask(&uart_hal_, kUartTxIntrMask);
227 uart_hal_ena_intr_mask(&uart_hal_, kUartTxIntrMask);
233 return ErrorCode::OK;
236ErrorCode ESP32UART::SetLoopback(
bool enable)
238 if (!uart_hw_enabled_)
240 return ErrorCode::STATE_ERR;
243 uart_ll_set_loop_back(uart_hal_.dev, enable);
244 return ErrorCode::OK;
247ErrorCode IRAM_ATTR ESP32UART::WriteFun(WritePort& port,
bool in_isr)
249 auto* uart = CONTAINER_OF(&port, ESP32UART, _write_port);
250 return uart->TryStartTx(in_isr);
253ErrorCode ESP32UART::ReadFun(ReadPort&,
bool) {
return ErrorCode::PENDING; }
255bool ESP32UART::ResolveWordLength(uint8_t data_bits, uart_word_length_t& out)
260 out = UART_DATA_5_BITS;
263 out = UART_DATA_6_BITS;
266 out = UART_DATA_7_BITS;
269 out = UART_DATA_8_BITS;
276bool ESP32UART::ResolveStopBits(uint8_t stop_bits, uart_stop_bits_t& out)
281 out = UART_STOP_BITS_1;
284 out = UART_STOP_BITS_2;
291uart_parity_t ESP32UART::ResolveParity(UART::Parity parity)
295 case UART::Parity::NO_PARITY:
296 return UART_PARITY_DISABLE;
297 case UART::Parity::EVEN:
298 return UART_PARITY_EVEN;
299 case UART::Parity::ODD:
300 return UART_PARITY_ODD;
302 return UART_PARITY_DISABLE;
308 if (uart_num_ >= UART_NUM_MAX)
310 return ErrorCode::NOT_SUPPORT;
313 periph_module_t uart_module = PERIPH_MODULE_MAX;
314 if (ResolveUartPeriph(uart_num_, uart_module) != ErrorCode::OK)
316 return ErrorCode::NOT_SUPPORT;
319 uart_hal_.dev = UART_LL_GET_HW(uart_num_);
320 if (uart_hal_.dev ==
nullptr)
322 return ErrorCode::NOT_SUPPORT;
325 periph_module_enable(uart_module);
326 periph_module_reset(uart_module);
328 uart_ll_sclk_enable(uart_hal_.dev);
329 uart_hal_init(&uart_hal_, uart_num_);
331 uart_hw_enabled_ =
true;
332 if (SetConfig(config_) != ErrorCode::OK)
334 uart_hw_enabled_ =
false;
335 return ErrorCode::INIT_ERR;
338 if (ConfigurePins() != ErrorCode::OK)
340 uart_hw_enabled_ =
false;
341 return ErrorCode::INIT_ERR;
344 uart_hal_txfifo_rst(&uart_hal_);
345 uart_hal_rxfifo_rst(&uart_hal_);
346 uart_hal_clr_intsts_mask(&uart_hal_, UINT32_MAX);
347 uart_hal_disable_intr_mask(&uart_hal_, UINT32_MAX);
349 return ErrorCode::OK;
356 if (!GPIO_IS_VALID_OUTPUT_GPIO(tx_pin_))
358 return ErrorCode::ARG_ERR;
360 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(tx_pin_));
361 esp_rom_gpio_connect_out_signal(
362 tx_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_TX_PIN_IDX),
false,
false);
367 if (!GPIO_IS_VALID_GPIO(rx_pin_))
369 return ErrorCode::ARG_ERR;
371 gpio_input_enable(
static_cast<gpio_num_t
>(rx_pin_));
372 esp_rom_gpio_connect_in_signal(
373 rx_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_RX_PIN_IDX),
false);
378 if (!GPIO_IS_VALID_OUTPUT_GPIO(rts_pin_))
380 return ErrorCode::ARG_ERR;
382 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(rts_pin_));
383 esp_rom_gpio_connect_out_signal(
384 rts_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_RTS_PIN_IDX),
false,
false);
389 if (!GPIO_IS_VALID_GPIO(cts_pin_))
391 return ErrorCode::ARG_ERR;
393 gpio_pullup_en(
static_cast<gpio_num_t
>(cts_pin_));
394 gpio_input_enable(
static_cast<gpio_num_t
>(cts_pin_));
395 esp_rom_gpio_connect_in_signal(
396 cts_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_CTS_PIN_IDX),
false);
399 return ErrorCode::OK;
402void IRAM_ATTR ESP32UART::ClearActiveTx()
404 tx_active_length_ = 0;
405 tx_active_offset_ = 0;
406 tx_active_info_ = {};
407 tx_active_valid_ =
false;
410void IRAM_ATTR ESP32UART::ClearPendingTx()
412 tx_pending_length_ = 0;
413 tx_pending_info_ = {};
414 tx_pending_valid_ =
false;
417bool IRAM_ATTR ESP32UART::StartAndReportActive(
bool in_isr)
419 if (!StartActiveTransfer(in_isr))
421 write_port_->Finish(in_isr, ErrorCode::FAILED, tx_active_info_);
428 write_port_->Finish(in_isr, ErrorCode::OK, tx_active_info_);
432ErrorCode IRAM_ATTR ESP32UART::TryStartTx(
bool in_isr)
434 if (in_tx_isr_.IsSet())
436 return ErrorCode::PENDING;
438 if (!tx_active_valid_)
440 (void)LoadActiveTxFromQueue(in_isr);
443 if (!tx_busy_.IsSet() && tx_active_valid_)
445 if (!StartActiveTransfer(in_isr))
448 return ErrorCode::FAILED;
452 if (!tx_pending_valid_)
454 (void)LoadPendingTxFromQueue(in_isr);
456 return ErrorCode::OK;
459 if (!tx_pending_valid_)
461 (void)LoadPendingTxFromQueue(in_isr);
464 return ErrorCode::PENDING;
467bool IRAM_ATTR ESP32UART::LoadActiveTxFromQueue(
bool in_isr)
471 size_t active_length = 0U;
472 if (!DequeueTxToBuffer(tx_active_buffer_, active_length, tx_active_info_, in_isr))
477 tx_active_length_ = active_length;
478 tx_active_valid_ =
true;
482bool IRAM_ATTR ESP32UART::LoadPendingTxFromQueue(
bool in_isr)
486 if (tx_pending_valid_)
491 size_t pending_length = 0U;
492 if (!DequeueTxToBuffer(tx_pending_buffer_, pending_length, tx_pending_info_, in_isr))
497 tx_pending_length_ = pending_length;
498 tx_pending_valid_ =
true;
502bool IRAM_ATTR ESP32UART::DequeueTxToBuffer(uint8_t* buffer,
size_t& size,
503 WriteInfoBlock& info,
bool in_isr)
508 WriteInfoBlock peek_info = {};
509 if (write_port_->queue_info_->Peek(peek_info) != ErrorCode::OK)
514 if (peek_info.data.size_ > tx_buffer_size_)
520#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
521 if (dma_backend_enabled_)
523 if (write_port_->queue_data_->PopBatch(buffer, peek_info.data.size_) != ErrorCode::OK)
530 if (write_port_->queue_info_->Pop(info) != ErrorCode::OK)
535 size = peek_info.data.size_;
539bool IRAM_ATTR ESP32UART::StartActiveTransfer(
bool)
541 if (!tx_active_valid_)
546 if (tx_busy_.TestAndSet())
551 tx_active_offset_ = 0;
553#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
554 if (dma_backend_enabled_)
566 uart_hal_clr_intsts_mask(&uart_hal_, kUartTxIntrMask);
567 uart_hal_ena_intr_mask(&uart_hal_, kUartTxIntrMask);
573void IRAM_ATTR ESP32UART::PushRxBytes(
const uint8_t* data,
size_t size,
bool in_isr)
576 bool pushed_any =
false;
577 while (offset < size)
579 const size_t free_space = read_port_->queue_data_->EmptySize();
585 const size_t chunk = std::min(free_space, size - offset);
586 if (read_port_->queue_data_->PushBatch(data + offset, chunk) != ErrorCode::OK)
597 read_port_->ProcessPendingReads(in_isr);
600void IRAM_ATTR ESP32UART::OnTxTransferDone(
bool in_isr, ErrorCode result)
602 Flag::ScopedRestore tx_flag(in_tx_isr_);
607 if ((result != ErrorCode::OK) && tx_pending_valid_)
609 write_port_->Finish(in_isr, ErrorCode::FAILED, tx_pending_info_);
613 if (result != ErrorCode::OK)
619 if (tx_pending_valid_)
621 std::swap(tx_active_buffer_, tx_pending_buffer_);
622 tx_active_length_ = tx_pending_length_;
623 tx_pending_length_ = 0;
624 tx_active_info_ = tx_pending_info_;
625 tx_active_valid_ =
true;
627 (void)StartAndReportActive(in_isr);
631 if (LoadActiveTxFromQueue(in_isr))
633 (void)StartAndReportActive(in_isr);
637 if (!tx_pending_valid_)
639 (void)LoadPendingTxFromQueue(in_isr);
@ NOT_SUPPORT
不支持 | Not supported
@ OK
操作成功 | Operation successful
ErrorCode(* ReadFun)(ReadPort &port, bool in_isr)
Function pointer type for read operations.
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
UART 配置结构体 / UART configuration structure.
uint8_t stop_bits
停止位长度 / Number of stop bits
Parity parity
校验模式 / Parity mode
uint8_t data_bits
数据位长度 / Number of data bits
uint32_t baudrate
波特率 / Baud rate