The STM32 SystemInit () and SetSysClock () function Detailed - Study Notes (4)

According to the article content organize wildfire tutorial, just learning record.
Wildfire tutorial contents SetSysClock () function to explain a bit, learn how to check the manual to see how.
I'm going to start analyzing from SystemInit (), after all, it is a C function is called, a good understanding of what to be a record.

Boards: wildfire STM32F429- Challenger V2
official version of the firmware library: STM32F4xx_DSP_StdPeriph_Lib_V1.8.0


Function SystemInit ()

This function is defined in system_stm32f4xx.c file. The first is a C language function reset function in the startup file assembly call.

/**
  * 设置微控制器系统
  * 初始化嵌入式Flash接口,锁相环和更新
  * 系统频率变量
  */
void SystemInit(void)
{
  /* 第一部分 浮点运算单元设置(我的没有启用这个宏)--> */
  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
    /* 把 CP10 和 CP11 全部置为1,用于启用该协处理器 */
    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  
  #endif
  /* <--第一部分 */
  
  /* 第二部分 将RCC时钟配置重置为默认重置状态--> */
  
  /* 将RCC的时钟控制寄存器的HSION(即第0位)置为1 */
  /* 位 0 HSION:内部高速时钟使能 (Internal high-speed clock enable) */
  /* 0: HSI 振荡器关闭, 1: HSI 振荡器打开 */
  RCC->CR |= (uint32_t)0x00000001;

  /* 将时钟配置寄存器全部置为0 */
  RCC->CFGR = 0x00000000;
  
  /* 将RCC的时钟控制寄存器的HSEON(即第24位)置为0 */
  /* 位 24 PLLON:主 PLL (PLL) 使能 (Main PLL (PLL) enable) */
  /* 0: PLL 关闭, 1: PLL 开启 */
  /* 将RCC的时钟控制寄存器的CSSON(即第19位)置为0 */
  /* 位 19 CSSON:时钟安全系统使能 (Clock security system enable) */
  /* 0:时钟安全系统关闭(时钟监测器关闭) */
  /* 1:时钟安全系统打开(如果 HSE 振荡器稳定,则时钟监测器打开;如果不稳定,则关闭) */
  /* 将RCC的时钟控制寄存器的HSEON(即第16位)置为0 */
  /* HSEON: HSE 时钟使能 (HSE clock enable) */
  /* 0: HSE 振荡器关闭, 1: HSE 振荡器打开 */
  RCC->CR &= (uint32_t)0xFEF6FFFF;

  /* 重置RCC的PLL配置寄存器, 根据《STM32F4xx中文参考手册》给出的复位值为0x24003010 */
  RCC->PLLCFGR = 0x24003010;

  /* 将RCC的时钟控制寄存器的HSEBYP(即第18位)置为0 */
  /* 位 18 HSEBYP: HSE 时钟旁路 (HSE clock bypass) */
  /* 0:不旁路 HSE 振荡器, 1:外部时钟旁路 HSE 振荡器 */
  RCC->CR &= (uint32_t)0xFFFBFFFF;

  /* 将RCC时钟中断寄存器全部置为0, 关闭所有RCC时钟中断 */
  RCC->CIR = 0x00000000;

  /* <--第二部分 */
  
  /* 第三部分 初始化外部SRAM或SDRAM(我的没有启用这个宏)--> */
#if defined(DATA_IN_ExtSRAM) || defined(DATA_IN_ExtSDRAM)
  SystemInit_ExtMemCtl(); 
#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
  /* <--第三部分 浮点运算单元设置 */

  /* 第四部分 配置系统时钟源、锁相环乘法和除法因子、AHB/APBx预调器和Flash设置--> */
  SetSysClock();
  /* <--第四部分 */
  
  /* 第五部分 配置向量表位置以及偏移地址--> */
  /* 我没有定义VECT_TAB_SRAM这个宏,所以向量表配置在了FLASH */
#ifdef VECT_TAB_SRAM
  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM */
#else  
  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH */
#endif
  /* <--第五部分 */
}

Additional information:

Part I: can view the "STM32F4xx-Cortex_-M4 Core Reference Manual" View FPU portion CPACR register parameter configuration details.
Here Insert Picture Description
The second part: you can view the "STM32F4xx Chinese Reference Manual" to view the RCC register parameters configuration details.
Part III: SystemInit_ExtMemCtl () function is defined where I was not found, and convenient to have known of the brothers, then you provide some.
Part IV: Configuring the system clock, which is the focus initialized. He explained below.
Part V: This configuration is the vector table address field. You can view the "STM32F4xx-Cortex_-M4 Core Reference Manual" View SCB portion VTOR register parameter configuration details.
Here Insert Picture Description
The SRAM_BASE , FLASH_BASE , VECT_TAB_OFFSET are defined in system_stm32f4xx.c in.


Function SetSysClock ()

这个函数是用来初始化系统时钟的,看名字也知道。这个函数定义在system_stm32f4xx.c 中。
因为使用的是STM32F429 的芯片,所以除了STM32F429_439xx 之外的宏就忽略了。
以下代码只留下STM32F429_439xx宏,其他用于兼容性适配的宏全删了,方便阅读。

static void SetSysClock(void)
{
#if defined(STM32F429_439xx)
/******************************************************************************/
/*            PLL (clocked by HSE) used as System clock source                */
/******************************************************************************/
  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
  
  /* 使能HSE, RCC_CR_HSEON 为 0x00010000,定义在 stm32f4xx.h */
  /* 将RCC的时钟控制寄存器的HSEON(即第16位)置为1 */
  /* HSEON: HSE 时钟使能 (HSE clock enable) */
  /* 0: HSE 振荡器关闭, 1: HSE 振荡器打开 */
  RCC->CR |= ((uint32_t)RCC_CR_HSEON);
 
  /* 等待HSE准备就绪或者超时跳出, RCC_CR_HSERDY 为 0x00020000,定义在 stm32f4xx.h */
  /* 位 17 HSERDY: HSE 时钟就绪标志, 就绪后硬件会置为 1,用以指示 HSE 振荡器已稳定 */
  /* 0: HSE 振荡器未就绪, 1: HSE 振荡器已就绪 */
  do
  {
    HSEStatus = RCC->CR & RCC_CR_HSERDY;
    StartUpCounter++;
  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

  /* 这里只是将状态记录到局部变量 HSEStatus,(RESET=0) */
  if ((RCC->CR & RCC_CR_HSERDY) != RESET)
  {
    HSEStatus = (uint32_t)0x01;
  }
  else
  {
    HSEStatus = (uint32_t)0x00;
  }
  
  if (HSEStatus == (uint32_t)0x01)
  {

    /* 使能电源接口时钟, 将RCC的APB1ENR寄存器的PWREN位设置位1 */
    /* RCC_APB1ENR_PWREN 为 0x10000000,定义在 stm32f4xx.h */
    /* 位 28 PWREN: 电源接口时钟使能 (Power interface clock enable) */
    /* 0:禁止电源接口时钟, 1:使能电源接口时钟 */
    RCC->APB1ENR |= RCC_APB1ENR_PWREN;
    /* 选择电压调节器输出为模式1 */
    /* PWR_CR_VOS 为 0x0000C000,定义在 stm32f4xx.h */
    /* 位 15:14 VOS:电压调节器模式 */
    /* 00: Reserved (Scale 3 mode selected), 01: Scale 3 mode */
    /* 10: Scale 2 mode, 11: Scale 1 mode (reset value) */
    PWR->CR |= PWR_CR_VOS;

    /* 设置HCLK(即AHB总线时钟)的AHB预分频器为不分频,将RCC的CFGR寄存器的HPRE位设置为0000 */
    /* RCC_CFGR_HPRE_DIV1 为 0x00000000 */
    /* 位 7:4 HPRE: AHB 预分频器 (AHB prescaler) */
    /* 0xxx:系统时钟不分频, 1000:系统时钟 2 分频 */
    /* 1001:系统时钟 4 分频, 1010:系统时钟 8 分频 */
    /* 1011:系统时钟 16 分频, 1100:系统时钟 64 分频 */
    /* 1101:系统时钟 128 分频, 1110:系统时钟 256 分频 */
    /* 1111:系统时钟 512 分频 */
    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;

#if defined(STM32F429_439xx)  /* 删除了其他宏 */
    /* 设置PCLK2(即APB2总线时钟)的APB高速预分频器(APB2)为2分频,将RCC的CFGR寄存器的PPRE2位设置为100 */
    /* RCC_CFGR_PPRE2_DIV2 为 0x00008000 */
    /* 位 15:13 PPRE2: APB 高速预分频器 (APB2) (APB high-speed prescaler (APB2)) */
    /* 0xx: AHB 时钟不分频, 100: AHB 时钟 2 分频 */
    /* 101: AHB 时钟 4 分频, 110: AHB 时钟 8 分频 */
    /* 111: AHB 时钟 16 分频 */
    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;
    
    /* PCLK1 = HCLK / 4*/
        /* 设置PCLK1(即APB1总线时钟)的APB低速预分频器(APB1)为4分频,将RCC的CFGR寄存器的PPRE1位设置为101 */
    /* RCC_CFGR_PPRE1_DIV4 为 0x00001400 */
    /* 位 12:10 PPRE1: APB 低速预分频器 (APB1) (APB Low speed prescaler (APB1)) */
    /* 0xx: AHB 时钟不分频, 100: AHB 时钟 2 分频 */
    /* 101: AHB 时钟 4 分频, 110: AHB 时钟 8 分频 */
    /* 111: AHB 时钟 16 分频 */
    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;
#endif /* STM32F429_439xx */

#if defined(STM32F429_439xx)
    /* 配置主PLL(即锁相环倍频因子),即配置RCC的PLLCFGR寄存器 */
    /* PLL_M = 25, PLL_N  = 360, PLL_P = 2, PLL_Q = 7 */
    /* RCC_PLLCFGR_PLLSRC_HSE 为 0x00400000 */
    /* PLL_M是位 5:0 PLLM: 主 PLL (PLL) 和音频 PLL (PLLI2S) 输入时钟的分频系数 */
    /* PLL_N是位 14:6 PLLN: 适用于 VCO 的主 PLL (PLL) 倍频系数 */
    /* PLL_P是位 17:16 PLLP: 适用于主系统时钟的主 PLL (PLL) 分频系数 */
    /* PLL_Q是位 27:24 PLLQ: 主 PLL (PLL) 分频系数,适用于 USB OTG FS、 SDIO 和随机数发生器时钟 */
    /* RCC_PLLCFGR_PLLSRC_HSE是位 22 PLLSRC: 主 PLL(PLL) 和音频 PLL (PLLI2S) 输入时钟源 */
    /* 0:选择 HSI 时钟作为 PLL 和 PLLI2S 时钟输入 */
    /* 1:选择 HSE 振荡器时钟作为 PLL 和 PLLI2S 时钟输入 */
    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |
                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);
#endif /* STM32F429_439xx */

    /* 使能主锁相环,即配置RCC的CR寄存器的PLLON位为1 */
    /* RCC_CR_PLLON 为 0x01000000 */
    /* 位 24 PLLON:主 PLL (PLL) 使能 (Main PLL (PLL) enable) */
    /* 0: PLL 关闭, 1: PLL 开启 */
    RCC->CR |= RCC_CR_PLLON;
    
    /* 等待主锁相环准备就绪,不断读取RCC的CR寄存器的PLLRDY位是否位1 */
    /* RCC_CR_PLLRDY 为 0x02000000 */
    /* 位 25 PLLRDY:主 PLL (PLL) 时钟就绪标志,就绪后硬件会置为1*/
    /* 0: PLL 未锁定, 1: PLL 已锁定 */
    while((RCC->CR & RCC_CR_PLLRDY) == 0)
    {
    }
    
#if defined(STM32F429_439xx)
    /* 使能Over-drive以达到180 Mhz的频率,及等待Over-drive使能就绪 */
    /* PWR_CR_ODEN 为 0x00010000 */
    /* PWR_CSR_ODRDY 为 0x00010000 */
    /* Bit 16 ODEN: Over-drive enable */
    /* 0: Over-drive disabled, 1: Over-drive enabled */
    /* Bit 16 ODRDY: Over-drive mode ready */
    /* 0: Over-drive mode not ready, 1: Over-drive mode ready */
    PWR->CR |= PWR_CR_ODEN;
    while((PWR->CSR & PWR_CSR_ODRDY) == 0)
    {
    }

    /* Over-drive开关使能,及等待Over-drive开关就绪 */
    /* PWR_CR_ODSWEN 为 0x00020000 */
    /* PWR_CSR_ODSWRDY 为 0x00020000 */
    /* Bit 17 ODSWEN: Over-drive switching enabled */
    /* 0: Over-drive switching disabled, 1: Over-drive switching enabled */
    /* Bit 17 ODSWRDY: Over-drive mode switching ready */
    /* 0: Over-drive mode is not active */
    /* 1: Over-drive mode is active on digital area on 1.2 V domain */
    PWR->CR |= PWR_CR_ODSWEN;
    while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)
    {
    }      
    /* 配置Flash预取、指令缓存、数据缓存和等待状态 */
    /* FLASH_ACR_PRFTEN 为 0x00000100 */
    /* FLASH_ACR_ICEN 为 0x00000200 */
    /* FLASH_ACR_DCEN 为 0x00000400 */
    /* FLASH_ACR_LATENCY_5WS 为 0x00000005 */
    /* 位 8 PRFTEN: 预取使能 (Prefetch enable) */
    /* 0:关闭预取, 1:使能预取 */
    /* 位 9 ICEN: 指令缓存使能 (Instruction cache enable) */
    /* 0:关闭指令缓存, 1:使能指令缓存 */
    /* 位 10 DCEN: 数据缓存使能 (Data cache enable) */
    /* 0:关闭数据缓存, 1:使能数据缓存 */
    /* 位 2:0 LATENCY: 延迟 (Latency),这些位表示 CPU 时钟周期与 Flash 访问时间之比。 */
    /* 000:零等待周期, 001:一个等待周期, 010:两个等待周期 */
    /* 011:三个等待周期, 100:四个等待周期, 101:五个等待周期, 110:六个等待周期 */
    /* 111:七个等待周期 */
    FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;
#endif /* STM32F429_439xx */

    /* 选择PLL锁相环时钟为系统时钟源 */
    /* RCC_CFGR_SW 为 0x00000003,取反为 0xFFFFFFFC,将位 1:0 SW置为00 */
    /* RCC_CFGR_SW_PLL 为 0x00000002,将位 1:0 SW置为10 */
    /* 位 1:0 SW: 系统时钟切换 (System clock switch) */
    /* 00:选择 HSI 振荡器作为系统时钟, 01:选择 HSE 振荡器作为系统时钟 */
    /* 10:选择 PLL 作为系统时钟, 11:不允许 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= RCC_CFGR_SW_PLL;
    
    /* 等待主锁相环时钟切换为系统时钟源 */
    /* RCC_CFGR_SWS 为 0x00000002 */
    /* RCC_CFGR_SWS_PLL 为 0x00000008 */
    /* 位 3:2 SWS: 系统时钟切换状态 (System clock switch status),状态由硬件切换 */
    /* 00: HSI 振荡器用作系统时钟, 01: HSE 振荡器用作系统时钟 */
    /* 10: PLL 用作系统时钟, 11:不适用 */
    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);
    {
    }
  }
  else
  { 
    /* HSE启动失败应用层的时钟配置将时错误的,这里用户可以添加一些错误情况的处理代码。 */
  }

#if defined(USE_HSE_BYPASS) /* 如果使用外部有源时钟 */
/* 因为我这边使用的是外部无源时钟,所以以下代码省略 */
#endif /* USE_HSE_BYPASS */  
#endif /* STM32F429_439xx */  
}

附加说明

PWR->CR / PWR->CSR: 这个在 《STM32F4xx中文参考手册》 中没有找到,要找英文版的 《STM32Fxx英文参考手册》
Here Insert Picture Description
Here Insert Picture Description
Here Insert Picture Description
锁相环倍频因子: 查看时钟树的图可以知道外部晶振(25MHz)HSE作为锁相环的输入。
有三个注意要点:
1、HSE=25M,经过M=25分频后得到1M,再经过N=360倍频后得到360M,再经过P=2分频后得到锁相环时钟PLLCLK=180M。
2、基于第一种情况下,在锁相环中经过N=360倍频后得到360M,再经过Q=7分频后得到的外围时钟约为51.5M,而外围时钟要求要是48M,这样子设置就不合适了。
(解决:将N设置为336,PPLCLK=336/2=168M,外围时钟=336/7=48M)
3、锁相环中的分频因子R在本芯片中没有使用。
Here Insert Picture Description

Published 63 original articles · won praise 106 · views 220 000 +

Guess you like

Origin blog.csdn.net/lang523493505/article/details/104107174