RCC :reset clock control 复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树,F767的一切时钟的来龙去脉都会了如指掌。
15.1 RCC主要作用—时钟部分
设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK等于多少)、设置APB2分频因子(决定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少)、设置各个外设的分频因子;控制AHB、APB2和APB1这三条总线时钟的开启、控制每个外设的时钟的开启。对于SYSCLK、HCLK、PCLK2、PCLK1这四个时钟的配置一般是:HCLK = SYSCLK=PLLCLK = 216 MHz,PCLK1=HCLK/2 = 108 MHz,PCLK1=HCLK/4 = 54 MHz。这个时钟配置也是库函数的标准配置,我们用的最多的就是这个。
15.2 RCC框图剖析—时钟树
时钟树单纯讲理论的话会比较枯燥,如果选取一条主线,并辅以代码,先主后次讲解的话会很容易,而且记忆还更深刻。这里以配置系统时钟函数SystemClock_Config () 的编写流程来讲解时钟树。该函数的功能是利用外部晶振HSE=25 MHz把时钟倍频设置为:HCLK = SYSCLK=PLLCLK = 216 MHz,PCLK1=HCLK/2 =108 MHz,PCLK1=HCLK/4 = 54 MHz下面我们就以这个代码的流程为主线,来分析时钟树,代码流程在时钟树中以数字的大小顺序标识。
图 15-1 STM32F767时钟树1
图 15-2 STM32F767时钟树2
15.2.1 系统时钟
1. ①HSE高速外部时钟信号
HSE是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从4-26 MHz不等。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空为高阻态,当选用无源晶振时,时钟从OSC_IN进入,OSC_OUT输出,并且要配谐振电容。HSE我们使用25 MHz的无源晶振。如果我们使用HSE或者HSE经过PLL倍频之后的时钟作为系统时钟SYSCLK,当HSE故障时候,不仅HSE会被关闭,PLL也会被关闭,此时高速的内部时钟时钟信号HSI会作为备用的系统时钟,直到HSE恢复正常,HSI=16 MHz。
2. ②锁相环PLL
PLL的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。PLL有三个,分别是主PLL、 PLLSAI、PLLI2S,他们均由HSE或者HSI提供时钟输入信号。
主PLL有两路的时钟输出,第一个输出时钟PLLCLK用于系统时钟,F767里面最高是216 MHz,第二个输出用于USB OTG FS的时钟(48 MHz)、RNG和SDMMC时钟(《=48 MHz)。PLLI2S用于生成精确时钟,给I2S、SAI、SPDIFRX提供时钟。PLLSAI为SAI、LCD_TFT提供时钟,同时也可以产生PLLSAI48CLK时钟用于USB OTG FS的时钟(48 MHz)、RNG和SDMMC时钟。
HSE或者HSI经过PLL时钟输入分频因子M(2~63)分频后,成为VCO的时钟输入,VCO的时钟必须在1~2 MHz之间,我们选择HSE=25 MHz作为PLL的时钟输入,M设置为25,那么VCO输入时钟就等于1 MHz。
VCO输入时钟经过VCO倍频因子N倍频之后,成为VCO时钟输出,VCO时钟必须在192~432 MHz之间。我们配置N为432,则VCO的输出时钟等于432 MHz。
VCO输出时钟之后有三个分频因子:PLLCLK分频因子p,USB OTG FS/RNG/SDMMC时钟分频因子Q,分频因子R(F769才有,F767没有)产生DSI时钟驱动屏幕。p可以取值2、4、6、8,我们配置为2,则得到PLLCLK=216 MHz。Q可以取值4~15,但是USB OTG FS必须使用48M,Q=VCO输出时钟432/48=9。有关PLL的配置有一个专门的RCC PLL配置寄存器RCC_PLLCFGR,具体描述看手册即可。
PLL的时钟配置经过,稍微整理下可由如下公式表达:
VCOCLK_IN = PLLCLK_IN / M = HSE / 25 = 1 MHz
VCOCLK_OUT = VCOCLK_IN * N = 1M * 432 = 432 MHz
PLLCLK_OUT=VCOCLK_OUT/P=432/2=216 MHz
USBCLK = VCOCLK_OUT/Q=432/9=48。
3. ③系统时钟SYSCLK
系统时钟来源可以是:HSI、PLLCLK、HSE,具体的由时钟配置寄存器RCC_CFGR的SW位配置。我们这里设置系统时钟:SYSCLK = PLLCLK = 216 MHz。如果系统时钟是由HSE经过PLL倍频之后的PLLCLK得到,当HSE出现故障的时候,系统时钟会切换为HSI=16M,直到HSE恢复正常为止。
4. ④AHB总线时钟HCLK
系统时钟SYSCLK经过AHB预分频器分频之后得到时钟叫APB总线时钟,即HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器RCC_CFGR的HPRE位设置。片上大部分外设的时钟都是经过HCLK分频得到,至于AHB总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB的时钟即可。我们这里设置为1分频,即HCLK=SYSCLK=216 MHz。
5. ⑤APB1总线时钟HCLK1
APB1总线时钟PCLK1由HCLK经过低速APB预分频器得到,分频因子可以是: [1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE1位设置。HCLK1属于低速的总线时钟,最高为54 MHz,片上低速的外设就挂载到这条总线上,比如LPTIM、USART2/3/4/5/7/8、SPI2/3,I2C1/2等。至于APB1总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB1的时钟即可。我们这里设置为4分频,即PCLK1 = HCLK/4 = 54 MHz。
6. ⑥APB2总线时钟HCLK2
APB2总线时钟PCLK2由HCLK经过高速APB2预分频器得到,分频因子可以是: [1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE2位设置。HCLK2属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的GPIO、USART1/6、SPI1等。至于APB2总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB2的时钟即可。我们这里设置为2分频,即PCLK2 = HCLK /2= 108 MHz。
7. 设置系统时钟库函数
上面的6个步骤对应的设置系统时钟库函数如下,为了方便阅读,已经把跟767不相关的代码删掉,把英文注释翻译成了中文。该函数是直接填写相应的结构体,最后调用HAL_RCC_OscConfig函数和HAL_RCC_ClockConfig函数就可以初始化时钟,这里需要注意的是,由于在 PLL 使能后主 PLL 配置参数便不可更改,所以建议先对 PLL 进行配置,然后再使能(选择 HSI 或 HSE 振荡器作为 PLL 时钟源,并配置分频系数 M、 N、 P 和 Q)。
代码 10 设置系统时钟库函数
1 /**
2 * @brief System Clock 配置
3 * system Clock 配置如下 :
4 * System Clock source = PLL (HSE)
5 * SYSCLK(Hz) = 216000000
6 * HCLK(Hz) = 216000000
7 * AHB Prescaler = 1
8 * APB1 Prescaler = 4
9 * APB2 Prescaler = 2
10 * HSE Frequency(Hz) = 25000000
11 * PLL_M = 25
12 * PLL_N = 432
13 * PLL_P = 2
14 * PLL_Q = 9
15 * VDD(V) = 3.3
16 * Main regulator output voltage = Scale1 mode
17 * Flash Latency(WS) = 7
18 * @param 无
19 * @retval 无
20 */
21 void SystemClock_Config(void)
22 {
23 RCC_ClkInitTypeDef RCC_ClkInitStruct;
24 RCC_OscInitTypeDef RCC_OscInitStruct;
25 HAL_StatusTypeDef ret = HAL_OK;
26
27 /*
28 使能HSE,配置HSE为PLL的时钟源,配置PLL的各种分频
29 因子M N P Q
30 * PLLCLK = HSE/M*N/P = 25M / 25 *432 / 2 = 216M
31 */
32 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
33 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
34 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
35 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
36 RCC_OscInitStruct.PLL.PLLM = 25;
37 RCC_OscInitStruct.PLL.PLLN = 432;
38 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
39 RCC_OscInitStruct.PLL.PLLQ = 9;
40
41 ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
42 if (ret != HAL_OK) {
43 while (1) {
44 ;
45 }
46 }
47
48 /* 激活 OverDrive 模式以达到216M频率 */
49 ret = HAL_PWREx_EnableOverDrive();
50 if (ret != HAL_OK) {
51 while (1) {
52 ;
53 }
54 }
55
56 /* 选择PLLCLK作为SYSCLK,并配置 HCLK, PCLK1 and PCLK2
57 的时钟分频因子
58 * SYSCLK = PLLCLK = 216M
59 * HCLK = SYSCLK / 1 = 216M
60 * PCLK2 = SYSCLK / 2 = 108M
61 * PCLK1 = SYSCLK / 4 = 54M
62 */
63 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
64 RCC_CLOCKTYPE_HCLK |
65 RCC_CLOCKTYPE_PCLK1 |
66 RCC_CLOCKTYPE_PCLK2);
67 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
68 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
69 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
70 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
71
72 ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
73 if (ret != HAL_OK) {
74 while (1) {
75 ;
76 }
77 }
78 }
15.2.2 其他时钟
通过对系统时钟设置的讲解,整个时钟树我们已经把握的有六七成,剩下的时钟部分我们讲解几个重要的。
1. RTC时钟
图 15-3 STM32F767 RTC和IWDG时钟
RTCCLK 时钟源可以是 HSE 1 MHz( HSE 由一个可编程的预分频器分频)、 LSE 或者 LSI时钟。选择方式是编程 RCC 备份域控制寄存器 (RCC_BDCR) 中的 RTCSEL[1:0] 位和 RCC时钟配置寄存器 (RCC_CFGR) 中的 RTCPRE[4:0] 位。所做的选择只能通过复位备份域的方式修改。我们通常的做法是由LSE给RTC提供时钟,大小为32.768KHZ。LSE由外接的晶体谐振器产生,所配的谐振电容精度要求高,不然很容易不起震。
2. 独立看门狗时钟
独立看门狗时钟由内部的低速时钟LSI提供,大小为32KHZ。
3. I2S时钟
I2S时钟可由外部的时钟引脚I2S_CKIN输入,也可由专用的PLLI2SCLK提供,具体的由RCC 时钟配置寄存器 (RCC_CFGR)的I2SSCR位配置。我们在使用I2S外设驱动W8978的时候,使用的时钟是PLLI2SCLK,这样就可以省掉一个有源晶振。
4. PHY以太网时钟
F767要想实现以太网功能,除了有本身内置的MAC之外,还需要外接一个PHY芯片,常见的PHY芯片有DP83848和LAN8720,其中DP83848支持MII和RMII接口,LAN8720只支持RMII接口。秉火F767开发板用的是RMII接口,选择的PHY芯片是LAN8720。使用RMII接口的好处是使用的IO减少了一半,速度还是跟MII接口一样。当使用RMII接口时,PHY芯片只需输出一路时钟给MCU即可,如果是MII接口,PHY芯片则需要提供两路时钟给MCU。
5. USB PHY 时钟
F767的USB没有集成PHY,要想实现USB高速传输的话,必须外置USB PHY芯片,常用的芯片是USB3300。当外接USB PHY芯片时,PHY芯片需要给MCU提供一个时钟。
外扩USB3300会占用非常多的IO,跟SDRAM和RGB888的IO会复用的很厉害,鉴于USB高速传输用的比较少,秉火767就没有外扩这个芯片。
6. MCO时钟输出
图 15-4 STM32F767 MCO时钟
MCO是microcontroller clock output的缩写,是微控制器时钟输出引脚,主要作用是可以对外提供时钟,相当于一个有源晶振。F767中有两个MCO,由PA8/PC9复用所得。MCO1所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO1PRE[2:0] 和 MCO1[1:0]位选择。MCO2所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO2PRE[2:0] 和 MCO2位选择。有关MCO的IO、时钟选择和输出速率的具体信息如下表所示
15.3 配置系统时钟实验
15.3.1 使用HSE
一般情况下,我们都是使用HSE,然后HSE经过PLL倍频之后作为系统时钟。F767系统时钟最高为216 MHz,这个是官方推荐的最高的稳定时钟。
如果我们使用库函数编程,当程序来到main函数首先调用SystemClock_Config ()函数把系统时钟初始化成216 MHz,SystemClock_Config ()在文件:main.c中定义。如果我们想把系统时钟设置低一点或者超频的话,可以修改底层的库文件。
15.3.2 使用HSI
当HSE直接或者间接(HSE经过PLL倍频)的作为系统时钟的时候,如果HSE发生故障,不仅HSE会被关闭,连PLL也会被关闭,这个时候系统会自动切换HSI作为系统时钟,此时SYSCLK=HSI=16M,如果没有开启CSS和CSS中断的话,那么整个系统就只能在低速率运行,这是系统跟瘫痪没什么两样。
如果开启了CSS功能的话,那么可以当HSE故障时,在CSS中断里面采取补救措施,使用HSI,重新设置系统频率为216 MHz,让系统恢复正常使用。但这只是权宜之计,并非万全之策,最好的方法还是要采取相应的补救措施并报警,然后修复HSE。临时使用HSI只是为了把损失降低到最小,毕竟HSI较于HSE精度还是要低点。
F103系列中,使用HSI最大只能把系统设置为64M,并不能跟使用HSE一样把系统时钟设置为72M,究其原因是HSI在进入PLL倍频的时候必须2分频,导致PLL倍频因子调到最大也只能到64M,而HSE进入PLL倍频的时候则不用2分频。
在F767中,无论是使用HSI还是HSE都可以把系统时钟设置为216 MHz,因为HSE或者HSI在进入PLL倍频的时候都会被分频为1M之后再倍频。
还有一种情况是,有些用户不想用HSE,想用HSI,但是又不知道怎么用HSI来设置系统时钟,因为调用库函数都是使用HSE,下面我们给出个使用HSI配置系统时钟例子,起个抛砖引玉的作用。
15.3.3 硬件设计
1、RCC
2、LED一个
RCC是单片机内部资源,不需要外部电路。通过LED闪烁的频率来直观的判断不同系统时钟频率对软件延时的效果。
15.3.4 软件设计
我们编写两个RCC驱动文件,bsp_clkconfig.h和bsp_clkconfig.c,用来存放RCC系统时钟配置函数。
1. 编程要点
1、开启HSE/HSI ,并等待 HSE/HSI 稳定
2、设置 AHB、APB2、APB1的预分频因子
3、设置PLL的时钟来源,设置VCO输入时钟 分频因子PLL_M,设置VCO输出时钟
倍频因子PLL_N,设置PLLCLK时钟分频因子PLL_P,设置OTG FS,SDIO,RNG
时钟分频因子 PLL_Q
4、开启PLL,并等待PLL稳定
5、把PLLCK切换为系统时钟SYSCLK
6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
RCC :reset clock control 复位和时钟控制器。本章我们主要讲解时钟部分,特别是要着重理解时钟树,理解了时钟树,F767的一切时钟的来龙去脉都会了如指掌。
15.1 RCC主要作用—时钟部分
设置系统时钟SYSCLK、设置AHB分频因子(决定HCLK等于多少)、设置APB2分频因子(决定PCLK2等于多少)、设置APB1分频因子(决定PCLK1等于多少)、设置各个外设的分频因子;控制AHB、APB2和APB1这三条总线时钟的开启、控制每个外设的时钟的开启。对于SYSCLK、HCLK、PCLK2、PCLK1这四个时钟的配置一般是:HCLK = SYSCLK=PLLCLK = 216 MHz,PCLK1=HCLK/2 = 108 MHz,PCLK1=HCLK/4 = 54 MHz。这个时钟配置也是库函数的标准配置,我们用的最多的就是这个。
15.2 RCC框图剖析—时钟树
时钟树单纯讲理论的话会比较枯燥,如果选取一条主线,并辅以代码,先主后次讲解的话会很容易,而且记忆还更深刻。这里以配置系统时钟函数SystemClock_Config () 的编写流程来讲解时钟树。该函数的功能是利用外部晶振HSE=25 MHz把时钟倍频设置为:HCLK = SYSCLK=PLLCLK = 216 MHz,PCLK1=HCLK/2 =108 MHz,PCLK1=HCLK/4 = 54 MHz下面我们就以这个代码的流程为主线,来分析时钟树,代码流程在时钟树中以数字的大小顺序标识。
图 15-1 STM32F767时钟树1
图 15-2 STM32F767时钟树2
15.2.1 系统时钟
1. ①HSE高速外部时钟信号
HSE是高速的外部时钟信号,可以由有源晶振或者无源晶振提供,频率从4-26 MHz不等。当使用有源晶振时,时钟从OSC_IN引脚进入,OSC_OUT引脚悬空为高阻态,当选用无源晶振时,时钟从OSC_IN进入,OSC_OUT输出,并且要配谐振电容。HSE我们使用25 MHz的无源晶振。如果我们使用HSE或者HSE经过PLL倍频之后的时钟作为系统时钟SYSCLK,当HSE故障时候,不仅HSE会被关闭,PLL也会被关闭,此时高速的内部时钟时钟信号HSI会作为备用的系统时钟,直到HSE恢复正常,HSI=16 MHz。
2. ②锁相环PLL
PLL的主要作用是对时钟进行倍频,然后把时钟输出到各个功能部件。PLL有三个,分别是主PLL、 PLLSAI、PLLI2S,他们均由HSE或者HSI提供时钟输入信号。
主PLL有两路的时钟输出,第一个输出时钟PLLCLK用于系统时钟,F767里面最高是216 MHz,第二个输出用于USB OTG FS的时钟(48 MHz)、RNG和SDMMC时钟(《=48 MHz)。PLLI2S用于生成精确时钟,给I2S、SAI、SPDIFRX提供时钟。PLLSAI为SAI、LCD_TFT提供时钟,同时也可以产生PLLSAI48CLK时钟用于USB OTG FS的时钟(48 MHz)、RNG和SDMMC时钟。
HSE或者HSI经过PLL时钟输入分频因子M(2~63)分频后,成为VCO的时钟输入,VCO的时钟必须在1~2 MHz之间,我们选择HSE=25 MHz作为PLL的时钟输入,M设置为25,那么VCO输入时钟就等于1 MHz。
VCO输入时钟经过VCO倍频因子N倍频之后,成为VCO时钟输出,VCO时钟必须在192~432 MHz之间。我们配置N为432,则VCO的输出时钟等于432 MHz。
VCO输出时钟之后有三个分频因子:PLLCLK分频因子p,USB OTG FS/RNG/SDMMC时钟分频因子Q,分频因子R(F769才有,F767没有)产生DSI时钟驱动屏幕。p可以取值2、4、6、8,我们配置为2,则得到PLLCLK=216 MHz。Q可以取值4~15,但是USB OTG FS必须使用48M,Q=VCO输出时钟432/48=9。有关PLL的配置有一个专门的RCC PLL配置寄存器RCC_PLLCFGR,具体描述看手册即可。
PLL的时钟配置经过,稍微整理下可由如下公式表达:
VCOCLK_IN = PLLCLK_IN / M = HSE / 25 = 1 MHz
VCOCLK_OUT = VCOCLK_IN * N = 1M * 432 = 432 MHz
PLLCLK_OUT=VCOCLK_OUT/P=432/2=216 MHz
USBCLK = VCOCLK_OUT/Q=432/9=48。
3. ③系统时钟SYSCLK
系统时钟来源可以是:HSI、PLLCLK、HSE,具体的由时钟配置寄存器RCC_CFGR的SW位配置。我们这里设置系统时钟:SYSCLK = PLLCLK = 216 MHz。如果系统时钟是由HSE经过PLL倍频之后的PLLCLK得到,当HSE出现故障的时候,系统时钟会切换为HSI=16M,直到HSE恢复正常为止。
4. ④AHB总线时钟HCLK
系统时钟SYSCLK经过AHB预分频器分频之后得到时钟叫APB总线时钟,即HCLK,分频因子可以是:[1,2,4,8,16,64,128,256,512],具体的由时钟配置寄存器RCC_CFGR的HPRE位设置。片上大部分外设的时钟都是经过HCLK分频得到,至于AHB总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB的时钟即可。我们这里设置为1分频,即HCLK=SYSCLK=216 MHz。
5. ⑤APB1总线时钟HCLK1
APB1总线时钟PCLK1由HCLK经过低速APB预分频器得到,分频因子可以是: [1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE1位设置。HCLK1属于低速的总线时钟,最高为54 MHz,片上低速的外设就挂载到这条总线上,比如LPTIM、USART2/3/4/5/7/8、SPI2/3,I2C1/2等。至于APB1总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB1的时钟即可。我们这里设置为4分频,即PCLK1 = HCLK/4 = 54 MHz。
6. ⑥APB2总线时钟HCLK2
APB2总线时钟PCLK2由HCLK经过高速APB2预分频器得到,分频因子可以是: [1,2,4,8,16],具体由时钟配置寄存器RCC_CFGR的PPRE2位设置。HCLK2属于高速的总线时钟,片上高速的外设就挂载到这条总线上,比如全部的GPIO、USART1/6、SPI1等。至于APB2总线上的外设的时钟设置为多少,得等到我们使用该外设的时候才设置,我们这里只需粗线条的设置好APB2的时钟即可。我们这里设置为2分频,即PCLK2 = HCLK /2= 108 MHz。
7. 设置系统时钟库函数
上面的6个步骤对应的设置系统时钟库函数如下,为了方便阅读,已经把跟767不相关的代码删掉,把英文注释翻译成了中文。该函数是直接填写相应的结构体,最后调用HAL_RCC_OscConfig函数和HAL_RCC_ClockConfig函数就可以初始化时钟,这里需要注意的是,由于在 PLL 使能后主 PLL 配置参数便不可更改,所以建议先对 PLL 进行配置,然后再使能(选择 HSI 或 HSE 振荡器作为 PLL 时钟源,并配置分频系数 M、 N、 P 和 Q)。
代码 10 设置系统时钟库函数
1 /**
2 * @brief System Clock 配置
3 * system Clock 配置如下 :
4 * System Clock source = PLL (HSE)
5 * SYSCLK(Hz) = 216000000
6 * HCLK(Hz) = 216000000
7 * AHB Prescaler = 1
8 * APB1 Prescaler = 4
9 * APB2 Prescaler = 2
10 * HSE Frequency(Hz) = 25000000
11 * PLL_M = 25
12 * PLL_N = 432
13 * PLL_P = 2
14 * PLL_Q = 9
15 * VDD(V) = 3.3
16 * Main regulator output voltage = Scale1 mode
17 * Flash Latency(WS) = 7
18 * @param 无
19 * @retval 无
20 */
21 void SystemClock_Config(void)
22 {
23 RCC_ClkInitTypeDef RCC_ClkInitStruct;
24 RCC_OscInitTypeDef RCC_OscInitStruct;
25 HAL_StatusTypeDef ret = HAL_OK;
26
27 /*
28 使能HSE,配置HSE为PLL的时钟源,配置PLL的各种分频
29 因子M N P Q
30 * PLLCLK = HSE/M*N/P = 25M / 25 *432 / 2 = 216M
31 */
32 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
33 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
34 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
35 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
36 RCC_OscInitStruct.PLL.PLLM = 25;
37 RCC_OscInitStruct.PLL.PLLN = 432;
38 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
39 RCC_OscInitStruct.PLL.PLLQ = 9;
40
41 ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
42 if (ret != HAL_OK) {
43 while (1) {
44 ;
45 }
46 }
47
48 /* 激活 OverDrive 模式以达到216M频率 */
49 ret = HAL_PWREx_EnableOverDrive();
50 if (ret != HAL_OK) {
51 while (1) {
52 ;
53 }
54 }
55
56 /* 选择PLLCLK作为SYSCLK,并配置 HCLK, PCLK1 and PCLK2
57 的时钟分频因子
58 * SYSCLK = PLLCLK = 216M
59 * HCLK = SYSCLK / 1 = 216M
60 * PCLK2 = SYSCLK / 2 = 108M
61 * PCLK1 = SYSCLK / 4 = 54M
62 */
63 RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK |
64 RCC_CLOCKTYPE_HCLK |
65 RCC_CLOCKTYPE_PCLK1 |
66 RCC_CLOCKTYPE_PCLK2);
67 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
68 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
69 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
70 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
71
72 ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_7);
73 if (ret != HAL_OK) {
74 while (1) {
75 ;
76 }
77 }
78 }
15.2.2 其他时钟
通过对系统时钟设置的讲解,整个时钟树我们已经把握的有六七成,剩下的时钟部分我们讲解几个重要的。
1. RTC时钟
图 15-3 STM32F767 RTC和IWDG时钟
RTCCLK 时钟源可以是 HSE 1 MHz( HSE 由一个可编程的预分频器分频)、 LSE 或者 LSI时钟。选择方式是编程 RCC 备份域控制寄存器 (RCC_BDCR) 中的 RTCSEL[1:0] 位和 RCC时钟配置寄存器 (RCC_CFGR) 中的 RTCPRE[4:0] 位。所做的选择只能通过复位备份域的方式修改。我们通常的做法是由LSE给RTC提供时钟,大小为32.768KHZ。LSE由外接的晶体谐振器产生,所配的谐振电容精度要求高,不然很容易不起震。
2. 独立看门狗时钟
独立看门狗时钟由内部的低速时钟LSI提供,大小为32KHZ。
3. I2S时钟
I2S时钟可由外部的时钟引脚I2S_CKIN输入,也可由专用的PLLI2SCLK提供,具体的由RCC 时钟配置寄存器 (RCC_CFGR)的I2SSCR位配置。我们在使用I2S外设驱动W8978的时候,使用的时钟是PLLI2SCLK,这样就可以省掉一个有源晶振。
4. PHY以太网时钟
F767要想实现以太网功能,除了有本身内置的MAC之外,还需要外接一个PHY芯片,常见的PHY芯片有DP83848和LAN8720,其中DP83848支持MII和RMII接口,LAN8720只支持RMII接口。秉火F767开发板用的是RMII接口,选择的PHY芯片是LAN8720。使用RMII接口的好处是使用的IO减少了一半,速度还是跟MII接口一样。当使用RMII接口时,PHY芯片只需输出一路时钟给MCU即可,如果是MII接口,PHY芯片则需要提供两路时钟给MCU。
5. USB PHY 时钟
F767的USB没有集成PHY,要想实现USB高速传输的话,必须外置USB PHY芯片,常用的芯片是USB3300。当外接USB PHY芯片时,PHY芯片需要给MCU提供一个时钟。
外扩USB3300会占用非常多的IO,跟SDRAM和RGB888的IO会复用的很厉害,鉴于USB高速传输用的比较少,秉火767就没有外扩这个芯片。
6. MCO时钟输出
图 15-4 STM32F767 MCO时钟
MCO是microcontroller clock output的缩写,是微控制器时钟输出引脚,主要作用是可以对外提供时钟,相当于一个有源晶振。F767中有两个MCO,由PA8/PC9复用所得。MCO1所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO1PRE[2:0] 和 MCO1[1:0]位选择。MCO2所需的时钟源通过 RCC 时钟配置寄存器 (RCC_CFGR) 中的 MCO2PRE[2:0] 和 MCO2位选择。有关MCO的IO、时钟选择和输出速率的具体信息如下表所示
15.3 配置系统时钟实验
15.3.1 使用HSE
一般情况下,我们都是使用HSE,然后HSE经过PLL倍频之后作为系统时钟。F767系统时钟最高为216 MHz,这个是官方推荐的最高的稳定时钟。
如果我们使用库函数编程,当程序来到main函数首先调用SystemClock_Config ()函数把系统时钟初始化成216 MHz,SystemClock_Config ()在文件:main.c中定义。如果我们想把系统时钟设置低一点或者超频的话,可以修改底层的库文件。
15.3.2 使用HSI
当HSE直接或者间接(HSE经过PLL倍频)的作为系统时钟的时候,如果HSE发生故障,不仅HSE会被关闭,连PLL也会被关闭,这个时候系统会自动切换HSI作为系统时钟,此时SYSCLK=HSI=16M,如果没有开启CSS和CSS中断的话,那么整个系统就只能在低速率运行,这是系统跟瘫痪没什么两样。
如果开启了CSS功能的话,那么可以当HSE故障时,在CSS中断里面采取补救措施,使用HSI,重新设置系统频率为216 MHz,让系统恢复正常使用。但这只是权宜之计,并非万全之策,最好的方法还是要采取相应的补救措施并报警,然后修复HSE。临时使用HSI只是为了把损失降低到最小,毕竟HSI较于HSE精度还是要低点。
F103系列中,使用HSI最大只能把系统设置为64M,并不能跟使用HSE一样把系统时钟设置为72M,究其原因是HSI在进入PLL倍频的时候必须2分频,导致PLL倍频因子调到最大也只能到64M,而HSE进入PLL倍频的时候则不用2分频。
在F767中,无论是使用HSI还是HSE都可以把系统时钟设置为216 MHz,因为HSE或者HSI在进入PLL倍频的时候都会被分频为1M之后再倍频。
还有一种情况是,有些用户不想用HSE,想用HSI,但是又不知道怎么用HSI来设置系统时钟,因为调用库函数都是使用HSE,下面我们给出个使用HSI配置系统时钟例子,起个抛砖引玉的作用。
15.3.3 硬件设计
1、RCC
2、LED一个
RCC是单片机内部资源,不需要外部电路。通过LED闪烁的频率来直观的判断不同系统时钟频率对软件延时的效果。
15.3.4 软件设计
我们编写两个RCC驱动文件,bsp_clkconfig.h和bsp_clkconfig.c,用来存放RCC系统时钟配置函数。
1. 编程要点
1、开启HSE/HSI ,并等待 HSE/HSI 稳定
2、设置 AHB、APB2、APB1的预分频因子
3、设置PLL的时钟来源,设置VCO输入时钟 分频因子PLL_M,设置VCO输出时钟
倍频因子PLL_N,设置PLLCLK时钟分频因子PLL_P,设置OTG FS,SDIO,RNG
时钟分频因子 PLL_Q
4、开启PLL,并等待PLL稳定
5、把PLLCK切换为系统时钟SYSCLK
6、读取时钟切换状态位,确保PLLCLK被选为系统时钟
举报