GD32F103和GD32E230在串口接收模式(dma + idle)的区别

   日期:2021-03-20     浏览:771    评论:0    
核心提示:先上GD32E230的串口DMA代码。static void rgb_com_dma_init(void){ rcu_periph_clock_enable(RCU_DMA); nvic_irq_enable(DMA_Channel1_2_IRQn, 1); dma_deinit(DMA_CH2

先上GD32E230的串口DMA代码。

static void rgb_com_dma_init(void)
{ 
    
    rcu_periph_clock_enable(RCU_DMA);
    
    nvic_irq_enable(DMA_Channel1_2_IRQn, 1);

    
    dma_deinit(DMA_CH2);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)uart0.rx_array;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0x100;
    dma_init_struct.periph_addr = USART0_RDATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;
    dma_init(DMA_CH2, &dma_init_struct);

    
    dma_circulation_disable(DMA_CH2);
    dma_memory_to_memory_disable(DMA_CH2);
    
    
    usart_dma_receive_config(USART0, USART_DENR_ENABLE);
    
    // dma_interrupt_enable(DMA_CH2, DMA_INT_FTF);
    
    dma_channel_enable(DMA_CH2);
}
void USART0_IRQHandler(void)
{ 
    uint16_t count = 0;
    if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)){ 
        dma_channel_disable(DMA_CH2);                               // 先关闭dma通道,不然后面没法复位dma cnt寄存器的值
        count = dma_transfer_number_get(DMA_CH2);                   // count是接收数组的剩余长度
        if (!uart0.is_busy && count != UART_RX_SIZE) { uart0.is_busy = SET;}
        dma_transfer_number_config(DMA_CH2, UART_RX_SIZE);                 // 重置cnt寄存器的值
        dma_channel_enable(DMA_CH2);                                // 再次打开dma通道
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);    // 清中断退出
    }
}

再看GD32F103的DMA部分代码

static void init_uart_dma_receive(void)
{ 
    
    rcu_periph_clock_enable(RCU_DMA0);
    
    // nvic_irq_enable(DMA0_Channel4_IRQn, 0, 1);
    
    dma_deinit(DMA0, DMA_CH4);
    dma_struct_para_init(&dma_init_struct);

    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)uart0.rx_array;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0x100;
    dma_init_struct.periph_addr = USART0_DATA_ADDRESS;
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;
    dma_init_struct.memory_width = DMA_PERIPHERAL_WIDTH_8BIT;
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;

    dma_init(DMA0, DMA_CH4, &dma_init_struct);
    dma_circulation_disable(DMA0, DMA_CH4);
    dma_memory_to_memory_disable(DMA0, DMA_CH4);
    
    usart_dma_receive_config(USART0, USART_DENR_ENABLE);
    
    // dma_interrupt_enable(DMA0, DMA_CH4, DMA_INT_FTF);
    
    dma_channel_enable(DMA0, DMA_CH4);
}
void USART0_IRQHandler(void)
{ 
    if (RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)){ 
        dma_channel_disable(DMA0, DMA_CH4);
        usart_data_receive(USART0);     // 非读不可,不读清不掉IDLE中断
        uart0.rx_cnt = dma_transfer_number_get(DMA0, DMA_CH4);
        if (!uart0.is_busy) { uart0.is_busy = SET;}
        dma_transfer_number_config(DMA0, DMA_CH4, UART_RX_SIZE);
        dma_channel_enable(DMA0, DMA_CH4);
    }
}

第一、可以看到GD32E230的DMA只有一个,所以关于它的函数不需要指定是哪个DMA,制定DMA通道就好了。但是GD32F103有多个DMA,需要制定是哪个DMA的哪个通道。

可以看到F103的IDLEF位需要先读USART_STAT,再读USART_DATA,才能清除IDLE的中断标识。所以在f103的标准库的usart_interrupt_flag_clear函数没有IDLE的选项。

但是GD32E230可以通过写IDLEC清除中断。usart_interrupt_flag_clear有IDLE的选项。
因此在GD32F103的串口中断中,需要usart_data_receive读一下数据寄存器才行。
另外,如果使用MDK V6的编译器,那么在中断中判断的标志位需要声明为volatile的,不然容易出bug。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
更多>相关资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服