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

时间:2019-03-28 09:55:17

标签: hardware interrupt stm32

我知道可以使用以下命令启用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中断的状态?

堆栈溢出问题不解决如何重置状态;我已经提到了以下问题:

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

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

4 个答案:

答案 0 :(得分:3)

  

如果[I]希望在一段时间后禁用Rx中断,该如何[重置] UART中断的状态[?]

(例如,请参见“ stm32f4xx_hal_uart.c ”中的用法。)

在执行huart->RxStateHAL_UART_Receive()HAL_UART_Receive_IT()等(以及许多其他操作)时,uart句柄结构的HAL_UART_Receive_DMA()成员实际上仅由HAL库在内部使用其他内部功能,如此类)。如果您手动实现自己的基于中断和基于环形缓冲区的UART Tx和Rx调用,但是这是首选的实现方式,该成员是完全没有意义的,使用它无关紧要,因为它仅在HAL库函数调用和HAL ISR处理程序(无需使用它们)中使用,并且实际上与寄存器级无关直接打断事物。

例如,通过挖掘 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;,只要您知道在处理过程中已正确停止了基于中断的接收,就可以了。

但是,让我们更进一步。

假设您正在STM32F4上使用UART7。因此,在您的 stm32f4xx_it.c 中断处理程序文件中,您将看到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 */
}

让我们讨论一下禁用/启用中断的一些层次。

2。从最广泛的范围到最窄的范围,以下是几种禁用/启用USART Rx中断的方法:

  1. 您可以使用以下ARM核心CMSIS调用来禁用/启用所有中断,包括此UART7_IRQHandler()

    __disable_irq();
    __enable_irq();
    

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

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

    __disable_irq();
    huart7->RxState= HAL_UART_STATE_READY;
    
    __enable_irq();
    HAL_UART_Receive_IT(&huart7, (uint8_t *)rx_buffer, expectedNumberOfBytes);
    
  2. 您只能使用以下命令禁用/启用UART7_IRQHandler()中断(连接到此中断向量的所有10种uart7中断,包括与Tx有关,与Rx有关,与错误有关等) STM32 HAL调用:

    HAL_NVIC_DisableIRQ(UART7_IRQn);
    HAL_NVIC_EnableIRQ(UART7_IRQn);
    

    然后,执行与上述相同的操作,只是使用这些调用来禁用/启用中断。

  3. 但是,如果深入研究HAL_UART_IRQHandler()调用的UART7_IRQHandler()的实现,您会发现它仅调用基于中断的接收处理程序{{1 }},如果同时使用UART_Receive_IT()位(USART状态寄存器中的“接收不为空”)和USART_SR_RXNE位(USART控制寄存器1中的“接收不为空中断使能”),都设置了。 USART_CR1_RXNEIE位在字节进入时置位,并在读取数据寄存器或向其写入零时清除。 您可以完全控制中断使能位来禁用此UART接收中断,如果您手动清除此位,则将禁用接收中断,而不会禁用与该USART相关的任何其他类型的中断。这是最好的方法,因为与此UART相关联的中断源有10个。换句话说,清除该位不仅会导致RXNE内部的检查失败,而且还会阻止首先收到发生的中断!例如,请参见参考手册RM0090修订版16

    p969:enter image description here

    p1009:enter image description here

    p1011:enter image description here

    p1015:enter image description here

    p1013:enter image description here

    因此,要仅禁用/启用“ USART接收非空”中断,请执行以下操作。请参阅上面显示的p1013上的控制寄存器(USART_CR1)。

    HAL_UART_IRQHandler()

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

    // 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);
    

3。如何(笨拙)使用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); 进行连续的基于中断的接收。

待办事项

4。为什么HAL_UART_Receive_IT()毕竟不是真正有用的功能。

待办事项

5。如何手动配置自己的基于中断的UART Tx和Rx ISR和功能。

待办事项

答案 1 :(得分:0)

当程序从保持寄存器中读取时,大多数UART清除所有未决的接收中断。所以我的答案是:禁用中断后只需读取数据寄存器,而忽略结果。

我还没有机会在STM32上尝试此操作,但是...

答案 2 :(得分:0)

您可以使用HAL_UART_Abort_IT

答案 3 :(得分:0)

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

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

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