串口DMA空闲中断接收,过一段时间后,接收到的数据无法存放到数组首位置。

串口DMA空闲中断接收数据,放在数组uart1_buffer[23]里。
用stlink调试,观测uart1_buffer[],以及串口的SR,CR1寄存器。
PC通过串口助手自动向单片机发送数据,一开始时,接收正常,接收到的数据到会更新到uart1_buffer[]数组里。
然后我不不断的修改串口助手里发送的数据内容,结果过一段时间后,串口接收到的数据,却存放到了uart1_buffer[]数组的后面位置,以此放置。好像没有进入空闲中断了。在空闲中断回调函数里放断点,也没有被触发。
但是SR寄存器的IDLE标志位,确实能看到被置位了,然后又被清空了。
如果不是空闲回调函数里清除IDLE标志位的话,还能有哪些地方能清掉IDLE标志?来了新数据以后自动清掉?

翻手册看到如下介绍,应该只能软件清除IDLE标志位吧?
DLE:监测到总线空闲 (IDLE line detected)
位4
当检测到总线空闲时,该位被硬件置位。如果USART_CR1中的IDLEIE为’1’,则产生中断。由软件序列清除该位(先读USART_SR,然后读USART_DR)。
0:没有检测到空闲总线;
1:检测到空闲总线。
注意:IDLE位不会再次被置高直到RXNE位被置起(即又检测到一次空闲总线)

空闲回调函数如下:

void IdleCallback(UART_HandleTypeDef *huart)
{
    if (huart == &huart1)
    {
        if (RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE))
        {
            recvLen = huart1.RxXferCount - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
            // __HAL_UART_DISABLE_IT(&huart1, UART_IT_IDLE);
            __HAL_UART_CLEAR_IDLEFLAG(&huart1);
            HAL_UART_DMAStop(&huart1);
            HAL_UART_Receive_DMA(&huart1, uart1_buffer, UART1_BUFF_SIZE);
        }
    }
}


奇怪的是,刚开始能正常接收的时候,SR寄存器的ILDE标志位是看不到闪烁的,也许是太快了。这时是可以进到空闲回调函数的断点的。

出现错误后,能看到SR寄存器的IDLE标志位闪烁,进不到回调函数的断点。


在串口初始化时使能了IDLE中断:

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);


主函数里先调用一次DMA接收:

HAL_UART_Receive_DMA(&huart1, uart1_buffer, UART1_BUFF_SIZE);


串口中断部分:

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    IdleCallback(&huart1);
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */
    // IdleCallback(&huart1);
  /* USER CODE END USART1_IRQn 1 */
}


QQ图片20181123092124.png

奇怪的是,刚开始能正常接收的时候,SR寄存器的ILDE标志位是看不到闪烁的,也许是太快了。这时是可以进到空闲回调函数的断点的。

出现错误后,能看到SR寄存器的IDLE标志位闪烁,进不到回调函数的断点。


或者在空闲中断回调函数里加入断点,触发断点后,再点继续运行,如果点的晚一点的话,也会出现这种现象。


----------------------------------------------------------------------------------------------


问题已解决。

空闲回调函数里不要用HAL_DMA_STOP(),而是用HAL_UART_AbortReceive()来代替。

原因是,HAL_DMA_STOP()关闭DMA后,到再次打开DMA接收前,如果有数据过来,会出现ORE错误,引起错误中断,进而无法触发DMA请求。

而HAL_UART_AbortReceve()里,关闭了CR3寄存器的EIE,不会再触发过载中断。

已邀请:

要回复问题请先登录注册