libxr
Embedded C++ framework for bare-metal, RTOS and Linux
Loading...
Searching...
No Matches
LibXR::CH32UART Class Reference

使用循环接收 DMA 和双缓冲发送的 CH32 串口 / CH32 UART with circular RX DMA and double-buffered TX. More...

#include <ch32_uart.hpp>

Inheritance diagram for LibXR::CH32UART:
[legend]
Collaboration diagram for LibXR::CH32UART:
[legend]

Public Member Functions

 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.
 
ErrorCode SetConfig (UART::Configuration config, bool in_isr=false) override
 提交串口配置请求 / Submit a UART configuration request.
 
void TxDmaIRQHandler ()
 处理发送 DMA 完成通知 / Handle TX DMA completion.
 
void RxDmaIRQHandler ()
 处理接收 DMA 进展通知 / Handle RX DMA progress.
 
void UartIRQHandler ()
 处理接收空闲和发送完成中断 / Handle RX idle and TX complete interrupts.
 
- Public Member Functions inherited from LibXR::UART
template<typename ReadPortType = ReadPort, typename WritePortType = WritePort>
 UART (ReadPortType *read_port, WritePortType *write_port)
 UART 构造函数 / UART constructor.
 
template<typename OperationType , typename = std::enable_if_t<std::is_base_of_v< WriteOperation, std::decay_t<OperationType>>>>
ErrorCode Write (ConstRawData data, OperationType &&op, bool in_isr=false)
 
template<typename OperationType , typename = std::enable_if_t<std::is_base_of_v< ReadOperation, std::decay_t<OperationType>>>>
ErrorCode Read (RawData data, OperationType &&op, bool in_isr=false)
 

Static Public Member Functions

static void WriteFun (WritePort &port, bool in_isr)
 通知后端处理已提交的写请求 / Notify the backend of released writes.
 

Public Attributes

ch32_uart_id_t id_
 
uint16_t uart_mode_
 
ReadPort _read_port
 接收字节队列与读请求 / RX byte queue and read requests.
 
WritePort _write_port
 写请求及发送字节队列 / Write requests and TX byte queue.
 
RawData dma_buff_rx_
 调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.
 
DoubleBuffer dma_buff_tx_
 当前与待发送的 DMA 半区 / Active and pending TX DMA halves.
 
size_t last_rx_pos_ = 0
 上次已处理的 DMA 接收位置 / Last processed RX DMA position.
 
USART_TypeDef * instance_
 
DMA_Channel_TypeDef * dma_rx_channel_
 
DMA_Channel_TypeDef * dma_tx_channel_
 
Flag::Plain tx_busy_
 发送半区是否在使用,仅后端处理器访问 / TX half in use; service-only access.
 
- Public Attributes inherited from LibXR::UART
ReadPort * read_port_
 读取端口 / Read port
 
WritePort * write_port_
 写入端口 / Write port
 

Static Public Attributes

static CH32UART * map_ [CH32_UART_NUMBER] = {nullptr}
 

Additional Inherited Members

- Public Types inherited from LibXR::UART
enum class  Parity : uint8_t { NO_PARITY = 0 , EVEN = 1 , ODD = 2 }
 奇偶校验模式 / Parity mode More...
 

Detailed Description

使用循环接收 DMA 和双缓冲发送的 CH32 串口 / CH32 UART with circular RX DMA and double-buffered TX.

写请求完整复制到发送缓冲半区后完成,DMA 完成仅释放半区。接收持续运行, 按 DMA 位置变化向 ReadPort 发布数据;软件队列放不下的部分作为接收溢出丢弃。 Writes complete once copied into a TX half; DMA completion only releases that half. RX runs continuously and publishes observed DMA bytes to ReadPort, discarding any overflow beyond available software capacity.

Precondition
调用遵守 ReadPort/WritePort 约定;DMA 缓冲区满足平台访问和对齐要求,运行期间有效。 Follow the port contracts. DMA buffers must meet platform access/alignment requirements and remain valid throughout operation.

Definition at line 32 of file ch32_uart.hpp.

Constructor & Destructor Documentation

◆ CH32UART()

CH32UART::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.

Parameters
id串口编号 / UART identifier.
dma_rx接收 DMA 缓冲区 / RX DMA buffer.
dma_tx双缓冲发送存储,每半区容纳一个请求 / TX storage, one request per half.
tx_gpio_port发送引脚端口 / TX GPIO port.
tx_gpio_pin发送引脚 / TX GPIO pin.
rx_gpio_port接收引脚端口 / RX GPIO port.
rx_gpio_pin接收引脚 / RX GPIO pin.
pin_remap引脚重映射配置,默认零 / Pin remapping, zero by default.
tx_queue_size写请求队列容量,启用发送时须大于零 / Positive TX request capacity.
config初始串口配置 / Initial UART configuration.

Definition at line 35 of file ch32_uart.cpp.

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}
使用循环接收 DMA 和双缓冲发送的 CH32 串口 / CH32 UART with circular RX DMA and double-buffered TX.
Definition ch32_uart.hpp:33
void RxDmaIRQHandler()
处理接收 DMA 进展通知 / Handle RX DMA progress.
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
WritePort _write_port
写请求及发送字节队列 / Write requests and TX byte queue.
Definition ch32_uart.hpp:83
RawData dma_buff_rx_
调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.
Definition ch32_uart.hpp:86
size_t size_
数据字节数 / Data size in bytes
void * addr_
数据起始地址 / Data start address
@ NO_PARITY
无校验 / No parity
@ ODD
奇校验 / Odd parity
@ EVEN
偶校验 / Even parity
UART(ReadPortType *read_port, WritePortType *write_port)
UART 构造函数 / UART constructor.
Definition uart.hpp:68
void(* WriteFun)(WritePort &port, bool in_isr)
写入进度通知函数类型 / Write progress notification function type.
uint8_t stop_bits
停止位长度 / Number of stop bits
Definition uart.hpp:53
uint32_t baudrate
波特率 / Baud rate
Definition uart.hpp:45

Member Function Documentation

◆ RxDmaIRQHandler()

void CH32UART::RxDmaIRQHandler ( )

处理接收 DMA 进展通知 / Handle RX DMA progress.

清除接收 DMA 中断标志并通知后端 / Clear RX DMA flags and notify the backend.

Definition at line 573 of file ch32_uart.cpp.

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}
bool Invoke(uint32_t events, bool in_isr, Handler &&handler) noexcept
发布事件并尝试取得执行权 / Publish events and attempt to claim execution.

◆ SetConfig()

ErrorCode CH32UART::SetConfig ( UART::Configuration config,
bool in_isr = false )
overridevirtual

提交串口配置请求 / Submit a UART configuration request.

Parameters
config目标配置 / Requested configuration.
in_isr当前调用是否在中断中 / Whether this call is in an ISR.
Returns
接纳返回 OK,配置槽被占用返回 BUSY,参数不支持返回 ARG_ERR 或 NOT_SUPPORT。 OK on admission, BUSY for an occupied slot, ARG_ERR or NOT_SUPPORT for unsupported settings.
Note
接纳后在发送空闲时应用,期间保留已准备的 DMA 数据;不保证返回前已经生效。 Applies when TX is idle while preserving prepared DMA data. May apply after return.

Implements LibXR::UART.

Definition at line 210 of file ch32_uart.cpp.

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}
@ BUSY
忙碌 / Busy
@ NOT_SUPPORT
不支持 / Not supported
@ OK
操作成功 / Operation successful
@ ARG_ERR
参数错误 / Argument error

◆ TxDmaIRQHandler()

void CH32UART::TxDmaIRQHandler ( )

处理发送 DMA 完成通知 / Handle TX DMA completion.

Definition at line 555 of file ch32_uart.cpp.

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}

◆ UartIRQHandler()

void CH32UART::UartIRQHandler ( )

处理接收空闲和发送完成中断 / Handle RX idle and TX complete interrupts.

Definition at line 517 of file ch32_uart.cpp.

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}

◆ WriteFun()

void CH32UART::WriteFun ( WritePort & port,
bool in_isr )
static

通知后端处理已提交的写请求 / Notify the backend of released writes.

Definition at line 299 of file ch32_uart.cpp.

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}
OwnerType * ContainerOf(MemberType *ptr, MemberType OwnerType::*member) noexcept
通过成员指针恢复其所属对象指针 Recover the owning object pointer from a member pointer

Member Data Documentation

◆ _read_port

ReadPort LibXR::CH32UART::_read_port

接收字节队列与读请求 / RX byte queue and read requests.

Definition at line 81 of file ch32_uart.hpp.

◆ _write_port

WritePort LibXR::CH32UART::_write_port

写请求及发送字节队列 / Write requests and TX byte queue.

Definition at line 83 of file ch32_uart.hpp.

◆ dma_buff_rx_

RawData LibXR::CH32UART::dma_buff_rx_

调用者提供的接收 DMA 缓冲区 / Caller-provided RX DMA buffer.

Definition at line 86 of file ch32_uart.hpp.

◆ dma_buff_tx_

DoubleBuffer LibXR::CH32UART::dma_buff_tx_

当前与待发送的 DMA 半区 / Active and pending TX DMA halves.

Definition at line 88 of file ch32_uart.hpp.

◆ dma_rx_channel_

DMA_Channel_TypeDef* LibXR::CH32UART::dma_rx_channel_

Definition at line 94 of file ch32_uart.hpp.

◆ dma_tx_channel_

DMA_Channel_TypeDef* LibXR::CH32UART::dma_tx_channel_

Definition at line 95 of file ch32_uart.hpp.

◆ id_

ch32_uart_id_t LibXR::CH32UART::id_

Definition at line 77 of file ch32_uart.hpp.

◆ instance_

USART_TypeDef* LibXR::CH32UART::instance_

Definition at line 93 of file ch32_uart.hpp.

◆ last_rx_pos_

size_t LibXR::CH32UART::last_rx_pos_ = 0

上次已处理的 DMA 接收位置 / Last processed RX DMA position.

Definition at line 91 of file ch32_uart.hpp.

◆ map_

CH32UART * CH32UART::map_ = {nullptr}
static

Definition at line 100 of file ch32_uart.hpp.

◆ tx_busy_

Flag::Plain LibXR::CH32UART::tx_busy_

发送半区是否在使用,仅后端处理器访问 / TX half in use; service-only access.

Definition at line 98 of file ch32_uart.hpp.

◆ uart_mode_

uint16_t LibXR::CH32UART::uart_mode_

Definition at line 78 of file ch32_uart.hpp.


The documentation for this class was generated from the following files: