STM32时钟初始化函数SysInit详解

合集下载

stm32启动文件详解及SystemInit函数分析

stm32启动文件详解及SystemInit函数分析
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
; External Interrupts
DCD WWDG_IRQHandler ; Window Watchdog
DCD PVD_IRQHandler ; PVD through EXTI Line detect
DCD TAMPER_IRQHandler ; Tamper
DCD RTC_IRQHandler ; RTC
DCD FLASH_IRQHandler ; Flash
;__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。
Stack_Size EQU 0x00000400 ;//定义堆栈大小
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0
;链接器检查要求堆栈八字节对齐的任何代码是否仅由保持堆栈八字节对齐的代码直接或间接地调用。
PRESERVE8 ;//指示编译器8字节对齐
Байду номын сангаас THUMB ;//指示编译器以后的指令为THUMB指令
;中断向量表定义
; Vector Table Mapped to Address 0 at Reset
;中断函数仅仅实现了Reset_Handler,其他要么是死循环,要么仅仅定义了函数名称
;STM32被设置为从内部FLASH启动时(这也是最常见的一种情况),当STM32遇到复位信号后,

STM32入门教程系统时钟SysTick

STM32入门教程系统时钟SysTick

STM32入门教程系统时钟SysTickSTM32 入门教程系统时钟 SysTick(一) 背景介绍在传统的嵌入式系统软件按中通常实现 Delay(N) 函数的方法为:for(i = 0; i <= x; i ++);x --- 对应于对应于 N 毫秒的循环值对于STM32系列微处理器来说,执行一条指令只有几十个ns,进行 for 循环时,要实现 N 毫秒的 x 值非常大,而且由于系统频率的宽广,很难计算出延时 N 毫秒的精确值。

针对 STM32 微处理器,需要重新设计一个新的方法去实现该功能,以实现在程序中使用Delay(N)。

(二) STM32 SysTick 介绍Cortex-M3 的内核中包含一个 SysTick 时钟。

SysTick 为一个 24 位递减计数器,SysTick 设定初值并使能后,每经过 1 个系统时钟周期,计数值就减 1。

计数到 0 时,SysTick 计数器自动重装初值并继续计数,同时内部的COUNTFLAG 标志会置位,触发中断(如果中断使能情况下)。

在 STM32 的应用中,使用 Cortex-M3 内核的 SysTick 作为定时时钟,设定每一毫秒产生一次中断,在中断处理函数里对N 减一,在Delay(N) 函数中循环检测 N 是否为 0,不为 0 则进行循环等待;若为0 则关闭 SysTick 时钟,退出函数。

注:全局变量 TimingDelay , 必须定义为 volatile 类型 , 延迟时间将不随系统时钟频率改变。

(三) ST SysTick 库文件使用ST的函数库使用systick的方法1、调用SysTick_CounterCmd() -- 失能SysTick计数器2、调用SysTick_ITConfig () -- 失能SysTick中断3、调用SysTick_CLKSourceConfig() -- 设置SysTick时钟源。

4、调用SysTick_SetReload() -- 设置SysTick重装载值。

STM32时钟总结剖析

STM32时钟总结剖析

STM32时钟总结一、时钟基本概念 (2)二、时钟树 (7)三、STM32上电后时钟的过程. (7)3.1 执行SystemInit ()函数 (7)3.2 执行SetSysClock()函数. (8)3.3 执行SetSysClockTo72()函数 (8)3.3.2 判断外部高速时钟源是否稳定 (8)3.3.4 FLASH 配置. (9)3.3.5 系统时钟配置是HCLK,PCLK2为HCLK,PCLK1为HCLK的一半93.3.6 配置PLL 在这里修改倍频值。

RCC_CFGR_PLLMUL9L 93.3.7 失能PLL;判断PLL是否Readay;选择PLL 为系统时钟,一直等到时钟稳定 (9)四、时钟源的选择 (10)4.1 系统默认配置时钟8*9=72M (10)4.2 配置HSI(高速内部时钟)为系统主时钟(永远不变8M)104.3 配置HSE为系统主时钟。

8M(和外部晶振有关)114.4 配置PLLCLK为系统主时钟. (11)4.5 程序 (11)五、配置HCLK,PCLK,1 PCLK2. (11)、时钟基本概念钟。

当时钟源被直接或通过PLL间接作为系统时钟时,它将不能被停止。

稳定阶段的延迟或PLL 稳定),从一个时钟源到另一个时钟源的切换才会发生。

在被选择时钟源没有就绪时,系统时钟的切换不会发生。

直至目标时钟源就绪,才发生切换。

时钟安全系统(CSS)时钟安全系统可以通过软件被激活。

一旦其被激活,时钟监测器将在HSE振荡器启动延迟后被使能,并在HSE时钟关闭后关闭。

如果HSE时钟发生故障,HSE 振荡器被自动关闭,时钟失效事件将被送到高级定时器TIM1的刹车输入端,并产生时钟安全中断CSSI,允许软件完成营救操作。

此CSSI中断连接到Cortex ?M3的NMI中断。

一旦CSS被激活,并且HSE时钟出现故障,CSS中断就产生,并且NMI 也自动产生。

NMI 将被不断执行,直到CSS中断挂起位被清除。

STM32单片机Systick函数的使用方法

STM32单片机Systick函数的使用方法

STM32单片机Systick函数的使用方法STM32单片机Systick函数的使用方法在“嵌入式学习006_Systick使用(一)”中,详细介绍了SysTIck中寄存器的使用方法,用到了很多函数,实际上到了3.5版本的标准固件库中,移除了相关驱动函数,用户必须调用CMSIS.h中定义的函数,其中CMSIS只提供了一个SysTIck设置的函数,替代了STM32原来有的所有的驱动函数,这样做的目的,可能是简化SysTIck 的设置,可是降低了用户对SysTIck的可控性。

在CMSIS中提供的函数是SysTick_Config(uint32_t ticks); 该函数设置了自动重载入计数器(LOAD)的值,SysTick IRQ的优先级,复位了计数器(V AL)的值,开始计数并打开SysTick IRQ中断。

SysTick时钟默认使用系统时钟。

其中这个函数定义在Core_cm3.h中,源代码如下所示:static __INLINE uint32_t SysTick_Config(uint32_t ticks){if (ticks 》SysTick_LOAD_RELOAD_Msk)return (1);SysTick-》LOAD= (ticksNVIC_SetPriority (SysTick_IRQn,(1《《__NVIC_PRIO_BITS)- 1);SysTick-》V AL= 0;SysTick-》CTRL= SysTick_CTRL_CLKSOURCE_Msk |SysTick_CTRL_TICKINT_Msk|SysTick_CTRL_ENABLE_Msk;return (0);}从上面的函数中可以看出,这个函数把Systick的初值,中断优先级,使能中断,开启定时器都完成了。

大大简化了程序。

其中ticks 代表的是初值。

例如系统时钟是72Mhz 那么要产生1ms的时基,那么我们可以这样去写。

STM32学习笔记

STM32学习笔记

STM32学习笔记——SystemInit()函数第一课时钟频率STM32F103内部8M的内部震荡,经过倍频后最高可以达到72M。

目前TI的M3系列芯片最高频率可以达到80M。

在stm32固件库3.0中对时钟频率的选择进行了大大的简化,原先的一大堆操作都在后台进行。

系统给出的函数为SystemInit()。

但在调用前还需要进行一些宏定义的设置,具体的设置在system_stm32f10x.c文件中。

文件开头就有一个这样的定义://#define SYSCLK_FREQ_HSE HSE_Value//#define SYSCLK_FREQ_20MHz 20000000//#define SYSCLK_FREQ_36MHz 36000000//#define SYSCLK_FREQ_48MHz 48000000//#define SYSCLK_FREQ_56MHz 56000000#define SYSCLK_FREQ_72MHz 72000000ST 官方推荐的外接晶振是8M,所以库函数的设置都是假定你的硬件已经接了8M 晶振来运算的.以上东西就是默认晶振8M 的时候,推荐的CPU 频率选择.在这里选择了:#define SYSCLK_FREQ_72MHz 72000000也就是103系列能跑到的最大值72M然后这个C文件继续往下看#elif defined SYSCLK_FREQ_72MHzconst uint32_t SystemFrequency = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_SysClk = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_AHBClk = SYSCLK_FREQ_72MHz;const uint32_t SystemFrequency_APB1Clk = (SYSCLK_FREQ_72MHz/2);const uint32_t SystemFrequency_APB2Clk = SYSCLK_FREQ_72MHz;这就是在定义了CPU跑72M的时候,各个系统的速度了.他们分别是:硬件频率,系统时钟,AHB总线频率,APB1总线频率,APB2总线频率.再往下看,看到这个了:#elif defined SYSCLK_FREQ_72MHzstatic void SetSysClockTo72(void);这就是定义72M 的时候,设置时钟的函数.这个函数被SetSysClock ()函数调用,而SetSysClock ()函数则是被SystemInit()函数调用.最后SystemInit()函数,就是被你调用的了所以设置系统时钟的流程就是:首先用户程序调用SystemInit()函数,这是一个库函数,然后SystemInit()函数里面,进行了一些寄存器必要的初始化后,就调用SetSysClock()函数. SetSysClock()函数根据那个#defineSYSCLK_FREQ_72MHz 72000000 的宏定义,知道了要调用SetSysClockTo72()这个函数,于是,就一堆麻烦而复杂的设置~!@#$%^然后,CPU跑起来了,而且速度是72M. 虽然说的有点累赘,但大家只需要知道,用户要设置频率,程序中就做的就两个事情:第一个: system_stm32f10x.c 中#define SYSCLK_FREQ_72MHz 72000000第二个:调用SystemInit()。

STM32启动文件详解及SystemInit函数分析

STM32启动文件详解及SystemInit函数分析

1/6/afeibfp/archive/2013/01/08/2850408.html <2013年1月>日一二三四五六303112345678910111213141516171819202122232425262728293031123456789昵称:afeibfp 园龄:2年5个月粉丝:0关注:0+加关注搜索找找看 谷歌搜索常用链接我的随笔我的评论我的参与最新评论我的标签更多链接我的标签51单片机(2)多字节除法(2)汇编(2)随笔分类(2)转发(2)随笔档案(16)2013年1月 (14)2011年9月 (2)最新评论1. Re:014:针对mdk 中STM32程序无法使用printf ,产生停留BEAB BKPT 0xAB 处问题的解决(转)不点那个MiclroLIB 就行了--blakeliu阅读排行榜1. 001:无符号双字节除以单字节(51单片机,汇编源码)(418)2. 004:STM32启动文件详解及SystemInit 函数分析(转)(389)3. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(312)4. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(208)5. 009:semihost/ITM 机制浅析以及使用JLINK 通过ITM 调试stm32单片机(转)(190)评论排行榜1. 014:针对mdk 中STM32程序无法使用printf ,产生停留BE AB BKPT 0xAB 处问题的解决(转)(1)2. 013:ADS semihosting 与硬件重定向(转)(0)3. 012:Keil 调试技术(转)(0)4. 011:Nuvoton(新唐) Cort ex M0 使用semihost 输入输出办法(转)(0)5. 010:请教STM32用JLINK V8 SWD 输出调试信息到ITM V iewer 的问题(转)(0)推荐排行榜博客园首页新随笔联系管理订阅 随笔- 16 文章- 0 评论- 1afeibfp004:STM32启动文件详解及SystemInit 函数分析(转)1 ;先在R A M 中分配系统使用的栈,R A M 的起始地址为0x 2000_00002 ;然后在R A M 中分配变量使用的堆3 ;然后在C O D E 区(f l a s h )分配中断向量表,f l a s h 的起始地址为0x 0800_0000,该中断向量表就从这个起始地址开始分配4 ;分配完成后,再定义和实现相应的中断函数,5 ;所有的中断函数全部带有[w e a k ]特性,即弱定义,如果编译器发现在别处文件中定义了同名函数,在链接时用别处的地址进行链接。

STM32中sysTick的设置

STM32中sysTick的设置

STM32中sysTick的设置(转)我不得不说意法半导体确实有点风骚!甚至有点变态。

我对ST文档 STM32F10XXX参考手册的编辑水平真是不敢恭维。

手册中好多说明都是含糊不清,甚至将好多对初学者来说很重要的地方都一笔带过,让人着实摸不着头脑。

比如前面我说过的关于NVIC嵌套向量中断控制器的介绍,这部分我认为是非常重要的,但当你看完他这部分介绍,你根本不会设置中断服务程序,他有哪些寄存器都不知道,更别说去设置了,NVIC的详细介绍是在Cotex-M3中有详细的介绍,不多说。

今天我们说的是systick定时器。

systick定时器和我上面说的情况一样,在手册中根本没有介绍。

我费了九牛二虎之力才在一个犄角格拉里找到systick定时器的英文版的说明。

在Cotex-M3有介绍,为什么要找STM32的介绍,是因为功能设置上还有点区别。

首先看一下systick定时器的作用,下面是Cotex-M3里的一段话:SysTick定时器被捆绑在NVIC中,用于产生SYSTICK异常(异常号:15)。

在以前,大多操作系统需要一个硬件定时器来产生操作系统需要的滴答中断,作为整个系统的时基。

例如,为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。

因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。

Cortex‐M3处理器内部包含了一个简单的定时器。

因为所有的CM3芯片都带有这个定时器,软件在不同 CM3器件间的移植工作得以化简。

该定时器的时钟源可以是内部时钟(FCLK,CM3上的自由运行时钟),或者是外部时钟( CM3处理器上的STCLK信号)。

不过,STCLK的具体来源则由芯片设计者决定,因此不同产品之间的时钟频率可能会大不相同,你需要检视芯片的器件手册来决定选择什么作为时钟源。

STM32时钟初始化函数SysInit详解

STM32时钟初始化函数SysInit详解

花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz函数调用顺序:startup_stm32f10x_cl.s(启动文件)→SystemInit() → SetSysClock () →SetSysClockTo72()初始化时钟用到的RCC寄存器复位值:RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;SystemInit()在调用SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):RCC->CR = 0x0000 0083; RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;SetSysClock()函数如下:static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHz//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()SetSysClockTo72();#endif}SetSysClockTo72()函数如下:static void SetSysClockTo72(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){/* 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;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* 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_DIV5); /* 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 */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;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */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 clockconfiguration. User can add here some code to deal with this error */}}1:AHB, APB1,APB2时钟确定//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ (至于72MHZ如何得来,请看下面分析)//那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ//AHB总线时钟等于系统时钟SYSCLK,也就是AHB时钟= HCLK = SYSCLK = 72MHZ /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//PLCK2等于HCLK一分频,所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ//APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟= HCLK = SYSCLK = 72MHZ/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ//APB1总线时钟等于HCLK的二分频,也就是APB1时钟= HCLK / 2 = 36MHZ/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);RCC_CFGR2_PREDIV2_DIV5: PREDIV2 = 5;5分频也就是PREDIV2对输入的外部时钟5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZRCC_CFGR2_PLL2MUL8 : PLL2MUL = 8;8倍频8倍频后,PLL2时钟= 5 * 8 = 40MHZ; 因此PLL2CLK = 40MHZRCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1,选择PLL2CLK 作为PREDIV1的时钟源RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频PREDIV1CLK = PLL2CLK / 5 = 8MHZ以上是对RCC_CFGR2进行的配置--------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的位[3:0]中的最低位是相同的效果RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK =8MHZ,所以输入给PLL倍频的时钟源是8MHZRCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对PLLCLK = PREDIV1CLK * 8 = 72MHZ以上是对RCC_CFGR进行的配置---------------------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLLCLK作为系统时钟源--------------------------------------------------------------------------------------------------至此基本配置已经完成,配置的时钟如下所述:SYSCLK(系统时钟) = 72MHZAHB总线时钟 = 72MHZAPB1总线时钟 = 36MHZAPB2总线时钟 = 72MHZPLL时钟 = 72MHZPLL2时钟 = 40MHZ。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

花了一天的时间,总算是了解了SystemInit()函数实现了哪些功能,初学STM32,,现记录如下(有理解错误的地方还请大侠指出):使用的是3.5的库,用的是STM32F107VC,开发环境RVMDK4.23我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz函数调用顺序:startup_stm32f10x_cl.s(启动文件)→SystemInit() → SetSysClock () →SetSysClockTo72()初始化时钟用到的RCC寄存器复位值:RCC_CR = 0x0000 xx83; RCC_CFGR = 0x0000 0000;RCC_CIR = 0x0000 0000; RCC_CFGR2 = 0x0000 0000;SystemInit()在调用SetSysClock()之前RCC寄存器的值如下(都是一些与运算,或运算,在此就不赘述了):RCC->CR = 0x0000 0083; RCC->CIR = 0x00FF0000; RCC->CFGR2 = 0x00000000;至于这些寄存器都代表着什么意思,详见芯片资料RCC寄存器,该文重点不在此处;SetSysClock()函数如下:static void SetSysClock(void){#ifdef SYSCLK_FREQ_HSESetSysClockToHSE();#elif defined SYSCLK_FREQ_24MHzSetSysClockTo24();#elif defined SYSCLK_FREQ_36MHzSetSysClockTo36();#elif defined SYSCLK_FREQ_48MHzSetSysClockTo48();#elif defined SYSCLK_FREQ_56MHzSetSysClockTo56();#elif defined SYSCLK_FREQ_72MHz//我的定义的是SYSCLK_FREQ_72MHz,所以调用SetSysClockTo72()SetSysClockTo72();#endif}SetSysClockTo72()函数如下:static void SetSysClockTo72(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){/* 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;/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;#ifdef STM32F10X_CL/* Configure PLLs ------------------------------------------------------*//* 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_DIV5); /* 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 */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;/* Wait till PLL is ready */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* Select PLL as system clock source */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 clockconfiguration. User can add here some code to deal with this error */}}1:AHB, APB1,APB2时钟确定//HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ (至于72MHZ如何得来,请看下面分析)//那么就是HCLK(AHB总线时钟)=PLLCLK = 72MHZ//AHB总线时钟等于系统时钟SYSCLK,也就是AHB时钟= HCLK = SYSCLK = 72MHZ /* HCLK = SYSCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;//PLCK2等于HCLK一分频,所以PCLK2 = HCLK,HCLK = 72MHZ, 那么PLCK2(APB2总线时钟) = 72MHZ//APB2总线时钟等于HCLK的一分频,也就是不分频;APB2 时钟= HCLK = SYSCLK = 72MHZ/* PCLK2 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;//PCLK1 = HCLK / 2;PCLK1 等于HCLK时钟的二分频,那么PCLK1(APB1) = 72MHZ / 2 = 36MHZ//APB1总线时钟等于HCLK的二分频,也就是APB1时钟= HCLK / 2 = 36MHZ/* PCLK1 = HCLK */RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;2:如何得出SYSCLK(系统时钟)为72MHZ(外部晶振25MHZ)//记得参考英文芯片资料的时钟树P115页和RCC时钟寄存器进行理解RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);RCC_CFGR2_PREDIV2_DIV5: PREDIV2 = 5;5分频也就是PREDIV2对输入的外部时钟5分频,那么PLL2和PLL3没有倍频前是25 /5 = 5MHZRCC_CFGR2_PLL2MUL8 : PLL2MUL = 8;8倍频8倍频后,PLL2时钟= 5 * 8 = 40MHZ; 因此PLL2CLK = 40MHZRCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1,选择PLL2CLK 作为PREDIV1的时钟源RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入时钟5分频PREDIV1CLK = PLL2CLK / 5 = 8MHZ以上是对RCC_CFGR2进行的配置--------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 |RCC_CFGR_PLLMULL9);RCC_CFGR_PLLXTPRE_PREDIV1 :操作的是RCC_CFGR的第17位PLLXTPRE,操作这一位和操作RCC_CFGR2寄存器的位[3:0]中的最低位是相同的效果RCC_CFGR_PLLSRC_PREDIV1 :选择PREDIV1输出作为PLL输入时钟;PREDIV1CLK =8MHZ,所以输入给PLL倍频的时钟源是8MHZRCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频系数为9,也就是对PLLCLK = PREDIV1CLK * 8 = 72MHZ以上是对RCC_CFGR进行的配置---------------------------------------------------------------------------------------------------RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLLCLK作为系统时钟源--------------------------------------------------------------------------------------------------至此基本配置已经完成,配置的时钟如下所述:SYSCLK(系统时钟) = 72MHZAHB总线时钟 = 72MHZAPB1总线时钟 = 36MHZAPB2总线时钟 = 72MHZPLL时钟 = 72MHZPLL2时钟 = 40MHZ。

相关文档
最新文档