system_stm32f10x.c文件解读

刚看到system_stm32f10x.c文件时,一堆的字母,看起来感觉头都大了,仔细读下来,其实包含的内容并不多,各位看官且看我一一道来。

首先,我们把注释去掉,函数收缩起来,就可以得到以下的视图:

1. 一堆的#define,这是给我们做选择的,用哪个,就把注释取消,不用的注释掉就好了

2.这个是根据上面定义的内容,进行的选择分支,我们一般是不动这里的

3.这个更好理解了,实现以上定义的功能函数。这样看就很清晰了,开机:1. 运行SystemInit();2. 如果有用外部SRAM的话,运行SystemInit_ExtMenCtl(),没有的话跳过;3. 再根据选择的频率运行对应的频率设置函数SetSysClockto**()。

注释内容翻译:

 * 1.  This file provides two functions and one global variable to be called from

  *     user application:

1.这个文件提供了两个函数和一个全局变量给用户应用调用)

  *      - SystemInit(): Setups the system clock (System clock source, PLL Multiplier

  *                      factors, AHB/APBx prescalers and Flash settings).

  *                      This function is called at startup just after reset and

  *                      before branch to main program. This call is made inside

  *                      the "startup_stm32f10x_xx.s" file.

SystemInit():设置系统时钟(系统时钟源,PLL倍频系数,AHB/APBx预分频器和flash时钟设定)

这个函数在复位后,进入main程序之前,就会被启动文件调用,调用命令在“startup_stm32f10x_xx.s”这个文件中)

  *

  *      - SystemCoreClock variable: Contains the core clock (HCLK), it can be used

  *                                  by the user application to setup the SysTick

  *                                  timer or configure other parameters.

  SystemCoreClock变量):包含内核时钟(HCLK),可以用于设置SysTick定时器,或者配置其他参数。

  (如果没有用这个变量来计算的值的话,这个可以不管了,可以自己直接定义一个新的时钟变量来用,这样可能产生的问题就是系统时钟突然变了,所有基于这个值的计算都会出错。

如果要用这个时钟变量的话,最好就是用之前调用一下SystemCoreClockUpdate()函数。)

  *      - SystemCoreClockUpdate(): Updates the variable SystemCoreClock and must

  *                                 be called whenever the core clock is changed

  *                                 during program execution.

SystemCoreClockUpdate():更新SystemCoreClock变量,在程序执行过程中,无论什么时候改变内核时钟,都要调用该函数)

  *

  * 2. After each device reset the HSI (8 MHz) is used as system clock source.

  *    Then SystemInit() function is called, in "startup_stm32f10x_xx.s" file, to

  *    configure the system clock before to branch to main program.

2.在每一个设备复位之后,HSI(内部RC时钟源8MHz)就会用作系统时钟源)

(然后在"startup_stm32f10x_xx.s"文件中调用SystemInit()函数,在进入main程序前,配置系统时钟)

  *

  * 3. If the system clock source selected by user fails to startup, the SystemInit()

  *    function will do nothing and HSI still used as system clock source. User can

  *    add some code to deal with this issue inside the SetSysClock() function.

3.如果用户选择的系统时钟源启动失败,SystemInit()函数会什么都不做,然后HSI仍然用作系统时钟源。用户可以在SetSysClock()函数中添加一些代码,用来处理这件事。)

意思就是:假如想用外部8MHz晶振来做时钟源,但是这个外部晶振坏了,或者没焊好,这个SystemInit()函数就不会切换到外部晶振了,仍然用内部时钟源。

  *

  * 4. The default value of HSE crystal is set to 8 MHz (or 25 MHz, depedning on

  *    the product used), refer to "HSE_VALUE" define in "stm32f10x.h" file.

  *    When HSE is used as system clock source, directly or through PLL, and you

  *    are using different crystal you have to adapt the HSE value to your own

  *    configuration.

4.默认的HSE(外部时钟源)设为8MHz(或者25MHz,取决于产品的使用),参考"stm32f10x.h" 文件中的"HSE_VALUE"定义。当使用的外部晶振频率与默认的8MHz不同时,那必须设置"HSE_VALUE"值和所用的晶振频率一致。(这句不太好翻译,不知道是不是漏字了,我英文水平有限,只能瞎编了)

  * @brief  Setup the microcontroller system

  *         Initialize the Embedded Flash Interface, the PLL and update the

  *         SystemCoreClock variable.

(这里是函数的简介:设置微处理器系统,初始化内置flash接口,PLL和更新SystemCoreClock变量)

  * @note   This function should be used only after reset.

(这个函数应当仅用于复位后)

  * @param  None

  * @retval None

  */

void SystemInit (void)

{

  /* Reset the RCC clock configuration to the default reset state(for debug purpose) */

(复位RCC时钟配置到默认复位状态(用于调试))

  /* Set HSION bit */

  RCC->CR |= (uint32_t)0x00000001;

(设置HSION位,由寄存器描述可知,这里置1HSI开启)

  /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */

#ifndef STM32F10X_CL

  RCC->CFGR &= (uint32_t)0xF8FF0000;

#else

  RCC->CFGR &= (uint32_t)0xF0FF0000;

#endif /* STM32F10X_CL */  

  (复位RCC_CFGR寄存器,CL型和非CL型产品分开,是因为CL型的MCO4bit的,其他的是3bit的。

复位的值对照寄存器可以看到:

1.MCO没有时钟输出;2. ADCPREADC预分频2分频;3.PPRE2APB2不分频;4.PPRE1APB1不分频;5.HPREAHB不分频;6:SW:选择HSI为系统时钟)

(以上寄存器的内容,请自行参考《STM32中文参考手册_V10》第6162页和8788页)

  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;

PLL关闭,时钟监测器关闭,外部晶振关闭。)

  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;

(不避开外部晶振(英文Bypass,这个可能是指先选上备用的意思吧,不确定。反正Bypass就是不能用外部晶振)。)

(经大神指导,见评论,这个Bypass指的是旁路时钟源(BYPASS Clock Source),直接从SOC_IN导入外部时钟信号。感谢!——修改于2024.09.26

  /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

  RCC->CFGR &= (uint32_t)0xFF80FFFF;

USBOTG预分频1.5分频,PLL倍频2倍,HSE不分频,HSI 2分频。)

#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR &= (uint32_t)0xEBFFFFFF;

(关闭PLL2PLL3。)

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;

(关闭所有中断和清除中断标志位。)

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

(系统时钟作为I2S时钟,PLL不倍频,预分频器不分频。)

(下面几句也是一样的,只是不同类型产品,寄存器有一些差别而已)

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;     

#else

  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x009F0000;

#endif /* STM32F10X_CL */

   

#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

  #ifdef DATA_IN_ExtSRAM(如果用外部SRAM,调用SystemInit_ExtMemCtl()函数)

    SystemInit_ExtMemCtl();

  #endif /* DATA_IN_ExtSRAM */

#endif

  /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

(配置系统时钟频率,HCLKPCLK2PCLK1预分频系数)

  /* Configure the Flash Latency cycles and enable prefetch buffer */

(配置flash的延迟周期和预取缓冲器)

  SetSysClock();

#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

}

(配置系统时钟频率的函数基本都一样的,这里就只拿72MHz的来说吧)

static void SetSysClockTo72(void)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/   

  /* Enable HSE */   

  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

(1. 使能外部晶振HSE)

  /* Wait till HSE is ready and if Time out is reached exit */

  do

  {

    HSEStatus = RCC->CR & RCC_CR_HSERDY;

(读取HSE的状态标志,以判断HSE是否已准备好)

    StartUpCounter++; 

(同时进行计数)

  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));

(当HSE没有准备好,并且计数超时,就一直循环,有一个条件不成立就退出循环,往下执行)

  if ((RCC->CR & RCC_CR_HSERDY) != RESET)

(这里是判断HSE已经准备好了)

  {

    HSEStatus = (uint32_t)0x01;(准备好了,状态位位0x01)

  }

  else

  {

    HSEStatus = (uint32_t)0x00;

  } 

  if (HSEStatus == (uint32_t)0x01)

(判断状态位,如果是准备好了,往下执行代码,不然的话,就会跑到最底部else上了,那里留了一句话,HSE启动失败,你可以在这里添加失败后的系统处理代码)

  {

    /* Enable Prefetch Buffer */

    FLASH->ACR |= FLASH_ACR_PRFTBE;

(2.使能flash预存取缓冲区)

    /* Flash 2 wait state */

    FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

    FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;   

(flash读写延迟周期设置。这里有个规则,系统时钟频率0~24MHz,延时0周期,24~48MHz,1周期,48~72MHz,2周期,这个函数是设置成72的,所以这里是FLASH_ACR_LATENCY_2)

    /* HCLK = SYSCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;

     /* PCLK2 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;

    /* PCLK1 = HCLK */

    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;

(3.设置AHB、APB1、APB2分频。这里可以看到,AHB、APB2不分频,APB1为2分频,是因为AHB、APB2最大频率可达72MHz,APB1最大只能到36MHz,如果系统时钟设置超过36MHz的话,APB1就必须2分频,36MHz及以下的可以不分频。)  

#ifdef STM32F10X_CL

    /* Configure PLLs ------------------------------------------------------*/

    /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

    /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */

       

    RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |

                              RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);

    RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |

                             RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);

(4.配置PLL2倍率)  

    /* Enable PLL2 */

    RCC->CR |= RCC_CR_PLL2ON;

    /* Wait till PLL2 is ready */

    while((RCC->CR & RCC_CR_PLL2RDY) == 0)

    {

    }

(5.使能PLL2)  

    /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */

    RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |

                            RCC_CFGR_PLLMULL9);

(6.配置PLL倍率)  

#else   

    /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |

                                        RCC_CFGR_PLLMULL));

    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

(#else这里,有些产品是没有PLL2的,只需设置PLL倍率就行了)

#endif /* STM32F10X_CL */

    /* Enable PLL */

    RCC->CR |= RCC_CR_PLLON;

    /* Wait till PLL is ready */

    while((RCC->CR & RCC_CR_PLLRDY) == 0)

    {

    }

   (7.使能PLL,等待准备完成)  

    /* Select PLL as system clock source */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;   

    /* Wait till PLL is used as system clock source */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)

    {

    }

   (8.系统时钟选择PLL时钟源,等待就绪。这就完成配置了。)  

  }

  else

  { /* If HSE fails to start-up, the application will have wrong clock

         configuration. User can add here some code to deal with this error */

  }

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值