【问题标题】:STM32 TIM callback to raise flagSTM32 TIM回调引发标志
【发布时间】:2020-11-14 17:16:02
【问题描述】:

我读过很多次,通常最好的做法是尽量减少在定时器中断上花费的时间,并且多次提出只提高标志的建议。

我正在使用计时器来运行一些代码(将传感器数据转换为可用数据)。在我的应用程序中,以相当高的速度 (8KHz) 读取和操作这些数据非常重要。

这是我解决问题的方法:

  • 我正在使用 STM32 H743

  • 我正在使用具有两个线程的 RTOS,优先级略有不同

  • 在我的情况下,我使用了 2 个计时器(TIM2 和 TIM3)

  • TIM2 设置为在 1KHz 触发回调,并在我的主线程中启动(优先级略高于辅助线程)

  • TIM3 设置为在 8KHz 触发回调,并在辅助线程中启动

  • HAL_TIM_PeriodElapsedCallback 用于两个计时器,如下所示:

    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
    /* USER CODE BEGIN Callback 0 */
    
    /* USER CODE END Callback 0 */
        if (htim->Instance == TIM6) {
          HAL_IncTick();
        }
    /* USER CODE BEGIN Callback 1 */
    else if (htim->Instance == TIM2) {
        TIM3_flag = 1;
    }
    
    else if (htim->Instance == TIM3) {
        TIM3_flag = 1;
    }
    /* USER CODE END Callback 1 */
    }
    

然后 2 个线程中的每一个都对标志进行简单测试,这是辅助线程的样子:

void StartSecondaryThread(void *argument)
{
  /* USER CODE BEGIN StartSecondaryThread */
    HAL_TIM_Base_Start_IT(&htim3);
  /* Infinite loop */
  for(;;)
  {
      if (TIM3_flag == 1) {
          runCALC();
          //MORE USER CODE HERE
          TIM3_flag = 0;
      }
  }
  /* USER CODE END StartSecondaryThread */
}

根据 CubeMX 自动生成的代码,mainThread 和 secondaryThread 无限 for(;;) 循环都有一个 osDelay(1)。

我应该保留这些天吗?在升旗的 if 语句之外?

我有些担心,如果我不这样做,它会导致 MCU 崩溃,因为在没有升起标志的情况下,外界无事可做。而且我担心保持 osDelay(1) 会“太长”(1ms vs 125 us)。有没有办法应用更短的延迟而不会减慢我的 8KHz 轮询?

当然,runCAL() 的内容将比 125 us 周期花费的时间要少得多。

将延迟全部消除对我来说是有意义的,但我感觉它会严重崩溃。

我该怎么办?

干杯

【问题讨论】:

    标签: timer stm32 interrupt


    【解决方案1】:

    使用 RTOS 时,标志并不是线程同步的好方法。

    在这种情况下,请使用信号量、互斥锁或直接任务通知。

    比辅助线程的优先级略高

    它在您显示的代码中没有任何区别不同优先级的 RTOS 任务不会被调度程序抢占,并且只有当您自己传递控制权时才会发生上下文切换。唯一真正会一直运行的任务是最后启动的任务,因为您的任务不会将控制权传递给 RTOS,而 ISR 也不会。您的代码实际上不是正确的 RTOS 代码。

    您可以在一项任务中使用它。

    void StartSecondaryThread(void *argument)
    {
        /* USER CODE BEGIN StartSecondaryThread */
        HAL_TIM_Base_Start_IT(&htim3);
        HAL_TIM_Base_Start_IT(&htim2);
        /* Infinite loop */
        for(;;)
        {
            switch(ulTaskNotifyTake(pdTRUE, portMAX_DELAY))
            {
                case 3:
                    runCALC();
                    //MORE USER CODE HERE for timer 3
                    break;
                case 2:
                    //MORE USER CODE HERE for timer 2
                    break;
                default:
                    //MORE USER CODE HERE for other timers
                    break;
            }
        }
        /* USER CODE END StartSecondaryThread */
    }
    
    
    void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
    {
        BaseType_t xHigherPriorityTaskWoken = pdFalse;
        switch((uint32_t)htim->Instance)
        {
            case (uint32_t)TIM6:
                HAL_IncTick();
                break;
            case (uint32_t)TIM2:
                xTaskNotifyFromISR( xThreadHndl, 2, eSetValueWithOverwrite, &xHigherPriorityTaskWoken );
                break;
            case (uint32_t)TIM3:
                xTaskNotifyFromISR( xThreadHndl, 3, eSetValueWithOverwrite, &xHigherPriorityTaskWoken );
                break;
        }
        portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
    }
    

    【讨论】:

    • 默认情况下(configUSE_TIME_SLICING 定义为 1),FreeRTOS 调度程序在具有最高优先级的任务之间切换。如果您将系统设计为完全具有同等优先级的任务,这可能会很有用,但当然最好使用适当的同步原语。
    猜你喜欢
    • 2021-08-17
    • 2019-04-20
    • 1970-01-01
    • 1970-01-01
    • 2018-10-07
    • 2011-03-21
    • 1970-01-01
    • 2021-10-23
    • 2020-11-08
    相关资源
    最近更新 更多