[研电赛技术支持] GD32F407ZET6的通用的串口闲时中断+DMA

[复制链接]
小海师 发表于 2025-8-26 08:44 | 显示全部楼层 |阅读模式
#ifndef USART2_H_
#define USART2_H_

#include <stdio.h>
#include "gd32f4xx.h"

#define USART2_DATA_ADDRESS      ((uint32_t)&USART_DATA(USART2))

#define  USART2_TRANSMIT_GROOVE_SIZE    5   //
#define  USART2_TRANSMIT_BUFFER_SIZE    15   //
#define  USART2_RECEIVE_GROOVE_SIZE     5    //
#define  USART2_RECEIVE_BUFFER_SIZE     15   //

typedef enum {USART_DMA_UNDONE = 0, USART_DMA_DONE = !USART_DMA_UNDONE} USART_DMAState;

typedef void (*usart2_handler_t)(uint8_t *pBuff, uint8_t len);

/********************************************* USART1 *******************************************/
//写USART2发送缓冲区
#define WriteDataToUSART2TraismitBufferDone(  ) ucUSART2_TransmitWritingBytePointer = 0; \
        ucWtiteDataToUSART2TransmitGrooveIndex = ( (ucWtiteDataToUSART2TransmitGrooveIndex+1) == USART2_TRANSMIT_GROOVE_SIZE ) ? 0 : (ucWtiteDataToUSART2TransmitGrooveIndex+1);\
        ucUSART2_TransmitMessageNumber++

//USART2发送 DMA传输完成
#define DMA0_CH3TransmitDone(  ) \
        ucDMA0_CH3_SUB4_TransmitGrooveIndex = ( (ucDMA0_CH3_SUB4_TransmitGrooveIndex+1) == USART2_TRANSMIT_GROOVE_SIZE ) ? 0 : (ucDMA0_CH3_SUB4_TransmitGrooveIndex+1)

//USART2接收 DMA接收完成  
#define DMA0_CH1_SUB4_ReceiveDone(  ) \
        ucDMA0_CH1_SUB4_ReceiveGrooveIndex = ( (ucDMA0_CH1_SUB4_ReceiveGrooveIndex+1) == USART2_RECEIVE_GROOVE_SIZE ) ? 0 : (ucDMA0_CH1_SUB4_ReceiveGrooveIndex+1);\
        ucUSART2_ReceiveMessageNumber++

//USART2 接收缓冲数据读取完成  
#define USART2ReceiveDataReadDone(  ) \
        ucUSART2ReadBufferIndex = ( (ucUSART2ReadBufferIndex+1) == USART2_RECEIVE_GROOVE_SIZE ) ? 0 : (ucUSART2ReadBufferIndex+1);\
        ucUSART2_ReceiveMessageNumber--

//获取测试未处理消息数
#define usartGET_TEST_RECEIVE_MESSAGE_NUMBER(  )  ucUSART2_ReceiveMessageNumber


void Usart2_init(void);
void Usart2_TX_Init(uint8_t *MemoryAddr,uint32_t DataSize);
void Usart2_RX_Init(uint8_t *MemoryAddr,uint32_t DataSize);

void Process_usart2_cmd(void);
void Send_usart2_cmd(void);
void insert_usart2_cmd(uint8_t * buff,uint8_t len);

int32_t Usart2_Callback_Register(usart2_handler_t callback);

#endif





#include "usart2.h"

#include "MY_RTT.h"

static usart2_handler_t usart2_callback_handler = {NULL};


/****************************USART2收发相关变量***********************************/
uint8_t ucUSART2TrainsmitBuffer[USART2_TRANSMIT_GROOVE_SIZE][USART2_TRANSMIT_BUFFER_SIZE] = {0}; //USART2发送数据缓冲区
uint8_t ucUSART2TrainsmitLength[USART2_TRANSMIT_GROOVE_SIZE];    //USART2缓冲区长度  
uint8_t ucDMA0_CH3_SUB4_TransmitGrooveIndex = 0;                   //DMA0_CH7 传输第几个缓冲
uint8_t ucUSART2_TransmitMessageNumber = 0;                      //USART2需要传输的消息数   
uint8_t ucWtiteDataToUSART2TransmitGrooveIndex = 0;              //发送USART2第几个缓冲                                               
uint8_t ucUSART2_TransmitWritingBytePointer = 0;                 //USART2发送数据缓冲区下标

uint8_t ucUSART2ReceiveBuffer[USART2_RECEIVE_GROOVE_SIZE][USART2_RECEIVE_BUFFER_SIZE] = {0};    //USART2接收数据缓冲区
uint8_t ucUSART2ReceiveBufferLength[USART2_RECEIVE_GROOVE_SIZE];                                //USART2接收数据缓冲区数据长度     
uint8_t ucUSART2ReceiveGrooveIndex = 0;                          //USART2接收第几个缓冲
uint8_t ucUSART2ReadBufferIndex = 0;                             //读取USART2第几个缓冲
uint8_t ucUSART2ReceiveWritingBytePointer = 0;                   //USART2接收缓冲下标   
uint8_t ucDMA0_CH1_SUB4_ReceiveGrooveIndex = 0;                    //DMA0_CH2接收第几个缓冲
uint8_t ucUSART2_ReceiveMessageNumber = 0;                       //USART2还未处理的消息数

uint8_t buff2[5] = {0x11,0x22,0x33,0x44,0x55};

// USART2_RX   DMA0 CH1 SUB4
// USART2_TX   DMA0 CH3 SUB4

void Usart2_init(void)
{
          /* enable GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART2);
       
          rcu_periph_clock_enable(RCU_DMA0);
       
          //nvic_irq_enable(DMA0_Channel1_IRQn, 1, 0);
    //nvic_irq_enable(DMA0_Channel3_IRQn, 1, 1);
       
          nvic_irq_enable(USART2_IRQn, 0, 0);
       
                //Usart2_TX_Init(ucUSART2TrainsmitBuffer[ucDMA0_CH5_SUB4_TransmitGrooveIndex],USART2_TRANSMIT_BUFFER_SIZE);
          Usart2_TX_Init(buff2,USART2_TRANSMIT_BUFFER_SIZE);
                Usart2_RX_Init(ucUSART2ReceiveBuffer[ucUSART2ReceiveGrooveIndex],USART2_RECEIVE_BUFFER_SIZE);
                  
    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_10);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOB, GPIO_AF_7, GPIO_PIN_11);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_10);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_11);

    /* configure USART */
    usart_deinit(USART2);
    usart_baudrate_set(USART2, 115200U);
    usart_receive_config(USART2, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART2, USART_TRANSMIT_ENABLE);
    usart_dma_receive_config(USART2, USART_RECEIVE_DMA_ENABLE);
    usart_enable(USART2);
               
    usart_interrupt_enable(USART2, USART_INT_IDLE);
               
                usart_dma_transmit_config(USART2, USART_TRANSMIT_DMA_ENABLE);
    usart_dma_receive_config(USART2, USART_RECEIVE_DMA_ENABLE);
}

// USART2_RX   DMA0 CH1 SUB4
// USART2_TX   DMA0 CH3 SUB4
void Usart2_TX_Init(uint8_t *MemoryAddr,uint32_t DataSize)
{
    dma_single_data_parameter_struct dma_init_struct;

    /* deinitialize DMA0 channel7(USART2 TX) */
    dma_single_data_para_struct_init(&dma_init_struct);
    dma_deinit(DMA0, DMA_CH3);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;
    dma_init_struct.memory0_addr = (uint32_t)MemoryAddr;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;
    dma_init_struct.number = DataSize;
    dma_init_struct.periph_addr = USART2_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_CH3, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH3);
    dma_channel_subperipheral_select(DMA0, DMA_CH3, DMA_SUBPERI4);
    /* enable DMA0 channel7 transfer complete interrupt */
    dma_interrupt_enable(DMA0, DMA_CH3, DMA_CHXCTL_FTFIE);
    /* enable DMA0 channel7 */
    dma_channel_enable(DMA0, DMA_CH3);
}
// USART2_RX   DMA0 CH1 SUB4
// USART2_TX   DMA0 CH3 SUB4
void Usart2_RX_Init(uint8_t *MemoryAddr,uint32_t DataSize)
{
    dma_single_data_parameter_struct dma_init_struct;

    rcu_periph_clock_enable(RCU_DMA0);

    dma_deinit(DMA0, DMA_CH1);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr = (uint32_t)MemoryAddr;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = DataSize;
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART2);
    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_CH1, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH1);
    dma_channel_subperipheral_select(DMA0, DMA_CH1, DMA_SUBPERI4);
    /* enable DMA0 channel2 */
    dma_channel_enable(DMA0, DMA_CH1);
}


void USART2_IRQHandler(void)
{
    if(RESET != usart_interrupt_flag_get(USART2, USART_INT_FLAG_IDLE)){
        /* clear IDLE flag */
        usart_data_receive(USART2);

        /* number of data received */
        //rx_count = 256 - (dma_transfer_number_get(DMA0, DMA_CH2));
        //receive_flag = 1;
                       
                          ucUSART2ReceiveBufferLength[ucDMA0_CH1_SUB4_ReceiveGrooveIndex] = USART2_RECEIVE_BUFFER_SIZE - (dma_transfer_number_get(DMA0, DMA_CH1));

                          //LOG_INFO("len = %d %02x\r\n", ucUSART2ReceiveBufferLength[ucDMA0_CH5_SUB4_ReceiveGrooveIndex],ucUSART2ReceiveBuffer[ucDMA0_CH5_SUB4_ReceiveGrooveIndex][0]);
                       
                       
                          DMA0_CH1_SUB4_ReceiveDone(  );
                       
                          
        /* disable DMA and reconfigure */
        dma_channel_disable(DMA0, DMA_CH1);
        dma_flag_clear(DMA0, DMA_CH1, DMA_FLAG_FTF);
                          dma_memory_address_config(DMA0,DMA_CH1,DMA_MEMORY_0,(uint32_t)(&(ucUSART2ReceiveBuffer[ucDMA0_CH1_SUB4_ReceiveGrooveIndex][0])) );
        dma_transfer_number_config(DMA0, DMA_CH1, USART2_RECEIVE_BUFFER_SIZE);
        dma_channel_enable(DMA0, DMA_CH1);
    }
}

void Process_usart2_cmd(void)
{
   int i = 0;
       
         if(ucUSART2_ReceiveMessageNumber > 0)
         {
                 LOG_INFO("INFO: ");
                 
                 for(i = 0; i < ucUSART2ReceiveBufferLength[ucUSART2ReadBufferIndex];i++)
                 {                 
                  LOG_INFO("%02x ",ucUSART2ReceiveBuffer[ucUSART2ReadBufferIndex][i]);
                 }
                 
                 LOG_INFO("\r\n");                 
                 
                 if(usart2_callback_handler != NULL)
                 {
                    usart2_callback_handler(ucUSART2ReceiveBuffer[ucUSART2ReadBufferIndex],ucUSART2ReceiveBufferLength[ucUSART2ReadBufferIndex]);
                 }
            
           USART2ReceiveDataReadDone();         
         }

}

/*
  memcpy(ucUSART2TrainsmitBuffer[ucWtiteDataToUSART2TransmitGrooveIndex],buff2);
        ucUSART2TrainsmitLength[ucWtiteDataToUSART2TransmitGrooveIndex]=NUM;/
        WriteDataToUSART2TraismitBufferDone();

*/

void insert_usart2_cmd(uint8_t * buff,uint8_t len)
{
  memcpy(ucUSART2TrainsmitBuffer[ucWtiteDataToUSART2TransmitGrooveIndex],buff,len);
       
        ucUSART2TrainsmitLength[ucWtiteDataToUSART2TransmitGrooveIndex] = len;
       
        WriteDataToUSART2TraismitBufferDone();
}


void Send_usart2_cmd(void)
{
          static USART_DMAState DMA0_CH3Flag = USART_DMA_DONE;
       
   int i = 0;

        if(ucUSART2_TransmitMessageNumber > 0)
        {
                 if(dma_flag_get(DMA0,DMA_CH3,DMA_FLAG_FTF) == SET)
                 {
                   dma_flag_clear(DMA0,DMA_CH3,DMA_FLAG_FTF);
                         DMA0_CH3TransmitDone();
                   DMA0_CH3Flag = USART_DMA_DONE;
                 }
                 
                 if(DMA0_CH3Flag == USART_DMA_DONE)
                 {                 
                                DMA0_CH3Flag = USART_DMA_UNDONE;
                         
                                dma_channel_disable(DMA0, DMA_CH3);
                         
                                ucUSART2_TransmitMessageNumber--;
                         
        dma_flag_clear(DMA0, DMA_CH3, DMA_FLAG_FTF);
                          dma_memory_address_config(DMA0,DMA_CH3,DMA_MEMORY_0,(uint32_t)(ucUSART2TrainsmitBuffer[ucWtiteDataToUSART2TransmitGrooveIndex])  );
        dma_transfer_number_config(DMA0, DMA_CH3, ucUSART2TrainsmitLength[ucWtiteDataToUSART2TransmitGrooveIndex]);         

        dma_channel_enable(DMA0, DMA_CH3);

                         usart_dma_transmit_config(USART2,USART_TRANSMIT_DMA_ENABLE);               
                         
             //while(RESET == dma_flag_get(DMA0, DMA_CH3, DMA_FLAG_FTF));                 
                       
                 }
         }
       
}


int32_t Usart2_Callback_Register(usart2_handler_t callback)
{
          if (callback == NULL) {
                return 1;
        }
        if(usart2_callback_handler == callback) {
                        return 0;
                }
       
        if(usart2_callback_handler == NULL) {
                        usart2_callback_handler = callback;
                        return 0;
                }

        return 1;

}




————————————————
版权声明:本文为CSDN博主「SSONICX」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_43996145/article/details/149906518

内政奇才 发表于 2025-8-26 16:44 | 显示全部楼层
非常高效的方式,特别适用于不定长数据帧的接收。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

67

主题

210

帖子

1

粉丝
快速回复 在线客服 返回列表 返回顶部