使用硬件平台GD32F407VET6
1、GDF4串口配置+DMA
/*!
\brief configure DMA
\param[in] none
\param[out] none
\retval none
*/
void dma_config(void)
{
dma_single_data_parameter_struct dma_init_struct;
nvic_irq_enable(DMA0_Channel6_IRQn, 0, 0);
/* enable DMA0 */
rcu_periph_clock_enable(RCU_DMA0);
/* deinitialize DMA channel6(USART1 TX) */
dma_deinit(DMA0, DMA_CH6);
dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
dma_init_struct.memory0_addr = (uint32_t)0;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.number = 0;
dma_init_struct.periph_addr = USART1_DATA_ADDRESS;
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_struct);
/* configure DMA mode */
dma_circulation_disable(DMA0, DMA_CH6);
dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI4);
/* enable DMA0 channel6 transfer complete interrupt */
dma_interrupt_enable(DMA0, DMA_CH6, DMA_CHXCTL_FTFIE);
/* USART DMA enable for transmission and reception */
usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
nvic_irq_enable(DMA0_Channel5_IRQn, 0, 0);
dma_deinit(DMA0, DMA_CH5);
dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
dma_init_struct.memory0_addr = (uint32_t)sUartAttr.pReadDma;
dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
dma_init_struct.number = MW_UART_DMA_LEN;
dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART1);
dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
dma_single_data_mode_init(DMA0, DMA_CH5, &dma_init_struct);
/* configure DMA mode */
dma_circulation_enable(DMA0, DMA_CH5); /* 配置DMA的轮询模式,因为dma0的通道5对应RX,所以配置为轮询模式 */
dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);
/* enable DMA0 channel2 transfer complete interrupt */
dma_interrupt_enable(DMA0, DMA_CH5, DMA_CHXCTL_FTFIE);
/* 使能串口的DMA接收 */
usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
// /* enable DMA channel6 */
// dma_channel_enable(DMA0, DMA_CH6);
}
void USART1_config(void)
{
nvic_irq_enable(USART1_IRQn, 2, 3);
/* enable GPIO clock */
rcu_periph_clock_enable(RCU_GPIOD);
/* enable USART clock */
rcu_periph_clock_enable(RCU_USART1);
/* configure the USART0 TX pin and USART0 RX pin */
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_5);
gpio_af_set(GPIOD, GPIO_AF_7, GPIO_PIN_6);
/* configure USART0 TX as alternate function push-pull */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_5);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_5);
/* configure USART0 RX as alternate function push-pull */
gpio_mode_set(GPIOD, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
gpio_output_options_set(GPIOD, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
/* USART configure */
usart_deinit(USART1);
usart_baudrate_set(USART1, 115200);
usart_word_length_set(USART1, USART_WL_8BIT);
usart_stop_bit_set(USART1, USART_STB_1BIT);
usart_parity_config(USART1, USART_PM_NONE);
usart_hardware_flow_rts_config(USART1, USART_RTS_DISABLE);
usart_hardware_flow_cts_config(USART1, USART_CTS_DISABLE);
usart_receive_config(USART1, USART_RECEIVE_ENABLE);
usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
usart_enable(USART1);
/* 使能串口的空闲中断 */
usart_interrupt_enable(USART1, USART_INT_IDLE);
printf("USART_Init a usart transmit test example!");
// usart_interrupt_enable(USART1, USART_INT_RBNE);
}
/*!
\brief initialize exmc_norsram_parameter_struct with the default values
\param[in] none
\param[out] exmc_norsram_init_struct: the initialized struct exmc_norsram_parameter_struct pointer
\retval none
*/
void USART_Init()
{
/************************** 串口初始化 **********************************/
USART1_config();
/************************** DMA初始化 ****************** DMA0 CH6 ****************/
dma_config();
}
2、中断处理函数
/*!
\brief this function handles DMA1_Channel7_IRQHandler interrupt
\param[in] none
\param[out] none
\retval none
*/
uint8_t tran_OK = 0;
uint8_t tran_OKing = 0;
void DMA0_Channel6_IRQHandler(void)
{
/*
* 配合串口1的发送。功能是继续发送缓冲区未发送的数据。
* 发送完成配置的CNT次数后,会进入此中断函数
* tran_OKing:缓冲区不为空后,自加1。
* tran_OKing:表示缓冲区为空,自加1。
*/
int32_t TransNum = 0;
if(dma_interrupt_flag_get(DMA0, DMA_CH6, DMA_INT_FLAG_FTF)) {
dma_interrupt_flag_clear(DMA0, DMA_CH6, DMA_INT_FLAG_FTF);
MW_UART_ATTR *pUartAttr = &sUartAttr;
/*从发送循环缓冲区中获取数据*/
TransNum = CfifoBuff_Read(&pUartAttr->SendCFifo,(char *)(pUartAttr->pWriteDma),pUartAttr->DmaSize);
if(TransNum > 0)
{
tran_OKing++;
usart1_dma_send(pUartAttr->pWriteDma, TransNum);
}
else
{
tran_OK++;
pUartAttr->TransFlag = MW_TRANS_IDLE;
}
}
}
uint8_t rx_OK = 0;
void DMA0_Channel5_IRQHandler(void)
{
/*
* 配合串口1的接收空闲中断。功能是复位DMA的偏移量
* 1、为了串口1的空闲中断在处理数据时防止越界,将 pUartAttr->DamOffset置为0;
* 2、DMA为轮询方式进行数据搬运的,当搬运完配置的Cnt后,会进入此中断处理函数,
* 3、当有数据过来时,数据将会拷贝到缓冲区的起始位置;
* 4、注意:如果DMA为正常模式,那么当完成一次拷贝后,DMA会自动disable掉。
*/
if(dma_interrupt_flag_get(DMA0, DMA_CH5, DMA_INT_FLAG_FTF))
{
dma_interrupt_flag_clear(DMA0, DMA_CH5, DMA_INT_FLAG_FTF);
rx_OK++;
MW_UART_ATTR *pUartAttr = &sUartAttr;
/*复位DMA偏移量*/
pUartAttr->DamOffset = 0;
}
}
/*!
\brief this function handles USART interrupt request
\param[in] none
\param[out] none
\retval none
*/
void USART1_IRQHandler(void)
{
/* 串口1的接收空闲中断方式进行了数据缓存。*/
int32_t RecvNum = 0;
int32_t WriteNum = 0;
int32_t DmaIdleNum = 0;
if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE))
{
/* clear IDLE flag */
usart_data_receive(USART1);
MW_UART_ATTR *pUartAttr = &sUartAttr;
/*计算在DMA缓冲区需要获取的数据长度*/
DmaIdleNum = dma_transfer_number_get(DMA0, DMA_CH5);
RecvNum = pUartAttr->DmaSize - DmaIdleNum - pUartAttr->DamOffset;
/*将获取到的数据放到数据接收缓冲区中*/
WriteNum = CfifoBuff_Write(&pUartAttr->AcceptCFifo,(char *)(pUartAttr->pReadDma + pUartAttr->DamOffset),RecvNum);
if(WriteNum != RecvNum)
{
printf("Uart ReadFifo is not enough\r\n");
}
/*计算获取数据位置的偏移量*/
pUartAttr->DamOffset += RecvNum;
}
}
3、缓冲区的代码实现
3.1 cfifo_usart_dma.c
#include "cfifo_usart_dma.h"
#include "gd32f4xx_libopt.h"
/* 发送接收DMA的数据缓存 */
static uint8_t Uart1TxDma[MW_UART_DMA_LEN] = {0}; //DMA发送缓存区
static uint8_t Uart1RxDma[MW_UART_DMA_LEN] = {0}; //DMA接受缓存区
/* 一个串口的维护发送、接收、缓存的数据结构 */
MW_UART_ATTR sUartAttr;
/*!
\brief 串口1进行DMA的数据发送
\param[in] buffer:发送缓冲区
\param[in] len:发送缓冲区大小
\param[out] none
\retval none
*/
void usart1_dma_send(uint8_t *buffer,uint16_t len)
{
dma_channel_disable(DMA0, DMA_CH6);
dma_memory_address_config(DMA0, DMA_CH6,0,(uint32_t)buffer);
dma_transfer_number_config(DMA0, DMA_CH6, len);
/*清除DMA0_CH6 发送完成的标志*/
dma_flag_clear(DMA0, DMA_CH6,DMA_INTC_FTFIFC);
dma_channel_enable(DMA0, DMA_CH6);
}
/*!
\brief 初始化串口的缓冲区指针、DMA的空间大小、DMA偏移量、发送接收队列的初始化
\param[in] none
\param[out] none
\retval MW_SUCCESS:成功 MW_FAIL:失败
*/
int8_t MW_UART_Init()
{
/*为属性的参数附初值*/
MW_UART_ATTR *pUartAttr = &sUartAttr;
pUartAttr->DamOffset = 0;
pUartAttr->TransFlag = MW_TRANS_IDLE;
pUartAttr->DmaSize = MW_UART_DMA_LEN;
pUartAttr->pReadDma = Uart1RxDma;
pUartAttr->pWriteDma = Uart1TxDma;
CfifoBuff_Init(&pUartAttr->AcceptCFifo); //用于数据接受
CfifoBuff_Init(&pUartAttr->SendCFifo); //用于数据发送
return MW_SUCCESS;
}
/*!
\brief 通过循环队列的方式进行数据的发送
\param[in] buffer:发送缓冲区
\param[out] len:发送缓冲区大小
\retval 写入发送缓冲区的长度
*/
int32_t MW_UART_Transmit(uint8_t* buffer,int32_t len)
{
int32_t TransNum = 0;
int32_t TransLen = 0;
MW_UART_ATTR *pUartAttr = &sUartAttr;
/*将要发送的数据先写入循环缓冲区*/
TransNum = CfifoBuff_Write(&pUartAttr->SendCFifo, (char *) buffer, len);
/*如果发送DMA未在发送中,则使能发送*/
if(pUartAttr->TransFlag == MW_TRANS_IDLE)
{
TransLen = CfifoBuff_Read(&pUartAttr->SendCFifo,(char *)(pUartAttr->pWriteDma),pUartAttr->DmaSize);
if(TransLen > 0)
{
pUartAttr->TransFlag = MW_TRANS_BUSY;
usart1_dma_send(pUartAttr->pWriteDma, TransLen);
}
}
return TransNum;
}
3.2 cfifo_usart_dma.h
#ifndef _CFIFO_USART_DMA_H_
#define _CFIFO_USART_DMA_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "cfifo.h"
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
#define MW_FAIL 0
#define MW_SUCCESS 1
#define MW_TRANS_IDLE 0
#define MW_TRANS_BUSY 1
#define MW_UART_DMA_LEN 512
/* USER CODE END Private defines */
typedef struct
{
int16_t TransFlag; /*数据发送标志位*/
int32_t DmaSize; /*DMA缓冲区的大小*/
int32_t DamOffset; /*获取数据在DMA缓冲区的偏移量*/
uint8_t *pReadDma; /*指向接收DMA缓冲区的首地址*/
uint8_t *pWriteDma; /*指向发送DMA缓冲区的首地址*/
CfifoBuff AcceptCFifo; /*接受数据的循环缓冲区*/
CfifoBuff SendCFifo; /*发送数据的循环缓冲区*/
}MW_UART_ATTR;
extern MW_UART_ATTR sUartAttr;
/* USER CODE BEGIN Prototypes */
int8_t MW_UART_Init(); //初始化
int32_t MW_UART_Transmit(uint8_t* buffer,int32_t len); //CFIFO+DMA+Usart数据发送
void usart1_dma_send(uint8_t *buffer,uint16_t len);
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* _CFIFO_USART_DMA_H_ */
3.3 cfifo.c
#include "cfifo.h"
/*环形CFIFO初始化*/
void CfifoBuff_Init(CfifoBuff * Cfifo_pointer)
{
//初始化相关信息
Cfifo_pointer->Head = 0;
Cfifo_pointer->Tail = 0;
Cfifo_pointer->Lenght = 0;
memset(Cfifo_pointer->BUFF,'\0',CFIFO_SIZE); //环形CFIFO缓存区初始化
}
/*环形CFIFO数据清除*/
void CfifoBuff_Clear(CfifoBuff * Cfifo_pointer)
{
//清除相关信息
Cfifo_pointer->Head = 0;
Cfifo_pointer->Tail = 0;
Cfifo_pointer->Lenght = 0;
memset(Cfifo_pointer->BUFF,'\0',CFIFO_SIZE); //环形CFIFO缓存区清除
}
/*环形CFIFO数据写入*/
/*
*参数说明:
* Cfifo_pointer————环形CFIFO结构体
* User_buff————待写入数据
* num————写入数据长度
*
*返回值说明:正确写入到FIFO缓存区中的数据长度
*
*功能说明:将User_buff中的数据写入到环形CFIFO缓存区
*
*/
int16_t CfifoBuff_Write(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num)
{
int16_t i , wrint_num;
if(Cfifo_pointer->Lenght >= CFIFO_SIZE) //判断缓存区是否已满
{
wrint_num=-1;
return wrint_num; //数据溢出
}
if(Cfifo_pointer->Lenght+num<CFIFO_SIZE) //判断写入的数据长度是否超出当前可写入的最大值
{
wrint_num=num;
}
else
{
wrint_num=CFIFO_SIZE-Cfifo_pointer->Lenght;
}
for(i=0;i<wrint_num;i++)
{
Cfifo_pointer->BUFF[Cfifo_pointer->Tail]=*(User_buff+i);
Cfifo_pointer->Tail = (Cfifo_pointer->Tail+1)%CFIFO_SIZE;//防止越界非法访问
}
Cfifo_pointer->Lenght+=wrint_num;
return wrint_num; //返回正确写入的数据长度
}
/*环形CFIFO读取*/
/*
*参数说明:
* Cfifo_pointer————环形CFIFO结构体
* User_buff————读取数据存放地
* num————读取数据长度
*
*返回值说明:正确读取到User_buff的数据长度
*
*功能说明:将环形CFIFO缓存区的数据读取到User_buff
*
*/
int16_t CfifoBuff_Read(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num)
{
int16_t i , read_num;
if(Cfifo_pointer->Lenght == 0) //判断非空
{
read_num=-1;
return read_num; //没有数据
}
if(Cfifo_pointer->Lenght-num>=0) //判断读取的数据长度是否超出当前可读取的最大值
{
read_num=num;
}
else
{
read_num=Cfifo_pointer->Lenght;
}
for(i=0;i<read_num;i++)
{
*(User_buff+i)=Cfifo_pointer->BUFF[Cfifo_pointer->Head];
Cfifo_pointer->Head = (Cfifo_pointer->Head+1)%CFIFO_SIZE;//防止越界非法访问
}
Cfifo_pointer->Lenght-=read_num;
return read_num; //返回正确写入的数据长度
}
3.4 cfifo.h
#ifndef _CFIFO_H_
#define _CFIFO_H_
#ifdef __cplusplus
extern "C" {
#endif
/* Includes ------------------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <string.h>
#include <stdio.h>
#include "stdint.h"
/* USER CODE END Includes */
/* USER CODE BEGIN Private defines */
#define CFIFO_SIZE 2048 //环形队列CFIFO大小
/*环形CFIFO结构体*/
typedef struct
{
uint16_t Head; //环形CFIFO队列头
uint16_t Tail; //环形CFIFO队列尾
uint16_t Lenght; //环形CFIFO数据长度
uint8_t BUFF[CFIFO_SIZE]; //环形CFIFO缓存区
}CfifoBuff;
/* USER CODE END Private defines */
/* USER CODE BEGIN Prototypes */
void CfifoBuff_Init(CfifoBuff * Cfifo_pointer); //CFIFO初始化
void CfifoBuff_Clear(CfifoBuff * Cfifo_pointer); //CFIFO数据清除
int16_t CfifoBuff_Write(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num); //CFIFO数据写人
int16_t CfifoBuff_Read(CfifoBuff * Cfifo_pointer,char * User_buff,uint16_t num); //CFIFO数据读出
/* USER CODE END Prototypes */
#ifdef __cplusplus
}
#endif
#endif /* _CFIFO_H_ */
4、调用循序
先调用初始化函数MW_UART_Init , 再调用调用初始化函数USART_Init 。
5、自定义打印函数
#include "string.h"
#include "stdio.h"
#include "stdarg.h
void DbgPrintf(const char *format,...)
{
uint16_t len;
char sbuf[128];
va_list args;
va_start(args, format);
len = vsnprintf((char *)sbuf, sizeof(sbuf)-1, (char *)format, args);
va_end(args);
MW_UART_Transmit(sbuf, len);
}
————————————————
版权声明:本文为CSDN博主「shuangwei我是伟」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/m0_50089156/article/details/131791100
|
|