stm32的时钟系统rcc详细整理(转) -ag凯发k8国际
一、综述:
1、时钟源
在 stm32 中,一共有 5 个时钟源,分别是 hsi 、 hse 、 lsi 、 lse 、 pll 。
①hsi 是高速内部时钟, rc 振荡器,频率为 8mhz ;
②hse 是高速外部时钟,可接石英 / 陶瓷谐振器,或者接外部时钟源,频率范围是 4mhz – 16mhz ;
③lsi 是低速内部时钟, rc 振荡器,频率为 40khz ;
④lse 是低速外部时钟,接频率为 32.768khz 的石英晶体;
⑤pll 为锁相环倍频输出,严格的来说并不算一个独立的时钟源, pll 的输入可以接 hsi/2 、 hse 或者 hse/2 。pll倍频可选择为 2 – 16 倍,但是其输出频率最大不得超过 72mhz 。
其中, 40khz 的 lsi 供独立看门狗 iwdg 使用,另外它还可以被选择为实时时钟 rtc 的时钟源。另外,实时时钟 rtc 的时钟源还可以选择 lse ,或者是 hse 的 128 分频。
stm32 中有一个全速功能的 usb 模块,其串行接口引擎需要一个频率为 48mhz 的时钟源。该时钟源只能从 pll 端获取,可以选择为 1.5 分频或者 1 分频,也就是,当需使用到 usb 模块时, pll 必须使能,并且时钟配置为 48mhz 或 72mhz 。
另外 stm32 还可以选择一个时钟信号输出到 mco 脚 (pa.8) 上,可以选择为 pll 输出的 2 分频、 hsi 、 hse 或者系统时钟。
系统时钟 sysclk ,它是提供 stm32 中绝大部分部件工作的时钟源。系统时钟可以选择为 pll 输出、 hsi 、 hse 。系系统时钟最大频率为 72mhz ,它通过 ahb 分频器分频后送给各个模块使用, ahb 分频器可以选择 1 、 2 、 4 、 8 、 16 、 64 、 128 、 256 、 512 分频,ahb分频器输出的时钟送给 5 大模块使用:
①送给 ahb 总线、内核、内存和 dma 使用的 hclk 时钟;②通过 8 分频后送给 cortex 的系统定时器时钟stclk;③直接送给 cortex 的空闲运行时钟 fclk ;④送给 apb1 分频器。 apb1 分频器可以选择 1 、 2 、 4 、 8 、 16 分频,其输出一路供 apb1 外设使用( pclk1 ,最大频率 36mhz ),另一路送给定时器 (timer)2 、 3 、 4 倍频器使用。该倍频器根据pclk1的分频值自动选择 1 或者 2 倍频,时钟输出供定时器 2 、 3 、 4 使用。⑤送给 apb2 分频器。 apb2 分频器可以选择 1 、 2 、 4 、 8 、 16 分频,其输出一路供 apb2 外设使用( pclk2 ,最大频率 72mhz ),另外一路送给定时器 (timer)1 倍频使用。该倍频器根据pclk2的分频值自动选择1 或 2 倍频,时钟输出供定时器 1 使用。另外 apb2 分频器还有一路输出供 adc 分频器使用,分频后送给 adc 模块使用。 adc 分频器可选择为 2 、 4 、 6 、 8 分频。需要注意的是定时器的倍频器,当 apb 的分频为 1 时,它的倍频值为 1 ,否则它的倍频值就为 2 。
2、apb1和apb2连接的模块
①连接在 apb1( 低速外设 ) 上的设备有:电源接口、备份接口、 can 、 usb 、 i2c1 、 i2c2 、 uart2 、 uart3 、 spi2 、窗口看门狗、 timer2 、 timer3 、 timer4 。 注意 usb 模块虽然需要一个单独的 48mhz 的时钟信号,但是它应该不是供 usb 模块工作的时钟,而只是提供给串行接口引擎 (sie) 使用的时钟。 usb 模块的工作时钟应该是由 apb1 提供的。
②连接在 apb2 (高速外设)上的设备有: uart1 、 spi1 、 timer1 、 adc1 、 adc2 、 gpiox(pa~pe) 、第二功能 io 口。
二、寄存器介绍:
typedef struct
{
__io uint32_t cr;
__io uint32_t cfgr;
__io uint32_t cir;
__io uint32_t apb2rstr;
__io uint32_t apb1rstr;
__io uint32_t ahbenr;
__io uint32_t apb2enr;
__io uint32_t apb1enr;
__io uint32_t bdcr;
__io uint32_t csr;
__io uint32_t ahbrstr;
__io uint32_t cfgr2;
uint32_t reserved0;
__io uint32_t cfgr2;
} rcc_typedef;
1、时钟控制寄存器(rcc_cr):(复位值为0x0000 xx83,内部低速时钟使能和就绪,内部时钟校准)
主要功能:内外部高速时钟的使能和就绪标志(含内部高速时钟校准调整),外部高速时钟旁路,时钟安全系统css使能,pll使能和pll就绪标志。
2、时钟配置寄存器(rcc_cfgr):(复位值为0x0000 0000)
主要功能:系统时钟源切换及状态,ahb、apb1、apb2、adc、usb预分频,pll输入时钟源选择及hse输入pll分频选择,pll倍频系数,mco(pa8)引脚微控制器时钟输出。
3、时钟中断寄存器 (rcc_cir):(复位值: 0x0000 0000)
主要功能:lsi、lse、his、hse、pll就绪中断标志,hse时钟失效导致时钟安全系统中断标志,lsi、lse、his、hse、pll就绪中断使能,清除lsi、lse、his、hse、pll就绪中断,清除时钟安全系统中断。
4、apb2外设复位寄存器 (rcc_apb2rstr):(复位值: 0x0000 0000)
主要功能:afio、iopa、iopb、iopc、iopd、iope、iopf、iopg、adc1、adc2、tim1、spi1、tim8、usart1、adc3复位。
5、apb1外设复位寄存器 (rcc_apb1rstr) :(复位值: 0x0000 0000)
主要功能:tim2、tim3、tim4、tim5、tim6、tim7、wwdg、spi2、spi3、usart2、usart3、usart4、usart5、i2c1、i2c2、usb、can、bkp、pwr、dac复位。
6、ahb外设时钟使能寄存器 (rcc_ahbenr) :(复位值: 0x0000 0014睡眠模式时sram、闪存接口电路时钟开启)
主要功能:dma1、dma2、sram、flitf、crc、fsmc、sdio时钟使能。
7、apb2外设时钟使能寄存器(rcc_apb2enr) :(复位值: 0x0000 0000)
主要功能:afio、iopa、iopb、iopc、iopd、iope、iopf、iopg、adc1、adc2、tim1、spi1、tim8、usart1、adc3时钟使能。
8、apb1外设时钟使能寄存器(rcc_apb1enr) :(复位值: 0x0000 0000)
主要功能:tim2、tim3、tim4、tim5、tim6、tim7、wwdg、spi2、spi3、usart2、usart3、usart4、usart5、i2c1、i2c2、usb、can、bkp、pwr、dac时钟使能。
9、备份域控制寄存器 (rcc_bdcr) :(复位值: 0x0000 0000)
主要功能:外部低速振荡器使能和就绪标志及旁路、rtc时钟源选择和时钟使能、备份域软件复位。
10、控制/状态寄存器 (rcc_csr) :(复位值: 0x0c00 0000 nrst引脚复位标志、上电/掉电复位标志)
主要功能:内部低速振荡器就绪、清除复位标志、nrst引脚复位标志、上电/掉电复位标志、软件复位标志、独立看门狗复位标志、窗口看门狗复位标志、低功耗复位标志。
三、初始化设置
采用8mhz 外部hse 时钟,在 mdk 编译平台中,程序的时钟设置参数流程如下:
将 rcc 寄存器重新设置为默认值:rcc_deinit();打开外部高速时钟晶振 hse : rcc_hseconfig(rcc_hse_on);等待外部高速时钟晶振工作: hsestartupstatus = rcc_waitforhsestartup();设置 ahb 时钟 (hclk) : rcc_hclkconfig(rcc_sysclk_div1);设置apb 2时钟 (apb2) : rcc_pclk2config(rcc_hclk_div1);设置apb1 时钟 (apb1) : rcc_pclk1config(rcc_hclk_div2);设置 pll : rcc_pllconfig(rcc_pllsource_hse_div1, rcc_pllmul_9); 打开 pll : rcc_pllcmd(enable);等待 pll 工作: while(rcc_getflagstatus(rcc_flag_pllrdy) == reset);设置系统时钟: rcc_sysclkconfig(rcc_sysclksource_pllclk);
判断 pll 是否是系统时钟: while(rcc_getsysclksource() != 0x08);
1、使用库函数进行时钟系统初始化配置
void rcc_config()//如果外部晶振为8m,pllclk=sysclk=72m,hclk=72m,//p2clk=72m,p1clk=36m,adcclk=36m,usbclk=48m,timclk=72m
{
errorstatus hsestartupstatus; // 定义错误状态变量rcc_deinit();//将rcc寄存器重新设置为默认值rcc_hseconfig(rcc_hse_on); //打开外部高速时钟晶振hsestartupstatus = rcc_waitforhsestartup();// 等待外部高速时钟晶振工作if(hsestartupstatus == success){rcc_hclkconfig(rcc_sysclk_div1);//设置ahb不分频,hclk=sysclkrcc_pclk2config(rcc_hclk_div1);//设置apb2不分频,p2clk=hclkrcc_pclk1config(rcc_hclk_div2); //设置apb1 为2分频,p1clk=hclk/2flash_setlatency(flash_latency_2);//设置flash代码延时flash_prefetchbuffercmd(flash_prefetchbuffer_enable);//使能预取指缓存rcc_pllconfig(rcc_pllsource_hse_div1, rcc_pllmul_9);//设置pll时钟源,//外部时钟不分频,为hse的9倍频8mhz * 9 = 72mhz
rcc_pllcmd(enable);//使能pll
}
2、使用寄存器进行rcc时钟初始化配置
void rcc_init(u8 pll)//输入pll的倍频值2—16倍频
//hclk=pllclk=sysclk=p2clk=p1clk*2=adcclk*2=timclk=usbclk*2/3
{
unsigned char temp=0; //rcc_deinit(); //将rcc寄存器重新设置为默认值rcc->cr|=0x00010000; //外部高速时钟使能hseonwhile(!(rcc->cr>>17));//等待外部时钟就绪rcc->cfgr=0x00000400; //apb1=div2;apb2=div1;ahb=div1;pll-=2;//抵消2个单位rcc->cfgr|=pll<<18; //设置pll倍频值 2~16rcc->cfgr|=1<<16; //pll时钟源选择flash->acr|=0x32; //flash 2个延时周期rcc->cr|=0x01000000; //pllonwhile(!(rcc->cr>>25));//等待pll锁定rcc->cfgr|=0x00000002;//pll作为系统时钟 while(temp!=0x02) //等待pll作为系统时钟设置成功{ temp=rcc->cfgr>>2;temp&=0x03;}}
四、相关库函数解析
1、库中所涉及到的结构体
typedef struct
{
uint32_t sysclk_frequency; /!< returns sysclk clock frequency expressed in hz /
uint32_t hclk_frequency; /!< returns hclk clock frequency expressed in hz /
uint32_t pclk1_frequency; /!< returns pclk1 clock frequency expressed in hz /
uint32_t pclk2_frequency; /!< returns pclk2 clock frequency expressed in hz /
uint32_t adcclk_frequency; /!< returns adcclk clock frequency expressed in hz /
}rcc_clockstypedef;
2、库函数解析
void rcc_deinit(void);//将外设rcc寄存器设为缺省值;(除rcc_bdcr和rcc_csr)
void rcc_hseconfig(uint32_t rcc_hse);//设置外部高速晶振(hse);
//输入:rcc_hse_off,rcc_hse_on,rcc_hse_bypass(hse旁路)
errorstatus rcc_waitforhsestartup(void);//等待hse起振;
//返回值:success,hse晶振稳定且就绪;error,hse晶振未就绪
void rcc_adjusthsicalibrationvalue(uint8_t hsicalibrationvalue);//调整内部高速晶振(hsi)校准值
//输入:校准补偿值(该参数取值必须在0到0x1f之间)
void rcc_hsicmd(functionalstate newstate);//使能或者失能内部高速晶振(hsi)
//输入:enable或者disable(如果hsi被用于系统时钟,或者flash编写操作进行中,那么它不能被停振)
void rcc_pllconfig(uint32_t rcc_pllsource, uint32_t rcc_pllmul);//设置pll时钟源及倍频系数
//输入:rcc_pllsource_hsi_div2,rcc_pllsource_hse_div1,rcc_pllsource_hse_div2
//输入:rcc_pllmul_2到rcc_pllmul_16
void rcc_pllcmd(functionalstate newstate);// 使能或者失能pll
//输入:enable或者disable
void rcc_prediv1config(uint32_t rcc_prediv1_source, uint32_t rcc_prediv1_div);//
void rcc_prediv2config(uint32_t rcc_prediv2_div);//
void rcc_pll2config(uint32_t rcc_pll2mul);//
void rcc_pll2cmd(functionalstate newstate);//
void rcc_pll3config(uint32_t rcc_pll3mul);//
void rcc_pll3cmd(functionalstate newstate);//
void rcc_sysclkconfig(uint32_t rcc_sysclksource);//设置系统时钟(sysclk)源
// rcc_sysclksource_hsi,rcc_sysclksource_hse,rcc_sysclksource_pllclk
uint8_t rcc_getsysclksource(void);// 返回用作系统时钟的时钟源
//返回值:0x00 hsi作为系统时钟,0x04 hse作为系统时钟,0x08 pll作为系统时钟
void rcc_hclkconfig(uint32_t rcc_sysclk);//设置ahb时钟(hclk)
//输入:rcc_sysclk_div1,rcc_sysclk_div2,rcc_sysclk_div4,rcc_sysclk_div8,rcc_sysclk_div16,
//rcc_sysclk_div32,rcc_sysclk_div64,rcc_sysclk_div128,rcc_sysclk_div256,rcc_sysclk_div512
void rcc_pclk1config(uint32_t rcc_hclk);// 设置低速ahb时钟(pclk1)
//输入: rcc_hclk_div1, rcc_hclk_div2, rcc_hclk_div4, rcc_hclk_div8, rcc_hclk_div16
void rcc_pclk2config(uint32_t rcc_hclk);// 设置高速ahb时钟(pclk2)
//输入:rcc_hclk_div1, rcc_hclk_div2, rcc_hclk_div4, rcc_hclk_div8, rcc_hclk_div16
void rcc_itconfig(uint8_t rcc_it, functionalstate newstate);// 使能或者失能指定的rcc中断
//输入:rcc_it_lsirdy lsi就绪中断->enable或者disable
//rcc_it_lserdy lse就绪中断,rcc_it_hsirdy hsi就绪中断
//rcc_it_hserdy hse就绪中断,rcc_it_pllrdy pll就绪中断
void rcc_usbclkconfig(uint32_t rcc_usbclksource);// 设置usb时钟(usbclk)
//输入:rcc_usbclksource_pllclk_1div5,usb时钟 = pll时钟除以1.5
rcc_usbclksource_pllclk_div1,usb时钟 = pll时钟
void rcc_otgfsclkconfig(uint32_t rcc_otgfsclksource);//
void rcc_adcclkconfig(uint32_t rcc_pclk2);// 设置adc时钟(adcclk)
//rcc_pclk2_div2,adc时钟 = pclk / 2;rcc_pclk2_div4,adc时钟 = pclk / 4;
//rcc_pclk2_div6,adc时钟 = pclk / 6;rcc_pclk2_div8,adc时钟 = pclk / 8
void rcc_i2s2clkconfig(uint32_t rcc_i2s2clksource); //
void rcc_i2s3clkconfig(uint32_t rcc_i2s3clksource);//
void rcc_lseconfig(uint8_t rcc_lse);// 设置外部低速晶振(lse)
//输入:rcc_lse_off,lse晶振off;rcc_lse_on,lse晶振on;
//rcc_lse_bypass,lse晶振被外部时钟旁路
void rcc_lsicmd(functionalstate newstate);// 使能或者失能内部低速晶振(lsi)
//输入:enable或者disable (iwdg运行的话,lsi不能被失能)
void rcc_rtcclkconfig(uint32_t rcc_rtcclksource);//设置rtc时钟(rtcclk)源(rtc时钟一经选定即不能更改,除非复位后备域)
//输入:rcc_rtcclksource_lse,选择lse作为rtc时钟;rcc_rtcclksource_lsi,选择lsi作为rtc时钟;rcc_rtcclksource_hse_div128,选择hse时钟频率除以128作为rtc时钟
void rcc_rtcclkcmd(functionalstate newstate);// 使能或者失能rtc时钟
//输入:enable或者disable
void rcc_getclocksfreq(rcc_clockstypedef* rcc_clocks);// 返回时钟的频率
//输入:指向结构rcc_clockstypedef的指针,包含了各个时钟的频率(单位为hz)
void rcc_ahbperiphclockcmd(uint32_t rcc_ahbperiph, functionalstate newstate);// 使能或者失能ahb外设时钟
//输入:rcc_ahbperiph_dma,dma时钟->enable或者disable;
//rcc_ahbperiph_sram,sram时钟;rcc_ahbperiph_flitf,flitf时钟
//rcc_ahbperiph_dma1,dma1时钟;rcc_ahbperiph_dma2,dma2时钟
//rcc_ahbperiph_crc,crc时钟;rcc_ahbperiph_fsmc,fsmc时钟
//rcc_ahbperiph_sdio,sdio时钟
void rcc_apb2periphclockcmd(uint32_t rcc_apb2periph, functionalstate newstate);// 使能或者失能apb2外设时钟
//输入:rcc_apb2periph_afio,功能复用io时钟->enable或者disable;
//rcc_apb2periph_gpioa,gpioa时钟;rcc_apb2periph_gpiob,gpiob时钟;
//rcc_apb2periph_gpioc,gpioc时钟;rcc_apb2periph_gpiod,gpiod时钟;
//rcc_apb2periph_gpioe,gpioe时钟;rcc_apb2periph_adc1,adc1时钟;
//rcc_apb2periph_adc2,adc2时钟;rcc_apb2periph_tim1,tim1时钟;
//rcc_apb2periph_spi1,spi1时钟;rcc_apb2periph_usart1,usart1时钟;
//rcc_apb2periph_all,全部apb2外设时钟
void rcc_apb1periphclockcmd(uint32_t rcc_apb1periph, functionalstate newstate);// 使能或者失能apb1外设时钟
//输入:rcc_apb1periph_tim2,tim2时钟->enable或者disable;
//rcc_apb1periph_tim3,tim3时钟;rcc_apb1periph_tim4,tim4时钟
//rcc_apb1periph_wwdg,wwdg时钟;rcc_apb1periph_spi2,spi2时钟
//rcc_apb1periph_usart2,usart2时钟;rcc_apb1periph_usart3,usart3时钟
//rcc_apb1periph_i2c1,i2c1时钟;rcc_apb1periph_i2c2,i2c2时钟
//rcc_apb1periph_usb,usb时钟;rcc_apb1periph_can,can时钟
//rcc_apb1periph_bkp,bkp时钟;rcc_apb1periph_pwr,pwr时钟
//rcc_apb1periph_all,全部apb1外设时钟
void rcc_ahbperiphresetcmd(uint32_t rcc_ahbperiph, functionalstate newstate);//
void rcc_apb2periphresetcmd(uint32_t rcc_apb2periph, functionalstate newstate);// 强制或者释放高速apb(apb2)外设复位
//输入:同void rcc_apb2periphclockcmd(uint32_t rcc_apb2periph, functionalstate newstate);函数的值
void rcc_apb1periphresetcmd(uint32_t rcc_apb1periph, functionalstate newstate);// 强制或者释放低速apb(apb1)外设复位
//输入:同void rcc_apb1periphclockcmd(uint32_t rcc_apb1periph, functionalstate newstate);函数的值
//例:/* enter the spi1 peripheral to reset */
//rcc_apb2periphresetcmd(rcc_apb2periph_spi1, enable);
/* exit the spi1 peripheral from reset */
//rcc_apb2periphresetcmd(rcc_apb2periph_spi1, disable);
void rcc_backupresetcmd(functionalstate newstate);// 强制或者释放后备域复位
void rcc_clocksecuritysystemcmd(functionalstate newstate);//使能或者失能时钟安全系统
//输入:enable或者disable
void rcc_mcoconfig(uint8_t rcc_mco);// 选择在mco管脚上输出的时钟源
//输入:rcc_mco_noclock 无时钟被选中 ;rcc_mco_sysclk 选中系统时钟;
//rcc_mco_hsi 选中hsi ;rcc_mco_hse 选中hse ;
//rcc_mco_pllclk_div2 选中pll时钟除以2
//警告:当选中系统时钟作为mco管脚的输出时,注意它的时钟频率不超过50mhz(最大i/o速率)。
flagstatus rcc_getflagstatus(uint8_t rcc_flag);// 检查指定的rcc标志位设置与否
//输入:待检查的rcc标志位
//rcc_flag_hsirdy ,hsi晶振就绪;rcc_flag_hserdy ,hse晶振就绪;
//rcc_flag_pllrdy ,pll就绪;rcc_flag_lserdy ,lsi晶振就绪;
//rcc_flag_lsirdy ,lse晶振就绪;rcc_flag_pinrst ,管脚复位 ;
//rcc_flag_porrst ,por/pdr复位;rcc_flag_sftrst ,软件复位 ;
//rcc_flag_iwdgrst ,iwdg复位;rcc_flag_wwdgrst ,wwdg复位;
//rcc_flag_lpwrrst ,低功耗复位
//返回值:rcc_flag的新状态(set或者reset)
//例:/* test if the pll clock is ready or not */
//flagstatus status;
//status = rcc_getflagstatus(rcc_flag_pllrdy);
//if(status == reset)
//{
//…
//}
//else
void rcc_clearflag(void);// 清除rcc的复位标志位
//(可以清除的复位标志位有:rcc_flag_pinrst, rcc_flag_porrst, //rcc_flag_sftrst, rcc_flag_iwdgrst, rcc_flag_wwdgrst, rcc_flag_lpwrrst)
itstatus rcc_getitstatus(uint8_t rcc_it);// 检查指定的rcc中断发生与否
//输入:rcc_it_lsirdy,lsi晶振就绪中断;rcc_it_lserdy,lse晶振就绪中断
//rcc_it_hsirdy,hsi晶振就绪中断;rcc_it_hserdy,hse晶振就绪中断
//rcc_it_pllrdy,pll就绪中断;rcc_it_css,时钟安全系统中断
//返回值:rcc_it的新状态
//例:
/* test if the pll ready interrupt has occurred or not */
//itstatus status;
//status = rcc_getitstatus(rcc_it_pllrdy);
//if(status == reset)
//{
//…
//}
//else
//{
//…
//}
void rcc_clearitpendingbit(uint8_t rcc_it);// 清除rcc的中断待处理位
//rcc_it_lsirdy,lsi晶振就绪中断;rcc_it_lserdy,lse晶振就绪中断
//rcc_it_hsirdy,hsi晶振就绪中断;rcc_it_hserdy,hse晶振就绪中断
//rcc_it_pllrdy,pll就绪中断;rcc_it_css,时钟安全系统中断
五、实例详解
/* #define sysclk_freq_hse hse_value */
#define sysclk_freq_24mhz 24000000
/* #define sysclk_freq_hse hse_value */
/* #define sysclk_freq_24mhz 24000000 */
/* #define sysclk_freq_36mhz 36000000 */
/* #define sysclk_freq_48mhz 48000000 */
/* #define sysclk_freq_56mhz 56000000 */
/只需修改以上几句就可以自动设置使用外部倍频作为系统时钟,如果以上宏都未定义则在下边把内部高速时钟作为系统时钟/
/*!< uncomment the following line if you need to use external sram mounted
on stm3210e-eval board (stm32 high density and xl-density devices) or on
stm32100e-eval board (stm32 high-density value line devices) as data memory */
/* #define data_in_extsram */
/*!< uncomment the following line if you need to relocate your vector table in
internal sram. */
/* #define vect_tab_sram */
/*********************************************************************
* clock definitions;以下为把系统时钟的定义值传给系统内核时钟变量,如果没有定义外部高速时钟则用内部高速时钟,为8m
*********************************************************************/
uint32_t systemcoreclock = sysclk_freq_hse; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = sysclk_freq_24mhz; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = sysclk_freq_36mhz; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = sysclk_freq_48mhz; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = sysclk_freq_56mhz; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = sysclk_freq_72mhz; /!< system clock frequency (core clock) /
uint32_t systemcoreclock = hsi_value; /!< system clock frequency (core clock) 如果没有定义外部高速时钟则用内部高速时钟,为8000000/
__i uint8_t ahbpresctable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};//ahb配方表
/**
* @}
*/
/** @addtogroup stm32f10x_system_private_functionprototypes
* @{
*/
/***********************************************************************
以下为函数声明
***********************************************************************/
static void setsysclock(void); //设置系统时钟的函数声明
//以下为根据不同的系统时钟的定义来声明用到的相应的函数,为后面的函数调用做好准备
static void setsysclocktohse(void);
static void setsysclockto24(void);
static void setsysclockto36(void);
static void setsysclockto48(void);
static void setsysclockto56(void);
static void setsysclockto72(void);
static void systeminit_extmemctl(void);
/**
* @}
*/
/** @addtogroup stm32f10x_system_private_functions
* @{
*/
/**
* @brief setup the microcontroller system
* initialize the embedded flash interface, the pll and update the
* systemcoreclock variable.
* @note this function should be used only after reset.
* @param none
* @retval none
*/
void systeminit (void)//系统初始化函数,设置系统的时钟及时钟中断(在startup_stm32f10x_md.s中调用)(复位rcc时钟配置为默认状态,直到设置时钟函数)
{
/* reset the rcc clock configuration to the default reset state(for debug purpose) */
/* set hsion bit */
rcc->cr |= (uint32_t)0x00000001; //内部高速时钟使能,内部8mhz时钟开启
/* reset sw, hpre, ppre1, ppre2, adcpre and mco bits */
rcc->cfgr &= (uint32_t)0xf8ff0000;//mco微控制器没有时钟输出(对外部引脚),adc预分频pclk2 2分频后作为adc时钟,apb预分频hclk不分频,ahb预分频sysclk不分频,hsi作为系统时钟
//hsi作为系统时钟输出(已输出),sysclk=pclk=pclk1=pclk2=8m,adcclk=1/2(pclk2)=4m
rcc->cfgr &= (uint32_t)0xf0ff0000;//同上;rcc->cfgr的27位为保留位始终为0 ,hsi作为系统时钟输出(未输出原因为未编译)
/* reset hseon, csson and pllon bits */
rcc->cr &= (uint32_t)0xfef6ffff;//时钟监测器关闭,hse振荡器关闭
/* reset hsebyp bit */
rcc->cr &= (uint32_t)0xfffbffff;//外部4-25mhz振荡器没有旁路
/* reset pllsrc, pllxtpre, pllmul and usbpre/otgfspre bits */
rcc->cfgr &= (uint32_t)0xff80ffff; //pll时钟1.5倍分频作为usb时钟,pll 2倍频输出,hse不分频,hsi时钟2分频后作为pll输入时钟
//pllclk=hsiclk=8m(还未输出),hseclk=hseosc,usbclk=pllclk/1.5 ,除pll外其他分频系数都为0
/* reset pll2on and pll3on bits */
rcc->cr &= (uint32_t)0xebffffff;//cr中的26和28位置0
/* disable all interrupts and clear pending bits */
rcc->cir = 0x00ff0000;//清除中断标志,关闭一些中断
/* reset cfgr2 register */
rcc->cfgr2 = 0x00000000; //没有此寄存器
/* disable all interrupts and clear pending bits */
rcc->cir = 0x009f0000;//清除中断标志,关闭一些中断
/* reset cfgr2 register */
rcc->cfgr2 = 0x00000000; //没有此寄存器
/* disable all interrupts and clear pending bits */
rcc->cir = 0x009f0000; //清除中断标志,关闭一些中断
#ifdef data_in_extsram
systeminit_extmemctl();//如果宏定义了外部sram则对其初始化控制
#endif /* data_in_extsram */
/* configure the system clock frequency, hclk, pclk2 and pclk1 prescalers */
/* configure the flash latency cycles and enable prefetch buffer */
setsysclock();//设置系统时钟
scb->vtor = sram_base | vect_tab_offset; /* vector table relocation in internal sram. 向量表放在内部sram中*/
scb->vtor = flash_base | vect_tab_offset; /* vector table relocation in internal flash. 向量表放在内部flash中*/
}
/**
* @brief update systemcoreclock according to clock register values
* @note none
* @param none
* @retval none
*/
void systemcoreclockupdate (void)
{
uint32_t tmp = 0, pllmull = 0, pllsource = 0;
uint32_t prediv1source = 0, prediv1factor = 0, prediv2factor = 0, pll2mull = 0;
uint32_t prediv1factor = 0;
/* get sysclk source ——————————————————-*/
tmp = rcc->cfgr & rcc_cfgr_sws;
switch (tmp)
{
case 0x00: /* hsi used as system clock */
systemcoreclock = hsi_value;
break;
case 0x04: /* hse used as system clock */
systemcoreclock = hse_value;
break;
case 0x08: /* pll used as system clock */
/* get pll clock source and multiplication factor ———————-*/
pllmull = rcc->cfgr & rcc_cfgr_pllmull;
pllsource = rcc->cfgr & rcc_cfgr_pllsrc;
#if defined (stm32f10x_ld_vl) || defined (stm32f10x_md_vl) || (defined stm32f10x_hd_vl)
prediv1factor = (rcc->cfgr2 & rcc_cfgr2_prediv1) 1;
/* hse oscillator clock selected as prediv1 clock entry */
systemcoreclock = (hse_value / prediv1factor) * pllmull;
#else
/* hse selected as pll clock entry */
if ((rcc->cfgr & rcc_cfgr_pllxtpre) != (uint32_t)reset)
{/* hse oscillator clock divided by 2 */
systemcoreclock = (hse_value >> 1) * pllmull;
}
else
{
systemcoreclock = hse_value * pllmull;
}
#endif
}
}
/* compute hclk clock frequency —————-*/
/* get hclk prescaler */
tmp = ahbpresctable[((rcc->cfgr & rcc_cfgr_hpre) >> 4)];
/* hclk clock frequency */
systemcoreclock >>= tmp;
}
/**
* @brief configures the system clock frequency, hclk, pclk2 and pclk1 prescalers.
* @param none
* @retval none
*/
static void setsysclock(void)//根据不同的宏定义,设置不同的系统时钟
{
setsysclocktohse();
setsysclockto24();
setsysclockto36();
setsysclockto48();
setsysclockto56();
setsysclockto72();
/* if none of the define above is enabled, the hsi is used as system clock
source (default after reset) */
}
/**
* @brief setup the external memory controller. called in startup_stm32f10x.s
* before jump to __main
* @param none
* @retval none
*/
/**
* @brief setup the external memory controller.
* called in startup_stm32f10x_xx.s/.c before jump to main.
* this function configures the external sram mounted on stm3210e-eval
* board (stm32 high density devices). this sram will be used as program
* data memory (including heap and stack).
* @param none
* @retval none
*/
void systeminit_extmemctl(void)
{
/*!< fsmc bank1 nor/sram3 is used for the stm3210e-eval, if another bank is
required, then adjust the register addresses */
/* enable fsmc clock */
rcc->ahbenr = 0x00000114;
/* enable gpiod, gpioe, gpiof and gpiog clocks */
rcc->apb2enr = 0x000001e0;
/* ————— sram data lines, noe and nwe configuration —————*/
/—————- sram address lines configuration ————————-/
/—————- noe and nwe configuration ——————————–/
/—————- ne3 configuration —————————————-/
/—————- nbl0, nbl1 configuration ———————————/
gpiod->crl = 0x44bb44bb;
gpiod->crh = 0xbbbbbbbb;
gpioe->crl = 0xb44444bb;
gpioe->crh = 0xbbbbbbbb;
gpiof->crl = 0x44bbbbbb;
gpiof->crh = 0xbbbb4444;
gpiog->crl = 0x44bbbbbb;
gpiog->crh = 0x44444b44;
/—————- fsmc configuration —————————————/
/—————- enable fsmc bank1_sram bank ——————————/
fsmc_bank1->btcr[4] = 0x00001011;
fsmc_bank1->btcr[5] = 0x00000200;
}
/**
* @brief selects hse as system clock source and configure hclk, pclk2
* and pclk1 prescalers.
* @note this function should be used only after reset.
* @param none
* @retval none
*/
static void setsysclocktohse(void)
{
__io uint32_t startupcounter = 0, hsestatus = 0;
/* sysclk, hclk, pclk2 and pclk1 configuration —————————*/
/* 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)
{
{
flash->acr |= (uint32_t)flash_acr_latency_0;
}
else
{
flash->acr |= (uint32_t)flash_acr_latency_1;
}
}
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 */
}
}
static void setsysclockto72(void)//系统时钟设置为72m:sysclk=72m,hclk=72m,pclk1=36m(最高36m),pclk2=72m,adcclk=36m,
{
__io uint32_t startupcounter = 0, hsestatus = 0;//启动计数,hse状态
/* sysclk, hclk, pclk2 and pclk1 configuration —————————*/
/* enable hse */
rcc->cr |= ((uint32_t)rcc_cr_hseon);//hse使能
/* wait till hse is ready and if time out is reached exit */
do //循环,直到hse使能成功或者超时
{
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;//hse使能成功
}
else
{
hsestatus = (uint32_t)0x00;//hse使能不成功
}
if (hsestatus == (uint32_t)0x01)//hse使能成功
{
/* enable prefetch buffer */
flash->acr |= flash_acr_prftbe;//flash缓存使能
/* flash 2 wait state */
flash->acr &= (uint32_t)((uint32_t)~flash_acr_latency);//
flash->acr |= (uint32_t)flash_acr_latency_2;//
}
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 */
}
}
总结
以上是ag凯发k8国际为你收集整理的stm32的时钟系统rcc详细整理(转)的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: void gpio_init(gpio_
- 下一篇: