如何使用硬件定时器在 STM32f7xx 上生成精确的 1us 中断

How to generate exact 1us interrupt on STM32f7xx using Hardware Timers

我是基于中断的编程新手。 在我当前的项目中,我需要以 1us 的间隔准确生成中断。 下面是 CubeMX 时钟配置选项卡的屏幕截图。 我正在使用 TIM3 定时器,因为它可以产生 1us 的时钟频率。

下面是TIM3配置代码。

static void MX_TIM3_Init(void)
{
    TIM_ClockConfigTypeDef sClockSourceConfig;
    TIM_MasterConfigTypeDef sMasterConfig;

    htim3.Instance = TIM3;
    htim3.Init.Prescaler = 1-1 ;//0x00;// 0x36; || 0x00//1-1
    htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
    htim3.Init.Period = 0xffff-1;  //0x64; || 0xd7 //0xffff-1
    htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;

    if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }

    sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
    if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
    {
       _Error_Handler(__FILE__, __LINE__);
    }

    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
    {
        _Error_Handler(__FILE__, __LINE__);
    }
}

我正在调用定时器

HAL_TIM_IRQHandler(&htim3);
/* USER CODE BEGIN TIM3_IRQn 1 */

HAL_GPIO_TogglePin(GPIOB,GPIO_PIN_6);

我看到产生了持续时间为1.2ms的中断。 任何人都可以让我知道为什么会发生这种情况以及如何将中断持续时间减少到 1us? 定时器频率是否需要更改?

我也在用freeRTOS,其他应用也在微控制器上运行。

非常感谢这方面的任何帮助。

提前致谢

如果您的要求输出一个准确的 500KHz 1:1 mark/space 信号(即 1us 高,1us 低),那么通过中断来做到这一点同时期望您的系统做其他有用的工作既不切实际又不必要。通用定时器具有输出比较功能,可以直接驱动 GPIO 引脚,无需中断或软件开销。

只有某些引脚连接到定时器 OC 通道,因此在这种情况下要驱动 PB6,您需要使用 TIM4 通道 1。

此外,您应该使用可用的 HAL RCC 时钟函数(HAL_RCC_GetPCLK1Freq() 在这种情况下)来计算值以避免错误,而不是确定和硬编码定时器重载和脉冲,这样代码将可移植到其他系统或如果您更改时钟配置将正常工作。

static void MX_TIM4_Init(void)
{
    cost uint32_t PULSE_WIDTH = HAL_RCC_GetPCLK1Freq() * 2 / 1000000 ;
    
    htim4.Instance = TIM4 ;
    htim4.Init.Prescaler = 0;
    htim4.Init.CounterMode = TIM_COUNTERMODE_UP ;
    htim4.Init.Period = PULSE_WIDTH * 2 ;
    htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1 ;
    HAL_TIM_PWM_Init( &htim4 ) ;
    
    TIM_MasterConfigTypeDef sMasterConfig ;
    sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
    sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
    HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
    
    TIM_OC_InitTypeDef sConfigOC ;
    sConfigOC.OCMode = TIM_OCMODE_PWM1;
    sConfigOC.Pulse = PULSE_WIDTH ;
    sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
    sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;

    HAL_TIM_PWM_ConfigChannel(&htim4, &sConfigOC, TIM_CHANNEL_1);
}

那么在其他地方你需要将PB6配置为输出并启动定时器:

  LL_GPIO_InitTypeDef GPIO_InitStruct = {0} ;
  GPIO_InitStruct.Pin = GPIO_PIN_6 ;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE ;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_LOW ;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL ;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO ;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_2 ;

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB)
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);


  HAL_TIM_PWM_Start( &htim4, TIM_CHANNEL_1 ) ; 

此后信号将无限期地保持在 PB6 上,没有 GPIO 访问或中断处理。