打印

GD32F4xx关于DMA串口收发

[复制链接]
2485|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
F4xx手册描述8个串口都支持DMA传输,但是实际使用过程中,当1和7都用的话,始终有一个有异常。无法发送,接收正常。不知道大家有遇到过没。

使用特权

评论回复
沙发
suifengkm|  楼主 | 2024-4-2 15:09 | 只看该作者
本帖最后由 suifengkm 于 2024-4-2 15:15 编辑

这是初始化代码


//串口1初始化
void usart1_init(u32 bound)
{
        dma_single_data_parameter_struct dma_init_struct;

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART1);

    /* configure the USART1Tx pin and USART1 Rx pin */
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_2);
    gpio_af_set(GPIOA, GPIO_AF_7, GPIO_PIN_3);

    /* configure USART1 Tx as alternate function push-pull */
    gpio_mode_set(GPIOA, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_2|GPIO_PIN_3);
    gpio_output_options_set(GPIOA, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_2|GPIO_PIN_3);

    /* USART configure */
    usart_deinit(USART1);
    usart_baudrate_set(USART1, bound);
    usart_receive_config(USART1, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART1, USART_TRANSMIT_ENABLE);
    usart_enable(USART1);

    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);

    /* deinitialize DMA channel6(USART1 tx) */
    dma_deinit(DMA0, DMA_CH6);                                                           //dma寄存器初始化

    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;                       //传输模式,存储到外设(发送)
    dma_init_struct.memory0_addr = (uint32_t)gUsart1.txBuff1;                //dma内存地址
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;        //内存地址增量模式
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;     //dma外设宽度8位
    dma_init_struct.number = USART_LEN_TX_1;                                      //长度
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART1);        //外设基地址
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;                //外设地址增量禁用
    dma_init_struct.priority = DMA_PRIORITY_HIGH;                                        //优先级高
    dma_single_data_mode_init(DMA0, DMA_CH6, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH6);                                                 //循环模式禁用
    dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI4);        //通道6  外设4  USART1_TX
        
        dma_interrupt_enable(DMA0, DMA_CH6, DMA_CHXCTL_FTFIE);                        //传输完成中断
        nvic_irq_enable(DMA0_Channel6_IRQn, 5, 0);                                                //5 抢占优先级,(组4只有抢占优先级)

        usart_dma_transmit_config(USART1, USART_TRANSMIT_DMA_ENABLE);
        
         /* deinitialize DMA0 channel5 (USART1 rx) */
    dma_deinit(DMA0, DMA_CH5);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;                        //传输模式,外设到存储(接收)
    dma_init_struct.memory0_addr = (uint32_t)gUsart1.rxBuff1;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = USART_LEN_RX_1;
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART1);
    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_CH5, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH5);
    dma_channel_subperipheral_select(DMA0, DMA_CH5, DMA_SUBPERI4);

        usart_interrupt_enable(USART1, USART_INT_IDLE);
        /* USART interrupt configuration */
        nvic_irq_enable(USART1_IRQn, 4, 0);

    /* enable DMA1 channel5 */
    dma_channel_enable(DMA0, DMA_CH5);
        usart_dma_receive_config(USART1, USART_RECEIVE_DMA_ENABLE);
}

//串口1 DMA接收,只触发空闲中断
void USART1_IRQHandler(void){

    if(RESET != usart_flag_get(USART1, USART_FLAG_IDLE))
    {
                USART_STAT0(USART1);
                usart_data_receive(USART1);                                //清除串口中断

               gUsart1.RevLen1 = USART_LEN_RX_1 - dma_transfer_number_get(DMA0, DMA_CH5);        

                dma_channel_disable(DMA0, DMA_CH5);
                dma_transfer_number_config(DMA0, DMA_CH5, USART_LEN_RX_1);
                dma_flag_clear(DMA0,DMA_CH5,DMA_INTF_FTFIF);                                //清除dma中断
                dma_channel_enable(DMA0, DMA_CH5);
               
                //测试代码
//                printf("Usart1:%d %s\r\n",gUsart1.RevLen1,gUsart1.rxBuff1);
//                memcpy((u8 *)gUsart1.txBuff1,(u8 *)gUsart1.rxBuff1,gUsart1.RevLen1);
//                usartSend(1,gUsart1.RevLen1);

                if(!gEppFlag.isUsart1)
                {
                        gEppFlag.isUsart1 = TRUE;
                        gRevLen1 = gUsart1.RevLen1;
                        
                        memset((u8 *)gRevBuf1,0, USART_LEN_RX_1);
                        memcpy((u8 *)gRevBuf1,(u8 *)gUsart1.rxBuff1,gRevLen1);
                        
                        memset((u8 *)gUsart1.rxBuff1,0, USART_LEN_RX_1);
                }
    }
}

//dma中断 串口1 发送完成
void DMA0_Channel6_IRQHandler(void)
{
    if(dma_interrupt_flag_get(DMA0, DMA_CH6, DMA_INT_FLAG_FTF))
        {
        dma_interrupt_flag_clear(DMA0, DMA_CH6, DMA_INT_FLAG_FTF);
                dma_flag_clear(DMA0,DMA_CH6,DMA_INTF_FTFIF);
    }
        gEppFlag.isTxUsart1 = FALSE;
}


//串口7初始化
void usart7_init(u32 bound)
{
        dma_single_data_parameter_struct dma_init_struct;

    /* enable USART clock */
    rcu_periph_clock_enable(RCU_UART7);

    /* configure the UART7 Tx pin and USART7 Rx pin */
        gpio_af_set(GPIOE, GPIO_AF_8, GPIO_PIN_1);
    gpio_af_set(GPIOE, GPIO_AF_8, GPIO_PIN_0);

    /* configure USART5 Tx as alternate function push-pull */
    gpio_mode_set(GPIOE, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_0|GPIO_PIN_1);
    gpio_output_options_set(GPIOE, GPIO_OTYPE_PP, GPIO_OSPEED_MAX, GPIO_PIN_0|GPIO_PIN_1);

    /* USART configure */
    usart_deinit(UART7);
    usart_baudrate_set(UART7, bound);
    usart_receive_config(UART7, USART_RECEIVE_ENABLE);
    usart_transmit_config(UART7, USART_TRANSMIT_ENABLE);
    usart_enable(UART7);

    /* enable DMA0 */
    rcu_periph_clock_enable(RCU_DMA0);

    /* deinitialize DMA channel0(UART7 tx) */
    dma_deinit(DMA0, DMA_CH0);                                                             //dma寄存器初始化

    dma_init_struct.direction = DMA_MEMORY_TO_PERIPH;                          //传输模式,存储到外设(发送)
    dma_init_struct.memory0_addr = (uint32_t)gUsart7.txBuff7;                //dma内存地址
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;                //内存地址增量模式
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;        //dma外设宽度8位
    dma_init_struct.number = USART_LEN_TX_7;                                                //长度
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(UART7);                //外设基地址
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;                //外设地址增量禁用
    dma_init_struct.priority = DMA_PRIORITY_HIGH;                                        //优先级高
    dma_single_data_mode_init(DMA0, DMA_CH0, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH0);                                                        //循环模式禁用
    dma_channel_subperipheral_select(DMA0, DMA_CH0, DMA_SUBPERI5);        //通道0  外设5  UART7_TX
        
        dma_interrupt_enable(DMA0, DMA_CH0, DMA_CHXCTL_FTFIE);                        //传输完成中断
        nvic_irq_enable(DMA0_Channel0_IRQn, 11, 0);                                                //5 抢占优先级,(组4只有抢占优先级)

        usart_dma_transmit_config(UART7, USART_TRANSMIT_DMA_ENABLE);
        
         /* deinitialize DMA0 channel6 (UART7 rx) */
    dma_deinit(DMA0, DMA_CH6);
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;                        //传输模式,外设到存储(接收)
    dma_init_struct.memory0_addr = (uint32_t)gUsart7.rxBuff7;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.number = USART_LEN_RX_7;
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(UART7);
    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_CH6, &dma_init_struct);

    /* configure DMA mode */
    dma_circulation_disable(DMA0, DMA_CH6);
    dma_channel_subperipheral_select(DMA0, DMA_CH6, DMA_SUBPERI5);

        usart_interrupt_enable(UART7, USART_INT_IDLE);
        /* USART interrupt configuration */
        nvic_irq_enable(UART7_IRQn, 10, 0);

    /* enable DMA0 channel1 */
    dma_channel_enable(DMA0, DMA_CH6);
        usart_dma_receive_config(UART7, USART_RECEIVE_DMA_ENABLE);
}

//串口7 DMA接收,只触发空闲中断
void UART7_IRQHandler(void){
        
    if(RESET != usart_flag_get(UART7, USART_FLAG_IDLE))
    {
                USART_STAT0(UART7);
                usart_data_receive(UART7);                                //清除串口中断

               gUsart7.RevLen7 = USART_LEN_RX_7 - dma_transfer_number_get(DMA0, DMA_CH6);        

                dma_channel_disable(DMA0, DMA_CH6);
                dma_transfer_number_config(DMA0, DMA_CH6, USART_LEN_RX_7);
                dma_flag_clear(DMA0,DMA_CH6,DMA_INTF_FTFIF);                                //清除dma中断
                dma_channel_enable(DMA0, DMA_CH6);
               
                printf("Usart7:%d %s\r\n",gUsart7.RevLen7,gUsart7.rxBuff7);
                memcpy((u8 *)gUsart7.txBuff7,(u8 *)gUsart7.rxBuff7,gUsart7.RevLen7);
                usartSend(7,gUsart7.RevLen7);
               
                if(!gEppFlag.isUsart7)
                {
                        gEppFlag.isUsart7 = TRUE;
                        gRevLen7 = gUsart7.RevLen7;
                        
                        memset((u8 *)gRevBuf7,0, USART_LEN_RX_7);
                        memcpy((u8 *)gRevBuf7,(u8 *)gUsart7.rxBuff7,gRevLen7);
                        
                        memset((u8 *)gUsart7.rxBuff7,0, USART_LEN_RX_7);
                }
    }
}

//dma中断 串口7 发送完成
void DMA0_Channel0_IRQHandler(void)
{
    if(dma_interrupt_flag_get(DMA0, DMA_CH0, DMA_INT_FLAG_FTF))
        {
        dma_interrupt_flag_clear(DMA0, DMA_CH0, DMA_INT_FLAG_FTF);
                dma_flag_clear(DMA0,DMA_CH0,DMA_INTF_FTFIF);
    }
        gEppFlag.isTxUsart7 = FALSE;
}


//串口发送数据
void usartSend(u8 usaetId, u16 sendLen)
{
        if(sendLen != 0)                        //不管哪个串口,不能发送空操作。
        {
                switch(usaetId)
                {
                        case 1:
                        {
                                gEppFlag.isTxUsart1 = TRUE;                //置端口使用状态,在发送完成中断清零                PC
                                dma_transfer_number_config(DMA0, DMA_CH6,sendLen);                                //设置发送长度
                                dma_channel_enable(DMA0, DMA_CH6);                                                                //开启发送        
                                break;
                        }
                     
                        case 7:
                        {
                                gEppFlag.isTxUsart7 = TRUE;                //置端口使用状态,在发送完成中断清零         高压板
                                dma_transfer_number_config(DMA0, DMA_CH0,sendLen);                                //设置发送长度
                                dma_channel_enable(DMA0, DMA_CH0);                                                                //开启发送        
                                break;
                        }
                        default:
                                break;
                }
        }
}




使用特权

评论回复
板凳
suifengkm|  楼主 | 2024-4-3 14:19 | 只看该作者
结贴:左边的列是用于区分哪个外设的,同个通道同时只有一个外设有效。即右边画圈的串口。不能同时使用。需要分时。

使用特权

评论回复
地板
wangtaohui| | 2024-7-31 22:25 | 只看该作者
在 STM32F4 系列中,不同的 USART 通道使用不同的 DMA 流。检查是否正确配置了每个 USART 的 DMA 流和通道。

使用特权

评论回复
5
wangtaohui| | 2024-7-31 22:25 | 只看该作者
如果某个 DMA 通道被禁用或没有正确配置,可能会导致数据传输失败。

使用特权

评论回复
6
林白给| | 2024-8-2 11:26 | 只看该作者
suifengkm 发表于 2024-4-3 14:19
结贴:左边的列是用于区分哪个外设的,同个通道同时只有一个外设有效。即右边画圈的串口。不能同时使用。需 ...

你好我想问一下,这个分时该如何分时使用?

使用特权

评论回复
7
林白给| | 2024-8-2 11:30 | 只看该作者
林白给 发表于 2024-8-2 11:26
你好我想问一下,这个分时该如何分时使用?

我现在GDF470的八个串口都使用了,然后有些串口的dma接收和发送通道是共用一个通道,导致通道中断也是共用的,我想问一下如何分时使用

使用特权

评论回复
8
林白给| | 2024-8-2 11:31 | 只看该作者
本帖最后由 林白给 于 2024-8-2 11:33 编辑

C:\Users\linhy\Desktop

微信图片_20240802113057.png (14.93 KB )

微信图片_20240802113057.png

使用特权

评论回复
9
suifengkm|  楼主 | 2024-8-5 16:23 | 只看该作者
林白给 发表于 2024-8-2 11:30
我现在GDF470的八个串口都使用了,然后有些串口的dma接收和发送通道是共用一个通道,导致通道中断也是共 ...

分时只是厂商忽悠人的。最终应用的时候基本上无法使用。比如你A口再用的时候。B口接收数据是无效的。最终还是只能用一个。目前我们使用的方法是六个串口dma。2个数据量小的。使用中断收发。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

24

帖子

0

粉丝