STM32: 使用具有字符匹配ISR和DMA缓冲区的USART

5

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

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

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

初始化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中断服务程序

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 硬件 FIFO。我的想法是使用 DMA 来模拟通常使用的 FIFO?

1个回答

5
DMA 的目的是为了不让 CPU 在每个字节传输中都参与其中。如果 ISR 每次调用时都涉及到一个字节,那么开启 DMA 就不会有任何性能提升,即使可能存在这种情况也是如此。摆脱两者之一——每字节中断或 DMA。如果您确实想要检查某个特定字符何时到达,则DMA将不能发挥作用。
使用任意长度输入和 DMA 时检测输入结束的另一种流行方法是使用 USART 空闲中断。当经过一个字节时间(当前波特率下传输一个字节所需的时间)而没有任何传输时,该中断被触发。在此中断中,您可以将 DMA 缓冲区内容传输到另一个内存位置,然后重新初始化 DMA 以进行未来的输入并离开。或者您可以立即处理输入。只要 ISR 快速完成执行,您可以在空闲 ISR 中做任何想要做的事情。
如果您的输入具有大量连续的数据运行,则空闲中断将在很长时间后触发,而此时您可能已经覆盖了缓冲区。您可以使用其他 DMA 中断(如 Half Complete 和 Full Complete)来处理此问题。因此,这也可以得到解决。个人在压力测试期间发现此方法存在错误。但是,没有理由它存在错误,当我尝试使用它时,我没有足够的时间进行调试,但您会在网上找到有关此技术的文章。

你能解释一下吗 -- 为什么字符匹配不能用于生成中断,只有当字符与DMA匹配时才能使用?我查看了参考手册,但我不清楚为什么空闲检测可以与DMA一起使用,但字符匹配却不行。 - Dan Sandberg
DMA没有任何机制来执行自定义逻辑。它只会将内存缓冲区填充接收到的字节,并在缓冲区满(甚至半满)时引发中断。中断可用于触发接收数据的检查,但如果缓冲区未满,则永远不会收到中断,也不会触发检查。 - Dojo
我现在已经看到很多例子,其中DMA被设置为使用循环模式,然后UART的空闲线检测或字符匹配标志被用来创建中断。中断是由UART触发的,而不是由DMA触发的。 - Dan Sandberg
那就是我在答案中所写的。 - Dojo
也许我误解了,“如果你一定要检查特定字符是否到达,DMA将无法帮忙。” 这句话让我感到困惑。 因为我确实想要检查特定字符,并且我想使用DMA,因为它更节省CPU资源。 所以在我的情况下,使用DMA可以帮助检查特定字符(使用匹配标志),因为比不使用DMA更高效。 - Dan Sandberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接