libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_uart.cpp
1#include "stm32_uart.hpp"
2
3#include "stm32_dcache.hpp"
4#ifdef HAL_UART_MODULE_ENABLED
5
6using namespace LibXR;
7
8STM32UART* STM32UART::map[STM32_UART_NUMBER] = {nullptr};
9
10stm32_uart_id_t stm32_uart_get_id(USART_TypeDef* addr)
11{
12 if (addr == nullptr)
13 { // NOLINT
14 return stm32_uart_id_t::STM32_UART_ID_ERROR;
15 }
16#ifdef USART1
17 else if (addr == USART1) // NOLINT
18 {
19 return stm32_uart_id_t::STM32_USART1;
20 }
21#endif
22#ifdef USART2
23 else if (addr == USART2) // NOLINT
24 {
25 return stm32_uart_id_t::STM32_USART2;
26 }
27#endif
28#ifdef USART3
29 else if (addr == USART3) // NOLINT
30 {
31 return stm32_uart_id_t::STM32_USART3;
32 }
33#endif
34#ifdef USART4
35 else if (addr == USART4) // NOLINT
36 {
37 return stm32_uart_id_t::STM32_USART4;
38 }
39#endif
40#ifdef USART5
41 else if (addr == USART5) // NOLINT
42 {
43 return stm32_uart_id_t::STM32_USART5;
44 }
45#endif
46#ifdef USART6
47 else if (addr == USART6) // NOLINT
48 {
49 return stm32_uart_id_t::STM32_USART6;
50 }
51#endif
52#ifdef USART7
53 else if (addr == USART7) // NOLINT
54 {
55 return stm32_uart_id_t::STM32_USART7;
56 }
57#endif
58#ifdef USART8
59 else if (addr == USART8) // NOLINT
60 {
61 return stm32_uart_id_t::STM32_USART8;
62 }
63#endif
64#ifdef USART9
65 else if (addr == USART9) // NOLINT
66 {
67 return stm32_uart_id_t::STM32_USART9;
68 }
69#endif
70#ifdef USART10
71 else if (addr == USART10) // NOLINT
72 {
73 return stm32_uart_id_t::STM32_USART10;
74 }
75#endif
76#ifdef USART11
77 else if (addr == USART11) // NOLINT
78 {
79 return stm32_uart_id_t::STM32_USART11;
80 }
81#endif
82#ifdef USART12
83 else if (addr == USART12) // NOLINT
84 {
85 return stm32_uart_id_t::STM32_USART12;
86 }
87#endif
88#ifdef USART13
89 else if (addr == USART13) // NOLINT
90 {
91 return stm32_uart_id_t::STM32_USART13;
92 }
93#endif
94#ifdef UART1
95 else if (addr == UART1) // NOLINT
96 {
97 return stm32_uart_id_t::STM32_UART1;
98 }
99#endif
100#ifdef UART2
101 else if (addr == UART2) // NOLINT
102 {
103 return stm32_uart_id_t::STM32_UART2;
104 }
105#endif
106#ifdef UART3
107 else if (addr == UART3) // NOLINT
108 {
109 return stm32_uart_id_t::STM32_UART3;
110 }
111#endif
112#ifdef UART4
113 else if (addr == UART4) // NOLINT
114 {
115 return stm32_uart_id_t::STM32_UART4;
116 }
117#endif
118#ifdef UART5
119 else if (addr == UART5) // NOLINT
120 {
121 return stm32_uart_id_t::STM32_UART5;
122 }
123#endif
124#ifdef UART6
125 else if (addr == UART6) // NOLINT
126 {
127 return stm32_uart_id_t::STM32_UART6;
128 }
129#endif
130#ifdef UART7
131 else if (addr == UART7) // NOLINT
132 {
133 return stm32_uart_id_t::STM32_UART7;
134 }
135#endif
136#ifdef UART8
137 else if (addr == UART8) // NOLINT
138 {
139 return stm32_uart_id_t::STM32_UART8;
140 }
141#endif
142#ifdef UART9
143 else if (addr == UART9) // NOLINT
144 {
145 return stm32_uart_id_t::STM32_UART9;
146 }
147#endif
148#ifdef UART10
149 else if (addr == UART10) // NOLINT
150 {
151 return stm32_uart_id_t::STM32_UART10;
152 }
153#endif
154#ifdef UART11
155 else if (addr == UART11) // NOLINT
156 {
157 return stm32_uart_id_t::STM32_UART11;
158 }
159#endif
160#ifdef UART12
161 else if (addr == UART12) // NOLINT
162 {
163 return stm32_uart_id_t::STM32_UART12;
164 }
165#endif
166#ifdef UART13
167 else if (addr == UART13) // NOLINT
168 {
169 return stm32_uart_id_t::STM32_UART13;
170 }
171#endif
172#ifdef LPUART1
173 else if (addr == LPUART1) // NOLINT
174 {
175 return stm32_uart_id_t::STM32_LPUART1;
176 }
177#endif
178#ifdef LPUART2
179 else if (addr == LPUART2) // NOLINT
180 {
181 return stm32_uart_id_t::STM32_LPUART2;
182 }
183#endif
184#ifdef LPUART3
185 else if (addr == LPUART3) // NOLINT
186 {
187 return stm32_uart_id_t::STM32_LPUART3;
188 }
189#endif
190 else
191 {
192 return stm32_uart_id_t::STM32_UART_ID_ERROR;
193 }
194}
195
196ErrorCode STM32UART::WriteFun(WritePort& port, bool)
197{
198 auto* uart = LibXR::ContainerOf(&port, &STM32UART::_write_port);
199
200 if (uart->in_tx_isr.IsSet())
201 {
202 return ErrorCode::PENDING;
203 }
204
205 if (!uart->dma_buff_tx_.HasPending())
206 {
207 WriteInfoBlock info;
208 if (port.queue_info_->Peek(info) != ErrorCode::OK)
209 {
210 return ErrorCode::PENDING;
211 }
212
213 uint8_t* buffer = nullptr;
214 bool use_pending = false;
215
216 if (uart->uart_handle_->gState == HAL_UART_STATE_READY)
217 {
218 buffer = reinterpret_cast<uint8_t*>(uart->dma_buff_tx_.ActiveBuffer());
219 }
220 else
221 {
222 buffer = reinterpret_cast<uint8_t*>(uart->dma_buff_tx_.PendingBuffer());
223 use_pending = true;
224 }
225
226 if (port.queue_data_->PopBatch(reinterpret_cast<uint8_t*>(buffer), info.data.size_) !=
228 {
229 ASSERT(false);
230 return ErrorCode::EMPTY;
231 }
232
233 if (use_pending)
234 {
235 uart->dma_buff_tx_.SetPendingLength(info.data.size_);
236 uart->dma_buff_tx_.EnablePending();
237 if (uart->uart_handle_->gState == HAL_UART_STATE_READY &&
238 uart->dma_buff_tx_.HasPending())
239 {
240 uart->dma_buff_tx_.Switch();
241 }
242 else
243 {
244 return ErrorCode::PENDING;
245 }
246 }
247
248 port.queue_info_->Pop(uart->write_info_active_);
249
250 STM32_CleanDCacheByAddr(uart->dma_buff_tx_.ActiveBuffer(), info.data.size_);
251
252 uart->dma_buff_tx_.SetActiveLength(info.data.size_);
253 uart->tx_busy_.Set();
254 auto ans = HAL_UART_Transmit_DMA(
255 uart->uart_handle_, static_cast<uint8_t*>(uart->dma_buff_tx_.ActiveBuffer()),
256 info.data.size_);
257
258 if (ans != HAL_OK)
259 {
260 uart->tx_busy_.Clear();
261 return ErrorCode::FAILED;
262 }
263 else
264 {
265 return ErrorCode::OK;
266 }
267 }
268
269 return ErrorCode::PENDING;
270}
271
272ErrorCode STM32UART::ReadFun(ReadPort&, bool) { return ErrorCode::PENDING; }
273
274STM32UART::STM32UART(UART_HandleTypeDef* uart_handle, RawData dma_buff_rx,
275 RawData dma_buff_tx, uint32_t tx_queue_size)
276 : UART(&_read_port, &_write_port),
277 _read_port(dma_buff_rx.size_),
278 _write_port(tx_queue_size, dma_buff_tx.size_ / 2),
279 dma_buff_rx_(dma_buff_rx),
280 dma_buff_tx_(dma_buff_tx),
281 uart_handle_(uart_handle),
282 id_(stm32_uart_get_id(uart_handle_->Instance))
283{
284 ASSERT(id_ != STM32_UART_ID_ERROR);
285
286 map[id_] = this;
287
288 if ((uart_handle->Init.Mode & UART_MODE_TX) == UART_MODE_TX)
289 {
290 ASSERT(uart_handle_->hdmatx != NULL);
291 _write_port = WriteFun;
292 }
293
294 SetRxDMA();
295}
296
298{
299 HAL_UART_DeInit(uart_handle_);
300 uart_handle_->Init.BaudRate = config.baudrate;
301
302 switch (config.parity)
303 {
305 uart_handle_->Init.Parity = UART_PARITY_NONE;
306 uart_handle_->Init.WordLength = UART_WORDLENGTH_8B;
307 break;
309 uart_handle_->Init.Parity = UART_PARITY_EVEN;
310 uart_handle_->Init.WordLength = UART_WORDLENGTH_9B;
311 break;
313 uart_handle_->Init.Parity = UART_PARITY_ODD;
314 uart_handle_->Init.WordLength = UART_WORDLENGTH_9B;
315 break;
316 default:
317 ASSERT(false);
318 }
319
320 switch (config.stop_bits)
321 {
322 case 1:
323 uart_handle_->Init.StopBits = UART_STOPBITS_1;
324 break;
325 case 2:
326 uart_handle_->Init.StopBits = UART_STOPBITS_2;
327 break;
328 default:
329 ASSERT(false);
330 }
331
332 if (HAL_UART_Init(uart_handle_) != HAL_OK)
333 {
334 return ErrorCode::INIT_ERR;
335 }
336
337 last_rx_pos_ = 0;
338
339 SetRxDMA();
340
341 if (tx_busy_.IsSet())
342 {
343 HAL_UART_Transmit_DMA(uart_handle_, dma_buff_tx_.ActiveBuffer(),
344 dma_buff_tx_.GetActiveLength());
345 }
346
347 return ErrorCode::OK;
348}
349
350void STM32UART::SetRxDMA()
351{
352 if ((uart_handle_->Init.Mode & UART_MODE_RX) == UART_MODE_RX)
353 {
354 ASSERT(uart_handle_->hdmarx != NULL);
355
356 uart_handle_->hdmarx->Init.Mode = DMA_CIRCULAR;
357 HAL_DMA_Init(uart_handle_->hdmarx);
358
359 HAL_UARTEx_ReceiveToIdle_DMA(
360 uart_handle_, reinterpret_cast<uint8_t*>(dma_buff_rx_.addr_), dma_buff_rx_.size_);
361 _read_port = ReadFun;
362 }
363}
364
365// NOLINTNEXTLINE
366static inline void STM32_UART_RX_ISR_Handler(UART_HandleTypeDef* uart_handle)
367{
368 auto uart = STM32UART::map[stm32_uart_get_id(uart_handle->Instance)];
369 auto rx_buf = static_cast<uint8_t*>(uart->dma_buff_rx_.addr_);
370 size_t dma_size = uart->dma_buff_rx_.size_;
371
372 size_t curr_pos =
373 dma_size - __HAL_DMA_GET_COUNTER(uart_handle->hdmarx); // 当前 DMA 写入位置
374 size_t last_pos = uart->last_rx_pos_;
375
376 STM32_InvalidateDCacheByAddr(rx_buf, dma_size);
377
378 if (curr_pos != last_pos)
379 {
380 if (curr_pos > last_pos)
381 {
382 // 线性接收区
383 uart->read_port_->queue_data_->PushBatch(&rx_buf[last_pos], curr_pos - last_pos);
384 }
385 else
386 {
387 // 回卷区:last→end,再从0→curr
388 uart->read_port_->queue_data_->PushBatch(&rx_buf[last_pos], dma_size - last_pos);
389 uart->read_port_->queue_data_->PushBatch(&rx_buf[0], curr_pos);
390 }
391
392 uart->last_rx_pos_ = curr_pos;
393 uart->read_port_->ProcessPendingReads(true);
394 }
395}
396
397// NOLINTNEXTLINE
398void STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_id_t id)
399{
400 auto uart = STM32UART::map[id];
401
402 uart->tx_busy_.Clear();
403
404 Flag::ScopedRestore tx_flag(uart->in_tx_isr);
405
406 size_t pending_len = uart->dma_buff_tx_.GetPendingLength();
407
408 if (pending_len == 0)
409 {
410 return;
411 }
412
413 uart->dma_buff_tx_.Switch();
414
415 STM32_CleanDCacheByAddr(uart->dma_buff_tx_.ActiveBuffer(), pending_len);
416
417 uart->dma_buff_tx_.SetActiveLength(pending_len);
418 uart->tx_busy_.Set();
419
420 auto ans = HAL_UART_Transmit_DMA(
421 uart->uart_handle_, static_cast<uint8_t*>(uart->dma_buff_tx_.ActiveBuffer()),
422 pending_len);
423
424 ASSERT(ans == HAL_OK);
425
426 WriteInfoBlock& current_info = uart->write_info_active_;
427
428 if (uart->write_port_->queue_info_->Pop(current_info) != ErrorCode::OK)
429 {
430 ASSERT(false);
431 return;
432 }
433
434 uart->write_port_->Finish(true, ans == HAL_OK ? ErrorCode::OK : ErrorCode::BUSY,
435 current_info);
436
437 WriteInfoBlock next_info;
438
439 if (uart->write_port_->queue_info_->Peek(next_info) != ErrorCode::OK)
440 {
441 return;
442 }
443
444 if (uart->write_port_->queue_data_->PopBatch(
445 reinterpret_cast<uint8_t*>(uart->dma_buff_tx_.PendingBuffer()),
446 next_info.data.size_) != ErrorCode::OK)
447 {
448 ASSERT(false);
449 return;
450 }
451
452 uart->dma_buff_tx_.SetPendingLength(next_info.data.size_);
453
454 uart->dma_buff_tx_.EnablePending();
455}
456
457extern "C" void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t)
458{
459 STM32_UART_RX_ISR_Handler(huart);
460}
461
462extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart)
463{
464 STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_get_id(huart->Instance));
465}
466
467extern "C" __attribute__((used)) void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
468{
469 HAL_UART_Abort_IT(huart);
470}
471
472extern "C" void HAL_UART_AbortCpltCallback(UART_HandleTypeDef* huart)
473{
474 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
475 uart->last_rx_pos_ = 0;
476 HAL_UARTEx_ReceiveToIdle_DMA(huart, huart->pRxBuffPtr, uart->dma_buff_rx_.size_);
477 if (uart->tx_busy_.IsSet())
478 {
479 HAL_UART_Transmit_DMA(huart, uart->dma_buff_tx_.ActiveBuffer(),
480 uart->dma_buff_tx_.GetActiveLength());
481 }
482}
483
484#endif
size_t size_
数据字节数 / Data size in bytes
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer
size_t GetActiveLength() const
获取当前活动缓冲区中准备好的数据长度 Gets the size of valid data in active buffer
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
ErrorCode PopBatch(Data *data, size_t size)
批量弹出数据 / Pops multiple elements from the queue
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
ReadPort class for handling read operations.
Definition read_port.hpp:18
STM32 UART 驱动实现 / STM32 UART driver implementation.
STM32UART(UART_HandleTypeDef *uart_handle, RawData dma_buff_rx, RawData dma_buff_tx, uint32_t tx_queue_size=5)
构造 UART 对象 / Construct UART object
ErrorCode SetConfig(UART::Configuration config)
设置 UART 配置 / Sets the UART configuration
通用异步收发传输(UART)基类 / Abstract base class for Universal Asynchronous Receiver-Transmitter (UART)
Definition uart.hpp:19
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
WritePort class for handling write operations.
LockFreeQueue< uint8_t > * queue_data_
Payload queue for pending write bytes. 挂起写入字节的数据队列。
LockFreeQueue< WriteInfoBlock > * queue_info_
Metadata queue for pending write batches. 挂起写批次的元数据队列。
LibXR 命名空间
Definition ch32_can.hpp:14
void STM32_InvalidateDCacheByAddr(const void *addr, size_t size)
Invalidates D-Cache lines covering the specified memory range.
ErrorCode
定义错误码枚举
@ INIT_ERR
初始化错误 | Initialization error
@ BUSY
忙碌 | Busy
@ FAILED
操作失败 | Operation failed
@ EMPTY
为空 | Empty
@ PENDING
等待中 | Pending
@ OK
操作成功 | Operation successful
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
通过成员指针恢复其所属对象指针
void STM32_CleanDCacheByAddr(const void *addr, size_t size)
Cleans D-Cache lines covering the specified memory range.
UART 配置结构体 / UART configuration structure.
Definition uart.hpp:44
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:50
Parity parity
校验模式 / Parity mode
Definition uart.hpp:47
uint32_t baudrate
波特率 / Baud rate
Definition uart.hpp:45
ConstRawData data
Data buffer. 数据缓冲区。