找回密码
 立即注册
首页 业界区 安全 STM32时钟体系、SetSysClock、PLL、时钟源

STM32时钟体系、SetSysClock、PLL、时钟源

懵诬哇 昨天 09:32
V1.0 2024年7月12日

目录

  • 一、时钟体系

    • 1、参考手册
    • 2、时钟源3种
    • 3、时钟树
    • 4. 时钟详解

      • HSE时钟
      • HSI时钟
      • 锁相环时钟
      • 系统时钟
      • HCLK时钟
      • PCLK1时钟
      • PCLK2时钟
      • RTC时钟
      • 独立看门狗时钟:
      • I2S时钟:
      • 以太网PHY时钟:
      • USB PHY时钟:
      • MCO时钟输出

    • 系统时钟配置函数SetSysClock()
    • 系统时钟配置流程

  • 二、PLL

    • 2.1 概述
    • 2.2 基本组成
    • 2.3 类比说明
    • 2.3 相位差[拓展]

  • 三、SystemInit系统初始化函数

    • 1.其实第一个执行的文件是汇编文件
    • 2.初始化Flash接口,更新PLL系统频率
    • 3.调用SetSysClock函数设置PLL时钟,然后进行分频
    • 4.阅读system_stm32f4xx.c文件的头部注释

  • 四、时钟源
  • 参考文章

一、时钟体系

给单片机提供一个时钟信号(一个非常稳定的频率信号),使单片机各内部组件同步工作,并且在和外部设备通信时是也能达到同步。
动态调整运行频率,就可以控制性能与功耗!
STM32 的时钟系统由外部晶振、PLL(锁相环)和内部 RC 振荡器组成。时钟系统主要提供了处理器时钟,以及可选的外设时钟和RTC模块时钟。
其作用包括:

  • 为处理器提供准确的时钟信号,保证处理器、总线和外设的正确工作。
  • 通过 PLL 的倍频功能,产生多种频率的时钟信号,满足不同外设的时钟需求。
  • 通过时钟系统提供的时钟分频器、预分频器等功能,进一步调整时钟频率,以适应不同的应用场景。
时钟系统在 STM32 的系统中扮演着关键的角色,它的稳定性和精度对整个系统的性能影响很大。
1、参考手册

STM32F4xx 中文参考手册.pdf 第 106 页
2、时钟源3种

a.可以使用三种不同的时钟源来驱动系统时钟 (SYSCLK),CPU 运行的频率为 168MHz:
●HSI 振荡器时钟(16MHz),也就是高速内部时钟,一般来说很少用,因为精度没有外部高速时钟那么高。
● HSE 振荡器时钟,也就是高速外部时钟,GECM4 开发板 8MHz。
● 主 PLL (PLL) 时钟
b.器件具有以下两个次级时钟源:
● 32 kHz 低速内部 RC (LSI RC),该 RC 用于驱动独立看门狗,也可选择提供给 RTC 用于停机/待机模式下的自动唤醒。
●32.768 kHz 低速外部晶振(LSE 晶振),用于驱动 RTC 时钟 (RTCCLK)对于每个时钟源来说,在未使用时都可单独打开或者关闭,以降低功耗。
3、时钟树

时钟树就是关注时钟源和时钟的流向,嵌入式系统中的模块和外设工作都以时钟为基准。有了时钟树,就有了时钟域。嵌入式中除了内核,还有各个单元,每个单元工作在不同的时钟频率下,给每个单元提供不同的时钟。
实际应用中根据需要配置外设的时钟控制开关,选择需要的时钟频率,并可关闭不用外设时钟。
1.png

stm32对每个外设的时钟都设置了开关,让用户可以精确地控制,关闭不需要的设备,达到节省供电的目的。如果不用的就完全关闭,尽可能降低芯片功耗,以下以GPIO作为举例

  • 降低功耗:STM32设计允许用户精确控制各个外设的电源管理,包括时钟的开关。当不使用某个外设时,通过关闭其时钟可以显著减少功耗。因此,GPIO的时钟默认是关闭的,以节省电力。
  • 激活功能:使能GPIO的时钟是激活其功能的第一步。没有时钟,GPIO的寄存器无法读写,从而无法配置GPIO的工作模式(如输入、输出、上拉、下拉等)或读取输入状态。
  • 同步操作:硬件时钟为GPIO提供了必要的时序和同步信号,确保GPIO的操作与系统其他部分协调一致。这对于维持数据的稳定传输和处理非常重要。
  • 支持高级功能:对于某些高级功能,如复用功能(GPIO复用为其他外设功能)、中断功能等,可能还需要额外使能AFIO(Alternate Function Input Output)的时钟。这是因为这些功能涉及到更复杂的内部信号路由和管理。
实际上,在这里面还涉及到一个时钟门控技术,而这又涉及到同步电路,我们都知道(默认你们都知道)在同步电路中总是有一个时钟控制。这里就不赘述了,回去翻翻一本叫《数字电子技术基础》的书,可以找到答案。
4. 时钟详解

查看
HSE时钟

HSE:High Speed External Clock signal,即高速的外部时钟。
来源:有源晶振(1-50M)、无源晶振(4-26M)
控制:RCC_CR 时钟控制寄存器的位16:HSEON控制
HSI时钟

HSI:Low Speed Internal Clock signal,即高速的内部时钟。
来源:芯片内部,大小为16M,当HSE故障时,系统时钟会自动切换到HSI,直到HSE启动成功。
控制: RCC_CR 时钟控制寄存器的位0:HSION控制
锁相环时钟

锁相环时钟:PLLCLK
来源:HSI、HSE。由PLLSRC位配置。(0HSI 1HSE)
HSE或者HSI先经过一个分频因子M进行分频,然后再经过一个倍频因子N,然后再经过一个分频因子P,最后成为锁相环时钟PLLCLK = (HSE/M) * N / P = 25/25 * 336 / 2 = 168M
控制: RCC_PLLCFGR :RCC PLL 配置寄存器
PLL48CK:USB_FS(USB全速接口)、RANG(随机发发生器)、SDIO提供时钟
2.png

HSI精度不高.
PLLM 分频因子
PLLN 倍频
PLLP分配
系统时钟

缩写:SYSCLK,最高为168M。
来源:HSI、HSE,PLLCLK。
控制: RCC_CFGR 时钟配置寄存器的SW位( 一般配置为10 选择PLL作为系统时钟)
3.png

HCLK时钟

HCLK:AHB高速总线时钟,最高为168M。为AHB总线的外设提供时钟、为Cortex系统定时器提供时钟(SysTick, 一般会8分频)、为内核提供时钟(FCLK 自由运行时钟)。
AHB为advanced high-performance bus。
来源:系统时钟分频得到。
控制: RCC_CFGR 时钟配置寄存器的HPRE位
PCLK1时钟

PCLK1:APB1低速总线时钟,最高为42M,为APB1总线的外设提供时钟。
来源:HCLK分频得到,通常配置为4分频
控制: RCC_CFGR 时钟配置寄存器的PPRE1位
PCLK2时钟

PCLK1:APB高速总线时钟,最高为84M,为APB2总线的外设提供时钟。
来源:HCLK分频得到,通常配置为2分频。
控制: RCC_CFGR 时钟配置寄存器的PPRE2位
RTC时钟

RTC:为芯片内部的RTC提供时钟。
来源:HSE_RTC(HSE分频得到)、LSE(外部32.768KHZ的晶体提供)、LSI(32KHZ)。
控制: RCC备份域控制寄存器RCC_BDCR:RTCSEL位控制
独立看门狗时钟:

IWDGCLK,由LSI提供
4.png

I2S时钟:

由外部的引脚I2S_CKIN或者PLLI2SCLK提供。
以太网PHY时钟:

407没有集成PHY,只能外接PHY芯片,比如LAN8720,那PHY时钟就由外部的PHY芯片提供,大小为50M。
USB PHY时钟:

407的USB没有集成PHY,要想实现USB高速传输,只能外接PHY芯片,比如USB33000。那USB PHY时钟就由外部的PHY芯片提供。
MCO时钟输出

MCO:把控制器的时钟通过外部的引脚输出,可以外外部的设备提供时钟。MCO1为PA8,MCO2为PC9。
控制: RCC_CFGR 时钟配置寄存器的MCOX的PREx位
5.png

系统时钟配置函数SetSysClock()

打开汇编文件
6.png

找到时钟初始化
7.png

8.png

设置系统时钟
将下面这一段拷贝出, 进行裁剪:
  1. /**
  2.   * @brief  Configures the System clock source, PLL Multiplier and Divider factors,
  3.   *         AHB/APBx prescalers and Flash settings
  4.   * @Note   This function should be called only once the RCC clock configuration  
  5.   *         is reset to the default reset state (done in SystemInit() function).   
  6.   * @param  None
  7.   * @retval None
  8.   */
  9. static void SetSysClock(void)
  10. {
  11. #if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx) || defined (STM32F401xx)
  12. /******************************************************************************/
  13. /*            PLL (clocked by HSE) used as System clock source                */
  14. /******************************************************************************/
  15.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  16.   
  17.   /* Enable HSE */
  18.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
  19.   /* Wait till HSE is ready and if Time out is reached exit */
  20.   do
  21.   {
  22.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  23.     StartUpCounter++;
  24.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
  25.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  26.   {
  27.     HSEStatus = (uint32_t)0x01;
  28.   }
  29.   else
  30.   {
  31.     HSEStatus = (uint32_t)0x00;
  32.   }
  33.   if (HSEStatus == (uint32_t)0x01)
  34.   {
  35.     /* Select regulator voltage output Scale 1 mode */
  36.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
  37.     PWR->CR |= PWR_CR_VOS;
  38.     /* HCLK = SYSCLK / 1*/
  39.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
  40. #if defined (STM32F40_41xxx) || defined (STM32F427_437xx) || defined (STM32F429_439xx)      
  41.     /* PCLK2 = HCLK / 2*/
  42.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
  43.    
  44.     /* PCLK1 = HCLK / 4*/
  45.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
  46. #endif /* STM32F40_41xxx || STM32F427_437x || STM32F429_439xx */
  47. #if defined (STM32F401xx)
  48.     /* PCLK2 = HCLK / 2*/
  49.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
  50.    
  51.     /* PCLK1 = HCLK / 4*/
  52.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
  53. #endif /* STM32F401xx */
  54.    
  55.     /* Configure the main PLL */
  56.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
  57.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
  58.     /* Enable the main PLL */
  59.     RCC->CR |= RCC_CR_PLLON;
  60.     /* Wait till the main PLL is ready */
  61.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  62.     {
  63.     }
  64.    
  65. #if defined (STM32F427_437xx) || defined (STM32F429_439xx)
  66.     /* Enable the Over-drive to extend the clock frequency to 180 Mhz */
  67.     PWR->CR |= PWR_CR_ODEN;
  68.     while((PWR->CSR & PWR_CSR_ODRDY) == 0)
  69.     {
  70.     }
  71.     PWR->CR |= PWR_CR_ODSWEN;
  72.     while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
  73.     {
  74.     }      
  75.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  76.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
  77. #endif /* STM32F427_437x || STM32F429_439xx  */
  78. #if defined (STM32F40_41xxx)     
  79.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  80.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
  81. #endif /* STM32F40_41xxx  */
  82. #if defined (STM32F401xx)
  83.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  84.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
  85. #endif /* STM32F401xx */
  86.     /* Select the main PLL as system clock source */
  87.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  88.     RCC->CFGR |= RCC_CFGR_SW_PLL;
  89.     /* Wait till the main PLL is used as system clock source */
  90.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
  91.     {
  92.     }
  93.   }
  94.   else
  95.   { /* If HSE fails to start-up, the application will have wrong clock
  96.          configuration. User can add here some code to deal with this error */
  97.   }
  98. #elif defined (STM32F411xE)
  99. #if defined (USE_HSE_BYPASS)
  100. /******************************************************************************/
  101. /*            PLL (clocked by HSE) used as System clock source                */
  102. /******************************************************************************/
  103.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  104.   
  105.   /* Enable HSE and HSE BYPASS */
  106.   RCC->CR |= ((uint32_t)RCC_CR_HSEON | RCC_CR_HSEBYP);
  107.   /* Wait till HSE is ready and if Time out is reached exit */
  108.   do
  109.   {
  110.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  111.     StartUpCounter++;
  112.   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
  113.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  114.   {
  115.     HSEStatus = (uint32_t)0x01;
  116.   }
  117.   else
  118.   {
  119.     HSEStatus = (uint32_t)0x00;
  120.   }
  121.   if (HSEStatus == (uint32_t)0x01)
  122.   {
  123.     /* Select regulator voltage output Scale 1 mode */
  124.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
  125.     PWR->CR |= PWR_CR_VOS;
  126.     /* HCLK = SYSCLK / 1*/
  127.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
  128.     /* PCLK2 = HCLK / 2*/
  129.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
  130.    
  131.     /* PCLK1 = HCLK / 4*/
  132.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
  133.     /* Configure the main PLL */
  134.     RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
  135.                    (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
  136.    
  137.     /* Enable the main PLL */
  138.     RCC->CR |= RCC_CR_PLLON;
  139.     /* Wait till the main PLL is ready */
  140.     while((RCC->CR & RCC_CR_PLLRDY) == 0)
  141.     {
  142.     }
  143.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  144.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
  145.     /* Select the main PLL as system clock source */
  146.     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  147.     RCC->CFGR |= RCC_CFGR_SW_PLL;
  148.     /* Wait till the main PLL is used as system clock source */
  149.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
  150.     {
  151.     }
  152.   }
  153.   else
  154.   { /* If HSE fails to start-up, the application will have wrong clock
  155.          configuration. User can add here some code to deal with this error */
  156.   }
  157. #else /* HSI will be used as PLL clock source */
  158.   /* Select regulator voltage output Scale 1 mode */
  159.   RCC->APB1ENR |= RCC_APB1ENR_PWREN;
  160.   PWR->CR |= PWR_CR_VOS;
  161.   
  162.   /* HCLK = SYSCLK / 1*/
  163.   RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
  164.   
  165.   /* PCLK2 = HCLK / 2*/
  166.   RCC->CFGR |= RCC_CFGR_PPRE2_DIV1;
  167.   
  168.   /* PCLK1 = HCLK / 4*/
  169.   RCC->CFGR |= RCC_CFGR_PPRE1_DIV2;
  170.   
  171.   /* Configure the main PLL */
  172.   RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) | (PLL_Q << 24);
  173.   
  174.   /* Enable the main PLL */
  175.   RCC->CR |= RCC_CR_PLLON;
  176.   
  177.   /* Wait till the main PLL is ready */
  178.   while((RCC->CR & RCC_CR_PLLRDY) == 0)
  179.   {
  180.   }
  181.   
  182.   /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  183.   FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_2WS;
  184.   
  185.   /* Select the main PLL as system clock source */
  186.   RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
  187.   RCC->CFGR |= RCC_CFGR_SW_PLL;
  188.   
  189.   /* Wait till the main PLL is used as system clock source */
  190.   while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
  191.   {
  192.   }
  193. #endif /* USE_HSE_BYPASS */  
  194. #endif /* STM32F40_41xxx || STM32F427_437xx || STM32F429_439xx || STM32F401xx */  
  195. }
复制代码
启动外部晶振, HSE高速的外部时钟
9.png

10.png

配置预分频器
RCC_CFGR
11.png
  1.     /* HCLK = SYSCLK / 1 AHB高速总线的分配因子 1分频*/
  2.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
  3.     /* PCLK2 = HCLK / 2 APB2总线的分频因子 2分频*/
  4.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;   
  5.     /* PCLK1 = HCLK / 4 APB1总线的分频因子 4分频*/
  6.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
复制代码
12.png

13.png

注释掉系统默认的系统时钟汇编代码, 系统默认使用HSI 16 MHz, 我们可以自定义的配置系统时钟函数
14.png

15.png
  1. #include "bsp_clkconfig.h"
  2. void User_SetSysClock(void)
  3. {
  4.   /******************************************************************************/
  5.   /*            PLL (clocked by HSE) used as System clock source                */
  6.   /******************************************************************************/
  7.   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  8.   /* 复位RCC的所有寄存器 */
  9.   RCC_DeInit();
  10.   /* Enable HSE */
  11.   /* 使能HSE 《中文参考手册 6.3.1 RCC时钟控制寄存器》 ((uint32_t)0x00010000) */
  12.   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
  13.   /* Wait till HSE is ready and if Time out is reached exit */
  14.   /* 等待HSE启动稳定,如果超时则退出  由RCC_CR HSERDY控制*/
  15.   do
  16.   {
  17.     HSEStatus = RCC->CR & RCC_CR_HSERDY;
  18.     StartUpCounter++;
  19.   } while ((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
  20.   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  21.   {
  22.     HSEStatus = (uint32_t)0x01;
  23.   }
  24.   else
  25.   {
  26.     HSEStatus = (uint32_t)0x00;
  27.   }
  28.   /* HSE 启动成功 */
  29.   if (HSEStatus == (uint32_t)0x01)
  30.   {
  31.     /* Select regulator voltage output Scale 1 mode */
  32.     /* 选择电压调节器的模式为1  和电源控制器PWR有关 PWR_CR寄存器VOS位, 实现功耗平衡*/
  33.     RCC->APB1ENR |= RCC_APB1ENR_PWREN;
  34.     PWR->CR |= PWR_CR_VOS;
  35.     /* HCLK = SYSCLK / 1 AHB高速总线的分频因子*/
  36.     RCC->CFGR |= RCC_CFGR_HPRE_DIV1;
  37.     /* PCLK2 = HCLK / 2 APB2总线的分频因子*/
  38.     RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
  39.     /* PCLK1 = HCLK / 4 APB1总线的分频因子*/
  40.     RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
  41.     /**
  42.      * Configure the main PLL
  43.      * 配置主PLL
  44.      * PLL_M分频因子应该和外部时钟HSE一致, 分频后为1
  45.      * 因此N为336 P为2(/2得到168M), Q是7(得到48Mhz)
  46.      * RCC_PLLCFGR_PLLSRC_HSE 选择锁相环时钟来源, 这里选择HSE 8M
  47.      *
  48.      * 可以设置N最大为432 《中文参考手册 6.3.2 》, 可超频到216M, 原168M
  49.      */
  50.     //    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
  51.     //                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
  52.     RCC->PLLCFGR = 25 | (336 << 6) | (((2 >> 1) - 1) << 16) |
  53.                    (RCC_PLLCFGR_PLLSRC_HSE) | (7 << 24);
  54.     /* Enable the main PLL */
  55.     /* 使能主PLL  因为使能后无法修改! */
  56.     RCC->CR |= RCC_CR_PLLON;
  57.     /* Wait till the main PLL is ready */
  58.     /* 等待主PLL稳定 */
  59.     while ((RCC->CR & RCC_CR_PLLRDY) == 0)
  60.     {
  61.     }
  62.     /* Configure Flash prefetch, Instruction cache, Data cache and wait state */
  63.     /* 配置FLASH预取指(将指令提前准备好),指令缓存,数据缓存,等待周期(速度越快等待周期越长, 见中文参考手册3.8.1)
  64.      * 配置flash外设的acr寄存器
  65.      */
  66.     FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS;
  67.     /* Select the main PLL as system clock source */
  68.     /* 选择主PLL时钟作为系统时钟 */
  69.     RCC->CFGR &= (uint32_t)((uint32_t) ~(RCC_CFGR_SW));
  70.     RCC->CFGR |= RCC_CFGR_SW_PLL;
  71.     /* Wait till the main PLL is used as system clock source */
  72.     /* 确保主PLL时钟选为系统时钟, 若设置成功, 系统会硬件置1 《中文参考手册 6.3.3 》*/
  73.     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL)
  74.       ;
  75.     {
  76.     }
  77.   }
  78.   else
  79.   { /* If HSE fails to start-up, the application will have wrong clock
  80.          configuration. User can add here some code to deal with this error */
  81.     /* HSE 启动失败,在这里添加启动失败的处理代码 */
  82.   }
  83. }
复制代码
若使用系统自带的系统配置文件, 需要做HSE修改, 默认是25M
16.png

系统时钟配置流程

二、PLL

2.1 概述

PLL(Phase Locked Loop): 为锁相回路或锁相环,用来统一整合时钟信号,使高频器件正常工作,如内存的存取资料等。
PLL基于振荡器中的反馈技术,许多电子设备要正常工作,通常需要外部的输入信号与内部的振荡信号同步。
一般的晶振由于工艺与成本原因,做不到很高的频率,而在需要高频应用时,由相应的器件VCO,实现转成高频,但并不稳定,故利用锁相环路就可以实现稳定且高频的时钟信号。
2.2 基本组成

锁相环路是一种反馈控制电路,简称锁相环(PLL,Phase-Locked Loop)。锁相环的特点是:利用外部输入的参考信号控制环路内部振荡信号的频率和相位。因锁相环可以实现输出信号频率对输入信号频率的自动跟踪,所以锁相环通常用于闭环跟踪电路。
锁相环在工作的过程中,当输出信号的频率与输入信号的频率相等时,输出电压与输入电压保持固定的相位差值,即输出电压与输入电压的相位被锁住,这就是锁相环名称的由来。锁相环通常由鉴相器(PD,Phase Detector)、环路滤波器(LF,Loop Filter)和压控振荡器(VCO,Voltage Controlled Oscillator)三部分组成。
锁相环的工作原理是检测输入信号和输出信号的相位差,并将检测出的相位差信号通过鉴相器转换成电压信号输出,经低通滤波器滤波后形成压控振荡器的控制电压,对振荡器输出信号的频率实施控制,再通过反馈通路把振荡器输出信号的频率、相位反馈到鉴相器。
锁相环在工作过程中,当输出信号的频率成比例地反映输入信号的频率时,输出电压与输入电压保持固定的相位差值,这样输出电压与输入电压的相位就被锁住了。
17.png

2.3 类比说明

我们刚开始学车的时候,在道路上开车,眼睛就好像一个鉴相器,负责发现车行驶的方向(反馈)和前方的路(输入)是否有差别,把差别输入大脑进行判断,然后指挥双手旋转方向盘,旋转方向盘的动作转换成车的行驶方向,如下图所示。
18.png

我们通过这么一个闭环过程不断地调节方向盘,保证车行驶在正道上。
2.3 相位差[拓展]

两个频率相同的交流电相位的差叫做相位差,或者叫做相差,又称“相角差”、“相差”、“周相差”或“位相差”。两个作周期变化的物理量的相之间的差值。它为正值时称前者超前于后者,为负值时则滞后于后者。它为零或π的偶数倍时,两物理量同相;为π的奇数倍时则称反相。
这两个频率相同的交流电,可以是两个交流电流,可以是两个交流电压,可以是两个交流电动势,也可以是这三种量中的任何两个。两个同频率正弦量的相位差就等于初相之差。是一个不随时间变化的常数。也可以是一个元件上的电流与电压的相位变化。任意一个正弦量y = Asin(wt+ j0)的相位为(wt+ j0),两个同频率正弦量的相位差(与时间t无关)。设第一个正弦量的初相为 j01,第二个正弦量的初相为 j02,则这两个正弦量的相位差为j12 = j01 - j02。
19.png

2.4 PLL配置参数
20.png

不同的芯片,倍频(频率翻倍)公式是不一样的,需要查询芯片手册!
三、SystemInit系统初始化函数

1.其实第一个执行的文件是汇编文件


  • 栈的初始化,提供函数调用的时候进行现场保护和现场恢复
  • 堆的初始化,为申请内存提供空间,调用malloc
  • 执行Reset_Handler,意思说上电复位后执行的动作
  • 执行SystemInit函数
  • 跳转到main函数
2.初始化Flash接口,更新PLL系统频率
  1. /**
  2.   * @brief  Setup the microcontroller system
  3.   *         Initialize the Embedded Flash Interface, the PLL and update the
  4.   *         SystemFrequency variable.
  5.   * @param  None
  6.   * @retval None
  7.   */
  8. void SystemInit(void)
  9. {
  10.     ................
  11.         /* Configure the System clock source, PLL Multiplier and Divider factors,
  12.      AHB/APBx prescalers and Flash settings ----------------------------------*/
  13.         SetSysClock();
  14.     ................
  15. }
复制代码
3.调用SetSysClock函数设置PLL时钟,然后进行分频
  1. /**
  2.   * @brief  Configures the System clock source, PLL Multiplier and Divider factors,
  3.   *         AHB/APBx prescalers and Flash settings
  4.   * @Note   This function should be called only once the RCC clock configuration  
  5.   *         is reset to the default reset state (done in SystemInit() function).   
  6.   * @param  None
  7.   * @retval None
  8.   */
  9. static void SetSysClock(void)
  10. {
  11.    .....................
  12.        /* Configure the main PLL */
  13.        RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
  14.        (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
  15.    .....................
  16. }
复制代码
2.选择HSI作为系统时钟源
  1. /* PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N */
  2. #define PLL_M      8     //(记得修改为8)
  3. /* USB OTG FS, SDIO and RNG Clock =  PLL_VCO / PLLQ */
  4. #define PLL_Q      7
  5. #if defined (STM32F40_41xxx)
  6. #define PLL_N      336
  7. /* SYSCLK = PLL_VCO / PLL_P */
  8. #define PLL_P      2
  9. #endif /* STM32F40_41xxx */
复制代码
3.选择HSE作为系统时钟源
  1. *=============================================================================
  2. *=============================================================================
  3. *                    Supported STM32F40xxx/41xxx devices
  4. *-----------------------------------------------------------------------------
  5. *        System Clock source                    | PLL (HSE)
  6. *-----------------------------------------------------------------------------
  7. *        SYSCLK(Hz)                             | 168000000
  8. *-----------------------------------------------------------------------------
  9. *        HCLK(Hz)                               | 168000000
  10. *-----------------------------------------------------------------------------
  11. *        AHB Prescaler                          | 1
  12. *-----------------------------------------------------------------------------
  13. *        APB1 Prescaler                         | 4
  14. *-----------------------------------------------------------------------------
  15. *        APB2 Prescaler                         | 2
  16. *-----------------------------------------------------------------------------
  17. *        HSE Frequency(Hz)                      | 25000000   粤嵌开发板外部晶振是8MHz,我们要将25MHz修改为8MHz
  18. *-----------------------------------------------------------------------------
  19. *        PLL_M                                  | 25
  20. *-----------------------------------------------------------------------------
  21. *        PLL_N                                  | 336
  22. *-----------------------------------------------------------------------------
  23. *        PLL_P                                  | 2
  24. *-----------------------------------------------------------------------------
  25. *        PLL_Q                                  | 7
  26. *-----------------------------------------------------------------------------
  27. *        PLLI2S_N                               | NA
  28. *-----------------------------------------------------------------------------
  29. *        PLLI2S_R                               | NA
  30. *-----------------------------------------------------------------------------
  31. *        I2S input clock                        | NA
  32. *-----------------------------------------------------------------------------
  33. *        VDD(V)                                 | 3.3
  34. *-----------------------------------------------------------------------------
  35. *        Main regulator output voltage          | Scale1 mode
  36. *-----------------------------------------------------------------------------
  37. *        Flash Latency(WS)                      | 5
  38. *-----------------------------------------------------------------------------
  39. *        Prefetch Buffer                        | ON
  40. *-----------------------------------------------------------------------------
  41. *        Instruction cache                      | ON
  42. *-----------------------------------------------------------------------------
  43. *        Data cache                             | ON
  44. *-----------------------------------------------------------------------------
  45. *        Require 48MHz for USB OTG FS,          | Disabled
  46. *        SDIO and RNG clock                     |
  47. *-----------------------------------------------------------------------------
  48. *=============================================================================
复制代码
五、应用场景
调节 CPU 的运行频率,来控制系统的性能与功耗。比较典型的例子就是说手机/笔记本电脑都有高性能模式、平衡模式、低性能模式。
21.png

22.png

六、寄存器边界地址
详见《STM32F4xx中文参考手册》的P52 ~ P54页,部分展示如下:
23.png

参考文章


  • 温子祺笔记
  • 野火STM32库开发实战指南

来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
您需要登录后才可以回帖 登录 | 立即注册