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

2019-07-21 04:41发布


原子哥,最近遇到了一个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 ",recv_len,total_len);
        uart2_dma_enable(DMA1_Channel6);
    }
}[/mw_shl_code]
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。