一:ADS.12的工程建立與配置
① 新建工程類型爲 ARM Excuteable Image。用於由 ARM 指令的代碼生成一個 ELF 格式的可以執行映象文件。
② 再把lib與inc文件夾拷貝到所建工程的文件夾中,inc文件夾中包含了很多.h文件,其中.c文件在lib中。(後面將對這些文件的作用與含義進行分析)。
③ 把需要用到的函數所在的.c文件添加到工程中,在簡單的現在默認工程中我們要添加這三個文件,
2440init.s(是對板子的啓動初始化,有內存配置,中斷初始化,棧空間的分配,中斷時入棧與出棧的方式寄存器的保存——這部分與具體的板子芯片都十分相關也是系統移植時需要關注的),並且要注意在初始化時跳入C語言的入口點BL Main (在後面自己寫函數時,一定要寫爲Main不要寫成main,不然將找不到入口)。
2440lib.c文件(裏面包含了對芯片的常規初始化,主要是IO的初始化與時鐘頻率初始化要使用到的函數,有時候會有Uart需要的一些函數,但是沒有的時候可以自己在內部加入,因此自己要寫一些十分基本和常用的函數時,可以把這些函數寫入到這個.c文件中,但是是針對某個特殊芯片的的函數,eg:NAND FLASH,IIS,IIC等的操作,最好要在另外建立他的.c文件,這樣文件結構會更加清楚)
2440slib.s文件主要是對CP15這個協處理的配置(內存管理器),配置結束後使內存,cache,CPU協調工作,最開始也對LCD的一些內存區進行了分配等。
④ 建立自己的主函數文件。(文件名字可以是main.c但是裏面的函數一定是Main)
⑤ 寫好自己的主函數後,再進行Debug setting,主要設置的有五項:
Target settings,其中有 Target Name (當前目標設置)Linker(默認,是表示使用什麼連接器),post-Linker是鏈接後生成什麼文件,設置爲ARM from ELF(exe load flash)。
ARM Assembler 與ARM C compiler 都把芯片型號配置爲ARM920T(即你開發板的型號),
ARM Linker
其中下面編譯的內容中可以去掉-map –list list.txt對程序運行沒影響,只是出現一些提示信息。
ARM from ELF 中設置輸出文件的名字。到此一個完整的工程與配置都已經完成。
二、對一個最簡單工程中的頭文件與一些函數作用的分析。
在main.c中一般要包含一下幾個頭文件
(def.h) 定義了一些數據類型,eg:#define U8 char 。目的是增強可移植性。
(option.h) RAM,中斷,棧的基地址定義,與系統時鐘的定義
(2440addr.h) 定義了各種寄存器的地址。
(2440lib.h) 申明瞭2440lib.c中使用的函數,與其中用到的宏定義。
(2440slib.h) 申明瞭2440slib.s中使用到的函數。
函數 Port_Init()中就是對A-J的端口進行了一般的初始化。要修改時可以對照着用戶手冊進行對應的修改。
下面還包括了四個與系統時鐘有關的函數,
void ChangeMPllValue(int mdiv, int pdiv, int sdiv) //對MPLL這個鎖相環進行配置
{
Rmpllcon = (mdiv << 12) | (pdiv <<4) | sdiv;
}
void ChangeClockDivider(int hdivn_val, int pdivn_val),
{
int hdivn=2, pdivn=0;
// hdivn_val (FCLK:HCLK)ratio hdivn
// 11 1:1 (0)
// 12 1:2 (1)
// 13 1:3 (3)
// 14 1:4 (2)
// pdivn_val (HCLK:PCLK)ratio pdivn
// 11 1:1 (0)
// 12 1:2 (1)
switch(hdivn_val) {
case 11: hdivn=0; break;
case 12: hdivn=1; break;
case 13:
case 16: hdivn=3; break;
case 14:
case 18: hdivn=2; break;
}
switch(pdivn_val) {
case 11: pdivn=0; break;
case 12: pdivn=1; break;
}
rCLKDIVN = (hdivn<<1) | pdivn;
switch(hdivn_val) {
case 16: // when 1, HCLK=FCLK/8.
rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<8);
break;
case 18: // when 1, HCLK=FCLK/6.
rCAMDIVN = (rCAMDIVN & ~(3<<8)) | (1<<9);
break;
}
if(hdivn!=0)
MMU_SetAsyncBusMode();
else
MMU_SetFastBusMode();
}
void ChangeUPllValue(int mdiv, int pdiv, int sdiv) //對UPLL這個鎖相環的配置
{
rUPLLCON = (mdiv<<12) | (pdiv<<4) | sdiv;
}
static void cal_cpu_bus_clk(void)
{
U32 val;
U8 m, p, s;
val = rMPLLCON; //MPLL控制寄存器
m = (val>>12)&0xff; //獲得MDIV的值
p = (val>>4)&0x3f; //獲得PDIV的值
s = val&3; //獲得SDIV的值
//(m+8)*FIN*2 不要超出32位數!
FCLK = ((m+8)*(FIN/100)*2)/((p+2)*(1<<s))*100; //MPLL與FCLK應該等同
val = rCLKDIVN; //時鐘分頻器控制寄存器
m = (val>>1)&3; //獲取HDIVN的值,控制HCLK與FCLK的關係(FCLK被分頻多少)
p = val&1; //控制PCLK與HCLK之間的關係
val = rCAMDIVN; //攝像頭時鐘分頻寄存器
s = val>>8; //與HDIVN共同控制HCLK與FCLK的關係
switch (m) {
case 0:
HCLK = FCLK;
break;
case 1:
HCLK = FCLK>>1;
break;
case 2:
if(s&2)
HCLK = FCLK>>3;//右移3位 == 除以8
else
HCLK = FCLK>>2;//右移2位 == 除以4
break;
case 3:
if(s&1)
HCLK = FCLK/6;
else
HCLK = FCLK/3;
break;
}
if(p)
PCLK = HCLK>>1;
else
PCLK = HCLK;
if(s&0x10) //取DIVN_UPLL的值,0:FCLK = MPLL clock 1:FCLK = HCLK
cpu_freq = HCLK;
else
cpu_freq = FCLK;
val = rUPLLCON; //UPLL控制寄存器
m = (val>>12)&0xff; //獲取MDIV
p = (val>>4)&0x3f; //獲取PDIV
s = val&3; //獲取SDIV
UPLL = ((m+8)*FIN)/((p+2)*(1<<s)); //計算出UPLL
UCLK = (rCLKDIVN&8)?(UPLL>>1):UPLL; //控制UCLK與UPLL的關係
}
對這幾個函數使用方式:
//給出了能產生 200M,300M,400M,440M幾種頻率的算法,設定好mpll_val與key
//再通過函數ChangeMPllValue與ChangeClockDivider把他們傳遞進去
//最後再進行cal_cpu_bus_clk,()時鐘的最後確定
i = 2 ; //don't use 100M!
//boot_params.cpu_clk.val = 3;
switch ( i ) {
case 0: //200
key = 12;
mpll_val = (92<<12)|(4<<4)|(1);
break;
case 1: //300
key = 13;
mpll_val = (67<<12)|(1<<4)|(1);
break;
case 2: //400
key = 14;
mpll_val = (92<<12)|(1<<4)|(1);
break;
case 3: //440!!!
key = 14;
mpll_val = (102<<12)|(1<<4)|(1);
break;
default:
key = 14;
mpll_val = (92<<12)|(1<<4)|(1);
break;
}
//init FCLK=400M, so change MPLL first
ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);
ChangeClockDivider(key, 12);
cal_cpu_bus_clk();
對於上述知識自己也瞭解不是很透,作爲筆記內容記錄,在有更深入的瞭解後再改動,也希望高手們指出其中的錯誤。