7#include "esp_clk_tree.h"
9#include "esp_heap_caps.h"
10#include "esp_private/periph_ctrl.h"
11#include "esp_rom_gpio.h"
12#include "hal/uart_ll.h"
13#include "soc/gpio_sig_map.h"
14#include "soc/uart_periph.h"
20constexpr uint32_t UART_RX_INTR_MASK =
21 UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF;
25constexpr uint32_t UART_TX_INTR_MASK = UART_INTR_TXFIFO_EMPTY;
30constexpr uint8_t RX_TOUT_THRESHOLD = 1;
34constexpr uint16_t TX_EMPTY_THRESHOLD = SOC_UART_FIFO_LEN / 2U;
38bool IsConsoleUartInUse(uart_port_t uart_num)
40#if defined(CONFIG_ESP_CONSOLE_UART) && CONFIG_ESP_CONSOLE_UART
41 return static_cast<int>(uart_num) == CONFIG_ESP_CONSOLE_UART_NUM;
54#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
55 if (
owner_.dma_backend_enabled_)
68 void* aligned = heap_caps_aligned_alloc(
69 4, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
70 if (aligned !=
nullptr)
72 return static_cast<uint8_t*
>(aligned);
75 return static_cast<uint8_t*
>(
76 heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT));
86 out = PERIPH_UART0_MODULE;
89 out = PERIPH_UART1_MODULE;
91#if SOC_UART_HP_NUM > 2
93 out = PERIPH_UART2_MODULE;
105 int cts_pin,
size_t rx_buffer_size,
size_t tx_buffer_size,
107 :
UART(&_read_port, &_write_port),
114 requested_config_(config),
115 rx_isr_buffer_(new uint8_t[rx_buffer_size]),
116 rx_isr_buffer_size_(rx_buffer_size),
117 tx_storage_(AllocateTxStorage(tx_buffer_size * 2)),
118 dma_requested_(enable_dma),
119 _read_port(rx_buffer_size, *this),
120 _write_port(tx_queue_size, tx_buffer_size),
121 tx_dma_model_(*this, _write_port,
RawData(tx_storage_, tx_buffer_size * 2U))
127 ASSERT(tx_buffer_size > 0);
138#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
148 if (!dma_backend_enabled_)
172 const uint16_t full_thr =
static_cast<uint16_t
>(SOC_UART_FIFO_LEN / 2U);
174 uart_hal_set_rxfifo_full_thr(&
uart_hal_, full_thr);
175 uart_hal_set_rx_timeout(&
uart_hal_, RX_TOUT_THRESHOLD);
176 uart_hal_clr_intsts_mask(&
uart_hal_, UART_RX_INTR_MASK);
177 uart_hal_ena_intr_mask(&
uart_hal_, UART_RX_INTR_MASK);
192 uart_word_length_t word_length = UART_DATA_8_BITS;
193 uart_stop_bits_t stop_bits = UART_STOP_BITS_1;
205 requested_config_.Store(config);
210void ESP32UART::OnConfigRequested() { rx_config_gate_.RequestConfig(); }
212bool ESP32UART::ApplyPendingConfig(
bool in_isr)
214 if (!rx_config_gate_.TryEnterConfig())
219 UART::Configuration config{};
220 (void)requested_config_.LoadLatest(config);
222 uart_word_length_t word_length = UART_DATA_8_BITS;
223 uart_stop_bits_t stop_bits = UART_STOP_BITS_1;
227 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
231#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
232 if (dma_backend_enabled_ && (tx_dma_channel_ !=
nullptr))
234 gdma_stop(tx_dma_channel_);
235 gdma_reset(tx_dma_channel_);
239 bool dma_backend_enabled =
false;
240#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
241 dma_backend_enabled = dma_backend_enabled_;
243 if (!dma_backend_enabled)
245 uart_hal_disable_intr_mask(&
uart_hal_, UART_TX_INTR_MASK);
250 const uart_sclk_t sclk = UART_SCLK_DEFAULT;
251 uart_hal_set_sclk(&
uart_hal_,
static_cast<soc_module_clk_t
>(sclk));
253 uint32_t sclk_hz = 0;
254 if ((esp_clk_tree_src_get_freq_hz(
static_cast<soc_module_clk_t
>(sclk),
255 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
256 &sclk_hz) != ESP_OK) ||
259 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
263#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
264 if (!uart_hal_set_baudrate(&
uart_hal_, config.baudrate, sclk_hz))
266 DEV_ASSERT_FROM_CALLBACK(
false, in_isr);
270 uart_hal_set_baudrate(&
uart_hal_, config.baudrate, sclk_hz);
273 uart_hal_set_data_bit_num(&
uart_hal_, word_length);
274 uart_hal_set_stop_bits(&
uart_hal_, stop_bits);
276 uart_hal_set_hw_flow_ctrl(&
uart_hal_, UART_HW_FLOWCTRL_DISABLE, 0);
277 uart_hal_set_mode(&
uart_hal_, UART_MODE_UART);
278 uart_hal_set_txfifo_empty_thr(&
uart_hal_, TX_EMPTY_THRESHOLD);
282 uart_hal_clr_intsts_mask(&
uart_hal_, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
284#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
285 if (dma_backend_enabled_)
297bool ESP32UART::OnConfigApplied(
bool in_isr)
299 rx_config_gate_.LeaveConfig();
300#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
301 if (dma_backend_enabled_)
310#if !(SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED)
311bool ESP32UART::StartDmaTx(uint8_t*,
size_t,
int) {
return false; }
324 uart_ll_set_loop_back(
uart_hal_.dev, enable);
333#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
334 if (uart->dma_backend_enabled_)
336 return uart->tx_dma_model_.Submit(in_isr);
339 if (uart->rx_config_gate_.ConfigRequested())
343 return uart->TryStartTx(in_isr);
358 out = UART_DATA_5_BITS;
361 out = UART_DATA_6_BITS;
364 out = UART_DATA_7_BITS;
367 out = UART_DATA_8_BITS;
381 out = UART_STOP_BITS_1;
384 out = UART_STOP_BITS_2;
398 return UART_PARITY_DISABLE;
400 return UART_PARITY_EVEN;
402 return UART_PARITY_ODD;
404 return UART_PARITY_DISABLE;
418 periph_module_t uart_module = PERIPH_MODULE_MAX;
430 periph_module_enable(uart_module);
431 periph_module_reset(uart_module);
451 uart_hal_clr_intsts_mask(&
uart_hal_, UINT32_MAX);
452 uart_hal_disable_intr_mask(&
uart_hal_, UINT32_MAX);
463 if (!GPIO_IS_VALID_OUTPUT_GPIO(
tx_pin_))
467 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(
tx_pin_));
468 esp_rom_gpio_connect_out_signal(
474 if (!GPIO_IS_VALID_GPIO(
rx_pin_))
478 gpio_input_enable(
static_cast<gpio_num_t
>(
rx_pin_));
479 esp_rom_gpio_connect_in_signal(
485 if (!GPIO_IS_VALID_OUTPUT_GPIO(
rts_pin_))
489 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(
rts_pin_));
490 esp_rom_gpio_connect_out_signal(
500 gpio_pullup_en(
static_cast<gpio_num_t
>(
cts_pin_));
501 gpio_input_enable(
static_cast<gpio_num_t
>(
cts_pin_));
502 esp_rom_gpio_connect_in_signal(
578 size_t active_length = 0U;
640 uart_hal_clr_intsts_mask(&
uart_hal_, UART_TX_INTR_MASK);
641 uart_hal_ena_intr_mask(&
uart_hal_, UART_TX_INTR_MASK);
653 bool pushed_any =
false;
654 while (offset < size)
662 const size_t chunk = std::min(free_space, size - offset);
size_t size_
数据字节数 / Data size in bytes
static ErrorCode ResolveUartPeriph(uart_port_t uart_num, periph_module_t &out)
Map one UART index to its peripheral module.
ErrorCode TryStartTx(bool in_isr)
Try to start queued transmit work.
ErrorCode SetConfig(UART::Configuration config) override
Apply a new UART framing and baud configuration.
UART::Configuration config_
Current UART framing configuration.
ErrorCode SetLoopback(bool enable)
Toggle UART peripheral internal loopback mode.
int rx_pin_
RX GPIO pin or PIN_NO_CHANGE.
int tx_pin_
TX GPIO pin or PIN_NO_CHANGE.
bool LoadActiveTxFromQueue(bool in_isr)
Load one active TX request from the queue.
void ConfigureRxInterruptPath()
Program RX interrupt thresholds and masks.
bool dma_requested_
Constructor preference for DMA mode.
Flag::Plain tx_busy_
Hardware TX engine currently owns the request.
bool StartActiveTransfer(bool in_isr)
Start the active request on the selected TX backend.
static ErrorCode WriteFun(WritePort &port, bool in_isr)
Queue-driven TX entry used by WritePort.
uart_hal_context_t uart_hal_
ESP-IDF UART HAL context.
bool DequeueFifoTx(size_t &size, WriteInfoBlock &info)
Claim one queued request for the FIFO TX backend.
ErrorCode InitUartHardware()
Initialize UART hardware and base HAL state.
static uart_parity_t ResolveParity(UART::Parity parity)
Convert configured parity into the HAL enum.
size_t rx_isr_buffer_size_
Size of rx_isr_buffer_.
void FillTxFifo(bool in_isr)
Drain active TX bytes into the UART FIFO backend.
ESP32UART(uart_port_t uart_num, int tx_pin, int rx_pin, int rts_pin=PIN_NO_CHANGE, int cts_pin=PIN_NO_CHANGE, size_t rx_buffer_size=1024, size_t tx_buffer_size=512, uint32_t tx_queue_size=5, UART::Configuration config={115200, UART::Parity::NO_PARITY, 8, 1}, bool enable_dma=true)
Create and initialize one ESP32 UART instance.
bool tx_active_valid_
Whether the active TX metadata is valid.
void OnTxTransferDone(bool in_isr, ErrorCode result)
Finalize one TX transfer result.
WritePort _write_port
Write-side queue bridge exposed to UART.
void DrainRxFifo(bool in_isr)
Drain pending bytes from the hardware RX FIFO.
WriteInfoBlock tx_active_info_
Metadata for the active TX request.
int cts_pin_
CTS GPIO pin or PIN_NO_CHANGE.
Flag::Plain in_tx_isr_
Reentry guard while processing TX ISR work.
bool StartAndReportActive(bool in_isr)
Start the active request and report queue completion ownership.
int rts_pin_
RTS GPIO pin or PIN_NO_CHANGE.
static ErrorCode ReadFun(ReadPort &port, bool in_isr)
Queue-driven RX entry used by ReadPort.
ESP32UARTReadPort _read_port
Read-side queue bridge exposed to UART.
UartDmaTxModel< ESP32UART > tx_dma_model_
One-shot DMA TX execution model.
void ClearActiveTx()
Clear active TX state.
static uint8_t * AllocateTxStorage(size_t size)
Allocate DMA-capable backing storage for TX buffers.
static bool ResolveStopBits(uint8_t stop_bits, uart_stop_bits_t &out)
Convert configured stop bits into the HAL enum.
uart_port_t uart_num_
Selected UART peripheral index.
size_t tx_active_offset_
Bytes already emitted for the active request.
static bool ResolveWordLength(uint8_t data_bits, uart_word_length_t &out)
Convert configured data bits into the HAL enum.
bool uart_hw_enabled_
UART hardware block was initialized.
void PushRxBytes(const uint8_t *data, size_t size, bool in_isr)
Push RX bytes into the software queue.
size_t tx_active_length_
Active TX payload length in bytes.
ErrorCode InstallUartIsr()
Install the UART interrupt handler.
ErrorCode ConfigurePins()
Configure the selected GPIO pins.
ESP32UART & owner_
所属 UART 后端 / Owning UART backend
void OnRxDequeue(bool in_isr) override
软件队列出队后的回调 / Callback after software RX dequeue
bool TestAndSet() noexcept
测试并置位:置位并返回旧状态 / Test-and-set: set and return previous state
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
void Clear() noexcept
清除标志 / Clear the flag
作用域标志管理器:构造时写入指定值,析构时恢复原值 / Scoped flag restorer: set on entry, restore on exit
可写原始数据视图 / Mutable raw data view
ReadPort class for handling read operations.
SPSCQueue< uint8_t > * queue_data_
RX payload queue. 接收数据字节队列。
void ProcessPendingReads(bool in_isr)
Processes pending reads.
size_t MaxSize() const
获取队列最大容量 / Get the maximum queue capacity
size_t EmptySize() const
获取剩余空槽数 / Get the current free-slot count
ErrorCode PushBatch(const Data *data, size_t size)
批量推入多个 payload。
通用异步收发传输(UART)基类 / Abstract base class for Universal Asynchronous Receiver-Transmitter (UART)
ReadPort * read_port_
读取端口 / Read port
Parity
奇偶校验模式 / Parity mode
@ NO_PARITY
无校验 / No parity
WritePort * write_port_
写入端口 / Write port
WritePort class for handling write operations.
void Finish(bool in_isr, ErrorCode ans, WriteInfoBlock &info)
更新写入操作的状态。 Updates the status of the write operation.
SPSCQueue< WriteInfoBlock > * queue_info_
Metadata queue for pending write batches. 挂起写批次的元数据队列。
SPSCQueue< uint8_t > * queue_data_
Payload queue for pending write bytes. 挂起写入字节的数据队列。
@ INIT_ERR
初始化错误 | Initialization error
@ STATE_ERR
状态错误 | State error
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ OK
操作成功 | Operation successful
@ ARG_ERR
参数错误 | Argument error
ErrorCode(* ReadFun)(ReadPort &port, bool in_isr)
Function pointer type for read notifications.
ErrorCode(* WriteFun)(WritePort &port, bool in_isr)
Function pointer type for write operations.
OwnerType * ContainerOf(MemberType *ptr, MemberType OwnerType::*member) noexcept
通过成员指针恢复其所属对象指针
UART 配置结构体 / UART configuration structure.
uint8_t stop_bits
停止位长度 / Number of stop bits
uint8_t data_bits
数据位长度 / Number of data bits
ConstRawData data
Data buffer. 数据缓冲区。