585|0

104

帖子

0

资源

一粒金砂(中级)

【GD32450I-EVAL】USART与DMA不定长接收 [复制链接]

本帖最后由 tinnu 于 2020-10-25 23:18 编辑

(一)使能DMA

例程中推荐的DMA发送USART的模式:

void USART_DMA_Init(void)
{
    dma_single_data_parameter_struct dma_init_struct;
	rcu_periph_clock_enable(RCU_DMA1);
    dma_deinit(DMA1, DMA_CH2);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;
    dma_init_struct.memory0_addr = (uint32_t)rxbuffer;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = 10;
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART0);
    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(DMA1, DMA_CH2, &dma_init_struct);

    dma_channel_subperipheral_select(DMA1, DMA_CH2, DMA_SUBPERI4);
    /* enable DMA channel2 */
    dma_channel_enable(DMA1, DMA_CH2);
    usart_dma_receive_config(USART0, USART_DENR_ENABLE);
}

 

(二)问题1

但根据实际测试,这个模式在发送完缓冲区10个数据之后,如果不及时重启DMA的话会导致溢出。
针对溢出,在参考手册507页有这样的一段话:


当接收到一帧数据,而RBNE位还没有被清零,随后的数据帧将不会存储在数据接收缓冲区中。
USART_STAT0 寄存器中的溢出错误标志位 ORERR 将置位。如果使能 DMA 并置位 USART_CTL2寄存器中ERRIE位或者置位RBNEIE,将产生中断。


这样还得去处理 ORERR 这个错误标志位,非常繁琐。

 

 

(三)空闲中断
可以考虑用空闲中断来处理,我们默认每次空闲中断触发后都重启DMA :
2.png
使能空闲中断:

	usart_interrupt_enable(USART0, USART_INT_IDLE);
	nvic_irq_enable(USART0_IRQn, 2U, 0U);

处理函数:

void USART0_IRQHandler()
{
    static uint32_t g_counter1 = 0;
    if (RESET != usart_flag_get(USART0, USART_FLAG_IDLE))
    {
        usart_flag_clear(USART0, USART_FLAG_IDLE);
        g_counter2++;
        USART_DMA_Init();
    }
}

 

(四)问题2
上述方法依然存在问题:
1.gif
每次完成空闲中断都会触发好多次,这可能是兆易方面IP核的策略,针对这个问题可以通过查询当前DMA未发送的位还有多少来解决,如果一个位都没有发送,那就认为不需要重启。
因为空闲中断不是每个bit都会中断的,而是一串bit完成之后,多少时间内没有新的bit出现才会置位一段时间的 IDLE 标志位,我猜这也是为什么IDLE标志位会持续触发而无法被软件清除的原因。

void USART0_IRQHandler()
{
    static uint32_t g_counter1 = 0;
    if (RESET != usart_flag_get(USART0, USART_FLAG_IDLE))
    {
        usart_flag_clear(USART0, USART_FLAG_IDLE);
        if (dma_transfer_number_get(DMA1, DMA_CH2) == 10)
            return;
        g_counter2++;
        USART_DMA_Init();
    }
}

这样就解决了。事实上也可以通过查询缓存中的数据量,数据内容,在没有满的条件下重启。

此帖出自GD32 MCU论坛

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

最新文章 更多>>
    关闭
    站长推荐上一条 1/5 下一条

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

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

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

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