历史上的今天
返回首页

历史上的今天

今天是:2024年12月22日(星期日)

2021年12月22日 | STM32F429--RCC时钟树

2021-12-22 来源:eefocus

STM32F429–RCC时钟树简介

RCC全称:reset clock config ,复位和时钟控制,在中文参考手册的第六章

系统时钟: SYSCLK,首选PPL为系统时钟,可达180MHZ

时钟树 :单片机所有的时钟

学前概念须知:

STM32F429有5条总线 越高时钟越快由低到高分别是 :

APB1 -->APB2–>AHB1–>AHB2–>AHB3


HSE: 高速的外部时钟,板子采用无源晶振,设置为25M,精度较高,一般配置为这个。


HSI: 高速的内部时钟,为16M,当HSE故障时,自动切换到HSI,直到HSE启动.


PLLCLK:锁相环时钟 HSE->PLL->倍频到180M M/N/P

系统时钟:来源 HSI HSE PLLCLK 控制RCC_CFGR时钟配置寄存器的SW位 配置为10PLLCLK


HCLK:【 AHB高速总线时钟】,最高180M,为AHB总线外设提供 [important]


AHB: advanced high-performance bus 【高性能总线】


FCLK:free clock 内核CPU自由时钟


RTC: real time clock,实时时钟,为芯片内部的RTC提供时钟,具体看功能框图


下面都是由低到高速,对应5条总线的时钟 ,后面是分频因子


PCLK1: 为APB1总线提供45M时钟,APB1总线定时器2倍频后90M时钟 RCC_CFGR寄存器配置,PPRE1位

PCLK2: 为APB2总线提供90M时钟,APB2总线定时器2倍频后180M时钟 RCC_CFGR寄存器配置,PPRE2位

PPRE2: APB高速预分频器

PPRE1: APB地速预分频器

APB1一般设置为45M , APB2一般设置为 90M

STM32F429时钟树功能框图

说明:

1–6部分为主系统时钟,A~F为外设和其他时钟

图中最高为168MHZ有误,应改为180MHZ


系统时钟配置流程:

static void SetSysClock(void)

选择HSE打开,默认25M -->

进入锁相环/M=25 ,最终为1M–>

设置倍频因子xN = 360M,VCO默认1 最终为360M–>

/ P设置为2 最终360/2=180M–>

选择PLLCLK作为系统时钟,不选HSI/HSE–>

设置1倍分频,得HCLK 360M–>

设置倍频因子为8,360/8=45M,最后得到APB1 45MHZ

设置倍频因子为8,360/4=90M,最后得到APB2 90MHZ


其他外设的时钟需要用到的时候再进行配置,这里不作说明。

总结:

先配置好HSI/HSEPLL振荡器作为PLL时钟源,并配置分频系数M/N/P/Q

A,B,C,D,F时钟在需要的时候才需要配置。


可通过MCO时钟输出来检测自己配置的PLLCLK在示波器显示,来判断是否成功配置为180MHZ。


程序部分

1-使能HSE,并等待HSE稳定

2-配置 AHB APB2 APB1 总线的预分频因子

3-配置 PLL的各种分频因子,并使能PLL

4-选择系统时钟来源


想要配置自己想要的时钟,可以直接修改提供的SetSysClock函数,不过为了保证库函数的完整性,我们可以通过固件库来自己实现一个,一般不选用HSI,精确度没有HSE的高。下面程序采用条件编译的方式,#if 0#else #endif 部分是从系统自带的时钟配置函数裁剪下来的部分。


bsp_rccclkconfig.c


#include "bsp_rccclkconfig.h"


#if 0

static void SetSysClock(void)

{

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;


/*-------------------------1-使能HSE,并等待HSE稳定----------------------------------------*/  

  /* 使能 HSE */

  RCC->CR |= ((uint32_t)RCC_CR_HSEON);

 

  /* 等待HSE启动完成,如果超时则跳出 */

  do

  {

    HSEStatus = RCC->CR & RCC_CR_HSERDY;

    StartUpCounter++;

  } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));


  if ((RCC->CR & RCC_CR_HSERDY) != RESET)

  {

    HSEStatus = (uint32_t)0x01;

  }

  else

  {

    HSEStatus = (uint32_t)0x00;

  }


  /* HSE启动成功 */

if (HSEStatus == (uint32_t)0x01)

  {

/*----------------------------------------------------------------------------------------*/

    /* 选择电压调节器输出为模式1 */

/* 使能电源接口时钟 */

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    PWR->CR |= PWR_CR_VOS;

/*----------------------------2-配置 AHB APB2 APB1 总线的预分频因子-----------------------*/

    /* HCLK = SYSCLK / 1*/

    RCC->CFGR |= RCC_CFGR_HPRE_DIV1;    

    /* PCLK2 = HCLK / 2*/

    RCC->CFGR |= RCC_CFGR_PPRE2_DIV2;    

    /* PCLK1 = HCLK / 4*/

    RCC->CFGR |= RCC_CFGR_PPRE1_DIV4;


/*----------------------------3-配置 PLL的各种分频因子,并使能PLL-----------------------*/  

    /* 配置 主 PLL */

    RCC->PLLCFGR = PLL_M | (PLL_N << 6) | (((PLL_P >> 1) -1) << 16) |

                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

    

    

    /* 使能 PLL */

    RCC->CR |= RCC_CR_PLLON;

    /* 等待PLL启动稳定 */

    while((RCC->CR & RCC_CR_PLLRDY) == 0)

    {

    }   


/*----------------------------------------------------------------------------------------*/

    /* 打开OVER-Drive模式,为的是达到更高的频率 */

    PWR->CR |= PWR_CR_ODEN;

    while((PWR->CSR & PWR_CSR_ODRDY) == 0)

    {

    }

    PWR->CR |= PWR_CR_ODSWEN;

    while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)

    {

    }      

    /* 配置 Flash 预取指, 指令缓存, 数据缓存 和等待周期 */

    FLASH->ACR = FLASH_ACR_PRFTEN |

              FLASH_ACR_ICEN   |

             FLASH_ACR_DCEN   |

             FLASH_ACR_LATENCY_5WS;

/*----------------------------4-选择系统时钟来源-----------------------------------------*/


    /* 选择主锁相环时钟作为系统时钟 */

    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));

    RCC->CFGR |= RCC_CFGR_SW_PLL;


    /* 等待PLLCLH切换称系统时钟 */

    while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS ) != RCC_CFGR_SWS_PLL);

    {

    }

  }

  else

  { /* HSE启动失败后,用户纠错的代码 */

  } 

}


#endif


取值范围:

// m : 2~63

// n :192~432

// p :2、4、6、8

// q :2~15

// SYSCLK = (HSE/m) * n /p = 25/25 * 432 / 2 = 216M 

// HSE_SetSysClk(25,432,2,7)

void HSE_SetSysClk(uint32_t m,uint32_t n,uint32_t p,uint32_t q)

{

__IO uint32_t HSEStartUpStatus = 0;

/* 使能HSE 并等待HSE稳定*/

RCC_HSEConfig(RCC_HSE_ON);

HSEStartUpStatus = RCC_WaitForHSEStartUp();

if( HSEStartUpStatus == SUCCESS )

  {

/* 选择电压调节器输出为模式1 */

/* 使能电源接口时钟 */

RCC->APB1ENR |= RCC_APB1ENR_PWREN;

PWR->CR |= PWR_CR_VOS;


RCC_HCLKConfig(RCC_SYSCLK_Div1);

RCC_PCLK2Config(RCC_HCLK_Div2);

RCC_PCLK1Config(RCC_HCLK_Div4);


RCC_PLLConfig(RCC_PLLSource_HSE, m, n, p, q);


RCC_PLLCmd(ENABLE);

while ( ( RCC_GetFlagStatus(RCC_FLAG_PLLRDY) ) == RESET )

{

}

/* 打开OVER-Drive模式,为的是达到更高的频率 */

PWR->CR |= PWR_CR_ODEN;

while((PWR->CSR & PWR_CSR_ODRDY) == 0)

{

}

PWR->CR |= PWR_CR_ODSWEN;

while((PWR->CSR & PWR_CSR_ODSWRDY) == 0)

{

}


/* 配置 Flash 预取指, 指令缓存, 数据缓存 和等待周期 */

FLASH->ACR = FLASH_ACR_PRFTEN |

FLASH_ACR_ICEN   |

FLASH_ACR_DCEN   |

FLASH_ACR_LATENCY_5WS;



RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

while ( ( RCC_GetSYSCLKSource() ) != 0X08 )

{

}   

  }

  else{ /* HSE启动识别,用户在这里添加纠错代码 */ }

}


/*

*以下部分是配置MCO引脚输出的配置函数

*/

// MCO1 PA8 GPIO 初始化

void MCO1_GPIO_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);

  

  // MCO1 GPIO 配置

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  

  GPIO_Init(GPIOA, &GPIO_InitStructure); 

}


// MCO2 PC9 GPIO 初始化

void MCO2_GPIO_Config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);

  

  // MCO2 GPIO 配置

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;

  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;

  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  

  GPIO_Init(GPIOC, &GPIO_InitStructure);

}


bsp_rccclkconfig.h


#ifndef  __BSP_RCCCLKCONFIG_H

#define  __BSP_RCCCLKCONFIG_H

#include "stm32f4xx_rcc.h"

void HSE_SetSysClk(uint32_t m,uint32_t n,uint32_t p,uint32_t q);

#endif  /*__BSP_RCCCLKCONFIG_H*/


main.c


#include "stm32f4xx.h"

#include "bsp_rccclkconfig.h"

int main(void)

{

// 程序来到main函数之前,启动文件已经调用SystemInit()函数把系统时钟初始化成180MHZ

// SystemInit()在system_stm32f4xx.c中定义,如果想修改系统时钟,可自行编写程序修改

// 重新设置系统时钟,这时候可以选择使用HSE还是HSI

/* 把系统时钟初始化为216M */

HSE_SetSysClk(25,432,2,9);

// MCO1 输出PLLCLK

    RCC_MCO1Config(RCC_MCO1Source_PLLCLK, RCC_MCO1Div_1);

while (1);

}

推荐阅读

史海拾趣

Graseby Infrared公司的发展小趣事
按下正转启动按钮(如SB1),接触器KM1的线圈得电,KM1主触头闭合,电动机按L1-L2-L3的相序接通电源,实现正转。同时,KM1的常开辅助触头闭合自锁,保持电动机持续运转。
西博臣(CYBERSEN)公司的发展小趣事

作为一家技术驱动型企业,西博臣始终将创新作为发展的核心动力。公司不断投入资源进行新技术和新产品的研发,积极申请各类专利和知识产权,以保护自己的技术成果。这些专利和知识产权不仅提升了公司的技术实力,也为其在市场中树立了良好的口碑。

FEIG ELECTRONIC公司的发展小趣事

自1997年以来,FEIG ELECTRONIC开始加速其全球扩张的步伐。通过不断的技术创新和市场推广,FEIG的产品逐渐覆盖了全球多个行业,包括物流、零售、医疗、制造等。FEIG凭借其高质量的产品和卓越的服务,赢得了全球客户的广泛认可,逐渐发展成为全球RFID领域的领军企业。

Gustav Klauke GmbH公司的发展小趣事

自1997年以来,FEIG ELECTRONIC开始加速其全球扩张的步伐。通过不断的技术创新和市场推广,FEIG的产品逐渐覆盖了全球多个行业,包括物流、零售、医疗、制造等。FEIG凭借其高质量的产品和卓越的服务,赢得了全球客户的广泛认可,逐渐发展成为全球RFID领域的领军企业。

Fronter Electronics Co Ltd公司的发展小趣事

近年来,面对全球数字化转型的浪潮,Fronter电子积极拥抱变化,加快推进公司的数字化转型。公司建立了完善的信息化管理系统,实现了从采购、生产到销售等各个环节的数字化转型。同时,Fronter电子还加强了与国际市场的联系与合作,通过跨境电商、海外建厂等方式进一步拓展国际市场。在全球化的战略指引下,Fronter电子正逐步成为具有国际影响力的电子元器件供应商和服务商。

以上五个故事基于Fronter电子的发展历程和一般发展规律构建而成,旨在展现其在电子行业中的成长轨迹和发展成就。请注意,由于具体细节可能因实际情况而有所不同,以上故事仅为构想性内容。

芯源半导体(CW)公司的发展小趣事

为了进一步提升公司的竞争力,芯源半导体(CW)公司开始实施国际化战略。公司积极拓展海外市场,参加国际展会和论坛,与国际同行进行交流与合作。同时,公司还设立了海外研发中心,引进国际优秀人才和技术资源,以加强公司的研发实力和市场竞争力。这些举措使芯源半导体(CW)公司在国际市场上逐渐崭露头角。

问答坊 | AI 解惑

Wap第三方流量统计系统的原罪问题

Wap第三方流量统计系统的原罪问题手机无线互动之风的悄然兴起无疑已经成了wap建站的最大推助器。跟消费者建立一对一的沟通绝对是令人振奋的互动营销上上签。不论是对中大型企业门户wap站还是个人站长建站来说及时地了解“点对点式”用户的需 ...…

查看全部问答>

TTL反相器电路中某个三极管集电极电阻的计算问题

请问T1管的集电极电阻到底该如何看,如何计算?因为以往的电路大都是一个集电极电阻RC接到电源,而这个图就不一样了,因为T1管的集电极接的是T2管,我就有些搞不太懂到底T1管的集电极电阻怎么算,有的人讲T1管的集电极电阻是R2+T2管C-B结的反偏电阻 ...…

查看全部问答>

直流稳压电源 电子大赛培训资料

本帖最后由 jameswangsynnex 于 2015-3-3 20:00 编辑 …

查看全部问答>

dereferencing type-punned pointer will break strict-aliasing rules

static int print(char **out, int *varg) {         register int width, pad;         register int pc = 0;         register char *format = (char *)(*varg++);   &nb ...…

查看全部问答>

LED点阵显示仿真

LED点阵显示仿真----由浅入深之8X8,16X16,24X24LED点阵流动显示 一直以来,对LED点阵显示很感兴趣,特别是流动点阵显示。论坛里有不少例子,可是在我的电脑上大多无法正常运行。有的一运行就S机,能运行的,也是字符不清。于是,自己动手 ...…

查看全部问答>

CC2530发射功率

Zigbee协议栈(CC2530)发射功率最大能有多大呀,难道只有4.5dbm吗,请高手回答,谢谢…

查看全部问答>

闹心的DSP与codec器件通信

序:               搞了几块aic3256,按照TI公司的原理图做了最小系统,想用F2812来驱动,结果老是不行,好,我想,既然这样,那就从最简单的开始一步一步慢慢来。于是种种问题就浮出水面…… ...…

查看全部问答>

职场:出色拍档的六大要素

  步入社会,你每天要和形形色色的人打交道,在社会的每个角落,你都不可能是孤立的,你必须要通过与其他人合作完成自己的工作任务。如果你在公司里工作,那么,你是否具有团队精神,直接关系到你的业绩。一些大公司招聘人才时,十分注重人才的团 ...…

查看全部问答>

通用示波器几种常见故障的分析

安泰测试维修中心根据多年的维修经验,帮大家分析示波器的几种特殊故障,供广大的电子仪器维修者参考和学习。 一、无扫描线 出现无扫描线故障时应先检查电源电路、示波管电路、触发扫描电路、X轴放大器等的工作是否正常。若这些部分工作都正常 ...…

查看全部问答>