3#include "ch32_uart.hpp"
8#include "ch32_gpio.hpp"
17 if (config.
parity == UART::Parity::NO_PARITY)
22 return (config.
parity == UART::Parity::EVEN || config.
parity == UART::Parity::ODD) &&
33CH32UART* CH32UART::map_[ch32_uart_id_t::CH32_UART_NUMBER] = {
nullptr};
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,
39 :
UART(&_read_port, &_write_port),
41 _read_port(dma_rx.size_),
42 _write_port(tx_queue_size, dma_tx.size_ / 2),
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])
51 bool tx_enable = dma_tx.
size_ > 1;
52 bool rx_enable = dma_rx.
size_ > 0;
54 ASSERT(tx_enable || rx_enable);
57 ASSERT(tx_queue_size > 0U);
58 ASSERT(dma_tx_channel_ !=
nullptr);
59 ASSERT(CH32_UART_TX_DMA_IT_MAP[
id] != 0);
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);
69 GPIO_InitTypeDef gpio_init = {};
70 gpio_init.GPIO_Speed = GPIO_Speed_50MHz;
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);
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);
92 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
93 GPIO_PinRemapConfig(pin_remap, ENABLE);
97 if (CH32_UART_APB_MAP[
id] == 1)
99 RCC_APB1PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[
id], ENABLE);
101 else if (CH32_UART_APB_MAP[
id] == 2)
103 RCC_APB2PeriphClockCmd(CH32_UART_RCC_PERIPH_MAP[
id], ENABLE);
109 RCC_AHBPeriphClockCmd(CH32_UART_RCC_PERIPH_MAP_DMA[
id], ENABLE);
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;
122 usart_cfg.USART_Parity = USART_Parity_No;
123 usart_cfg.USART_WordLength = USART_WordLength_8b;
126 usart_cfg.USART_Parity = USART_Parity_Even;
127 usart_cfg.USART_WordLength =
128 config.
data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
131 usart_cfg.USART_Parity = USART_Parity_Odd;
132 usart_cfg.USART_WordLength =
133 config.
data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
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);
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;
156 ch32_dma_callback_t rx_cb_fun = [](
void* arg)
159 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_RX_DMA_CHANNEL_MAP[
id]),
162 DMA_DeInit(dma_rx_channel_);
163 dma_init.DMA_PeripheralBaseAddr = (uint32_t)&instance_->DATAR;
165 dma_init.DMA_DIR = DMA_DIR_PeripheralSRC;
166 dma_init.DMA_Mode = DMA_Mode_Circular;
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);
177 ch32_dma_callback_t tx_cb_fun = [](
void* arg)
180 ch32_dma_register_callback(ch32_dma_get_id(CH32_UART_TX_DMA_CHANNEL_MAP[
id]),
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);
194 USART_Cmd(instance_, ENABLE);
198 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
199 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_rx_channel_)]);
204 NVIC_EnableIRQ(CH32_DMA_IRQ_MAP[ch32_dma_get_id(dma_tx_channel_)]);
207 NVIC_EnableIRQ(CH32_UART_IRQ_MAP[
id]);
227 if (!Ch32DataBitsSupported(config))
232 if (!Ch32StopBitsSupported(config))
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))
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); });
253 USART_ITConfig(instance_, USART_IT_TC, DISABLE);
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;
263 usart_cfg.USART_Parity = USART_Parity_No;
264 usart_cfg.USART_WordLength = USART_WordLength_8b;
267 usart_cfg.USART_Parity = USART_Parity_Even;
268 usart_cfg.USART_WordLength =
269 config.
data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
272 usart_cfg.USART_Parity = USART_Parity_Odd;
273 usart_cfg.USART_WordLength =
274 config.
data_bits == 7U ? USART_WordLength_8b : USART_WordLength_9b;
281 usart_cfg.USART_Mode = uart_mode_;
282 usart_cfg.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
283 USART_Init(instance_, &usart_cfg);
285 if (uart_mode_ & USART_Mode_Rx)
287 USART_DMACmd(instance_, USART_DMAReq_Rx, ENABLE);
288 USART_ITConfig(instance_, USART_IT_IDLE, ENABLE);
291 if (uart_mode_ & USART_Mode_Tx)
293 USART_DMACmd(instance_, USART_DMAReq_Tx, ENABLE);
296 USART_Cmd(instance_, ENABLE);
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); });
308void CH32UART::HandleTxService(uint32_t events,
bool in_isr)
310 if ((events & TX_EVENT_CONFIG) != 0U)
312 ConfigState state = config_state_.load(std::memory_order_acquire);
313 if (state == ConfigState::RESERVED)
315 config_state_.store(ConfigState::PUBLISHED, std::memory_order_release);
319 DEV_ASSERT_FROM_CALLBACK(state == ConfigState::PUBLISHED, in_isr);
323 if ((events & TX_EVENT_DMA_DONE) != 0U)
325 HandleTxDone(in_isr);
328 if ((events & TX_EVENT_RX_WORK) != 0U)
330 HandleRxData(in_isr);
333 if ((events & (TX_EVENT_CONFIG | TX_EVENT_DMA_DONE | TX_EVENT_TC)) != 0U)
335 TryApplyConfig(in_isr);
338 if ((uart_mode_ & USART_Mode_Tx) != 0U &&
339 (events & (TX_EVENT_WRITE | TX_EVENT_DMA_DONE | TX_EVENT_CONFIG | TX_EVENT_TC)) !=
341 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
347void CH32UART::FillTx(
bool in_isr)
353 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
364 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
372 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
389 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
398 config_state_.load(std::memory_order_acquire) == ConfigState::EMPTY)
403 const size_t size = queue.AvailableSize();
412void CH32UART::HandleTxDone(
bool in_isr)
424void CH32UART::TryApplyConfig(
bool in_isr)
426 if (config_state_.load(std::memory_order_acquire) != ConfigState::PUBLISHED)
436 if ((uart_mode_ & USART_Mode_Tx) != 0U &&
437 USART_GetFlagStatus(instance_, USART_FLAG_TC) == RESET)
439 USART_ITConfig(instance_, USART_IT_TC, ENABLE);
448 const size_t remaining = dma_rx_channel_->CNTR;
450 const size_t position =
455 config_state_.store(ConfigState::EMPTY, std::memory_order_release);
459void CH32UART::StartTxDma(
bool in_isr)
462 DEV_ASSERT_FROM_CALLBACK(size != 0U && size <=
dma_buff_tx_.
Size(), in_isr);
464 DMA_Cmd(dma_tx_channel_, DISABLE);
466 dma_tx_channel_->CNTR = size;
468 DMA_Cmd(dma_tx_channel_, ENABLE);
472void CH32UART::HandleRxData(
bool in_isr)
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;
484 DEV_ASSERT_FROM_CALLBACK(last_pos < dma_size, in_isr);
486 if (curr_pos != last_pos)
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;
492 size_t accepted = std::min(first_size + second_size, queue.EmptySize());
496 const size_t first_accepted = std::min(first_size, accepted);
497 if (first_accepted != 0U)
499 [[maybe_unused]]
const auto push_batch_result = queue.PushBatch(
501 DEV_ASSERT_FROM_CALLBACK(push_batch_result ==
ErrorCode::OK, in_isr);
502 accepted -= first_accepted;
506 [[maybe_unused]]
const auto push_batch_result =
508 DEV_ASSERT_FROM_CALLBACK(push_batch_result ==
ErrorCode::OK, in_isr);
519 const bool idle = USART_GetITStatus(instance_, USART_IT_IDLE) != RESET;
520 const bool tc = USART_GetITStatus(instance_, USART_IT_TC) != RESET;
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); });
531 if (config_state_.load(std::memory_order_acquire) != ConfigState::EMPTY)
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); });
539 USART_ITConfig(instance_, USART_IT_TC, DISABLE);
544extern "C" void ch32_uart_isr_handler_idle(ch32_uart_id_t
id)
546 auto uart = CH32UART::map_[id];
549 uart->UartIRQHandler();
557 if (DMA_GetITStatus(CH32_UART_TX_DMA_IT_MAP[id_]) == RESET)
562 if (dma_tx_channel_->CNTR == 0)
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); });
575 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_HT_MAP[id_]) == SET)
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); });
582 if (DMA_GetITStatus(CH32_UART_RX_DMA_IT_TC_MAP[id_]) == SET)
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); });
592extern "C" void USART1_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
594extern "C" void USART1_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART1); }
598extern "C" void USART2_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
600extern "C" void USART2_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART2); }
604extern "C" void USART3_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
606extern "C" void USART3_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART3); }
610extern "C" void USART4_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
612extern "C" void USART4_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART4); }
616extern "C" void USART5_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
618extern "C" void USART5_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART5); }
622extern "C" void USART6_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
624extern "C" void USART6_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART6); }
628extern "C" void USART7_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
630extern "C" void USART7_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART7); }
634extern "C" void USART8_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
636extern "C" void USART8_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_USART8); }
640extern "C" void UART1_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
642extern "C" void UART1_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART1); }
646extern "C" void UART2_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
648extern "C" void UART2_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART2); }
652extern "C" void UART3_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
654extern "C" void UART3_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART3); }
658extern "C" void UART4_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
660extern "C" void UART4_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART4); }
664extern "C" void UART5_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
666extern "C" void UART5_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART5); }
670extern "C" void UART6_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
672extern "C" void UART6_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART6); }
676extern "C" void UART7_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
678extern "C" void UART7_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART7); }
682extern "C" void UART8_IRQHandler(
void) __attribute__((interrupt(
"WCH-Interrupt-fast")));
684extern "C" void UART8_IRQHandler(
void) { ch32_uart_isr_handler_idle(CH32_UART8); }
使用循环接收 DMA 和双缓冲发送的 CH32 串口 / CH32 UART with circular RX DMA and double-buffered TX.
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.
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.
ReadPort _read_port
接收字节队列与读请求 / RX byte queue and read requests.
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.
WritePort _write_port
写请求及发送字节队列 / Write requests and TX byte queue.
void UartIRQHandler()
处理接收空闲和发送完成中断 / Handle RX idle and TX complete interrupts.
Flag::Plain tx_busy_
发送半区是否在使用,仅后端处理器访问 / TX half in use; service-only access.
RawData dma_buff_rx_
调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.
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
bool IsSet() const noexcept
判断是否已置位 / Check whether the flag is set
void Clear() noexcept
清除标志 / Clear the flag
可写原始数据视图 / 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.
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)
@ NO_PARITY
无校验 / No 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.
ErrorCode
定义错误码枚举 / Defines an enumeration for error codes
@ 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.
uint8_t stop_bits
停止位长度 / Number of stop bits
uint32_t baudrate
波特率 / Baud rate