libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
esp_uart_fifo.cpp
1#include <algorithm>
2
3#include "esp_attr.h"
4#include "esp_uart.hpp"
5#include "soc/uart_periph.h"
6
7namespace
8{
9constexpr uint32_t kUartRxIntrMask =
10 UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT | UART_INTR_RXFIFO_OVF;
11constexpr uint32_t kUartTxIntrMask = UART_INTR_TXFIFO_EMPTY;
12} // namespace
13
14namespace LibXR
15{
16
17void IRAM_ATTR ESP32UART::UartIsrEntry(void* arg)
18{
19 auto* self = static_cast<ESP32UART*>(arg);
20 if (self != nullptr)
21 {
22 self->HandleUartInterrupt();
23 }
24}
25
26ErrorCode ESP32UART::InstallUartIsr()
27{
28 if (uart_isr_installed_)
29 {
30 return ErrorCode::OK;
31 }
32
33#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S3
34 // Classic ESP32/S3 can enter cache-disabled flash windows while UART IRQ is active.
35 // The current WritePort path is not fully IRAM-safe, so keep this IRQ non-IRAM.
36 constexpr int kUartIntrFlags = 0;
37#else
38 constexpr int kUartIntrFlags = ESP_INTR_FLAG_IRAM;
39#endif
40
41 const esp_err_t err = esp_intr_alloc(uart_periph_signal[uart_num_].irq, kUartIntrFlags,
42 UartIsrEntry, this, &uart_intr_handle_);
43 if (err != ESP_OK)
44 {
46 }
47
48 uart_isr_installed_ = true;
49 return ErrorCode::OK;
50}
51
52void IRAM_ATTR ESP32UART::FillTxFifo(bool in_isr)
53{
54 if (!tx_active_valid_)
55 {
56 return;
57 }
58
59#if SOC_GDMA_SUPPORTED && SOC_UHCI_SUPPORTED
60 if (dma_backend_enabled_)
61 {
62 while (tx_active_offset_ < tx_active_length_)
63 {
64 if (uart_hal_get_txfifo_len(&uart_hal_) == 0)
65 {
66 break;
67 }
68
69 uint32_t write_size = 0;
70 const uint8_t* src = tx_active_buffer_ + tx_active_offset_;
71 const uint32_t remaining =
72 static_cast<uint32_t>(tx_active_length_ - tx_active_offset_);
73
74 uart_hal_write_txfifo(&uart_hal_, src, remaining, &write_size);
75 if (write_size == 0)
76 {
77 break;
78 }
79
80 tx_active_offset_ += write_size;
81 }
82 }
83 else
84#endif
85 {
86 while (tx_active_offset_ < tx_active_length_)
87 {
88 const uint32_t fifo_space = uart_hal_get_txfifo_len(&uart_hal_);
89 if (fifo_space == 0U)
90 {
91 break;
92 }
93
94 const size_t remaining = tx_active_length_ - tx_active_offset_;
95 const size_t chunk_size = std::min<size_t>(remaining, fifo_space);
96
97 const ErrorCode pop_ec = write_port_->queue_data_->PopWithReader(
98 chunk_size,
99 [this](const uint8_t* src, size_t size) -> ErrorCode
100 {
101 uint32_t write_size = 0;
102 uart_hal_write_txfifo(&uart_hal_, src, static_cast<uint32_t>(size),
103 &write_size);
104 return (write_size == static_cast<uint32_t>(size)) ? ErrorCode::OK
106 });
107 if (pop_ec != ErrorCode::OK)
108 {
109 ASSERT(false);
110 break;
111 }
112
113 tx_active_offset_ += chunk_size;
114 }
115 }
116
117 if ((tx_active_offset_ < tx_active_length_) || !in_isr)
118 {
119 return;
120 }
121
122 uart_hal_disable_intr_mask(&uart_hal_, UART_INTR_TXFIFO_EMPTY);
123 OnTxTransferDone(true, ErrorCode::OK);
124}
125
126void IRAM_ATTR ESP32UART::DrainRxFifoFromIsr()
127{
128 bool pushed_any = false;
129 while (uart_hal_get_rxfifo_len(&uart_hal_) > 0U)
130 {
131 const size_t fifo_len = uart_hal_get_rxfifo_len(&uart_hal_);
132 const size_t write_len = std::min(fifo_len, read_port_->queue_data_->EmptySize());
133 if (write_len == 0U)
134 {
135 break;
136 }
137
138 const ErrorCode push_ec = read_port_->queue_data_->PushWithWriter(
139 write_len,
140 [this](uint8_t* buffer, size_t chunk_size) -> ErrorCode
141 {
142 int read_len = static_cast<int>(chunk_size);
143 uart_hal_read_rxfifo(&uart_hal_, buffer, &read_len);
144 return (read_len == static_cast<int>(chunk_size)) ? ErrorCode::OK
146 });
147
148 if ((push_ec == ErrorCode::FULL) || (push_ec == ErrorCode::EMPTY))
149 {
150 break;
151 }
152 if (push_ec != ErrorCode::OK)
153 {
154 ASSERT(false);
155 break;
156 }
157
158 pushed_any = true;
159 }
160
161 if (pushed_any)
162 {
164 }
165}
166
167void IRAM_ATTR ESP32UART::HandleRxInterrupt(uint32_t uart_intr_status)
168{
169 const bool has_overflow = (uart_intr_status & UART_INTR_RXFIFO_OVF) != 0U;
170 const bool has_rx_data =
171 (uart_intr_status & (UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT)) != 0U;
172
173 if (!has_overflow && !has_rx_data)
174 {
175 return;
176 }
177
178 if (has_overflow)
179 {
180 // Overrun means at least one incoming byte was dropped. Keep remaining FIFO
181 // bytes to minimize extra loss instead of resetting the whole RX FIFO.
182 uart_hal_clr_intsts_mask(&uart_hal_, UART_INTR_RXFIFO_OVF);
183 }
184
185 DrainRxFifoFromIsr();
186 uart_hal_clr_intsts_mask(&uart_hal_, UART_INTR_RXFIFO_FULL | UART_INTR_RXFIFO_TOUT);
187}
188
189void IRAM_ATTR ESP32UART::HandleTxInterrupt(uint32_t uart_intr_status)
190{
191 if ((uart_intr_status & UART_INTR_TXFIFO_EMPTY) == 0U)
192 {
193 return;
194 }
195
196 Flag::ScopedRestore tx_flag(in_tx_isr_);
197 FillTxFifo(true);
198 uart_hal_clr_intsts_mask(&uart_hal_, UART_INTR_TXFIFO_EMPTY);
199}
200
201void IRAM_ATTR ESP32UART::HandleUartInterrupt()
202{
203 uint32_t uart_intr_status = uart_hal_get_intsts_mask(&uart_hal_);
204
205 while (uart_intr_status != 0)
206 {
207 if (uart_intr_status & kUartRxIntrMask)
208 {
209 HandleRxInterrupt(uart_intr_status);
210 }
211
212 if (uart_intr_status & kUartTxIntrMask)
213 {
214 HandleTxInterrupt(uart_intr_status);
215 }
216
217 uart_intr_status = uart_hal_get_intsts_mask(&uart_hal_);
218 }
219}
220
221} // namespace LibXR
size_t EmptySize()
计算队列剩余可用空间 / Calculates the remaining available space in the queue
ErrorCode PushWithWriter(size_t size, Writer &&writer)
通过写入器回调写入固定长度数据(单生产者) / Push fixed-size data via writer callback (single producer)
ErrorCode PopWithReader(size_t size, Reader &&reader)
通过读取器回调弹出固定长度数据(单消费者) / Pop fixed-size data via reader callback (single consumer)
void ProcessPendingReads(bool in_isr)
Processes pending reads.
Definition libxr_rw.cpp:193
ReadPort * read_port_
读取端口 / Read port
Definition uart.hpp:53
WritePort * write_port_
写入端口 / Write port
Definition uart.hpp:54
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
Definition libxr_def.hpp:64
@ INIT_ERR
初始化错误 | Initialization error
@ EMPTY
为空 | Empty
@ FULL
已满 | Full
@ OK
操作成功 | Operation successful