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/128LSELSI 提供动力;

  • PLLXTPRE 为预分频选择器,主要选择 不分频/2,它和 HSI RC 8MHz(内部高速振荡器)的 /2 共同接入到了 PLLSRC ,由其选择使用外部时钟 HSE 还是内部时钟 HSI,再将时钟信号输入到 PLLMUL

  • HSI RC 8MHz 不但有上述作用,flash 编程接口也是由其驱动的;

  • PLLMUL 为倍频器,最高倍频到 16,主要倍频 HSIHSE,得到 PLLCLK,其可用作 USBCLK 的驱动源,一般预分频到 48 MHz;

  • CSS

  • SYSCLK 主要由 HSEHSIPLLCLK 提供,最大频率为 72 MHz;

  • I2S3I2S2 都是由 SYSCLK 驱动的;

  • SYSCLK 主要为 AHB 总线提供驱动:
    在这里插入图片描述

上图可以看到 AHB 系统总线主要与 SDIORCCAPB1APB2 交互,且为它们提供时钟驱动。APB2APB1 两个总线连接上图的片上外设;

  • SYSCLK 会经过 AHB 预分频器(/1,…,/512),从而为其他总线提供时钟:
  1. HCLK 提供时钟,频率最高为 72 MHz。HCLKAHB BUScorememoryDMA 等;
  2. AHB/8 至 Cortex 系统定时器;
  3. AHB/1 也可直接为 FCLK Cortex 自由运行定时器提供驱动;
  4. APB1 总线的最大频率为 36 MHz,由此需要经由 APB1 预分频器分频(/1,2,4,8,16)。再由外设时钟使能得到 PCLK1 至 APB1 总线上的外设;
  5. APB2 总线的最大频率为 72 MHz,同样需要经由 APB2 预分频器分频(/1,2,4,8,16)。再由外设时钟使能得到 PCLK2 至 APB2 总线上的外设;
  6. APB2 总线的时钟频率在给 ADC 驱动时,需要先分频(/2,4,6,8),ADCCLK 最大频率为 14 MHz;
  7. 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;
	}
}
发布了47 篇原创文章 · 获赞 52 · 访问量 2万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章