stm32启动文件详解及SystemInit函数分析
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
;先在RAM中分配系统使用的栈,RAM的起始地址为0x2000_0000
;然后在RAM中分配变量使用的堆
;然后在CODE区(flash)分配中断向量表,flash的起始地址为0x0800_0000,该中断向量表就从这个起始地址开始分配
;分配完成后,再定义和实现相应的中断函数,
;所有的中断函数全部带有[weak]特性,即弱定义,如果编译器发现在别处文件中定义了同名函数,在链接时用别处的地址进行链接。
;中断函数仅仅实现了Reset_Handler,其他要么是死循环,要么仅仅定义了函数名称
;STM32被设置为从内部FLASH启动时(这也是最常见的一种情况),当STM32遇到复位信号后,
;从0x0800_0000处取出栈顶地址存放于MSP寄存器,从0x0800_0004处取出复位中断服务入口地址放入PC寄存器,
;继而执行复位中断服务程序Reset_Handler,
;Reset_Handler仅仅执行了两个函数调用,一个是SystemInit,另一个__main,
;SystemInit定义在system_stm32f10x.c中,主要初始化了STM的时钟系统:HSI,HSE,LSI,LSE,PLL,SYSCLK,USBCLK,APECLK等等.
;__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。
Stack_Size EQU 0x00000400 ;//定义堆栈大小
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段 按8字节对齐 ;AREA 伪指令用于定义一个代码段或数据段 NOINIT:指定此数据段仅仅保留了内存单元,而没有将各初始值写入内存单元,或者将各个内存单元值初始化为0
Stack_Mem SPACE Stack_Size ;//保留Stack_Size大小的堆栈空间 分 配连续 Stack_Size 字节的存储单元并初始化为 0
__initial_sp ;//标号,代表堆栈顶部地址,后面有用
;
;
;
Heap_Size EQU 0x00000200 ;//定义堆空间大小
AREA HEAP, NOINIT, READWRITE, ALIGN=3 ;//定义一个数据段,8字节对齐
__heap_base ;//标号,代表堆末底部地址,后面有用
Heap_Mem SPACE Heap_Size ;//保留Heap_Size的堆空间
__heap_limit ;//标号,代表堆界限地址,后面有用
;PRESERVE8 指令指定当前文件保持堆栈八字节对齐。 它设置 PRES8 编译属性以通知链接器。
;链接器检查要求堆栈八字节对齐的任何代码是否仅由保持堆栈八字节对齐的代码直接或间接地调用。
PRESERVE8 ;//指示编译器8字节对齐
THUMB ;//指示编译器以后的指令为THUMB指令
;中断向量表定义
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY ;//定义只读数据段,其实放在CODE区,位于0地址
EXPORT __Vectors ;EXPORT:在程序中声明一个
全局的标号__Vectors,该标号可在其他的文件中引用
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack ;给__initial_sp分配4字节32位的地址0x0
DCD Reset_Handler ; Reset Handler ; 给标号Reset Handler分配地址为0x00000004
DCD NMI_Handler ; NMI Handler ; 给标号NMI Handler分配地址0x00000008
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved ; 这种形式就是保留地址,不给任何标号分配
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
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
DCD RCC_IRQHandler ; RCC
DCD EXTI0_IRQHandler ; EXTI Line 0
DCD EXTI1_IRQHandler ; EXTI Line 1
DCD EXTI2_IRQHandler ; EXTI Line 2
DCD EXTI3_IRQHandler ; EXTI Line 3
DCD EXTI4_IRQHandler ; EXTI Line 4
DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1
DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2
DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3
DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4
DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5
DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6
DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7
DCD ADC1_2_IRQHandler ; ADC1 & ADC2
DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or CAN1 RX0
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
DCD
CAN1_SCE_IRQHandler ; CAN1 SCE
DCD EXTI9_5_IRQHandler ; EXTI Line 9..5
DCD TIM1_BRK_IRQHandler ; TIM1 Break
DCD TIM1_UP_IRQHandler ; TIM1 Update
DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
DCD TIM2_IRQHandler ; TIM2
DCD TIM3_IRQHandler ; TIM3
DCD TIM4_IRQHandler ; TIM4
DCD I2C1_EV_IRQHandler ; I2C1 Event
DCD I2C1_ER_IRQHandler ; I2C1 Error
DCD I2C2_EV_IRQHandler ; I2C2 Event
DCD I2C2_ER_IRQHandler ; I2C2 Error
DCD SPI1_IRQHandler ; SPI1
DCD SPI2_IRQHandler ; SPI2
DCD USART1_IRQHandler ; USART1
DCD USART2_IRQHandler ; USART2
DCD USART3_IRQHandler ; USART3
DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
DCD RTCAlarm_IRQHandler ; RTC Alarm through EXTI Line
DCD USBWakeUp_IRQHandler ; USB Wakeup from suspend
DCD TIM8_BRK_IRQHandler ; TIM8 Break
DCD TIM8_UP_IRQHandler ; TIM8 Update
DCD TIM8_TRG_COM_IRQHandler ; TIM8 Trigger and Commutation
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
DCD ADC3_IRQHandler ; ADC3
DCD FSMC_IRQHandler ; FSMC
DCD SDIO_IRQHandler ; SDIO
DCD TIM5_IRQHandler ; TIM5
DCD SPI3_IRQHandler ; SPI3
DCD UART4_IRQHandler ; UART4
DCD UART5_IRQHandler ; UART5
DCD TIM6_IRQHandler ; TIM6
DCD TIM7_IRQHandler ; TIM7
DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1
DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2
DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3
DCD DMA2_Channel4_5_IRQHandler ; DMA2 Channel4 & Channel5
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY ;代码段定义
; Reset Handler
;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
Reset_Handler PROC ;过程的开始
EXPORT Reset_Handler [WEAK];[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
;如果没有其它定方定义,编译器也不报错,
以此处地址进行链接。
;EXPORT提示编译器该标号可以为外部文件引用。
IMPORT __main ;通知编译器要使用的标号在其他文件
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0 ;BX是ARM指令集和THUMB指令集之间程序的跳转
LDR R0, =__main ;使用“=”表示LDR目前是伪指令不是标准指令。这里是把__main的地址给RO。
BX R0 ;BX是ARM指令集和THUMB指令集之间程序的跳转
ENDP ;过程的结束
; Dummy Exception Handlers (infinite loops which can be modified)
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B . ;原地跳转(即无限循环),
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
Default_Handler PROC
EXPORT WWDG_IRQHandler [WEAK]
EXPORT PVD_IRQHandler [WEAK]
EXPORT TAMPER_IRQHandler [WEAK]
EXPORT RTC_IRQHandler [WEAK]
EXPORT FLASH_IRQHandler [WEAK]
EXPORT RCC_IRQHandler [WEAK]
EXPORT EXTI0_IRQHandler [WEAK]
EXPORT EXTI1_IRQHandler [WEAK]
EXPORT EXTI2_IRQHandler [WEAK]
EXPORT EXTI3_IRQHandler [WEAK]
EXPORT EXTI4_IRQHandler [WEAK]
EXPORT DMA1_Channel1_IRQHandler [WEAK]
EXPORT DMA1_Channel2_IRQHandler [WEAK]
EXPORT DMA1_Channel3_IRQHandler [WEAK]
EXPORT DMA1_Channel4_IRQHandler [WEAK]
EXPORT DMA1_Channel5_IRQHandler [WEAK]
EXPORT DMA1_Channel6_IRQHandler [WEAK]
EXPORT DMA1_Channel7_IRQHandler [WEAK]
EXPORT ADC1_2_IRQHandler [WEAK]
EXPORT USB_HP_CAN1_TX_IRQHandler [WEAK]
EXPORT USB_LP_CAN1_RX0_IRQHandler [WEAK]
EXPORT CAN1_RX1_IRQHandler [WEAK]
EXPORT CAN1_SCE_IRQHandler [WEAK]
EXPORT EXTI9_5_IRQHandler [WEAK]
EXPORT TIM1_BRK_IRQHandler [WEAK]
EXPORT TIM1_UP_IRQHandler [WEAK]
EXPORT TIM1_TRG_COM_IRQHandler [WEAK]
EXPORT TIM1_CC_IRQHandler [WEAK]
EXPORT TIM2_IRQHandler [WEAK]
EXPORT TIM3_IRQHandler [WEAK]
EXPORT TIM4_IRQHandler [WEAK]
EXPORT I2C1_EV_IRQHandler [WEAK]
EXPORT I2C1_ER_IRQHandler [WEAK]
EXPORT I2C2_EV_IRQHandler [WEAK]
EXPORT I2C2_ER_IRQHandler [WEAK]
EXPORT SPI1_IRQHandler [WEAK]
EXPORT SPI2_IRQHandler [WEAK]
EXPORT USART1_IRQHandler [WEAK]
EXPORT USART2_IRQHandler [WEAK]
EXPORT USART3_IRQHandler [WEAK]
EXPORT EXTI15_10_IRQHandler [WEAK]
EXPORT RTCAlarm_IRQHandler [WEAK]
EXPORT USBWakeUp_IRQHandler [WEAK]
EXPORT TIM8_BRK_IRQHandler [WEAK]
EXPORT TIM8_UP_IRQHandler [WEAK]
EXPORT TIM8_TRG_COM_IRQHandler [WEAK]
EXPORT TIM8_CC_IRQHandler [WEAK]
EXPORT ADC3_IRQHandler [WEAK]
EXPORT FSMC_IRQHandler [WEAK]
EXPORT SDIO_IRQHandler [WEAK]
EXPORT TIM5_IRQHandler [WEAK]
EXPORT SPI3_IRQHandler [WEAK]
EXPORT UART4_IRQHandler [WEAK]
EXPORT UART5_IRQHandler [WEAK]
EXPORT TIM6_IRQHandler [WEAK]
EXPORT TIM7_IRQHandler [WEAK]
EXPORT DMA2_Channel1_IRQHandler [WEAK]
EXPORT DMA2_Channel2_IRQHandler [WEAK]
EXPORT DMA2_Channel3_IRQHandler [WEAK]
EXPORT DMA2_Channel4_5_IRQHandler [WEAK]
WWDG_IRQHandler
PVD_IRQHandler
TAMPER_IRQHandler
RTC_IRQHandler
FLASH_IRQHandler
RCC_IRQHandler
EXTI0_IRQHandler
EXTI1_IRQHandler
EXTI2_IRQHandler
EXTI3_IRQHandler
EXTI4_IRQHandler
DMA1_Channel1_IRQHandler
DMA1_Channel2_IRQHandler
DMA1_Channel3_IRQHandler
DMA1_Channel4_IRQHandler
DMA1_Channel5_IRQHandler
DMA1_Channel6_IRQHandler
DMA1_Channel7_IRQHandler
ADC1_2_IRQHandler
USB_HP_CAN1_TX_IR
QHandler
USB_LP_CAN1_RX0_IRQHandler
CAN1_RX1_IRQHandler
CAN1_SCE_IRQHandler
EXTI9_5_IRQHandler
TIM1_BRK_IRQHandler
TIM1_UP_IRQHandler
TIM1_TRG_COM_IRQHandler
TIM1_CC_IRQHandler
TIM2_IRQHandler
TIM3_IRQHandler
TIM4_IRQHandler
I2C1_EV_IRQHandler
I2C1_ER_IRQHandler
I2C2_EV_IRQHandler
I2C2_ER_IRQHandler
SPI1_IRQHandler
SPI2_IRQHandler
USART1_IRQHandler
USART2_IRQHandler
USART3_IRQHandler
EXTI15_10_IRQHandler
RTCAlarm_IRQHandler
USBWakeUp_IRQHandler
TIM8_BRK_IRQHandler
TIM8_UP_IRQHandler
TIM8_TRG_COM_IRQHandler
TIM8_CC_IRQHandler
ADC3_IRQHandler
FSMC_IRQHandler
SDIO_IRQHandler
TIM5_IRQHandler
SPI3_IRQHandler
UART4_IRQHandler
UART5_IRQHandler
TIM6_IRQHandler
TIM7_IRQHandler
DMA2_Channel1_IRQHandler
DMA2_Channel2_IRQHandler
DMA2_Channel3_IRQHandler
DMA2_Channel4_5_IRQHandler
B .
ENDP
ALIGN ;填充字节使地址对齐
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
;堆和栈的初始化
IF :DEF:__MICROLIB ;“DEF”的用法——:DEF:X 就是说X定义了则为真,否则为假
;如果定义了MICORLIB,
EXPORT __initial_sp ;则将栈顶地址,
EXPORT __heap_base ;堆起始地址赋予全局属性,
EXPORT __heap_limit ;堆末端界限地址赋予全局属性,使外部程序可调用
ELSE ;如果没定义__MICROLIB,则使用默认的C运行时库
IMPORT __use_two_region_memory ;;通知编译器要使用的标号在其他文件__use_two_region_memory
EXPORT __user_initial_stackheap ;声明全局标号__user_initial_stackheap,这样外程序也可调用此标号
;则进行堆栈和堆的赋值,在__main函数执行过程中调用
;如果使用默认的C库,程序启动过程中就不会执行该标号下的代码
__user_initial_stackheap ;标号__user_initial_stackheap,表示用户堆栈初始化程序入口
;//则进行堆栈和堆的赋值,在__main函数执行过程中调用。
LDR R0, = Heap_Mem ;保存堆始地址
LDR R1, =(Stack_Mem + Stack_Size) ;保存栈的大小
LDR R2, = (Heap_Mem + Heap_Size) ;保存堆的大小
LDR R3, = Stack_Mem ;保存栈顶指针
BX LR
ALIGN ;填充字节使地址对齐
ENDIF
END
//SystemInit()函数主要流程如下
//1. RCC_CR时钟控制寄存器,第0位置1,开启内部8Mhz高速时钟HSI
//2. 设置SYSCLK=HSI=8Mhz
// HCK=SYSCLK=8Mhz
// PCLK1=HCLK=8Mhz
// PCLK2=HCLK=8Mhz
// ADCCLK=PCLK2/2=4Mhz
// MCO, 没有时
钟输出
//3. 关闭HSE外部高速时钟
// 关闭CSS时钟安全系统
// 关闭PLL锁相环
//4. 设置HSE没有被旁路,意思为HSE使用外部晶体,而不是外部时钟源
//5. 复位PLLSRC,PLLXTPRE,PLLMUL,USBPRE,为下一步重新设置新的值做准备
复位后:
PLLSRC=HSI/2, PLL关闭时才可写入
PLLXTPRE=HSE, PLL关闭时才可写入
PLLMUL=2, PLL关闭时才可写入,PLL开启后,PLLMUL的值才有意义,PLL=PLLSRC*PLLMUL
USBPRE=0, USBCLK=PLLCLK/1.5,(PLL被关闭,USBCLK同时失效,外部晶振开启成功后变为72/1.5)
//6. 禁止所有时钟中断,清中断标志位
//然后调用SetSysClockTo72()函数继续执行以下功能
//1. HSE外部高速时钟使能
//2. 使能flash预取缓冲区
// 设置SYSCLK与闪存访问时间的比例
//3. 重新设置HCLK,PCLK2,PCLK1
HCLK = SYSCLK
PCLK2 = HCLK
PCLK1 = HCLK /2
//4. 又一次复位PLLSRC,PLLXTPRE,PLLMUL,
PLLSRC=HSI/2
PLLXTPRE=HSE不分频
PLLMUL=2倍频输出
//5. 重设PLLSRC,PLLMUL
PLLSRC=HSE
PLLMUL=9倍频
//6. 使能PLL(PLLCLK=PLLSRC*PLLMUL,PLLSRC=HSE=8Mhz,PLLMUL=9)
//7. 设置SYSCLK=PLLCLK=72Mhz
//*******************************************************************************
//原来的sysytem_stm32f10x.c编译条件太多,这里仅仅摘抄了关键的部分
// 这些参数,和MDK的设备参数一致,如图所示:
宏
MCU 型号
FLASH大小
STM32F10X_LD
STM32F101xx
STM32F102xx
STM32F103xx
16 ~ 32 Kbytes
STM32F10X_MD
STM32F101xx
STM32F102xx
STM32F103xx
64 ~ 128 Kbytes
STM32F10X_HD
STM32F101xx
STM32F103xx
256 ~ 512 Kbytes
STM32F10X_CL
STM32F105xx
STM32F107xx
忽略
//STM32F10X_LD_VL
//STM32F10X_MD_VL
//这两个宏都没有被定义,因此系统时钟的频率被定义为72000000
#if defined (STM32F10X_LD_VL) || (defined STM32F10X_MD_VL)
/* #define SYSCLK_FREQ_HSE HSE_Value */
#define SYSCLK_FREQ_24MHz 24000000
#else
/* #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 */
#define SYSCLK_FREQ_72MHz 72000000 //定义系统时钟的频率
#endif
//*******************************************************************************
* Clock Definitions
*******************************************************************************/
//这里定义了一个存储系统时钟频率的变量,利用宏定义给他赋予不同的值
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock
= SYSCLK_FREQ_36MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz; /*!< System Clock Frequency (Core Clock) */
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz; /*!< System Clock Frequency (Core Clock) */
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_Value; /*!< System Clock Frequency (Core Clock) */
#endif
__I uint8_t AHBPrescTable[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
//函数声明
static void SetSysClock(void);
//根据宏定义声明不同的函数
#ifdef SYSCLK_FREQ_HSE
static void SetSysClockToHSE(void);
#elif defined SYSCLK_FREQ_24MHz
static void SetSysClockTo24(void);
#elif defined SYSCLK_FREQ_36MHz
static void SetSysClockTo36(void);
#elif defined SYSCLK_FREQ_48MHz
static void SetSysClockTo48(void);
#elif defined SYSCLK_FREQ_56MHz
static void SetSysClockTo56(void);
#elif defined SYSCLK_FREQ_72MHz
static void SetSysClockTo72(void);
#endif
#ifdef DATA_IN_ExtSRAM
static void SystemInit_ExtMemCtl(void);
#endif /* DATA_IN_ExtSRAM */
void SystemInit (void)
{
/* Reset the RCC clock configuration to the default reset state(for debug purpose) */
/* Set HSION bit */
//RCC_CR时钟控制寄存器,将位0置1,开启内部8Mhz高速时钟HSI,置0则关闭内部8M高速时钟HSI
RCC->CR |= (uint32_t)0x00000001; //位(0)1:HSION,使能内部8M高速时钟HSI
/* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
#ifndef STM32F10X_CL //此宏为MCU器件类型定义,参照顶部MCU器件类型表
RCC->CFGR &= (uint32_t)0xF8FF0000;
//位(26:24)000:MCO, 没有时钟输出
//位(15:14)00:ADCPRE,PCLK2 2分频后作为ADC时钟频率 ADCCLK=PCLK2/2
//位(13:11)000:PPRE2, HCLK不分频给APB2, PCLK2=HCLK
//位(10:8)000:PPRE1, HCLK不分频给APB1, PCLK1=HCLK
//位(7:4)0000:HPRE, SYSCLK不分频给AHB,HCK=SYSCLK=8Mhz
//位(3:2)00,SWS, HSI作为系统时钟(由硬件置1或清0)
//位(1:0)00,SW, HSI作为系统时钟SYSCLK=8Mhz
#else
RCC->CFGR &= (uint32_t)0xF0FF0000; //如果是互联网型器件
//位(27:24)0000: MCO没有时钟输出
#endif /* STM32F10X_CL */
/* Reset HSEON, CSSON and PLLON bits */
RCC->CR &= (uint32_t)0xFEF6FFFF; //位(16)0:HSEON,关闭外部高速时钟HSE
//位(19)0:CSSON,关闭时钟安全系统CSS
//
位(24)0:PLLON,关闭PLL
/* Reset HSEBYP bit */
RCC->CR &= (uint32_t)0xFFFBFFFF; //位(18)0:HSEBYP,外部高速时钟HSE没有被旁路,必须先关闭HSE才能写该位
/* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
RCC->CFGR &= (uint32_t)0xFF80FFFF; //位(22)0:USBPRE,等于0时USBCLK=PLLCLK/1.5,等于1时USBCLK=PLLCLK
//位(21:18)0000:PLLMUL=2,PLLCLK=PLLSRC*PLLMUL,倍频系数,PLL关闭时才可写入
//位(17)0:PLLXTPRE,PLLXTPRE=HSE,不分频,PLL关闭时才可写入
//位(16)0:PLLSRC,PLL输入时钟源,PLLSRC=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)
/* 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; //禁止所有时钟中断,清中断标志位
//位(23)1:CSSC,清除时钟安全系统中断
//位(20)1:PLLRDYC,清除PLL就绪中断
//位(19)1:HSERDYC,清除HSE就绪中断
//位(18)1:HSIRDYC,清除HSI就绪中断
//位(17)1:LSERDYC,清除LSE就绪中断
//位(16)1:LSIRDYC,清除LSI就绪中断
//位(12)0:PLLRDYIE,PLL就绪中断关闭
//位(11)0:HSERDYIE,HSE...
//位(10)0:HSIRDYIE,
//位( 9)0:LSERDYIE,
//位( 8)0:LSIRDYIE,
//位7-0,写0操作无意义
#endif /* STM32F10X_CL */
/* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
/* Configure the Flash Latency cycles and enable prefetch buffer */
SetSysClock();//调用SetSysClock函数
#ifdef STM32F10X_HD
#ifdef DATA_IN_ExtSRAM
SystemInit_ExtMemCtl();
#endif /* DATA_IN_ExtSRAM */
#endif /* STM32F10X_HD */
}
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif de
fined 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
}
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);// RCC_CR_HSEON((uint32_t)0x00010000) 外部高速时钟使能
//RCC_CR第16位,0:HSE外部高速时钟关闭
//RCC_CR第16位,1: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)HSERDY由硬件清0或置1
//RCC_CR第17位,0:外部时钟没有就绪
//RCC_CR第17位,1:外部时钟就绪
StartUpCounter++; //设置等待超时
} while((HSEStatus == 0) && (StartUpCounter != HSEStartUp_TimeOut)); //HSEStartUp_TimeOut((uint16_t)0x0500)
if ((RCC->CR & RCC_CR_HSERDY) != RESET) //RESET=0 ,测试HSE状态
{
HSEStatus = (uint32_t)0x01; //HSE可用,HSEStatus=1
}
else
{
HSEStatus = (uint32_t)0x00; //HSE不可用,HSEStatus=0
}
if (HSEStatus == (uint32_t)0x01)//当HSE可以用时
{
/* Enable Prefetch Buffer */
FLASH->ACR |= FLASH_ACR_PRFTBE; //FLASH_ACR_PRFTBE((uint8_t)0x10)使能flash预取缓冲区
//位(4):1,PRFTBE,预取缓冲区,0:关闭,1:使能
/* Flash 2 wait state *///设置SYSCLK与闪存访问时间的比例
FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY); //FLASH_ACR_LATENCY((uint8_t)0x03)先将低2位清0
FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;//((uint8_t)0x02)
//位(2:0)LATENCY,设置SYSCLK与闪存访问时间的比例
//000:零等待,当0
/* HCLK = SYSCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //RCC_CFGR_HPRE_DIV1((uint32_t)0x00000000)
//HCLK等于系统时钟
/* PCLK2 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; //RCC_CFGR_PPRE2_DIV1((uint32_t)0x00000000)
//PCLK2高速预分频为HCLK
/* PCLK1 = HCLK */
RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2; //RCC_CFGR_PPRE1_DIV2((uint32_t)0x00000400)
//PRE1(10:8),第10位置1,PRE1=100,PCLK1=HCLK/2
#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_PLLSRC ((uint32_t)0x00010000)
//RCC_CFGR_PLLXTPRE((uint32_t)0x00020000)
//RCC_CFGR_PLLMULL ((uint32_t)0x003C0000)
//将(21:16)清零
//16:PLLSRC,0:HSI时钟2分频作为PLL输入
//17,PLLSTPRE,0:HSE不分频
//21:18:PLLMUL,0000:PLL2倍频输出
RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);
//RCC_CFGR_PLLSRC_HSE((uint32_t)0x00010000)
//RCC_CFGR_PLLMULL9 ((uint32_t)0x001C0000)
//16:PLLSRC,1:HSE作为PLL输入时钟
//PLLNUL:0111,PLL9倍频
#endif /* STM32F10X_CL */
/* Enable PLL *///使能PLL
RCC->CR |= RCC_CR_PLLON;//RCC_CR_PLLON((uint32_t)0x01000000)
//第24位PLLON,0关闭PLL,1使能PLL
/* Wait till PLL is ready *///等待PLL就绪
while((RCC->CR & RCC_CR_PLLRDY) == 0) //RCC_CR_PLLRDY((uint32_t)0x02000000)
//第25位,PLLRDY,PLL就绪后由硬件置1
{
}
/* Select PLL as system clock source *///将PLL设为系统时钟
RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW)); //RCC_CFGR_SW((uint32_t)0x00000003)
//(1:0)SW,
//00:HSI为系统时钟
//01:HSE位系统时钟
//10:PLL为系统时钟
//11:不可用
RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;//RCC_CFGR_SW_PLL((uint32_t)0x00000002)设置PLL为系统时钟
/* Wait till PLL is used as system clock source *///等待PLL作为系统时钟就绪
while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){}//等待系统时钟准备好
//(3:2)SWS,由硬件操作来指示哪一个时钟源被选择
//00:HSI为系统时钟
//01:HSE位系统时钟
//10:PLL为系统时钟
//11:不可用
}
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 */
while (1) //如果HSE不能用,则跳入死循环
{
}
}
}