0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

STM32库函数SystemInit()详解

jf_pJlTbmA9 来源:jf_pJlTbmA9 作者:jf_pJlTbmA9 2023-09-18 15:45 次阅读

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函数之前执行的,要是自定义该函数,那这里也要修改名称,建议不要随意修改或者重构该函数。

审核编辑:彭菁

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 接口
    +关注

    关注

    33

    文章

    8582

    浏览量

    151072
  • STM32
    +关注

    关注

    2270

    文章

    10897

    浏览量

    355820
  • 函数
    +关注

    关注

    3

    文章

    4329

    浏览量

    62585
  • 代码
    +关注

    关注

    30

    文章

    4782

    浏览量

    68546
收藏 人收藏

    评论

    相关推荐

    STM32学习笔记1 基于STM32F103的SystemInit()函数详解

    本帖最后由 zhangshun5233 于 2015-1-20 11:37 编辑 STM32学习笔记1 基于STM32F103的SystemInit()函数
    发表于 01-20 11:30

    SystemInit()函数到底做了哪些操作

    使用库函数编写的LED程序,在system_stm32f10x.c文件中可以找到SystemInit()函数SystemInit()代码如
    发表于 08-10 07:53

    SystemInit()函数到底做了哪些操作

    使用库函数编写的LED程序,在system_stm32f10x.c文件中可以找到SystemInit()函数SystemInit()代码如
    发表于 08-12 06:21

    SystemInit函数的功能是什么

    对system_stm32f4xx的理解上一篇博客解释了stm32的启动文件,在启动文件中,在进入__mainC库函数之前,进入了SystemInit
    发表于 08-24 08:09

    PICC库函数详解

    PICC库函数详解
    发表于 04-18 20:13 132次下载

    STM32库函数代码自动生成器V1.2

    stm32库函数代码自动生成器是STM32学习的小工具。 stm32库函数代码自动生成器可以根据你的配置生成相应的
    发表于 06-17 17:55 0次下载

    STM32库函数代码自动生成器正式版

    STM32库函数代码自动生成器正式版 STM32库函数代码自动生成器正式版
    发表于 07-25 18:52 0次下载

    STM32 IAR的库函数资料免费下载

    本文档的主要内容详细介绍的是STM32 IAR的库函数资料免费下载。
    发表于 03-27 09:48 43次下载
    <b class='flag-5'>STM32</b> IAR的<b class='flag-5'>库函数</b>资料免费下载

    STM32F4 HAL库函数说明下载

    STM32F4 HAL库函数说明下载
    发表于 05-26 09:27 78次下载

    STM32SystemInit()和SetSysClock()函数详解——学习笔记(4)

    文章内容根据野火学习教程进行整理,仅仅是学习记录。野火的教程把SetSysClock()函数的内容讲解了一下,学会了怎么查手册怎么看。我打算从SystemInit()开始分析,毕竟是第一个被调用的C
    发表于 11-26 09:51 20次下载
    <b class='flag-5'>STM32</b>的<b class='flag-5'>SystemInit</b>()和SetSysClock()<b class='flag-5'>函数</b><b class='flag-5'>详解</b>——学习笔记(4)

    stm32下标准库函数与HAL库函数编程方式的差异

    stm32下标准库函数与HAL库函数编程方式的差异标准库函数HAL库函数标准库函数与HAL
    发表于 12-09 14:21 15次下载
    <b class='flag-5'>stm32</b>下标准<b class='flag-5'>库函数</b>与HAL<b class='flag-5'>库函数</b>编程方式的差异

    STM32入门-STM32时钟系统,时钟初始化配置函数

    使用库函数编写的LED程序,在system_stm32f10x.c文件中可以找到SystemInit()函数SystemInit()代码如
    发表于 12-27 19:07 2次下载
    <b class='flag-5'>STM32</b>入门-<b class='flag-5'>STM32</b>时钟系统,时钟初始化配置<b class='flag-5'>函数</b>

    基于标准库函数与基于HAL库函数stm32编程方式对比

    以实例程序(串口通信),分析基于标准库函数与基于HAL库函数stm32编程方式的差异一、基于标准库函数stm32编程方式二、基于HAL
    发表于 12-28 19:09 30次下载
    基于标准<b class='flag-5'>库函数</b>与基于HAL<b class='flag-5'>库函数</b>的<b class='flag-5'>stm32</b>编程方式对比

    STM32库函数开发-GPIO

    2021-01-11 学习日志STM32f1库函数开发学习实战一 · I/O口1. 文件夹结构2. 配置细节 · 从寄存器到库函数3. 跑马灯4. 按键输入STM32f1
    发表于 01-13 16:17 14次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>库函数</b>开发-GPIO

    STM32库函数SystemInit()详解

    STM32单片机应用非常广泛,官方提供了标准的接口库,用户可以不用直接操作寄存器,只需要调用接口函数就可以了。
    发表于 02-08 15:20 3次下载
    <b class='flag-5'>STM32</b><b class='flag-5'>库函数</b><b class='flag-5'>SystemInit</b>()<b class='flag-5'>详解</b>