OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 4196|回复: 8

STM32F1 USART2+DMA接收不定长数据丢包

[复制链接]

1

主题

6

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-7-6
在线时间
3 小时
发表于 2019-3-5 16:41:16 | 显示全部楼层 |阅读模式

原子哥,最近遇到了一个BUG,麻烦帮忙看下,这是网上比较流行的UARTRX+DMA接受不定长数据的驱动

平台:stm32f103RET6

OS:裸跑

背景:需要USART2接受蓝牙芯片的音频流数据,蓝牙音乐44.1KHz的1s数据量为:44100*16*2/8= 176400Byte,由于蓝牙音乐是有压缩,所以1s的数据量为40KB左右,115200的波特率最大的传输是1s14KB左右,所以采用921600的波特率,由于蓝牙音乐建立连接,发现一直丢数据,所以弄stm32F103直接通过通过串口助手和PC通讯,来进行压力测试

问题点1:在间隔5ms,一直持续发啊送640byte,发现totalsize会丢数据
1551774878(1).jpg

如图:发送了11584000Byte的数据,只接收到11465496,丢了118504byte的数据

问题点2:
1551774894(1).jpg
每次发送640byte的时候,发现有的时候空闲中断来不及,所以就出现如图所示的size

程序:

[mw_shl_code=c,true]
uint8_t hw_uart2_init(uint32_t baud_rate)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    /* Enable USART2,GPIOA,DMA1 RCC clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    /* Initialize the GPIOA0,GPIOA1,GPIOA2,GPIOA3 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_3;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    /* Data format :1:8:1, no parity check, hardware flow control */
    USART_InitStructure.USART_BaudRate = baud_rate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS_CTS;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

    /* Enable USART interrupts, mainly for idle interrupts */
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    /* Initializes USART2 to enable USART,USART idle interrupts, and USART RX DMA */
    USART_Init(USART2, &USART_InitStructure);
    USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
    USART_DMACmd(USART2,USART_DMAReq_Rx,ENABLE);
    USART_Cmd(USART2, ENABLE);

    /* Initializes DMA and enables it */
    memset(&DMA_UART2,0,sizeof(DMA_InitTypeDef));
    DMA_DeInit(DMA1_Channel6);
    DMA_UART2.DMA_PeripheralBaseAddr = (uint32_t)&USART2->DR;
    DMA_UART2.DMA_MemoryBaseAddr = (uint32_t)bt_dma_rx_buf;
    DMA_UART2.DMA_DIR = DMA_DIR_PeripheralSRC;
    DMA_UART2.DMA_BufferSize = BT_DMA_BUF_SIZE;
    DMA_UART2.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_UART2.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_UART2.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_UART2.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_UART2.DMA_Mode = DMA_Mode_Normal;
    DMA_UART2.DMA_Priority = DMA_Priority_Medium;
    DMA_UART2.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(DMA1_Channel6, &DMA_UART2);

    DMA_Cmd(DMA1_Channel6, ENABLE);

    return 0;

}
[/mw_shl_code]
[mw_shl_code=c,true]void uart2_dma_enable(DMA_Channel_TypeDef*DMA_CHx)
{
    DMA_Cmd(DMA_CHx, DISABLE);
    DMA_UART2.DMA_MemoryBaseAddr = (uint32_t)bt_dma_rx_buf;
    DMA_UART2.DMA_BufferSize = BT_DMA_BUF_SIZE;
    DMA_Init(DMA1_Channel6, &DMA_UART2);
    DMA_Cmd(DMA_CHx, ENABLE);
}[/mw_shl_code]
[mw_shl_code=c,true]uint32_t total_len = 0;
/******************************************************************************
* func name   : USART2_IRQHandler
* para        : NULL
* return      : NULL
* description : Interrupt handler for usart2
******************************************************************************/
void USART2_IRQHandler(void)
{
    uint32_t recv_len;
    if(USART_GetITStatus(USART2, USART_IT_IDLE) != RESET)
    {
        /* Without this, the interrupt cannot be cleared and continues into the interrupt */
        USART_ReceiveData(USART2);

        /* Clear the interrupt and reset DMA */
        USART_ClearITPendingBit(USART2,USART_IT_IDLE);
        recv_len = BT_DMA_BUF_SIZE - DMA_GetCurrDataCounter(DMA1_Channel6);
        total_len += recv_len;
        printf("len %d total len %d\n",recv_len,total_len);
        uart2_dma_enable(DMA1_Channel6);
    }
}[/mw_shl_code]

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-7-6
在线时间
3 小时
 楼主| 发表于 2019-3-5 16:43:26 | 显示全部楼层
这个问题困扰我2个周了,开始没有怀疑到驱动,只是以为蓝牙协议栈处理有问题,后来经过一层层的做实验,验证,定位到时驱动这边有问题

有没有大神遇到过,帮忙作答下
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-7-6
在线时间
3 小时
 楼主| 发表于 2019-3-5 16:45:14 | 显示全部楼层
或者有没有大神写过一个接受不定长数据的uart驱动,也可以贴上来参考下
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-7-6
在线时间
3 小时
 楼主| 发表于 2019-3-5 16:45:39 | 显示全部楼层
自己顶,不要沉
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2017-7-6
在线时间
3 小时
 楼主| 发表于 2019-3-6 14:15:57 | 显示全部楼层
竟然没人,失望~
回复 支持 反对

使用道具 举报

35

主题

560

帖子

2

精华

资深版主

Rank: 8Rank: 8

积分
17786
金钱
17786
注册时间
2018-3-3
在线时间
523 小时
发表于 2019-3-6 16:01:33 | 显示全部楼层
帮顶~~~up  建议不要在中断函数里面写printf
/*
*
*
*
*
*
*/
回复 支持 反对

使用道具 举报

0

主题

7

帖子

0

精华

新手上路

积分
49
金钱
49
注册时间
2019-3-6
在线时间
13 小时
发表于 2019-3-6 16:06:17 | 显示全部楼层
有个问题想问下:在间隔5ms,一直持续发啊送640byte,那不是每秒128KB,这用921600能够接收完吗?
回复 支持 反对

使用道具 举报

5

主题

20

帖子

0

精华

初级会员

Rank: 2

积分
130
金钱
130
注册时间
2018-11-15
在线时间
49 小时
发表于 2019-11-27 10:16:34 | 显示全部楼层
楼主解决了吗,我现在也遇到了串口丢包问题
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
3
金钱
3
注册时间
2020-2-9
在线时间
1 小时
发表于 2020-11-14 15:09:47 | 显示全部楼层
我也遇到过接收丢包的问题,原因是进接受完成中断时先关了DMA,如果先调用USART_ReceiveData(USART2);然后在读取数据长度和数据,最后再关DMA,设置DMA接收长度,再开DMA,就这样就不丢数据了。我的理解是进接收完成中断时DMA还没准备就绪,需要等待一下子,否则可能会丢数据;
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-22 06:27

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表