以前使用STM32都是使用庫函數開發,最近心血來潮想要使用寄存器來試試手感,於是乎便在工作之余研究了一下STM32F4的時鍾配置,在此將經歷過程寫下來作為鍛煉,同時也供和我一樣的新手參考,如有錯誤或者更好的方法歡迎大家批評指正。
從技術文檔上得到STM32時鍾源有三種, HSI 振盪器時鍾 、HSE 振盪器時鍾 、主 PLL時鍾,由於每個時鍾的工作特性的差異,若想將系統時鍾設置為最高頻時需使用PLL將基礎時鍾源進行倍頻。
由於使用外部晶振倍頻精確度會比內部震盪時鍾高很多,所以一般都是使用外部晶振,這跟我們使用庫開發是一樣的原理,所以一般的配置關鍵點大概如下圖紅框所示:
1、第一步首先要將外部HSE時鍾打開,等待震盪穩定后再進行下一步操作。
2、配置PLL寄存器參數。
3、切換系統時鍾源。
第一步實現:
依據:
開啟HSE時鍾源主要是控制CR寄存器的16位,然后打開后硬件會自動將第17位置位,如果未成功則等待,當然在這個地方可以加入時間等待,如果超時說明打開失敗,進行其他方法設置。
實現:
第二步實現:
依據:
在這里技術文檔上說明了各個參數的設置范圍:
2 ≤ PLLQ ≤ 15 、 PLLP = 2、4、6 或 8、 192 ≤ PLLN ≤ 432 、 2 ≤ PLLM ≤ 63
由於我想將STM32設置成最高頻168M,於是根據以上參數范圍以及計算方法,選擇一組設置參數如下:
PLL_M = 8,PLL_N = 336,PLL_P = 1 (2分頻),PLLQ = 7;
參數確定便可以直接設置,這些位只能在 PLL 已禁止時寫入。
實現:在這里記錄一下自己的小心得,以前配置寄存器都是將要配置的數先算出來,耽誤時間,今天在看技術文檔時突然發現直接用移位即可,且為提高代碼的可讀性,最好是選用或運算單個設置每個設置點。這樣看起來就舒服多了。
第三步實現:
依據:
這個時候就需要將系統時鍾切換過來了,主要是設置SW開關,然后再設置AHB、APB1、APB2、等時鍾,在上時鍾樹上可看出。
還是操作對應的位,在這里又發現一個小技巧,原來STM32系統頭文件已經做好這些設置的宏定義,直接使用即可,而且從可讀性來說大大加強,如下圖所示。最后將設置好的時鍾通過MCO1輸出,檢測。
實現:
整個時鍾就到此配置結束,原以為會夢想成真,可實際卻發現不盡人意,為啥波形沒有呢,苦思冥想了很長時間,最后參考庫函數底層實現方式,加了一句:
然后就完美輸出,在這里我不是很理解為什么要添加這句,以前用msp430的時候好像也沒這個設置,而且我發現光設置CPU等待周期還不行,還得設置前面兩個參數,不然設置的時鍾偏差很大。
實際設置函數如下所示:
1 void SystemClockInit(void) 2 { 3 4 RCC->CR |= RCC_CR_HSEON; 5 while(!(RCC->CR & RCC_CR_HSERDY)){} 6 7 RCC->CR &= ~RCC_CR_PLLON; 8 RCC->PLLCFGR = 0x00000000; 9 //PLL_M = 8,PLL_N = 336,PLL_P = 1 (2分頻) 10 RCC->PLLCFGR |= 8 << 0; 11 RCC->PLLCFGR |= 336 << 6; 12 RCC->PLLCFGR |= 1 << 16; 13 14 RCC->PLLCFGR |= 7 << 24; //配置PLLQ為48M 15 RCC->CR |= RCC_CR_PLLON; 16 17 while(!(RCC->CR & RCC_CR_PLLRDY)){} 18 19 FLASH->ACR = FLASH_ACR_ICEN | FLASH_ACR_DCEN | FLASH_ACR_LATENCY_5WS; 20 21 RCC->CFGR |= RCC_CFGR_HPRE_DIV1; //不分頻使AHB時鍾為168M 22 RCC->CFGR |= RCC_CFGR_PPRE2_DIV2; //APB2 = 84M 23 RCC->CFGR |= RCC_CFGR_PPRE1_DIV4; //APB1 = 42M 24 25 RCC->CFGR |= RCC_CFGR_SWS_PLL; 26 RCC->CFGR |= RCC_CFGR_SW_PLL; 27 28 RCC->CFGR |= 3 << 21; //PLL輸出 29 RCC->CFGR |= 4 << 24; // 2分頻 30 31 }
最后兩分頻的波形顯示如下:
到此配置就結束了,留有一個問題,那就是STM32時鍾配置為啥要配置那個CPU等待周期,也就是這條語句:
歡迎大神不吝賜教,下方留言解答,萬分感謝。