问答

汇集网友智慧,解决技术难题

21ic问答首页 - GD32F303 串口DMA发送问题

串口DMA GD32F303 UART se ip

GD32F303 串口DMA发送问题

jsrdczy2021-11-22
本帖最后由 jsrdczy 于 2021-11-22 15:55 编辑

兄弟萌,有一个关于gd32的串口dma发送问题:场景描述:串口DMA发送数据,一般的做法是开DMA发送完成中断,然后在中断里切换发送状态或者进行下一次传输。
思路描述:如果是485传输,如果用DMA发送完成中断的话,在中断里发送改为接收状态时,可能会丢1个字节。所以沿用之前stm32的做法,打开串口的发送完成中断,利用tc中断在串口中断服务程序中切换状态或者进行下一帧发送。
问题:之前stm32的工程就是用串口tc发送完成中断来标识发送完成的,但是同样的做法在gd32上,虽然能够进行入tc中断,但是发送出来的数据完全不对。解决办法:dma通道使能后delay 3个ms 就可以发送正确发送了,和开dma或者串口tc中断没有关系。

贴一部分代码:
DMA配置:
static void gd32_dma_config(struct rt_serial_device *serial, rt_ubase_t flag)
{
   struct dma_config *dma_config;
    struct gd32_uart *uart;
    dma_parameter_struct dma_init_struct;
        
    RT_ASSERT(serial != RT_NULL);
    uart = (struct gd32_uart *)serial->parent.user_data;
        
    if (RT_DEVICE_FLAG_DMA_TX == flag)
   {
         dma_config = uart->dma_tx;
   }
   else if(RT_DEVICE_FLAG_DMA_RX == flag)
   {
         return ; // no support temporarily
   }
                //enable dma clock
    rcu_periph_clock_enable(dma_config->dma_rcu);
                //initillize DMA channel
    dma_deinit(dma_config->dma_periph, dma_config->channel);
    dma_struct_para_init(&dma_init_struct);
    dma_channel_disable(uart->dma_tx->dma_periph,uart->dma_tx->channel);
    dma_init_struct.direction = DMA_MEMORY_TO_PERIPHERAL;
    dma_init_struct.memory_addr = RT_NULL;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 0;
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(uart->uart_periph);
    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_config->dma_periph, dma_config->channel, &dma_init_struct);
               
    dma_circulation_disable(dma_config->dma_periph, dma_config->channel);
    dma_memory_to_memory_disable(dma_config->dma_periph, dma_config->channel);

    if (RT_DEVICE_FLAG_DMA_TX == flag)
                {
                        usart_flag_clear(uart->uart_periph, USART_FLAG_TC); //clear flag
                        dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G);
                                /* enable rx irq */
                        NVIC_EnableIRQ(uart->irqn);
                                /* enable interrupt */
                        usart_interrupt_enable(uart->uart_periph, USART_INT_TC); //uart tc send complete interrupt
                        usart_dma_transmit_config(uart->uart_periph, USART_DENT_ENABLE);
                }
                #endif
}

DMA发送
static rt_size_t gd32_dma_transmit(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, int direction)
{
    struct gd32_uart *uart;
    RT_ASSERT(serial != RT_NULL);
    RT_ASSERT(buf != RT_NULL);
    uart = (struct gd32_uart *)serial->parent.user_data;
    struct rt_serial_tx_dma *tx_dma;

    tx_dma = (struct rt_serial_tx_dma*)(serial->serial_tx);
    if (size == 0)
    {
        return 0;
    }

    if (RT_SERIAL_DMA_TX == direction)
    {
                dma_channel_disable(uart->dma_tx->dma_periph,uart->dma_tx->channel);
                dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G);
                usart_flag_clear(uart->uart_periph, USART_FLAG_TC); //clear flag
                dma_memory_address_config(uart->dma_tx->dma_periph,uart->dma_tx->channel,(uint32_t)buf);
                dma_transfer_number_config(uart->dma_tx->dma_periph,uart->dma_tx->channel,size);
                dma_channel_enable(uart->dma_tx->dma_periph,uart->dma_tx->channel);
                 //rt_thread_mdelay(3); 这里delay就能发送
                return size;
    }               
    return 0;
}

串口发送完成中断(tc)处理:
static void uart_isr(struct rt_serial_device *serial)
{
    struct gd32_uart *uart = (struct gd32_uart *) serial->parent.user_data;
    rt_base_t level;
    rt_size_t trans_total_index;
        
    RT_ASSERT(uart != RT_NULL);

    /* UART in mode Receiver -------------------------------------------------*/
    if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_RBNE) != RESET) &&
            (usart_flag_get(uart->uart_periph, USART_FLAG_RBNE) != RESET))
    {
        rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_IND);
        /* Clear RXNE interrupt flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_RBNE);
    }
               
    /* UART in mode Transmiter -------------------------------------------------*/
    if ((usart_interrupt_flag_get(uart->uart_periph, USART_INT_FLAG_TC) != RESET) &&
            (usart_flag_get(uart->uart_periph, USART_FLAG_TC) != RESET))
   {
        if(dma_flag_get(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_FTF) == SET)
        {
                rt_hw_serial_isr(serial, RT_SERIAL_EVENT_TX_DMADONE);
                dma_interrupt_flag_clear(uart->dma_tx->dma_periph, uart->dma_tx->channel,DMA_FLAG_G);
        }
        /* Clear TC interrupt flag */
        usart_flag_clear(uart->uart_periph, USART_FLAG_TC);
        }
}


目前的现象就是tc中断可以进,发出来的字节数也对,但是内容除了头2个字节,其余的字节全都不对。换成DMA发送完成中断也是杨的现象
那位用gd32的大佬使用过,一起探讨下,看是否是我哪里配置有啥问题



回答 +关注 6
1912人浏览 1人回答问题 分享 举报
1 个回答

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