欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32 时钟设置

程序员文章站 2022-06-09 08:28:37
...

时钟设置

时钟树介绍

有以下三种时钟可以作为系统时钟(SYSCLK):

  • HSI 振荡器时钟
  • HSE 振荡器时钟
  • PLL 时钟

时钟树如下:
STM32 时钟设置

  • 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 总线提供驱动:
    STM32 时钟设置

上图可以看到 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;
	}
}
相关标签: stm32 时钟