3.STM32F429时钟系统配置方法


在前几篇文章中我想把一些基础的部分简单总结一下:首先是前两篇文章,学习一个mcu就要先对它的外设有初步的理解,还有要使用的HAL库,它相当于我们的代码与硬件之间连接的桥梁;这篇博客会总结一下429时钟树的一些知识,还有时钟配置函数;再之后可能还会总结基于SysTick的延时函数、程序执行流程、中断、DMA等。

1.时钟系统

1.1.时钟源

F429有5个时钟源:HSI,HSE,LSI,LSE,PLL(PLL,PLLI2S,PLLSAI)。HSI,HSE,PLL是高速时钟,LSI,LSE是低速时钟。HSE,LSE是外部时钟源。

  1. LSI是低速内部时钟,32kHz左右RC振荡器,独立看门狗和自动唤醒单元。
  2. LSE是低速外部时钟,32.768kHz石英晶体,RTC 的时钟源。
  3. HSE是高速外部时钟,4MHz~26MHz,板子是25M。可以做为系统时钟或PLL输入。
  4. HSI是高速内部时钟,16MHz,系统时钟或PLL输入。仅需几个微秒就能启动,但是精度差。当HSE故障时,HSI是备用时钟。
  5. PLL主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件,共有3个PLL:
    a) 主PLL由HSE或者HSI提供时钟信号,有两个不同的输出时钟。第一个PLLCLK用于生成高速的系统时钟(最高180MHz)。第二个PLLQ为48M,用于USB OTG FS,随机数发生器和SDIO时钟。
    b) PLLI2S在I2S和SAI1上实现高品质音频
    c) PLLSAI用于SAI输入时钟,LCD_TFT接口时钟。

1.2.系统时钟SYSCLK计算

在这里插入图片描述
主PLL时钟来若自HSE,也就是25MHz的外部晶振,先经过分频系数为M的分频器,再经过倍频系数为N的倍频器,还需要经过分频系数为 P(第一个输出 PLLP)或者 Q(第二个输出 PLLQ)的分频器分频之后,最后生成最终的主PLL时钟。我们设置M=25,N=360,P=2,则生成的高速时钟 PLLP(也就是PLLCLK)为180MHz。下图为在CubeMX中配置主时钟,HSE可以由有源或无源晶振或提供。当使用有源晶振时,时钟从OSC_IN进入,OSC_OUT 悬空;选用无源晶振时,时钟从OSC_IN 和 OSC_OUT进入,并且要配谐振电容。
在这里插入图片描述
在这里插入图片描述
但是 USB OTG FS的情况比较特殊,必须使用 48M,Q=VCO输出时钟360/48=7.5,出现了小数这明显是错误。野火教程中将N设为336,PLLCLK=VCOCLK/2=168M,USBCLK=336/7=48M,也就是PLLCLK降频了。正点原子教程中选择超频的方法,设N=432,USBCLK=432/9=48M,此时PLLCLK=216MHz。

1.3.AHB和APB总线时钟

AHB总线时钟HCLk由SYSCLK经AHB预分频器分频后得到,分频系数由RCC_CFGR的HPRE 位设置,设为1分频,即HCLK=SYSCLK=180M。AHB上的外设有FSMC,RNG,DCMI,USB OTG FS,USB OTG HS,以太网MAC,DMA,SRAM,Flash,RCC,CRC,GPIO。
APB1总线时钟PCLK1由HCLK经低速APB预分频器得到,分频系数由RCC_CFGR 的PPRE1位设置,配置PCLK1=HCLK/4=45M。总线上的外设有UART2/3/4/5/7/8,DAC,PWR,CAN1/2,I2C1/2/3,I2S2/3,SPI2/3,RTC,TIM2/3/4/5/6/7/12/13/14。
APB2总线时钟PCLK2由HCLK经高速APB2预分频器得到,由RCC_CFGR的PPRE2位设置。PCLK2=HCLK/2=90M。总线上的外设有SPI1/4/5/6,TIM1/8/9/10/11,EXTI,SYSCFG,ADC1/2/3,USART1/6。
在这里插入图片描述

1.4.其它时钟

  1. 独立看门狗时钟源只能是低速LSI,32kHz左右。
  2. RTC 时钟源可以选择 LSI,LSE,以及HSE分频后的时钟(通过 RCC_BDCR选择),一般选择 LSE,即外部32.768Khz。
  3. MCO1和MCO2分别是向PA8和PC9输出时钟。MCO1的四个时钟来源分别为:HSI/LSE/HSE/PLL;MCO2的四个时钟来源分别为:HSE/PLL/SYSCLK/PLLI2S,最大不超过100MHz。
  4. I2S时钟源可以是PLLI2S_R 时钟或外部时钟I2S_CKIN(通过寄存器I2SSRC选择),原子的教程播放音频用的SAI,没用I2S。
  5. LCD-TFT(LTDC)接口时钟唯一来源是PLLSAI_R。
  6. SAI1_A的时钟,通过寄存器SAI1ASRC选择内部PLLSAI_Q、PLLI2S_Q或外部I2SCKIN作为时钟。原子教程使用SAI1_A驱动 WM8978,时钟来自PLLSAI_Q。
  7. LTDC的时钟固定为PLLSAI_R。
  8. Systick的时钟源可以是AHB时钟HCLK或HCLK/8。

2.时钟配置函数

2.1.SystemInit函数

该函数在system_stm32f4xx.c中实现,在启动文件startup_stm32f429xx.s中被调用。SystemInit主要做了如下四个方面工作:

  1. FPU设置。
  2. 复位RCC时钟配置为默认复位值(默认开启HIS),即配置系统时钟为16MHz,没有像标准库的SystemInit一样进行时钟的初始化配置。
  3. 外部存储器配置。
  4. 中断向量表地址配置。
void SystemInit(void)
{
	/* FPU 设置------------------------------------------------------------*/
	#if (__FPU_PRESENT == 1) && (__FPU_USED == 1)
		SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2)); /* set CP10 and CP11 Full Access */
	#endif
	/* 复位 RCC 时钟配置为默认配置-----------*/
	RCC->CR |= (uint32_t)0x00000001;//打开 HSION 位
	RCC->CFGR = 0x00000000;//复位 CFGR 寄存器
	RCC->CR &= (uint32_t)0xFEF6FFFF;//复位 HSEON, CSSON and PLLON 位
	RCC->PLLCFGR = 0x24003010; //复位寄存器 PLLCFGR
	RCC->CR &= (uint32_t)0xFFFBFFFF;//复位 HSEBYP 位
	RCC->CIR = 0x00000000;//关闭所有中断
	#if defined (DATA_IN_ExtSRAM) || defined (DATA_IN_ExtSDRAM)
		SystemInit_ExtMemCtl();
	#endif /* DATA_IN_ExtSRAM || DATA_IN_ExtSDRAM */
	/* 配置中断向量表地址=基地址+偏移地址 ------------------*/
	#ifdef VECT_TAB_SRAM
		SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET;
	#else
		SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET;
	#endif
}

2.2.Stm32_Clock_Init函数

该函数除了配置SYSCLK值外,还配置了AHB,APB1和APB2的分频系数,也就是确定了HCLK,PCLK1和PCLK2的时钟值,是正点原子教程里的时钟初始化函数,在HAL_Init()之后调用。

void Stm32_Clock_Init(u32 plln,u32 pllm,u32 pllp,u32 pllq)
{
    HAL_StatusTypeDef ret = HAL_OK;
    RCC_OscInitTypeDef RCC_OscInitStructure; 
    RCC_ClkInitTypeDef RCC_ClkInitStructure;
    
    __HAL_RCC_PWR_CLK_ENABLE(); //使能PWR时钟
    
    //下面这个设置用来设置调压器输出电压级别,以便在器件未以最大频率工作
    //时使性能与功耗实现平衡,此功能只有STM32F42xx和STM32F43xx器件有,
    __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);//设置调压器输出电压级别1
    
    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    //时钟源为HSE
    RCC_OscInitStructure.HSEState=RCC_HSE_ON;                      //打开HSE
    RCC_OscInitStructure.PLL.PLLState=RCC_PLL_ON;//打开PLL
    RCC_OscInitStructure.PLL.PLLSource=RCC_PLLSOURCE_HSE;//PLL时钟源选择HSE
    RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
    RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍频系数(PLL倍频),取值范围:64~432.  
    RCC_OscInitStructure.PLL.PLLP=pllp; //系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
    RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.
    ret=HAL_RCC_OscConfig(&RCC_OscInitStructure);//初始化
	
    if(ret!=HAL_OK) while(1);
    
    ret=HAL_PWREx_EnableOverDrive(); //开启Over-Driver功能
    if(ret!=HAL_OK) while(1);
    
    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;//AHB分频系数为1
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; //APB1分频系数为4
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; //APB2分频系数为2
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5);//同时设置FLASH延时周期为5WS,也就是6个CPU周期。
		
    if(ret!=HAL_OK) while(1);
}

该函数步骤如下:

  1. 使能PWR时钟:调用__HAL_RCC_PWR_CLK_ENABLE()。
  2. 设置调压器输出电压级别:调用__HAL_PWR_VOLTAGESCALING_CONFIG()。
  3. 选择是否开启Over-Driver功能:调用函数 HAL_PWREx_EnableOverDrive()。
  4. 配置时钟源相关参数,配置好后调用函数 HAL_RCC_OscConfig()。
  5. 配置系统时钟源以及AHB,APB1和APB2的分频系数,配置好后调用函数HAL_RCC_ClockConfig()。

2.3.一些汇编指令

//关闭所有中断(但是不包括fault和NMI中断)
__asm void INTX_DISABLE(void)
{
	CPSID   I
	BX      LR	  
}
//开启所有中断
__asm void INTX_ENABLE(void)
{
	CPSIE   I
	BX      LR  
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr) 
{
	MSR MSP, r0 			//set Main Stack value
	BX r14
}
发布了4 篇原创文章 · 获赞 12 · 访问量 1306

猜你喜欢

转载自blog.csdn.net/weixin_41898804/article/details/105107823
今日推荐