完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
花了一天的时间总骗了解了SystemInit()函数实现了哪些功能,初学STM32,现记录如下(有侠理解错误的地方还请大意
的库):使用的是3.5,用的是STM32F107VC ,开发环境RVMDK4.23 我已经定义了STM32F10X_CL,SYSCLK_FREQ_72MHz 函数调用顺序: startup_stm32f10x_cl.s(启动文件→SystemInit()→SetSysClock()→SetSysClockTo72() 初始化的 RCC0寄存器值:RCC_CR = 0x00 ; 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_HSE SetSysClockToHSE(); #elif 定义了 SYSCLK_FREQ_24MHz SetSysClockTo24(); #elif 定义了 SYSCLK_FREQ_36MHz SetSysClockTo36(); #elif 定义了 SYSCLK_FREQ_48MHz SetSysClockTo48(); #elif 定义了 SYSCLK_FREQ_56MHz SetSysClockTo56(); #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和PCLK1配置--------------------------- / /启用HSE * / RCC-> CR | =( (uint32_t)RCC_CR_HSEON); /* 等到 HSE 准备好,如果超时退出 */ 做 { HSEStatus = RCC->CR & RCC_CR_HSERDY; 启动计数器++; } 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 |= FLASH_ACR_PRFTBE; /* Flash 2 等待状态 */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 /* 配置 PLL ------------------------------------------- ----------- / / PLL2配置:PLL2CLK =(HSE / 5)* 8 = 40兆赫/ / PREDIV1配置:PREDIV1CLK = PLL2 / 5 = 8兆赫* / 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); /* 启用 PLL2 */RCC->CR |= RCC_CR_PLL2ON;/* 等到 PLL2 准备好 */while((RCC->CR & RCC_CR_PLL2RDY) == 0){} /* PLL 配置: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_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL) #else /* PLL 配置:PLLCLK = HSE * 9 = 72 MHz / RCC->CFGR & RCC_CFGR_PLLMULL)); RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9); #endif / STM32F10X_CL */ /* 启用 PLL */RCC->CR |= RCC_CR_PLLON;/* 等待 PLL 准备就绪 */while((RCC->CR & RCC_CR_PLLRDY) == 0){}/* 选择 PLL 作为系统时钟源 */RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; /* 等待 PLL 作为系统时钟源 */while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08){} } else { /* 如果 HSE 启动失败,应用程序会有错误的时钟 配置。用户可以在这里添加一些代码来处理这个错误 */ } } 1:AHB, APB1,APB2 注册确定 //HCLK = SYSCLK ,从下面的分析可以得出SYSCLK是使用PLLCLK时钟的,也就是72MHZ(至于72MHZ如何得来,请看下面分析) //那么就是HCLK(AHB时钟)=PLLCLK = 72MHZ / /AHB总线也就是时钟系统logsysclk = HCLK = SYSCLK = 72MHZ /* HCLK = SYSCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1; //PLCK2等于HCLK一分频,所以PCLK2 = HCLK,HCLK = 2MHZ,那么PLCK2(APB2总线时钟) = 72MHZ //APB2总线时钟HCLK的一分频,也就是不分频;APB2 = HCLK = SYSCLK = 72MHZ /* PCLK2 = HCLK */ RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1; //PCLK1 = HCLK / 2;CLK1 等于HCLKP的二分频,那么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 = 5MHZ RCC_CFGR2_PLL2MUL8 : PLL2MUL = 8; 8倍频 8频,后PLL2频率 = 5 * 8 = 40MHZ;因此PLL2CLK = 40MHZ RCC_CFGR2_PREDIV1SRC_PLL2 : RCC_CFGR2的第16位为1, 选择PLL2CLK PREDIV1的时钟源 RCC_CFGR2_PREDIV1_DIV5:PREDIV1 = 5;PREDIV1对输入频率= 5;PREDIV1对输入频率= 5分 频进行配置 PREDIV1MHRCCCF = 0 >CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | RCC_CFGR_PLLMULL9); RCC_CFGR_PLLXTPRE_PREDV1 :操作是RCC_CFGR的第17位PLLXTPRE,操作RCC_CFGR2的位[3:0]中位是相同的效果 RCC_CFGR_PLLSRC_PREDV1 :选择PLL输入PREDIV1输出作为PLL输入;PREDIV1CLK = 8MHZ,所以给PLL倍频的输入源是8MHZ RCC_CFGR_PLLMULL9 :PLLMUL = 9;PLL倍频是为9,也就是对PLLCLK = PREDIV1CLK * 8 = 72 以上对RCC_CFGR进行的配置 RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL; //选择PLLCLK作为系统源 完成至基本已经,配置的此配置如下所述: SYSCLK(系统时钟) = 72Z AHB时钟= 72MHZ APB1 总线 = 36MHZ APB2 时钟 = 72MHZ PLL = 72MHZ PLL2时钟= 40MHZ STM32的电话树 对于那些初次接触STM32的朋友(甚至是首次接触了机械臂的用户朋友),说到了开发环境的使用之后,总会在同一问题上“陷入困境”。个关键字叫:钟树。 外接,微控制器(处理器)的必须要依赖外部的一个调用来运行驱动——往往用于提供输入输入起始,最终转换为多个外部设备的辅助为末,荷兰“能量”流动的人口流动的,就像大树的分流通过主干流向各个路径,从而带来了常情的“情感树”。自己也有自己的一个家庭树系统,但其中的汽车是不受控制的,也就是在拥有自己的电后,汽车树就固定在某个不可改变的状态(假设即将发生的正常工作的状态) )。比如51单片机使用典型的12MHz的晶振作为时钟源,则外设如IO口,定时器,串口等设备的驱动时钟速率便已经是固定的,用户无法将此时钟速率更改,除非更换晶振。 而STM32微控制器的时钟树则是可配置的,外设的输入源与最终达到处的时钟速率不再有固定的关系,以后会详细解析STM32微控制器的时钟树图1是STM32微。控制器的时钟树,1是内部各个标号所表示的 小区。图1标号标释义 1 低 外部速速(LSI,40Khz)2 低外部内部速速(LSE,32.768Khz) 3 外部高速下载( HSE,3-25MHz) 4 内部高速私有(HIS,8MHz) 5 PLL 输入选择位 6 RTC输入选择位 7 PLL1 分频数参数 8 PLL1 倍频频率 9 系统选择位 频频10 USB 分频 11 AHB 分频频滤波器 12 APB1分频滤波器 13 AHB总线 14 APB1外设总线 15 22分频滤波器 16 APB2外设总线 17 ADC预分频滤波器 18 ADC 19 PLL2分频数滤波器 20 PLL2倍频 频率滤波器21 PLL选择源选择 开关设备22 独立看门狗设备 23 RTC设备 图1 STM32的电话树 在认识这颗心树之前,首先要明确“主干”和最终的“分支”。这个假设使用外部8MHz晶振作为STM32的时钟输入源(最常见的这步),则8MHz就是“主干”,而“分支”很可能是最终的外部设备,比如通用输入设备(GPIO)。这样输出可以轻松找出第一条的“脉络”: 3——5——7——21—— 8——9——11——13条对于 此条时钟路径做如下解析: 3,首先是外部的3-25MHz(前文已假为8MHz)输入; 对于5,PLL通过选择位犯罪选择题PLL分支的输入外部(外部选择外部晶振); 对于7,设置晶振的分频数(假1分频); 对于21,选择倍频频的时钟源(选择分频后的外部晶振); 对于8,设置PLL倍频数(假9倍频); 9,选择系统光源(对于假选择PLL倍频所的输出); 11,设置AHB总线分频数(假1分频); 对于13,总部到达AHB; 在上一章节中所介绍的GPIO外设属于APB2设备,即GPIO的调用来自APB2总线,同样在图1中也可以获取GPIO外设的主机寻: 3——5——7—— 21——9——11——115——16 对于3,首先是外部的3-25MHz(前文已假为8MHz)输入; 对于5,通过PLL选择位选择任务PLL分支的输入名称(假设选择外部晶振); 对于7,设置外部晶振的分频数(假1分频); 21,选择PLL倍频的时钟源(假设选择分频后的外部晶振); 对于8,设置PLL倍频数(假9频); 对于9,选择系统源(假选择通过PLL倍频所输出的频率); 对于11,设置AHB总线分频数(假1分频); 对于15,设置APB2总线分频数(假1分频); 对于16条,每条到达APB2总线; 现在来计算一下GPIO设备的最大驱动速度(各种条件已在上述要点中假设):
|
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1621 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1546 浏览 1 评论
980 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
686 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1599 浏览 2 评论
1865浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
648浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
517浏览 3评论
534浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
506浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-23 11:11 , Processed in 0.688487 second(s), Total 78, Slave 61 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号