STM32cubeMX配置Systick的bug

STM32cubeMX版本:6.11.0

现象

STM32cubeMX配置Systick的时钟,不管选择不分频 还是8分频。

生成的代码都是一样的,代码都是不分频。

即不管选择不分频还是8分频,Systick都是使用的系统时钟

函数调用

HAL_Init() →

HAL_InitTick(TICK_INT_PRIORITY) →

HAL_SYSTICK_Config(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) →

SysTick_Config(TicksNumb)

各个函数的源码如下所示:

c 复制代码
__weak HAL_StatusTypeDef HAL_InitTick(uint32_t TickPriority)
{
  /* Check uwTickFreq for MisraC 2012 (even if uwTickFreq is a enum type that don't take the value zero)*/
  if((uint32_t)uwTickFreq == 0UL)
  {
    return HAL_ERROR;
  }

    /* Configure the SysTick to have interrupt in 1ms time basis*/
    if (HAL_SYSTICK_Config(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) > 0U)
    {
      return HAL_ERROR;
    }

  /* Configure the SysTick IRQ priority */
  if (TickPriority < (1UL << __NVIC_PRIO_BITS))
  {
    HAL_NVIC_SetPriority(SysTick_IRQn, TickPriority, 0U);
    uwTickPrio = TickPriority;
  }
  else
  {
    return HAL_ERROR;
  }

  /* Return function status */
  return HAL_OK;
}

uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
   return SysTick_Config(TicksNumb);
}

__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks)
{
  if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk)
  {
    return (1UL);                                                   /* Reload value impossible */
  }

  SysTick->LOAD  = (uint32_t)(ticks - 1UL);                         /* set reload register */
  NVIC_SetPriority (SysTick_IRQn, (1UL << __NVIC_PRIO_BITS) - 1UL); /* set Priority for Systick Interrupt */
  SysTick->VAL   = 0UL;                                             /* Load the SysTick Counter Value */
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk |
                   SysTick_CTRL_TICKINT_Msk   |
                   SysTick_CTRL_ENABLE_Msk;                         /* Enable SysTick IRQ and SysTick Timer */
  return (0UL);                                                     /* Function successful */
}

可以看到

HAL_SYSTICK_Config(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq))

括号里的(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) 会被设置为SysTick的LOAD寄存器,即重装载值。

SysTick->LOAD = (uint32_t)(ticks - 1UL); /* set reload register */

Cortex M7内核手册有对Systick 的控制和状态寄存器的介绍。

bit2 CLKSOURCE 表明了Systick的时钟源。

为1 时,时钟源为处理器时钟,即系统时钟,也就是不分频或者说1分频。

为0 时,时钟源为外部时钟,也就是系统时钟的8分频。

而Systick的控制与状态寄存器的时钟源选择位设为1。

SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk,即使用系统时钟。

不管选择不分频还是8分频,生成的代码都是这样的,也就是SysTick一直使用的是系统时钟。

配置时钟源HAL_SYSTICK_CLKSourceConfig

其实HAL是有选择时钟源的函数的,就是HAL_SYSTICK_CLKSourceConfig。

源码如下:

c 复制代码
/**
  * @brief  Configures the SysTick clock source.
  * @param  CLKSource specifies the SysTick clock source.
  *         This parameter can be one of the following values:
  *             @arg SYSTICK_CLKSOURCE_HCLK_DIV8: AHB clock divided by 8 selected as SysTick clock source.
  *             @arg SYSTICK_CLKSOURCE_HCLK: AHB clock selected as SysTick clock source.
  * @retval None
  */
void HAL_SYSTICK_CLKSourceConfig(uint32_t CLKSource)
{
  /* Check the parameters */
  assert_param(IS_SYSTICK_CLK_SOURCE(CLKSource));
  if (CLKSource == SYSTICK_CLKSOURCE_HCLK)
  {
    SysTick->CTRL |= SYSTICK_CLKSOURCE_HCLK;
  }
  else
  {
    SysTick->CTRL &= ~SYSTICK_CLKSOURCE_HCLK;
  }
}

我们可以看到 ,配置时钟源也就是设置状态与控制寄存器SysTick->CTRL。

但是这个函数从未被调用。

继续文件搜索这个函数

在stm32h7xx_hal_cortex.c文件中 ,发现了这么一段注释:

You can change the SysTick Clock source to be HCLK_Div8 by calling the macro

HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8) just after the

HAL_SYSTICK_Config() function call. The HAL_SYSTICK_CLKSourceConfig() macro is defined

inside the stm32h7xx_hal_cortex.h file.

你可以通过在这个函数HAL_SYSTICK_Config()之后调用HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8)来更改SysTick的时钟源为HCLK_Div8 。

验证

我们来实验一下

main中的大循环里只有一个点灯程序,每1s切换一次。

修改HAL_SYSTICK_Config函数,在SysTick_Config之后调用HAL_SYSTICK_CLKSourceConfig。

c 复制代码
uint32_t HAL_SYSTICK_Config(uint32_t TicksNumb)
{
    //return SysTick_Config(TicksNumb);

    uint32_t ret = 0;
    ret = SysTick_Config(TicksNumb);
    HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK_DIV8);
    return ret;
}

现象:led灯由原来的1s切换一次,变为8s切换一次。

这是因为SysTick的频率变为原来的1/8。

但是重装载值依然为原来1ms时的装载值(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq)) 。

也就是重装载值没变,但是速度变慢了8倍。

将(SystemCoreClock / (1000UL / (uint32_t)uwTickFreq))修改为

(SystemCoreClock/ 8 / (1000UL / (uint32_t)uwTickFreq))。

现象:led灯1s切换一次。

相关推荐
神膘护体小月半2 分钟前
bug 记录 - 使用 el-dialog 的 before-close 的坑
前端·javascript·bug
想搞嵌入式的小白2 小时前
STM32 NVIC中断控制器
stm32·单片机·嵌入式硬件·nvic
深圳市尚想信息技术有限公司3 小时前
【深尚想】OPA855QDSGRQ1运算放大器IC德州仪器TI汽车级高速8GHz增益带宽的全面解析
单片机·嵌入式硬件
代码总长两年半4 小时前
STM32----IAP远程升级
stm32·单片机·嵌入式硬件
广药门徒5 小时前
STM32手册上标称的18MHz GPIO翻转速度和你实际测量到的速度之间的差异是预期之内且合理的
单片机·嵌入式硬件
广药门徒5 小时前
在使用一些不用驱动大电流的设备就可以用stm32的自己的上下拉但是本身上下拉不就是给iicspi这些他通信给信号的吗中怎么还跟驱动能力扯上了有什么场景嘛
stm32·单片机·fpga开发
顽强d石头5 小时前
bug:undefined is not iterable (cannot read property Symbol(Symbol.iterator))
前端·bug
most diligent14 小时前
蓝桥杯_DS18B20温度传感器---新手入门级别超级详细解析
单片机·嵌入式硬件
君鼎15 小时前
stm32——SPI协议
stm32·单片机·嵌入式硬件
tengtext16 小时前
stm32使用hal库模拟spi模式3
stm32·单片机·嵌入式硬件