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切换一次。

相关推荐
weixin_4526006944 分钟前
《青牛科技 GC6125:驱动芯片中的璀璨之星,点亮 IPcamera 和云台控制(替代 BU24025/ROHM)》
人工智能·科技·单片机·嵌入式硬件·新能源充电桩·智能充电枪
weixin_452600692 小时前
【青牛科技】14W 高保真音频放大电路——D2030
科技·单片机·嵌入式硬件·音视频·电动工具·智能电表
小刘同学-很乖9 小时前
MQTT从入门到精通之MQTT Dashboard
spring boot·stm32·物联网·iot
YuCaiH10 小时前
【STM32】USART串口数据包
笔记·stm32·单片机·嵌入式硬件
随遇而安622&50810 小时前
分布式微服务项目,同一个controller方法间的转发导致cookie丢失,报错null pointer异常
分布式·微服务·架构·bug
Kasen's experience12 小时前
STM32 GPIO 配置
stm32·单片机·嵌入式硬件
知行电子-12 小时前
Proteus中数码管动态扫描显示不全(已解决)
单片机·proteus·嵌入式
学习路上_write13 小时前
FPGA/Verilog,Quartus环境下if-else语句和case语句RT视图对比/学习记录
单片机·嵌入式硬件·qt·学习·fpga开发·github·硬件工程
非概念13 小时前
stm32学习笔记----51单片机和stm32单片机的区别
笔记·stm32·单片机·学习·51单片机
jjjxxxhhh12314 小时前
FPGA,使用场景,相比于单片机的优势
单片机·嵌入式硬件·fpga开发