ARM(IMX6U)裸机主频和时钟
參考:Linux之ARM(IMX6U)裸機主頻和時鐘配置
作者:一只青木呀
發(fā)布時間: 2020-08-28 10:39:17
網(wǎng)址:https://blog.csdn.net/weixin_45309916/article/details/108237599
目錄
- 1、I.MX6U 時鐘系統(tǒng)詳解
- 系統(tǒng)時鐘來源(兩個晶振)
- 7路PLL時鐘源(倍頻而來)
- 7路PLL的具體作用
- 時鐘樹簡介
- 2、系統(tǒng)主頻的配置(內(nèi)核時鐘設(shè)置)
- 步驟①:設(shè)置分頻系數(shù)
- 步驟②:設(shè)置PLL1頻率
- 步驟③:暫時切換時鐘源
- 修改I.MX6U主頻的步驟總結(jié)
- 3、兩個PLL對應(yīng)的PFD時鐘配置
- 設(shè)置PLL2的4路PFD 頻率
- 設(shè)置PLL3的4路PFD頻率
- 4、其他外設(shè)的時鐘配置(AHB、IPG和PERCLK 根時鐘)
- 5、實驗程序編寫(內(nèi)核時鐘主頻為528MHz)
- bsp_clk.c
- bsp_clk.h
- main.c
- 6、編譯下載驗證
I.MX6U 系列標準的工作頻率為 528MHz,有些型號甚至可以工作到 696MHz,但是 默認的工作頻率為396MHz,這就造成了浪費了,本次 我們來配置主頻時鐘使其工作在528MHz,以及其他的外設(shè)時鐘源都工作在NXP推薦的工作頻率。
1、I.MX6U 時鐘系統(tǒng)詳解
I.MX6U 的系統(tǒng)主頻為 528MHz,有些型號可以跑到 696MHz,但是默認情況下內(nèi)部 boot rom 會將 I.MX6U 的主頻設(shè)置為 396MHz。我們在使用 I.MX6U的時候肯定是要發(fā)揮它的最大性能,那么主頻肯定要設(shè)置到 528MHz(其它型號可以設(shè)置更高,比如 696MHz),其它的外設(shè)時鐘也要設(shè)置到 NXP 推薦的值。可參考NXP官方參考手冊。
系統(tǒng)時鐘來源(兩個晶振)
打開 I.MX6U-ALPHA 開發(fā)板原理圖,開發(fā)板時鐘原理圖如圖:
I.MX6U-ALPHA 開發(fā)板的系統(tǒng)時鐘來源于兩部分: 32.768KHz 和24MHz 的晶振
-
32.768KHz 晶振是 I.MX6U 的 RTC (實時時鐘,不參與整個系統(tǒng))時鐘源
-
24MHz 晶振是 I.MX6U 內(nèi)核和其它外設(shè)的時鐘源,看原理圖是接在了6ull的T16、T17這兩個IO上。
7路PLL時鐘源(倍頻而來)
I.MX6U 的外設(shè)有很多,不同的外設(shè)時鐘源不同, NXP 將這些外設(shè)的時鐘源進行了分組,一共有 7 組,這 7 組時鐘源都是從 24MHz 晶振 PLL(倍頻) 而來的,因此也叫做 7 組 PLL,這 7 組 PLL結(jié)構(gòu)如圖 :
7路PLL的具體作用
| ARM_PLL(PLL1) | 此路 PLL 是供ARM 內(nèi)核(主頻)使用的, ARM 內(nèi)核時鐘就是由此 PLL生成的,此 PLL 通過編程的方式最高可倍頻到 1.3GHz。 |
| 528_PLL(PLL2) | 此路 PLL 也叫做 System_PLL,此路 PLL 是固定的 22 倍頻,不可編程修改。因此,此路 PLL 時鐘=24MHz * 22 = 528MHz,這也是為什么此 PLL 叫做 528_PLL 的原因。此 PLL 分出了 4 路 PFD,分別為: PLL2_PFD0~PLL2_PFD3,這 4 路 PFD 和 528_PLL共同作為其它很多外設(shè)的根時鐘源。通常 528_PLL 和這 4 路 PFD 是 I.MX6U 內(nèi)部系統(tǒng)總線的時鐘源,比如內(nèi)處理邏輯單元、 DDR 接口、 NAND/NOR 接口等等。 |
| USB1_PLL(PLL3) | 此路 PLL 主要用于 USBPHY,此PLL 也有四路 PFD,為:PLL3_PFD0~PLL3_PFD3, USB1_PLL 是固定的 20 倍頻,因此 USB1_PLL=24MHz *20=480MHz。USB1_PLL雖然主要用于USB1PHY,但是其和四路PFD同樣也可以作為其他外設(shè)的根時鐘源。 |
| USB2_PLL(PLL7,沒有寫錯!就是 PLL7,雖然序號標為 4,但是實際是 PLL7) | 看名字就知道此路PLL是給USB2PHY使用的。同樣的,此路PLL固定為20倍頻,因此也是480MHz。 |
| ENET_PLL(PLL6) | 此路 PLL 固定為 20+5/6 倍頻,因此 ENET_PLL=24MHz * (20+5/6)= 500MHz。此路 PLL 用于生成網(wǎng)絡(luò)所需的時鐘,可以在此 PLL 的基礎(chǔ)上生成 25/50/100/125MHz的網(wǎng)絡(luò)時鐘。 |
| VIDEO_PLL(PLL5) | 此路 PLL 用于視頻顯示相關(guān)的外設(shè),比如 LCD,此路 PLL 的倍頻可以調(diào)整, PLL 的輸出范圍在 650MHz~1300MHz。此路 PLL 在最終輸出的時候還可以進行分頻,可選 1/2/4/8/16 分頻。 |
| AUDIO_PLL(PLL4) | 此路 PLL 用于音頻相關(guān)的外設(shè),此路 PLL 的倍頻可以調(diào)整, PLL的輸出范圍同樣也是 650MHz~1300MHz,此路 PLL 在最終輸出的時候也可以進行分頻,可選1/2/4 分頻 |
時鐘樹簡介
I.MX6U 的所有外設(shè)時鐘源都是從這 7 路 PLL 和有些 PLL 的PFD 而來的,這些外設(shè)究竟是如何選擇 PLL 或者 PFD 的?這個就要借助《IMX6ULL 參考手冊》里面的時鐘樹了,在“Chapter 18 Clock Controller Module (CCM)”的 18.3 小節(jié)給出了 I.MX6U詳細的時鐘樹圖,如圖:
在圖中一共有三部分: CLOCK_SWITCHER、 CLOCK ROOT GENERATOR 和SYSTEM CLOCKS。其中左邊的 CLOCK_SWITCHER就是那 7 路 PLL 和8 路 PFD,右邊的 SYSTEM CLOCKS就是芯片外設(shè),中間的 CLOCK ROOT GENERATOR是最復(fù)雜的!這一部分就像“月老”一樣, 給左邊的CLOCK_SWITCHER和右邊的SYSTEM CLOCKS進行牽線搭橋。外設(shè)時鐘源是有多路可以選擇的, CLOCK ROOT GENERATOR 就負責(zé)從 7 路PLL 和 8 路 PFD 中選擇合適的時鐘源給外設(shè)使用。
具體操作肯定是設(shè)置相應(yīng)的寄存器,我們以ESAI 這個外設(shè)為例, ESAI 的時鐘圖如圖:
在圖中我們分為了 3 部分,這三部分如下:
①、此部分是時鐘源選擇器, ESAI 有 4 個可選的時鐘源: PLL4、 PLL5、 PLL3_PFD2 和pll3_sw_clk 。 具 體 選 擇 哪 一 路 作 為 ESAI 的 時 鐘 源 是 由 寄 存 器 CCM->CSCMR2 的ESAI_CLK_SEL 位來決定的,用戶可以自由配置,配置如圖:
②、此部分是 ESAI 時鐘的前級分頻,分頻值由寄存器 CCM_CS1CDR 的 ESAI_CLK_PRED來確定的,可設(shè)置 1~8 分頻,假如現(xiàn)在 PLL4=650MHz,我們選擇 PLL4 作為 ESAI 時鐘,前級分頻選擇 2 分頻,那么此時的時鐘就是 650/2=325MHz。
③、此部分又是一個分頻器,對②中輸出的時鐘進一步分頻,分頻值由寄存器CCM_CS1CDR 的 ESAI_CLK_PODF 來決定,可設(shè)置 1~8 分頻。假如我們設(shè)置為 8 分頻的話,經(jīng)過此分頻器以后的時鐘就是 325/8=40.625MHz。因此最終進入到 ESAI 外設(shè)的時鐘就是40.625MHz。
2、系統(tǒng)主頻的配置(內(nèi)核時鐘設(shè)置)
I.MX6U 的時鐘系統(tǒng)前面已經(jīng)分析的差不多了,現(xiàn)在就可以開始設(shè)置相應(yīng)的時鐘頻率了。先從主頻開始,我們將 I.MX6U 的主頻設(shè)置為 528MHz,根據(jù)時鐘樹可以看到ARM 內(nèi)核時鐘如圖所示:
圖中各部分詳解如下:
①、內(nèi)核時鐘源來自于 PLL1,假如此時 PLL1 為 996MHz。
②、通過寄存器 CCM_CACRR 的 ARM_PODF 位對 PLL1 進行分頻,可選擇 1/2/4/8 分頻,假如我們選擇 2 分頻,那么經(jīng)過分頻以后的時鐘頻率是 996/2=498MHz。
③、大家不要被此處的 2 分頻給騙了,此處沒有進行 2 分頻(我就被這個 2 分頻騙了好久,主頻一直配置不正確!)。
④、經(jīng)過第②步 2 分頻以后的 498MHz 就是 ARM 的內(nèi)核時鐘,也就是 I.MX6U 的主頻。
步驟①:設(shè)置分頻系數(shù)
經(jīng)過上面幾步的分析可知,假如我們要設(shè)置內(nèi)核主頻為 528MHz,那么 PLL1 可以設(shè)置為1056MHz,寄存器 CCM_CACRR 的 ARM_PODF 位設(shè)置為 2 分頻即可。同理,如果要將主頻設(shè)置為 696MHz,那么 PLL1 就可以設(shè)置為 696MHz, CCM_CACRR 的 ARM_PODF 設(shè)置為 1 分頻即可(如果選2分頻就超過PLL1的最大值了,手冊上講到PLL的范圍如下所示)。
CCM_CACRR 寄存器結(jié)構(gòu)如圖所示:
寄存器 CCM_CACRR 只有 ARM_PODF 位,可以設(shè)置為 0~ 7,分別對應(yīng) 1~8 分頻。如果要設(shè)置為2分頻的話CCM_CACCR就要設(shè)置為1。
步驟②:設(shè)置PLL1頻率
PLL1 的頻率可以通過寄存器CCM_ANALOG_PLL_ARMn 來設(shè)置,此寄存器結(jié)構(gòu)如圖所示:
在寄存器 CCM_ANALOG_PLL_ARMn 中重要的位如下:
| ENABLE | 時鐘輸出使能位,此位設(shè)置為 1 使能 PLL1 輸出,如果設(shè)置為 0 的話就關(guān)閉 PLL1輸出。 |
| DIV_SELECT | 此位設(shè)置 PLL1 的輸出頻率,可設(shè)置范圍為: 54~108, PLL1 CLK = Fin *div_seclec/2.0(手冊上給的)), Fin=24MHz(晶振)。如果 PLL1 要輸出 1056MHz 的話, div_select 就要設(shè)置為 88。 |
步驟③:暫時切換時鐘源
在修改 PLL1 時鐘頻率的時候我們需要先將內(nèi)核時鐘源改為其他的時鐘源(臨時的時鐘,類似給一個臨時的心臟先用著), PLL1 可選擇的時鐘源如圖所示:
①、 pll1_sw_clk 也就是 PLL1 的最終輸出頻率。
②、此處是一個選擇器,選擇 pll1_sw_clk 的時鐘源,由寄存器 CCM_CCSR 的PLL1_SW_CLK_SEL 位決定 pll1_sw_clk 是選擇 pll1_main_clk 還是 step_clk。
正常情況下應(yīng)該選擇 pll1_main_clk,但是如果要對 pll1_main_clk(PLL1)的頻率進行調(diào)整的話,比如我們要設(shè)置PLL1=1056MHz,此時就要先將 pll1_sw_clk 切換到 step_clk 上(臨時的時鐘,類似給一個臨時的心臟先用著)。等 pll1_main_clk 調(diào)整完成以后再切換回來。
③、此處也是一個選擇器,選擇 step_clk 的時鐘源,由寄存器 CCM_CCSR 的 STEP_SEL 位來決定 step_clk 是選擇 osc_clk 還是 secondary_clk。一般首選 osc_clk,也就是 24MHz 的晶振(因為系統(tǒng)一上電此晶振一直在運行)。這里我們就用到了一個寄存器 CCM_CCSR,此寄存器結(jié)構(gòu)如圖所示:
寄存器 CCM_CCSR 我們只用到了 STEP_SEL、 PLL1_SW_CLK_SEL 這兩個位,一個是用來選擇 step_clk 時鐘源的,一個是用來選擇 pll1_sw_clk 時鐘源的。
修改I.MX6U主頻的步驟總結(jié)
到這里,修改 I.MX6U 主頻的步驟就很清晰了,修改步驟如下:
①、 設(shè)置寄存器 CCSR 的 STEP_SEL 位,設(shè)置 step_clk 的時鐘源為 24M 的晶振。
②、設(shè)置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,設(shè)置 pll1_sw_clk 的時鐘源為step_clk=24MHz,通過這一步我們就將 I.MX6U的主頻先設(shè)置為 24MHz,直接來自于外部的24M 晶振(臨時的時鐘先用著)。
③、設(shè)置寄存器 CCM_ANALOG_PLL_ARMn,將pll1_main_clk(PLL1)設(shè)置為 1056MHz。
④、設(shè)置寄存器 CCSR 的 PLL1_SW_CLK_SEL 位,重新將pll1_sw_clk 的時鐘源切換回pll1_main_clk,切換回來以后的 pll1_sw_clk 就等于 1056MHz。
⑤、最后設(shè)置寄存器 CCM_CACRR 的 ARM_PODF 為 2 分頻, I.MX6U 的內(nèi)核主頻就為1056/2=528MHz。
【注意】:第⑤步驟要先于第④步進行,也就是先設(shè)置好分頻系數(shù),防止一上來接入1056MHZ出問題,因為系統(tǒng)主頻最大就是528MHz!
課堂筆記:
3、兩個PLL對應(yīng)的PFD時鐘配置
設(shè)置好主頻以后我們還需要設(shè)置好其他的 PLL 和 PFD 時鐘,PLL1 已經(jīng)設(shè)置了,PLL2、 PLL3 和 PLL7 固定為 528MHz、 480MHz 和 480MHz, PLL4~PLL6 (音視頻、LCD相關(guān))都是針對特殊外設(shè)的,用到的時候再設(shè)置。
因此,接下來重點就是設(shè)置 PLL2 和 PLL3 的各自 4 路 PFD, NXP 推薦的這 8 路 PFD 頻率如表所示:
| PLL2_PFD0 | 352MHz |
| PLL2_PFD1 | 594MHz |
| PLL2_PFD2 | 400MHz(實際為 396MHz) |
| PLL2_PFD3 | 297MHz |
| PLL3_PFD0 | 720MHz |
| PLL3_PFD1 | 540MHz |
| PLL3_PFD2 | 508.2MHz |
| PLL3_PFD3 | 454.7MHz |
設(shè)置PLL2的4路PFD 頻率
用到寄存器是:CCM_ANALOG_PFD_528n,寄存器結(jié)構(gòu)如圖所示:
從圖可以看出,寄存器 CCM_ANALOG_PFD_528n 其實分為四組,分別對應(yīng)PFD0~PFD3,每組 8 個 bit,我們就以 PFD0 為例,看一下如何設(shè)置 PLL2_PFD0 的頻率。 PFD0對應(yīng)的寄存器位如下:
| PFD0_FRAC | PLL2_PFD0 的分頻數(shù), PLL2_PFD0 的計算公式為 528 * 18 / PFD0_FRAC,此為 可 設(shè) 置 的 范 圍 為 12~35 。 如 果 PLL2_PFD0 的 頻 率 要 設(shè) 置 為 352MHz 的 話PFD0_FRAC=528*18/352=27。 |
| PFD0_STABLE | 此位為只讀位,可以通過讀取此位判斷 PLL2_PFD0 是否穩(wěn)定。 |
| PFD0_CLKGATE | PLL2_PFD0 輸出使能位,為 1 的時候關(guān)閉 PLL2_PFD0 的輸出,為 0 的時候使能輸出。 |
如果我們要設(shè)置 PLL2_PFD0 的頻率為 352MHz 的話就需要設(shè)置 PFD0_FRAC 為 27,PFD0_CLKGATE 為 0 。 PLL2_PFD1~PLL2_PFD3 設(shè) 置 類 似 , 頻 率 計 算 公 式 都 是528*18/PFDX_FRAC(X=1~3) , 因 此 PLL2_PFD1=594MHz 的 話 , PFD1_FRAC=16 ;PLL2_PFD2=400MHz 的話 PFD2_FRAC 不能整除,因此取最近的整數(shù)值,即 PFD2_FRAC=24,這樣 PLL2_PFD2 實際為 396MHz; PLL2_PFD3=297MHz 的話, PFD3_FRAC=32。
設(shè)置PLL3的4路PFD頻率
使用到的寄存器是CCM_ANALOG_PFD_480n,此寄存器結(jié)構(gòu)如圖所示:
從圖可以看出,寄存器 CCM_ANALOG_PFD_480n 和 CCM_ANALOG_PFD_528n的結(jié)構(gòu)是一模一樣的,只是一個是 PLL2 的,一個是 PLL3 的。寄存器位的含義也是一樣的,只是 頻 率 計 算 公 式 不 同 , 比 如 PLL3_PFDX=480*18/PFDX_FRAC(X=0~3) 。 如 果PLL3_PFD0=720MHz 的話, PFD0_FRAC=12;如果 PLL3_PFD1=540MHz 的話, PFD1_FRAC=16;如果 PLL3_PFD2=508.2MHz 的話, PFD2_FRAC=17;如果 PLL3_PFD3=454.7MHz 的話,PFD3_FRAC=19。
課堂筆記:
4、其他外設(shè)的時鐘配置(AHB、IPG和PERCLK 根時鐘)
7 路 PLL 和 8 路 PFD 設(shè)置完成以后最后還需要設(shè)置AHB_CLK_ROOT、IPG_CLK_ROOT和PERCLK_CLK_ROOT的時鐘,因為它們控制了大量的外設(shè)。由上圖分析可知,IPG_CLK_ROOT和PERCLK_CLK_ROOT都要用到AHB_CLK_ROOT,所以首先需要初始化AHB_CLK_ROOT。
查詢芯片手冊,I.MX6U 外設(shè)根時鐘可設(shè)置范圍如圖所示:
圖給出了大多數(shù)外設(shè)的根時鐘設(shè)置范圍, AHB_CLK_ROOT 最高可以設(shè)置 132MHz,IPG_CLK_ROOT和PERCLK_CLK_ROOT最高可以設(shè)置66MHz。那我們就將AHB_CLK_ROOT、IPG_CLK_ROOT 和 PERCLK_CLK_ROOT 分 別 設(shè) 置 為 132MHz 、 66MHz 、 66MHz 。
AHB_CLK_ROOT 和 IPG_CLK_ROOT 的涉及如下圖所示(將上面的圖簡化):
①、此選擇器用來選擇 pre_periph_clk 的時鐘源,可以選擇 PLL2、 PLL2_PFD2、 PLL2_PFD0和 PLL2_PFD2/2。寄存器 CCM_CBCMR 的 PRE_PERIPH_CLK_SEL 位決定選擇哪一個,默認選擇 PLL2_PFD2,因此 pre_periph_clk=PLL2_PFD2=396MHz。
②、此選擇器用來選擇 periph_clk 的時鐘源,由寄存器 CCM_CBCDR 的 PERIPH_CLK_SEL位與 PLL_bypass_en2 組成的或來選擇。當(dāng) CCM_CBCDR 的 PERIPH_CLK_SEL 位為 0 的時候periph_clk=pr_periph_clk=396MHz。
③、通過 CBCDR 的 AHB_PODF 位來設(shè)置 AHB_CLK_ROOT 的分頻值,可以設(shè)置 1~8 分頻,如果想要 AHB_CLK_ROOT=132MHz 的話就應(yīng)該設(shè)置為 3 分頻: 396/3=132MHz。圖 16.1.2中雖然寫的是默認 4 分頻,但是 I.MX6U 的內(nèi)部 boot rom 將其改為了 3 分頻!
④、通過 CBCDR 的 IPG_PODF 位來設(shè)置 IPG_CLK_ROOT 的分頻值,可以設(shè)置 1~4 分頻,IPG_CLK_ROOT 時鐘源是 AHB_CLK_ROOT,要想 IPG_CLK_ROOT=66MHz 的話就應(yīng)該設(shè)置2 分頻: 132/2=66MHz。
最后要設(shè)置的就是 PERCLK_CLK_ROOT 時鐘頻率,其時鐘結(jié)構(gòu)圖如下圖所示:
從 上圖可 以 看 出 , PERCLK_CLK_ROOT 來 源 有 兩 種 : OSC(24MHz) 和IPG_CLK_ROOT,由寄存器 CCM_CSCMR1 的 PERCLK_CLK_SEL 位來決定,如果為 0 的話PERCLK_CLK_ROOT 的 時 鐘 源 就 是 IPG_CLK_ROOT=66MHz 。 可 以 通 過 寄 存 器CCM_CSCMR1 的 PERCLK_PODF 位來設(shè)置分頻,如果要設(shè)置 PERCLK_CLK_ROOT 為 66MHz的話就要設(shè)置為 1 分頻。
在上面的設(shè)置中用到了三個寄存器: CCM_CBCDR、 CCM_CBCMR 和 CCM_CSCMR1,我們依次來看一下這些寄存器, CCM_CBCDR 寄存器結(jié)構(gòu)如圖所示:
寄存器 CCM_CBCDR 各個位的含義如下:
| PERIPH_CLK2_PODF | periph2 時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
| PERIPH2_CLK_SEL | 選擇 peripheral2 的主時鐘,如果為 0 的話選擇 PLL2,如果為 1 的話選擇 periph2_clk2_clk。修改此位會引起一次與 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信號由寄存器 CCM_CDHIPR 中指定位表示。 |
| PERIPH_CLK_SEL | peripheral 主時鐘選擇,如果為 0 的話選擇 PLL2,如果為 1 的話選擇 periph_clk2_clock。修改此位會引起一次與 MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信號由寄存器 CCM_CDHIPR 中指定位表示。 |
| AXI_PODF | axi 時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
| AHB_PODF | ahb 時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。修改此位會引起一次與MMDC 的握手,所以修改完成以后要等待握手完成,握手完成信號由寄存器 CCM_CDHIPR 中指定位表示。 |
| IPG_PODF | ipg 時鐘分頻,可設(shè)置 0~3,分別對應(yīng) 1~4 分頻。 |
| AXI_ALT_CLK_SEL | axi_alt 時鐘選擇,為 0 的話選擇 PLL2_PFD2,如果為 1 的話選擇PLL3_PFD1。 |
| AXI_CLK_SEL | axi 時鐘源選擇,為 0 的話選擇 periph_clk,為 1 的話選擇 axi_alt 時鐘。 |
| FABRIC_MMDC_PODF | fabric/mmdc 時鐘分頻設(shè)置,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
| PERIPH2_CLK2_PODF | periph2_clk2 的時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
接下來看一下寄存器 CCM_CBCMR,寄存器結(jié)構(gòu)如下圖所示:
寄存器 CCM_CBCMR 各個位的含義如下:
| LCDIF1_PODF | lcdif1 的時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
| PRE_PERIPH2_CLK_SEL | pre_periph2 時鐘源選擇, 00 選擇 PLL2, 01 選擇 PLL2_PFD2,10 選擇 PLL2_PFD0, 11 選擇 PLL4。 |
| PERIPH2_CLK2_SEL | periph2_clk2 時鐘源選擇為 0 的時候選擇 pll3_sw_clk,為 1 的時候選擇 OSC。 |
| PRE_PERIPH_CLK_SEL | pre_periph 時鐘源選擇, 00 選擇 PLL2, 01 選擇 PLL2_PFD2, 10 選擇 PLL2_PFD0, 11 選擇 PLL2_PFD2/2。 |
| PERIPH_CLK2_SEL | peripheral_clk2 時鐘源選擇, 00 選擇 pll3_sw_clk, 01 選擇 osc_clk,10 選擇 pll2_bypass_clk。 |
最后看一下寄存器 CCM_CSCMR1,寄存器結(jié)構(gòu)如下圖所示:
此寄存器主要用于外設(shè)時鐘源的選擇,比如 QSPI1、 ACLK、 GPMI、 BCH 等外設(shè),我們重點看一下下面兩個位:
| PERCLK_CK_SEL | perclk 時鐘源選擇,為 0 的話選擇 ipg clk,為 1 的話選擇 osc clk。 |
| PERCLK_PODF | perclk 的時鐘分頻,可設(shè)置 0~7,分別對應(yīng) 1~8 分頻。 |
在修改如下時鐘選擇器或者分頻器的時候會引起與 MMDC 的握手發(fā)生:
①、 mmdc_podf
②、 periph_clk_sel
③、 periph2_clk_sel
④、 arm_podf
⑤、 ahb_podf
發(fā)生握手信號以后需要等待握手完成,寄存器 CCM_CDHIPR 中保存著握手信號是否完成,如果相應(yīng)的位為 1 的話就表示握手沒有完成,如果為 0 的話就表示握手完成,很簡單,這里就不詳細的列舉寄存器 CCM_CDHIPR 中的各個位了。
另外在修改 arm_podf 和 ahb_podf 的時候需要先關(guān)閉其時鐘輸出,等修改完成以后再打開,否則的話可能會出現(xiàn)在修改完成以后沒有時鐘輸出的問題。本教程需要修改寄存器CCM_CBCDR 的 AHB_PODF 位來設(shè)置 AHB_ROOT_CLK 的時鐘,所以在修改之前必須先關(guān)閉AHB_ROOT_CLK 的輸出。但是筆者沒有找到相應(yīng)的寄存器,因此目前沒法關(guān)閉,那也就沒法設(shè)置 AHB_PODF 了。不過 AHB_PODF 內(nèi)部 boot rom 設(shè)置為了 3 分頻,如果 pre_periph_clk 的時鐘源選擇 PLL2_PFD2 的話, AHB_ROOT_CLK 也是 396MHz/3=132MHz。
課堂筆記:
5、實驗程序編寫(內(nèi)核時鐘主頻為528MHz)
我們在上一次實驗的基礎(chǔ)上(ARM(MX6U)裸機按鍵輸入實驗(GPIO的輸出與輸入))進行修改.
bsp_clk.c
#include "bsp_clk.h"/*使能所有外設(shè)時鐘*/ void clk_enable(void) {CCM->CCGR0 =0xFFFFFFFF;CCM->CCGR1 =0xFFFFFFFF;CCM->CCGR2 =0xFFFFFFFF;CCM->CCGR3 =0xFFFFFFFF;CCM->CCGR4 =0xFFFFFFFF;CCM->CCGR5 =0xFFFFFFFF;CCM->CCGR6 =0xFFFFFFFF;} /** @description : 初始化系統(tǒng)時鐘 528Mhz,并且設(shè)置 PLL2 和 PLL3 各個* PFD 時鐘,所有的時鐘頻率均按照 I.MX6U 官方手冊推薦的值.* @param : 無* @return : 無*/ void imx6u_clkinit(void) {/* 1、初始化 ARM 內(nèi)核時鐘(主頻)為 528MHz *//* 1.1、判斷當(dāng)前內(nèi)部bootroom使用哪個時鐘源啟動的,正常情況下是由 pll1_sw_clk 驅(qū)動的,而* pll1_sw_clk 有兩個來源: pll1_main_clk 和 step_clk, 如果要* 讓 I.MX6ULL 跑到 528M, 那必須選擇 pll1_main_clk 作為 pll1 的時鐘* 源。 如果我們要修改 pll1_main_clk 時鐘的話就必須先將 pll1_sw_clk 從* pll1_main_clk 切換到 step_clk,當(dāng)修改完以后再將 pll1_sw_clk 切換* 回 pll1_main_cl, step_clk 等于 24MHz。*/unsigned int reg = 0;if((((CCM->CCSR)>>2) & 0x1) ==0)//內(nèi)部bootroom使用的時鐘是否是pll1_main_clk{CCM->CCSR &= ~(1 << 8); /* 配置 step_clk 時鐘源為 24MHz OSC */CCM->CCSR |= (1 << 2); /* 配置 pll1_sw_clk 時鐘源為 step_clk 24MHz */}/* 1.2、設(shè)置 pll1_main_clk 為 1056MHz,也就是 528*2=1056MHZ,* 因為 pll1_sw_clk 進 ARM 內(nèi)核的時候會被二分頻!* 配置 CCM_ANALOG->PLL_ARM 寄存器* bit13: 1 使能時鐘輸出* bit[6:0]: 88, 由公式: Fout = Fin * div_select / 2.0,* 1056=24*div_select/2.0, 得出: div_select=88。*/// 13位使能 div_select bit0~bit6設(shè)置為88CCM_ANALOG->PLL_ARM = (1 << 13) | ((88 << 0) & 0X7F);CCM->CCSR &= ~(1 << 2); /* 將 pll_sw_clk 時鐘切換回 pll1_main_clk */CCM->CACRR = 1; // 設(shè)置2分頻 ARM 內(nèi)核時鐘為 pll1_sw_clk/2=1056/2=528Mhz 視頻里這一步放到前面,分頻好了再切換/* 2、設(shè)置 PLL2(SYS PLL)4路 PFD */reg = CCM_ANALOG->PFD_528;reg &= ~(0x3f3f3f3f); /* 清除原來的設(shè)置 用16進制計算器計算就行*/reg |= (32<<24); /* PLL2_PFD3=528*18/32=297Mhz */reg |= (24<<16); /* PLL2_PFD2=528*18/24=396Mhz */reg |= (16<<8); /* PLL2_PFD1=528*18/16=594Mhz */reg |= (27<<0); /* PLL2_PFD0=528*18/27=352Mhz */CCM_ANALOG->PFD_528 = reg; /* 設(shè)置 PLL2_PFD0~3 *//* 3、設(shè)置 PLL3(USB1)4路 PFD */reg =0; /* 清零reg */reg = CCM_ANALOG->PFD_480; /* 清除原來的設(shè)置 */reg &= ~(0x3f3f3f3f); reg |= (19<<24); /* PLL3_PFD3=480*18/19=454.74Mhz */reg |= (17<<16); /* PLL3_PFD2=480*18/17=508.24Mhz */reg |= (16<<8); /* PLL3_PFD1=480*18/16=540Mhz */reg |= (12<<0); /* PLL3_PFD0=480*18/12=720Mhz */CCM_ANALOG->PFD_480 = reg; /* 設(shè)置 PLL3_PFD0~3 *//* 4、設(shè)置 AHB 時鐘為最大值 132Mhz */CCM->CBCMR &= ~(3<<18); /* 清除設(shè)置*/CCM->CBCMR |= (1<<18); /* pre_periph_clk=PLL2_PFD2=396MHz 后面3分頻正好就是132MHz*/ CCM->CBCDR &= ~(1<<25); /* periph_clk=pre_periph_clk=396MHz */while(CCM->CDHIPR & (1 << 5)); /* 等待握手完成 (手冊上要求的步驟)*//* 修改 AHB_PODF 位的時候需要先禁止 AHB_CLK_ROOT 的輸出,但是* 我沒有找到關(guān)閉 AHB_CLK_ROOT 輸出的的寄存器,所以就沒法設(shè)置。* 下面設(shè)置 AHB_PODF 的代碼僅供學(xué)習(xí)參考不能直接拿來使用!!* 內(nèi)部 boot rom 將 AHB_PODF 設(shè)置為了 3 分頻,即使我們不設(shè)置 AHB_PODF,* AHB_ROOT_CLK 也依舊等于 396/3=132Mhz。*/ #if 0/* 要先關(guān)閉 AHB_ROOT_CLK 輸出,否則時鐘設(shè)置會出錯 */CCM->CBCDR &= ~(7 << 10); /* CBCDR 的 AHB_PODF 清零 */CCM->CBCDR |= (2 << 10); /* AHB_PODF 3 分頻, AHB_CLK_ROOT=132MHz */while(CCM->CDHIPR & (1 << 5)); /* 等待握手完成 */ #endif/* 5、設(shè)置 IPG_CLK_ROOT成最大值 66Mhz */CCM->CBCDR &= ~(3<<8); /* CBCDR 的 IPG_PODF 清零 */CCM->CBCDR |= (1<<8); /* IPG_PODF 2 分頻, IPG_CLK_ROOT=66MHz *//* 6、設(shè)置 PERCLK_CLK_ROOT 時鐘 */CCM->CSCMR1 &= ~(1<<6); /* PERCLK_CLK_ROOT 時鐘源為 IPG */CCM->CSCMR1 &= ~(0x3f << 0); /* 1分頻 */}bsp_clk.c 中一共有兩個函數(shù): clk_enable 和 imx6u_clkinit
- clk_enable 就是使能 I.MX6U 的所有外設(shè)時鐘
- 函數(shù) imx6u_clkinit 先設(shè)置系統(tǒng)主頻為 528MHz,然后根據(jù)我們分析的 I.MX6U 時鐘系統(tǒng)來設(shè)置 8 路 PFD,最后設(shè)置 AHB、 IPG 和 PERCLK 的時鐘頻率。
bsp_clk.h
#ifndef __BSP_CLK_H #define __BSP_CLK_H#include "imx6ul.h"void clk_enable(void);//使能外設(shè)時鐘 void imx6u_clkinit(void);//初始化時鐘#endif // !__BSP_CLK_H在 bsp_clk.h 文件中添加函數(shù) imx6u_clkinit 的聲明
main.c
修改 main.c 文件,在 main 函數(shù)里面調(diào)用 imx6u_clkinit 來初始化時鐘,代碼如下:
#include "main.h"int main() {int i=0;int keyvalue=0; unsigned char led_status= OFF;unsigned char beep_status= OFF;imx6u_clkinit(); /* 初始化系統(tǒng)時鐘 */ clk_enable(); //使能外設(shè)時鐘led_init(); //初始化LEDinit_beep();//初始化蜂鳴器key_init(); //初始化keywhile(1){keyvalue = key_get_value();if(keyvalue){switch (keyvalue){case KEY_VALUE:beep_status=!beep_status;beep_switch(beep_status);break;default:break;}}i++;if(i == 50){i=0;led_status=!led_status;led_switch(LED0,led_status);}delay(10);}return 0; }6、編譯下載驗證
具體所有代碼在GitHub:裸機主頻時鐘配置
使用 Make 命令編譯代碼,編譯成功以后使用軟件 imxdownload 將編譯完成的 clk.bin 文件下載到 SD 卡中,命令如下:
chmod 777 imxdownload //給予 imxdownload 可執(zhí)行權(quán)限,一次即可 ./imxdownload clk.bin /dev/sdd //燒寫到 SD 卡中燒寫成功以后將 SD 卡插到開發(fā)板的 SD 卡槽中,然后復(fù)位開發(fā)板。本試驗效果其實和試驗“7_key”一樣,但是 LED 燈的閃爍頻率相比試驗“7_key”要快一點。因為試驗“7_key”的主頻是 396MHz,而本試驗的主頻被配置成了 528MHz,因此代碼執(zhí)行速度會變快,所以延時函數(shù)的運行就會加快。
總結(jié)
以上是生活随笔為你收集整理的ARM(IMX6U)裸机主频和时钟的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SharePoint 2013:解决添加
- 下一篇: matlab 取整