历史上的今天
返回首页

历史上的今天

今天是:2024年10月13日(星期日)

正在发生

2018年10月13日 | STM32F407系统时钟解析

2018-10-13 来源:eefocus

STM32F407系统时钟解析


STM32F4时钟系统初始化是在system_stm32f4xx.c中的SystemInit()函数中完成的。对于系统时钟关键寄存器设置主要是在SystemInit函数中调用SetSysClock()函数来设置的。我们可以先看看SystemInit()函数体:

//@brief  Setup the microcontroller system

//        Initialize the Embedded Flash Interface, the PLL and update the

//        SystemFrequency variable.

//@param  None

//@retval None

void SystemInit(void)

{

  // FPU settings ------------------------------------------------------------

  #if (__FPU_PRESENT == 1) && (__FPU_USED == 1)

    SCB->CPACR |= ((3UL << 10*2)|(3UL << 11*2));  // set CP10 and CP11 Full Access

  #endif

 

  // Reset the RCC clock configuration to the default reset state ------------

  // Set HSION bit

  RCC->CR |= (uint32_t)0x00000001;

 

  // Reset CFGR register

  RCC->CFGR = 0x00000000;

 

  // Reset HSEON, CSSON and PLLON bits

  RCC->CR &= (uint32_t)0xFEF6FFFF;

 

  // Reset PLLCFGR register

  RCC->PLLCFGR = 0x24003010;

 

  // Reset HSEBYP bit

  RCC->CR &= (uint32_t)0xFFFBFFFF;

 

  // Disable all interrupts

  RCC->CIR = 0x00000000;

 

#ifdef DATA_IN_ExtSRAM

  SystemInit_ExtMemCtl();

#endif // DATA_IN_ExtSRAM

         

  // Configure the System clock source, PLL Multiplier and Divider factors,

     AHB/APBx prescalers and Flash settings ----------------------------------

  SetSysClock();

 

  // Configure the Vector Table location add offset address ------------------

#ifdef VECT_TAB_SRAM

  SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; // Vector Table Relocation in Internal SRAM

#else

  SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; // Vector Table Relocation in Internal FLASH

#endif

}

  SystemInit函数开始先进行浮点运算单元设置,然后是复位PLLCFGR,CFGR寄存器,同时通过设置CR寄存器的HSI时钟使能位来打开HSI时钟。默认情况下如果CFGR寄存器复位,那么是选择HSI作为系统时钟,这点大家可以查看RCC->CFGR寄存器的位描述最低2位可以得知,当低两位配置为00的时候(复位之后),会选择HSI振荡器为系统时钟。也就是说,调用SystemInit函数之后,首先是选择HSI作为系统时钟。

在设置完相关寄存器后,接下来SystemInit函数内部会调用SetSysClock函数。这个函数比较长,我们就把函数一些关键代码行截取出来给大家讲解一下。这里我们省略一些宏定义标识符值的判断而直接把针对STM32F407比较重要的内容贴出来:

//@brief  Configures the System clock source, PLL Multiplier and Divider factors,

//        AHB/APBx prescalers and Flash settings

//@Note   This function should be called only once the RCC clock configuration  

//        is reset to the default reset state (done in SystemInit() function).   

//@param  None

//@retval None

static void SetSysClock(void)

{

//////////////////////////////////////////////////////////////////////////

//          PLL (clocked by HSE) used as System clock source            //

//////////////////////////////////////////////////////////////////////////

  __IO uint32_t StartUpCounter = 0, HSEStatus = 0;

  

  // Enable HSE

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

 

  // Wait till HSE is ready and if Time out is reached exit

  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;

  }

 

  if (HSEStatus == (uint32_t)0x01)

  {

// Select regulator voltage output Scale 1 mode, System frequency up to 168 MHz

    RCC->APB1ENR |= RCC_APB1ENR_PWREN;

    PWR->CR |= PWR_CR_VOS;

 

    // 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;

 

    // Configure the main PLL

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

                   (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

 

    // Enable the main PLL

    RCC->CR |= RCC_CR_PLLON;

 

    // Wait till the main PLL is ready

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

    {

    }

   

    // Configure Flash prefetch, Instruction cache, Data cache and wait state

    FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;

 

    // Select the main PLL as system clock source

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

    RCC->CFGR |= RCC_CFGR_SW_PLL;

 

    // Wait till the main PLL is used as system clock source

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

    {

    }

  }

  else

  {

        // If HSE fails to start-up, the application will have wrong clock

        // configuration. User can add here some code to deal with this error

  }

}

  这段代码的大致流程是这样的:先使能外部时钟HSE,等待HSE稳定之后,配置AHB,APB1,APB2时钟相关的分频因子,也就是相关外设的时钟。等待这些都配置完成之后,打开主PLL时钟,然后设置主PLL作为系统时钟SYSCLK时钟源。如果HSE不能达到就绪状态(比如外部晶振不能稳定或者没有外部晶振),那么依然会是HSI作为系统时钟。

  在这里要特别提出来,在设置主PLL时钟的时候,会要设置一系列的分频系数和倍频系数参数。大家可以从SetSysClock函数的这行代码看出:

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

          (RCC_PLLCFGR_PLLSRC_HSE) | (PLL_Q << 24);

这些参数是通过宏定义标识符的值来设置的。默认的配置在System_stm32f4xx.c文件开头的地方配置。对于我们开发板,我们的设置参数值如下:

    #define PLL_M      8

    #define PLL_Q      7

    #define PLL_N      336

    #define PLL_P       2

所以我们的主PLL时钟为:

    PLL=8MHz * N/ (M*P)=8MHz* 336/(8*2) = 168MHz

在开发过程中,我们可以通过调整这些值来设置我们的系统时钟。

这里还有个特别需要注意的地方,就是我们还要同步修改stm32f4xx.h中宏定义标识符HSE_VALUE的值为我们的外部时钟:

#if !defined  (HSE_VALUE)

#define HSE_VALUE    ((uint32_t)8000000)  //Value of the External oscillator in Hz

 

#endif   // HSE_VALUE

这里默认固件库配置的是25000000,我们外部时钟为8MHz,所以我们根据我们硬件情况修改为8000000即可。

最后我们总结一下SystemInit()函数中设置的系统时钟大小:

     SYSCLK(系统时钟)             =168MHz

    AHB总线时钟(HCLK=SYSCLK)           =168MHz

    APB1总线时钟(PCLK1=SYSCLK/4)                            =42MHz

    APB2总线时钟(PCLK2=SYSCLK/2)                            =84MHz

    PLL主时钟                  =168MHz


推荐阅读

史海拾趣

Bombardier Inc公司的发展小趣事

随着全球航空市场的不断变化,庞巴迪公司在商用航空领域也取得了显著成就。其生产的CRJ系列区域喷气客机和Q系列涡桨飞机在全球范围内广受欢迎。这些飞机配备了先进的电子设备和系统,提供了更高的安全性和舒适性。庞巴迪还推出了C系列单通道中距客机,该机型以其环保、经济和人性化的设计赢得了市场的广泛认可。

柯爱亚(ceaiya)公司的发展小趣事

为了保持技术领先地位,柯爱亚不断加大研发投入,引进先进的研发设备和人才。公司在功率电感、变压器等领域取得了多项技术成果,并申请了多项专利。这些技术成果不仅提升了柯爱亚产品的竞争力,还推动了整个电子行业的发展。

Futaba Electric Co Ltd公司的发展小趣事

作为一家有社会责任感的企业,柯爱亚积极参与各种公益活动。公司不仅捐款捐物支持灾区重建、教育事业等公益事业,还组织员工参与志愿者活动,为社会做出了积极贡献。这些行为展现了柯爱亚作为一家优秀企业的社会担当和良好形象。

请注意,以上故事框架仅供参考,具体内容需要根据柯爱亚公司的实际发展历程进行编写。

E Connector Solutions公司的发展小趣事

随着公司业务的不断发展,E Connector Solutions公司开始积极拓展市场。公司通过参加国际展会、与海外客户建立合作关系等方式,逐步打开了国际市场的大门。同时,公司还积极实施国际化战略,通过设立海外研发中心、生产基地等方式,加强与全球客户的合作与交流。这些举措不仅拓宽了公司的业务范围,还提升了公司的国际竞争力。

Electroswitch公司的发展小趣事

随着市场竞争的加剧,Electroswitch意识到仅仅依靠产品质量已经不足以赢得市场。因此,公司开始注重提升服务质量,为客户提供更加全面和专业的支持。通过加强售前咨询、售后服务以及技术支持等方面的投入,Electroswitch成功赢得了客户的信任和忠诚。这也使得公司在电子行业中的地位得到了进一步提升。

方向电子公司的发展小趣事

随着市场竞争的加剧,Electroswitch意识到仅仅依靠产品质量已经不足以赢得市场。因此,公司开始注重提升服务质量,为客户提供更加全面和专业的支持。通过加强售前咨询、售后服务以及技术支持等方面的投入,Electroswitch成功赢得了客户的信任和忠诚。这也使得公司在电子行业中的地位得到了进一步提升。

问答坊 | AI 解惑

在Keil C51 uVision3 中调试w77E58如何设置才能使用片上的1K外部存贮器呀?

伟福V8仿真调试Winbond77E58不能正常使用片上1K外部存贮器的问题: 我用伟福V8/L仿真调试Winbond77E58板子, W77E58有片上1K外部存贮器,我不知是我的编译环境设置不对, 还是伟福不能仿真片上1K外部存贮器?在下面的程序中,将 int xdata i ...…

查看全部问答>

嵌入式程序运行时,硬件CPU空闲多少算正常状态?

嵌入式程序运行时,硬件CPU空闲多少算正常状态? ppc MPC8541 VxWorks…

查看全部问答>

ucosII上开发pdf查看应用程序

想在ucosII上开发一款pdf查看程序(平台君正 Xburst MIPS jz4740),现有Foxit Embedded PDF SDK可惜不免费!!!!!!!!! 总不能从头开发吧,难度太了点吧!!可有免费的库!!!推荐一个!!…

查看全部问答>

VS2005 调试问题

vs2005 编译发布成功,但弹出“unable to start debugging”这个问题怎么解决呢?先感谢各位回帖者,谢谢…

查看全部问答>

嵌入式技术

安徽省信息产业厅唯一指定的嵌入式实训基地落到合肥市,其培训的课程体系主要是ARM+Linux课程体系 嵌入式系统的基本概念及软硬件开发过程 ARM体系结构及指令 嵌入式集成开发工具ADS的集成开发 LPC2000系列原理及基于LPC2000系列的系统构成 L ...…

查看全部问答>

应届毕业生如何进军华为?

应届毕业生如何进军华为? 有没有在华为工作的前辈? 请指点指点,万分感谢!!!!…

查看全部问答>

【求助】74HC165的操作,只能控制一个按键,其他的控制不了,搞不明白

#define PL P2_3//SHIFT/LOAD引脚 #define CLOCK P2_4 #define SETBSC P2_5//OUTPUT QH引脚 read74hc165m() {uchar basic,c; PL=1; nop(); PL=0;//使能端为低电平时8位数据进入寄存器 nop(); PL=1;//高电平数据锁存,同时165数据自动 ...…

查看全部问答>

實用應急便攜手電棒

個人思路是這樣的:      可家用也可探險用。    加防水防塵防摔用於潮濕水等惡劣環境    可使用1~3個LED,以便節能。即使用調光也可以。但電池電壓降到9伏特以下呢?充分利用電池。低電時可手搖發電。 &n ...…

查看全部问答>

申请LM3S8962

三 书包小帮手  它的功能简单,却有很大的用处。我们大学生常常忘记星期几上什么课,几点上,教室在哪儿,老师的名字,电话等。它就像一个学习小管家,功能简单,外形小巧,可以放进书包上的挂饰,娃娃等,它采用防水功能。 它有个显示 ...…

查看全部问答>