STM32 时钟设置
时钟设置
时钟树介绍
有以下三种时钟可以作为系统时钟(SYSCLK):
- HSI 振荡器时钟
- HSE 振荡器时钟
- PLL 时钟
时钟树如下:
-
OSC_OUT 和 OSC_IN 为外部晶振的接口,为 HSE(高速) 提供振荡源,接 4 -16 MHz 的晶振;
-
OSC32_OUT 和 OSC32_IN 为外部晶振的接口,为 LSE(低速) 提供振荡源,接 32.768 kHz 的晶振。其为看门狗时钟 (IWDGCLK) 提供动力;
-
LSI RC 为内部低速振荡器,频率为 40kHz;
-
RTCCLK (Real Time Clock) 由 HSE/128、LSE 和 LSI 提供动力;
-
PLLXTPRE 为预分频选择器,主要选择 不分频 或 /2,它和 HSI RC 8MHz(内部高速振荡器)的 /2 共同接入到了 PLLSRC ,由其选择使用外部时钟 HSE 还是内部时钟 HSI,再将时钟信号输入到 PLLMUL;
-
HSI RC 8MHz 不但有上述作用,flash 编程接口也是由其驱动的;
-
PLLMUL 为倍频器,最高倍频到 16,主要倍频 HSI 或 HSE,得到 PLLCLK,其可用作 USBCLK 的驱动源,一般预分频到 48 MHz;
-
CSS
-
SYSCLK 主要由 HSE、HSI 或 PLLCLK 提供,最大频率为 72 MHz;
-
I2S3、I2S2 都是由 SYSCLK 驱动的;
-
SYSCLK 主要为 AHB 总线提供驱动:
上图可以看到 AHB 系统总线主要与 SDIO、RCC、APB1 及 APB2 交互,且为它们提供时钟驱动。APB2 和 APB1 两个总线连接上图的片上外设;
- SYSCLK 会经过 AHB 预分频器(/1,…,/512),从而为其他总线提供时钟:
- 为 HCLK 提供时钟,频率最高为 72 MHz。HCLK 至 AHB BUS、core、memory 及 DMA 等;
- AHB/8 至 Cortex 系统定时器;
- AHB/1 也可直接为 FCLK Cortex *运行定时器提供驱动;
- APB1 总线的最大频率为 36 MHz,由此需要经由 APB1 预分频器分频(/1,2,4,8,16)。再由外设时钟使能得到 PCLK1 至 APB1 总线上的外设;
- APB2 总线的最大频率为 72 MHz,同样需要经由 APB2 预分频器分频(/1,2,4,8,16)。再由外设时钟使能得到 PCLK2 至 APB2 总线上的外设;
- APB2 总线的时钟频率在给 ADC 驱动时,需要先分频(/2,4,6,8),ADCCLK 最大频率为 14 MHz;
- AHB/2 经由外设时钟使能(HCLK/2),至 SDIO AHB 接口;
-
MCO(主时钟输出)由以下 4 个时钟源以供选择:
- PLLCLK
- HSI
- HSE
- SYSCLK
#include <stm32f10x.h>
// 设置向量表偏移地址
//NVIC_VectTab: 基址
//Offset: 偏移量
void MY_NVIC_SetVectorTable(u32 NVIC_VectTab, u32 Offset){
//设置NVIC的向量表偏移寄存器,用于标识向量表在CODE区还是RAM区
SCB->VTOR = NVIC_VectTab|(Offset & (u32)0x1FFFFF80);
}
// 系统初始的配置:主要用来配置向量表
void MYRCC_DeInit(void) {
RCC->APB1RSTR = 0x0000 0000; // No effect
RCC->APB2RSTR = 0x0000 0000;
// 初始是睡眠状态,打开闪存接口电路时钟使能(FLITFEN)和SRAM时钟使能(SRAMEN)
RCC->AHBENR = 0x0000 0014;
RCC->APB2ENR = 0x0000 0000;
RCC->APB1ENR = 0x0000 0000;
// 使能内部高速时钟HSI开始工作
RCC->CR |= RCC_CR_HSION;
// datasheet's note:先配置,再控制
// 配置RCC(复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]):SYSClock<--HSI(时钟树的SW处), SYSClock不分频,APB1和APB2也都不分频,ADC默认/2,PLL时钟源选择HSE(现在用不到), MCO:No Clock¸
RCC->CFGR &= 0xF8FF 0000;
// 关闭 HSE、PLL、CSS 使能
RCC->CR &= 0xFEF6FFFF;
// 在HSE未使能时,设置HSE晶振没有旁路
RCC->CR &= 0xFFFBFFFF;
// 复位 PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE
RCC->CFGR &= 0xFF80FFFF;
// 清除所有中断标志
RCC->CIR = 0x00000000;
// 配置向量表
#ifdef VECT_TAB_RAM
MY_NVIC_SetVectorTable(0x20000000, 0x0);
#else
MY_NVIC_SetVectorTable(0x08000000,0x0);
#endif
}
// stm32时钟的初始化
void Stm32_Clock_Init(u8 pll){
// 复位并配置向量表
MYRCC_DeInit();
// 使能HSEON
RCC->CR |= RCC_CR_HSEON;
// 等待 HSE 使能就绪:HSERDY == 1
while(!(RCC->CR>>17));
// APB1 = DIV2; APB2 = DIV1; AHB = DIV1
RCC->CFGR = (RCC_CFGR_PPRE1_DIV2 + RCC_CFGR_PPRE2_DIV1 + RCC_CFGR_HPRE_DIV1);
// PLLMUL[21:18] ====> 0000: PLL Clock x 2,所以要 -2.
PLL -= 2;
// 设置倍频,PLL = 9 即倍频到72MHz
RCC->CFGR |= PLL<<18;
// PLL Clock <--- HSE
RCC->CFGR |= RCC_CFGR_PLLSRC;
// ?? FLASH 两个延时周期
FLASH->ACR|=0x32;
// 使能PLL时钟
RCC->CR |= RCC_CR_PLLON;
// 等待PLL时钟就绪:PLLRDY == 1
while(!(RCC->CR>>25));
// 设置 PLL 为 SYSCLK
RCC->CFGR |= RCC_CFGR_SW_PLL;
// 等待SYSCLK设置就绪:SWS == 10 -- PLL
while(temp!=0x02)
{
temp = RCC->CFGR>>2;
temp &= 0x03;
}
}
上一篇: Android 购物车加减功能的实现代码
下一篇: 如何利用jQuery实现可以编辑的表格