【嵌入式开发】时钟初始化 ( 时钟相关概念 | 嵌入式时钟体系 | Lock Time | 分频参数设置 | CPU 异步模式设置 | APLL MPLL 时钟频率设置 )
文章目錄
- 一. 時鐘相關概念解析
- 1. 相關概念術語
- ( 1 ) 時鐘脈沖信號 ( 概念 : 電壓幅度 時間間隔 形成脈沖 | 作用 : 時序邏輯基礎 間隔固定 根據脈沖數量可計算出時間 )
- ( 2 ) 時鐘脈沖頻率 ( 概念 : 單位時間內產生的脈沖個數 )
- (3) 時鐘源 ( 產生來源 : ① 晶振 ② 鎖相環 PLL | 晶振 : 晶體震蕩電路 | PLL 鎖相環 : 晶振 + PLL 合成 | 晶振 與 PLL 對比 優缺點 )
- 二. 時鐘體系簡介
- 1. 2440 開發板 時鐘體系
- (1) 2440 開發板時鐘體系介紹 ( 12MHz 晶振 | 2 PLL : ① MPLL ② UPLL | MPLL -> ① FCLK [ ARM 核 ] ② HCLK [ AHB 總線 ] ③ PCLK [ APB 總線 ] | UPLL -> UCLK [ USB 總線 ] )
- (2) 6410 開發板時鐘體系介紹 ( 12MHz 晶振頻率 | 3 PLL : ① APLL ② MPLL ③ EPLL | APLL -> ACLK [ ARM 核 ] | MPLL -> ① HCLK [ AHB 總線 ] ② PCLK [ APB 總線 ] | EPLL -> SCLK [ USB 總線 ] )
- (3) S5PV210 開發板時鐘體系介紹 ( 24MHz 晶振頻率 | 4 PLL ① APLL ② MPLL ③ EPLL ④ VPLL )
- 三. S3C6410 初始化時鐘
- 1. S3C 6410 時鐘初始化流程簡介
- (1) CPU 頻率變化過程 ( ① 上電后 12MHz | ② 配置 PLL | ③ 處于 Lock Time 頻率 0Hz | ④ 正常 PLL 頻率 )
- (2) 時鐘初始化的四個步驟 ( ① 配置 Lock Time | ② 設置分頻系數 | ③ 設置 APLL MPLL 頻率 | ④ 設置 CPU 工作模式 -> 異步工作模式 )
- 2. S3C 6410 時鐘初始化 匯編代碼編寫
- (1) 配置 Lock Time
- (2) 設置分頻系數
- (3) 設置 CPU 異步工作模式
- (4) 設置 APLL 和 MPLL 時鐘頻率
- (5) 設置 時鐘源
- (6) 代碼示例
- 3. 鏈接器腳本
- 4. Makefile 編譯腳本
- 5. 編譯輸出可執行文件
- 6. 燒寫代碼到開發板并執行
- ( 1 ) OK6410 開發板啟動切換方式
- ( 2 ) 制作 SD 卡啟盤 并 準備程序
- ( 3 ) SecureCRT 連接開發板并燒寫程序
- 7. 將程序燒寫到開發板上運行 ( 僅做參考 )
本博客的參考文章及相關資料下載 :
- 1.本博客代碼及參考手冊下載 :https://download.csdn.net/download/han1202012/10606616
一. 時鐘相關概念解析
1. 相關概念術語
( 1 ) 時鐘脈沖信號 ( 概念 : 電壓幅度 時間間隔 形成脈沖 | 作用 : 時序邏輯基礎 間隔固定 根據脈沖數量可計算出時間 )
時鐘脈沖信號 :
- 1.概念 : 按照 一定的電壓幅度 和 一定的時間間隔 , 連續發出的 脈沖信號, 就是 時鐘 脈沖信號;
- 2.重要作用 : 時鐘脈沖信號 是 時序邏輯的 基礎, 脈沖信號的 間隔是固定的, 可以 根據脈沖信號的個數 及 間隔 計算出對應的時間 ;
- 3.應用場景 : 芯片 中的 晶體管 工作狀態 都是由 0 1 組成, 即 開和關, 控制這些開關操作都是 按照 時鐘信號 的 節奏 進行 的;
- 4.說明示例 : 現在的主流 CPU i7 8700K 主頻是 3.7GHz, 其中 1 GHz = 10^3 MHz = 10^6 KHz = 10^9 Hz 即 10億 Hz, 每秒鐘有 37億 次時鐘脈沖信號; 也就是 經常說的 每秒鐘 運算 37 億次; 當前的超級計算機可以到達 每秒 2億億次;
( 2 ) 時鐘脈沖頻率 ( 概念 : 單位時間內產生的脈沖個數 )
時鐘脈沖頻率 :
- 1.概念 : 單位時間內 產生 的 時鐘脈沖個數 就是 時鐘脈沖頻率;
- 2.舉例 : 1秒中 產生 1次, 就是 1Hz, 1秒鐘產生 100 次就是 100Hz, 上面舉例的 i78700K CPU, 一秒鐘產生 37億次, 就是 3.7GHz 的時鐘脈沖頻率;
(3) 時鐘源 ( 產生來源 : ① 晶振 ② 鎖相環 PLL | 晶振 : 晶體震蕩電路 | PLL 鎖相環 : 晶振 + PLL 合成 | 晶振 與 PLL 對比 優缺點 )
時鐘源 : 時鐘脈沖信號 是由 晶振 或 鎖相環 PLL 產生;
- 1.晶振 : 全稱 晶體振蕩器, 是由 石英晶體 制作的, 石英晶體 ① 按照一定的方位角 切割, 并 ② 在其內部添加電子元件組成振蕩電路;
- ① 震蕩特性 : 如果 給晶振通電, 就會產生機械震蕩, 其 頻率由 制作的材質, 切割角度 等決定;
- ② 物理特性 : 石英非常 穩定, 其控制的 震蕩頻率也很穩定, 其 頻率可以根據集合尺寸精確控制;
- ③ 晶振優勢 : 晶振具有 A. 結構簡單, B. 噪音低, C. 可提供精確定制的頻率, 等優點;
- ④ 晶振缺陷 : A. 生產成本高 , B. 交貨的周期很長;
- 2.PLL(鎖相環) : 鎖相環 比 晶振 更復雜, PLL 需要一個外部晶振作為輸入, PLL 可以對外部晶振產生的頻率進行 加倍 或 分頻 操作, 即 提高 或 降低 頻率;
- ① 使用場景 : 簡單系統一般采用 石英晶振, 復雜的系統采用 晶振 + PLL 合成 提供時鐘源;
- ② 降低成本 : 如果需要特定的時鐘頻率, 可以使用 PLL + 低頻晶振 代替高頻的晶振 , 這樣成本比較低;
- ③ 多時鐘頻率系統 : 如果 在一個設備上需要多個時鐘頻率系統, 可以使用 PLL + 晶振 合成提供時鐘源, PLL 將 晶振頻率 進行 加倍 或 分頻 即可得到不同頻率的時鐘源;
- ④ 與晶振對比 : PLL + 晶振 比 純晶振 成本要低, 并且提供更加靈活多變的時鐘頻率 ;
二. 時鐘體系簡介
時鐘體系學習步驟 : 對不不同的時鐘體系, 需要按照下面的學習步驟學習即可;
① 晶振頻率 ;
② PLL 個數 及 種類 ;
③ PLL 產生的時鐘類型;
④ PLL 產生的時鐘作用;
1. 2440 開發板 時鐘體系
參考手冊 : S3C2440.pdf , 章節 : 7 CLOCK & POWER MANAGEMENT , Page 235;
(1) 2440 開發板時鐘體系介紹 ( 12MHz 晶振 | 2 PLL : ① MPLL ② UPLL | MPLL -> ① FCLK [ ARM 核 ] ② HCLK [ AHB 總線 ] ③ PCLK [ APB 總線 ] | UPLL -> UCLK [ USB 總線 ] )
2440 開發板時鐘體系介紹 :
- 1.晶振頻率 : 12MHz;
- 2.PLL (鎖相環) : 有 2 個 PLL, 分別是 MPLL 和 UPLL;
- 3.產生時鐘個數 : ① MPLL 鎖相環 產生出 FCLK , HCLK, PCLK 三個時鐘; ② UPLL 鎖相環 產生出 UCLK 時鐘;
- 4.各個時鐘作用 :
- ① FCLK 時鐘作用 : 處理器 中使用, ARM 核使用的時鐘是 FCLK, 該時鐘是 MPLL 產生的;
- ② HCLK 時鐘作用 : AHB 總線中使用, 如 LCD, DMA 控制, 該時鐘是 MPLL 產生的;
- ③ PCLK 時鐘作用 : APB 總線中使用, 如 Uart 串口, GPIO, 該時鐘是 MPLL 產生的;
- ④ UCLK 時鐘作用 : USB 總線中使用, 該時鐘是 UPLL 產生的;
- 5.2440 時鐘體系圖示 : 該圖在 S3C2440.pdf 文檔中的 7 CLOCK & POWER MANAGEMENT 章節, 237 頁 ;
(2) 6410 開發板時鐘體系介紹 ( 12MHz 晶振頻率 | 3 PLL : ① APLL ② MPLL ③ EPLL | APLL -> ACLK [ ARM 核 ] | MPLL -> ① HCLK [ AHB 總線 ] ② PCLK [ APB 總線 ] | EPLL -> SCLK [ USB 總線 ] )
參考手冊 : S3C6410X.pdf , 章節 : 3.3.4.1 Clock selection between PLLs and input reference clock , Page 124;
6410 開發板時鐘體系介紹 :
- 1.晶振頻率 : 12MHz;
- 2.PLL (鎖相環) : 有 3 個 PLL, 分別是 APLL , MPLL 和 EPLL;
- 3.產生時鐘個數 : ① APLL 鎖相環 產生出 ACLK 一個時鐘; ② MPLL 鎖相環 產生出 HCLK, PCLK 時鐘; ③ EPLL 產生 SCLK 時鐘;
- 4.各個時鐘作用 :
- ① ACLK 時鐘作用 : 處理器中使用, ARM核中使用 ACLK 時鐘, 該時鐘是 APLL 鎖相環產生;
- ② HCLK 時鐘作用 : AHB 總線中使用, 如 LCD, DMA ; 該時鐘是 MPLL 產生的;
- ③ PCLK 時鐘作用 : APB 總線中使用, 如 Uart 串口, GPIO 中使用, 該時鐘是 MPLL 產生的;
- ④ SCLK 時鐘作用 : USB 總線中使用, 該時鐘是 EPLL 鎖相環產生的;
- 5.6410時鐘體系圖示 : 該圖在 S3C6410X.pdf 文檔中的 3.3.4.1 Clock selection between PLLs and input reference clock 章節, 124 頁 ;
(3) S5PV210 開發板時鐘體系介紹 ( 24MHz 晶振頻率 | 4 PLL ① APLL ② MPLL ③ EPLL ④ VPLL )
參考手冊 : S5PV210_UM_REV1.1.pdf , 章節 : 3.4 CLOCK GENERATION , Page 361;
S5PV210 開發板時鐘體系介紹 :
- 1.晶振頻率 : 24MHz;
- 2.PLL (鎖相環) : 有 4 個 PLL, 分別是 APLL , MPLL , EPLL 和 VPLL;
- 3.S5PV210 的 時鐘體系分類 : 分為 以下 三類 ;
- ① 主系統時鐘體系 : MSYS , 由 APLL 鎖相環產生, 產生的時鐘有 ARMCLK, HCLK_MSYS, PCLK_MSYS , 應用在 ARM 核 中;
- ② 顯示相關時鐘體系 : DSYS , 由 MPLL 鎖相環產生, 產生的時鐘有 HCLK_DSYS, PCLK_DSYS, 主要應用在顯示相關的部件中 ;
- ③ 外圍設備時鐘體系 : PSYS , 由 EPLL 鎖相環產生, 產生的時鐘有 HCLK_PSYS, CLK_DPM, 主要用于外設, 如 Uart 串口 等;
- ④ VPLL 鎖相環產生的時鐘 : VPLL 產生的時鐘 主要用于視頻處理;
- 4.S5PV210時鐘體系圖示 : 該圖在 S5PV210_UM_REV1.1.pdf 文檔中的3.4 CLOCK GENERATION, 361 頁 ;
三. S3C6410 初始化時鐘
1. S3C 6410 時鐘初始化流程簡介
(1) CPU 頻率變化過程 ( ① 上電后 12MHz | ② 配置 PLL | ③ 處于 Lock Time 頻率 0Hz | ④ 正常 PLL 頻率 )
CPU 上電后 從 低頻率 到 高頻率的變化過程 :
- 1.上電后的工作頻率 : 上電后 ARM 核的工作頻率就是晶振頻率, 即 12MHz, 這個速度非常慢;
- 2.配置鎖相環 : 配置鎖相環, 使 頻率 增加;
- 3.Lock Time 時間 : 配置 PLL 鎖相環后, 會出現一段不工作的時間, 此時 CPU 頻率為 0Hz, 這段時間叫 Lock Time;
- 4.正常頻率 : 在 Lock Time 之后, 就會進入正式的 鎖相環 工作頻率, 此時的頻率是 晶振頻率 經過 鎖相環 處理后的 高頻率;
- 5.圖示 : 下圖是處理器上電后各種參數的變化, 橫軸是時間軸, 沒有縱軸, 各個參數在上電后的每個時間段的表現;
整個時鐘初始化流程是需要軟件幫助進行的, 因此這些步驟需要開發者進行開發, 這也是該博客的主要內容;
(2) 時鐘初始化的四個步驟 ( ① 配置 Lock Time | ② 設置分頻系數 | ③ 設置 APLL MPLL 頻率 | ④ 設置 CPU 工作模式 -> 異步工作模式 )
時鐘初始化流程 :
- 1.配置 Lock Time : 配置 PLL 鎖相環后會有一段 CPU 頻率為 0 的時間, 這段時間處理器不工作, 這段時間就是 Lock Time;
- 2.設置分頻系數 : 通過 為 不同的時鐘設置不同的分頻系數, 根據這個分頻系數, 來確定每個時鐘的頻率;
- 3.設置 APLL MPLL 頻率 : 設置一個時鐘的頻率, 可以根據分頻系數計算出其它所有時鐘的頻率了;
- 4.設置 CPU 工作模式 : 如果 FCLK 與 HCLK 的頻率不同, 那么 CPU 需要設置為 異步工作模式, FCLK 是 ARM 核的時鐘, HCLK 是 總線時鐘, 如果兩個時鐘不一致, 需要將 CPU 設置為 異步工作模式;
- ① 常用設置 : 一般情況下 設置 分頻系數的時候, 不會給 FCLK 與 HCLK 設置相同的分頻系數, 因此, 該步驟大部分情況下都要執行;
2. S3C 6410 時鐘初始化 匯編代碼編寫
參考手冊 : ARM芯片 手冊 S3C6410X.pdf ( 基于 6410 開發板 ARM 11 )
- 1.手冊對應章節 : 3 SYSTEM CONTROLLER;
- 2.S3C6410X.pdf手冊下載地址 :
(1) 配置 Lock Time
配置 Lock Time :
- 1.文檔位置 : S3C6410X.pdf 手冊, Page 141, 3.4.2.1 PLL Control Registers 章節;
- 2.默認設置不變 ( 推薦 ) : 一般情況下, 使用開發板的默認設置即可, 如果有特殊定制需求才修改該 PLL_LOCK 寄存器的值;
(2) 設置分頻系數
設置分頻系數 :
- 1.相關文檔位置 : S3C6410X.pdf 手冊, Page 125, 3.3.4.2 ARM and AXI/AHB/APB bus clock generation 章節;
- 2.APLL 鎖相環 : 12 MHz 的晶振頻率, 經過 APLL 鎖相環 產生 輸出時鐘, 該輸出時鐘 經過 DIVARM 分頻, 產生 ARMCLK, 這是 ARM 核使用的時鐘;
- 3.MPLL 鎖相環 : 12MHz 晶振頻率時鐘, 經過 MPLL 鎖相環 產生的 時鐘, 該時鐘 經過 DIVHCLKX2 分頻后, 產生 HCLKx2 時鐘, 同時 DIVHCLKX2 分頻后的時鐘 又 經過不同的 分頻 產生 HCLK, PCLK, CLKJPEG, CLKSECUR 時鐘;
- ① HCLK 時鐘 : HCLKx2 時鐘 經過 DIVHCLK 分頻后, 產生 HCLK 時鐘;
- ② PCLK 時鐘 : HCLKx2 時鐘 經過 DIVPCLK 分頻后, 產生 PCLK 時鐘;
- ③ CLKJPEG 時鐘 : HCLKx2 時鐘 經過 DIVCLKJPEG 分頻后, 產生 CLKJPEG 時鐘;
- ④ CLKSECUR 時鐘 : HCLKx2 時鐘 經過 DIVCLKSECUR 分頻后, 產生 CLKSECUR 時鐘;
- 4.分頻參數參考 : 不同的時鐘分頻器的分頻參數列表 , 來源 S3C6410X.pdf 手冊, Page 126, 3.3.4.2 ARM and AXI/AHB/APB bus clock generation 章節;
- 5.時鐘分頻公式 : 文檔位置 S3C6410X.pdf 手冊, Page 126, 3.4.2.3 Clock divider control register 章節;
- ① DIVARM 分頻公式 : ARMCLK = DOUTAPLL / (ARM_RATIO + 1) , DOUTAPLL 是 APLL 鎖相環輸出的時鐘, ARM_RATIO 是設置的分頻系數;
- ② DIVHCLKX2 分頻公式 : HCLKX2 = HCLKX2IN / (HCLKX2_RATIO + 1), HCLKX2IN 是 MPLL 鎖相環的輸出時鐘頻率, HCLKX2_RATIO 是設置的分頻系數;
- ③ DIVHCLK 分頻公式 : HCLK = HCLKX2 / (HCLK_RATIO + 1), HCLKX2 是 DIVHCLKX2 分頻后的時鐘頻率, HCLK_RATIO 是設置的分頻系數;
- ④ DIVPCLK 分頻公式 : PCLK = HCLKX2 / (PCLK_RATIO + 1), HCLKX2 是 DIVHCLKX2 分頻后的時鐘頻率, PCLK_RATIO 是設置的分頻系數;
- 6.PLL 鎖相環輸出頻率 :
- ① APLL 鎖相環輸出頻率 : 533 MHz ;
- ② MPLL 鎖相環輸出頻率 : 533 MHz ;
- 7.具體參考參數設置 : 從 6410 開發板中的 u-boot 源碼中查找相關的時鐘 分頻系數 ;
- ① DIVARM 分頻參數 : 0 , APLL 輸出頻率為 533MHz, 根據公式計算 ARMCLK 時鐘頻率為 533MHz;
- ② DIVHCLKX2 分頻參數 : 1 , MPLL 輸出頻率 533MHz, 根據公式計算 HCLKX2 時鐘為 266 MHz;
- ③ DIVPCLK 分頻參數 : 3 , HCLKX2 時鐘為 266 MHz, PCLK 頻率為 66MHz;
- ④ DIVHCLK 分頻參數 : 1 , HCLKX2 時鐘為 266 MHz, HCLK 頻率為 133MHz;
設置分頻系數代碼編寫 :
- 1.定義分頻控制寄存器( Clock divider control register ) 地址 : 之前說的 分頻參數 都是通過 CLK_DIV0 寄存器設置的, 將 CLK_DIV0 的地址定義成常量, #define CLK_DIV0 0x7E00F020;
- 2.定義分頻參數的值 : 參考 CLK_DIV0 值的表格 設置 CLK_DIV0 寄存器的實際值;
- ① 定義 ARM_RATIO 分頻參數 : 這個參數設置成 0, CLK_DIV0 寄存器的 [3:0] 位 設置該參數, 該參數單獨為 0x0 << 0;
- ② 定義 HCLKX2_RATIO 分頻參數 : 這個參數設置成 1, CLK_DIV0 寄存器的 [11:9] 位 設置該參數, 值為 0x1 << 9;
- ③ 定義 HCLK_RATIO 分頻參數 : 這個參數設置成 1, CLK_DIV0 寄存器的 [8] 位 設置該參數, 值為 0x1 << 8;
- ④ 定義 PCLK_RATIO 分頻參數 : 這個參數設置成 3, CLK_DIV0 寄存器的 [15:12] 位 設置該參數, 值為 0x3 << 12;
- ⑤ 設置的值 : 將上面四個值匯總起來為 (0x0 << 0) | (0x1 << 9) | (0x1 << 8) | (0x3 << 12) ;
- ⑥ 代碼 : #define CLK_VAL ( (0x0 << 0) | (0x1 << 9) | (0x1 << 8) | (0x3 << 12) ) ;
- 3.裝載 CLK_DIV0 地址到通用寄存器中 : ldr r0, =CLK_DIV0;
- 4.裝載 CLK_DIV0 的寄存器值到通用寄存器中 : ldr r1, =CLK_VAL;
- 5.設置 CLK_DIV0 寄存器的值 : str r1, [r0], 將 r1 寄存器中的內容 存儲到 r0 存儲的地址 指向的內存中 ;
- 6.截止到當前的匯編代碼展示 :
(3) 設置 CPU 異步工作模式
設置 CPU 異步工作模式 :
- 1.相關文檔位置 : S3C6410X.pdf 手冊, Page 169, 3.4.2.14 Others control register 章節;
- 2.Others control register 寄存器 [7] : 第 7 位 [7], 設置為 0 時工作在 異步模式下, 設置為 1 時 工作在 同步模式 下;
- 3.Others control register 寄存器 [6] : 第 6 位 用于選擇 鎖相環輸出源, 設置為 0 選擇 MPLL 鎖相環 輸出時鐘, 設置為 1 選擇 APLL 鎖相環輸出時鐘, 注意 只有在 CPU 同步模式下才設置為1;
匯編代碼編寫 :
- 1.定義 OTHERS 寄存器地址 : #define OTHERS 0x7E00F900;
- 2.將 OTHERS 寄存器地址存儲到 r0 寄存器中 : ldr r0, =OTHERS;
- 3.讀取 OTHERS 寄存器的值 : ldr r1, [r0], 即 將 r0 寄存器存儲的地址指向的內存中的值 裝載到 r1 通用寄存器中;
- 4.設置寄存器值 : 將 r1 寄存器中存儲的 OTHERS 寄存器的 6 和 7 位 清零, 設置 CPU 異步工作模式, 同時設置 MPLL 鎖相環時鐘輸出, bic r1, r1, #0xc0;
- 5.設置 OTHERS 寄存器值 : str r1, [r0], 將 r1 通用寄存器中的值 存儲到 r0 寄存器中保存的地址指向的內存中, 即 OTHERS 寄存器;
- 6.截止到當前的匯編代碼展示 :
(4) 設置 APLL 和 MPLL 時鐘頻率
設置 APLL 和 MPLL 時鐘頻率 :
- **1.相關文檔位置 : **S3C6410X.pdf 手冊, Page 141, 3.4.2.1 PLL Control Registers 章節;
- 2.APLL 和 MPLL 控制寄存器 : 下面兩張表格 分別說明了 兩個 PLL 控制寄存器對應的地址, 以及寄存器每一位設置的值;
- 3.PLL 輸出頻率公式 : FOUT = MDIV X FIN / (PDIV X 2^SDIV), 該公式在 S3C6410X.pdf 文檔 142 頁, 由公式可以得到 PLL 輸出頻率由 MDIV , PDIV, SDIV 三個參數決定, 文檔中給出了一個固定的表格示例, 這里我們選擇 第 5 行的參數進行設置;
匯編代碼編寫 :
- 1.定義 APLL_CON 寄存器地址常量 : #define APLL_CON 0x7E00F00C ;
- 2.定義 MPLL_CON 寄存器地址常量 : #define MPLL_CON 0x7E00F010 ;
- 3.分析 PLL 控制寄存器要設置的位 : 我們要設置 533MHz 的 PLL 輸出頻率, APLL 和 MPLL 都輸出 533MHz 的頻率;
- ① 533MHz 輸出確定的參數 : MDIV 設置成 266, PDIV 設置 3, SDIV 設置 1;
- ② 寄存器值設置 : #define PLL_VAL ( (0x1 << 31) | (266 << 16) | (3 << 8) | (1 << 0) ) ;
- a. 啟用 PLL : [31] 設置成 1 , 設置值為 1 << 31;
- b. 設置 MDIV : [25:16] 位設置成 266, 設置值為 266 << 16;
- c. 設置 PDIV : [13:8] 位 設置成 3, 值為 3 << 8 ;
- d.設置 SDIV : [2:0] 位 設置成 1, 值為 1 << 0;
- e. 最終值為 : (0x1 << 31) | (266 << 16) | (3 << 8) | (1 << 0) ;
- ① 533MHz 輸出確定的參數 : MDIV 設置成 266, PDIV 設置 3, SDIV 設置 1;
- 4.設置 APLL_CON 寄存器的值 : 首先將 APLL_CON 寄存器地址存儲到 r0 寄存器中, 然后將 要設置的值 存儲到 r1 寄存器中, 之后 使用 str 指令將 r1 寄存器的值 存儲到 r0 寄存器中存儲的地址指向的內存中, 即 將 PLL_VAL 值設置給 APLL_CON 寄存器;
- 5.設置 MPLL_CON 寄存器的值 : 首先將 MPLL_CON 寄存器地址存儲到 r0 寄存器中, 然后將 要設置的值 存儲到 r1 寄存器中, 之后 使用 str 指令將 r1 寄存器的值 存儲到 r0 寄存器中存儲的地址指向的內存中, 即 將 PLL_VAL 值設置給 MPLL_CON 寄存器;
- 6.截止到當前的代碼 : 目前已完成 ① 分頻參數設置,② CPU 異步模式設置, ③APLL 和 MPLL 時鐘頻率設置工作;
(5) 設置 時鐘源
時鐘源設置 :
- 1.相關文檔位置 : S3C6410X.pdf 手冊, Page 145, 3.4.2.2 Clock source control register 章節;
- 2.CLK_SRC 寄存器 : 控制時鐘源;
- ① 控制 APLL 時鐘源 : [0] 位 控制 APLL 時鐘源, 如果設置為 0 , 使用晶振作為時鐘源, 如果設置為 1, 使用 APLL 輸出的時鐘作為時鐘源;
- ② 控制 MPLL 時鐘源 : [1] 位 控制 MPLL 時鐘源, 如果設置為 0 , 使用晶振作為時鐘源, 如果設置為 1, 使用 MPLL 輸出的時鐘作為時鐘源;
- ③ 控制 EPLL 時鐘源 : [2] 位 控制 EPLL 時鐘源, 如果設置為 0 , 使用晶振作為時鐘源, 如果設置為 1, 使用 EPLL 輸出的時鐘作為時鐘源;
匯編代碼編寫 :
- 1.定義 CLK_SRC 寄存器地址常量 : #define CLK_SRC 0x7E00F01C ;
- 2.設置 CLK_SRC 寄存器的值 : 將 [1:0] 兩位設置成 1; 首先將 CLK_SRC 寄存器地址存儲到 r0 寄存器中, 然后將 要設置的值 0x3 立即數 存儲到 r1 寄存器中, 之后 使用 str 指令將 r1 寄存器的值 存儲到 r0 寄存器中存儲的地址指向的內存中, 即 將 0x3 值設置給 CLK_SRC 寄存器;
(6) 代碼示例
代碼示例 : 截止到當前的代碼示例 ① 設置 MVC 模式 ② 外設基地址初始化, ③ 關閉看門狗, ④ 關閉中斷, ⑤ 關閉 MMU, ⑥ 初始化時鐘, ⑦ 打開 LED 發光二極管;
@**************************** @File:start.S @ @BootLoader 初始化代碼 @**************************** .text @ 宏 指明代碼段 .global _start @ 偽指令聲明全局開始符號 _start: @ 程序入口標志 b reset @ reset 復位異常 ldr pc, _undefined_instruction @ 未定義異常, 將 _undefined_instruction 值裝載到 pc 指針中 ldr pc, _software_interrupt @ 軟中斷異常 ldr pc, _prefetch_abort @ 預取指令異常 ldr pc, _data_abort @ 數據讀取異常 ldr pc, _not_used @ 占用 0x00000014 地址 ldr pc, _irq @ 普通中斷異常 ldr pc, _fiq @ 軟中斷異常 _undefined_instruction: .word undefined_instruction @ _undefined_instruction 標號存放了一個值, 該值是 32 位地址 undefined_instruction, undefined_instruction 是一個地址 _software_interrupt: .word software_interrupt @ 軟中斷異常 _prefetch_abort: .word prefetch_abort @ 預取指令異常 處理 _data_abort: .word data_abort @ 數據讀取異常 _not_used: .word not_used @ 空位處理 _irq: .word irq @ 普通中斷處理 _fiq: .word fiq @ 快速中斷處理 undefined_instruction: @ undefined_instruction 地址存放要執行的內容 nop software_interrupt: @ software_interrupt 地址存放要執行的內容 nop prefetch_abort: @ prefetch_abort 地址存放要執行的內容 nop data_abort: @ data_abort 地址存放要執行的內容 nop not_used: @ not_used 地址存放要執行的內容 nop irq: @ irq 地址存放要執行的內容 nop fiq: @ fiq 地址存放要執行的內容 nop reset: @ reset 地址存放要執行的內容 bl set_svc @ 跳轉到 set_svc 標號處執行bl set_serial_port @ 設置外設基地址端口初始化bl disable_watchdog @ 跳轉到 disable_watchdog 標號執行, 關閉看門狗bl disable_interrupt @ 跳轉到 disable_interrupt 標號執行, 關閉中斷bl disable_mmu @ 跳轉到 disable_mmu 標號執行, 關閉 MMU init_clock @ 跳轉到 init_clock 標號, 執行時鐘初始化操作bl light_led @ 打開開發板上的 LED 發光二極管set_svc:mrs r0, cpsr @ 將 CPSR 寄存器中的值 導出到 R0 寄存器中bic r0, r0, #0x1f @ 將 R0 寄存器中的值 與 #0x1f 立即數 進行與操作, 并將結果保存到 R0 寄存器中, 實際是將寄存器的 0 ~ 4 位 置 0orr r0, r0, #0xd3 @ 將 R0 寄存器中的值 與 #0xd3 立即數 進行或操作, 并將結果保存到 R0 寄存器中, 實際是設置 0 ~ 4 位 寄存器值 的處理器工作模式代碼msr cpsr, r0 @ 將 R0 寄存器中的值 保存到 CPSR 寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼#define pWTCON 0x7e004000 @ 定義看門狗控制寄存器 地址 ( 6410開發板 ) disable_watchdog: ldr r0, =pWTCON @ 先將控制寄存器地址保存到通用寄存器中mov r1, #0x0 @ 準備一個 0 值, 看門狗控制寄存器都設置為0 , 即看門狗也關閉了str r1, [r0] @ 將 0 值 設置到 看門狗控制寄存器中 mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼disable_interrupt:mvn r1,#0x0 @ 將 0x0 按位取反, 獲取 全 1 的數據, 設置到 R1 寄存器中ldr r0,=0x71200014 @ 設置第一個中斷屏蔽寄存器, 先將 寄存器 地址裝載到 通用寄存器 R0 中 str r1,[r0] @ 再將 全 1 的值設置到 寄存器中, 該寄存器的內存地址已經裝載到了 R0 通用寄存器中ldr r0,=0x71300014 @ 設置第二個中斷屏蔽寄存器, 先將 寄存器 地址裝載到 通用寄存器 R0 中 str r1,[r0] @ 再將 全 1 的值設置到 寄存器中, 該寄存器的內存地址已經裝載到了 R0 通用寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼disable_mmu : mcr p15,0,r0,c7,c7,0 @ 設置 I-Cache 和 D-Cache 失效mrc p15,0,r0,c1,c0,0 @ 將 c1 寄存器中的值 讀取到 R0 通用寄存器中bic r0, r0, #0x00000007 @ 使用 bic 位清除指令, 將 R0 寄存器中的 第 0, 1, 2 三位 設置成0, 代表 關閉 MMU 和 D-Cachemcr p15,0,r0,c1,c0,0 @ 將 R0 寄存器中的值寫回到 C1 寄存器中mov pc, lr @ 返回到 返回點處 繼續執行后面的代碼set_serial_port : ldr r0, =0x70000000 @ 將基地址裝載到 r0 寄存器中, 該基地址 在 arm 核 手冊中定義orr r0, r0, #0x13 @ 設置初始化基地址的范圍, 將 r0 中的值 與 0x13 立即數 進行或操作, 將結果存放到 r0 中mcr p15, 0, r0, c15, c2, 4 @ 將 r0 中的值設置給 c15 協處理器 mov pc, lr#define CLK_DIV0 0x7E00F020 @ 定義 CLK_DIV0 寄存器地址, 時鐘的分頻參數都是通過該寄存器進行設置的 #define OTHERS 0x7E00F900 @ 定義 OTHERS 寄存器地址, 用于設置 CPU 異步工作模式 #define CLK_VAL ( (0x0 << 0) | (0x1 << 9) | (0x1 << 8) | (0x3 << 12) ) @ 設置 CLK_DIV0 寄存器的值, 即 各個時鐘分頻器的參數 #define MPLL_CON 0x7E00F010 @ 定義 MPLL_CON 寄存器地址常量 #define APLL_CON 0x7E00F00C @ 定義 APLL_CON 寄存器地址常量 #define PLL_VAL ( (0x1 << 31) | (266 << 16) | (3 << 8) | (1 << 0) ) @ 設置 PLL 控制寄存器的值 #define CLK_SRC 0x7E00F01C @ 定義 CLK_SRC 時鐘源控制寄存器的地址常量 init_clock : ldr r0, =CLK_DIV0 @ 將 CLK_DIV0 的地址裝載到 r0 通用寄存器中ldr r1, =CLK_VAL @ 將 要設置給 CLK_DIV0 寄存器的值 CLK_VAL 立即數 裝載到 r1 通用寄存器中; str r1, [r0] @ 將 r1 寄存器中的內容 存儲到 r0 存儲的地址 指向的內存中ldr r0, =OTHERS @ 將 OTHERS 寄存器地址存到 r0 通用寄存器中ldr r1, [r0] @ 將 r0 寄存器存儲的地址指向的寄存器中的值讀取到 r1 通用寄存器中bic r1, r1, #0xc0 @ 將 r1 寄存器中的值的 第 6 位 和 第 7 位 設置成 0str r1, [r0] @ 將 r1 寄存器中的值 寫出到 r0 寄存器存儲的地址指向的內存位置 即 OTHERS 寄存器ldr r0, =APLL_CON @ 將 APLL_CON 寄存器地址存到 r0 通用寄存器中ldr r1, =PLL_VAL @ 將 要設置給 APLL_CON 寄存器的值 PLL_VAL 立即數 裝載到 r1 通用寄存器中;str r1, [r0] @ 將 r1 寄存器中的內容 存儲到 r0 存儲的地址 指向的內存中, 即 將 PLL_VAL 的值 設置到 APLL_CON 寄存器中ldr r0, =MPLL_CON @ 將 MPLL_CON 寄存器地址存到 r0 通用寄存器中ldr r1, =PLL_VAL @ 將 要設置給 MPLL_CON 寄存器的值 PLL_VAL 立即數 裝載到 r1 通用寄存器中;str r1, [r0] @ 將 r1 寄存器中的內容 存儲到 r0 存儲的地址 指向的內存中, 即 將 PLL_VAL 的值 設置到 MPLL_CON 寄存器中ldr r0, =CLK_SRC @ 將 CLK_SRC 寄存器地址設置到 r0 通用寄存器中mov r1, #0x3 @ 將 0x3 立即數設置給 r1 寄存器str r1, [r0] @ 將 r1 中存儲的立即數設置給 r0 寄存器存儲的地址指向的內存中, 即 CLK_SRC 寄存器中mov pc, lr#define GPBCON 0x7F008820 #define GPBDAT 0x7F008824 light_led : ldr r0, =GPBCON @ 將 0x7F008820 GPM 控制寄存器的地址 0x7F008820 裝載到 r0 寄存器中ldr r1, =0x1111 @ 設置 GPM 控制寄存器的行為 為 Output 輸出, 即每個對應引腳的設置為 0b0001 值str r1, [r0] @ 將 r1 中的值 存儲到 r0 指向的 GPBCON 0x7F008820 地址的內存中ldr r0, =GPBDAT @ 將 GPBDAT 0x7F008824 地址值 裝載到 r0 寄存器中ldr r1, =0b110000 @ 計算 GPM 數據寄存器中的值, 設置 0 為 低電平, 設置 1 為高電平, 這里設置 0 ~ 3 位為低電平, 其它為高電平str r1, [r0] @ 將 r1 中的值 存儲到 r0 指向的 GPBDAT 0x7F008824 地址的內存中mov pc, lr3. 鏈接器腳本
u-boot.lds 鏈接器腳本 代碼解析 :
- 1.指明輸出格式 ( 處理器架構 ) : 使用 OUTPUT_ARCH(架構名稱) 指明***輸出格式, 即處理器的架構***, 這里是 arm 架構的, OUTPUT_ARCH(arm) ;
- 2.指明輸出程序的入口 : 設置編譯輸出的程序入口位置, 語法為 ENTRY(入口位置), 在上面的 Start.S 中設置的程序入口是 _start, 代碼為 ENTRY(_start) ;
- 3.設置代碼段 : 使用 .text : 設置代碼段;
- 4.設置數據段 : 使用 .data : 設置數據段;
- 5.設置 BSS 段 : 使用 .bss : 設置 BSS 段;
- ( 1 ) 記錄 BSS 段的起始地址 : bss_start = .; ;
- ( 2 ) 記錄 BSS 段的結束地址 : bss_end = .; ;
- 6.對齊 : 每個段都需要設置內存的對齊格式, 使用 . = ALIGN(4); 設置四字節對齊即可;
- 7.代碼示例 :
4. Makefile 編譯腳本
makefile 文件編寫 :
- 1.通用規則 ( 匯編文件編譯規則 ) : 匯編文件 編譯 成同名的 .o 文件, 文件名稱相同, 后綴不同, %.o : %.S, 產生過程是 arm-linux-gcc -g -c $^ , 其中 ^ 標識是所有的依賴文件, 在該規則下 start.S 會被變異成 start.o ;
- 2.通用規則 ( C 文件編譯規則 ) : C 代碼編譯成同名的 .o 文件, %.o : %.c , 產生過程是 arm-linux-gcc -g -c $^ ;
- 3.設置最終目標 : 使用 all: 設置最終編譯目標;
- ( 1 ) 依賴文件 : 產生最終目標需要依賴 start.o 文件, 使用 all: start.o 表示最終目標需要依賴該文件;
- ( 2 ) 鏈接過程 : arm-linux-ld -Tu-boot.lds -o u-boot.elf $^, 需要使用鏈接器腳本進行連接, ①鏈接工具是 arm-linux-ld 工具, ②使用 -Tu-boot.lds 設置鏈接器腳本 是剛寫的 u-boot.lds 鏈接器腳本, ③輸出文件是 u-boot.elf 這是個中間文件, ④ 依賴文件是 $^ 代表所有的依賴;
- ( 3 ) 轉換成可執行二進制文件 : arm-linux-objcopy -O binary u-boot.elf u-boot.bin, 使用 -O binary 設置輸出二進制文件, 依賴文件是 u-boot.elf, 輸出的可執行二進制文件 即 結果是 u-boot.bin ;
- 4.makefile 文件內容 :
5. 編譯輸出可執行文件
編譯過程 :
- 1.文件準備 : 將 匯編代碼 ( start.S ) 鏈接器腳本 ( gboot.lds ) makefile 文件 拷貝到編譯目錄 ;
- 2.執行編譯命令 : make ;
- 3.編譯結果 : 可以看到 生成了 編譯目標文件 start.o, 鏈接文件 u-boot.elf, 可執行的二進制文件 u-boot.bin ;
6. 燒寫代碼到開發板并執行
( 1 ) OK6410 開發板啟動切換方式
OK6410 開發板啟動切換方式 : 通過控制 開發板右側的 8個開關來設置啟動來源;
- 1.sd 卡啟動 : (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1;
- 2.nand flash 啟動 : (1~8) 位置 : x, x, x, 1, 1, 0, 0, 1;
- 3.nor flash 啟動 : (1~8) 位置 : x, x, x, 1, 0, 1, 0, x;
( 2 ) 制作 SD 卡啟盤 并 準備程序
制作 SD 卡啟動盤 :
- 1.找到開發板的燒寫工具 : OK6410-A 開發板的燒寫工具 在開發光盤 A 的 OK6410-A-1G用戶光盤(A)-20160812\Linux-3.0.1\Linux燒寫工具 目錄下, 開發板光盤資料下載地址 ;
- 2.設置 SD_Writer.exe 屬性 ( win10系統需要進行的設置 ) : 右鍵點擊屬性, 在兼容性一欄, 設置 以 Windows 7 兼容模式運行, 并設置 以管理員身份運行此程序 ;
- 3.先格式化 SD 卡 : 注意這里要使用 SD_Writer 中的 format 功能進行格式化 , 按照下面的步驟, 一步一步點擊確定執行 ;
- 4.選擇要燒寫的文件 : 這里選擇 OK6410-A-1G用戶光盤(A)-20160812\Linux-3.0.1\Linux燒寫工具\mmc_ram256.bin 文件;
- 5.燒寫文件到 SD 卡中 : 直接點擊 Program 按鈕, 就將啟動程序燒寫到了 SD 卡中;
- 6.準備 LED 燈程序 : 將編譯出的 gboot.bin 文件名修改成 u-boot.bin, 必須修改成該文件名, 否則無法燒寫上去;
- 7.將程序拷貝到 SD 卡中 : 將程序直接拷貝到 SD 卡中即可;
參考資料 : OK6410燒寫裸板程序方法
這是之前寫過的博客, 僅作為參考;
( 3 ) SecureCRT 連接開發板并燒寫程序
SecureCRT 連接開發板并燒寫程序 步驟 :
- 1.硬件連接操作 : 使用 USB 轉 串口工具 將電腦 與 開發板鏈接, USB 插在電腦端, 串口端插在 開發板上, 插上電源適配器, 但是不要打開電源開關;
- 2.開發板設置 : 將開發板右側的開關設置成 SD 卡啟動, 即 (1~8) 位置 : 0, 0, 0, 1, 1, 1, 1, 1; 該步驟很重要;
- 2.查詢串口端口號 : 在設備管理器中查看串口端口號, 這里可以看到是 COM9;
- 3.SecureCRT 連接串口 : 打開 SecureCRT 軟件, 點擊快速連接, 然后在彈出的對話框中按照下面進行配置, ① 首先要選擇 Serial 協議, ② 然后選擇端口, 這個端口從設備管理器中查看, ③ 波特率選擇 115200, ④ 取消 RTS/CTS 選項;
- 4.打開開發板 ( 很重要 ) : 選中 SecureCRT 軟件, 然后按住空格鍵不放, 這個操作很重要, 打開開發板開關, ① 先按住空格鍵, ②再打開開關;
- 5.首先格式化 Nand Flash : 選擇 [1] 選項, 格式化 Nand Flash;
- 6.選擇從 SD 卡中燒寫 : 選擇 [2] Burn image from SD card 選項, 從 SD 卡中向開發板燒寫程序;
- 7.選擇燒寫 u-boot : 選擇 [2] Flash u-boot, 燒寫 u-boot, 會從 SD 卡中查找 u-boot.bin 文件, 然后燒寫到 nand flash 中, 如果 SD 卡中 沒有 u-boot.bin 會報錯;
- 8.設置從 Nand Flash 啟動 : 設置開發板上的啟動開關, (1~8) 位置 : x, x, x, 1, 1, 0, 0, 1; 此時 四個 LED 全亮;
- 9.效果展示 : 設置的 GPBDAT 寄存器值為 0b110000, 四個 LED 燈都亮起來;
- 10.修改 LED 燈顯示參數后顯示結果 : 設置 GPBDAT 寄存器中值為 0b110101 是 第一個 和 第三個 LED 亮起來;
7. 將程序燒寫到開發板上運行 ( 僅做參考 )
燒寫程序并運行 :
- 1.參考步驟 : 燒寫代碼到開發板并執行
- 2.本次運行結果 : 設置的 GPBDAT 寄存器值為 0b110000, 四個 LED 燈都亮起來;
- 3.修改 LED 燈顯示參數后顯示結果 : 設置 GPBDAT 寄存器中值為 0b110101 是 第一個 和 第三個 LED 亮起來;
總結
以上是生活随笔為你收集整理的【嵌入式开发】时钟初始化 ( 时钟相关概念 | 嵌入式时钟体系 | Lock Time | 分频参数设置 | CPU 异步模式设置 | APLL MPLL 时钟频率设置 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【嵌入式开发】 ARM 关闭 MMU (
- 下一篇: 【Android 应用开发】UI绘制流程