1278|0

159

帖子

0

资源

一粒金砂(高级)

六、USART1发送和接收的DMA实现 [复制链接]

在下的GD32L233C-START专题测评:

一、开箱评测 http://bbs.eeworld.com.cn/thread-1192788-1-1.html

二、GD32L233C-START环境搭建http://bbs.eeworld.com.cn/thread-1193053-1-1.html

三、点灯案例与扩展http://bbs.eeworld.com.cn/thread-1193183-1-1.html

四、Demo工程的分析http://bbs.eeworld.com.cn/thread-1193279-1-1.html

五、USART0的printf实现和DMA实现http://bbs.eeworld.com.cn/thread-1193517-1-1.html


开学后,本人变得忙碌了,到了周末再发一篇,继续研究串口DMA,这回拿USART1来实现,并为后面连接ESP8266 AT模块做好准备。

1、案例思路

       本例以GD32L233C-START之USART1口的发送、接收功能实现,外加DMA方式作为目标,在工程中添加了Bsp目录,并添加自己的串口驱动文件“aita_gd32l233_usart.c”和“aita_gd32l233_usart.h”(当然,这是源于个人习惯,写在main.c里也一样)。

       头文件中,增加宏定义,用于条件编译,控制DMA发送和DMA接收的开启。

       源文件中,因为是DMA方式,定义了发送和接收缓存区,接收缓冲区索引量,发送中标志量。另外,为了在多个函数中可以配置DMA,定义了全局的“dma_parameter_struct(DMA参数配置)”结构体变量。

       USART1初始化与DMA初始化分别写成两个函数,由宏控制USART1初始化函数对DMA初始化函数的调用。发送功能函数也有宏来控制,分为开启DMA方式和不开启方式。DMA发送中判定标志量,以防止调用冲突。

       gd32l23x_it.c中,增加USART1中断函数和DMA通道2(用于发送)及通道3(用于接收)中断函数。USART1_IRQHandler()中,启用DMA时进行“空闲中断”检测以保证有接收即反应(否则是DMA缓存区收满才有反应),不启用时进行“接收中断”检测以实现收到字节即存入缓冲区。

2、代码实现

       “..\GD32L233C-START\GD32L233C_START_Demo_Suites\Projects\AITA_GD32L233C\Bsp\inc\aita_gd32l233_usart.h”(本人建立的路径)代码:

#ifndef _AITA_USART_H
#define _AITA_USART_H

//控制DMA是否启用
#define AITA_DMA_U1Tx_EN          1  //开启UART1口的DMA发送
#define AITA_DMA_U1Rx_EN          1  //开启UART1口的DMA接收
//DMA USART1 发送和接收寄存器地址
#define USART1_RDATA_ADDRESS      (&USART_RDATA(USART1))
#define USART1_TDATA_ADDRESS      (&USART_TDATA(USART1))
//USART1接收和发送缓存长度
#define USART1_BUF_LENGTH         128

#endif

 

        “..\GD32L233C-START\GD32L233C_START_Demo_Suites\Projects\AITA_GD32L233C\Bsp\inc\aita_gd32l233_usart.c”(本人建立的路径)代码:

#include "aita_sys.h"

//DMA USART1 用到的内存缓存
uint8_t u1txbuffer[USART1_BUF_LENGTH];
uint8_t u1rxbuffer[USART1_BUF_LENGTH];
//接收缓存索引
uint16_t u1rxindex = 0;
//发送中标志(用于DMA发送)
uint8_t u1txdoing = 0;
//全局DMA参数配置结构体变量
dma_parameter_struct dma_init_struct;

void aita_InitU1(void)
{
    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOA);
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);

    /* connect port to USART TX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
    /* connect port to USART RX */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);

    /* configure USART TX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_2);

    /* configure USART RX as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_3);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_3);

    /* USART configure */
    usart_deinit(USART1);
    usart_word_length_set(USART1, USART_WL_8BIT);
    usart_stop_bit_set(USART1, USART_STB_1BIT);
    usart_parity_config(USART1, USART_PM_NONE);
    usart_baudrate_set(USART1, 115200U);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);

    nvic_irq_enable(USART1_IRQn, 0);
    //启用Usart1 Rx DMA则开启空闲中断,否则开启接收中断
#if !AITA_DMA_U1Rx_EN
    usart_interrupt_enable(USART1, USART_INT_RBNE);
#else
    usart_interrupt_enable(USART1, USART_INT_IDLE);
#endif
    usart_enable(USART1);
		aita_InitDMAForU1();
}

void aita_InitDMAForU1(void) {
#if AITA_DMA_U1Tx_EN || AITA_DMA_U1Rx_EN
		/* enable DMA clock */
    rcu_periph_clock_enable(RCU_DMA);
#endif
    
#if AITA_DMA_U1Tx_EN
    /*configure DMA interrupt*/
    nvic_irq_enable(DMA_Channel2_IRQn, 0); //DMA CH2 for Uart1 Tx

    /* initialize DMA channel 2 */
    dma_deinit(DMA_CH2);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART1_TX;
    dma_init_struct.direction    = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr  = (uint32_t)u1txbuffer;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = ARRAYNUM(u1txbuffer);
    dma_init_struct.periph_addr  = (uint32_t)USART1_TDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH2, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH2);
    dma_memory_to_memory_disable(DMA_CH2);
    /* disable the DMAMUX_MUXCH2 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH2);
    /* USART DMA enable for transmission and reception */
    usart_dma_transmit_config(USART1, USART_DENT_ENABLE);
    /* enable DMA channel 2 transfer complete interrupt */
    dma_interrupt_enable(DMA_CH2, DMA_INT_FTF);
    /* disable DMA channel 2,每次发送时临时开启DMA */
    dma_channel_disable(DMA_CH2);
#endif

#if AITA_DMA_U1Rx_EN
    /*configure DMA interrupt*/
    nvic_irq_enable(DMA_Channel3_IRQn, 0); //DMA CH3 for Uart1 Rx

    /* initialize DMA channel 3 */
    dma_deinit(DMA_CH3);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.request      = DMA_REQUEST_USART1_RX;
    dma_init_struct.direction    = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr  = (uint32_t)u1rxbuffer;
    dma_init_struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number       = ARRAYNUM(u1rxbuffer);
    dma_init_struct.periph_addr  = (uint32_t)USART1_RDATA_ADDRESS;
    dma_init_struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority     = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH3, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA_CH3);
    dma_memory_to_memory_disable(DMA_CH3);
    /* disable the DMAMUX_MUXCH3 synchronization mode */
    dmamux_synchronization_disable(DMAMUX_MUXCH3);
    /* USART DMA enable for reception */
    usart_dma_receive_config(USART1, USART_DENR_ENABLE);
    /* enable DMA channel 3 transfer complete interrupt */
    dma_interrupt_enable(DMA_CH3, DMA_INT_FTF);
    /* enable DMA channel 3, 接收是被动的所以DMA要一直开启 */
    dma_channel_enable(DMA_CH3);
#endif
}

void aita_U1SendStr(uint8_t *arr, uint16_t len) {
#if AITA_DMA_U1Tx_EN //DMA发送模式,加载缓冲区,开启通道
  while(u1txdoing);
  memcpy(u1txbuffer, arr, len);
  aita_U1DMASend(len);
#else                //非DMA模式,程序查询,操作USART1_DR
  uint16_t i=0;
  while(i < len) {
    usart_data_transmit(USART1, arr[i++]);
    while(RESET == usart_flag_get(USART1, USART_FLAG_TBE));
  }
#endif
}

void aita_ClearU1RxBuffer(void) {
  memset(u1rxbuffer, 0, USART1_BUF_LENGTH);
  u1rxindex = 0;
}

#if AITA_DMA_U1Tx_EN
void aita_U1DMASend(uint16_t size) {
  u1txdoing = 1;
  dma_transfer_number_config(DMA_CH2, size);
  dma_channel_enable(DMA_CH2);
}
#endif

 

       也是建立的系统头文件aita_sys.h中,新增(主要是变量声明)代码:

#include "aita_gd32l233_usart.h"

extern uint8_t rx_buffer[256];
extern uint32_t nbr_data_to_read;
extern volatile uint32_t rx_counter;
//DMA USART1 用到的内存缓存
extern uint8_t u1txbuffer[128];
extern uint8_t u1rxbuffer[128];
extern uint16_t u1rxindex;
extern uint8_t u1txdoing;
extern dma_parameter_struct dma_init_struct;

 

       gd32l23x_it.c中建立的中断函数代码:

void USART1_IRQHandler(void)
{
#if !AITA_DMA_U1Rx_EN
    //未启用U1接收DMA,则采用接收中断
    if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_RBNE)) {
        //如果缓冲区填满,则清空
        if(u1rxindex > USART1_BUF_LENGTH) {
          u1rxindex = 0;
          memset(u1rxbuffer, 0, USART1_BUF_LENGTH);
        }
        /* read one byte from the receive data register */
        u1rxbuffer[u1rxindex++] = (uint8_t)usart_data_receive(USART1);
    }
#else
  if(RESET != usart_interrupt_flag_get(USART1, USART_INT_FLAG_IDLE)) {
    usart_interrupt_flag_clear(USART1, USART_INT_FLAG_IDLE);
    dma_channel_disable(DMA_CH3); //串口空闲后,关闭接收DMA防止干扰
    u1rxindex = USART1_BUF_LENGTH 
          - dma_transfer_number_get(DMA_CH3);//获取接收到的字节数    

    dma_transfer_number_config(DMA_CH3, USART1_BUF_LENGTH);
    dma_channel_enable(DMA_CH3);  //再开启接收DMA
  }
#endif
}

#if AITA_DMA_U1Tx_EN
void DMA_Channel2_IRQHandler(void)
{
    if(RESET != dma_interrupt_flag_get(DMA_CH2, DMA_INT_FLAG_FTF)){
        dma_interrupt_flag_clear(DMA_CH2, DMA_INT_FLAG_G);
        dma_channel_disable(DMA_CH2);
        u1txdoing = 0;
    }
}
#endif

#if AITA_DMA_U1Rx_EN
//Usart1 Rx DMA ISR(应当永不触发)
void DMA_Channel3_IRQHandler(void)
{
    if(RESET != dma_interrupt_flag_get(DMA_CH3, DMA_INT_FLAG_FTF)){
        dma_interrupt_flag_clear(DMA_CH3, DMA_INT_FLAG_G);
        dma_channel_disable(DMA_CH3);
        dma_transfer_number_config(DMA_CH3, USART1_BUF_LENGTH);
        dma_channel_enable(DMA_CH3);
    }
}
#endif

 

       最后是main.c中 编写的测试函数(这个很简单,仅是收发测试):

void aita_TestU1(void) {
  while(1) {
    aita_U1SendStr("hello from usart1 in dma\r\n", sizeof("hello from usart1 in dma\r\n"));
		if(u1rxindex) {
      aita_U1SendStr("Rsv: ", sizeof("Rsv: "));
      aita_U1SendStr(u1rxbuffer, u1rxindex);
      aita_U1SendStr("\r\n", sizeof("\r\n"));
      aita_ClearU1RxBuffer();
    }
    delay_1ms(1000);		
  }
}

 

此帖出自GD32 MCU论坛

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

最新文章 更多>>
    推荐帖子
    Ni-MH电池充电器PCB设计详解

    1 Protel软件简介随着电子信息技术的飞速发展,手工设计电子产品的PCB(印制电路板)已不能适应电子技术发展的需要。我们必须借 ...

    运放电路的散问

    【不懂就问】 图示的运放起到什么作用,或者属于哪一类运放 若去掉电感L,它和个积分放大器电路很像,只是输入端不一样 是不 ...

    stm32同一组io口不同引脚设置不同输入输出模式

    stm32同一组io口不同引脚设置不同输入输出模式,比如PA口的PA1用作输入使用来读取输入值,PA2用作输出使用来输出高低电平。这个 ...

    POE交换机选择和使用时需要注意的事项

    POE交换机选择和使用时需要注意的事项 POE交换机的电源相当于电源线。它通过网线为无线AP网络电话网络摄像机等设备供电,既 ...

    Sitara™开发红宝书

    小编尽可能多的为您罗列了各种可轻松获取的资源。在开发基于Sitara开发的应用程序时,你可以查阅Sitara相关的入门指南、观看实战 ...

    请问一下 低频卡在POR之前需要发送多少个FC的电磁波,怎么查了好多资料都没有明确数据

    本帖最后由 深圳小花 于 2022-4-30 18:00 编辑 请问一下 低频卡T5557卡 在POR之前需要发送多少个FC的电磁波,怎么查了好多资 ...

    关闭
    站长推荐上一条 1/9 下一条

    About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

    站点相关: 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

    北京市海淀区知春路23号集成电路设计园量子银座1305 电话:(010)82350740 邮编:100191

    电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2022 EEWORLD.com.cn, Inc. All rights reserved
    快速回复 返回顶部 返回列表