您的位置:首页 > 其它

stm32 RCC 时钟分析

2015-03-21 17:04 435 查看
stm32芯片手册上有张图表示的很清楚,一共有4个时钟源:

1.HSI(内部高速时钟 8MHz)提供可以位系统时钟提供时钟源

2.HSE(外部高速时钟)可以提供系统时钟和RTC时钟时钟源

3.LSE(低速外部时钟32.768kHz)可以为可以为RTC提供时钟源

4.LSI(低速内部时钟)可以为独立看门狗提供时钟源

首先分析一下ST公司给的库函数:我用的是3.5的库

我们看看SystemInit里是什么

void SystemInit (void)

{

RCC->CR |= (uint32_t)0x00000001;
//打开HSI内部高速时钟

#ifndef STM32F10X_CL

RCC->CFGR &= (uint32_t)0xF8FF0000;//CFCG寄存器的27位没用,所以这个宏没用

#else //MCO的两位清零,不往外输出时钟,0-15位清零,PLCK 2分频给ADC,HCLK不分频给APB2

RCC->CFGR &= (uint32_t)0xF0FF0000;//HCLK不分频给APB1,sysclk不分频给AHB,HSI用作系统时钟,

#endif /* STM32F10X_CL */



/* Reset HSEON, CSSON and PLLON bits */

RCC->CR &= (uint32_t)0xFEF6FFFF; //HSE禁用

/* Reset HSEBYP bit */

RCC->CR &= (uint32_t)0xFFFBFFFF;//外部高速时钟未被旁路

/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */

RCC->CFGR &= (uint32_t)0xFF80FFFF; //PLL 1.5分频,给USBpre,PLLMUL *2,HSE未分频做PLL输入HSI/2做PLL输入

#ifdef STM32F10X_CL

/* Reset PLL2ON and PLL3ON bits */

RCC->CR &= (uint32_t)0xEBFFFFFF;//

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x00FF0000;//禁止所有中断,清中断标志位

/* Reset CFGR2 register */

RCC->CFGR2 = 0x00000000;

#elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x009F0000;

/* Reset CFGR2 register */

RCC->CFGR2 = 0x00000000;

#else

/* Disable all interrupts and clear pending bits */

RCC->CIR = 0x009F0000;

#endif /* STM32F10X_CL */



#if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)

#ifdef DATA_IN_ExtSRAM

SystemInit_ExtMemCtl();

#endif /* DATA_IN_ExtSRAM */

#endif

/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */

/* Configure the Flash Latency cycles and enable prefetch buffer */

SetSysClock();//最终调用时钟设置函数,下面分析

#ifdef VECT_TAB_SRAM

SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /*中断向量表定位在SRAM_BASE(0X20000000)+VECT_TAB_OFFSET(0X0)处*/

#else

SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /*中断向量表定位在FLASH_BASE(0X08000000)+VECT_TAB_OFFSET(0X0)处 */

#endif

}

下面看看SetSysClock()函数

static void SetSysClock(void)

{

#ifdef SYSCLK_FREQ_HSE

SetSysClockToHSE();

#elif defined SYSCLK_FREQ_24MHz

SetSysClockTo24();

#elif defined SYSCLK_FREQ_36MHz

SetSysClockTo36();

#elif defined SYSCLK_FREQ_48MHz

SetSysClockTo48();

#elif defined SYSCLK_FREQ_56MHz

SetSysClockTo56();

#elif defined SYSCLK_FREQ_72MHz

SetSysClockTo72();

#endif



/* 如果上面没有一个宏成立,则HSI用作系统时钟源,一般调用SetSysClockTo72()函数*/

}

static void SetSysClockTo72(void)

{

__IO uint32_t StartUpCounter = 0, HSEStatus = 0; //__IO uint32_t即vu32



/* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/

/* Enable HSE */

RCC->CR |= ((uint32_t)RCC_CR_HSEON); // RCC_CR_HSEON((uint32_t)0x00010000) HSE使能



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

do

{

HSEStatus = RCC->CR & RCC_CR_HSERDY;//RCC_CR_HSERDY((uint32_t)0x00020000) 测试HSE状态

StartUpCounter++; //计数等待

} while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut)); //当计数 > HSEStartUp_TimeOut(0x500)时且HSE可用则跳出

if ((RCC->CR & RCC_CR_HSERDY) != RESET) //如果HSE可用

{

HSEStatus = (uint32_t)0x01; //HSEStatus置1

}

else

{

HSEStatus = (uint32_t)0x00; //HSEStatus置0

}

if (HSEStatus == (uint32_t)0x01) //当hse可以用时

{

/* Enable Prefetch Buffer */

FLASH->ACR |= FLASH_ACR_PRFTBE;

/* Flash 2 wait state */

FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);

FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;



/* HCLK = SYSCLK */

RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //HCLK等于系统时钟



/* PCLK2 = HCLK */

RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//APB高速预分频为HCLK



/* PCLK1 = HCLK */

RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;//APB高低速预分频为HCLK/2

#ifdef STM32F10X_CL

/* Configure PLLs ------------------------------------------------------*/ //没有PLL2

/* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */

/* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */



RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |

RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);

RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |

RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV3);



/* Enable PLL2 */

RCC->CR |= RCC_CR_PLL2ON;

/* Wait till PLL2 is ready */

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

{

}





/* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */

RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |

RCC_CFGR_PLLMULL9);

#else

/* PLL configuration: PLLCLK = HSE * 9 = 72 MHz */ //PLL9倍频==72MHz

RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |

RCC_CFGR_PLLMULL));

RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);

#endif /* STM32F10X_CL */

/* Enable PLL */

RCC->CR |= RCC_CR_PLLON; //使能PLL

/* Wait till PLL is ready */

while((RCC->CR & RCC_CR_PLLRDY) == 0) //等待PLL准备好

{

}



/* Select PLL as system clock source */ //设置系统时钟为PLL时钟源

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

RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;

/* Wait till PLL is used as system clock source */ //等待系统时钟准备好

while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)

{

}

}

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

/* Go to infinite loop */

while (1) //如果HSE不能用,则跳入死循环

{

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: