历史上的今天
返回首页

历史上的今天

今天是:2024年09月02日(星期一)

正在发生

2019年09月02日 | STM32开发 -- 时钟系统详解

2019-09-02 来源:eefocus

上一篇文章讲了RTC,里面其实已经包含了时钟系统的介绍了。这篇文章将再详细的讲一下。


一、时钟系统框图


这里写图片描述

二、时钟系统

STM32 有5个时钟源:HSI、HSE、LSI、LSE、PLL。

①、HSI是高速内部时钟,RC振荡器,频率为8MHz,精度不高。

②、HSE是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为4MHz~16MHz。

③、LSI是低速内部时钟,RC振荡器,频率为40kHz,提供低功耗时钟。 

④、LSE是低速外部时钟,接频率为32.768kHz的石英晶体。

⑤、PLL为锁相环倍频输出,其时钟输入源可选择为HSI/2、HSE或者HSE/2。倍频可选择为2~16倍,但是其输出频率最大不得超过72MHz。

系统时钟SYSCLK可来源于三个时钟源:

①、HSI振荡器时钟

②、HSE振荡器时钟

③、PLL时钟

STM32可以选择一个时钟信号输出到MCO脚(PA8)上,可以选择为PLL输出的2分频、HSI、HSE、或者系统时钟。

任何一个外设在使用之前,必须首先使能其相应的时钟。

三、RCC相关配置寄存器

        /** 

          * @brief Reset and Clock Control

          */

        typedef struct

        {

          __IO uint32_t CR;           // HSI,HSE,CSS,PLL等的使能和就绪标志位 

          __IO uint32_t CFGR;         // PLL等的时钟源选择,分频系数设定

          __IO uint32_t CIR;          // 清除/使能 时钟就绪中断

          __IO uint32_t APB2RSTR;     // APB2线上外设复位寄存器

          __IO uint32_t APB1RSTR;     // APB1线上外设复位寄存器

          __IO uint32_t AHBENR;       // DMA,SDIO等时钟使能

          __IO uint32_t APB2ENR;      // APB2线上外设时钟使能

          __IO uint32_t APB1ENR;      // APB1线上外设时钟使能

          __IO uint32_t BDCR;         // 备份域控制寄存器

          __IO uint32_t CSR;          // 控制状态寄存器


        #ifdef STM32F10X_CL  

          __IO uint32_t AHBRSTR;

          __IO uint32_t CFGR2;

        #endif /* STM32F10X_CL */ 


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

          uint32_t RESERVED0;

          __IO uint32_t CFGR2;

        #endif /* STM32F10X_LD_VL || STM32F10X_MD_VL || STM32F10X_HD_VL */ 

        } RCC_TypeDef;


四、RCC相关头文件和固件库源文件

所在文件:stm32f10x_rcc.c


时钟使能配置:

     RCC_LSEConfig() 、RCC_HSEConfig()、

     RCC_HSICmd() 、 RCC_LSICmd() 、 RCC_PLLCmd() ……


时钟源相关配置:

     RCC_PLLConfig ()、 RCC_SYSCLKConfig() 、

     RCC_RTCCLKConfig() …


分频系数选择配置:

      RCC_HCLKConfig() 、 RCC_PCLK1Config() 、 RCC_PCLK2Config()…


外设时钟使能:

     RCC_APB1PeriphClockCmd():  //APB1线上外设时钟使能

     RCC_APB2PeriphClockCmd();  //APB2线上外设时钟使能

     RCC_AHBPeriphClockCmd();   //AHB线上外设时钟使能


其他外设时钟配置:

    RCC_ADCCLKConfig ();  RCC_RTCCLKConfig();


状态参数获取参数:

     RCC_GetClocksFreq();

     RCC_GetSYSCLKSource();

     RCC_GetFlagStatus()


RCC中断相关函数 :

    RCC_ITConfig() 、 RCC_GetITStatus() 、 RCC_ClearITPendingBit()…


五、系统时钟初始化函数

系统时钟初始化函数:SystemInit();

我们在 STM32开发 – 启动流程 中讲过:


使用V3.5版本的库函数,该函数在系统启动之后会自动调用:

; Reset handler

Reset_Handler    PROC

                 EXPORT  Reset_Handler             [WEAK]

        IMPORT  SystemInit

        IMPORT  __main

                 LDR     R0, =SystemInit

                 BLX     R0

                 LDR     R0, =__main

                 BX      R0

                 ENDP


系统复位后先执行SystemInit,再执行main函数

 通过修改SystemInit函数名称,可以自定义系统初始化过程


在system_stm32f10x.c文件中找到SystemInit(void)源码:

/**

  * @brief  Setup the microcontroller system

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

  *         SystemCoreClock variable.

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

  /* Set HSION bit */

  RCC->CR |= (uint32_t)0x00000001;    //RCC_CR寄存器最低位置1:打开HSI(内部高速时钟8M)


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

#ifndef STM32F10X_CL

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

#else                      //stm32f103ZET6为大容量芯片HD

  RCC->CFGR &= (uint32_t)0xF0FF0000;     //RCC_CFGR寄存器初始化

#endif /* STM32F10X_CL */


  /* Reset HSEON, CSSON and PLLON bits */

  RCC->CR &= (uint32_t)0xFEF6FFFF;    //将RCC_CR寄存器HSEON,CSSON,PLLON位置0


  /* Reset HSEBYP bit */

  RCC->CR &= (uint32_t)0xFFFBFFFF;    //将RCC_CR寄存器HSEBYP位置0


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

  RCC->CFGR &= (uint32_t)0xFF80FFFF;   //将RCC_CFGR寄存器PLLSRC, PLLXTPRE,                         //PLLMUL,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                      //stm32f103ZET6为大容量芯片HD

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

}


源码解析

参看:系统初始化函数SystemInit讲解

参看:第一个函数SystemInit()里面有些啥


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


操作时钟控制寄存器,将内部8M高速时钟使能,从这里可以看出系统启动后是首先依靠内部时钟源而工作的。


#ifndef STM32F10X_CL

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

#else

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


这两行代码则是操作时钟配置寄存器,其主要设置了MCO(微控制器时钟输出)PLL相关(PLL倍频系数,PLL输入时钟源),ADCPRE(ADC时钟),PPRE2(高速APB分频系数),PPRE1(低速APB分频系数),HPRE(AHB预分频系数),SW(系统时钟切换),开始时,系统时钟切换到HSI,由它作为系统初始化时钟。宏STM32F10X_CL是跟具体STM32芯片相关的一个宏。


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


这几句话则是在先关闭HSE、CSS、PLL等的情况下配置好与之相关参数然后开启,达到生效的目的。



#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


这段跟设置外部RAM有关。


SetSysClock();


此函数主要是配置系统时钟频率。HCLK,PCLK2,PCLK1的分频值,分别代表AHB,APB2,和APB1。当然还干了其它的事情,配置FLASH延时周期和使能预取缓冲区。


/**

  * @brief  Configures the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers.

  * @param  None

  * @retval None

  */

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

}


查看可得默认定义系统时钟为72MHz


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

/* #define SYSCLK_FREQ_HSE    HSE_VALUE */

 #define SYSCLK_FREQ_24MHz  24000000

#else

/* #define SYSCLK_FREQ_HSE    HSE_VALUE */

/* #define SYSCLK_FREQ_24MHz  24000000 */ 

/* #define SYSCLK_FREQ_36MHz  36000000 */

/* #define SYSCLK_FREQ_48MHz  48000000 */

/* #define SYSCLK_FREQ_56MHz  56000000 */

#define SYSCLK_FREQ_72MHz  72000000

#endif


通过SystemCoreClock获取当前系统时钟频率


/*******************************************************************************

*  Clock Definitions

*******************************************************************************/

#ifdef SYSCLK_FREQ_HSE

  uint32_t SystemCoreClock         = SYSCLK_FREQ_HSE;        /*!< System Clock Frequency (Core Clock) */

推荐阅读

史海拾趣

EDI [Electronic devices inc.]公司的发展小趣事

在2000年代初,Eclipse Magnetics公司迎来了一个重要的合作伙伴——IBM。当时,IBM正在寻求一种可靠的磁性技术来支持其开源项目Eclipse。经过深入了解和严格测试,IBM最终选择了Eclipse Magnetics的产品。这一合作不仅为Eclipse Magnetics带来了可观的业务机会,还进一步提升了公司在行业中的影响力。

Electrolube公司的发展小趣事

在电子行业的激烈竞争中,Electrolube公司始终坚持以客户需求为导向,不断创新和拓展产品线。除了UVCL涂层外,公司还推出了一系列树脂、涂料和热管理解决方案的产品组合,为EV电池提供全面保护。

这些产品不仅具有优异的性能表现,而且能够满足不同客户的需求。例如,某些产品具有优异的耐高温性能,适用于高温环境下的电子设备;而另一些产品则具有出色的耐化学腐蚀性能,能够在恶劣的工作环境中保持稳定的性能。

Electrolube公司通过不断的技术创新和产品优化,成功拓展了市场份额,并在电子行业中树立了良好的品牌形象。同时,公司还积极与各大汽车制造商合作,共同推动电动汽车产业的发展。

方舟(ARKLED)公司的发展小趣事

方舟公司高度重视产品品质管理,从原材料采购到生产加工,再到成品检验,每一个环节都严格把关。公司引进了先进的生产设备和检测仪器,建立了完善的质量管理体系。通过ISO9001质量管理体系认证,方舟公司的产品质量得到了有效保障,赢得了客户的信赖和支持。

BAND-IT公司的发展小趣事

1937年,在美国的科罗拉多州,BAND-IT公司应运而生。当时,电子行业正处于快速发展的初期,对高质量紧固件的需求日益增长。BAND-IT创始人敏锐地捕捉到了这一机遇,开始设计和制造不锈钢带和扎扣,以及C00169标准绑带机。这些产品迅速在电子行业中获得了认可,成为电缆、电线束等部件紧固的理想选择。初创时期的BAND-IT面临着资金短缺、市场竞争激烈等挑战,但凭借其创新的产品和卓越的品质,逐渐在电子行业中站稳了脚跟。

AINFO Inc公司的发展小趣事

为了进一步提升技术水平和市场竞争力,AINFO Inc公司积极寻求与国际知名企业的技术合作。通过与国外企业的合作,公司引进了先进的技术和管理经验,提升了自身的研发能力和管理水平。同时,公司也加快了国际化发展的步伐,拓展了海外市场,提升了品牌知名度。

Cal-Chip Electronics公司的发展小趣事

在XXXX年,Cal-Chip Electronics公司迎来了一次技术创新的重大突破。公司研发团队成功开发出了一款具有高效能、低功耗特点的新型芯片,这款芯片在行业内引起了广泛关注。凭借这一技术创新,公司迅速扩大了市场份额,并与多家知名企业建立了长期合作关系。这一突破不仅提升了公司的技术水平,也为公司的长远发展奠定了坚实基础。

问答坊 | AI 解惑

中国半导体行业协会将申请成为世界半导体理事会成员

中国半导体行业协会将申请成为世界半导体理事会成员 美国半导体行业协会表示中国半导体行业协会的加入将增强这一世界性组织的影响力 2006-06-15   应世界半导体理事会(WSC)的邀请,中国半导体行业协会(CSIA)开始WSC的成员资格的申请工作 ...…

查看全部问答>

大功率白色发光二极管的特性研究

分析了大功率白色发光二极管的发光强度 即光强 、光通量和色坐标与测量位置的关系, 提出了解决的方法。同时, 对大功率白色发光二极管法向光强、光通量和峰值长随电流和时间的变化情况做了分析, 说明PN 结温度对于大功率发光二极管的发光具有较大的 ...…

查看全部问答>

硬件工程师的基础知识

目的:基于实际经验与实际项目详细理解并掌握成为合格的硬件工程师的最基本知识…

查看全部问答>

如何在WINCE下通过有线局域网访问网络

各位大虾;     有个问题请教大家, 我在ARM系统的开发板上要访问网络,网卡芯片是CS8900, 驱动也都有了, 在WINCE下我需要加哪些组件呢? 另外,如何配置呢/ 请知道的大虾指点一下, 不胜感激.…

查看全部问答>

本人4年wince平台应用、驱动开发经验,求Wince平台兼职,13910531491

本人4年wince平台应用、驱动开发经验,求Wince平台兼职,13910531491…

查看全部问答>

STM8S的C编译器太贵了!那位大侠处理一下啊!

IAR STM8S报价:2.3万人民币 COSMIC STM8S报价:2.3万人民币 Raisonance STM8S报价:990欧元(算成人民币大约:8600元不到) 三个用起来感觉Raisonance用起来好用些,价格也算是最便宜的!不过没有石皮 角刀牛。 比起AVR的CodeVisionAVR ...…

查看全部问答>

ADC10实验例程(含C#上位机)

C#上位机学习资料 https://bbs.eeworld.com.cn/viewthread.php?tid=308129&page=1#pid1198878上周逛论坛看到上面的C#串口教程,觉得挺有趣的,跟着学了一下,结合LaunchPad写了一个简单的ADC10+串口上位机。第一次用C#,线程、运行机制呀什么的 ...…

查看全部问答>

哪个大哥帮忙画下原理图

原文件发1307190512@qq.com.非常感谢啊。能提供代码就更好了。非常感谢啊,自己画不出来。…

查看全部问答>

光电鼠标如何探测位移

请教各位大侠,光电鼠标如何探测位移的?…

查看全部问答>

从单片机初学者迈向单片机工程师(一份正真的让你成为工程师的贴子)

学习单片机也已经有几年了,藉此机会和大家聊一下我学习过程中的一些经历和想法吧。也感谢一线工人提供了这个机会。希望大家有什么好的想法和建议都直接跟帖说出来。毕竟只有交流才能够碰撞出火花来^_^。     几年前,和众多初学 ...…

查看全部问答>