STM32库函数SystemInit()详解

发布时间:2024-07-23  

STM32单片机应用非常广泛,官方提供了标准的接口库,用户可以不用直接操作寄存器,只需要调用接口函数就可以了。在官方库中有一个非常重要的函数void SystemInit (void),


该函数用户可能不会直接调用,而在启动文件中一定会调用。函数原型如下:


函数原型


void SystemInit (void)

{

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

  /* Set HSION bit */

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


  /* 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 */   

  

  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR  = (uint32_t)0xFEF6FFFF;


  /* Reset HSEBYP bit */

  RCC->CR  = (uint32_t)0xFFFBFFFF;


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

  RCC->CFGR  = (uint32_t)0xFF80FFFF;


#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR  = (uint32_t)0xEBFFFFFF;


  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;


  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#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

    SystemInit_ExtMemCtl(); 

  #endif /* DATA_IN_ExtSRAM */

#endif 


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

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

  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 

}


可以看到函数体中几乎全是条件编译。

(1)先看第一行代码:RCC->CR |= (uint32_t)0x00000001;显然这是给CR寄存器的最低一位赋值为1.官方寄存器配置详解截图:

poYBAGIB2VOAGnwMAAMoC0MFciA571.png
pYYBAGIB2VWAKHq_AAKG7PP3AUs272.png

编译条件宏定义


#ifndef STM32F10X_CL

  RCC->CFGR  = (uint32_t)0xF8FF0000;

#else

  RCC->CFGR  = (uint32_t)0xF0FF0000;

#endif /* STM32F10X_CL */   


这个条件编译是根据芯片容量不同默认初始化CFGR寄存器(Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits )。

poYBAGIB2VeAQoQ9AAPmr-3FLb8441.png


 RCC->CR  = (uint32_t)0xFEF6FFFF;

 RCC->CR  = (uint32_t)0xFFFBFFFF;

显然是把CR寄存器的某些位赋值,其作用为:Reset HSEON, CSSON and PLLON ,HSEBYPbits即将HSEON,CSSON,PLLON,HSEBYP位置为零。


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

RCC->CFGR  = (uint32_t)0xFF80FFFF;

作用为把CFGR寄存器的PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE位置0。


#ifdef STM32F10X_CL

  /* Reset PLL2ON and PLL3ON bits */

  RCC->CR  = (uint32_t)0xEBFFFFFF;


  /* Disable all interrupts and clear pending bits  */

  RCC->CIR = 0x00FF0000;


  /* Reset CFGR2 register */

  RCC->CFGR2 = 0x00000000;

#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

  SystemInit_ExtMemCtl(); 

  #endif /* DATA_IN_ExtSRAM */

#endif 

这个条件编译块的作用为初始化Memory控制。


static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

  SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

  SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

  SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

  SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

  SetSysClockTo56();  

#elif defined SYSCLK_FREQ_72MHz

  SetSysClockTo72();

#endif

 

 /* If none of the define above is enabled, the HSI is used as System clock

    source (default after reset) */ 

}

我们可以看到该函数就是通过判断定义了哪个宏定义标志符而调用不同的设置sys时钟频率的函数,官方固件库默认定义了SYSCLK_FREQ_72MHz,所以会调用SetSysClockTo72这个函数。


如果要使用其它频率,那就解开相应注释(只保留一个不被注释)。


SetSysClockTo72()函数如下:


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);

 

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

  do

  {

    HSEStatus = RCC->CR   RCC_CR_HSERDY;

    StartUpCounter++;  

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


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

  {

    HSEStatus = (uint32_t)0x01;

  }

  else

  {

    HSEStatus = (uint32_t)0x00;

  }  


  if (HSEStatus == (uint32_t)0x01)

  {

    /* Enable Prefetch Buffer */

    FLASH->ACR |= FLASH_ACR_PRFTBE;


    /* Flash 2 wait state */

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

    FLASH->ACR |= (uint32_t)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;


#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);

  

    /* Enable PLL2 */

    RCC->CR |= RCC_CR_PLL2ON;

    /* Wait till PLL2 is ready */

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

    {

    }

    

   

    /* 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); 

#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);

#endif /* STM32F10X_CL */


    /* Enable PLL */

    RCC->CR |= RCC_CR_PLLON;


    /* Wait till PLL is ready */

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

    {

    }

    

    /* 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)

    {

    }

  }

  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 */

  }

}

这个函数体比较长,但仔细看会发现这个函数就是在配置CR,CFGR,ACR(设置FLASH)寄存器的某些位(使能,判断是否就绪,设置相应位,设置FLASH,设置AHB,APB预分频系数,设置HCLK,PCLK等等外设时钟,设置PLL锁相环倍频系数最终确定系统时钟),结合官方注释和官方寄存器的说明很容易理解。


至此,SystemInit函数就能大概理解了。但是还有一个问题需要注意:那就是虽然我们在main函数中并没有调用SystemInit函数,但它在start up启动文件中被调用了:

pYYBAGIB2VmAKJ23AADqsNTSO84400.png

可以看到SystemInit函数是在main函数之前执行的,要是自定义该函数,那这里也要修改名称,建议不要随意修改或者重构该函数。


文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>