tiny4412開發板時鐘操作示例
在上一節總我們介紹了《Exynos4412晶片的時鐘管理單元》,有了上一節的基礎知識我們就可以寫程式操作CPU的時鐘了。通過操作led來感受時鐘速率的變化。本文總共有三個示例,第一個是寫一個LED迴圈點亮的程式;第二個是將iROM中設定的時鐘禁止掉,觀察LED變化速率;第三個就是設定CPU的時鐘速率為1.4GHz,觀察LED的變化速率。
第一個程式很簡單,有兩個檔案start.S和main.c。其中,start.Sz檔案中設定棧,然後跳轉到C函式中執行。在main.c中設定LED的亮滅。首先,來看start.S內容:
.text .global _start _start: ldr sp, =0x02027400 //設定棧 bl main //跳轉到mian函式開始執行 halt_loop: //死迴圈 b halt_loop
程式很簡單,設定棧,關於為什麼設定棧這裡不再講述,自己可以去某度搜索。然後就是跳轉到main函式中執行,最後就是死迴圈。
main.c檔案的內容如下:
//關於GPM4引腳的巨集 #define GPM4CON (*(volatile long *)0x110002E0) #define GPM4DAT (*(volatile long *)0x110002E4) void delay(int n) { while(n--); } int main() { int i; //讓LED1、LED2、LED3和LED4迴圈閃爍 //1.首先,配置GPM4_0、GPM4_1、GPM4_2和GPM4_3四個引腳為輸出 GPM4CON &= ~(0xFFFF); GPM4CON |= (0x1111); //2.迴圈點亮 while(1) { for (i = 2; i <= 5; i++) { /* 點亮LED : GPIO輸出低電平 */ GPM4DAT &= ~(1 << (i - 2)); delay(100000); /* 熄滅LED : GPIO輸出高電平 */ GPM4DAT |= (1 << (i - 2)); delay(100000); } } return 0; }
很簡單,就是讓LED迴圈點亮;如果不是太懂,可以參照前面的關於操作LED方面的文章。這裡不做詳細介紹。我們可以觀察LED是迴圈點亮的。一直在哪裡死迴圈。
通過閱讀晶片的Spec可以知道在iROM中已經設定了CPU的時鐘頻率為400MHz,就是關於設定CLK_SRC_CPU、APLL_LOCK、APLL_CON0和CLK_DIV_CPU0等暫存器,關於時鐘相關的暫存器的設定大家可以閱讀上篇文章。這裡不贅述了。
現在,來看第二個程式的檔案,是同樣的檔名。其中,start.S檔案沒有更改,只修改了main.c,禁止CPU的時鐘使用FOUTAPLL。將CPU的時鐘源設定為FINPLL,只需要設定CLK_SRC_CPU暫存器的bit0即可實現。並觀察LED亮滅的變化。
main.c的檔案內容如下:
//操作時鐘的巨集
#define CLK_SRC_CPU (*(volatile long *)0x10044200)
//關於GPM4引腳的巨集
#define GPM4CON (*(volatile long *)0x110002E0)
#define GPM4DAT (*(volatile long *)0x110002E4)
void delay(int n)
{
while(n--);
}
int main()
{
int i;
//讓LED1、LED2、LED3和LED4迴圈閃爍
//1.首先,配置GPM4_0、GPM4_1、GPM4_2和GPM4_3四個引腳為輸出
GPM4CON &= ~(0xFFFF);
GPM4CON |= (0x1111);
//將CPU的時鐘源設定為FINPLL;將bit0設定為0
CLK_SRC_CPU &= ~(0x01 << 0);
//2.迴圈點亮
while(1)
{
for (i = 2; i <= 5; i++)
{
/* 點亮LED : GPIO輸出低電平 */
GPM4DAT &= ~(1 << (i - 2));
delay(100000);
/* 熄滅LED : GPIO輸出高電平 */
GPM4DAT |= (1 << (i - 2));
delay(100000);
}
}
return 0;
}
已經做了詳細的註釋,將編譯處的clock.bin檔案燒寫到SD中,將開發板設定為SD啟動模式,插入SD卡執行發現LED亮滅閃爍的時間和上個試驗相比很小,變化很慢。
第三個示例,將CPU的工作頻率設定為1.4GHz,觀察LED的亮滅情況。main.c檔案的內容如下:
// CMU_CPU
#define CLK_SRC_CPU (*(volatile unsigned int *)0x10044200)
#define CLK_DIV_CPU0 (*(volatile unsigned int *)0x10044500)
#define CLK_DIV_CPU1 (*(volatile unsigned int *)0x10044504)
// CMU_DMC
#define CLK_SRC_DMC (*(volatile unsigned int *)0x10040200)
#define CLK_DIV_DMC0 (*(volatile unsigned int *)0x10040500)
#define CLK_DIV_DMC1 (*(volatile unsigned int *)0x10040504)
// CMU_TOP
#define CLK_SRC_TOP0 (*(volatile unsigned int *)0x1003C210)
#define CLK_SRC_TOP1 (*(volatile unsigned int *)0x1003C214)
#define CLK_DIV_TOP (*(volatile unsigned int *)0x1003C510)
// CMU_LEFTBUS
#define CLK_SRC_LEFTBUS (*(volatile unsigned int *)0x10034200)
#define CLK_DIV_LEFTBUS (*(volatile unsigned int *)0x10034500)
// CMU_RIGHTBUS
#define CLK_SRC_RIGHTBUS (*(volatile unsigned int *)0x10038200)
#define CLK_DIV_RIGHTBUS (*(volatile unsigned int *)0x10038500)
// locktime
#define APLL_LOCK (*(volatile unsigned int *)0x10044000)
#define MPLL_LOCK (*(volatile unsigned int *)0x10044008)
#define EPLL_LOCK (*(volatile unsigned int *)0x1003C010)
#define VPLL_LOCK (*(volatile unsigned int *)0x1003C020)
// APLL
#define APLL_CON1 (*(volatile unsigned int *)0x10044104)
#define APLL_CON0 (*(volatile unsigned int *)0x10044100)
// MPLL
#define MPLL_CON0 (*(volatile unsigned int *)0x10040108)
#define MPLL_CON1 (*(volatile unsigned int *)0x1004010c)
// EPLL
#define EPLL_CON2 (*(volatile unsigned int *)0x1003C118)
#define EPLL_CON1 (*(volatile unsigned int *)0x1003C114)
#define EPLL_CON0 (*(volatile unsigned int *)0x1003C110)
// VPLL
#define VPLL_CON0 (*(volatile unsigned int *)0x1003C120)
#define VPLL_CON1 (*(volatile unsigned int *)0x1003C124)
#define VPLL_CON2 (*(volatile unsigned int *)0x1003C128)
//關於GPM4引腳的巨集
#define GPM4CON (*(volatile long *)0x110002E0)
#define GPM4DAT (*(volatile long *)0x110002E4)
/*
* 函式名: system_clock_init
* 功 能: 初始化4412的系統時鐘
* 最終結果: APLL=1.4GHz
*/
void system_clock_init(void)
{
/*
* 1. 在設定APLL之前, 先設定時鐘源為晶振
*/
CLK_SRC_CPU = 0x0;
/*
* 2. 設定APLL
*/
/* 2.1 設定鎖定時間: APLL_CON0中PDIV=3, 所以APLL_LOCK = 270x3 */
APLL_LOCK = 270 * 3;
/* 2.2 設定分頻引數 */
/*
* CORE2_RATIO = 0;
* APLL_RATIO = 2;
* PCLK_DBG_RATIO = 1;
* ATB_RATIO = 6;
* PERIPH_RATIO = 7;
* COREM1_RATIO = 7;
* COREM0_RATIO = 3;
* CORE_RATIO = 0;
*/
CLK_DIV_CPU0 = ((0<<28) | (2<<24) | (1<<20) | (6<<16) | (7<<12) | (7<<8) | (3<<4) | 0);
/*
* CORES_RATIO = 5;
* HPM_RATIO = 0;
* COPY_RATIO = 6;
*/
CLK_DIV_CPU1 = ((5 << 8) |(0 << 4) | (6));
/* 2.3 設定控制引數並使能PLL */
/* 預設值 */
APLL_CON1 = 0x00803800;
/*
* 設定APLL的M,P,S值, APLL輸出 = 0xAF x 24MHz / (3 x 2 ^ 0) = 1.4GHz
* 使能APLL
*/
APLL_CON0 = (1<<31 | 0xAF<<16 | 3<<8 | 0x0);
/* 3. 設定MUX, 使用APLL的輸出 */
CLK_SRC_CPU = 0x01000001;
//return 0;
}
void delay(int n)
{
while(n--);
}
int main()
{
int i;
system_clock_init();
//讓LED1、LED2、LED3和LED4迴圈閃爍
//1.首先,配置GPM4_0、GPM4_1、GPM4_2和GPM4_3四個引腳為輸出
GPM4CON &= ~(0xFFFF);
GPM4CON |= (0x1111);
//2.迴圈點亮
while(1)
{
for (i = 2; i <= 5; i++)
{
/* 點亮LED : GPIO輸出低電平 */
GPM4DAT &= ~(1 << (i - 2));
delay(100000);
/* 熄滅LED : GPIO輸出高電平 */
GPM4DAT |= (1 << (i - 2));
delay(100000);
}
}
return 0;
}
將檔案上傳到伺服器,編譯並燒寫,試驗觀察LED的亮滅情況。關於程式使用的連結指令碼和Makefile檔案這裡不介紹。