libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
ch32_uart.cpp
1// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
2
3#include "ch32_uart.hpp"
4
5#include <algorithm>
6
7#include "ch32_dma.hpp"
8#include "ch32_gpio.hpp"
9
10using namespace LibXR;
11
12namespace
13{
14
15bool Ch32DataBitsSupported(const UART::Configuration& config)
16{
17 if (config.parity == UART::Parity::NO_PARITY)
18 {
19 return config.data_bits == 8U;
20 }
21
22 return (config.parity == UART::Parity::EVEN || config.parity == UART::Parity::ODD) &&
23 (config.data_bits == 7U || config.data_bits == 8U);
24}
25
26bool Ch32StopBitsSupported(const UART::Configuration& config)
27{
28 return config.stop_bits == 1U || config.stop_bits == 2U;
29}
30
31} // namespace
32
33CH32UART* CH32UART::map_[ch32_uart_id_t::CH32_UART_NUMBER] = {nullptr};
34
35CH32UART::CH32UART(ch32_uart_id_t id, RawData dma_rx, RawData dma_tx,
36 GPIO_TypeDef* tx_gpio_port, uint16_t tx_gpio_pin,
37 GPIO_TypeDef* rx_gpio_port, uint16_t rx_gpio_pin, uint32_t pin_remap,
38 uint32_t tx_queue_size, UART::Configuration config)
39 : UART(&_read_port, &_write_port),
40 id_(id),
41 _read_port(dma_rx.size_),
42 _write_port(tx_queue_size, dma_tx.size_ / 2),
43 dma_buff_rx_(dma_rx),
44 dma_buff_tx_(dma_tx),
45 instance_(ch32_uart_get_instance_id(id)),
46 dma_rx_channel_(CH32_UART_RX_DMA_CHANNEL_MAP[id]),
47 dma_tx_channel_(CH32_UART_TX_DMA_CHANNEL_MAP[id])
48{
49 map_[id] = this;
50
51 bool tx_enable = dma_tx.size_ > 1;
52 bool rx_enable = dma_rx.size_ > 0;
53
54 ASSERT(tx_enable || rx_enable);
55 if (tx_enable)
56 {
57 ASSERT(tx_queue_size > 0U);
58 ASSERT(dma_tx_channel_ != nullptr);
59 ASSERT(CH32_UART_TX_DMA_IT_MAP[id] != 0);
60 }
61 if (rx_enable)
62 {
63 ASSERT(dma_rx_channel_ != nullptr);
64 ASSERT(CH32_UART_RX_DMA_IT_TC_MAP[id] != 0);
65 ASSERT(CH32_UART_RX_DMA_IT_HT_MAP[id] != 0);
66 }
67
68 // TX 使用复用推挽,RX 使用浮空输入 / TX alternate push-pull; RX floating input.
69 GPIO_InitTypeDef gpio_init = {};
70 gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
71
72 if (tx_enable)
73 {
74 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(tx_gpio_port), ENABLE);
75 gpio_init.GPIO_Pin = tx_gpio_pin;
76 gpio_init.GPIO_Mode = GPIO_Mode_AF_PP;
77 GPIO_Init(tx_gpio_port, &gpio_init);
78 (*write_port_) = WriteFun;
79 }
80
81 if (rx_enable)
82 {
83 RCC_APB2PeriphClockCmd(ch32_get_gpio_periph(rx_gpio_port), ENABLE);
84 gpio_init.GPIO_Pin = rx_gpio_pin;
85 gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING;
86 GPIO_Init(rx_gpio_port, &gpio_init);
87 }
88
89 // 可选引脚重映射 / Optional pin remapping.
90 if (pin_remap != 0)
91 {
92 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
93 GPIO_PinRemapConfig(pin_remap, ENABLE);
94 }
95
96 // 开启串口外设时钟 / Enable the UART peripheral clock.
97 if (CH32_UART_APB_MAP[id] == 1)
98 {
99 RCC_APB1PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[id], ENABLE);
100 }
101 else if (CH32_UART_APB_MAP[id] == 2)
102 {
103 RCC_APB2PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[id], ENABLE);
104 }
105 else
106 {
107 DEV_ASSERT(false);
108 }
109 RCC_AHBPeriphClockCmd(CH32_UART_RCC_PERIPH_MAP_DMA[id], ENABLE);
110
111 // 设置初始串口参数 / Apply initial UART settings.
112 ASSERT(config.baudrate > 0U);
113 ASSERT(Ch32DataBitsSupported(config));
114 ASSERT(Ch32StopBitsSupported(config));
115 USART_InitTypeDef usart_cfg = {};
116 usart_cfg.USART_BaudRate = config.baudrate;
117 usart_cfg.USART_StopBits =
118 (config.stop_bits == 2) ? USART_StopBits_2 : USART_StopBits_1;
119 switch (config.parity)
120 {
122 usart_cfg.USART_Parity = USART_Parity_No;
123 usart_cfg.USART_WordLength = USART_WordLength_8b;
124 break;
126 usart_cfg.USART_Parity = USART_Parity_Even;
127 usart_cfg.USART_WordLength =
128 config.data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
129 break;
131 usart_cfg.USART_Parity = USART_Parity_Odd;
132 usart_cfg.USART_WordLength =
133 config.data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
134 break;
135 default:
136 ASSERT(false);
137 }
138
139 usart_cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
140 usart_cfg.USART_Mode =
141 (tx_enable ? USART_Mode_Tx : 0) | (rx_enable ? USART_Mode_Rx : 0);
142 uart_mode_ = usart_cfg.USART_Mode;
143 USART_Init(instance_, &usart_cfg);
144
145 // 配置收发 DMA / Configure RX and TX DMA.
146 DMA_InitTypeDef dma_init = {};
147 dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
148 dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable;
149 dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
150 dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
151 dma_init.DMA_Priority = DMA_Priority_High;
152 dma_init.DMA_M2M = DMA_M2M_Disable;
153
154 if (rx_enable)
155 {
156 ch32_dma_callback_t rx_cb_fun = [](void* arg)
157 { reinterpret_cast<CH32UART*>(arg)->RxDmaIRQHandler(); };
158
159 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_RX_DMA_CHANNEL_MAP[id]),
160 rx_cb_fun, this);
161
162 DMA_DeInit(dma_rx_channel_);
163 dma_init.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
164 dma_init.DMA_MemoryBaseAddr = (uint32_t)dma_buff_rx_.addr_;
165 dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
166 dma_init.DMA_Mode = DMA_Mode_Circular;
167 dma_init.DMA_BufferSize = dma_buff_rx_.size_;
168 DMA_Init(dma_rx_channel_, &dma_init);
169 DMA_Cmd(dma_rx_channel_, ENABLE);
170 DMA_ITConfig(dma_rx_channel_, DMA_IT_TC, ENABLE);
171 DMA_ITConfig(dma_rx_channel_, DMA_IT_HT, ENABLE);
172 USART_DMACmd(instance_, USART_DMAReq_Rx, ENABLE);
173 }
174
175 if (tx_enable)
176 {
177 ch32_dma_callback_t tx_cb_fun = [](void* arg)
178 { reinterpret_cast<CH32UART*>(arg)->TxDmaIRQHandler(); };
179
180 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_TX_DMA_CHANNEL_MAP[id]),
181 tx_cb_fun, this);
182 DMA_DeInit(dma_tx_channel_);
183 dma_init.DMA_PeripheralBaseAddr = (u32)(&instance_->DATAR);
184 dma_init.DMA_MemoryBaseAddr = 0;
185 dma_init.DMA_DIR = DMA_DIR_PeripheralDST;
186 dma_init.DMA_Mode = DMA_Mode_Normal;
187 dma_init.DMA_BufferSize = 0;
188 DMA_Init(dma_tx_channel_, &dma_init);
189 DMA_ITConfig(dma_tx_channel_, DMA_IT_TC, ENABLE);
190 USART_DMACmd(instance_, USART_DMAReq_Tx, ENABLE);
191 }
192
193 // 开启串口及对应中断 / Enable the UART and its interrupts.
194 USART_Cmd(instance_, ENABLE);
195
196 if (rx_enable)
197 {
198 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
199 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
200 }
201
202 if (tx_enable)
203 {
204 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
205 }
206
207 NVIC_EnableIRQ(CH32_UART_IRQ_MAP[id]);
208}
209
211{
212 if (config.baudrate == 0U)
213 {
214 return ErrorCode::ARG_ERR;
215 }
216
217 switch (config.parity)
218 {
222 break;
223 default:
225 }
226
227 if (!Ch32DataBitsSupported(config))
228 {
229 return ErrorCode::ARG_ERR;
230 }
231
232 if (!Ch32StopBitsSupported(config))
233 {
234 return ErrorCode::ARG_ERR;
235 }
236
237 ConfigState expected = ConfigState::EMPTY;
238 if (!config_state_.compare_exchange_strong(expected, ConfigState::RESERVED,
239 std::memory_order_acq_rel,
240 std::memory_order_acquire))
241 {
242 return ErrorCode::BUSY;
243 }
244
245 pending_config_ = config;
246 tx_service_.Invoke(TX_EVENT_CONFIG, in_isr, [this](uint32_t events, bool owner_in_isr)
247 { HandleTxService(events, owner_in_isr); });
248 return ErrorCode::OK;
249}
250
251void CH32UART::ApplyConfig(UART::Configuration config)
252{
253 USART_ITConfig(instance_, USART_IT_TC, DISABLE);
254
255 USART_InitTypeDef usart_cfg = {};
256 usart_cfg.USART_BaudRate = config.baudrate;
257 usart_cfg.USART_StopBits =
258 (config.stop_bits == 2) ? USART_StopBits_2 : USART_StopBits_1;
259
260 switch (config.parity)
261 {
263 usart_cfg.USART_Parity = USART_Parity_No;
264 usart_cfg.USART_WordLength = USART_WordLength_8b;
265 break;
267 usart_cfg.USART_Parity = USART_Parity_Even;
268 usart_cfg.USART_WordLength =
269 config.data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
270 break;
272 usart_cfg.USART_Parity = USART_Parity_Odd;
273 usart_cfg.USART_WordLength =
274 config.data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
275 break;
276 default:
277 DEV_ASSERT(false);
278 return;
279 }
280
281 usart_cfg.USART_Mode = uart_mode_;
282 usart_cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
283 USART_Init(instance_, &usart_cfg);
284
285 if (uart_mode_ & USART_Mode_Rx)
286 {
287 USART_DMACmd(instance_, USART_DMAReq_Rx, ENABLE);
288 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
289 }
290
291 if (uart_mode_ & USART_Mode_Tx)
292 {
293 USART_DMACmd(instance_, USART_DMAReq_Tx, ENABLE);
294 }
295
296 USART_Cmd(instance_, ENABLE);
297}
298
299void CH32UART::WriteFun(WritePort& port, bool in_isr)
300{
301 auto* uart = LibXR::ContainerOf(&port, &CH32UART::_write_port);
302
303 uart->tx_service_.Invoke(TX_EVENT_WRITE, in_isr,
304 [uart](uint32_t events, bool owner_in_isr)
305 { uart->HandleTxService(events, owner_in_isr); });
306}
307
308void CH32UART::HandleTxService(uint32_t events, bool in_isr)
309{
310 if ((events & TX_EVENT_CONFIG) != 0U)
311 {
312 ConfigState state = config_state_.load(std::memory_order_acquire);
313 if (state == ConfigState::RESERVED)
314 {
315 config_state_.store(ConfigState::PUBLISHED, std::memory_order_release);
316 }
317 else
318 {
319 DEV_ASSERT_FROM_CALLBACK(state == ConfigState::PUBLISHED, in_isr);
320 }
321 }
322
323 if ((events & TX_EVENT_DMA_DONE) != 0U)
324 {
325 HandleTxDone(in_isr);
326 }
327
328 if ((events & TX_EVENT_RX_WORK) != 0U)
329 {
330 HandleRxData(in_isr);
331 }
332
333 if ((events & (TX_EVENT_CONFIG | TX_EVENT_DMA_DONE | TX_EVENT_TC)) != 0U)
334 {
335 TryApplyConfig(in_isr);
336 }
337
338 if ((uart_mode_ & USART_Mode_Tx) != 0U &&
339 (events & (TX_EVENT_WRITE | TX_EVENT_DMA_DONE | TX_EVENT_CONFIG | TX_EVENT_TC)) !=
340 0U &&
341 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
342 {
343 FillTx(in_isr);
344 }
345}
346
347void CH32UART::FillTx(bool in_isr)
348{
349 if (!tx_busy_.IsSet())
350 {
352 {
353 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
354 {
355 return;
356 }
357 const size_t size = dma_buff_tx_.GetPendingLength();
360 StartTxDma(in_isr);
361 }
362 else if (dma_buff_tx_.GetActiveLength() != 0U)
363 {
364 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
365 {
366 return;
367 }
368 StartTxDma(in_isr);
369 }
370 else
371 {
372 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
373 {
374 return;
375 }
376 size_t size = 0U;
377 {
378 auto queue = _write_port.GetWriteQueue(in_isr);
379 if (queue.Empty())
380 {
381 return;
382 }
383 size = queue.AvailableSize();
384 DEV_ASSERT_FROM_CALLBACK(size <= dma_buff_tx_.Size(), in_isr);
385 queue.PopAll(dma_buff_tx_.ActiveBuffer());
387 }
388
389 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
390 {
391 return;
392 }
393 StartTxDma(in_isr);
394 }
395 }
396
398 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
399 {
400 auto queue = _write_port.GetWriteQueue(in_isr);
401 if (!queue.Empty())
402 {
403 const size_t size = queue.AvailableSize();
404 DEV_ASSERT_FROM_CALLBACK(size <= dma_buff_tx_.Size(), in_isr);
405 queue.PopAll(dma_buff_tx_.PendingBuffer());
408 }
409 }
410}
411
412void CH32UART::HandleTxDone(bool in_isr)
413{
414 UNUSED(in_isr);
415 if (!tx_busy_.IsSet())
416 {
417 return;
418 }
419
420 tx_busy_.Clear();
422}
423
424void CH32UART::TryApplyConfig(bool in_isr)
425{
426 if (config_state_.load(std::memory_order_acquire) != ConfigState::PUBLISHED)
427 {
428 return;
429 }
430
431 if (tx_busy_.IsSet())
432 {
433 return;
434 }
435
436 if ((uart_mode_ & USART_Mode_Tx) != 0U &&
437 USART_GetFlagStatus(instance_, USART_FLAG_TC) == RESET)
438 {
439 USART_ITConfig(instance_, USART_IT_TC, ENABLE);
440 return;
441 }
442
443 const UART::Configuration config = pending_config_;
444 ApplyConfig(config);
445
446 if ((uart_mode_ & USART_Mode_Rx) != 0U && dma_buff_rx_.size_ != 0U)
447 {
448 const size_t remaining = dma_rx_channel_->CNTR;
449 DEV_ASSERT_FROM_CALLBACK(remaining <= dma_buff_rx_.size_, in_isr);
450 const size_t position =
451 remaining == 0U ? dma_buff_rx_.size_ : dma_buff_rx_.size_ - remaining;
452 last_rx_pos_ = position == dma_buff_rx_.size_ ? 0U : position;
453 }
454
455 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
456 UNUSED(in_isr);
457}
458
459void CH32UART::StartTxDma(bool in_isr)
460{
461 const size_t size = dma_buff_tx_.GetActiveLength();
462 DEV_ASSERT_FROM_CALLBACK(size != 0U && size <= dma_buff_tx_.Size(), in_isr);
463
464 DMA_Cmd(dma_tx_channel_, DISABLE);
465 dma_tx_channel_->MADDR = reinterpret_cast<uint32_t>(dma_buff_tx_.ActiveBuffer());
466 dma_tx_channel_->CNTR = size;
467 tx_busy_.Set();
468 DMA_Cmd(dma_tx_channel_, ENABLE);
469 UNUSED(in_isr);
470}
471
472void CH32UART::HandleRxData(bool in_isr)
473{
474 const size_t dma_size = dma_buff_rx_.size_;
475 if (dma_size == 0U)
476 {
477 return;
478 }
479
480 const size_t remaining = dma_rx_channel_->CNTR;
481 DEV_ASSERT_FROM_CALLBACK(remaining <= dma_size, in_isr);
482 const size_t curr_pos = remaining == 0U ? dma_size : dma_size - remaining;
483 const size_t last_pos = last_rx_pos_;
484 DEV_ASSERT_FROM_CALLBACK(last_pos < dma_size, in_isr);
485
486 if (curr_pos != last_pos)
487 {
488 const size_t first_size =
489 curr_pos > last_pos ? curr_pos - last_pos : dma_size - last_pos;
490 const size_t second_size = curr_pos > last_pos ? 0U : curr_pos;
491 auto queue = _read_port.GetReadQueue(in_isr);
492 size_t accepted = std::min(first_size + second_size, queue.EmptySize());
493
494 if (accepted != 0U)
495 {
496 const size_t first_accepted = std::min(first_size, accepted);
497 if (first_accepted != 0U)
498 {
499 [[maybe_unused]] const auto push_batch_result = queue.PushBatch(
500 static_cast<const uint8_t*>(dma_buff_rx_.addr_) + last_pos, first_accepted);
501 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
502 accepted -= first_accepted;
503 }
504 if (accepted != 0U)
505 {
506 [[maybe_unused]] const auto push_batch_result =
507 queue.PushBatch(static_cast<const uint8_t*>(dma_buff_rx_.addr_), accepted);
508 DEV_ASSERT_FROM_CALLBACK(push_batch_result == ErrorCode::OK, in_isr);
509 }
510 }
511
512 last_rx_pos_ = curr_pos == dma_size ? 0U : curr_pos;
513 queue.Publish();
514 }
515}
516
518{
519 const bool idle = USART_GetITStatus(instance_, USART_IT_IDLE) != RESET;
520 const bool tc = USART_GetITStatus(instance_, USART_IT_TC) != RESET;
521
522 if (idle)
523 {
524 USART_ReceiveData(instance_);
525 tx_service_.Invoke(TX_EVENT_RX_WORK, true, [this](uint32_t events, bool in_isr)
526 { HandleTxService(events, in_isr); });
527 }
528
529 if (tc)
530 {
531 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
532 {
533 USART_ITConfig(instance_, USART_IT_TC, DISABLE);
534 tx_service_.Invoke(TX_EVENT_TC, true, [this](uint32_t events, bool in_isr)
535 { HandleTxService(events, in_isr); });
536 }
537 else
538 {
539 USART_ITConfig(instance_, USART_IT_TC, DISABLE);
540 }
541 }
542}
543
544extern "C" void ch32_uart_isr_handler_idle(ch32_uart_id_t id)
545{
546 auto uart = CH32UART::map_[id];
547 if (uart)
548 {
549 uart->UartIRQHandler();
550 }
551}
552
553extern "C" void ch32_uart_isr_handler_tx_cplt(CH32UART* uart) { uart->TxDmaIRQHandler(); }
554
556{
557 if (DMA_GetITStatus(CH32_UART_TX_DMA_IT_MAP[id_]) == RESET)
558 {
559 return;
560 }
561
562 if (dma_tx_channel_->CNTR == 0)
563 {
564 DMA_ClearITPendingBit(CH32_UART_TX_DMA_IT_MAP[id_]);
565 tx_service_.Invoke(TX_EVENT_DMA_DONE, true, [this](uint32_t events, bool in_isr)
566 { HandleTxService(events, in_isr); });
567 }
568}
569
574{
575 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_HT_MAP[id_]) == SET)
576 {
577 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_HT_MAP[id_]);
578 tx_service_.Invoke(TX_EVENT_RX_WORK, true, [this](uint32_t events, bool in_isr)
579 { HandleTxService(events, in_isr); });
580 }
581
582 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_TC_MAP[id_]) == SET)
583 {
584 DMA_ClearITPendingBit(CH32_UART_RX_DMA_IT_TC_MAP[id_]);
585 tx_service_.Invoke(TX_EVENT_RX_WORK, true, [this](uint32_t events, bool in_isr)
586 { HandleTxService(events, in_isr); });
587 }
588}
589
590#if defined(USART1)
591// NOLINTNEXTLINE(readability-identifier-naming)
592extern "C" void USART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
593// NOLINTNEXTLINE(readability-identifier-naming)
594extern "C" void USART1_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART1); }
595#endif
596#if defined(USART2)
597// NOLINTNEXTLINE(readability-identifier-naming)
598extern "C" void USART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
599// NOLINTNEXTLINE(readability-identifier-naming)
600extern "C" void USART2_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART2); }
601#endif
602#if defined(USART3)
603// NOLINTNEXTLINE(readability-identifier-naming)
604extern "C" void USART3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
605// NOLINTNEXTLINE(readability-identifier-naming)
606extern "C" void USART3_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART3); }
607#endif
608#if defined(USART4)
609// NOLINTNEXTLINE(readability-identifier-naming)
610extern "C" void USART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
611// NOLINTNEXTLINE(readability-identifier-naming)
612extern "C" void USART4_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART4); }
613#endif
614#if defined(USART5)
615// NOLINTNEXTLINE(readability-identifier-naming)
616extern "C" void USART5_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
617// NOLINTNEXTLINE(readability-identifier-naming)
618extern "C" void USART5_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART5); }
619#endif
620#if defined(USART6)
621// NOLINTNEXTLINE(readability-identifier-naming)
622extern "C" void USART6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
623// NOLINTNEXTLINE(readability-identifier-naming)
624extern "C" void USART6_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART6); }
625#endif
626#if defined(USART7)
627// NOLINTNEXTLINE(readability-identifier-naming)
628extern "C" void USART7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
629// NOLINTNEXTLINE(readability-identifier-naming)
630extern "C" void USART7_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART7); }
631#endif
632#if defined(USART8)
633// NOLINTNEXTLINE(readability-identifier-naming)
634extern "C" void USART8_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
635// NOLINTNEXTLINE(readability-identifier-naming)
636extern "C" void USART8_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_USART8); }
637#endif
638#if defined(UART1)
639// NOLINTNEXTLINE(readability-identifier-naming)
640extern "C" void UART1_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
641// NOLINTNEXTLINE(readability-identifier-naming)
642extern "C" void UART1_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART1); }
643#endif
644#if defined(UART2)
645// NOLINTNEXTLINE(readability-identifier-naming)
646extern "C" void UART2_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
647// NOLINTNEXTLINE(readability-identifier-naming)
648extern "C" void UART2_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART2); }
649#endif
650#if defined(UART3)
651// NOLINTNEXTLINE(readability-identifier-naming)
652extern "C" void UART3_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
653// NOLINTNEXTLINE(readability-identifier-naming)
654extern "C" void UART3_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART3); }
655#endif
656#if defined(UART4)
657// NOLINTNEXTLINE(readability-identifier-naming)
658extern "C" void UART4_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
659// NOLINTNEXTLINE(readability-identifier-naming)
660extern "C" void UART4_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART4); }
661#endif
662#if defined(UART5)
663// NOLINTNEXTLINE(readability-identifier-naming)
664extern "C" void UART5_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
665// NOLINTNEXTLINE(readability-identifier-naming)
666extern "C" void UART5_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART5); }
667#endif
668#if defined(UART6)
669// NOLINTNEXTLINE(readability-identifier-naming)
670extern "C" void UART6_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
671// NOLINTNEXTLINE(readability-identifier-naming)
672extern "C" void UART6_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART6); }
673#endif
674#if defined(UART7)
675// NOLINTNEXTLINE(readability-identifier-naming)
676extern "C" void UART7_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
677// NOLINTNEXTLINE(readability-identifier-naming)
678extern "C" void UART7_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART7); }
679#endif
680#if defined(UART8)
681// NOLINTNEXTLINE(readability-identifier-naming)
682extern "C" void UART8_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
683// NOLINTNEXTLINE(readability-identifier-naming)
684extern "C" void UART8_IRQHandler(void) { ch32_uart_isr_handler_idle(CH32_UART8); }
685#endif
686
687// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast,performance-no-int-to-ptr)
使用循环接收 DMA 和双缓冲发送的 CH32 串口 / CH32 UART with circular RX DMA and double-buffered TX.
Definition ch32_uart.hpp:33
void RxDmaIRQHandler()
处理接收 DMA 进展通知 / Handle RX DMA progress.
ErrorCode SetConfig(UART::Configuration config, bool in_isr=false) override
提交串口配置请求 / Submit a UART configuration request.
size_t last_rx_pos_
上次已处理的 DMA 接收位置 / Last processed RX DMA position.
Definition ch32_uart.hpp:91
static void WriteFun(WritePort &port, bool in_isr)
通知后端处理已提交的写请求 / Notify the backend of released writes.
void TxDmaIRQHandler()
处理发送 DMA 完成通知 / Handle TX DMA completion.
DoubleBuffer dma_buff_tx_
当前与待发送的 DMA 半区 / Active and pending TX DMA halves.
Definition ch32_uart.hpp:88
ReadPort _read_port
接收字节队列与读请求 / RX byte queue and read requests.
Definition ch32_uart.hpp:81
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})
构造串口并关联 DMA 缓冲区 / Construct a UART with DMA buffers.
Definition ch32_uart.cpp:35
WritePort _write_port
写请求及发送字节队列 / Write requests and TX byte queue.
Definition ch32_uart.hpp:83
void UartIRQHandler()
处理接收空闲和发送完成中断 / Handle RX idle and TX complete interrupts.
Flag::Plain tx_busy_
发送半区是否在使用,仅后端处理器访问 / TX half in use; service-only access.
Definition ch32_uart.hpp:98
RawData dma_buff_rx_
调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.
Definition ch32_uart.hpp:86
void SetActiveLength(size_t length)
设置当前活动缓冲区的数据长度 Sets the size of the active buffer
void SetPendingLength(size_t length)
设置备用缓冲区的数据长度 Sets the size of the pending buffer
void EnablePending()
手动启用 pending 状态 Manually sets the pending state to true
bool HasPending() const
判断是否有待切换的缓冲区 Checks whether a pending buffer is ready
size_t Size() const
获取每个缓冲区的大小(单位:字节) Gets the size of each buffer in bytes
uint8_t * ActiveBuffer() const
获取当前正在使用的缓冲区指针 Returns the currently active buffer
size_t GetActiveLength() const
获取当前活动缓冲区中准备好的数据长度 Gets the size of valid data in active buffer
uint8_t * PendingBuffer() const
获取备用缓冲区的指针 Returns the pending (inactive) buffer
void Switch()
切换到备用缓冲区(若其有效) Switches to the pending buffer if it's valid
size_t GetPendingLength() const
获取 pending 缓冲区中准备好的数据长度 Gets the size of valid data in pending buffer
void Set() noexcept
置位标志 / Set the flag
Definition flag.hpp:125
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
Definition flag.hpp:138
void Clear() noexcept
清除标志 / Clear the flag
Definition flag.hpp:130
可写原始数据视图 / Mutable raw data view
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
ReadQueue GetReadQueue(bool in_isr=false)
获取后端接收入队接口 / Obtain the backend RX producer interface.
Definition read_port.cpp:14
bool Invoke(uint32_t events, bool in_isr, Handler &&handler) noexcept
发布事件并尝试取得执行权 / Publish events and attempt to claim execution.
通用异步收发传输(UART)基类 / Abstract base class for Universal Asynchronous Receiver-Transmitter (UART)
Definition uart.hpp:19
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
size_t AvailableSize() const
获取当前队头的剩余长度 / Get the current front remainder.
基于 SPSC 字节队列的写端口 / Write endpoint backed by an SPSC byte queue.
WriteQueue GetWriteQueue(bool in_isr=false)
获取已提交队头的出队接口 / Obtain a consumer interface for the released front.
LibXR 命名空间 / LibXR namespace.
Definition ch32_can.hpp:14
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ BUSY
忙碌 / Busy
@ NOT_SUPPORT
不支持 / Not supported
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error
void(* WriteFun)(WritePort &port, bool in_isr)
写入进度通知函数类型 / Write progress notification function type.
OwnerType * ContainerOf(MemberType *ptr, MemberType OwnerType::*member) noexcept
通过成员指针恢复其所属对象指针 Recover the owning object pointer from a member pointer
UART 配置结构体 / UART configuration structure.
Definition uart.hpp:44
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:53
uint32_t baudrate
波特率 / Baud rate
Definition uart.hpp:45