打印

GD32F350G DMA连续接收数据出现错误

[复制链接]
1383|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
IFELSERETURN|  楼主 | 2023-8-30 09:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我配置好DMA接收usart0数据后,在收到soc的命令后进行循环接收串口数据,一开始数据都是对的,收了几十帧数据后收到的数据就不对了。。
中断触发时usart0_rx.rx_idle会被置1,接收函数大致如下
        while (1) {
                if(usart0_rx.rx_idle == 1){
                        usart0_rx.rx_idle = 0;
                        memcpy(rev_data, usart0_rx.data, USART_RX_SIZE);//这里先保存一下数据
                               
                        for(i=0;i<usart0_rx.save_index;i++){
//                                printf("0x%x, ",rev_data[i]);
                                recv_char = rev_data[i];
                                switch(test) {
                                      case FRAME_HEAD0: {
                                            if (HEAD0 == recv_char) {
                                                test = FRAME_HEAD1;
                                             } else {
                                                   printf("<%s : %d> ... %d\r\n", __func__, __LINE__, test);
                                             }
                                       } break;
                                       case FRAME_HEAD1: {
                                             if (HEAD1 == recv_char) {
                                                   test = FRAME_DATA_LEN;
                                             } else {
                                                    printf("<%s : %d> ... %d\r\n", __func__, __LINE__, test);
                                                    test = FRAME_HEAD0;
                                             }
                                        } break;
                                ......

使用特权

评论回复
沙发
IFELSERETURN|  楼主 | 2023-8-30 16:26 | 只看该作者
有没有人知道是什么原因造成的

使用特权

评论回复
板凳
qintian0303| | 2023-8-30 17:08 | 只看该作者
DMA配置发出来啊

使用特权

评论回复
地板
qintian0303| | 2023-8-30 17:09 | 只看该作者
在进行串口数据转移时要关闭DMA,转移完成后再打开

使用特权

评论回复
5
IFELSERETURN|  楼主 | 2023-8-30 17:21 | 只看该作者
DMA配置:
void dma_config(void)
{
    dma_parameter_struct dma_init_struct;

        //nvic_irq_enable(USART0_IRQn, 0, 0);
       
    rcu_periph_clock_enable(RCU_DMA);

    /* deinitialize DMA channel2 (USART0 rx) */
    dma_deinit(DMA_CH2);
    dma_struct_para_init(&dma_init_struct);
    dma_init_struct.direction = DMA_PERIPHERAL_TO_MEMORY;
    dma_init_struct.memory_addr = (uint32_t)usart0_rx.data;
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;
    dma_init_struct.memory_width = DMA_MEMORY_WIDTH_8BIT;
    dma_init_struct.number = 256;
    dma_init_struct.periph_addr = (uint32_t)&USART_RDATA(USART0);
    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);
    /* enable DMA channel2 */
    dma_channel_enable(DMA_CH2);
}

void usart0_gpio_config(void)
{
    /* enable COM GPIO clock */
    rcu_periph_clock_enable(RCU_GPIOB);

    /* connect port to USARTx_Tx */
    gpio_af_set(GPIOB, GPIO_AF_0, GPIO_PIN_6);

    /* connect port to USARTx_Rx */
    gpio_af_set(GPIOB, GPIO_AF_0, GPIO_PIN_7);

    /* configure USART Tx as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_6);

    /* configure USART Rx as alternate function push-pull */
    gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
    gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_10MHZ, GPIO_PIN_7);
}

void usart0_config(void)
{
    /* enable USART clock */
    rcu_periph_clock_enable(RCU_USART0);

    /* USART configure */
    usart_deinit(USART0);
    usart_word_length_set(USART0, USART_WL_8BIT);
    usart_stop_bit_set(USART0, USART_STB_1BIT);
    usart_parity_config(USART0, USART_PM_NONE);
    usart_baudrate_set(USART0, 115200U);
    usart_receive_config(USART0, USART_RECEIVE_ENABLE);
    usart_transmit_config(USART0, USART_TRANSMIT_ENABLE);
        usart_dma_receive_config(USART0, USART_DENR_ENABLE);
    usart_dma_transmit_config(USART0, USART_DENT_ENABLE);
    usart_enable(USART0);
}

void uart_init(void)
{
        nvic_irq_enable(USART0_IRQn, 0, 0);
        dma_config();
        usart0_gpio_config();
    usart0_config();

       
        usart1_gpio_config();
    usart1_config();

        while(RESET == usart_flag_get(USART0, USART_FLAG_IDLE));
    usart_flag_clear(USART0, USART_FLAG_IDLE);
    usart_interrupt_enable(USART0, USART_INT_IDLE);
        usart_interrupt_enable(USART0, USART_INT_RBNE);

        printf("version: %s\r\n",VERSION);
        printf("uart_init over\r\n");
       
}

使用特权

评论回复
6
IFELSERETURN|  楼主 | 2023-8-30 17:31 | 只看该作者
本帖最后由 IFELSERETURN 于 2023-8-30 17:34 编辑

中断设置如下:
void USART0_IRQHandler(void)
{      
     if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
        /* clear IDLE flag */
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
               
        /* number of data received */
        usart0_rx.save_index = 256 - (dma_transfer_number_get(DMA_CH2));
        usart0_rx.rx_idle = 1;

        /* disable DMA and reconfigure */
        dma_channel_disable(DMA_CH2);
        dma_transfer_number_config(DMA_CH2, 256);
        dma_channel_enable(DMA_CH2);
    }
}

使用特权

评论回复
7
IFELSERETURN|  楼主 | 2023-8-30 17:35 | 只看该作者
qintian0303 发表于 2023-8-30 17:09
在进行串口数据转移时要关闭DMA,转移完成后再打开

中断来的时候有关闭再打开

使用特权

评论回复
8
qintian0303| | 2023-8-31 08:55 | 只看该作者
你的usart0_rx.data是DMA接收数组,可是你备份是在while进行的,备份应该在中断中关闭情况下进行,如果你在打开后没有备份完,这个时候来新数据了,你的usart0_rx.data就可能被更改了

使用特权

评论回复
评论
戈壁滩中的辉煌 2023-8-31 09:24 回复TA
确实需要注意 
9
zhuww| | 2023-8-31 21:13 | 只看该作者
几十帧后不对的?

使用特权

评论回复
评论
IFELSERETURN 2023-9-1 09:23 回复TA
是呀,有时候程序卡死了,不知道是不是内存泄漏了 
10
IFELSERETURN|  楼主 | 2023-9-1 09:56 | 只看该作者
qintian0303 发表于 2023-8-31 08:55
你的usart0_rx.data是DMA接收数组,可是你备份是在while进行的,备份应该在中断中关闭情况下进行,如果你在 ...

我在中断接收到数据信号的时候关了usart0中断,在while循环处理完数据后在我向主控发送ack信号时再打开,还是出现数据不对的情况
void USART0_IRQHandler(void)
{        
        if(RESET != usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE)) {
        /* clear IDLE flag */
        usart_interrupt_flag_clear(USART0, USART_INT_FLAG_IDLE);
               
        /* number of data received */
        usart0_rx.save_index = 256 - (dma_transfer_number_get(DMA_CH2));
        usart0_rx.rx_idle = 1;
//                printf("USART0_IRQHandler USART_INT_FLAG_RBNE: %d\r\n",usart0_rx.save_index);

        /* disable DMA and reconfigure */
        dma_channel_disable(DMA_CH2);
        dma_transfer_number_config(DMA_CH2, 256);
        dma_channel_enable(DMA_CH2);
               
        usart_interrupt_disable(USART0, USART_INT_IDLE);
    }
}

使用特权

评论回复
11
IFELSERETURN|  楼主 | 2023-9-1 10:53 | 只看该作者
zhuww 发表于 2023-8-31 21:13
几十帧后不对的?

不是卡死,是突然有一帧数据大小变成64的,按道理应该全部都是136的大小,我看了soc发送的数据是136的大小没错,但是mcu却显示为64

使用特权

评论回复
12
IFELSERETURN|  楼主 | 2023-9-1 11:10 | 只看该作者
接收错误应该就是这个SOC给mcu发送136大小的数据,DMA有时候却读到大小为64的数据,这是什么原因引起的呢

使用特权

评论回复
13
IFELSERETURN|  楼主 | 2023-9-1 14:52 | 只看该作者
爸爸们今天都不在线了吗

使用特权

评论回复
14
qintian0303| | 2023-9-2 09:02 | 只看该作者
IFELSERETURN 发表于 2023-9-1 09:56
我在中断接收到数据信号的时候关了usart0中断,在while循环处理完数据后在我向主控发送ack信号时再打开, ...

你不是用的DMA吗,关闭中断不影响DMA传输

使用特权

评论回复
15
IFELSERETURN|  楼主 | 2023-9-4 10:37 | 只看该作者
qintian0303 发表于 2023-9-2 09:02
你不是用的DMA吗,关闭中断不影响DMA传输

主控这边向我发了137字节数据,mcu偶尔出现只收到了64个字节的数据

使用特权

评论回复
16
Undshing| | 2023-9-27 22:40 | 只看该作者
IFELSERETURN 发表于 2023-9-4 10:37
主控这边向我发了137字节数据,mcu偶尔出现只收到了64个字节的数据

是不是缓冲区设置的问题

使用特权

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

本版积分规则

4

主题

22

帖子

1

粉丝