STM32:将 USART 与字符匹配 ISR 和 DMA 缓冲区一起使用

Posted

技术标签:

【中文标题】STM32:将 USART 与字符匹配 ISR 和 DMA 缓冲区一起使用【英文标题】:STM32: Use USART with character match ISR and DMA buffer 【发布时间】:2020-02-26 15:48:41 【问题描述】:

我正在使用带有 FreeRTOS 和 STM32CubeMX 的 STM32L432 设备。

我尝试通过基于 ASCII 协议的 USART 实现 M2M 通信。协议序列的长度可以不同,但​​具有最大长度和定义的结束字符('\r' / 0x0D)。

所以我考虑使用 DMA(如 FIFO)收集所有 RX-USART 数据,并使用基于 USART_ICR_CMCF 标志的地址匹配 isr 来确定结束字符。

初始化 USART1 并启用地址匹配 isr

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle) 
  GPIO_InitTypeDef GPIO_InitStruct = 0;
  if(uartHandle->Instance==USART1) 
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();
    __HAL_RCC_GPIOA_CLK_ENABLE();
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 5, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);

    /* USER CODE BEGIN USART1_MspInit 1 */
    USART1->CR2 |= 0x0D000000; // \r 0x0D
    __HAL_UART_ENABLE_IT(&huart1,UART_IT_CM);
  

USART1 isr 处理程序

void USART1_IRQHandler(void) 
  if (USART1->ISR & USART_ISR_CMF) 
    data = USART1->RDR;  
    SET_BIT(USART1->ICR,USART_ICR_CMCF);
  
  HAL_UART_IRQHandler(&huart1);

现在,地址匹配 isr 工作正常,但我不知道如何实现 DMA / FIFO 支持。

顺便说一句:

我很惊讶,该设备不支持 USART HW FIFO。我的想法是用DMA复现常用的FIFO吗?

【问题讨论】:

【参考方案1】:

DMA 的重点是不让 CPU 参与传输的每个字节。如果每个字节都调用您的 ISR,那么 CPU 就会参与进来,因此同时启用 DMA,如果可能的话,不会产生任何性能优势。摆脱每字节两个中断或 DMA 中的任何一个。如果您绝对想在某个特定字符到达时对其进行检查,那么 DMA 将无济于事。

在使用任意长度输入和 DMA 时检测输入结束的另一种流行方法是使用 USART 空闲中断。当一个字节时间(以当前波特率传输一个字节所需的时间)过去而没有任何传输时,将触发此中断。在此中断中,您可以将 DMA 缓冲区内容传输到另一个内存位置,然后重新初始化 DMA 以供将来输入并离开。或者您可以在现场处理输入。只要 ISR 快速完成执行,您就可以在空闲 ISR 中做任何您想做的事情。

如果您的输入有大量连续运行的数据,那么空闲中断将在很长一段时间后触发,并且您可能已经覆盖了您的缓冲区。您可以使用其他 DMA 中断(例如 Half Complete 和 Full Complete)来处理此问题。所以这也可以照顾。我个人发现这种方法在压力测试期间是有问题的。但是没有理由这样,当我尝试使用它时,我没有足够的时间来调试它,但是您会在网上找到有关此技术的文章。

【讨论】:

你能解释一下——为什么字符匹配不能用于生成中断 IF 并且只有字符与 DMA 匹配?我查看了参考手册,我不清楚为什么空闲检测可以与 DMA 一起使用,但不能与字符匹配一起使用。 DMA 没有任何机制来执行自定义逻辑。它会简单地用接收到的字节填充内存中的缓冲区,并在缓冲区已满(甚至半满)时引发中断。中断可用于触发接收数据的检查,但如果缓冲区未满,则永远不会收到中断,也不会触发检查。 ' 我现在看到很多例子,其中 DMA 设置为使用循环模式,然后使用 UART 的空闲线检测或字符匹配标志来创建中断。中断由 UART 触发,而不是 DMA。 这就是我在回答中所写的 也许我误解了,但我很困惑“如果您绝对想在某个特定字符到达时检查它,那么 DMA 将无济于事。”因为我确实想检查一个特定的字符,而且我想使用 DMA,因为它的 CPU 效率更高。因此,就我而言,DMA 在检查特定字符(使用匹配标志)时确实有帮助,因为它比不使用 DMA 更有效。

以上是关于STM32:将 USART 与字符匹配 ISR 和 DMA 缓冲区一起使用的主要内容,如果未能解决你的问题,请参考以下文章

stm32板的usart2设置与usart1有啥区别啊

STM32 上的 USART 接收器

STM32F0xx_USART收发配置详细过程

STM32之USART1串口:蓝牙接收字符控制LED亮灭

STM32库函数void USART_SendData的缺陷和解决方法

stm32 串口 中断的问题