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 rx_isr_buffer_(new uint8_t[rx_buffer_size]),
115 rx_isr_buffer_size_(rx_buffer_size),
116 tx_storage_(AllocateTxStorage(tx_buffer_size * 2)),
117 dma_requested_(enable_dma),
118 _read_port(rx_buffer_size, *this),
119 _write_port(tx_queue_size, tx_buffer_size)
125 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 const uart_sclk_t sclk = UART_SCLK_DEFAULT;
206 uart_hal_set_sclk(&
uart_hal_,
static_cast<soc_module_clk_t
>(sclk));
208 uint32_t sclk_hz = 0;
209 if ((esp_clk_tree_src_get_freq_hz(
static_cast<soc_module_clk_t
>(sclk),
210 ESP_CLK_TREE_SRC_FREQ_PRECISION_CACHED,
211 &sclk_hz) != ESP_OK) ||
222 uart_hal_set_data_bit_num(&
uart_hal_, word_length);
223 uart_hal_set_stop_bits(&
uart_hal_, stop_bits);
225 uart_hal_set_hw_flow_ctrl(&
uart_hal_, UART_HW_FLOWCTRL_DISABLE, 0);
226 uart_hal_set_mode(&
uart_hal_, UART_MODE_UART);
227 uart_hal_set_txfifo_empty_thr(&
uart_hal_, TX_EMPTY_THRESHOLD);
231 uart_hal_clr_intsts_mask(&
uart_hal_, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
233#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
234 if (dma_backend_enabled_)
246#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
247 if (dma_backend_enabled_)
254 uart_hal_clr_intsts_mask(&
uart_hal_, UART_TX_INTR_MASK);
255 uart_hal_ena_intr_mask(&
uart_hal_, UART_TX_INTR_MASK);
274 uart_ll_set_loop_back(
uart_hal_.dev, enable);
283 return uart->TryStartTx(in_isr);
298 out = UART_DATA_5_BITS;
301 out = UART_DATA_6_BITS;
304 out = UART_DATA_7_BITS;
307 out = UART_DATA_8_BITS;
321 out = UART_STOP_BITS_1;
324 out = UART_STOP_BITS_2;
338 return UART_PARITY_DISABLE;
340 return UART_PARITY_EVEN;
342 return UART_PARITY_ODD;
344 return UART_PARITY_DISABLE;
358 periph_module_t uart_module = PERIPH_MODULE_MAX;
370 periph_module_enable(uart_module);
371 periph_module_reset(uart_module);
391 uart_hal_clr_intsts_mask(&
uart_hal_, UINT32_MAX);
392 uart_hal_disable_intr_mask(&
uart_hal_, UINT32_MAX);
403 if (!GPIO_IS_VALID_OUTPUT_GPIO(
tx_pin_))
407 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(
tx_pin_));
408 esp_rom_gpio_connect_out_signal(
414 if (!GPIO_IS_VALID_GPIO(
rx_pin_))
418 gpio_input_enable(
static_cast<gpio_num_t
>(
rx_pin_));
419 esp_rom_gpio_connect_in_signal(
425 if (!GPIO_IS_VALID_OUTPUT_GPIO(
rts_pin_))
429 esp_rom_gpio_pad_select_gpio(
static_cast<uint32_t
>(
rts_pin_));
430 esp_rom_gpio_connect_out_signal(
440 gpio_pullup_en(
static_cast<gpio_num_t
>(
cts_pin_));
441 gpio_input_enable(
static_cast<gpio_num_t
>(
cts_pin_));
442 esp_rom_gpio_connect_in_signal(
463#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
464 if (dma_backend_enabled_)
503#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
526#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
544 size_t active_length = 0U;
546 uint8_t* active_buffer =
nullptr;
547#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
548 if (dma_backend_enabled_)
558#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
559 if (dma_backend_enabled_)
582#if !(SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED)
590 size_t pending_length = 0U;
609 pending_length = pending_info.
data.
size_;
622#if !(SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED)
625 if (!dma_backend_enabled_)
656#if !(SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED)
660 if (!dma_backend_enabled_)
697#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
698 if (dma_backend_enabled_)
709#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
710 if (dma_backend_enabled_)
748#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
749 if (dma_backend_enabled_)
761 uart_hal_clr_intsts_mask(&
uart_hal_, UART_TX_INTR_MASK);
762 uart_hal_ena_intr_mask(&
uart_hal_, UART_TX_INTR_MASK);
774 bool pushed_any =
false;
775 while (offset < size)
783 const size_t chunk = std::min(free_space, size - offset);
814#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
815 if (dma_backend_enabled_)
size_t size_
数据字节数 / Data size in bytes
void SetActiveLength(size_t length)
设置当前活动缓冲区的数据长度 Sets the size of the active buffer
void Reset()
重置 active/pending 状态,但保留已绑定的 backing storage Resets active/pending state while keeping bound backing ...
void SetPendingLength(size_t length)
设置备用缓冲区的数据长度 Sets the size of the pending buffer
void EnablePending()
手动启用 pending 状态 Manually sets the pending state to true
bool HasPending() const
判断是否有待切换的缓冲区 Checks whether a pending buffer is ready
size_t Size() const
获取每个缓冲区的大小(单位:字节) Gets the size of each buffer in bytes
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer
void Init(const LibXR::RawData &raw_data)
绑定连续 backing storage 并重置双缓冲状态 Binds continuous backing storage and resets double-buffer state
uint8_t * PendingBuffer() const
获取备用缓冲区的指针 Returns the pending (inactive) buffer
void Switch()
切换到备用缓冲区(若其有效) Switches to the pending buffer if it's valid
size_t GetPendingLength() const
获取 pending 缓冲区中准备好的数据长度 Gets the size of valid data in pending buffer
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.
uint8_t * tx_storage_
Backing storage for the TX half-buffers.
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.
bool LoadPendingTxFromQueue(bool in_isr)
Preload one pending TX request for DMA mode.
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.
bool StartPendingTxIfIdle(bool in_isr)
Start the current pending DMA request when TX is fully idle.
static ErrorCode ReadFun(ReadPort &port, bool in_isr)
Queue-driven RX entry used by ReadPort.
bool DequeueTxToBuffer(uint8_t *buffer, size_t &size, WriteInfoBlock &info, bool in_isr)
Dequeue one TX payload into the selected buffer.
ESP32UARTReadPort _read_port
Read-side queue bridge exposed to UART.
DoubleBuffer tx_dma_buffer_
TX double-buffer view for the DMA path.
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.
bool PromotePendingTxToActive()
Promote one preloaded DMA pending request into the active slot.
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.
void ClearPendingTx()
Clear pending TX state.
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
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 PopBatch(Data *data, size_t size)
批量弹出多个 payload。
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
Parity parity
校验模式 / Parity mode
uint8_t data_bits
数据位长度 / Number of data bits
uint32_t baudrate
波特率 / Baud rate
ConstRawData data
Data buffer. 数据缓冲区。