libxr  1.0
Want to be the best embedded framework
Loading...
Searching...
No Matches
ch32_uart.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2// ch32_uart.cpp
3
4#include "ch32_uart.hpp"
5
6#include "ch32_dma.hpp"
7#include "ch32_gpio.hpp"
8
9using namespace LibXR;
10
11// Static instance map.
12CH32UART* CH32UART::map_[ch32_uart_id_t::CH32_UART_NUMBER] = {nullptr};
13
14// Constructor: USART, DMA, and GPIO initialization.
15CH32UART::CH32UART(ch32_uart_id_t id, RawData dma_rx, RawData dma_tx,
16 GPIO_TypeDef* tx_gpio_port, uint16_t tx_gpio_pin,
17 GPIO_TypeDef* rx_gpio_port, uint16_t rx_gpio_pin, uint32_t pin_remap,
18 uint32_t tx_queue_size, UART::Configuration config)
19 : UART(&_read_port, &_write_port),
20 id_(id),
21 _read_port(dma_rx.size_),
22 _write_port(tx_queue_size, dma_tx.size_ / 2),
23 requested_config_(config),
24 rx_dma_model_(dma_rx),
25 tx_dma_model_(*this, _write_port, dma_tx),
26 instance_(ch32_uart_get_instance_id(id)),
27 dma_rx_channel_(CH32_UART_RX_DMA_CHANNEL_MAP[id]),
28 dma_tx_channel_(CH32_UART_TX_DMA_CHANNEL_MAP[id])
29{
30 map_[id] = this;
31
32 bool tx_enable = dma_tx.size_ > 1;
33 bool rx_enable = dma_rx.size_ > 0;
34
35 ASSERT(tx_enable || rx_enable);
36 if (tx_enable)
37 {
38 ASSERT(dma_tx_channel_ != nullptr);
39 ASSERT(CH32_UART_TX_DMA_IT_MAP[id] != 0);
40 }
41 if (rx_enable)
42 {
43 ASSERT(dma_rx_channel_ != nullptr);
44 ASSERT(CH32_UART_RX_DMA_IT_TC_MAP[id] != 0);
45 ASSERT(CH32_UART_RX_DMA_IT_HT_MAP[id] != 0);
46 }
47
48 /* GPIO配置(TX: 推挽输出,RX: 悬空输入) */
49 GPIO_InitTypeDef gpio_init = {};
50 gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
51
52 if (tx_enable)
53 {
54 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(tx_gpio_port), ENABLE);
55 gpio_init.GPIO_Pin = tx_gpio_pin;
56 gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
57 GPIO_Init(tx_gpio_port, &gpio_init);
58 (*write_port_) = WriteFun;
59 }
60
61 if (rx_enable)
62 {
63 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(rx_gpio_port), ENABLE);
64 gpio_init.GPIO_Pin = rx_gpio_pin;
65 gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
66 GPIO_Init(rx_gpio_port, &gpio_init);
67 (*read_port_) = ReadFun;
68 }
69
70 /* 可选:引脚重映射 */
71 if (pin_remap != 0)
72 {
73 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
74 GPIO_PinRemapConfig(pin_remap, ENABLE);
75 }
76
77 /* 串口外设时钟使能 */
78 if (CH32_UART_APB_MAP[id] == 1)
79 {
80 RCC_APB1PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[id], ENABLE);
81 }
82 else if (CH32_UART_APB_MAP[id] == 2)
83 {
84 RCC_APB2PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[id], ENABLE);
85 }
86 else
87 {
88 ASSERT(false);
89 }
90 RCC_AHBPeriphClockCmd(CH32_UART_RCC_PERIPH_MAP_DMA[id], ENABLE);
91
92 // 3. USART 配置
93 USART_InitTypeDef usart_cfg = {};
94 usart_cfg.USART_BaudRate = config.baudrate;
95 usart_cfg.USART_StopBits =
96 (config.stop_bits == 2) ? USART_StopBits_2 : USART_StopBits_1;
97 switch (config.parity)
98 {
100 usart_cfg.USART_Parity = USART_Parity_No;
101 usart_cfg.USART_WordLength = USART_WordLength_8b;
102 break;
104 usart_cfg.USART_Parity = USART_Parity_Even;
105 usart_cfg.USART_WordLength = USART_WordLength_9b;
106 break;
108 usart_cfg.USART_Parity = USART_Parity_Odd;
109 usart_cfg.USART_WordLength = USART_WordLength_9b;
110 break;
111 default:
112 ASSERT(false);
113 }
114
115 usart_cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
116 usart_cfg.USART_Mode =
117 (tx_enable ? USART_Mode_Tx : 0) | (rx_enable ? USART_Mode_Rx : 0);
118 uart_mode_ = usart_cfg.USART_Mode;
119 USART_Init(instance_, &usart_cfg);
120
121 /* DMA 配置 */
122 DMA_InitTypeDef dma_init = {};
123 dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
124 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
125 dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
126 dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
127 dma_init.DMA_Priority = DMA_Priority_High;
128 dma_init.DMA_M2M = DMA_M2M_Disable;
129
130 if (rx_enable)
131 {
132 ch32_dma_callback_t rx_cb_fun = [](void* arg)
133 { reinterpret_cast<CH32UART*>(arg)->RxDmaIRQHandler(); };
134
135 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_RX_DMA_CHANNEL_MAP[id]),
136 rx_cb_fun, this);
137
138 DMA_DeInit(dma_rx_channel_);
139 dma_init.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
140 dma_init.DMA_MemoryBaseAddr = (uint32_t)rx_dma_model_.Buffer();
141 dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
142 dma_init.DMA_Mode = DMA_Mode_Circular;
143 dma_init.DMA_BufferSize = rx_dma_model_.BufferSize();
144 DMA_Init(dma_rx_channel_, &dma_init);
145 rx_dma_model_.Start(*this);
146 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
147 DMA_ITConfig(dma_rx_channel_, DMA_IT_HT, ENABLE);
148 USART_DMACmd(instance_, USART_DMAReq_Rx, ENABLE);
149 }
150
151 if (tx_enable)
152 {
153 ch32_dma_callback_t tx_cb_fun = [](void* arg)
154 { reinterpret_cast<CH32UART*>(arg)->TxDmaIRQHandler(); };
155
156 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_TX_DMA_CHANNEL_MAP[id]),
157 tx_cb_fun, this);
158 DMA_DeInit(dma_tx_channel_);
159 dma_init.DMA_PeripheralBaseAddr = (u32)(&instance_->DATAR);
160 dma_init.DMA_MemoryBaseAddr = 0;
161 dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
162 dma_init.DMA_Mode = DMA_Mode_Normal;
163 dma_init.DMA_BufferSize = 0;
164 DMA_Init(dma_tx_channel_, &dma_init);
165 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
166 USART_DMACmd(instance_, USART_DMAReq_Tx, ENABLE);
167 }
168
169 // 6. USART和相关中断
170 USART_Cmd(instance_, ENABLE);
171
172 if (rx_enable)
173 {
174 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
175 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
176 }
177
178 if (tx_enable)
179 {
180 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
181 }
182
183 NVIC_EnableIRQ(CH32_UART_IRQ_MAP[id]);
184}
185
186// Runtime USART configuration.
188{
189 if ((config.stop_bits != 1U) && (config.stop_bits != 2U))
190 {
191 return ErrorCode::ARG_ERR;
192 }
193 if ((config.parity != UART::Parity::NO_PARITY) &&
194 (config.parity != UART::Parity::EVEN) && (config.parity != UART::Parity::ODD))
195 {
196 return ErrorCode::ARG_ERR;
197 }
198
199 requested_config_.Store(config);
200 tx_dma_model_.RequestConfig(false);
201 return ErrorCode::OK;
202}
203
204bool CH32UART::ApplyPendingConfig(bool in_isr)
205{
206 UNUSED(in_isr);
207 if (!rx_config_gate_.TryEnterConfig())
208 {
209 return false;
210 }
211
212 UART::Configuration config{};
213 (void)requested_config_.LoadLatest(config);
214
215 if (uart_mode_ & USART_Mode_Tx)
216 {
217 USART_DMACmd(instance_, USART_DMAReq_Tx, DISABLE);
218 DMA_Cmd(dma_tx_channel_, DISABLE);
219 DMA_ClearITPendingBit(CH32_UART_TX_DMA_IT_MAP[id_]);
220 }
221 if (uart_mode_ & USART_Mode_Rx)
222 {
223 USART_DMACmd(instance_, USART_DMAReq_Rx, DISABLE);
224 DMA_Cmd(dma_rx_channel_, DISABLE);
225 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_HT_MAP[id_]);
226 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_TC_MAP[id_]);
227 }
228
229 USART_InitTypeDef usart_cfg = {};
230 usart_cfg.USART_BaudRate = config.baudrate;
231 usart_cfg.USART_StopBits =
232 (config.stop_bits == 2) ? USART_StopBits_2 : USART_StopBits_1;
233
234 switch (config.parity)
235 {
237 usart_cfg.USART_Parity = USART_Parity_No;
238 usart_cfg.USART_WordLength = USART_WordLength_8b;
239 break;
241 usart_cfg.USART_Parity = USART_Parity_Even;
242 usart_cfg.USART_WordLength = USART_WordLength_9b;
243 break;
245 usart_cfg.USART_Parity = USART_Parity_Odd;
246 usart_cfg.USART_WordLength = USART_WordLength_9b;
247 break;
248 default:
249 ASSERT(false);
250 return true;
251 }
252
253 usart_cfg.USART_Mode = uart_mode_;
254 usart_cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
255 USART_DeInit(instance_);
256 USART_Init(instance_, &usart_cfg);
257
258 if (uart_mode_ & USART_Mode_Rx)
259 {
260 rx_dma_model_.Start(*this);
261 USART_DMACmd(instance_, USART_DMAReq_Rx, ENABLE);
262 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
263 }
264
265 if (uart_mode_ & USART_Mode_Tx)
266 {
267 USART_DMACmd(instance_, USART_DMAReq_Tx, ENABLE);
268 }
269
270 USART_Cmd(instance_, ENABLE);
271 return true;
272}
273
274// Write callback (DMA-based transfer).
275ErrorCode CH32UART::WriteFun(WritePort& port, bool in_isr)
276{
277 auto* uart = LibXR::ContainerOf(&port, &CH32UART::_write_port);
278 return uart->tx_dma_model_.Submit(in_isr);
279}
280
281bool CH32UART::StartDmaTx(uint8_t* data, size_t size, int)
282{
283 DMA_Cmd(dma_tx_channel_, DISABLE);
284 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(data);
285 dma_tx_channel_->CNTR = size;
286 DMA_Cmd(dma_tx_channel_, ENABLE);
287 return true;
288}
289
290// Read callback (interrupt-driven).
291ErrorCode CH32UART::ReadFun(ReadPort&, bool)
292{
293 // 接收由 IDLE 中断驱动,读取在 ISR 中完成
294 return ErrorCode::PENDING;
295}
296
297void ch32_uart_rx_isr_handler(LibXR::CH32UART* uart) { uart->OnRxDataAvailable(true); }
298
299void CH32UART::OnRxDataAvailable(bool in_isr)
300{
301 if (!rx_config_gate_.TryEnterRx())
302 {
303 return;
304 }
305
306 rx_dma_model_.OnDataAvailable(*this, _read_port, in_isr);
307 if (rx_config_gate_.LeaveRx())
308 {
309 tx_dma_model_.RequestConfig(in_isr);
310 }
311}
312
313// USART IDLE interrupt handler.
314extern "C" void ch32_uart_isr_handler_idle(ch32_uart_id_t id)
315{
316 auto uart = CH32UART::map_[id];
317 if (!uart)
318 {
319 return;
320 }
321
322 // 检查和清除IDLE标志
323 if (!USART_GetITStatus(uart->instance_, USART_IT_IDLE))
324 {
325 return;
326 }
327
328 USART_ReceiveData(uart->instance_);
329
330 ch32_uart_rx_isr_handler(uart);
331}
332
333// DMA TX completion interrupt handler.
334extern "C" void ch32_uart_isr_handler_tx_cplt(CH32UART* uart)
335{
336 DMA_ClearITPendingBit(CH32_UART_TX_DMA_IT_MAP[uart->id_]);
337 uart->tx_dma_model_.OnTransferDone(true);
338}
339
340// DMA channel IRQ callbacks.
341void CH32UART::TxDmaIRQHandler()
342{
343 if (DMA_GetITStatus(CH32_UART_TX_DMA_IT_MAP[id_]) == RESET)
344 {
345 return;
346 }
347
348 if (dma_tx_channel_->CNTR == 0)
349 {
350 ch32_uart_isr_handler_tx_cplt(this);
351 }
352}
353
363{
364 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_HT_MAP[id_]) == SET)
365 {
366 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_HT_MAP[id_]);
367 ch32_uart_rx_isr_handler(this);
368 }
369
370 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_TC_MAP[id_]) == SET)
371 {
372 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_TC_MAP[id_]);
373 ch32_uart_rx_isr_handler(this);
374 }
375}
376
377// USART IRQ entry adapters.
378#if defined(USART1)
379// NOLINTNEXTLINE(readability-identifier-naming)
380extern "C" void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
381// NOLINTNEXTLINE(readability-identifier-naming)
382extern "C" void USART1_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART1); }
383#endif
384#if defined(USART2)
385// NOLINTNEXTLINE(readability-identifier-naming)
386extern "C" void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
387// NOLINTNEXTLINE(readability-identifier-naming)
388extern "C" void USART2_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART2); }
389#endif
390#if defined(USART3)
391// NOLINTNEXTLINE(readability-identifier-naming)
392extern "C" void USART3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
393// NOLINTNEXTLINE(readability-identifier-naming)
394extern "C" void USART3_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART3); }
395#endif
396#if defined(USART4)
397// NOLINTNEXTLINE(readability-identifier-naming)
398extern "C" void USART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
399// NOLINTNEXTLINE(readability-identifier-naming)
400extern "C" void USART4_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART4); }
401#endif
402#if defined(USART5)
403// NOLINTNEXTLINE(readability-identifier-naming)
404extern "C" void USART5_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
405// NOLINTNEXTLINE(readability-identifier-naming)
406extern "C" void USART5_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART5); }
407#endif
408#if defined(USART6)
409// NOLINTNEXTLINE(readability-identifier-naming)
410extern "C" void USART6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
411// NOLINTNEXTLINE(readability-identifier-naming)
412extern "C" void USART6_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART6); }
413#endif
414#if defined(USART7)
415// NOLINTNEXTLINE(readability-identifier-naming)
416extern "C" void USART7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
417// NOLINTNEXTLINE(readability-identifier-naming)
418extern "C" void USART7_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART7); }
419#endif
420#if defined(USART8)
421// NOLINTNEXTLINE(readability-identifier-naming)
422extern "C" void USART8_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
423// NOLINTNEXTLINE(readability-identifier-naming)
424extern "C" void USART8_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART8); }
425#endif
426#if defined(UART1)
427// NOLINTNEXTLINE(readability-identifier-naming)
428extern "C" void UART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
429// NOLINTNEXTLINE(readability-identifier-naming)
430extern "C" void UART1_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART1); }
431#endif
432#if defined(UART2)
433// NOLINTNEXTLINE(readability-identifier-naming)
434extern "C" void UART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
435// NOLINTNEXTLINE(readability-identifier-naming)
436extern "C" void UART2_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART2); }
437#endif
438#if defined(UART3)
439// NOLINTNEXTLINE(readability-identifier-naming)
440extern "C" void UART3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
441// NOLINTNEXTLINE(readability-identifier-naming)
442extern "C" void UART3_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART3); }
443#endif
444#if defined(UART4)
445// NOLINTNEXTLINE(readability-identifier-naming)
446extern "C" void UART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
447// NOLINTNEXTLINE(readability-identifier-naming)
448extern "C" void UART4_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART4); }
449#endif
450#if defined(UART5)
451// NOLINTNEXTLINE(readability-identifier-naming)
452extern "C" void UART5_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
453// NOLINTNEXTLINE(readability-identifier-naming)
454extern "C" void UART5_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART5); }
455#endif
456#if defined(UART6)
457// NOLINTNEXTLINE(readability-identifier-naming)
458extern "C" void UART6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
459// NOLINTNEXTLINE(readability-identifier-naming)
460extern "C" void UART6_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART6); }
461#endif
462#if defined(UART7)
463// NOLINTNEXTLINE(readability-identifier-naming)
464extern "C" void UART7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
465// NOLINTNEXTLINE(readability-identifier-naming)
466extern "C" void UART7_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART7); }
467#endif
468#if defined(UART8)
469// NOLINTNEXTLINE(readability-identifier-naming)
470extern "C" void UART8_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
471// NOLINTNEXTLINE(readability-identifier-naming)
472extern "C" void UART8_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART8); }
473#endif
474
475// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
CH32 UART 驱动实现 / CH32 UART driver implementation.
Definition ch32_uart.hpp:29
void RxDmaIRQHandler()
DMA中断处理函数
ErrorCode SetConfig(UART::Configuration config)
设置 UART 配置 / Sets the UART configuration
bool StartDmaTx(uint8_t *data, size_t size, int block)
配置并启动一个 active UART TX DMA 载荷 / Configure and start one active UART TX DMA payload
CH32UART(ch32_uart_id_t id, RawData dma_rx, RawData dma_tx, GPIO_TypeDef *tx_gpio_port, uint16_t tx_gpio_pin, GPIO_TypeDef *rx_gpio_port, uint16_t rx_gpio_pin, uint32_t pin_remap=0, uint32_t tx_queue_size=5, UART::Configuration config={115200, UART::Parity::NO_PARITY, 8, 1})
构造 UART 对象 / Construct UART object
Definition ch32_uart.cpp:15
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
ReadPort class for handling read operations.
Definition read_port.hpp:18
通用异步收发传输(UART)基类 / Abstract base class for Universal Asynchronous Receiver-Transmitter (UART)
Definition uart.hpp:19
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
uint8_t * Buffer() const
获取 DMA 可写缓冲区起始地址 / Get the DMA-writable buffer start address
size_t BufferSize() const
获取循环 DMA 缓冲区容量 / Get the circular DMA buffer capacity
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
通过成员指针恢复其所属对象指针
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