Cortex-M3 入門指南(三):時鍾總線與復位時鍾控制器


 

【reset clock control  復位和時鍾控制器】

時鍾信號對於處理器非常重要,比如我們熟悉的 CPU 就是由時鍾信號驅動的,而主頻就是內核的的時鍾信號頻率。Cortex-M3 有着復雜的時鍾樹架構,而且我們需要在初始化階段配置好時鍾參數。

本文將會先介紹時鍾相關的概念,然后介紹使用庫函數便捷設置時鍾總線的方法,在文章最后再深入學習庫函數背后等效的時鍾寄存器原理。

 

時鍾源

STM32F103 中有 4 種可選時鍾源:

  1. 高速外部時鍾 (HSE): 以外部晶振作時鍾源,晶振頻率可取范圍為 4~16 MHz,常用 8MHz 晶振,開發板上的 8MHz 時鍾就是指的這個。
  2. 高速內部時鍾 (HSI): 由內部 RC 振盪器產生,頻率為8MHz, 無須外接晶振,但精確性比外部時鍾差。
  3. 低速外部時鍾 (LSE): 以外部晶振作時鍾源,可以提供時鍾信號給實時時鍾模塊,一般采用 32.768KHz 晶振,較為少用。
  4. 低速內部時鍾 (LSI): 由內部 RC 振盪器產生,也主要提供信號給實時時鍾模塊,頻率在 30-60KHz 間浮動,較為少用。

單片機啟動時默認使用高速內部時鍾 (HSI),啟動之后可以通過 RCC 時鍾控制寄存器器改用其他時鍾源。

 

系統時鍾 (SYSCLK)

系統時鍾 SYSCLK 最大頻率為 72MHz,它是供 STM32 中絕大部分部件工作的時鍾源。系統時鍾可由 PLL(鎖相環)、HSI 或者 HSE 提供輸入,並且通過 AHB(高速總線) 分頻器分頻后輸出送給各模塊使用。

 

鎖相環 (PLL)

如果打算使單片機運行在最高頻率 (72 MHz),我們還需要倍頻高速時鍾源的時鍾信號。鎖相環能夠將輸出頻率鎖定在輸入頻率的正整數倍。STM32F103 的鎖相環提供了 2 到 16 倍的倍頻系數。假設我們使用高速內部時鍾源 (8 MHz) ,想要使 STM32F103 達到最高主頻 (72 MHz),那么我們就要要啟用鎖相環,設置為 9 倍倍頻,並將 SYSCLK 時鍾源設置為 PLL。

 

時鍾總線

STM32F103 中有 4 條時鍾總線:

  • AHB 高速總線,時鍾為 HCLK,最大頻率為 72 MHz,時鍾信號提供給存儲器,DMA 及 Cortex 內核,是內核運行的時鍾,也就是主頻,它的大小與 STM32 運算速度,數據存取速度密切相關。
  • APB1 低速外設總線,時鍾為 PCLK1,最大頻率為 36 MHz,提供給掛載在APB1總線上的外設, 如 USART2
  • APB2 高速外設總線,時鍾為 PCLK2,最大頻率為 72 MHz,提供給掛載在APB2總線上的外設,如 GPIOUSART1
  • FCLK 自由運行時鍾,獨立於內核運行,一般設置為與 HCLK 同頻率,常用於采樣中斷和調試模塊供時。

 

使用庫函數設置 復位時鍾控制器 (RCC)

復位時鍾控制器是 STM32F103 提供的一組寄存器,負責控制和設置上面提到的時鍾源,鎖相環倍頻,各總線分頻系數以及開關總線上的各類外設。

stm32f1xx_hal 提供了簡潔的接口幫我們設置 RCC 寄存器,足夠滿足日常工作需要。工程上也推薦使用這種方式進行時鍾樹初始化。

下面例子中單片機使用外部 8MHz 晶振,並將所有總線設置為最高頻率:

#![no_main] #![no_std]  extern crate cortex_m; extern crate cortex_m_rt as rt; extern crate panic_halt; extern crate stm32f103xx_hal as hal;  use hal::prelude::*; use hal::stm32f103xx; use rt::entry;  #[entry] fn main() -> ! {  let dp = stm32f103xx::Peripherals::take().unwrap();   let mut flash = dp.FLASH.constrain();  let mut rcc = dp.RCC.constrain();   let clocks = rcc  .cfgr  .use_hse(8.mhz()) // 高速外部時鍾源  .sysclk(72.mhz()) // 系統時鍾  .hclk(72.mhz()) // AHB 高速總線  .pclk1(36.mhz()) // APB1 低速外設總線  .pclk2(72.mhz()) // APB2 高速外設總線  .freeze(&mut flash.acr); // 應用時鍾配置   loop {} }

 

深入了解 RCC 寄存器

RCC 寄存器的設置比其他一般外設寄存器要更為復雜,因此一般不會手動設置。但是我們可以通過學習它來掌握的庫函數背后的原理。

 

RCC 時鍾設置一般分為以下幾個步驟:

  1. 啟用外部晶振 (可選)
  2. 等待外部晶振穩定
  3. 設置各總線分頻系數
  4. 設置 FLASH 等待系數與預讀取
  5. 啟動鎖相環
  6. 等待鎖相環鎖定
  7. 將 SYSCLK 切換到鎖相環信號輸入

 

PS: 這里提到的 FLASH 等待系數和預讀取都與 Cortex-M 架構設計有關。Cortex-M 核心采用了三級管道技術,簡單來說就是當一個指令正在處理時,下一個指令已經被解碼的同時第三個指令已經被預讀取進緩存區了,這鍾處理方式能夠大幅提高處理器的運行效率。另外,FLASH 由於原理限制,很難達到與核心相同的高頻率,因此在核心讀取指令的速度超過 FLASH 發送指令速度的時候,核心需要暫時停下來等待。根據手冊,STM32F103 的 FLASH 等待系數應根據核心頻率 (HCLK) 設置:

HCLK        | FLASH WAIT STATE
-------------------------------
0 - 24 MHz  | 0 wait state
24 - 48 MHz | 1 wait state
48 - 72 MHz | 2 wait state

 

分頻

事實上,AHB,APB1,APB2 等各總線的頻率都嚴格成正整數倍關系,因為它們的時鍾信號並不是單獨產生的,而是根據特定結構分頻出來的。分頻就是按照預分頻系數降低輸入頻率,預分頻系數都為正整數。STM32F103 中的時鍾樹簡化之后是這樣的:

Example

我們這里用寄存器代替庫函數初始化時鍾樹,代碼與上節的庫函數完全等效。下面用到的寄存器有 RCC_CRRCC_CFGRFLASH_ACR,由於篇幅較長,手冊截圖將放在后面以供參考。

use stm32f103xx;  pub fn rcc_clock_init(rcc: &mut stm32f103xx::RCC, flash: &mut stm32f103xx::FLASH) {  // 啟動外部高速時鍾 (HSE)  rcc.cr.write(|w| w.hseon().enabled());   // 等待外部高速時鍾穩定  while !rcc.cr.read().hserdy().is_ready() {}   // 設置分頻 AHB(HCLK) = SYSCLK, APB1(PCLK1) = SYSCLK / 2, APB2(PCK2) = SYSCLK  rcc.cfgr  .write(|w| w.hpre().no_div().ppre1().div2().ppre2().no_div());   // 設置鎖相環為 9 x HSE  rcc.cfgr  .write(|w| w.pllsrc().external().pllxtpre().no_div().pllmul().mul9());   // 設置 flash : two wait states, 啟用預讀取  flash.acr.write(|w| w.latency().two().prftbe().enabled());   // 啟動鎖相環  rcc.cr.write(|w| w.pllon().enabled());   // 等待鎖相環鎖定  while !rcc.cr.read().pllrdy().is_locked() {}   // 使用鎖相環輸出作為 SYSCLK  rcc.cfgr.write(|w| w.sw().pll());   // 等待 SYSCLK 切換為鎖相環  while !rcc.cfgr.read().sws().is_pll() {} }

 

RCC 寄存器手冊 (P85)

 

 

Reference

[CSDN] STM32F10X的時鍾樹及時鍾初始化

STM32中的幾個時鍾SysTick、FCLK、SYSCLK、HCLK

[CSDN] RCC 復位與時鍾控制

 

原文鏈接:Cortex-M3 入門指南(三):時鍾總線與復位時鍾控制器 - 知乎  https://zhuanlan.zhihu.com/p/57918979

 


免責聲明!

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



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