HAL库踩坑记录

HAL库踩坑记录

一、stm32F405 usart idle只能进入一次

问题简述:

  1. 判断中断内部自动将huart->ReceptionType状态IDLE模式更改为HAL_UART_RECEPTION_STANDARD,并关闭空闲中断,若下次重新HAL_UARTEx_ReceiveToIdle_DMA失败,则永远不能进入空闲中断
    huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

  2. HAL_UARTEx_ReceiveToIdle_DMA定义失败,huart2.RxState多为busy,原因未知

  3. 获取标志位异常,无法完成HAL_UARTEx_RxEventCallback回调
    uint32_t isrflags = READ_REG(huart->Instance->SR);
    uint32_t cr1its = READ_REG(huart->Instance->CR1)

  4. 中断内部源码如下:

    void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)
    {
      uint32_t isrflags   = READ_REG(huart->Instance->SR);
      uint32_t cr1its     = READ_REG(huart->Instance->CR1);
      uint32_t cr3its     = READ_REG(huart->Instance->CR3);
      uint32_t errorflags = 0x00U;
      uint32_t dmarequest = 0x00U;
    
      /* If no error occurs */
      errorflags = (isrflags & (uint32_t)(USART_SR_PE | USART_SR_FE | USART_SR_ORE | USART_SR_NE));
      if (errorflags == RESET)
      {
        /* UART in mode Receiver -------------------------------------------------*/
        if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
        {
          UART_Receive_IT(huart);
          return;
        }
      }
    
      /* If some errors occur */
      if ((errorflags != RESET) && (((cr3its & USART_CR3_EIE) != RESET)
                                    || ((cr1its & (USART_CR1_RXNEIE | USART_CR1_PEIE)) != RESET)))
      {
        /* UART parity error interrupt occurred ----------------------------------*/
        if (((isrflags & USART_SR_PE) != RESET) && ((cr1its & USART_CR1_PEIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_PE;
        }
    
        /* UART noise error interrupt occurred -----------------------------------*/
        if (((isrflags & USART_SR_NE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_NE;
        }
    
        /* UART frame error interrupt occurred -----------------------------------*/
        if (((isrflags & USART_SR_FE) != RESET) && ((cr3its & USART_CR3_EIE) != RESET))
        {
          huart->ErrorCode |= HAL_UART_ERROR_FE;
        }
    
        /* UART Over-Run interrupt occurred --------------------------------------*/
        if (((isrflags & USART_SR_ORE) != RESET) && (((cr1its & USART_CR1_RXNEIE) != RESET)
                                                     || ((cr3its & USART_CR3_EIE) != RESET)))
        {
          huart->ErrorCode |= HAL_UART_ERROR_ORE;
        }
    
        /* Call UART Error Call back function if need be --------------------------*/
        if (huart->ErrorCode != HAL_UART_ERROR_NONE)
        {
          /* UART in mode Receiver -----------------------------------------------*/
          if (((isrflags & USART_SR_RXNE) != RESET) && ((cr1its & USART_CR1_RXNEIE) != RESET))
          {
            UART_Receive_IT(huart);
          }
    
          /* If Overrun error occurs, or if any error occurs in DMA mode reception,
             consider error as blocking */
          dmarequest = HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR);
          if (((huart->ErrorCode & HAL_UART_ERROR_ORE) != RESET) || dmarequest)
          {
            /* Blocking error : transfer is aborted
               Set the UART state ready to be able to start again the process,
               Disable Rx Interrupts, and disable Rx DMA request, if ongoing */
            UART_EndRxTransfer(huart);
    
            /* Disable the UART DMA Rx request if enabled */
            if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
            {
              ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    
              /* Abort the UART DMA Rx stream */
              if (huart->hdmarx != NULL)
              {
                /* Set the UART DMA Abort callback :
                   will lead to call HAL_UART_ErrorCallback() at end of DMA abort procedure */
                huart->hdmarx->XferAbortCallback = UART_DMAAbortOnError;
                if (HAL_DMA_Abort_IT(huart->hdmarx) != HAL_OK)
                {
                  /* Call Directly XferAbortCallback function in case of error */
                  huart->hdmarx->XferAbortCallback(huart->hdmarx);
                }
              }
              else
              {
                /* Call user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
                /*Call registered error callback*/
                huart->ErrorCallback(huart);
    #else
                /*Call legacy weak error callback*/
                HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
              }
            }
            else
            {
              /* Call user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
              /*Call registered error callback*/
              huart->ErrorCallback(huart);
    #else
              /*Call legacy weak error callback*/
              HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
            }
          }
          else
          {
            /* Non Blocking error : transfer could go on.
               Error is notified to user through user error callback */
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered error callback*/
            huart->ErrorCallback(huart);
    #else
            /*Call legacy weak error callback*/
            HAL_UART_ErrorCallback(huart);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
    
            huart->ErrorCode = HAL_UART_ERROR_NONE;
          }
        }
        return;
      } /* End if some error occurs */
    
      /* Check current reception Mode :
         If Reception till IDLE event has been selected : */
      if ((huart->ReceptionType == HAL_UART_RECEPTION_TOIDLE)
          && ((isrflags & USART_SR_IDLE) != 0U)
          && ((cr1its & USART_SR_IDLE) != 0U))
      {
        __HAL_UART_CLEAR_IDLEFLAG(huart);
    
        /* Check if DMA mode is enabled in UART */
        if (HAL_IS_BIT_SET(huart->Instance->CR3, USART_CR3_DMAR))
        {
          /* DMA mode enabled */
          /* Check received length : If all expected data are received, do nothing,
             (DMA cplt callback will be called).
             Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
          uint16_t nb_remaining_rx_data = (uint16_t) __HAL_DMA_GET_COUNTER(huart->hdmarx);
          if ((nb_remaining_rx_data > 0U)
              && (nb_remaining_rx_data < huart->RxXferSize))
          {
            /* Reception is not complete */
            huart->RxXferCount = nb_remaining_rx_data;
    
            /* In Normal mode, end DMA xfer and HAL UART Rx process*/
            if (huart->hdmarx->Init.Mode != DMA_CIRCULAR)
            {
              /* Disable PE and ERR (Frame error, noise error, overrun error) interrupts */
              ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_PEIE);
              ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    
              /* Disable the DMA transfer for the receiver request by resetting the DMAR bit
                 in the UART CR3 register */
              ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_DMAR);
    
              /* At end of Rx process, restore huart->RxState to Ready */
              huart->RxState = HAL_UART_STATE_READY;
              huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    
              ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
    
              /* Last bytes received, so no need as the abort is immediate */
              (void)HAL_DMA_Abort(huart->hdmarx);
            }
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered Rx Event callback*/
            huart->RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
    #else
            /*Call legacy weak Rx Event callback*/
            HAL_UARTEx_RxEventCallback(huart, (huart->RxXferSize - huart->RxXferCount));
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
          }
          return;
        }
        else
        {
          /* DMA mode not enabled */
          /* Check received length : If all expected data are received, do nothing.
             Otherwise, if at least one data has already been received, IDLE event is to be notified to user */
          uint16_t nb_rx_data = huart->RxXferSize - huart->RxXferCount;
          if ((huart->RxXferCount > 0U)
              && (nb_rx_data > 0U))
          {
            /* Disable the UART Parity Error Interrupt and RXNE interrupts */
            ATOMIC_CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));
    
            /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */
            ATOMIC_CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);
    
            /* Rx process is completed, restore huart->RxState to Ready */
            huart->RxState = HAL_UART_STATE_READY;
            huart->ReceptionType = HAL_UART_RECEPTION_STANDARD;
    
            ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);
    #if (USE_HAL_UART_REGISTER_CALLBACKS == 1)
            /*Call registered Rx complete callback*/
            huart->RxEventCallback(huart, nb_rx_data);
    #else
            /*Call legacy weak Rx Event callback*/
            HAL_UARTEx_RxEventCallback(huart, nb_rx_data);
    #endif /* USE_HAL_UART_REGISTER_CALLBACKS */
          }
          return;
        }
      }
    
      /* UART in mode Transmitter ------------------------------------------------*/
      if (((isrflags & USART_SR_TXE) != RESET) && ((cr1its & USART_CR1_TXEIE) != RESET))
      {
        UART_Transmit_IT(huart);
        return;
      }
    
      /* UART in mode Transmitter end --------------------------------------------*/
      if (((isrflags & USART_SR_TC) != RESET) && ((cr1its & USART_CR1_TCIE) != RESET))
      {
        UART_EndTransmit_IT(huart);
        return;
      }
    }
  1. 用户配置如下
bool driver_uart2_config_f( receive_callback_handle user_callback_handle, receive_callback_handle user_callback_error_handle )
{
    if ( NULL == user_callback_handle  ||  NULL == user_callback_error_handle )
        return false;
	
    memset( driver_uart1_f.rx_buffer, 0, DRIVER_UART_MAXNUM );
    driver_uart2_f.usart_receive_callback = user_callback_handle;
    driver_uart2_f.usart_receive_callback_error = user_callback_error_handle;
    driver_uart2_f.driver_usart_transmit = driver_usart2_transmit_f;
    driver_uart2_f.driver_usart_transmit_cleareeeor = driver_usart2_transmit_cleareeeor_f;
    huart2.Instance->DR;
    __HAL_UART_CLEAR_IDLEFLAG( &huart2 );
    while( HAL_OK != HAL_UARTEx_ReceiveToIdle_DMA(&huart2, driver_uart2_f.rx_buffer, DRIVER_UART_MAXNUM ) ) ;
    
    __HAL_UART_ENABLE_IT( &DRIVER_USART2, UART_IT_IDLE );
    __HAL_DMA_ENABLE_IT( &DRIVER_USART2_DMA_TX, DMA_IT_TC );
    HAL_NVIC_EnableIRQ(USART2_IRQn);
	log_a( "esp32_uart_init ready" );
    gpio_modute_rest.driver_gpio_write( &gpio_modute_rest, true );
	return true;
}
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
	if(huart->Instance ==DRIVER_USART2_INS)
    {
        driver_uart2_f.rx_state = RX_OVER;
        driver_uart2_f.rx_cnt = DRIVER_UART_MAXNUM - __HAL_DMA_GET_COUNTER( &hdma_usart2_rx );
        driver_uart2_f.usart_receive_callback();
        driver_uart2_f.rx_state = RX_IDLE;
        driver_uart2_f.rx_cnt = 0;
        huart2.RxState = HAL_UART_STATE_READY;
        __HAL_UART_ENABLE_IT( &DRIVER_USART2, UART_IT_IDLE );
        while( HAL_OK != HAL_UARTEx_ReceiveToIdle_DMA(&huart2, driver_uart2_f.rx_buffer, DRIVER_UART_MAXNUM ) ) ;
	}
	return;
}

解决方案:

尝试更改hal库底层:

强制设置标志位huart->ReceptionType以及huart->RxState,

屏蔽ATOMIC_CLEAR_BIT(huart->Instance->CR1, USART_CR1_IDLEIE);

仍然出现数据无法触发中断,最终更改为LL库

使用vscode生成LL 工程后,用户代码如下

/**
 * @description: 
 * @param {uint8_t} *p_buffer
 * @param {uint32_t} g_len
 * @return {*}
 */
driver_tx_state_Enu driver_usart1_transmit_f( uint8_t *p_buffer, uint16_t g_len )
{
    if ( TX_OVER == driver_uart1_f.tx_state )
    {
        LL_DMA_DisableStream( DMA2, LL_DMA_STREAM_7 );
        LL_DMA_SetMemoryAddress( DMA2, LL_DMA_STREAM_7, ( uint32_t )( &p_buffer[ 0 ] ) );
        LL_DMA_SetPeriphAddress( DMA2, LL_DMA_STREAM_7, ( uint32_t )( &USART1->DR ) );
        LL_DMA_SetDataLength( DMA2, LL_DMA_STREAM_7, g_len );
        LL_DMA_EnableStream( DMA2, LL_DMA_STREAM_7 );
        driver_uart1_f.tx_state = TX_NORMAL;
        return TX_NORMAL;
    }
    return TX_ERROR;
}
/**
 * @description: 
 * @return {*}
 */
void driver_usart1_transmit_cleareeeor_f( void )
{
    driver_uart1_f.tx_state = TX_OVER;
    LL_DMA_DisableStream( DMA2, LL_DMA_STREAM_7 );
}
/**
 * @description: 
 * @param {UART_HandleTypeDef} *huart
 * @param {DMA_HandleTypeDef} *hdma
 * @return {*}
 */
void user_uart_dma_interrupt( USART_TypeDef* huart, DMA_TypeDef* dma, uint32_t g_stream )
{
    if ( RESET != LL_DMA_IsActiveFlag_TC6( dma ) )
    {
        LL_DMA_ClearFlag_TC6( dma );
        driver_uart2_f.tx_state = TX_OVER;
        LL_DMA_DisableStream( dma, g_stream );
    }
    if ( RESET != LL_DMA_IsActiveFlag_TC7( dma ) )
    {
        LL_DMA_ClearFlag_TC7( dma );
        gpio_rs485_en.driver_gpio_write( &gpio_rs485_en, RS485_RX );
        driver_uart1_f.tx_state = TX_OVER;
        LL_DMA_DisableStream( dma, g_stream );
    }
}
/**
 * @description: 
 * @param {USART_TypeDef*} huart
 * @param {DMA_TypeDef*} dma
 * @param {uint32_t} g_stream
 * @return {*}
 */
void user_uart_interrupt( USART_TypeDef* huart, DMA_TypeDef* dma, uint32_t g_stream )
{
    if ( DRIVER_USART1_INS == huart )
    {
        if ( RESET != LL_USART_IsActiveFlag_IDLE( huart ) )
        {
            LL_USART_ClearFlag_IDLE( huart );
            
            LL_DMA_DisableStream( dma, g_stream );
            driver_uart1_f.usart_receive_callback();
            LL_DMA_SetPeriphAddress( dma, g_stream, ( uint32_t )( &USART1->DR ) );
            LL_DMA_SetMemoryAddress( dma, g_stream, ( uint32_t )( &driver_uart1_f.rx_buffer ) );
            LL_DMA_SetDataLength( dma, g_stream, DRIVER_UART_MAXNUM );
            LL_DMA_EnableStream( dma, g_stream );
        }
        LL_USART_ClearFlag_RXNE( huart );
    }
    else if( DRIVER_USART2_INS == huart )
    {
        if ( RESET != LL_USART_IsActiveFlag_IDLE( huart ) )
        {
            LL_USART_ClearFlag_IDLE( huart );
            
            LL_DMA_DisableStream( dma, g_stream );
            driver_uart2_f.usart_receive_callback();
            LL_DMA_SetPeriphAddress( dma, g_stream, ( uint32_t )( &USART2->DR ) );
            LL_DMA_SetMemoryAddress( dma, g_stream, ( uint32_t )( &driver_uart2_f.rx_buffer ) );
            LL_DMA_SetDataLength( dma, g_stream, DRIVER_UART_MAXNUM );
            LL_DMA_EnableStream( dma, g_stream );
        }
        LL_USART_ClearFlag_RXNE( huart );
    }
}
/**
 * @description: 
 * @param {receive_callback_handle} user_callback_handle
 * @param {receive_callback_handle} user_callback_error_handle
 * @return {*}
 */
bool driver_uart1_config_f( receive_callback_handle user_callback_handle, receive_callback_handle user_callback_error_handle )
{
    if ( NULL == user_callback_handle  ||  NULL == user_callback_error_handle )
        return false;
	
    memset( driver_uart1_f.rx_buffer, 0, DRIVER_UART_MAXNUM );
    driver_uart1_f.usart_receive_callback = user_callback_handle;
    driver_uart1_f.usart_receive_callback_error = user_callback_error_handle;
    driver_uart1_f.driver_usart_transmit = driver_usart1_transmit_f;
    driver_uart1_f.driver_usart_transmit_cleareeeor = driver_usart1_transmit_cleareeeor_f;
//    HAL_UARTEx_ReceiveToIdle_DMA( &DRIVER_USART1, driver_uart1_f.rx_buffer, DRIVER_UART_MAXNUM );
//    
//    __HAL_UART_ENABLE_IT( &DRIVER_USART1, UART_IT_IDLE );
//    __HAL_DMA_ENABLE_IT( &DRIVER_USART1_DMA_TX, DMA_IT_TC );
    
    LL_DMA_SetPeriphAddress( DMA2, LL_DMA_STREAM_2, ( uint32_t )( &USART1->DR ) );
    LL_DMA_SetDataLength( DMA2, LL_DMA_STREAM_2, DRIVER_UART_MAXNUM );
    LL_DMA_SetMemoryAddress( DMA2, LL_DMA_STREAM_2, ( uint32_t )( &driver_uart1_f.rx_buffer ) );
    LL_USART_EnableIT_IDLE( USART1 );
    LL_DMA_EnableStream( DMA2, LL_DMA_STREAM_2 );
    LL_USART_EnableDMAReq_RX( USART1 );

    LL_DMA_SetPeriphAddress( DMA2, LL_DMA_STREAM_7, ( uint32_t )( &USART1->DR ) );
    LL_DMA_EnableIT_TC( DMA2, LL_DMA_STREAM_7 );
    LL_USART_EnableDMAReq_TX( USART1 );
    
	log_a( "rs485_uart_init ready" );
    gpio_rs485_en.driver_gpio_write( &gpio_rs485_en, RS485_RX );
	return true;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
hal库是一个功能强大的硬件抽象层,用于简化嵌入式系统的开发过程。它提供了许多功能来控制外设,例如PWM(脉冲宽度调制)输出。 要记录输出PWM数量,我们可以使用HAL库提供的TIM(定时器)功能。首先,我们需要初始化一个TIM实例,并设置其相关参数,例如频率和占空比。然后,将TIM连接到GPIO引脚,并使能TIM以开始定时器计数。 接下来,我们需要在代码中创建一个变量来保存PWM数量。在每次PWM输出完成后,我们可以通过检查TIM的状态寄存器来确定是否已经输出完整的PWM周期。如果输出完成,则将PWM数量增加1。 以下是一个使用HAL库记录输出PWM数量的示例代码: ```c #include "stm32f4xx_hal.h" TIM_HandleTypeDef htim1; // TIM1实例 uint32_t pwmCount = 0; // 记录PWM数量的变量 void HAL_TIM_PWM_PulseFinishedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM1) { pwmCount++; } } int main(void) { HAL_Init(); // HAL库初始化 SystemClock_Config(); // 系统时钟配置(需要根据具体的MCU修改) // 初始化TIM1 htim1.Instance = TIM1; htim1.Init.Prescaler = 0; htim1.Init.CounterMode = TIM_COUNTERMODE_UP; htim1.Init.Period = 999; htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; HAL_TIM_PWM_Init(&htim1); // 使用GPIO引脚连接TIM1输出通道 GPIO_InitTypeDef GPIO_InitStruct; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = GPIO_PIN_8; GPIO_InitStruct.Mode = GPIO_MODE_AF_PP; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; GPIO_InitStruct.Alternate = GPIO_AF1_TIM1; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); // 启动TIM1 HAL_TIM_PWM_Start_IT(&htim1, TIM_CHANNEL_1); while (1) { // 主循环代码 } } ``` 在上面的示例中,我们使用了HAL库的定时器驱动功能来输出PWM。在每次PWM输出完成后,回调函数`HAL_TIM_PWM_PulseFinishedCallback`将被调用。我们在该回调函数中检查TIM的实例是否为TIM1,并在符合条件时将PWM数量增加1。 通过这种方式,我们就可以使用HAL库记录输出的PWM数量了!当然,具体的实现方式可能因系列和型号的MCU而有所区别,但基本的思路是一样的。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值