如何重置 STM32 HAL UART 驱动程序 (HAL) 状态?

How do I reset the STM32 HAL UART driver (HAL) state?

我知道可以使用

启用 UART 接收中断
HAL_UART_Receive_IT(&huart2, (uint8_t *)rx_buffer, expectedNumberOfBytes)

我们可以使用 HAL_NVIC_DisableIRQ()(例如:HAL_NVIC_DisableIRQ(USART1_IRQn))禁用 UART 中断。这将防止它引发中断,但是函数 HAL_UART_Receive_IT 设置的状态 HAL_UART_STATE_BUSY_RX 需要设置回 HAL_UART_STATE_READY 才能使 uart 句柄返回到状态可以接受新的 HAL_UART_Receive_IT() 呼叫。

问题
如果我想在一段时间后禁用 Rx 中断,如何重置 UART 中断的状态?

Stack Overflow 问题没有解决如何重置状态;我提到了这些问题:

  1. Disabling interrupt in interrupt handler STM32F407
  2. https://electronics.stackexchange.com/questions/100073/stm32-usart-rx-interrupts

我可以使用 USART_ClearITPendingBit()USART_ITConfig() 但这些被 STM 的 HAL 库定义为私有函数。那么我应该使用它们吗?

当程序从保持寄存器中读取时,大多数 UART 会清除任何挂起的接收中断。所以我的答案是:在禁用中断后简单地读取数据寄存器,并忽略结果。

我还没有机会在我的 STM32 上尝试这个,但是...

How [do I] reset the state of the UART interrupt if [I] wish to disable a Rx interrupt after some time[?]

(参见“stm32f4xx_hal_uart.c”中的用法)

uart 句柄结构的 huart->RxState 成员实际上只在 HAL 库内部使用,例如 HAL_UART_Receive()HAL_UART_Receive_IT()HAL_UART_Receive_DMA()、(以及许多其他类似的内部函数)等。但是,如果您手动实现自己的 interrupt-based 和 ring-buffer-based UART Tx 和 Rx 调用,这是首选方法,这个成员完全没有意义,你用它做什么并不重要,因为它只在 HAL 库函数调用和 HAL ISR 处理程序(你都不必使用)中使用,而且实际上什么都没有直接处理 register-level 中断和其他事情。

通过挖掘 stm32f4xx_hal_uart.c 中的源代码(例如),但是,这里有几个您可以使用的有效选项:

1。如何将 huart->RxState 重置为 HAL_UART_STATE_READY:

  1. 呼叫HAL_UART_Init()。通过检查它的源代码,您会看到它在返回之前调用 huart->RxState= HAL_UART_STATE_READY;
  2. 只需手动设置 huart->RxState = HAL_UART_STATE_READY; 只要您知道您已在处理过程中正确停止 interrupt-based 接收,这是完全有效的。

不过,让我们更进一步。

假设您在 STM32F4 上使用 UART7。因此,在您的 stm32f4xx_it.c 中断处理程序文件中,您将看到以下代码 auto-generated by STM32CubeMX:

/**
* @brief This function handles UART7 global interrupt.
*/
void UART7_IRQHandler(void)
{
  /* USER CODE BEGIN UART7_IRQn 0 */

  /* USER CODE END UART7_IRQn 0 */
  HAL_UART_IRQHandler(&huart7);
  /* USER CODE BEGIN UART7_IRQn 1 */

  /* USER CODE END UART7_IRQn 1 */
}

让我们回顾一些 disabling/enabling 中断层。

2。从最广泛到最狭窄的范围,这里有几种 disable/enable USART Rx 中断的方法:

  1. 您可以 disable/enable 所有中断,包括这个 UART7_IRQHandler(),使用这些 ARM-core CMSIS 调用:

    __disable_irq();
    __enable_irq();
    

    来源:https://stm32f4-discovery.net/2015/06/how-to-properly-enabledisable-interrupts-in-arm-cortex-m/

    因此,您可以执行以下操作来禁用中断,重置 RxState,然后在准备就绪时再次启动 interrupt-based 接收:

    __disable_irq();
    huart7->RxState= HAL_UART_STATE_READY;
    
    __enable_irq();
    HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
    
  2. 你只能disable/enable UART7_IRQHandler() 中断(连接到这个中断向量的所有 10 种类型的 uart7 中断,包括 Tx-related、Rx-related ,error-related,等),使用这些 STM32 HAL 调用:

    HAL_NVIC_DisableIRQ(UART7_IRQn);
    HAL_NVIC_EnableIRQ(UART7_IRQn);
    

    然后,除了使用这些对 disable/enable 中断的调用之外,执行与上面相同的操作。

  3. 如果你深入研究 HAL_UART_IRQHandler() 的实现,然而,它被 UART7_IRQHandler() 调用,你会发现它只调用 interrupt-based接收处理程序,UART_Receive_IT(),如果 USART_SR_RXNE 位("Receive Not Empty",在 USART 状态寄存器内)和 USART_CR1_RXNEIE 位("Receive Not Empty Interrupt Enable",在 USART 控制寄存器 1) 是 both 集。 RXNE 位在一个字节进入时设置,并在您读取数据寄存器或向其写入零时清除。 interrupt-enable 位是您可以完全控制以禁用此 UART 接收中断的东西,如果您手动清除此位,您将禁用接收中断而不会禁用与此相关的任何其他类型的中断美国艺术学院。这是最好的方法,因为有 10 个中断源与此 UART 关联。 换句话说,清除此位不仅会导致 HAL_UART_IRQHandler() 内部的检查失败,而且还会阻止接收中断从一开始就发生了!参考参考手册RM0090 Rev 16,例如:

    p969:

    p1009:

    p1011:

    p1015:

    p1013:

    因此,对于disable/enable USART Receive Not Empty interrupt only,请执行以下操作。 参考p1013上的控制寄存器(USART_CR1),如上所示。

    // Disable the USART Receive Not Empty interrupt
    CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    
    // Enable the USART Receive Not Empty interrupt
    SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    

    现在,您可以执行以下操作来禁用 USART 接收中断,重置 HAL RxState,然后在准备就绪时再次启动 interrupt-based 接收:

    CLEAR_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE);
    huart7->RxState= HAL_UART_STATE_READY;
    
    SET_BIT(huart7.Instance.CR1, USART_CR1_RXNEIE); // This call isn't actually necessary, as this bit is set inside `HAL_UART_Receive_IT()` as well
    HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
    

3。如何(笨拙地)使用 HAL_UART_Receive_IT() 连续 interrupt-based 接收。

待办事项

4。为什么 HAL_UART_Receive_IT() 真的不是一个非常有用的函数 after-all.

待办事项

5。如何手动配置您自己的 interrupt-based UART Tx 和 Rx ISR 和函数。

待办事项

您可以使用 HAL_UART_Abort_IT.

有函数static void UART_EndRxTransfer(UART_HandleTypeDef *huart) 在执行以下操作的 HAL 库中:

  • 禁用 RXNE、PE 和 ERR 中断
  • 恢复 huart->RxState 就绪

我在 stm32f7xx_hal_uart.c 文件中找到了那个函数。但是,它被定义为 static,所以我只是将定义复制到我使用它的文件中。这可能有点老套,但对我有用。