libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
esp_uart.cpp
1#include "esp_uart.hpp"
2
3#include <algorithm>
4#include <cstring>
5
6#include "esp_attr.h"
7#include "esp_clk_tree.h"
8#include "esp_err.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"
15
16namespace
17{
18// RX interrupt reasons handled by the FIFO receive path.
19// FIFO 接收路径处理的 RX 中断原因。
20constexpr uint32_t UART_RX_INTR_MASK =
21 UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF;
22
23// TX interrupt reason used by the FIFO transmit path.
24// FIFO 发送路径使用的 TX 中断原因。
25constexpr uint32_t UART_TX_INTR_MASK = UART_INTR_TXFIFO_EMPTY;
26
27// Use the minimum non-zero timeout so short RX tails are flushed as close as
28// possible to an idle-style boundary.
29// 使用最小非零 timeout,让短 RX 尾包尽量贴近 idle 风格边界被冲刷出来。
30constexpr uint8_t RX_TOUT_THRESHOLD = 1;
31
32// Ask for more TX bytes once the hardware FIFO drops to roughly half depth.
33// 当硬件 FIFO 下降到约一半深度时,请求补充更多 TX 字节。
34constexpr uint16_t TX_EMPTY_THRESHOLD = SOC_UART_FIFO_LEN / 2U;
35
36// This backend cannot coexist with the ESP-IDF console UART reservation.
37// 该后端不能与 ESP-IDF 的控制台 UART 占用同时存在。
38bool IsConsoleUartInUse(uart_port_t uart_num)
39{
40#if defined(CONFIG_ESP_CONSOLE_UART) && CONFIG_ESP_CONSOLE_UART
41 return static_cast<int>(uart_num) == CONFIG_ESP_CONSOLE_UART_NUM;
42#else
43 (void)uart_num;
44 return false;
45#endif
46}
47} // namespace
48
49namespace LibXR
50{
51
53{
54#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
55 if (owner_.dma_backend_enabled_)
56 {
57 return;
58 }
59#endif
60 owner_.DrainRxFifo(in_isr);
61}
62
63// Prefer aligned DMA-capable allocation first, then fall back to the broader
64// DMA-capable heap if the strict aligned allocation API is unavailable.
65// 优先使用对齐的 DMA 可访问分配;若失败,再退回到更宽松的 DMA heap。
66uint8_t* ESP32UART::AllocateTxStorage(size_t size)
67{
68 void* aligned = heap_caps_aligned_alloc(
69 4, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT);
70 if (aligned != nullptr)
71 {
72 return static_cast<uint8_t*>(aligned);
73 }
74
75 return static_cast<uint8_t*>(
76 heap_caps_malloc(size, MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA | MALLOC_CAP_8BIT));
77}
78
79// Translate the public UART index into the ESP peripheral module gate.
80// 将公开 UART 序号转换为 ESP 外设模块门控对象。
81ErrorCode ESP32UART::ResolveUartPeriph(uart_port_t uart_num, periph_module_t& out)
82{
83 switch (uart_num)
84 {
85 case UART_NUM_0:
86 out = PERIPH_UART0_MODULE;
87 return ErrorCode::OK;
88 case UART_NUM_1:
89 out = PERIPH_UART1_MODULE;
90 return ErrorCode::OK;
91#if SOC_UART_HP_NUM > 2
92 case UART_NUM_2:
93 out = PERIPH_UART2_MODULE;
94 return ErrorCode::OK;
95#endif
96 default:
98 }
99}
100
101// Construct queue plumbing first, then bind the storage into the TX
102// double-buffer view before touching hardware.
103// 先构造队列连接,再把 storage 绑定到 TX 双缓冲视图,最后再触碰硬件。
104ESP32UART::ESP32UART(uart_port_t uart_num, int tx_pin, int rx_pin, int rts_pin,
105 int cts_pin, size_t rx_buffer_size, size_t tx_buffer_size,
106 uint32_t tx_queue_size, UART::Configuration config, bool enable_dma)
107 : UART(&_read_port, &_write_port),
108 uart_num_(uart_num),
109 tx_pin_(tx_pin),
110 rx_pin_(rx_pin),
111 rts_pin_(rts_pin),
112 cts_pin_(cts_pin),
113 config_(config),
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))
122{
123 ASSERT(!IsConsoleUartInUse(uart_num_));
124 ASSERT(uart_num_ < UART_NUM_MAX);
125 ASSERT(uart_num_ < SOC_UART_HP_NUM);
126 ASSERT(rx_isr_buffer_size_ > 0);
127 ASSERT(tx_buffer_size > 0);
128
131
133 {
134 ASSERT(false);
135 return;
136 }
137
138#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
139 if (dma_requested_)
140 {
141 if (InitDmaBackend() != ErrorCode::OK)
142 {
143 ASSERT(false);
144 return;
145 }
146 }
147
148 if (!dma_backend_enabled_)
149 {
151 {
152 ASSERT(false);
153 return;
154 }
156 }
157#else
159 {
160 ASSERT(false);
161 return;
162 }
164#endif
165}
166
167// Use a half-FIFO RX threshold in FIFO mode. Short residual tails are handled
168// by the minimum non-zero RX timeout above.
169// FIFO 模式下使用半 FIFO 的 RX 阈值,剩余短尾包交给上面的最小非零 RX timeout。
171{
172 const uint16_t full_thr = static_cast<uint16_t>(SOC_UART_FIFO_LEN / 2U);
173
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);
178}
179
180// Reconfigure framing in place while preserving the current software queue
181// model. If TX is already in progress, resume the backend instead of surfacing
182// a synthetic BUSY state.
183// 原地重配帧格式,同时保持软件队列模型不变。若 TX 已在进行,则恢复后端,
184// 而不是人为抛出 BUSY 状态。
186{
187 if (!uart_hw_enabled_)
188 {
190 }
191
192 uart_word_length_t word_length = UART_DATA_8_BITS;
193 uart_stop_bits_t stop_bits = UART_STOP_BITS_1;
194
195 if (!ResolveWordLength(config.data_bits, word_length))
196 {
197 return ErrorCode::ARG_ERR;
198 }
199
200 if (!ResolveStopBits(config.stop_bits, stop_bits))
201 {
202 return ErrorCode::ARG_ERR;
203 }
204
205 requested_config_.Store(config);
206 tx_dma_model_.RequestConfig(false);
207 return ErrorCode::OK;
208}
209
210void ESP32UART::OnConfigRequested() { rx_config_gate_.RequestConfig(); }
211
212bool ESP32UART::ApplyPendingConfig(bool in_isr)
213{
214 if (!rx_config_gate_.TryEnterConfig())
215 {
216 return false;
217 }
218
219 UART::Configuration config{};
220 (void)requested_config_.LoadLatest(config);
221
222 uart_word_length_t word_length = UART_DATA_8_BITS;
223 uart_stop_bits_t stop_bits = UART_STOP_BITS_1;
224 if (!ResolveWordLength(config.data_bits, word_length) ||
225 !ResolveStopBits(config.stop_bits, stop_bits))
226 {
227 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
228 return true;
229 }
230
231#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
232 if (dma_backend_enabled_ && (tx_dma_channel_ != nullptr))
233 {
234 gdma_stop(tx_dma_channel_);
235 gdma_reset(tx_dma_channel_);
236 }
237#endif
238
239 bool dma_backend_enabled = false;
240#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
241 dma_backend_enabled = dma_backend_enabled_;
242#endif
243 if (!dma_backend_enabled)
244 {
245 uart_hal_disable_intr_mask(&uart_hal_, UART_TX_INTR_MASK);
246 tx_busy_.Clear();
248 }
249
250 const uart_sclk_t sclk = UART_SCLK_DEFAULT;
251 uart_hal_set_sclk(&uart_hal_, static_cast<soc_module_clk_t>(sclk));
252
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) ||
257 (sclk_hz == 0))
258 {
259 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
260 return true;
261 }
262
263#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 5, 0)
264 if (!uart_hal_set_baudrate(&uart_hal_, config.baudrate, sclk_hz))
265 {
266 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
267 return true;
268 }
269#else
270 uart_hal_set_baudrate(&uart_hal_, config.baudrate, sclk_hz);
271#endif
272
273 uart_hal_set_data_bit_num(&uart_hal_, word_length);
274 uart_hal_set_stop_bits(&uart_hal_, stop_bits);
275 uart_hal_set_parity(&uart_hal_, ResolveParity(config.parity));
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);
279 // Drop stale hardware RX FIFO bytes from the previous baud.
280 // Keep software read queue semantics aligned with ST/CH (no read_port reset).
281 uart_hal_rxfifo_rst(&uart_hal_);
282 uart_hal_clr_intsts_mask(&uart_hal_, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
283
284#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
285 if (dma_backend_enabled_)
286 {
287 // Re-align the circular RX DMA window after reconfig to avoid
288 // carrying stale pre-switch bytes into the next frame.
289 HandleDmaRxError();
290 }
291#endif
292
293 config_ = config;
294 return true;
295}
296
297bool ESP32UART::OnConfigApplied(bool in_isr)
298{
299 rx_config_gate_.LeaveConfig();
300#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
301 if (dma_backend_enabled_)
302 {
303 return true;
304 }
305#endif
306 (void)TryStartTx(in_isr);
307 return false;
308}
309
310#if !(SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED)
311bool ESP32UART::StartDmaTx(uint8_t*, size_t, int) { return false; }
312#endif
313
314// Internal UART loopback is exposed as a direct peripheral toggle for backend
315// self-test and board-free link checks.
316// UART 内部环回直接作为外设开关暴露,用于后端自测和无需外部短接的链路检查。
318{
319 if (!uart_hw_enabled_)
320 {
322 }
323
324 uart_ll_set_loop_back(uart_hal_.dev, enable);
325 return ErrorCode::OK;
326}
327
328// `WritePort` only needs a trampoline back into the owning UART instance.
329// `WritePort` 只需要一个回跳到所属 UART 实例的跳板。
330ErrorCode IRAM_ATTR ESP32UART::WriteFun(WritePort& port, bool in_isr)
331{
332 auto* uart = LibXR::ContainerOf(&port, &ESP32UART::_write_port);
333#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
334 if (uart->dma_backend_enabled_)
335 {
336 return uart->tx_dma_model_.Submit(in_isr);
337 }
338#endif
339 if (uart->rx_config_gate_.ConfigRequested())
340 {
341 return ErrorCode::PENDING;
342 }
343 return uart->TryStartTx(in_isr);
344}
345
346// RX is interrupt-driven. Publishing a read waiter does not need any extra
347// backend kick here.
348// RX 由中断驱动,因此这里只需要表明:发布读 waiter 时不需要额外 kick 后端。
350
351// Convert libxr data-bit semantics into the ESP HAL value set.
352// 将 libxr 数据位语义转换为 ESP HAL 取值。
353bool ESP32UART::ResolveWordLength(uint8_t data_bits, uart_word_length_t& out)
354{
355 switch (data_bits)
356 {
357 case 5:
358 out = UART_DATA_5_BITS;
359 return true;
360 case 6:
361 out = UART_DATA_6_BITS;
362 return true;
363 case 7:
364 out = UART_DATA_7_BITS;
365 return true;
366 case 8:
367 out = UART_DATA_8_BITS;
368 return true;
369 default:
370 return false;
371 }
372}
373
374// Convert libxr stop-bit semantics into the ESP HAL value set.
375// 将 libxr 停止位语义转换为 ESP HAL 取值。
376bool ESP32UART::ResolveStopBits(uint8_t stop_bits, uart_stop_bits_t& out)
377{
378 switch (stop_bits)
379 {
380 case 1:
381 out = UART_STOP_BITS_1;
382 return true;
383 case 2:
384 out = UART_STOP_BITS_2;
385 return true;
386 default:
387 return false;
388 }
389}
390
391// Convert libxr parity semantics into the ESP HAL value set.
392// 将 libxr 校验位语义转换为 ESP HAL 取值。
394{
395 switch (parity)
396 {
398 return UART_PARITY_DISABLE;
400 return UART_PARITY_EVEN;
402 return UART_PARITY_ODD;
403 default:
404 return UART_PARITY_DISABLE;
405 }
406}
407
408// Bring the UART block into a known idle state before higher-level ISR or DMA
409// plumbing is attached.
410// 在挂接更高层 ISR 或 DMA 连接前,先把 UART 模块拉到已知空闲状态。
412{
413 if (uart_num_ >= UART_NUM_MAX)
414 {
416 }
417
418 periph_module_t uart_module = PERIPH_MODULE_MAX;
419 if (ResolveUartPeriph(uart_num_, uart_module) != ErrorCode::OK)
420 {
422 }
423
424 uart_hal_.dev = UART_LL_GET_HW(uart_num_);
425 if (uart_hal_.dev == nullptr)
426 {
428 }
429
430 periph_module_enable(uart_module);
431 periph_module_reset(uart_module);
432
433 uart_ll_sclk_enable(uart_hal_.dev);
434 uart_hal_init(&uart_hal_, uart_num_);
435
436 uart_hw_enabled_ = true;
438 {
439 uart_hw_enabled_ = false;
440 return ErrorCode::INIT_ERR;
441 }
442
444 {
445 uart_hw_enabled_ = false;
446 return ErrorCode::INIT_ERR;
447 }
448
449 uart_hal_txfifo_rst(&uart_hal_);
450 uart_hal_rxfifo_rst(&uart_hal_);
451 uart_hal_clr_intsts_mask(&uart_hal_, UINT32_MAX);
452 uart_hal_disable_intr_mask(&uart_hal_, UINT32_MAX);
453
454 return ErrorCode::OK;
455}
456
457// GPIO mapping stays explicit because ESP UART routing is per-pin configurable.
458// GPIO 映射保持显式写法,因为 ESP UART 路由是逐引脚可配置的。
460{
461 if (tx_pin_ >= 0)
462 {
463 if (!GPIO_IS_VALID_OUTPUT_GPIO(tx_pin_))
464 {
465 return ErrorCode::ARG_ERR;
466 }
467 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(tx_pin_));
468 esp_rom_gpio_connect_out_signal(
469 tx_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_TX_PIN_IDX), false, false);
470 }
471
472 if (rx_pin_ >= 0)
473 {
474 if (!GPIO_IS_VALID_GPIO(rx_pin_))
475 {
476 return ErrorCode::ARG_ERR;
477 }
478 gpio_input_enable(static_cast<gpio_num_t>(rx_pin_));
479 esp_rom_gpio_connect_in_signal(
480 rx_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_RX_PIN_IDX), false);
481 }
482
483 if (rts_pin_ >= 0)
484 {
485 if (!GPIO_IS_VALID_OUTPUT_GPIO(rts_pin_))
486 {
487 return ErrorCode::ARG_ERR;
488 }
489 esp_rom_gpio_pad_select_gpio(static_cast<uint32_t>(rts_pin_));
490 esp_rom_gpio_connect_out_signal(
491 rts_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_RTS_PIN_IDX), false, false);
492 }
493
494 if (cts_pin_ >= 0)
495 {
496 if (!GPIO_IS_VALID_GPIO(cts_pin_))
497 {
498 return ErrorCode::ARG_ERR;
499 }
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(
503 cts_pin_, UART_PERIPH_SIGNAL(uart_num_, SOC_UART_CTS_PIN_IDX), false);
504 }
505
506 return ErrorCode::OK;
507}
508
509// Active state is shared by FIFO and DMA TX backends.
510// Active 状态由 FIFO 和 DMA 两条 TX 后端共用。
512{
515 tx_active_info_ = {};
516 tx_active_valid_ = false;
517}
518
519// Once hardware accepts the active request, completion ownership moves to the
520// backend ISR path and the queued write can be reported as accepted.
521// 一旦硬件接管 active 请求,完成所有权就转移到后端 ISR 路径,队列侧即可
522// 报告该写请求已经被接受。
523bool IRAM_ATTR ESP32UART::StartAndReportActive(bool in_isr)
524{
525 if (!StartActiveTransfer(in_isr))
526 {
529 return false;
530 }
531
532 // Align with STM/CH semantics: once the active write is kicked to HW,
533 // WritePort owns the completion notification and the ISR only advances queues.
535 return true;
536}
537
538// TX start only does two things:
539// 1. when TX is fully idle, start one active request;
540// 2. when DMA TX is busy and no pending request is preloaded yet, preload one.
541// TX 发起路径只做两件事:
542// 1. TX 完全空闲时,启动一个 active 请求;
543// 2. DMA TX 已忙且还没有预装 pending 时,补装一个。
544ErrorCode IRAM_ATTR ESP32UART::TryStartTx(bool in_isr)
545{
546 if (in_tx_isr_.IsSet())
547 {
548 return ErrorCode::PENDING;
549 }
550
551 if (!tx_active_valid_)
552 {
553 (void)LoadActiveTxFromQueue(in_isr);
554 }
555
557 {
558 if (!StartActiveTransfer(in_isr))
559 {
561 return ErrorCode::FAILED;
562 }
563
564 return ErrorCode::OK;
565 }
566
567 return ErrorCode::PENDING;
568}
569
570// Active TX load is shared by both backends. DMA writes payload bytes into the
571// double buffer, while FIFO mode only claims metadata and length.
572// Active TX 装载由两条后端共用。DMA 会把 payload 写进双缓冲;FIFO 模式只
573// 认领元数据和长度。
574bool IRAM_ATTR ESP32UART::LoadActiveTxFromQueue(bool in_isr)
575{
576 (void)in_isr;
577
578 size_t active_length = 0U;
579 WriteInfoBlock active_info = {};
580 if (!DequeueFifoTx(active_length, active_info))
581 {
582 return false;
583 }
584
585 tx_active_length_ = active_length;
587 tx_active_info_ = active_info;
588 tx_active_valid_ = true;
589 return true;
590}
591
592// Queue-data and queue-info stay decoupled, so dequeue first validates the
593// next metadata entry and only then moves bytes or ownership forward.
594// `queue_data_` 和 `queue_info_` 保持解耦,因此这里先验证下一条元数据,
595// 再推进字节或所有权。
596bool IRAM_ATTR ESP32UART::DequeueFifoTx(size_t& size, WriteInfoBlock& info)
597{
598 WriteInfoBlock peek_info = {};
599 if (write_port_->queue_info_->Peek(peek_info) != ErrorCode::OK)
600 {
601 return false;
602 }
603
604 size_t max_size = write_port_->queue_data_->MaxSize();
605 if (peek_info.data.size_ > max_size)
606 {
607 ASSERT(false);
608 return false;
609 }
610
611 if (write_port_->queue_info_->Pop(info) != ErrorCode::OK)
612 {
613 return false;
614 }
615
616 size = peek_info.data.size_;
617 return true;
618}
619
620// Backend start forks here:
621// - DMA path launches the staged active payload as one DMA transfer.
622// - FIFO path enables TX-empty interrupts and lets ISR-side refill drain data.
623// 后端启动在这里分叉:
624// - DMA 路径把已暂存的 active payload 作为一次 DMA 传输发出去。
625// - FIFO 路径开启 TX-empty 中断,让 ISR 侧补料并持续排空。
627{
628 if (!tx_active_valid_)
629 {
630 return false;
631 }
632
633 if (tx_busy_.TestAndSet())
634 {
635 return true;
636 }
637
639
640 uart_hal_clr_intsts_mask(&uart_hal_, UART_TX_INTR_MASK);
641 uart_hal_ena_intr_mask(&uart_hal_, UART_TX_INTR_MASK);
642 FillTxFifo(false);
643
644 return true;
645}
646
647// RX bytes are pushed opportunistically until the software queue is full, then
648// pending read callbacks are serviced once per batch.
649// RX 字节会尽量推进软件队列,直到队列满;完成后按批次触发待读回调。
650void IRAM_ATTR ESP32UART::PushRxBytes(const uint8_t* data, size_t size, bool in_isr)
651{
652 size_t offset = 0;
653 bool pushed_any = false;
654 while (offset < size)
655 {
656 const size_t free_space = read_port_->queue_data_->EmptySize();
657 if (free_space == 0)
658 {
659 break;
660 }
661
662 const size_t chunk = std::min(free_space, size - offset);
663 if (read_port_->queue_data_->PushBatch(data + offset, chunk) != ErrorCode::OK)
664 {
665 break;
666 }
667
668 offset += chunk;
669 pushed_any = true;
670 }
671
672 if (pushed_any)
673 {
675 }
676}
677
678// Completion does the complementary TX handoff work:
679// - if DMA has no pending request, TX is done here;
680// - if DMA has one pending request, start it and then try to preload the next one;
681// - FIFO mode directly loads and starts the next active request.
682// 完成路径负责与发起路径互补的交接工作:
683// - DMA 若没有 pending,请求链在这里结束;
684// - DMA 若有一个 pending,就先启动它,再尝试补装下一个;
685// - FIFO 模式则直接装载并启动下一个 active 请求。
686void IRAM_ATTR ESP32UART::OnTxTransferDone(bool in_isr, ErrorCode result)
687{
689 tx_busy_.Clear();
690
692
693 if (result != ErrorCode::OK)
694 {
695 return;
696 }
697
698 if (LoadActiveTxFromQueue(in_isr))
699 {
700 (void)StartAndReportActive(in_isr);
701 }
702}
703
704} // namespace LibXR
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.
Definition esp_uart.cpp:81
ErrorCode TryStartTx(bool in_isr)
Try to start queued transmit work.
Definition esp_uart.cpp:544
ErrorCode SetConfig(UART::Configuration config) override
Apply a new UART framing and baud configuration.
Definition esp_uart.cpp:185
UART::Configuration config_
Current UART framing configuration.
Definition esp_uart.hpp:340
ErrorCode SetLoopback(bool enable)
Toggle UART peripheral internal loopback mode.
Definition esp_uart.cpp:317
int rx_pin_
RX GPIO pin or PIN_NO_CHANGE.
Definition esp_uart.hpp:336
int tx_pin_
TX GPIO pin or PIN_NO_CHANGE.
Definition esp_uart.hpp:335
bool LoadActiveTxFromQueue(bool in_isr)
Load one active TX request from the queue.
Definition esp_uart.cpp:574
void ConfigureRxInterruptPath()
Program RX interrupt thresholds and masks.
Definition esp_uart.cpp:170
bool dma_requested_
Constructor preference for DMA mode.
Definition esp_uart.hpp:359
Flag::Plain tx_busy_
Hardware TX engine currently owns the request.
Definition esp_uart.hpp:352
bool StartActiveTransfer(bool in_isr)
Start the active request on the selected TX backend.
Definition esp_uart.cpp:626
static ErrorCode WriteFun(WritePort &port, bool in_isr)
Queue-driven TX entry used by WritePort.
Definition esp_uart.cpp:330
uart_hal_context_t uart_hal_
ESP-IDF UART HAL context.
Definition esp_uart.hpp:356
bool DequeueFifoTx(size_t &size, WriteInfoBlock &info)
Claim one queued request for the FIFO TX backend.
Definition esp_uart.cpp:596
ErrorCode InitUartHardware()
Initialize UART hardware and base HAL state.
Definition esp_uart.cpp:411
static uart_parity_t ResolveParity(UART::Parity parity)
Convert configured parity into the HAL enum.
Definition esp_uart.cpp:393
size_t rx_isr_buffer_size_
Size of rx_isr_buffer_.
Definition esp_uart.hpp:345
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.
Definition esp_uart.cpp:104
bool tx_active_valid_
Whether the active TX metadata is valid.
Definition esp_uart.hpp:351
void OnTxTransferDone(bool in_isr, ErrorCode result)
Finalize one TX transfer result.
Definition esp_uart.cpp:686
WritePort _write_port
Write-side queue bridge exposed to UART.
Definition esp_uart.hpp:362
void DrainRxFifo(bool in_isr)
Drain pending bytes from the hardware RX FIFO.
WriteInfoBlock tx_active_info_
Metadata for the active TX request.
Definition esp_uart.hpp:348
int cts_pin_
CTS GPIO pin or PIN_NO_CHANGE.
Definition esp_uart.hpp:338
Flag::Plain in_tx_isr_
Reentry guard while processing TX ISR work.
Definition esp_uart.hpp:353
bool StartAndReportActive(bool in_isr)
Start the active request and report queue completion ownership.
Definition esp_uart.cpp:523
int rts_pin_
RTS GPIO pin or PIN_NO_CHANGE.
Definition esp_uart.hpp:337
static ErrorCode ReadFun(ReadPort &port, bool in_isr)
Queue-driven RX entry used by ReadPort.
Definition esp_uart.cpp:349
ESP32UARTReadPort _read_port
Read-side queue bridge exposed to UART.
Definition esp_uart.hpp:361
UartDmaTxModel< ESP32UART > tx_dma_model_
One-shot DMA TX execution model.
Definition esp_uart.hpp:363
void ClearActiveTx()
Clear active TX state.
Definition esp_uart.cpp:511
static uint8_t * AllocateTxStorage(size_t size)
Allocate DMA-capable backing storage for TX buffers.
Definition esp_uart.cpp:66
static bool ResolveStopBits(uint8_t stop_bits, uart_stop_bits_t &out)
Convert configured stop bits into the HAL enum.
Definition esp_uart.cpp:376
uart_port_t uart_num_
Selected UART peripheral index.
Definition esp_uart.hpp:334
size_t tx_active_offset_
Bytes already emitted for the active request.
Definition esp_uart.hpp:350
static bool ResolveWordLength(uint8_t data_bits, uart_word_length_t &out)
Convert configured data bits into the HAL enum.
Definition esp_uart.cpp:353
bool uart_hw_enabled_
UART hardware block was initialized.
Definition esp_uart.hpp:355
void PushRxBytes(const uint8_t *data, size_t size, bool in_isr)
Push RX bytes into the software queue.
Definition esp_uart.cpp:650
size_t tx_active_length_
Active TX payload length in bytes.
Definition esp_uart.hpp:349
ErrorCode InstallUartIsr()
Install the UART interrupt handler.
ErrorCode ConfigurePins()
Configure the selected GPIO pins.
Definition esp_uart.cpp:459
ESP32UART & owner_
所属 UART 后端 / Owning UART backend
Definition esp_uart.hpp:66
void OnRxDequeue(bool in_isr) override
软件队列出队后的回调 / Callback after software RX dequeue
Definition esp_uart.cpp:52
bool TestAndSet() noexcept
测试并置位:置位并返回旧状态 / Test-and-set: set and return previous state
Definition flag.hpp:146
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
Definition flag.hpp:138
void Clear() noexcept
清除标志 / Clear the flag
Definition flag.hpp:130
作用域标志管理器:构造时写入指定值,析构时恢复原值 / Scoped flag restorer: set on entry, restore on exit
Definition flag.hpp:199
可写原始数据视图 / Mutable raw data view
ReadPort class for handling read operations.
Definition read_port.hpp:18
SPSCQueue< uint8_t > * queue_data_
RX payload queue. 接收数据字节队列。
Definition read_port.hpp:55
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)
Definition uart.hpp:19
ReadPort * read_port_
读取端口 / Read port
Definition uart.hpp:53
Parity
奇偶校验模式 / Parity mode
Definition uart.hpp:29
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
WritePort * write_port_
写入端口 / Write port
Definition uart.hpp:54
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. 挂起写入字节的数据队列。
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ INIT_ERR
初始化错误 | Initialization error
@ STATE_ERR
状态错误 | State error
@ NOT_SUPPORT
不支持 | Not supported
@ FAILED
操作失败 | Operation failed
@ PENDING
等待中 | Pending
@ 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.
Definition uart.hpp:44
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:50
uint8_t data_bits
数据位长度 / Number of data bits
Definition uart.hpp:48
ConstRawData data
Data buffer. 数据缓冲区。