GD32F4串口驱动记录(rtos+event+dma收发方式)
【代码】GD32F4串口驱动记录(rtos+event+dma收发方式)
·
前言
- 本次测试基于GD32F425RGT6核心板
- 驱动暂时只编写了USART0,其余的可以参考实现的
- 驱动编写参考官方手册和官方库提供的标准库里的示例程序
串口驱动
驱动头文件
/**
******************************************************************************
* @file : drv_usart.h
* @author : shchl
* @brief : None
* @attention : None
* @date : 2026/3/18
******************************************************************************
*/
#ifndef GD32F425_PROJECT_DRV_USART_H
#define GD32F425_PROJECT_DRV_USART_H
void DrvUsartInit(void);
int SerialInit(uint32_t usart_periph);
int SerialStart(uint32_t usart_periph, uint32_t baud);
int SerialSendAsync(uint32_t usart_periph,uint8_t* buf, uint16_t len, int32_t timeout);
int SerialRecv(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout);
#endif //GD32F425_PROJECT_DRV_USART_H
源文件
/**
******************************************************************************
* @file : drv_usart.c
* @author : shchl
* @brief : None
* @attention : None
* @date : 2026/3/18
******************************************************************************
*/
#include "drivers.h"
#include "drv_usart.h"
#define USART_RX_EVT 0x01 // 接收到数据
#define USART_TX_EVT 0x02 // 发送完成
#define USART_RS_TX_MODE 0
#define USART_RS_RX_MODE 1
#define U0_RS_ENABLE 1
#define U0_RS_CLK RCU_GPIOA
#define U0_RS_PORT GPIOA
#define U0_RS_PIN GPIO_PIN_8
#define U0_CACHE_BUF_LEN 256
#define U0_DMA DMA1
#define U0_RX_DMA_CH DMA_CH2
#define U0_TX_DMA_CH DMA_CH7
#define U1_RS_ENABLE 1
#define U1_RS_CLK RCU_GPIOB
#define U1_RS_PORT GPIOB
#define U1_RS_PIN GPIO_PIN_7
#define U1_CACHE_BUF_LEN 256
#define U2_RS_ENABLE 1
#define U2_RS_CLK RCU_GPIOB
#define U2_RS_PORT GPIOB
#define U2_RS_PIN GPIO_PIN_7
#define U2_CACHE_BUF_LEN 256
typedef struct
{
uint32_t instance;
osEventFlagsId_t evtHandle;
struct rt_ringbuffer rxRb;
uint8_t* pRxBuf;
uint8_t* pRbBuf;
uint16_t rxBufLen;
uint16_t rbBufLen;
uint8_t isInit;
} SerialDriver_t;
static uint8_t u0RxBuf[U0_CACHE_BUF_LEN] = {0};
static uint8_t u0RxRbBuf[U0_CACHE_BUF_LEN * 2] = {0};
static SerialDriver_t u0 = {
.instance = USART0,
.evtHandle = NULL,
.pRbBuf = u0RxRbBuf,
.pRxBuf = u0RxBuf,
.rxBufLen = sizeof(u0RxBuf),
.rbBufLen = sizeof(u0RxRbBuf),
.isInit = 0,
};
static uint8_t u1RxBuf[U1_CACHE_BUF_LEN] = {0};
static uint8_t u1RxRbBuf[U1_CACHE_BUF_LEN * 2] = {0};
static SerialDriver_t u1 = {
.instance = USART1,
.evtHandle = NULL,
.pRbBuf = u1RxRbBuf,
.pRxBuf = u1RxBuf,
.rxBufLen = sizeof(u1RxBuf),
.rbBufLen = sizeof(u1RxRbBuf),
.isInit = 0,
};
static uint8_t u2RxBuf[U2_CACHE_BUF_LEN] = {0};
static uint8_t u2RxRbBuf[U2_CACHE_BUF_LEN * 2] = {0};
static SerialDriver_t u2 = {
.instance = USART2,
.evtHandle = NULL,
.pRbBuf = u2RxRbBuf,
.pRxBuf = u2RxBuf,
.rxBufLen = sizeof(u2RxBuf),
.rbBufLen = sizeof(u2RxRbBuf),
.isInit = 0,
};
static SerialDriver_t* GetSerialDriver(uint32_t usart_periph)
{
if (usart_periph == USART0)
return &u0;
if (usart_periph == USART1)
return &u1;
if (usart_periph == USART2)
return &u2;
return NULL;
}
void DrvUsartInit(void)
{
SerialInit(USART0);
}
/**
*
* @param usart_periph
* @param mode 1:接收 0:发送
*/
static void instance_set_mode(uint32_t usart_periph, uint8_t mode)
{
#if U0_RS_ENABLE
if (usart_periph == USART0)
{
gpio_bit_write(U0_RS_PORT,U0_RS_PIN, mode ? RESET : SET);
}
else
#endif // U0_RS_ENABLE
#if U2_RS_ENABLE
if (usart_periph == USART2)
{
gpio_bit_write(U2_RS_PORT,U2_RS_PIN, mode ? RESET : SET);
}
#endif
}
int SerialInit(uint32_t usart_periph)
{
SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
assert(pSerial);
if (pSerial->isInit)
{
return 0;
}
pSerial->evtHandle = osEventFlagsNew(NULL);
if (!pSerial->evtHandle)
{
return -1;
}
rt_ringbuffer_init(&pSerial->rxRb, pSerial->pRbBuf, pSerial->rbBufLen);
if (usart_periph == USART0)
{
//============================NVIC==========================
nvic_irq_enable(USART0_IRQn, 5, 0);
//===========================时钟初始化==========================
rcu_periph_clock_enable(RCU_DMA1);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_USART0);
//===========================引脚初始化==========================
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_9); // TX
gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_10); // RX
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_9);
gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_9);
gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
#if U0_RS_ENABLE
rcu_periph_clock_enable(U0_RS_CLK);
gpio_mode_set(U0_RS_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, U0_RS_PIN);
gpio_output_options_set(U0_RS_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, U0_RS_PIN);
#endif
// ===========================串口初始化==========================
usart_deinit(USART0);
usart_baudrate_set(USART0, 115200U);
usart_receive_config(USART0, USART_RECEIVE_ENABLE);
usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
usart_enable(USART0);
// ===========================DMA初始化==========================
usart_dma_receive_config(USART0, USART_RECEIVE_DMA_ENABLE);
usart_dma_transmit_config(USART0, USART_TRANSMIT_DMA_ENABLE);
//============================DMA初始化(TX)==========================
dma_single_data_parameter_struct dma_param;
// 参数默认初始化
dma_single_data_para_struct_init(&dma_param);
dma_deinit(U0_DMA, U0_TX_DMA_CH);
dma_param.direction = DMA_MEMORY_TO_PERIPH;
// dma_param.memory0_addr = (uint32_t)txBuf;
// dma_param.number = sizeof(txBuf);
dma_param.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_param.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_param.periph_addr = ((uint32_t)&USART_DATA(USART0));
dma_param.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_param.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(U0_DMA, U0_TX_DMA_CH, &dma_param);
dma_circulation_disable(U0_DMA, U0_TX_DMA_CH);
dma_switch_buffer_mode_enable(U0_DMA, U0_TX_DMA_CH, DISABLE);
dma_channel_subperipheral_select(U0_DMA, U0_TX_DMA_CH, DMA_SUBPERI4);
// 开启串口完成中断
usart_interrupt_enable(USART0, USART_INT_TC);
// ============================DMA初始化(RX)==========================
dma_deinit(U0_DMA, U0_RX_DMA_CH);
dma_param.direction = DMA_PERIPH_TO_MEMORY;
dma_param.memory0_addr = (uint32_t)pSerial->pRxBuf;
dma_param.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_param.number = pSerial->rxBufLen;
dma_param.periph_addr = ((uint32_t)&USART_DATA(USART0));
dma_param.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_param.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_param.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(U0_DMA, U0_RX_DMA_CH, &dma_param);
dma_switch_buffer_mode_enable(U0_DMA, U0_RX_DMA_CH, DISABLE);
dma_circulation_disable(U0_DMA, U0_RX_DMA_CH);
dma_channel_subperipheral_select(U0_DMA, U0_RX_DMA_CH, DMA_SUBPERI4);
dma_channel_enable(U0_DMA, U0_RX_DMA_CH);
}
else if (usart_periph == USART1)
{
}
else if (usart_periph == USART2)
{
nvic_irq_enable(USART2_IRQn, 5, 0);
rcu_periph_clock_enable(RCU_DMA1);
}
else
{
return -2;
}
pSerial->isInit = 1;
return 0;
}
int SerialStart(uint32_t usart_periph, uint32_t baud)
{
SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
assert(pSerial);
if (!pSerial->isInit) return -1;
// USART使能(UEN=0)
usart_disable(usart_periph);
// 设置波特率;使能USART(UEN=1)时,不能写该寄存器。
usart_baudrate_set(usart_periph, baud);
// USART使能(UEN=1)
usart_enable(usart_periph);
// 开启串口空闲中断
usart_interrupt_enable(usart_periph, USART_INT_IDLE);
instance_set_mode(usart_periph, USART_RS_RX_MODE);
return 0;
}
int SerialSendAsync(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout)
{
SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
assert(pSerial);
if (!pSerial->isInit) return -1;
instance_set_mode(usart_periph, USART_RS_TX_MODE);
if (usart_periph == USART0)
{
// 停止DMA
dma_channel_disable(U0_DMA, U0_TX_DMA_CH);
// 设置DMA传输地址
dma_memory_address_config(U0_DMA,U0_TX_DMA_CH, DMA_MEMORY_0, (uint32_t)buf);
dma_transfer_number_config(U0_DMA, U0_TX_DMA_CH, len);
// 启动DMA
dma_channel_enable(U0_DMA, U0_TX_DMA_CH);
// 等待发送完成
}
else
{
return -2;
}
const uint32_t flags = osEventFlagsWait(pSerial->evtHandle, USART_TX_EVT, osFlagsWaitAny, timeout);
// 设置串口模式为接收模式
instance_set_mode(usart_periph, USART_RS_RX_MODE);
if (flags & USART_TX_EVT)
{
return len;
}
return 0;
}
int SerialRecv(uint32_t usart_periph, uint8_t* buf, uint16_t len, int32_t timeout)
{
SerialDriver_t* pSerial = GetSerialDriver(usart_periph);
assert(pSerial);
if (!pSerial->isInit) return -1;
if (usart_periph == USART0)
{
}
else
{
return -2;
}
const uint32_t flags = osEventFlagsWait(pSerial->evtHandle, USART_RX_EVT, osFlagsWaitAny, timeout);
if (flags & USART_RX_EVT)
{
return rt_ringbuffer_get(&pSerial->rxRb, buf, len);
}
else
{
// todo 错误处理
}
return rt_ringbuffer_get(&pSerial->rxRb, buf, len);
}
void USART0_IRQHandler(void)
{
// 接收处理
if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) != RESET)
{
/* 清除接收标志位 */
usart_data_receive(USART0);
const uint16_t rx_len = U0_CACHE_BUF_LEN - dma_transfer_number_get(U0_DMA, U0_RX_DMA_CH);
// 拷贝数据(缓存区)
rt_ringbuffer_put_force(&u0.rxRb, u0.pRxBuf, rx_len);
// todo 保存数据
osEventFlagsSet(u0.evtHandle, USART_RX_EVT);
dma_channel_disable(U0_DMA, U0_RX_DMA_CH);
// 清除传输完成标志位,否则下次无法正常接收到数据
dma_flag_clear(U0_DMA, U0_RX_DMA_CH, DMA_FLAG_FTF);
// 重新配置缓存区配置
dma_transfer_number_config(U0_DMA, U0_RX_DMA_CH, u0.rxBufLen);
dma_channel_enable(U0_DMA, U0_RX_DMA_CH);
dma_channel_enable(DMA1, U0_RX_DMA_CH);
}
// 发送处理
else if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_TC) != RESET)
{
// 清除中断完成标志位
usart_interrupt_flag_clear(USART0, USART_INT_FLAG_TC);
// 传输完成,通知应用层
osEventFlagsSet(u0.evtHandle, USART_TX_EVT);
// 禁用DMA通道
dma_channel_disable(U0_DMA, U0_TX_DMA_CH);
// 清除对应的标志位
dma_flag_clear(U0_DMA, U0_TX_DMA_CH, DMA_FLAG_FTF);
}
else
{
usart_data_receive(USART0);
}
}
测试程序
/**
******************************************************************************
* @file : main.c
* @author : shchl
* @brief : None
* @attention : None
* @date : 2026/3/14
******************************************************************************
*/
#include "main.h"
#include "SEGGER.h"
#include "SEGGER_RTT.h"
#include "Service/ioctrl_service.h"
static void StartAppTask(void* argument);
static void CompLoggerInit(void* argument);
osThreadId_t appHandle;
const osThreadAttr_t appHandle_attributes = {
.name = "App",
.stack_size = 512 * 4,
.priority = (osPriority_t)osPriorityNormal,
};
/**
* ck_sys:系统时钟频率(200MHz)
* ck_ahb:AHB时钟频率(200MHz)
* ck_apb1:APB1时钟频率(50MHz)
* ck_apb2:APB2时钟频率(100MHz)
* @brief 应用程序入口函数.
* @retval int
*/
int main(void)
{
/* 设置NVIC优先级分组为4位抢占优先级,0位子优先级 */
nvic_priority_group_set(NVIC_PRIGROUP_PRE4_SUB0);
rcu_periph_clock_enable(RCU_SYSCFG);
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_TIMER1);
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
nvic_irq_enable(TIMER1_IRQn, 5, 0);
nvic_irq_enable(USART0_IRQn, 5, 0); // USART0: 通信优先级,较高优先级
//=============================================================================
//============================================================================
#ifdef DEBUG
SEGGER_RTT_Init();
#endif // DEBUG
// 初始化内核
osKernelInitialize();
// 创建主任务
appHandle = osThreadNew(StartAppTask, NULL, &appHandle_attributes);
/* Start scheduler */
osKernelStart();
while (1)
{
}
}
static void StartAppTask(void* argument)
{
DriverInit();
// 组件初始化
CompLoggerInit(argument);
// IO控制服务初始化
IoCtrl_ServiceInit();
IoCtrl_ServiceStart();
IoCtrl_Led0Blink();
DrvUsartInit();
SerialStart(USART0, 115200);
static uint8_t buf[128];
for (;;)
{
int sz = SerialRecv(USART0, buf, sizeof(buf), osWaitForever);
if (sz > 0)
{
SerialSendAsync(USART0, buf, sz, osWaitForever);
}
// log_d("Hello World!");
}
}
/**
* @brief 组件初始化(日志)
* @param argument
*/
static void CompLoggerInit(void* argument)
{
elog_init();
elog_set_fmt(ELOG_LVL_ASSERT, ELOG_FMT_ALL);
elog_set_fmt(ELOG_LVL_ERROR, ELOG_FMT_LVL | ELOG_FMT_TIME);
elog_set_fmt(ELOG_LVL_WARN, ELOG_FMT_LVL | ELOG_FMT_TIME);
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TIME);
elog_set_fmt(ELOG_LVL_DEBUG, ELOG_FMT_ALL & ~ELOG_FMT_FUNC & ~ELOG_FMT_DIR & ~ELOG_FMT_TAG);
elog_set_filter_lvl(ELOG_LVL_DEBUG);
elog_set_text_color_enabled(true); /*Eenbale color*/
/* start EasyLogger */
elog_start();
}
测试结果

更多推荐
所有评论(0)