libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
stm32_uart.cpp
1#include "stm32_uart.hpp"
2
3#ifdef HAL_UART_MODULE_ENABLED
4
5using namespace LibXR;
6
7STM32UART* STM32UART::map[STM32_UART_NUMBER] = {nullptr};
8
9stm32_uart_id_t stm32_uart_get_id(USART_TypeDef* addr)
10{
11 if (addr == nullptr)
12 { // NOLINT
13 return stm32_uart_id_t::STM32_UART_ID_ERROR;
14 }
15#ifdef USART1
16 else if (addr == USART1) // NOLINT
17 {
18 return stm32_uart_id_t::STM32_USART1;
19 }
20#endif
21#ifdef USART2
22 else if (addr == USART2) // NOLINT
23 {
24 return stm32_uart_id_t::STM32_USART2;
25 }
26#endif
27#ifdef USART3
28 else if (addr == USART3) // NOLINT
29 {
30 return stm32_uart_id_t::STM32_USART3;
31 }
32#endif
33#ifdef USART4
34 else if (addr == USART4) // NOLINT
35 {
36 return stm32_uart_id_t::STM32_USART4;
37 }
38#endif
39#ifdef USART5
40 else if (addr == USART5) // NOLINT
41 {
42 return stm32_uart_id_t::STM32_USART5;
43 }
44#endif
45#ifdef USART6
46 else if (addr == USART6) // NOLINT
47 {
48 return stm32_uart_id_t::STM32_USART6;
49 }
50#endif
51#ifdef USART7
52 else if (addr == USART7) // NOLINT
53 {
54 return stm32_uart_id_t::STM32_USART7;
55 }
56#endif
57#ifdef USART8
58 else if (addr == USART8) // NOLINT
59 {
60 return stm32_uart_id_t::STM32_USART8;
61 }
62#endif
63#ifdef USART9
64 else if (addr == USART9) // NOLINT
65 {
66 return stm32_uart_id_t::STM32_USART9;
67 }
68#endif
69#ifdef USART10
70 else if (addr == USART10) // NOLINT
71 {
72 return stm32_uart_id_t::STM32_USART10;
73 }
74#endif
75#ifdef USART11
76 else if (addr == USART11) // NOLINT
77 {
78 return stm32_uart_id_t::STM32_USART11;
79 }
80#endif
81#ifdef USART12
82 else if (addr == USART12) // NOLINT
83 {
84 return stm32_uart_id_t::STM32_USART12;
85 }
86#endif
87#ifdef USART13
88 else if (addr == USART13) // NOLINT
89 {
90 return stm32_uart_id_t::STM32_USART13;
91 }
92#endif
93#ifdef UART1
94 else if (addr == UART1) // NOLINT
95 {
96 return stm32_uart_id_t::STM32_UART1;
97 }
98#endif
99#ifdef UART2
100 else if (addr == UART2) // NOLINT
101 {
102 return stm32_uart_id_t::STM32_UART2;
103 }
104#endif
105#ifdef UART3
106 else if (addr == UART3) // NOLINT
107 {
108 return stm32_uart_id_t::STM32_UART3;
109 }
110#endif
111#ifdef UART4
112 else if (addr == UART4) // NOLINT
113 {
114 return stm32_uart_id_t::STM32_UART4;
115 }
116#endif
117#ifdef UART5
118 else if (addr == UART5) // NOLINT
119 {
120 return stm32_uart_id_t::STM32_UART5;
121 }
122#endif
123#ifdef UART6
124 else if (addr == UART6) // NOLINT
125 {
126 return stm32_uart_id_t::STM32_UART6;
127 }
128#endif
129#ifdef UART7
130 else if (addr == UART7) // NOLINT
131 {
132 return stm32_uart_id_t::STM32_UART7;
133 }
134#endif
135#ifdef UART8
136 else if (addr == UART8) // NOLINT
137 {
138 return stm32_uart_id_t::STM32_UART8;
139 }
140#endif
141#ifdef UART9
142 else if (addr == UART9) // NOLINT
143 {
144 return stm32_uart_id_t::STM32_UART9;
145 }
146#endif
147#ifdef UART10
148 else if (addr == UART10) // NOLINT
149 {
150 return stm32_uart_id_t::STM32_UART10;
151 }
152#endif
153#ifdef UART11
154 else if (addr == UART11) // NOLINT
155 {
156 return stm32_uart_id_t::STM32_UART11;
157 }
158#endif
159#ifdef UART12
160 else if (addr == UART12) // NOLINT
161 {
162 return stm32_uart_id_t::STM32_UART12;
163 }
164#endif
165#ifdef UART13
166 else if (addr == UART13) // NOLINT
167 {
168 return stm32_uart_id_t::STM32_UART13;
169 }
170#endif
171#ifdef LPUART1
172 else if (addr == LPUART1) // NOLINT
173 {
174 return stm32_uart_id_t::STM32_LPUART1;
175 }
176#endif
177#ifdef LPUART2
178 else if (addr == LPUART2) // NOLINT
179 {
180 return stm32_uart_id_t::STM32_LPUART2;
181 }
182#endif
183#ifdef LPUART3
184 else if (addr == LPUART3) // NOLINT
185 {
186 return stm32_uart_id_t::STM32_LPUART3;
187 }
188#endif
189 else
190 {
191 return stm32_uart_id_t::STM32_UART_ID_ERROR;
192 }
193}
194
195ErrorCode STM32UART::WriteFun(WritePort& port, bool in_isr)
196{
197 auto* uart = LibXR::ContainerOf(&port, &STM32UART::_write_port);
198 return uart->tx_dma_model_.Submit(in_isr);
199}
200
201ErrorCode STM32UART::ReadFun(ReadPort&, bool) { return ErrorCode::PENDING; }
202
203static UART::Configuration STM32_UART_GetConfig(UART_HandleTypeDef* handle)
204{
206 if (handle->Init.Parity == UART_PARITY_EVEN)
207 {
208 parity = UART::Parity::EVEN;
209 }
210 else if (handle->Init.Parity == UART_PARITY_ODD)
211 {
212 parity = UART::Parity::ODD;
213 }
214
215 return UART::Configuration{
216 handle->Init.BaudRate, parity, 8U,
217 static_cast<uint8_t>(handle->Init.StopBits == UART_STOPBITS_2 ? 2U : 1U)};
218}
219
220STM32UART::STM32UART(UART_HandleTypeDef* uart_handle, RawData dma_buff_rx,
221 RawData dma_buff_tx, uint32_t tx_queue_size)
222 : UART(&_read_port, &_write_port),
223 _read_port(dma_buff_rx.size_),
224 _write_port(tx_queue_size, dma_buff_tx.size_ / 2),
225 requested_config_(STM32_UART_GetConfig(uart_handle)),
226 rx_dma_model_(dma_buff_rx),
227 tx_dma_model_(*this, _write_port, dma_buff_tx),
228 uart_handle_(uart_handle),
229 id_(stm32_uart_get_id(uart_handle_->Instance))
230{
231 ASSERT(id_ != STM32_UART_ID_ERROR);
232
233 map[id_] = this;
234
235 if ((uart_handle->Init.Mode & UART_MODE_TX) == UART_MODE_TX)
236 {
237 ASSERT(uart_handle_->hdmatx != NULL);
238 _write_port = WriteFun;
239 }
240
241 SetRxDMA();
242}
243
245{
246 if ((config.stop_bits != 1U) && (config.stop_bits != 2U))
247 {
248 return ErrorCode::ARG_ERR;
249 }
250 if ((config.parity != UART::Parity::NO_PARITY) &&
251 (config.parity != UART::Parity::EVEN) && (config.parity != UART::Parity::ODD))
252 {
253 return ErrorCode::ARG_ERR;
254 }
255
256 requested_config_.Store(config);
257 tx_dma_model_.RequestConfig(false);
258 return ErrorCode::OK;
259}
260
261bool STM32UART::ApplyPendingConfig(bool in_isr)
262{
263 if (!rx_config_gate_.TryEnterConfig())
264 {
265 return false;
266 }
267
268 UART::Configuration config{};
269 (void)requested_config_.LoadLatest(config);
270
271 HAL_UART_DeInit(uart_handle_);
272 uart_handle_->Init.BaudRate = config.baudrate;
273
274 switch (config.parity)
275 {
277 uart_handle_->Init.Parity = UART_PARITY_NONE;
278 uart_handle_->Init.WordLength = UART_WORDLENGTH_8B;
279 break;
281 uart_handle_->Init.Parity = UART_PARITY_EVEN;
282 uart_handle_->Init.WordLength = UART_WORDLENGTH_9B;
283 break;
285 uart_handle_->Init.Parity = UART_PARITY_ODD;
286 uart_handle_->Init.WordLength = UART_WORDLENGTH_9B;
287 break;
288 default:
289 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
290 return true;
291 }
292
293 switch (config.stop_bits)
294 {
295 case 1:
296 uart_handle_->Init.StopBits = UART_STOPBITS_1;
297 break;
298 case 2:
299 uart_handle_->Init.StopBits = UART_STOPBITS_2;
300 break;
301 default:
302 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
303 return true;
304 }
305
306 if (HAL_UART_Init(uart_handle_) != HAL_OK)
307 {
308 DEV_ASSERT_FROM_CALLBACK(false, in_isr);
309 return true;
310 }
311
312 SetRxDMA();
313 return true;
314}
315
316void STM32UART::SetRxDMA()
317{
318 if ((uart_handle_->Init.Mode & UART_MODE_RX) == UART_MODE_RX)
319 {
320 ASSERT(uart_handle_->hdmarx != NULL);
321
322 rx_dma_model_.Start(*this);
323 _read_port = ReadFun;
324 }
325}
326
327// NOLINTNEXTLINE
328static inline void STM32_UART_RX_ISR_Handler(UART_HandleTypeDef* uart_handle)
329{
330 auto uart = STM32UART::map[stm32_uart_get_id(uart_handle->Instance)];
331 uart->OnRxDataAvailable(true);
332}
333
334void STM32UART::OnRxDataAvailable(bool in_isr)
335{
336 if (!rx_config_gate_.TryEnterRx())
337 {
338 return;
339 }
340
341 rx_dma_model_.OnDataAvailable(*this, _read_port, in_isr);
342 if (rx_config_gate_.LeaveRx())
343 {
344 tx_dma_model_.RequestConfig(in_isr);
345 }
346}
347
348// NOLINTNEXTLINE
349void STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_id_t id)
350{
351 auto uart = STM32UART::map[id];
352 uart->tx_dma_model_.OnTransferDone(true);
353}
354
355extern "C" void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef* huart, uint16_t)
356{
357 STM32_UART_RX_ISR_Handler(huart);
358}
359
360extern "C" void HAL_UART_TxCpltCallback(UART_HandleTypeDef* huart)
361{
362 STM32_UART_ISR_Handler_TX_CPLT(stm32_uart_get_id(huart->Instance));
363}
364
365extern "C" __attribute__((used)) void HAL_UART_ErrorCallback(UART_HandleTypeDef* huart)
366{
367 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
368 uart->tx_dma_model_.RequestConfig(true);
369}
370
371extern "C" void HAL_UART_AbortCpltCallback(UART_HandleTypeDef* huart)
372{
373 auto uart = STM32UART::map[stm32_uart_get_id(huart->Instance)];
374 uart->tx_dma_model_.RequestConfig(true);
375}
376
377bool STM32UART::StartDmaTx(uint8_t* data, size_t size, int)
378{
379 STM32_CleanDCacheByAddr(data, size);
380 return HAL_UART_Transmit_DMA(uart_handle_, data, size) == HAL_OK;
381}
382
383#endif
可写原始数据视图 / Mutable raw data view
ReadPort class for handling read operations.
Definition read_port.hpp:18
STM32 UART 驱动实现 / STM32 UART driver implementation.
bool StartDmaTx(uint8_t *data, size_t size, int block)
通过 STM32 HAL 启动一个 active UART TX DMA 载荷 / Start one active UART TX DMA payload through STM32 HAL
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
Parity
奇偶校验模式 / Parity mode
Definition uart.hpp:29
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
void OnDataAvailable(Backend &backend, ReadPort &port, bool in_isr)
消费上次 DMA 事件后新产生的数据 / Consume bytes produced since the previous DMA event
void Start(Backend &backend)
复位读取位置并启动循环 DMA / Reset the read position and start circular DMA
WritePort class for handling write operations.
LibXR 命名空间
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举
@ 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
通过成员指针恢复其所属对象指针
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