码迷,mamicode.com
首页 > 其他好文 > 详细

STM32之时钟

时间:2016-05-13 03:20:10      阅读:387      评论:0      收藏:0      [点我收藏+]

标签:

1、时钟源

三个不同的时钟源可做系统时钟(SYSCLK):

HSI 振荡器时钟 :高速内部时钟
HSE 振荡器时钟:高速外部时钟
PLL 时钟

两个二级时钟

LSI(低速内部时钟) :32kHz 低速内部 RC (LSI RC) 独立看门狗时钟源,RTC 可用于自动唤醒停止/待机模式。
LSE(低速外部时钟):32.768kHz 低速外部晶振 (LSE crystal) ,可选择作为 RTC(RTCCLK) 时钟源

每一个时钟源不需要时都可以被选择性关闭,用来节省系统电源消耗

预分频器被用来设置 AHB, APB (APB2) 和 APB (APB1) 频率。 AHB域最大频率可设置为168 MHz。APB2 域最高频率可达 84 MHz。APB1 域最高频率可达 42 MHz。

AHB:主要用于控制USB,网卡,IO口,DMA等设备
APB:主要用于控制串口,AD,I2C等设备
以上总线时钟分频系数在RCC_CFGR 寄存器的10到15位设置

2、时钟输出

  • 一共有两个微控制器时钟输出脚
    1. MCO1:配置预分频器可以选择四种时钟源输出到MCO1引脚
      (PA8)HSI LSE HSE PLL
      配置 MCO1PRE[2:0] 和 MCO1[1:0] 位来选择上面给出时钟源
    2. MCO2:配置预分频器可以选择四种时钟源输出到MCO2引脚(PC9)
      HSE PLL SYSCLK PLLI2S
      配置 MCO2PRE[2:0] 和 MCO2 位来选择上面给出的时钟源

另:输出时钟的最高频率不得超过100MHz,因为引脚的最高速不超过100MHz

3、时钟测量

STM32F407ZG允许用TIM5 channel 4 和 TIM11 channel 1捕获时钟源,以此间接的测量所有片上时钟源的频率

  • TIM5 channel 4

    TIM5有一个复用控制器可用来选择输入捕获由I/O触发还是由内部时钟触发。可通过设置 TIM5_OR 的 TI4_RMP [1:0] 位来选择。
    测量LSI时钟频率的设置步骤:

    1. 使能 TIM5 时钟,并配置 channel 4 为输入捕获模式
    2. 设置 TIM5_OR 寄存器的 TI4_RMP 位为 0x01 来连接 LSI 时钟
    3. 用TIM5 4个事件或者中断来捕获/比较测量内部时钟
      4.用测量到的 LSI 频率来更新 RTC 的预分频对看门狗时钟输出编程
  • TIM11 channel 1

    TIM11有一个复用控制器可用来选择输入捕获由I/O触发还是由内部时钟触发。可通过设置 TIM11_OR 的 TI1_RMP [1:0] 位来选择。
    设置步骤与TIM5 channel 4 类似

4、PLL的数值设置

f(VCO clock) = f(PLL clock input) × (PLLN / PLLM)
f(PLL general clock output) = f(VCO clock) / PLLP
f(USB OTG FS, SDIO, RNG clock output) = f(VCO clock) / PLLQ
标号 意义
f(PLL clock input) 也就是输入到PLL锁相环的时钟,输入源可选择,系统刚刚上电的时候是HSI源,参见下面的:系统复位时钟设置
f(VCO clock) 暂且理解为经倍频之后待输出的频率,之后要进行分频设置,频率大小与芯片硬件相关
f(PLL general clock output) PLL实际输出的时钟频率,参照STM32时钟树图的中间部分SYSCLK 168MHz max处,这个点的时钟频率就是f(PLL general clock output),之后又会经过分频以供不同的设备使用
f(USB OTG FS, SDIO, RNG clock output) 也就是USB SDIO等等的频率,通常48MHz

5、时钟树图

对比S3C2440与该STM32也就是Cortex M4的时钟图(S3C2440画的更清晰明了,更详细一点)

STM32的时钟树图
技术分享

S3C2440的时钟树图
技术分享

ARM的时钟基本就是采用PLL锁相环结构,之后分出来FCLK,PCLK与HCLK分别给系统内核,片内外设,以及硬件提供时钟。

6、系统复位时时钟设置

寄存器 复位值 意义
RCC_CR 0x00000083 开启HSI,系统运行刚上电就是以HSI为时钟源运行的
RCC_PLLCFGR 0x24003010 PLLQ = 4, HSI为PLL源,PLLP = 2,PLLM = 16,PLLN = 192
RCC_CFGR 0x00000000 系统时钟不分频,系统时钟源为HSI

STM32F407ZG寄存器地址映射
技术分享

7、时钟初始化最简编程实例

#define BYM_RCC_struct \
    ((RCC_TypeDef *)(AHB1PERIPH_BASE + 0x3800))

#define BYM_FLASH_struct \
    ((FLASH_TypeDef *)(AHB1PERIPH_BASE + 0x3C00))

#define F_VCO_CLK_336   ((336 << 6) | (8 << 0))
#define PLL_OUT_CLK_168 (0 << 16)
#define USB_OUT_CLK_48  (7 << 24)

/* 
 * Initialize system clock
 * f(VCO clock) = f(PLL clock input) * (PLLN / PLLM)
 * f(PLL general clock output) = f(VCO clock) / PLLP
 * f(USB OTG FS, SDIO, RNG clock output) = f(VCO clock) / PLLQ
 * 
 * PLLP = 2; PLLQ = 7; PLLN / PLLM = 42;
 * f(PLL clock input) = 8M; f(VCO clock) = 336M; 
 * f(PLL general clock output) = 168M; f(USB OTG FS, SDIO, RNG clock output) = 48M
 */
void sys_clk_init(void)
{   
    /* 开启HSE高速外部时钟 */
    BYM_RCC_struct->CR &= ~(1 << 16);      //Disable HSE, be required by bit18 if you want to write bit18
    BYM_RCC_struct->CR &= ~(1 << 18);      //HSE not bypassed
    BYM_RCC_struct->CR |= (1 << 16);        //Enable HSE
    while((BYM_RCC_struct->CR & (1 << 17)) == 0);   //Wait for HSE ready

    /* 设置倍频系数确定时钟频率(PLL模式) */
    BYM_RCC_struct->PLLCFGR &= ~(0xf << 24);   //Clear old data
    BYM_RCC_struct->PLLCFGR |= USB_OUT_CLK_48;  //Flush new data
    BYM_RCC_struct->PLLCFGR &= ~(0x3 << 16);   //Clear old data
    BYM_RCC_struct->PLLCFGR |= PLL_OUT_CLK_168; //Flush new data
    BYM_RCC_struct->PLLCFGR &= ~(0x7fff << 0); //Clear old data
    BYM_RCC_struct->PLLCFGR |= F_VCO_CLK_336;   //Flush new data

    /* 选择PLL源为HSE,开启PLL */
    BYM_RCC_struct->PLLCFGR |= (1 << 22);       //HSE oscillator clock selected as PLL and PLLI2S clock entry

    BYM_RCC_struct->CR &= ~(1 << 26);          //Close PLLI2S
    BYM_RCC_struct->CR |= (1 << 24);            //Enable PLL
    while((BYM_RCC_struct->CR & (1 << 25)) == 0);

    /* 使能指令预取与指令数据Cache(调试过程发现此步是必须的,否则程序没法运行) */
    BYM_FLASH_struct->ACR   |= (1 << 8);        //
    BYM_FLASH_struct->ACR   |= (1 << 9);        //Enable ICache
    BYM_FLASH_struct->ACR   |= (1 << 10);       //Enable DCache
    BYM_FLASH_struct->ACR   |= (5 << 0);        //Wait

    /* 配置预分频器来对时钟进行分频 */
    BYM_RCC_struct->CFGR    &= ~(0x7 << 13);
    BYM_RCC_struct->CFGR    |= (4 << 13);       //APB2 max value = 84M, 2 devided as system clock = 168M
    BYM_RCC_struct->CFGR    &= ~(0x7 << 10);
    BYM_RCC_struct->CFGR    |= (5 << 10);       //APB1 max value = 42M, 4 devided as system clock = 168M
    BYM_RCC_struct->CFGR    &= ~(0xf << 4);        //system clock not devided

    /* 选择系统时钟来源 */
    BYM_RCC_struct->CFGR    &= ~(0x3 << 0);
    BYM_RCC_struct->CFGR    |= (2 << 0);        //PLL used as system clock
    while((BYM_RCC_struct->CFGR & (2 << 2)) == 0);

    BYM_RCC_struct->CR &= ~(1 << 0);       //Close HSI
    while((BYM_RCC_struct->CR & (1 << 1)));
}

8、初始化时钟的步骤,PLL模式

  • 开启HSE高速外部时钟
  • 设置倍频系数确定时钟频率(PLL模式)
  • 配置预分频器来对时钟进行分频
  • 选择PLL源为HSE,开启PLL
  • 使能指令预取与指令数据Cache(调试过程发现此步是必须的,否则程序没法运行)
  • 选择系统时钟来源

由上面的程序可知,某些步骤可以被打乱,但是开启PLL之前必须选择好PLL源以及设置好倍频系数。设置系统时钟来源之前必须先启动ICache与DCache。要关闭HSI的话要在上述步骤设置完之后才能够关闭,因为系统上电之后默认的是HSI为系统时钟源并且使用PLL,所以在HSI还在被使用的时候是不可能被关闭的,只有系统时钟源改变之后才能够被关闭,关闭HSI以节省电量

STM32之时钟

标签:

原文地址:http://blog.csdn.net/u013904227/article/details/51336353

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!