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

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个回答

所属标签

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