zoukankan      html  css  js  c++  java
  • STM32F4 时钟树概述

    STM32F4 相对于 STM32F1 来说,时钟部分复杂了很多, STM32F4 的时钟配置,我们提供两个函数: Sys_Clock_Set Stm32_Clock_Init。其中 Sys_Clock_Set 是核心的系统时钟配置函
    数,由 Stm32_Clock_Init 调用,实现对系统时钟的配置。外部程序,一般调用 Stm32_Clock_Init函数来配置时钟。 sys文件夹中

    STM32F4 中,有 5 个最重要的时钟源,为 HSIHSELSILSEPLL。 其中 PLL 实际是分为两个时钟源,分别为主 PLL 和专用 PLL。 从时钟频率来分可以分为高速时钟源和低速
    时钟源,在这 5 个中 HSIHSE 以及 PLL 是高速时钟, LSI LSE 是低速时钟。从来源可分为外部时钟源和内部时钟源,外部时钟源就是从外部通过接晶振的方式获取时钟源,其中 HSE
    LSE 是外部时钟源,其他的是内部时钟源。

    ①、 LSI 是低速内部时钟, RC 振荡器,频率为 32kHz 左右。 供独立看门狗和自动唤醒单元使用。
    ②、 LSE 是低速外部时钟,接频率为 32.768kHz 的石英晶体。 这个主要是 RTC 的时钟源。
    ③、 HSE 是高速外部时钟,可接石英/陶瓷谐振器,或者接外部时钟源,频率范围为 4MHz~26MHz
    我们的开发板接的是 8M 的晶振。 HSE 也可以直接做为系统时钟或者 PLL 输入。
    ④、 HSI 是高速内部时钟, RC 振荡器, 频率为 16MHz。 可以直接作为系统时钟或者用作 PLL
    输入。
    ⑤、 PLL 为锁相环倍频输出。 STM32F4 有两个 PLL:
    1) 主 PLL(PLL)HSE 或者 HSI 提供时钟信号,并具有两个不同的输出时钟。
    第一个输出 PLLP 用于生成高速的系统时钟(最高 168MHz
    第二个输出 PLLQ 用于生成 USB OTG FS 的时钟(48MHz),随机数发生器的时钟和 SDIO
    时钟。
    2) 专用 PLL(PLLI2S)用于生成精确时钟,从而在 I2S 接口实现高品质音频性能。

    STM32F4 的时钟树图(非常重要)

    上图从左往右看,就是整个 STM32F4 的时钟走向。这里,我们挑选出 9 个重要的地方进行介绍(图 5.2.2.1 中标出的①~⑨)。
    ① 这是进入 PLL 之前的一个时钟分频系数(M),取值范围是: 2~63,一般取 8。注意,这个分频系数,对主 PLL PLLI2S 都有效。
    ② 这是 STM32F4 的主 PLL,该部分控制 STM32F4 的主频率(PLLCLK)和 USB/SDIO/随机数发生器等外设的频率(PLL48CK)。其中, N 是主 PLL vco 的倍频系数,其取值
    范围是: 64~432P 是系统时钟的主 PLL 分频系数,其取值范围是: 246 8(仅 限这四个值); Q USB/SDIO/随机数产生器等的主 PLL 分频系数,其取值范围是:
    2~15R 没用到。
    ③ 这是 STM32F4 I2S 部分的 PLL,该部分主要用于设置 STM32F4 I2S 内部输入时钟频率。其中, N 是用于 PLLI2S vco 的倍频系数,其取值范围是: 192~432R I2S 时钟的分
    频系数,其取值范围是: 2~7P Q 没用到。
    ④ 这是 PLL 之后的系统主时钟(PLLCLK), STM32F4 的主频最高是 168Mhz,所以我们一般设置 PLLCLK 168Mhz(M=8,N=336,P=2),通过 SW 选择 SYSCLK=PLLCLK
    即可得到 168Mhz 的系统运行频率。
    ⑤ 这是 PLL 之后的 USB/SDIO/随机数发生器时钟频率,由于 USB 必须是 48Mhz 才可以正常工作,所以这个频率一般设置为 48Mhz(M=8,N=336,Q=7)
    ⑥ 是 I2S 的时钟,通过 I2SSRC 选择内部 PLLI2SCLK 还是外部 I2SCKIN 作为时钟。 探索者 STM32F4 开发板使用的是内部 PLLI2SCLK
    ⑦ 这是 Cortex 系统定时器,也就是 SYSTICK 的时钟。上图清楚的表明 SYSTICK 的来源是 AHB 分频后再 8 分频(这个 8 分频是可以设置的,即 8 分频,或者不分频,一般使
    8 分频), 我们一般设置 AHB 不分频,则 SYSTICK 的频率为: 168M/8=21Mhz。前面介绍的延时函数,就是基于 SYSTICK 来实现的。
    ⑧ 这里是 STM32F4 很多外设的时钟来源,即两个总线桥: APB1 APB2,其中 APB1是低速总线(最高 42Mhz), APB2 是高速总线(最高 84Mhz)。另外定时器部分,如
    果所在总线(APB1/APB2)的分频系数为 1,那么就不倍频,如果不为 1(比如 2/4/8/16),那么就会 2 倍频(Fabpx*2)后,作为定时器时钟输入。
    ⑨ 这是 STM32F4 内部以太网 MAC 时钟的来源。对于 MII 接口来说,必须向外部 PHY芯片提供 25Mhz 的时钟,这个时钟,可以由 PHY 芯片外接晶振,或者使用 STM32F4
    MCO 输出来提供。然后, PHY 芯片再给 STM32F4 提供 ETH_MII_TX_CLK ETH_MII_RX_CLK 时钟。对于 RMII 接口来说,外部必须提供 50Mhz 的时钟驱动 PHY
    STM32F4 ETH_RMII_REF_CLK,这个 50Mhz 时钟可以来自 PHY、有源晶振或者 STM32F4 MCO。 我们的开发板使用的是 RMII 接口,使用 PHY 芯片提供 50Mhz
    时钟驱动 STM32F4 ETH_RMII_REF_CLK
    关于时钟的详细介绍,在《STM32F4xx 中文参考手册》第 6.2 节(106~113 页)有详细介绍。有不明白的地方,可以对照手册仔细研究。 最后,提醒下大家, STM32F4 默认的情况下
    (比如串口 IAP 时或未初始化时钟时),使用的是内部 16M HSI 作为时钟的,所以不需要外部晶振也可以下载和运行代码的。
    从上图可以看出 STM32F4 的时钟设计的比较复杂,各个时钟基本都是可控的,任何外设都有对应的时钟控制开关,这样的设计,对降低功耗是非常有用的,不用的外设不开启时钟,
    就可以大大降低其功耗。
    下面开始 Sys_Clock_Set 函数的介绍, 该函数用于配置 STM32F4 的时钟,包括系统主时钟、USB/SDIO/随机数发生器时钟、 APB1 APB2 时钟等。 该函数代码如下:

    //时钟设置函数
    //Fvco=Fs*(plln/pllm);
    //Fsys=Fvco/pllp=Fs*(plln/(pllm*pllp));
    //Fusb=Fvco/pllq=Fs*(plln/(pllm*pllq));
    //Fvco:VCO 频率
    //Fsys:系统时钟频率
    //Fusb:USB,SDIO,RNG 等的时钟频率
    //Fs:PLL 输入时钟频率,可以是 HSI,HSE 等.
    //plln:主 PLL 倍频系数(PLL 倍频),取值范围:64~432.
    //pllm:主 PLL 和音频 PLL 分频系数(PLL 之前的分频),取值范围:2~63.
    //pllp:系统时钟的主 PLL 分频系数(PLL 之后的分频),取值范围:2,4,6,8.(仅限这 4 个值!)
    //pllq:USB/SDIO/随机数产生器等的主 PLL 分频系数(PLL 之后的分频),取值范围:2~15.
    //外部晶振为 8M 的时候,推荐值:plln=336,pllm=8,pllp=2,pllq=7.
    //得到:Fvco=8*(336/8)=336Mhz
    // Fsys=336/2=168Mhz
    // Fusb=336/7=48Mhz
    //返回值:0,成功;1,失败。
    u8 Sys_Clock_Set(u32 plln,u32 pllm,u32 pllp,u32 pllq)
    {
    u16 retry=0;
    u8 status=0;
    RCC->CR|=1<<16; //HSE 开启
    while(((RCC->CR&(1<<17))==0)&&(retry<0X1FFF))retry++;//等待 HSE RDY
    if(retry==0X1FFF)status=1; //HSE 无法就绪
    else
    {
    RCC->APB1ENR|=1<<28; //电源接口时钟使能
    PWR->CR|=3<<14; //高性能模式,时钟可到 168Mhz
    RCC->CFGR|=(0<<4)|(5<<10)|(4<<13);//HCLK 不分频;APB1 4 分频;APB2 2 分频.
    RCC->CR&=~(1<<24); //关闭主 PLL
    RCC->PLLCFGR=pllm|(plln<<6)|(((pllp>>1)-1)<<16)|(pllq<<24)|(1<<22);
    //配置主 PLL,PLL 时钟源来自 HSE
    RCC->CR|=1<<24; //打开主 PLL
    while((RCC->CR&(1<<25))==0);//等待 PLL 准备好
    FLASH->ACR|=1<<8; //指令预取使能.
    FLASH->ACR|=1<<9; //指令 cache 使能.
    FLASH->ACR|=1<<10; //数据 cache 使能.
    FLASH->ACR|=5<<0; //5 个 CPU 等待周期.
    RCC->CFGR&=~(3<<0); //清零
    RCC->CFGR|=2<<0; //选择主 PLL 作为系统时钟
    while((RCC->CFGR&(3<<2))!=(2<<2));//等待主 PLL 作为系统时钟成功.
    }
    return status;
    }

    Sys_Clock_Set 函数中,我们设置了 APB1 4 分频, APB2 2 分频, HCLK 不分频,同时选择 PLLCLK 作为系统时钟。该函数有 4 个参数,具体意义和计算方法,见函数前面的说
    明。 一般我们推荐设置为: Sys_Clock_Set(336,8,2,7),即可设置 STM32F4 运行在 168Mhz 的频率下, APB1 42MhzAPB2 84MhzUSB/SDIO/随机数发生器时钟为 48Mhz

     

     以上代码中, RCC FLASH 都是 MDK 定义的一个结构体,包含 RCC/FLASH 相关的寄存器组。其寄存器名与《STM32F4xx 中文参考手册》 里面定义的寄存器名字是一摸一样的,所
    以在你不明白某个寄存器干什么用的时候,可以到《STM32F4xx 中文参考手册》里面查找一下,你就可以迅速查到这个寄存器的作用以及每个位所代表的意思。 特别注意,由于 FLASH 速度
    远远跟不上 CPU 的运行频率,所以这里我们设置了 FLASH 的等待周期为 5, 很明显, FLASH会大大拖慢程序的运行,不过 STM32F4 有自适实时存储器加速器(ART),通过这个加速器,可
    以让 STM32F4 获得相当于 0 FLASH 等待周期的运行效果。关于 STM32F4 FLASH 以及 ART等的介绍,请大家参考《STM32F4xx 中文参考手册》第 3.3 节(59 页开始)。
    接下来,我们再看下 Stm32_Clock_Init 函数,该函数代码如下:

    //系统时钟初始化函数
    //plln:主 PLL 倍频系数(PLL 倍频),取值范围:64~432.
    //pllm:主 PLL 和音频 PLL 分频系数(PLL 之前的分频),取值范围:2~63.
    //pllp:系统时钟的主 PLL 分频系数(PLL 之后的分频),取值范围:2,4,6,8.(仅限这 4 个值!)
    //pllq:USB/SDIO/随机数产生器等的主 PLL 分频系数(PLL 之后的分频),取值范围:2~15.
    void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
    {
    RCC->CR|=0x00000001; //设置 HISON,开启内部高速 RC 振荡
    RCC->CFGR=0x00000000; //CFGR 清零
    RCC->CR&=0xFEF6FFFF; //HSEON,CSSON,PLLON 清零
    RCC->PLLCFGR=0x24003010; //PLLCFGR 恢复复位值
    RCC->CR&=~(1<<18); //HSEBYP 清零,外部晶振不旁路
    RCC->CIR=0x00000000; //禁止 RCC 时钟中断
    Sys_Clock_Set(plln,pllm,pllp,pllq);//设置时钟
    //配置向量表
    #ifdef VECT_TAB_RAM
    MY_NVIC_SetVectorTable(1<<29,0x0);
    #else
    MY_NVIC_SetVectorTable(0,0x0);
    #endif
    }

    该函数主要进行了时钟配置前的一些设置工作,然后通过调用 Sys_Clock_Set 函数,实现对 STM32F4 的时钟配置。最后,根据代码运行的位置( FLASH or SRAM), 调用函数
    MY_NVIC_SetVectorTable 进行中断向量表偏移设置。MY_NVIC_SetVectorTable 函数的代码如下:

    //设置向量表偏移地址
    //NVIC_VectTab:基址
    //Offset:偏移量
    void MY_NVIC_SetVectorTable(u32 NVIC_VectTab,u32 Offset)
    {
    SCB->VTOR=NVIC_VectTab|(Offset&(u32)0xFFFFFE00);
    //设置 NVIC 的向量表偏移寄存器,VTOR 低 9 位保留,即[8:0]保留。
    }

    该函数是用来配置中断向量表基址和偏移量,决定是在那个区域。当在 RAM 中调试代码 的时候,需要把中断向量表放到 RAM 里面, 这就需要通过这个函数来配置。关于向量表的详
    细介绍请参考《Cortex M3 M4 权威指南》第 4.5.3 节(117 页)或者《Cortex M3 权威指南》第七章,第 113 页的向量表一章。 关于 SCB->VTOR 寄存器,请参考《STM32F3 F4 系列 Cortex
    M4 内核编程手册》第 4.4.4 节(212 页),有详细描述。

     

     

  • 相关阅读:
    电脑连不上网
    decompiler of java
    emmmmmmmmmmmmmmmmmm01
    WEB-INF
    tan?
    spring配置
    maven安装和使用前的几个点
    ※剑指offer系列29:两个链表的第一个公共结点
    剑指offer系列28:数组中的逆序对
    剑指offer系列27:第一个只出现一次的字符
  • 原文地址:https://www.cnblogs.com/caiya/p/15076923.html
Copyright © 2011-2022 走看看