C语言 STM32:UART DMA未正确启动

qkf9rpyu  于 2023-04-29  发布在  其他
关注(0)|答案(3)|浏览(217)

我使用两个通过RS232连接的STM32H743。这两个模块连接到相同的电源。它们使用UART和DMA。当我同时打开模块时,UART和DMA正确启动。但是,当我重新启动其中一个模块而另一个模块处于唤醒状态时,重置模块的UART和DMA不会启动,因此它们无法相互通信。
STM32F4系列以前也出现过这个问题。MCU与FPGA通过UART进行通信。当FPGA先于MCU启动时,DMA和UART无法正常启动。是什么导致了这个问题?在启动UART之前,我需要有一个高z或浮动引脚状态吗?

bogh5gae

bogh5gae1#

经过长时间的调试,我终于找到了原因和解决方案。当第一个字节到达UART外设时,由于时钟不匹配,它触发帧错误,然后停止DMA。当UART数据速率非常高时,这种情况会发生得更频繁。但是我添加了ErrorCallback函数来处理中断。不幸的是,我误用了这个功能。
我的用途:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_MspDeInit();   
    HAL_UART_Receive_DMA(...);
}

HAL_UART_MspDeInit未清除结构和初始化,因此Receive_DMA函数无法再次启动。我的沟通停止了。
正确用途:

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
    HAL_UART_DeInit();  
    HAL_UART_Receive_DMA(...);
}

由于我的代码中的三个错别字,它给我带来了很多时间。但最后,它解决了。

cu6pst1q

cu6pst1q2#

UART和DMA外设通常有一个错误检测器,因此将其标志写入状态寄存器。当发生错误时,STM32 HAL将停止任何正在进行的传输,并等待您处理此故障。您可以使用调试模块检查HAL状态寄存器以解决问题,并在代码中添加处理方法。首先,您可以通过运行DeInit()来重置外围设备,并在运行外围设备的Init()例程错误后立即重置任何其他代码e。例如,状态机和使用来自该外围设备的数据的东西。

tjrkku2a

tjrkku2a3#

根据我的经验,问题的根源是HAL,它通过禁用DMA来对任何错误做出React。由于我使用循环DMA,这不是处理错误的可行方法。正如您所发现的,在初始化时,数据流(以速度)也肯定会发生错误。以下是我的解决方案,增加了通常的UART_Start_Receive_DMA() init代码:

// flush the UART, otherwise the DMA won't start with data coming in
RMA_USART->CR1 &= ~USART_CR1_RE;        // disable UART rx
while (USART1->ISR & USART_ISR_RXNE_RXFNE) {
    u8 h = USART1->RDR;                 // flush the FIFO
    UNUSED(h);
}
USART1->CR1 |= USART_CR1_RE;            // reenable UART rx
// now race to setup the UART with DMA (as usual)
UART_Start_Receive_DMA(&huart1, (u8 *)my_rx.buf, sizeof(my_rx.buf));
// stop errors from aborting the DMA (can't do this in Cube)
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_TC);

运行此代码时请禁用中断。
一个更好的解决方案是用更接近金属的东西代替HAL代码。我没有尝试过这个,但libopencm3似乎是值得的。
还要注意,DMA通道3不能用于至少某些STM32上的UART RX。

相关问题