【ARM】---關於STM32F407啟動后的系統時鍾頻率問題


  玩STM32的時間也比較久了,最早的一直玩的是STD標准庫的103系列,但是ST公司也是“與時俱進”,舍棄了當年的標准庫,轉而推廣HAL庫,反正無論怎么樣把,對於STM32的使用也僅僅停留在使用階段,底層涉入不神,我一直覺得真正的大牛們,都是趴在最底層不願意起來的那一群,唉……底層難啊。近來由於課設要求,重新撿起來F407的板子,繼續ST進階之路。長時間不玩,對於STM32陌生了好多,這次玩板子,看的更深了點,花了一下午,終於解決了一個問題:關於板子上電以后系統時鍾頻率的設置問題。  

  以前最先用103的STD庫做開發,后來搞過一段時間寄存器開發,一直都認為STM32的主流時鍾頻率比如72M,168M等是在啟動文件里,main()函數之前SystemInit函數中設置,后來才發現目前的代碼都沒有對他進行設置。本人喜好寄存器版的簡單粗暴,不需要添加過多的文件,直接建個工程,弄個main函數就開始跑程序了,那么問題就來了,這時候的系統時鍾頻率到底是多少呢,SystemInit沒有對他設置,那么到底是在哪里設置了他呢,不然程序怎么能跑起來?帶着這些問題,搞了一下午,也算是了解了!

  OK,。下面,以我自己的STM32F407的板子為例進行測試說明,HSE晶振為8M,HSI為16M

  下面是:啟動文件里面的原版代碼,粘來是方便大家看下,查找源碼可以發現,SystemInit的代碼的第一行是開啟HSI時鍾源,其他的基本都是復位操作,還有一些內存SRAM的設置。我們建立工程之后,直接在main中寫代碼,程序是可以運行的,那么這時候我的407板子的時鍾是多少M呢?

 1 //啟動代碼中的函數
 2 Reset_Handler PROC
 3 EXPORT Reset_Handler [WEAK]
 4 IMPORT SystemInit
 5 IMPORT __main
 6 
 7 LDR R0, =SystemInit
 8 BLX R0
 9 LDR R0, =__main
10 BX R0
11 ENDP

  我分了幾個部分對這個進行測試,

  一、確保程序可以運行,

1 int main(void)
2 {
3     u32 fre1;
4         
5     fre1 = 2;
6 }

  建立完工程,編譯無錯誤之后,寫入上面的代碼,編譯通過后,load到板子里,然后開啟debug,調試,通過watch窗口,查看到fre1變量的值會變成2,如下圖,說明程序可以運行,fre2,fre3是測試程序時添加的變量,這里不用在意。

  二、OK,測試程序可以跑,那么接下來開始思考,這時系統的主頻是多少,我采用了,HAL庫提供的一個函數HAL_RCC_GetSysClockFreq(),通過它可以得到系統主頻的值。代碼也是非常簡單,

1 int main(void)
2 {
3     u32 fre1;
4     fre1 = 2;
5     fre1 = HAL_RCC_GetSysClockFreq();
6 }

  將上面的程序load到板子后,繼續開啟debug模式,查看系統主頻,結果如下,可以看到fre1最后的值是0x00F42400,通過計算器換算之后發現該值其實是16M,那也就是說此時的系統時鍾頻率是16M,這就讓我比較奇怪了,怎么會是16M!

  為了查看為什么此時系統時鍾的值是16M,我查看了以下此時RCC中關於時鍾配置的寄存器的值,如下圖

  

  先來說CFGR寄存器,因為要查看的是系統時鍾,那么就要搞清楚目前系統時鍾的來源是誰,看最低兩位的SW1和SW0,手冊上是這樣描述的!

由上圖可以看到,該兩位都是0,根據手冊,此時的系統時鍾來源是HSI,就沒有HSE和PLL啥事,查閱407板載資料,HSI的時鍾源是16MHZ,至此我明白了,原來此時的系統時鍾,是由系統時鍾HSI時鍾源提供的,那么到底是不是呢,為了驗證我的想法,我繼續查看了CR寄存器,此時,他的值如下,可以看到此時HSION是被置位的,也就是此時開啟了,HSI的時鍾,那應該就沒啥錯了!

 

  不過還有一個疑問,就是到底是誰開啟了HSI時鍾呢,又是在哪段代碼里開啟了呢,這可以說是一個不算問題的問題,但是筆者還真的試圖去源碼當中找過,也真的是太不認真了,后來才發現這個CR寄存器的復位值,就直接將HSION位置1了。這句是直接從手冊中截圖來的,也就是每一次的復位,系統硬件都會把HSION位置1,表明此時開啟了HSI時鍾源!

  而且剛剛還忽略了一個嚴重的問題,在SystemInit()函數中,第一條代碼,就是開啟HSI時鍾,我嘗試將該行代碼注釋掉,發現並沒有任何影響,看來確實是由硬件置位的。看到這里,問題基本被解決了一大半,此時系統的主時鍾基本是有寄存器初始復位值所決定,原來搞了這么久都竟然沒發現這個問題,唉,實在是太不應該,如果有像筆者一樣的菜鳥的話,也在此給各位提個醒。

  三、問題基本被搞清楚了,那么我就想,既然現在是HSI時鍾源,那么晚我想將系統時鍾變為其他的頻率,可以嗎?答案是當然,我沒有直接去設置168M,而是用了簡單的三行代碼,將時鍾源選擇改為了HSE,大家看過時鍾樹圖的都應該清楚,系統時鍾的來源可以是HSE,也可以是PLL,而如果要設為高速時鍾的話,肯定就需要PLL,不過我的目的僅僅是測試下修改時鍾,因此也就不那么麻煩了,我添加了幾行代碼,如下:

 1 int main(void)
 2 {
 3     u32 fre1;
 4     fre1 = 2;
 5     fre1 = HAL_RCC_GetSysClockFreq();
 6     
 7     /*選擇時鍾源為HSE*/
 8     RCC->CR |= 0X1<<16;              //開啟HSE時鍾
 9     while((RCC->CR & 0X1<<16) == 1);  //等待HSERDY就緒
10
11     RCC->CFGR |= 0X1;                //時鍾源選擇為HSE
12     
13     fre1 = HAL_RCC_GetSysClockFreq();
14

  根據以上的代碼,大家應該能猜到fre1的值的變化情況把 ,第一次為2,第二次是16M,那么第三次…………,沒錯就應該是8M了,結果如下:0x007a1200,經過換算,沒錯確實是8M,一切成功。

  四、設置時鍾主頻為168M

  玩過407的人應該都知道,407推薦主頻為168M比較好,那么我們就在這里設置下他的系統主頻,168M是一個高速時鍾,那么我的時鍾源肯定要不能直接使用HSE了,而應該使用PLL(其實PLL的源是HSE),而系統主頻的源是PLL,這三者之間的關系大家要搞清楚。在這里我們先不做大的改動,直接將PLL時鍾源開啟,然后將系統時鍾的源選擇為PLL,測試一下時鍾頻率是多少,代碼如下:

 1 int main(void)
 2 {
 3     u32 fre1 = 0;
 4     
 5     /*選擇PLL的時鍾源是HSE*/
 6     RCC->PLLCFGR |= 0X1<<22;  //必需在開啟PLL和HSE之前設置
 7     
 8     /*開啟HSE*/
 9     RCC->CR |= 0X1<<16;    
10     while((RCC->CR & 0X1<<16) == 1);
11     
12     /*開啟PLL*/
13     RCC->CR |= 0X1<<24;
14     while((RCC->CR & 0X1<<24) == 1);//等待PLLRDY准備就緒
15     
16     /*選擇PLL為系統的時鍾源*/
17     RCC->CFGR |= 0X2;
18     
19     FLASH->ACR = FLASH_ACR_ICEN |FLASH_ACR_DCEN |FLASH_ACR_LATENCY_5WS;  //設置FALSH預取等待時間
20     
21     fre1 = HAL_RCC_GetSysClockFreq();
22 }

  使用PLL的源得到的系統時鍾經過測試為48M,結果如下圖:

  

  明明沒有設置過RCC_PLLCFGR的值,但是竟然還是得到了48M的時鍾,原因是什么呢,跟前面一樣,同樣這里RCC_PLLCFGR的寄存器有個RESET值,有心的朋友可以對照着手冊查看一下,該寄存器的RESET值最終能夠得到pll_m = 16,pll_p = 2,pll_n = 192,計算之后同樣能夠的得到這個48M的時鍾頻率,那么如果你想要設置主頻時鍾為168M,那么在筆者的代碼基礎上修改一下PLL_CFGR寄存器的值,應該就可以解決所有的問題了,着重提醒一下,當你的時鍾設置為168M后,必須要設置FLASH預取等待時間,否則會有問題!

  由於主要目的是為了測試,因此代碼着實有點粗鄙不堪。不夠嚴謹,還望各位能夠見諒,這里也只是希望能夠給各位分享一下,上電之后系統主頻的變化。從最底層的角度來幫助分析,這樣才更加清楚明了,當你底層都會了,那么無論再來什么的庫都不是問題。相反,你只是停留在庫的層面,這個庫你會了,下次換個庫,你又得花時間整!

  個人觀點,不喜勿噴,希望能給予大家幫助。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM