STM32G474CBT6之HAL_RCC_ClockConfig()问题?

news2025/3/2 1:09:00

STM32G474CBT6之HAL_RCC_ClockConfig()问题?

很多人在用HAL库时,都用到了寄存器,特别是在数字电源案例中。我也在想,有了标准库,为什么要搞HAL库?HAL库降低了入门的门槛,但在实际应用中,问题也多。最近在阅读HAL_RCC_ClockConfig()函数时,我发现一个问题,问了群里的研发人员,大家也认为是一个bug,但是这个bug很难表现出来,因为后面的程序将前面的错误给修改了,但对于局部来说,是一个bug

问题如下:
MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV16);
修改对象是“RCC_CFGR_PPRE2

 

HAL库程序如下:

HAL_StatusTypeDef HAL_RCC_ClockConfig(RCC_ClkInitTypeDef  *RCC_ClkInitStruct, uint32_t FLatency)

{

  uint32_t tickstart;

  uint32_t pllfreq;

  uint32_t hpre = RCC_SYSCLK_DIV1;

  /* Check Null pointer */

  if (RCC_ClkInitStruct == NULL)

  {

    return HAL_ERROR;

  }

  /* Check the parameters */

  assert_param(IS_RCC_CLOCKTYPE(RCC_ClkInitStruct->ClockType));

  assert_param(IS_FLASH_LATENCY(FLatency));

  /* To correctly read data from FLASH memory, the number of wait states (LATENCY)

    must be correctly programmed according to the frequency of the CPU clock

    (HCLK) and the supply voltage of the device. */

  /* Increasing the number of wait states because of higher CPU frequency */

  if (FLatency > __HAL_FLASH_GET_LATENCY())

  {//读取FLASH->ACR寄存器的bit3:0(LATENCY[3:0])

    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */

    __HAL_FLASH_SET_LATENCY(FLatency);

         //设置FLASH->ACR寄存器的bit3:0(LATENCY[3:0]),令LATENCY[3:0]=FLatency

    /* Check that the new number of wait states is taken into account to access the Flash

    memory by reading the FLASH_ACR register */

    if (__HAL_FLASH_GET_LATENCY() != FLatency)

    {

      return HAL_ERROR;

    }

  }

  /*--------SYSCLK系统时钟配置(SYSCLK Configuration)--------------*/

  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_SYSCLK) == RCC_CLOCKTYPE_SYSCLK)

  {

    assert_param(IS_RCC_SYSCLKSOURCE(RCC_ClkInitStruct->SYSCLKSource));

    /*使用PLL作为系统时钟源,PLL is selected as System Clock Source */

    if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_PLLCLK)

    {

      /* Check the PLL ready flag */

      if (READ_BIT(RCC->CR, RCC_CR_PLLRDY) == 0U)

      {//RCC->CR寄存器的bit25(PLLRDY),PLLRDY=1表示PLL时钟已经就绪

        return HAL_ERROR;

      }

      /* Undershoot management when selection PLL as SYSCLK source and frequency above 80Mhz */

      /* Compute target PLL output frequency */

      pllfreq = RCC_GetSysClockFreqFromPLLSource();//读取系统时钟频率为85MHz

      /* Intermediate step with HCLK prescaler 2 necessary before to go over 80Mhz */

                            //在超过80MHz之前,需要这个中间步骤将HCLK设置为2分频

      if(pllfreq > 80000000U)//如果系统时钟频率大于80MHz

      {

        if (((READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) == RCC_SYSCLK_DIV1)) ||

            (((((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK) &&

              (RCC_ClkInitStruct->AHBCLKDivider == RCC_SYSCLK_DIV1))))

        {

          MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);

/*修改RCC->CFGR寄存器bit7:4(HPRE[3:0]),HPRE[3:0]=1000b,设置AHB分频器值为2分频;AHB时钟为系统时钟的2分频,SYSCLK divided by 2HCLK时钟频率为系统时钟的2分频,后面会再次对它进行配置,这里是个中间步骤。*/

          hpre = RCC_SYSCLK_DIV2;

//记录,后面以此为依据来修改;但是本次配置已经指定了"AHB时钟(HCLK)的分频值"

        }

      }

    }

    else

    {

      /* HSE is selected as System Clock Source */

      if (RCC_ClkInitStruct->SYSCLKSource == RCC_SYSCLKSOURCE_HSE)

      {

        /* Check the HSE ready flag */

        if(READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U)

        {

          return HAL_ERROR;

        }

      }

      /* HSI is selected as System Clock Source */

      else

      {

        /* Check the HSI ready flag */

        if(READ_BIT(RCC->CR, RCC_CR_HSIRDY) == 0U)

        {

          return HAL_ERROR;

        }

      }

      /* Overshoot management when going down from PLL as SYSCLK source and frequency above 80Mhz */

      pllfreq = HAL_RCC_GetSysClockFreq();

    /* Intermediate step with HCLK prescaler 2 necessary before to go under 80Mhz */

      if(pllfreq > 80000000U)

      {

        MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV2);

        hpre = RCC_SYSCLK_DIV2;

      }

    }

    MODIFY_REG(RCC->CFGR, RCC_CFGR_SW, RCC_ClkInitStruct->SYSCLKSource);

//修改RCC->CFGR寄存器bit1:0(SW[1:0]),SW[1:0]=11bPLL被选择为系统时钟

    /* Get Start Tick*/

    tickstart = HAL_GetTick();

    while (__HAL_RCC_GET_SYSCLK_SOURCE() != (RCC_ClkInitStruct->SYSCLKSource << RCC_CFGR_SWS_Pos))

    {

      if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)

      {

        return HAL_TIMEOUT;

      }

    }

  }

  /*-------HCLK时钟配置,HCLK Configuration --------------*/

  if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_HCLK) == RCC_CLOCKTYPE_HCLK)

  {

    /* Set the highest APB divider in order to ensure that we do not go through

       a non-spec phase whatever we decrease or increase HCLK. */

/*设置最高的APB分配器,以确保我们不会经历一个非规范的阶段,无论我们如何减少或增加HCLK*/

    if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)

    {

      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_HCLK_DIV16);

/*修改RCC->CFGR寄存器bit10:8(PPRE1[2:0]),PPRE1[2:0]=111bAPB1分频器值为16; APB1时钟,PCLK1时钟为HCLK divided by 16,后面会对它进行修改,这里是一个中间步骤;*/

    }

    if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)

    {

      MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, RCC_HCLK_DIV16);

/*修改RCC->CFGR寄存器bit13:11(PPRE2[2:0]),PPRE2[2:0]=111bAPB2分频器值为16;APB2时钟,PCLK2时钟为HCLK divided by 16,后面会对它进行修改,这里是一个中间步骤;*/

//这个“HAL库”是不是错了?还是有意为之??

    }

    /* Set the new HCLK clock divider */

    assert_param(IS_RCC_HCLK(RCC_ClkInitStruct->AHBCLKDivider));

    MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_ClkInitStruct->AHBCLKDivider);

/*修改RCC->CFGR寄存器bit7:4(HPRE[3:0]),HPRE[3:0]=0xxxbAHB分频器值为1HCLKSYSCLK not divided;还记得前面有一个中间步骤吗?这里再次配置HCLK时钟分频器。*/

  }

  else

  {

    /* Is intermediate HCLK prescaler 2 applied internally, complete with HCLK prescaler 1 */

    if(hpre == RCC_SYSCLK_DIV2)

    {

      MODIFY_REG(RCC->CFGR, RCC_CFGR_HPRE, RCC_SYSCLK_DIV1);

    }

  }

  /* Decreasing the number of wait states because of lower CPU frequency */

  if (FLatency < __HAL_FLASH_GET_LATENCY())

  {//读取FLASH->ACR寄存器的bit3:0(LATENCY[3:0])

    /* Program the new number of wait states to the LATENCY bits in the FLASH_ACR register */

    __HAL_FLASH_SET_LATENCY(FLatency);

/*设置FLASH->ACR寄存器的bit3:0(LATENCY[3:0]),令LATENCY[3:0]=FLatency*/

    /* Check that the new number of wait states is taken into account to access the Flash

    memory by polling the FLASH_ACR register */

    tickstart = HAL_GetTick();

    while (__HAL_FLASH_GET_LATENCY() != FLatency)

    {

      if ((HAL_GetTick() - tickstart) > CLOCKSWITCH_TIMEOUT_VALUE)

      {

        return HAL_TIMEOUT;

      }

    }

  }

  /*--------PCLK1时钟配置,PCLK1 Configuration ---------*/

  if (((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK1) == RCC_CLOCKTYPE_PCLK1)

  {

    assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB1CLKDivider));

    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE1, RCC_ClkInitStruct->APB1CLKDivider);

/*修改RCC->CFGR寄存器bit10:8(PPRE1[2:0]),PPRE1[2:0]=0xxbAPB1分频器值为1APB1时钟,PCLK1时钟为HCLK divided by 1;记得前面对它配置过一次,用的是16分频,但那只是一个中间步骤,不是最终的配置;*/

  }

  /*--------PCLK2时钟配置,PCLK2 Configuration ----------*/

  if(((RCC_ClkInitStruct->ClockType) & RCC_CLOCKTYPE_PCLK2) == RCC_CLOCKTYPE_PCLK2)

  {

    assert_param(IS_RCC_PCLK(RCC_ClkInitStruct->APB2CLKDivider));

    MODIFY_REG(RCC->CFGR, RCC_CFGR_PPRE2, ((RCC_ClkInitStruct->APB2CLKDivider) << 3U));

/*修改RCC->CFGR寄存器bit13:11(PPRE2[2:0]),PPRE2[2:0]=0xxxbAPB2分频器值为1APB2时钟,PCLK2时钟为HCLK divided by 1;记得前面对它配置过一次,用的是16分频,但那只是一个中间步骤,不是最终的配置;*/

  }

  /* Update the SystemCoreClock global variable */

  SystemCoreClock = HAL_RCC_GetSysClockFreq() >> (AHBPrescTable[READ_BIT(RCC->CFGR, RCC_CFGR_HPRE) >> RCC_CFGR_HPRE_Pos] & 0x1FU);

  //读取系统时钟频率为85MHz

  /* Configure the source of time base considering new system clocks settings*/

  return HAL_InitTick(TICK_INT_PRIORITY);

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1987942.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

24/8/6算法笔记 支持向量机

支持向量机&#xff08;Support Vector Machine, SVM&#xff09;是一种监督学习算法&#xff0c;主要用于分类和回归任务。它基于统计学习理论中的结构风险最小化原理&#xff0c;通过找到数据点之间的最优边界来实现模型的泛化能力。 import numpy as np import matplotlib.…

Android SurfaceFlinger——Fence流转状态(五十)

明白了 fence 的基本原理&#xff0c;我们可以进一步的探索整个 SurfaceFlinger 的中 fence 在其中处于什么角色。 一、流转状态 从启动到屏幕的第一帧的渲染&#xff0c;fence 是不会有任何效果的。因为此时 fence 还没有经过 hwc_set 给 fence 进行赋值。但是到了第二帧开始…

《知识点扫盲 · 请求类型 ContentType》

&#x1f4e2; 大家好&#xff0c;我是 【战神刘玉栋】&#xff0c;有10多年的研发经验&#xff0c;致力于前后端技术栈的知识沉淀和传播。 &#x1f497; &#x1f33b; CSDN入驻不久&#xff0c;希望大家多多支持&#xff0c;后续会继续提升文章质量&#xff0c;绝不滥竽充数…

Lambda函数理解与应用

Lambda 函数是 Python 中一种简洁的定义简单匿名函数的方法。它们通常用于需要小型函数对象的地方&#xff0c;尤其是作为高阶函数&#xff08;如 map, filter, reduce&#xff09;的参数。Lambda 函数的语法非常紧凑&#xff0c;只允许包含一个表达式。 1、问题背景 理解Lamb…

《大型集团信息安全整体解决方案》:从策略到执行的全方位指南(169页PDF下载)

一、前言 本PPT是一份关于华润集团信息安全整体规划方案的详细报告&#xff0c;从集团信息安全建设需求分析、建设规划蓝图、方案设计成果说明、建设内容与指标等几个方案全面阐述了某大型集团信息安全整体解决方案&#xff0c;值得借鉴与参考。报告首先对华润集团当前的信息安…

ChatGPT首次被植入人类大脑:帮助残障人士开启对话

马斯克在脑机接口中最强大的竞争对手Synchron有了新的技术进展&#xff0c;他们首次将ChatGPT整合到其脑机系统中&#xff0c;以使瘫痪患者更容易控制他们的数字设备。Synchron凭借其独特的脑机接口&#xff08;BCI&#xff09;技术脱颖而出&#xff0c;该技术巧妙地运用了成熟…

yum-aptget对应积累

libssl-dev openssl-devel libsnappy-dev

线上扭蛋机小程序详解,扭蛋机带来的乐趣

在当下潮流文化风靡的时代中&#xff0c;扭蛋机作为潮玩娱乐休闲模式&#xff0c;受到了消费者的关注&#xff0c;同时吸引了无数创业者入局。 扭蛋机小程序是在互联网发展下的产物&#xff0c;借助互联网技术&#xff0c;为消费者打造一个集娱乐购物与智能扭蛋为一体的新型扭…

Java 中的序列化和反序列化是什么?

1. 序列化 序列化是将对象转换成可传输的字节序列格式的过程&#xff0c;便于存储和传输。 对象在JVM中是“立体”的&#xff0c;包含各种引用。为了网络传输&#xff0c;需要将这些引用“压扁”&#xff0c;包含必要的信息。 因为对象在JVM中可以认为是“立体”的&#xff0…

Go sdk下载和配置环境变量

本文目录 SDK下载环境变量配置测试 SDK下载 下载地址&#xff1a;https://golang.google.cn/dl/ 更多版本&#xff0c;找到1.9.2 我是win10 64位的&#xff0c;我找到这个下载 下载之后解压&#xff0c;可以看到bin文件夹。 环境变量配置 我的电脑 -> 属性 -> 高级…

跨越距离无缝协作,最新远程控制软件

远程控制与协作已成为推动社会进步与企业发展的重要力量。无论是跨国企业的全球协同办公&#xff0c;还是家庭用户间的远程技术支持&#xff0c;甚至是教育行业的在线教学&#xff0c;远程控制软件都扮演着至关重要的角色。 1.向日葵远程控制 链接一下&#xff1a;https://do…

初探 C++模板:开启高效编程之门

目录 模版的引入 泛型编程 模板的概念 模板的使用 函数模版 函数模板概念 函数模板格式 函数模板的原理 函数模板的实例化 模板参数的匹配原则 类模版 类模板的定义格式 类模板的由来 类模板的实例化 模板的总结 模版的引入 如下代码&#xff0c;我们想实现交换…

OMS 2.0至3.0升级项目成功案例:木九十

作为眼镜行业的标杆品牌木九十&#xff0c;近期成功完成了OMS系统从2.0版本到3.0版本的全面升级。此次升级旨在提升全渠道库存管理能力&#xff0c;优化与SAP系统的无缝对接&#xff0c;实现与WMS系统的全面集成&#xff0c;并改进加工业务、维修单、特权订单和小程序服务。通过…

Ubuntu 无法进行SSH连接,开启22端口

我们在VM中安装好Ubuntu 虚拟机后&#xff0c;经常需要使用Xshell等工具进行远程连接&#xff0c;但是会出现无法连接的问题&#xff0c;原因是Ubuntu中默认关闭了SSH 服务。 1、 查看Ubuntu虚拟机IP地址 2、 利用Tabby等工具进行远程连接 命令&#xff1a;ssh ip地址 这里就是…

Java包

目录 1.包基本介绍 应用场景 包的三大作用 包基本语法 2.包原理 包的本质分析 3.包快速入门 4.包的命名 命名规则 命名规范 5.常用的包 6.包的使用细节 如何引入包 注意事项和使用细节 1.包基本介绍 应用场景 包的三大作用 区分相同名字的类&#xff0c;类…

浏览器用户文件夹详解 - Extensions(十二)

1.Extensions 简洁 1.1 什么是Extensions Extensions是Chromium浏览器中用于存储用户安装的扩展程序的一个重要目录。每当用户从Chrome Web Store或其他来源安装扩展程序时&#xff0c;这些扩展程序的文件都会被下载并存储在这个中。通过管理Extensions&#xff0c;用户和开发…

【时时三省】Code::Blocks 17.12 软件的使用----创建c工程

目录 1&#xff0c;软件下载 2&#xff0c;软件安装 3&#xff0c;软件下载 4&#xff0c;创建工程 5&#xff0c;编译运行 6&#xff0c;调试代码 一&#xff1a;第一种场景调试&#xff1a; 二&#xff1a;第二种场景调试&#xff1a; 三&#xff1a;第三种场景调试 …

哪个牌子手持洗拖一机好?多款热门家用洗地机推荐

以前打扫卫生&#xff0c;每次拖地前都要先扫地&#xff0c;然后再用拖把拧水&#xff0c;拖完还要清洗拖把&#xff0c;整个过程既费时又费力&#xff0c;还容易弄脏手&#xff0c;更重要的是还会出现清洁不干净的情况。而洗地机作为一种集吸尘、拖地、洗地于一体的智能清洁设…

2_stm32定时中断点灯

定时器是个好东西啊~ 之前搞上层应用时&#xff0c;通过定时器可以以某种频率刷新状态&#xff0c;stm32定时器的一种功能就是如此。此外&#xff0c;stm32的定时器还有很多其他功能&#xff0c;如PWM输出等。定时器具体再细分可以分为高级控制定时器、通用定时器、基本定时器等…

stm32应用、项目、调试

主要记录实际使用中的一些注意点。 1.LCD1602 电路图&#xff1a; 看手册&#xff1a;电源和背光可以使用5v或者3.3v&#xff0c;数据和控制引脚直接和单片机引脚连接即可。 单片机型号&#xff1a;stm32c031c6t6 可以直接使用推完输出连接D0--D7,RS,EN,RW引脚&#xff0c;3…