你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32~配置时钟频率[一文带你解决STM32主频配置]

[复制链接]
STMCU 发布时间:2020-9-14 12:41
前言

  最近开发项目,对MCU主频要求比较精确,尝试了两种配置主频的方法,掌握这两种方法也就熟悉STM32系列主频的配置方法了。分别是,使用外部晶振作为时钟源;内部RC时钟作为时钟源。介绍两种时钟源的区别:


  • HSI内部8MHz的RC振荡器的误差在1%左右,内部RC振荡器的精度通常比用HSE(外部晶振)要差上十倍以上。
  • 内部RC频率受温度影响比较大,如果省电Sleep模式下内部RC会停止工作。



1 . 时钟系统

  在STM32中,有五个时钟源,为HSI、HSE、LSI、LSE、PLL。


  • HSI是高速内部时钟,RC振荡器,频率为8MHz。
  • HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。
  • LSI是低速内部时钟,RC振荡器,频率为40kHz。
  • LSE是低速外部时钟,接频率为32.768kHz的石英晶体。
  • PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

1.png



 用户可通过多个预分频器配置AHB总线、高速APB2总线和低速APB1总线的频率。AHB和APB2域的最大频率是72MHZ。APB1域的最大允许频率是36MHZ。SDIO接口的时钟频率固定为HCLK/2。
  40kHz的LSI供独立看门狗IWDG使用,另外它还可以被选择为实时时钟RTC的时钟源。另外,实时时钟RTC的时钟源还可以选择LSE,或者是HSE的128分频。RTC的时钟源通过RTCSEL[1:0]来选择。
  STM32中有一个全速功能的USB模块,其串行接口引擎需要一个频率为48MHz的时钟源。该时钟源只能从PLL输出端获取,可以选择为1.5分频或者1分频,也就是,当需要使用USB模块时,PLL必须使能,并且时钟频率配置为48MHz或72MHz。
  另外,STM32还可以选择一个PLL输出的2分频、HSI、HSE、或者系统时钟SYSCLK输出到MCO脚(PA8)上。系统时钟SYSCLK,是供STM32中绝大部分部件工作的时钟源,它可选择为PLL输出、HSI或者HSE,(一般程序中采用PLL倍频到72Mhz)在选择时钟源前注意要判断目标时钟源是否已经稳定振荡。Max=72MHz,它分为2路,1路送给I2S2、I2S3使用的I2S2CLK,I2S3CLK;另外1路通过AHB分频器分频(1/2/4/8/16/64/128/256/512)分频后送给以下8大模块使用:


  • 送给SDIO使用的SDIOCLK时钟。
  • 送给FSMC使用的FSMCCLK时钟。
  • 送给AHB总线、内核、内存和DMA使用的HCLK时钟。
  • 通过8分频后送给Cortex的系统定时器时钟(SysTick)。
  • 直接送给Cortex的空闲运行时钟FCLK。
  • 送给APB1分频器。APB1分频器可选择1、2、4、8、16分频,其输出一路供APB1外设使用(PCLK1,最大频率36MHz),另一路送给定时器(Timer2-7)2、3、4倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器2、3、4、5、6、7使用。
  • 送给APB2分频器。APB2分频器可选择1、2、4、8、16分频,其输出一路供APB2外设使用(PCLK2,最大频率72MHz),另一路送给定时器(Timer1、Timer8)1、2倍频器使用。该倍频器可选择1或者2倍频,时钟输出供定时器1和定时器8使用。另外,APB2分频器还有一路输出供ADC分频器使用,分频后得到ADCCLK时钟送给ADC模块使用。ADC分频器可选择为2、4、6、8分频。
  • 2分频后送给SDIO AHB接口使用(HCLK/2)。


2 . 外部晶振作为时钟源

接下来,解决使用12M外部晶振时,如何配置作为系统时钟源。
第一步,修改stm32f10x.h中的HSE_VALUE为12000000


  1. /**
  2. * @brief In the following line adjust the value of External High Speed oscillator (HSE)
  3.    used in your application
  4.    
  5.    Tip: To avoid modifying this file each time you need to use different HSE, you
  6.         can define the HSE value in your toolchain compiler preprocessor.
  7.   */           
  8. #if !defined  HSE_VALUE
  9. #ifdef STM32F10X_CL   
  10.   #define HSE_VALUE    ((uint32_t)25000000) /*!< Value of the External oscillator in Hz */
  11. #else
  12.   #define HSE_VALUE    ((uint32_t)12000000) /*!< Value of the External oscillator in Hz */
  13. #endif /* STM32F10X_CL */
  14. #endif /* HSE_VALUE */
复制代码

第二步,修改system_stm32f10x.c中的时钟配置,先找到void SystemInit(void)—》SetSysClock()—》SetSysClockTo72(),将9倍频改为6倍频,12*6=72MHz


  1. /**
  2.   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2
  3.   *         and PCLK1 prescalers.
  4.   * @note   This function should be used only after reset.
  5.   * @param  None
  6.   * @retval None
  7.   */
  8. static void SetSysClockTo72(void)
  9. {
  10.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  11.   
  12.   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   
  13.   /* Enable HSE */   
  14.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);

  15.   /* Wait till HSE is ready and if Time out is reached exit */
  16.   do
  17.   {
  18.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  19.     StartUpCounter++;  
  20.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  21.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  22.   {
  23.     HSEStatus = (uint32_t)0x01;
  24.   }
  25.   else
  26.   {
  27.     HSEStatus = (uint32_t)0x00;
  28.   }  

  29.   if (HSEStatus == (uint32_t)0x01)
  30.   {
  31.     /* Enable Prefetch Buffer */
  32.     FLASH->ACR |= FLASH_ACR_PRFTBE;

  33.     /* Flash 2 wait state */
  34.     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
  35.     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   


  36.     /* HCLK = SYSCLK */
  37.     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  38.       
  39.     /* PCLK2 = HCLK */
  40.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
  41.    
  42.     /* PCLK1 = HCLK */
  43.     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

  44. #ifdef STM32F10X_CL
  45.     // ...
  46. #else   
  47.     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
  48.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
  49.                                         RCC_CFGR_PLLMULL));
  50.     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6); // 12
  51. #endif /* STM32F10X_CL */

  52.     /* Enable PLL */
  53.     RCC->CR |= RCC_CR_PLLON;

  54.     /* Wait till PLL is ready */
  55.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  56.     {
  57.     }
  58.    
  59.     /* Select PLL as system clock source */
  60.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  61.     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

  62.     /* Wait till PLL is used as system clock source */
  63.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
  64.     {
  65.     }
  66.   }
  67.   else
  68.   { /* If HSE fails to start-up, the application will have wrong clock
  69.          configuration. User can add here some code to deal with this error */
  70.   }
  71. }
复制代码


3 . 内部RC作为时钟源

  实际开发中使用内部RC振荡器主频不能达到72,我使用的是STM32F103C8T6,库函数最多支持16倍频也就是8/2*16=64Mhz,实际测试芯片跑不起来功能没有正常工作。使用内部RC振荡最大能达到52M,不信大家可以试验一下。

在system_STM32f10x.c中,找到函数void SystemInit (void){} 注释掉所有代码,添加下属代码。


  1. //开启HSI
  2.         RCC->CR |= (uint32_t)0x00000001;
  3.         //选择HSI为PLL的时钟源,HSI必须2分频给PLL
  4.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLSRC_HSI_Div2;
  5.         // 8/2 *13 = 52 8/2 *9 = 36 8/2 * 12,设置倍频
  6.         RCC->CFGR |= (uint32_t)RCC_CFGR_PLLMULL12;
  7.         //PLL不分频
  8.         RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
  9.         // 使能PLL
  10.         RCC->CR |= RCC_CR_PLLON;
  11.         // 等待PLL始终就绪
  12.         while((RCC->CR & RCC_CR_PLLRDY) == 0){}
  13.         // 选择PLL为系统时钟源
  14.         RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  15.         RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;
  16.         // 等待PLL成功
  17.         while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}
复制代码


4 .Keil MDK中Xtal的作用


2.png





在手动配置主频的过程中,想到Keil工程菜单应该提供了配置主频的选项,于是又看到这个。百度了一下,这个参数只用于软件仿真的,对于硬件仿真或者直接把程序下载到板子里是没有影响的。

  Xtal 后面的数值是晶振频率值,默认值是所选目标 CPU 的最高可用频率值 。该数值与最终产生的目标代码无关,仅用于软件模拟调试时显示程序执行时间。正确设置该数值可使显示时间与实际所用时间一致,一般将其设置成与你的硬件所用晶振频率相同。




收藏 1 评论0 发布时间:2020-9-14 12:41

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版