- 論壇徽章:
- 0
|
get from http://www.laogu.com/wz_1411.htm
下一次,接著就去看看U-BOOT的源程序了。當(dāng)然是基于S3C44B0的BOOTLOADER進(jìn)行的。
上一次說到要學(xué)習(xí)UBOOT的代碼,但在看之前,首先要知道目標(biāo)機(jī)器的編程資源,這里的資源,是指S3C44B0所提供的
運(yùn)行程序的資源,對(duì)任何嵌入式軟件開發(fā),都首先要對(duì)硬件有一個(gè)很好的了解,這跟PC機(jī)的編程是大不一樣的。因?yàn)?br />
PC機(jī)都已經(jīng)發(fā)展了30多年,但整個(gè)編程的體系是沒有很大的變化,就是說現(xiàn)在的PC都是在虛擬機(jī)上編寫了,跟硬件打
交道的機(jī)會(huì)很少,所以不用去了解它。但是在嵌入式的軟件里,每樣硬件都是千差萬別的,所以一定要去看原版的
S3C44B0說明手冊(cè),一定要看英文原版的,不能看那種中文版的,哈哈,為什么要看英文原版的呢?第一,每個(gè)CPU都
有很多特別寄存器,而這些寄存器都是用英文縮寫的,看中文,就不知道它是什么意思了,并且還要死記,沒有英文
整句好記。第二,中文是經(jīng)過翻譯的,并且都不是三星廠家進(jìn)行翻譯,都是一些業(yè)余水平的人來做,很難保證按原文
的意思進(jìn)行。有一次,我看中文的S3C44B0資料找特別寄存器,就找不到,我說為什么沒有呢,原來別人都不翻譯那些
,結(jié)果在英文原版中,一看就找到了。因此,喜歡看英文原版的。并且只要學(xué)習(xí)過幾個(gè)CPU之后,發(fā)現(xiàn)嵌入式軟件就那
幾樣?xùn)|西了。
對(duì)開發(fā)軟件的人來說,最重要的東西是什么呢?哈哈,當(dāng)然是存儲(chǔ)器和寄存器了。每次拿到開發(fā)板之后,一定要去了
解存儲(chǔ)器是怎么樣分配的,是從什么地址開始,存儲(chǔ)器有多大。是什么樣的存儲(chǔ)器,是FLASH的,還是SDRAM的。FLASH
的存儲(chǔ)器映射在S3C44B0的什么地址空間呢?SDRAM又是映射在什么地址空間呢?一定要把這些問題搞清楚,否則就很
難對(duì)它開發(fā)軟件。所以看S3C44B0的手冊(cè)時(shí),就要注意看它的存儲(chǔ)管理。目前,S3C44B0的存儲(chǔ)器管理,分為很多BANK
的。BANK0一般用來映射FLASH存儲(chǔ)器,并且在BANK0后面一段空間里進(jìn)行特別寄存器映射,它的空間是4M大小。并且一
般的開發(fā)板,都是把FLASH存儲(chǔ)器映射在0x0000_0000 到 0x001F_FFFF,這里的地址空間,就是2M大小。把SDRAM映射在
BANK6里面,地址空間就是0x0c00_0000 到 0x0c7f_ffff,這里就是8M的SDRAM了。
特別寄存器的地址空間是從 0x01c0_0000到0x0200_0000的4M空間里,這里的寄存器,大多數(shù)都是跟IO有關(guān)的。比如串
行通訊,DMA,PWM,看門狗,IO口等等。
看懂了存寄器和存儲(chǔ)器,就可以進(jìn)行匯編練習(xí)。當(dāng)然S3C44B0它還有ARM標(biāo)準(zhǔn)的寄存器,共有37個(gè)吧。這些是所有ARM的
CPU都具有的。
把CPU和S3C44B0特別的功能深入了解之后,就可以去看UBOOT代碼。
目前我的引導(dǎo)程序是在UBOOT1.1.2上修改過來的,大家可以下載UBOOT的源程序,也許你們會(huì)問在那里有下呢?這個(gè)問
題不用我回答了,用GOOGLE,直接找u-boot,就可以找到了。
由于這個(gè)引導(dǎo)程序是從u-boot1.1.2修改過來的,所以還是采用uboot的編譯工具,它就是
arm-linux-tools-20031127.tar.gz,這個(gè)可以u(píng)boot的網(wǎng)站下載,然后在linux下安裝好,就可以編譯引導(dǎo)程序。
編譯命令主要:
make clean 是清空所有臨時(shí)文件,一般是用來清空目錄,用來重新編譯程序。
make XXXX_config 是編譯本引導(dǎo)程序,XXXX是自己定義的開發(fā)板,在board目錄下。
make backup 是備份引導(dǎo)程序的源程序。
UBOOT編譯環(huán)境建立起來,就可以去修改和學(xué)習(xí)UBOOT的源程序,就可以開發(fā)自己的boot。源程序已經(jīng)下載,就可以解
開壓縮包,在目錄u-boot-1.1.3,因目前最新的UBOOT是1.1.2,那個(gè)1.1.3是我自己的UBOOT源程序,如果自己想改為
1.1.3名稱,在LINUX下編譯是有點(diǎn)問題的,自己去試試吧。哈哈。。。
接著,我到目錄cpu\s3c44b0,這個(gè)目錄,就是S3C44B0的CPU引導(dǎo)程序,最開始運(yùn)行的代碼就是從這里開始的。那我看
代碼,也要從這里開始。
看一下這個(gè)目錄,包括文件有:
G:\Downloads\lichee\lichee\boot\src\u-boot-1.1.3\cpu\s3c44b0 的目錄
2005-07-18 12:47 .
2005-07-18 12:47 ..
2005-07-16 04:35 4,154 .depend
2004-02-24 08:16 1,066 config.mk
2004-10-18 05:12 9,878 cpu.c
2004-02-24 08:16 4,843 interrupts.c
2004-02-24 08:16 1,303 Makefile
2004-10-18 05:12 4,378 serial.c
2005-07-17 23:48 4,820 start.S
2005-07-17 23:47 4,784 start.S.bak
有好幾個(gè)文件,它們的作用,大家自己先想想,不懂的再問我,目前我要開始看start.S文件,這個(gè)最開始運(yùn)行的文件
。
這個(gè)文件是匯編寫的,但它是經(jīng)過c的預(yù)處理的,所以像在頭文件.h中的宏,也可以使用的,這就是GCC的博大之處。
大家看到我的目錄,也許很奇怪,為什么會(huì)有“l(fā)ichee”這個(gè)名稱?我來告知各位,這個(gè)是我起的名稱,叫做“荔枝
”,我的BOOT代碼和我的uClinux的代號(hào),都叫“荔枝”。吃過“荔枝”的人,都知道外面紅紅的,里面的肉是白的,
清甜可口。我的BOOT和OS都是外面看起來很好看,里面的功能,就是難看了,但要深入去了解,才會(huì)嘗到新鮮的味道
。
好了,下面就要開始品嘗我的“荔枝”了,第一段代碼:
/** S3C44B0 CPU啟動(dòng)代碼。* 蔡軍生 2005/07/17 **/
/** 包含配置文件。*/
#include /*添加版本說明.2005/07/16*/
#include /** 中斷向量表.*/
/* 聲明標(biāo)量是全局函數(shù),CPU加電啟動(dòng)后,就從這里執(zhí)行代碼。 */
.globl _start
_start: b reset /* 跳到復(fù)位中斷開始位置。 */
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
add pc, pc, #0x0c000000
.balignl 16,0xdeadbeef
上面這段代碼,看懂了嗎?如果有什么不懂,就發(fā)問題過來。
這里用到ARM指令,b指令就是無條件地跳到reset的地方運(yùn)行,reset是一個(gè)標(biāo)記,并且它是相對(duì)量。
add pc, pc, #0x0c000000,這句用到了4G空間跳轉(zhuǎn)技術(shù),因?yàn)锳RM的CPU下一次值是根據(jù)PC的值來進(jìn)行的。這里
修改了PC的值,就相當(dāng)跳到對(duì)應(yīng)的地址運(yùn)行了。又由ARM的指令的寬度是4字節(jié)的,所以這里的PC值就是0x0c000004。
如果這里直接用b指令是不行的,因?yàn)樗怀?2M的尋址空間,只有修改PC值才可以達(dá)到目的,因此采用ADD指令來修
改PC值。
.balignl 16,0xdeadbeef
上面這句,就是填充多少字節(jié)在后面。
整段代碼實(shí)現(xiàn)建立中斷向量表,這個(gè)根據(jù)ARM的CPU來編寫的。
第一段代碼看完了,再接著看第二段代碼。
/******************************************************************
* 啟動(dòng)代碼。
** 如果不作內(nèi)存初始化,就只建立堆棧,重新定位代碼到RAM位置。
* 然后就可以跳到第二階段的代碼運(yùn)行了。
**********************************************************************/
/* 保存變量的數(shù)據(jù)區(qū) */
_TEXT_BASE:
.word TEXT_BASE
.globl _armboot_start
_armboot_start:
.word _start
/** These are defined in the board-specific linker script.*/
.globl _bss_start
_bss_start:
.word __bss_start
.globl _bss_end
_bss_end:
.word _end
#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
.word 0x0badc0de
/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
.word 0x0badc0de
#endif
上面這段代碼,主要保存一些全局變量,用于BOOT程序從FLASH拷貝到RAM,或者其它的使用。還有一些變量的長(zhǎng)度是
通過連接腳本里得到,實(shí)際上由編譯器算出來的。
看了數(shù)據(jù)區(qū),這次要看從引導(dǎo)那里跳到這里執(zhí)行時(shí),運(yùn)行什么東西了。
/** 實(shí)際運(yùn)行的復(fù)位代碼。從一開始運(yùn)行的代碼,就跳到這里運(yùn)行。*/
reset:
/* * 設(shè)置cpu運(yùn)行在SVC32模式。*/
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0x13
msr cpsr,r0
具體分析如下:
/** 實(shí)際運(yùn)行的復(fù)位代碼。從一開始運(yùn)行的代碼,就跳到這里運(yùn)行。*/
reset:
/** 設(shè)置cpu運(yùn)行在SVC32模式。S3C44B0共有7種模式。 */
mrs r0,cpsr
取得當(dāng)前程序狀態(tài)寄存器cpsr到r0。
bic r0,r0,#0x1f
這里使用位清除指令,把中斷全部清除,只置位模式控制位。
orr r0,r0,#0x13
計(jì)算為超級(jí)保護(hù)模式。
msr cpsr,r0
設(shè)置cpsr為超級(jí)保護(hù)模式。
通過設(shè)置ARM的CPSR寄存器,讓CPU運(yùn)行在操作系統(tǒng)模式,為后面進(jìn)行其它操作作好準(zhǔn)備了。后面的代碼如下:
/* * 當(dāng)是從FLASH啟動(dòng)時(shí),就要進(jìn)行內(nèi)存測(cè)試,當(dāng)
* 是從RAM啟動(dòng)時(shí),一般就是開發(fā)本源程序時(shí),就
* 可以跳過。
*
*/
#ifdef CONFIG_INIT_CRITICAL
bl cpu_init_crit
/*
* 在重新定位之前,要進(jìn)行RAM訪問時(shí)間測(cè)試,因?yàn)槊總(gè)開發(fā)
* 都是不一樣的。
* 可以在文件memsetup.S里看到它的說明。
*/
bl memsetup
#endif
/* 進(jìn)行重定位 */
relocate: /* 重定位Boot代碼到RAM內(nèi)存,比如從FLASH移到RAM */
adr r0, _start /* 把_start的相對(duì)地址移到r0 */
ldr r1, _TEXT_BASE /* 把_TEXT_BASE地址,就是BOOT在RAM中運(yùn)行地址 */
cmp r0, r1 /* 比較兩個(gè)地址是否相同,如果相同,就已經(jīng)在RAM運(yùn)行,否則就是FLASH中運(yùn)行。*/
beq stack_setup
/* 是在FLASH中運(yùn)行,要把FLASH中的BOOT代碼移到RAM中,然后再運(yùn)行. */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2保存引導(dǎo)代碼大小 */
add r2, r0, r2 /* r2保存引導(dǎo)代碼最后地址 */
copy_loop:
ldmia r0!, {r3-r10} /* 從源地址[r0]讀取8個(gè)字節(jié)到寄存器,每讀一個(gè)就更新一
次r0地址 */
stmia r1!, {r3-r10} /* 拷貝寄存器r3-r10的值保存到 [r1]指明的地址,每寫一
個(gè)字節(jié),就增加1. */
cmp r0, r2 /* 判斷是否拷貝到[r2]地址,就是引導(dǎo)代碼結(jié)束位置。 */
ble copy_loop /* 循環(huán)拷貝 */
/*拷貝中斷向量表,實(shí)際是建立起二級(jí)中斷向量表,當(dāng)CPU中斷時(shí),先運(yùn)行FLASH中斷,接著就轉(zhuǎn)移到實(shí)際中向表執(zhí)行
中斷程序。*/
adr r0, real_vectors
add r2, r0, #1024
ldr r1, =0x0c000000
add r1, r1, #0x08
vector_copy_loop:
ldmia r0!, {r3-r10}
stmia r1!, {r3-r10}
cmp r0, r2
ble vector_copy_loop
/* 建立起堆棧 */
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /* leave 3 words for abort-stack */
ldr pc, _start_armboot /* 已經(jīng)準(zhǔn)備好了堆棧,就可跳到C寫的代碼里,由于我的代碼是ARM,就是
跳到lib_arm\board.c(208):void start_armboot (void)中運(yùn)行。 */
_start_armboot: .word start_armboot
/**************************************************************************
* CPU_init_critical臨界區(qū)寄存器
* 設(shè)置一些重要的寄存器,并進(jìn)行內(nèi)存測(cè)試。
*************************************************************************
*/
#define INTCON (0x01c00000+0x200000) /* 中斷控制器 */
#define INTMSK (0x01c00000+0x20000c) /* 中斷控制屏蔽寄存器 */
#define LOCKTIME (0x01c00000+0x18000c)
#define PLLCON (0x01c00000+0x180000)
#define CLKCON (0x01c00000+0x180004)
#define WTCON (0x01c00000+0x130000)
cpu_init_crit:
/* 關(guān)閉看門狗 */
ldr r0, =WTCON
ldr r1, =0x0
str r1, [r0]
/** 清除所有中斷位,設(shè)置INTMRs實(shí)現(xiàn)。*/
ldr r1,=INTMSK
ldr r0, =0x03fffeff
str r0, [r1]
ldr r1, =INTCON
ldr r0, =0x05
str r0, [r1]
/* 設(shè)置時(shí)鐘控制寄存器 */
ldr r1, =LOCKTIME
ldrb r0, =800
strb r0, [r1]
/* 設(shè)置鎖相環(huán),控制CPU運(yùn)行速度。 */
ldr r1, =PLLCON
#if CONFIG_S3C44B0_CLOCK_SPEED==66
ldr r0, =0x34031 /* 66MHz (Quartz=11MHz) */
#elif CONFIG_S3C44B0_CLOCK_SPEED==75
ldr r0, =0x610c1 /*B2: Xtal=20mhz Fclk=75MHz */
#else
# error CONFIG_S3C44B0_CLOCK_SPEED undefined
#endif
str r0, [r1]
ldr r1,=CLKCON
ldr r0, =0x7ff8
str r0, [r1]
/* 調(diào)用子函數(shù)返回 */
mov pc, lr
/*************************************************/
/* 實(shí)際的中斷向量表 */
/*************************************************/
real_vectors:
b reset
b undefined_instruction
b software_interrupt
b prefetch_abort
b data_abort
b not_used
b irq
b fiq
/*************************************************/
undefined_instruction:
mov r6, #3
b reset
software_interrupt:
mov r6, #4
b reset
prefetch_abort:
mov r6, #5
b reset
data_abort:
mov r6, #6
b reset
not_used:
/* we *should* never reach this */
mov r6, #7
b reset
irq:
mov r6, #8
b reset
fiq:
mov r6, #9
b reset
把引導(dǎo)的匯編看完,已經(jīng)準(zhǔn)備C的運(yùn)行環(huán)境,下面就開始學(xué)習(xí)C的源程序,從start.S文件里到跳文件lib_arm\board.c里運(yùn)
行.
/*引導(dǎo)程序從匯編start.S里跳到這里執(zhí)行。蔡軍生 2005/07/19*/
void start_armboot (void)
{
/* 聲明一個(gè)全局指針,它是指向一個(gè)數(shù)據(jù)結(jié)構(gòu),用于保存參數(shù)。
并且它占用r8寄存器,用它來保存內(nèi)存地址,達(dá)到全局使用目的。
*/
DECLARE_GLOBAL_DATA_PTR;
ulong size;
init_fnc_t **init_fnc_ptr;
char *s;
#if defined(CONFIG_VFD) defined(CONFIG_LCD) unsigned long addr;
#endif
/* gd指針可寫,因?yàn)橐呀?jīng)分配一個(gè)寄存器給它作為變量。
這里就相當(dāng)于把后面算出來的地址保存到r8寄存器.
*/
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* 下面一句是阻止3.4以上版本的GCC進(jìn)行代碼優(yōu)化,把后面的代碼刪除掉。 */
__asm__ __volatile__("": : :"memory");
/* 清空gd指向的結(jié)構(gòu) */
memset ((void*)gd, 0, sizeof (gd_t));
/* */
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
這一段準(zhǔn)備好保存參數(shù)的全局變量區(qū).
后面就是一系列的初始化和獲取正確的參數(shù).
/* 用循環(huán)調(diào)用所有初始化函數(shù) */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr)
{
if ((*init_fnc_ptr)() != 0)
{
/* 當(dāng)每個(gè)函數(shù)初始化失敗時(shí),就會(huì)掛機(jī)在這里。 */
hang();
}
}
上次說到在函數(shù)指針數(shù)組里,不斷地調(diào)用所有初始化函數(shù)進(jìn)行初始化,下面就來仔細(xì)地分析一下,它們到底是做什么
的,做什么樣的初始化,怎么樣為后面做好運(yùn)行的準(zhǔn)備工作?吹降谝粋(gè)初始化函數(shù),就是CPU初始化(cpu_init),
這個(gè)函數(shù)是在cpu\s3c44b0\cpu.c里,它的作用就是進(jìn)行S3C44B0初始化工作?吹竭@個(gè)函數(shù)內(nèi)容如下:
/* CPU初始化。蔡軍生 2005/07/23*/
int cpu_init (void)
{
/* 清空緩沖區(qū) */
icache_enable();
return 0;
}
它在里面調(diào)用了函數(shù)icache_enable(),它就是用來初始化S3C44B0的緩沖區(qū),并且啟用CPU緩沖區(qū)。因?yàn)镃PU在加電之
后,它的初始化值是不啟用內(nèi)部的8K緩沖區(qū)的,必須由程序進(jìn)行設(shè)置。接著看看那個(gè)調(diào)用的函數(shù)又是怎么樣初始化內(nèi)
部緩存區(qū)的呢?
/* CPU內(nèi)存的緩沖初始化。蔡軍生 2005/07/23*/
void icache_enable (void)
{
ulong reg;
/* 清空內(nèi)存的緩沖區(qū). */
s3c44b0_flush_cache();
/* 初始化緩沖區(qū),設(shè)置非緩沖區(qū)的起始地址和結(jié)束地址。第一個(gè)寄存器指明下面的地址不要緩存,低16位是起始地址,高16位是結(jié)束地址。并且空間大小都是以4K為界。0x0000:0000 - 0x0C00:0000*/
NCACHBE0 = 0xC0000000;
NCACHBE1 = 0x00000000;
/* 設(shè)置SYSCFG寄存器啟用8K緩沖區(qū)。 */
reg = SYSCFG;
reg = 0x00000006; /* 8kB */
SYSCFG = reg;
}
在這個(gè)函數(shù)里,第一個(gè)先調(diào)用函數(shù)是進(jìn)行緩沖區(qū)清0的工作,它有一些特別的地方,如下:
/* CPU的內(nèi)部緩沖初始化。蔡軍生 2005/07/23*/
static void s3c44b0_flush_cache(void)
{
volatile int i;
/* 清空緩沖區(qū),每次要按4個(gè)32位來讀寫,所以要加16. */
for( i = 0x10002000; i
它用一個(gè)for循環(huán)進(jìn)行內(nèi)部的緩沖區(qū)初始化,由于S3C44B0決定每次讀寫都是按16字節(jié)進(jìn)行的。因此,這里的i就是不斷
地加16個(gè)字節(jié)。不過,這里為什么不清除0x10000000到0x10001fff區(qū)域呢?這個(gè)我也沒有搞清楚,等我有空試試清除
有沒有問題!
到現(xiàn)在為止,緩沖區(qū)已經(jīng)清空,就要設(shè)置那些內(nèi)存區(qū)域是不要進(jìn)行緩存的。因?yàn)椴皇撬袃?nèi)存都需要進(jìn)行緩沖的,比
如讀取外面的IO,就不需要進(jìn)行緩沖;讀取FLASH也不需要。因此,設(shè)置第一個(gè)非緩沖區(qū)的起始地址為NCACHBE0 =
0xC0000000,這個(gè)值里的低16位是起始地址0x0000,它的32位地址就是從0x00000000開始。它的高16位是結(jié)束地址
0Xc000,它的32位地址就是從0Xc0000000結(jié)束。最后就是通過設(shè)置SYSCFG寄存器的[2:1]位的值為11,就啟用了8K內(nèi)存
數(shù)據(jù)和指令緩沖區(qū)。到這里為止,就已經(jīng)設(shè)置好CPU的緩沖區(qū)初始化和啟用。
由于前幾次,把編譯好的UBOOT寫到FLASH老是運(yùn)行不了。那么怎么辦呢?思考了很久,也查看了源程序,還是沒有發(fā)
現(xiàn)問題。也許那個(gè)UBOOT的源程序太大,有很多的編譯開關(guān),還有很多驅(qū)動(dòng)程序選擇,所以一頭霧水,不知怎么辦好。
到了這個(gè)時(shí)候,只有從頭開始跟蹤了。就是盡可能地跟蹤程序運(yùn)行到那里。因而依次地進(jìn)行下面的檢查:
1. 檢查設(shè)置的倍頻是否對(duì)。
2. 檢查程序?qū)懙紽LASH的數(shù)據(jù)是否對(duì)。
3. 檢查設(shè)置RAM是否對(duì)。
4. 檢查設(shè)置串口的波特率是否對(duì)。
一般進(jìn)行四部份檢查就找出大體的問題。我首先查了一下,我的開發(fā)板上的晶振是10MHz輸入,那么我要倍頻到60MHz
,所以就要計(jì)算它的倍頻系數(shù)。當(dāng)然最快的辦法,就是用三星提供的PLLSET.EXE工具,五秒鐘就搞定了。經(jīng)過檢查,
發(fā)現(xiàn)我的倍頻系數(shù)不對(duì),所以重新設(shè)置倍頻系數(shù)。一般設(shè)置過倍頻系后,都要調(diào)整串口波特率、SDRAM的刷新頻率。設(shè)
置好倍頻系數(shù)后,接著,就要計(jì)算串口的波特率,這個(gè)三星的S3C44B0的手冊(cè)有計(jì)算公式。比如9600,就是拿60MHz進(jìn)
行分頻得到的。
這次設(shè)置好后這些東西之后,就把UBOOT編譯后,再寫到FLASH運(yùn)行,還是不行。偶都在痛苦中,為什么還不行呢。后
來我想想,把UBOOT的編譯地址改到0x00000000運(yùn)行,就是在FLASH運(yùn)行,不拷貝到SDRAM中運(yùn)行。結(jié)果是可以運(yùn)行一段
,串口有東西輸出來,我的設(shè)置的LED也可以顯示。蜂鳴器也不響。說明這個(gè)串口的設(shè)置已經(jīng)對(duì),那么系統(tǒng)的倍頻也對(duì)
了。但UBOOT的堆棧我沒有改,所以只能跑到?jīng)]有使用到堆棧的代碼。接著,我還需要改回到0x0C100000的基地址運(yùn)行
。經(jīng)過用ADS中的AXD調(diào)試,單步跟蹤。又是一件痛苦的事情,發(fā)現(xiàn)AXD只能單步跟蹤,設(shè)置斷點(diǎn),或者其它調(diào)試都不行
,如果在后面設(shè)置了斷點(diǎn),選擇運(yùn)行,發(fā)現(xiàn)到斷點(diǎn),還停不下來的。
呵呵。。。。。。。調(diào)試就是這樣的,不是樣樣都順手。既然只能單步運(yùn)行,就老老實(shí)實(shí)地單步調(diào)試了,經(jīng)過30多分
鐘的單步運(yùn)行,F8都已經(jīng)按得手軟。最后才跟蹤到出錯(cuò)的地址,發(fā)現(xiàn)內(nèi)存設(shè)置不對(duì)。主要是SDRAM的設(shè)置不對(duì),查看了
加載地址的出錯(cuò)了。發(fā)現(xiàn)了這個(gè)加載地址出錯(cuò),偶也沒有更好的辦法解決之前,就只好把算好的值,依次地用ldr加載
到r1-r13,共13個(gè)寄存器里。接著讓AXD全速運(yùn)行,程序就可運(yùn)行了。原來出錯(cuò)就是沒有把SDRAM的參數(shù)加載正確,讓
我調(diào)試了三天。
通過一個(gè)多小時(shí)的調(diào)試,串口可以顯示了,UBOOT的很多命令也可運(yùn)行了。但還沒有調(diào)通USB口,也沒有網(wǎng)絡(luò)接口。后
面的工作,就是先調(diào)通網(wǎng)絡(luò)接口。我的開發(fā)板用的網(wǎng)絡(luò)芯片是RTL8019AS,這個(gè)我也沒有怎么看過,得好好找點(diǎn)資料,
了解了解這個(gè)IC,然后找一份LINUX的RTL8019的驅(qū)動(dòng)程序出來看看,再?zèng)Q定怎么樣調(diào)通RTL8019,由于RTL8019要用到
中斷,就要先檢查S3C44B0設(shè)置,否則到最后都沒有辦法調(diào)試。
通過開發(fā)板的調(diào)試,與SKYEYE相比,主要的區(qū)別是在SDRAM的頻率,串口的頻率,還有中斷的功能,都有很大的不同。
因此,在SKYEYE上能運(yùn)行的,在開發(fā)板,就不一定可以運(yùn)行,就是這個(gè)原因
below get from http://www.linuxfans.org/nuke//modules.php?name=News&file=article&sid=2765
基于Atmel at91rm9200的armlinux的bootloader啟動(dòng)代碼分析
1.4 u-boot源代碼目錄結(jié)構(gòu)
board:開發(fā)板相關(guān)的源碼,不同的板子對(duì)應(yīng)一個(gè)子目錄,內(nèi)部放著主板相關(guān)代碼。
at91rm9200dk/at91rm9200.c, config.mk, Makefile, flash.c ,u-boot.lds等都和具體開發(fā)板的硬件和地址分配有關(guān)。
common:與體系結(jié)構(gòu)無關(guān)的代碼文件,實(shí)現(xiàn)了u-boot所有命令,
其中內(nèi)置了一個(gè)shell腳本解釋器(hush.c, a prototype Bourne shell grammar parser), busybox中也使用了它.
cpu:與cpu相關(guān)代碼文件,其中的所有子目錄都是以u(píng)-boot所支持的cpu命名.
at91rm9200/at45.c, at91rm9200_ether.c, cpu.c, interrupts.c serial.c, start.S, config.mk, Makefile等.
其中cpu.c負(fù)責(zé)初始化CPU、設(shè)置指令Cache和數(shù)據(jù)Cache等;
interrupt.c負(fù)責(zé)設(shè)置系統(tǒng)的各種中斷和異常,比如快速中斷、開關(guān)中斷、時(shí)鐘中斷、軟件中斷、
預(yù)取中止和未定義指令等;
start.S負(fù)責(zé)u-boot啟動(dòng)時(shí)執(zhí)行的第一個(gè)文件,它主要是設(shè)置系統(tǒng)堆棧和工作方式,為跳轉(zhuǎn)到C程序入口點(diǎn).
disk:設(shè)備分區(qū)處理代碼。
doc:u-boot相關(guān)文檔。
drivers:u-boot所支持的設(shè)備驅(qū)動(dòng)代碼, 網(wǎng)卡、支持CFI的Flash、串口和USB總線等。
fs: u-boot所支持支持文件系統(tǒng)訪問存取代碼, 如jffs2.
include:u-boot head文件,主要是與各種硬件平臺(tái)相關(guān)的頭文件,
如include/asm-arm/arch-at91rm9200/, include/asm-arm/proc-armv
net:與網(wǎng)絡(luò)有關(guān)的代碼,BOOTP協(xié)議、TFTP協(xié)議、RARP協(xié)議代碼實(shí)現(xiàn).
lib_arm:與arm體系相關(guān)的代碼。(這里我們主要面向的是ARM體系,所以該目錄是我們主要研究對(duì)象)
tools:編譯后會(huì)生成mkimage工具,用來對(duì)生成的raw bin文件加入u-boot特定的image_header.
1.5 u-boot的功能介紹
u-boot支持SCC/FEC以太網(wǎng)、OOTP/TFTP引導(dǎo)、IP和MAC的功能.
讀寫Flash、DOC、IDE、IIC、EEROM、RTC
支持串行口kermit和S-record下載代碼, 并直接從串口下載并執(zhí)行。
在我們生成的內(nèi)核鏡像時(shí),要做如下處理.
1. arm-linux-objcopy -O binary -R.note -R.comment -S vmlinux linux.bin
2. gzip -9 linux.bin
3. mkimage -A arm -O linux -T kernel -C gzip -a 0xc0008000 -e 0xc0008000 -n
"Linux-2.4.19-rmk7” -d linux.bin.gz uImage
即在Linux內(nèi)核鏡像vmLinux前添加了一個(gè)特殊的頭,這個(gè)頭在include/image.h中定義,
typedef struct image_header
{
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
當(dāng)u-boot引導(dǎo)時(shí)會(huì)對(duì)這個(gè)文件頭進(jìn)行CRC校驗(yàn),如果正確,才會(huì)跳到內(nèi)核執(zhí)行.
如果u-boot啟動(dòng)以后會(huì)出現(xiàn)
u-boot>
敲入help, 會(huì)出現(xiàn)大量的命令提示,Monitor command
go - start application at address 'addr'
run - run commands in an environment variable
bootm - boot application image from memory
bootp - boot image via network using BootP/TFTP protocol
tftpboot- boot image via network using TFTP protocol
and env variables "ipaddr" and "serverip"
(and eventually "gatewayip")
rarpboot- boot image via network using RARP/TFTP protocol
diskboot- boot from IDE devicebootd - boot default, i.e., run 'bootcmd'
loads - load S-Record file over serial line
loadb - load binary file over serial line (kermit mode)
md - memory display
mm - memory modify (auto-incrementing)
nm - memory modify (constant address)
mw - memory write (fill)
cp - memory copy
cmp - memory compare
crc32 - checksum calculation
imd - i2c memory display
imm - i2c memory modify (auto-incrementing)
inm - i2c memory modify (constant address)
imw - i2c memory write (fill)
icrc32 - i2c checksum calculation
iprobe - probe to discover valid I2C chip addresses
iloop - infinite loop on address range
isdram - print SDRAM configuration information
sspi - SPI utility commands
base - print or set address offset
printenv- print environment variables
setenv - set environment variables
saveenv - save environment variables to persistent storage
protect - enable or disable FLASH write protection
erase - erase FLASH memory
flinfo - print FLASH memory information
bdinfo - print Board Info structure
iminfo - print header information for application image
coninfo - print console devices and informations
ide - IDE sub-system
loop - infinite loop on address range
mtest - simple RAM test
icache - enable or disable instruction cache
dcache - enable or disable data cache
reset - Perform RESET of the CPU
echo - echo args to console
version - print monitor version
help - print online help
? - alias for 'help'
u-boot支持大量的命令可用, 這里就不作介紹,大家有興趣可以看看u-boot 的README文檔
3.3 對(duì)u-boot-1.0.0的修改和移植
1.6 關(guān)于u-boot的移植如下,由于u-boot的軟件設(shè)計(jì)體系非常清晰,它的移植工作并不復(fù)雜,
相信各位的代碼閱讀功力不錯(cuò)的話,參照如下就可以完成。
If the system board that you have is not listed, then you will need
to port U-Boot to your hardware platform. To do this, follow these
steps:
1. Add a new configuration option for your board to the toplevel
"Makefile" and to the "MAKEALL" script, using the existing
entries as examples. Note that here and at many other places
boards and other names are listed in alphabetical sort order. Please
keep this order.
2. Create a new directory to hold your board specific code. Add any
files you need. In your board directory, you will need at least
the "Makefile", a ".c", "flash.c" and "u-boot.lds".
3. Create a new configuration file "include/configs/.h" for
your board
4. If you're porting U-Boot to a new CPU, then also create a new
directory to hold your CPU specific code. Add any files you need.
5. Run "make _config" with your new name.
6. Type "make", and you should get a working "u-boot.srec" file
7. Debug and solve any problems that might arise.
[Of course, this last step is much harder than it sounds.]
為了使u-boot-1.0.0支持新的開發(fā)板,一種簡(jiǎn)便的做法是在u-boot已經(jīng)支持的開發(fā)板中參考選擇一種較接近板的進(jìn)行修改,
幸運(yùn)的是在u-boot-1.0.0中已經(jīng)有了at91rm9200的支持。
1.7 與at91rm9200相關(guān)的u-boot代碼
在include/configs/at91rm9200dk.h 它包括開發(fā)板的CPU、系統(tǒng)時(shí)鐘、RAM、Flash系統(tǒng)及其它相關(guān)的配置信息。
在include/asm-arm/AT91RM9200.h, 該文件描述了H9200寄存器的結(jié)構(gòu)及若干宏定義。
具體內(nèi)容要參考相關(guān)處理器手冊(cè)。
在cpu/at91rm9200/目錄下別為cpu.c、interrupts.c和serial.c等文件.
在board/at91rm9200dk/目錄下分別為flash.c、at91rm9200dk.c, config.mk, Makefile,u-boot.lds
flash.c : u-boot讀、寫和刪除Flash設(shè)備的源代碼文件。由于不同開發(fā)板中Flash存儲(chǔ)器的種類各不相同,
所以,修改flash.c時(shí)需參考相應(yīng)的Flash芯片手冊(cè)。它包括如下幾個(gè)函數(shù):
unsigned long flash_init (void ),F(xiàn)lash初始化;
void flash_print_info (flash_info_t *info),打印Flash信息;
int flash_erase (flash_info_t *info, int s_first, int s_last),F(xiàn)lash擦除;
volatile static int write_dword (flash_info_t *info, ulong dest, ulong data),F(xiàn)lash寫入;
int write_buff (flash_info_t *info, uchar *src, ulong addr, ulong cnt),從內(nèi)存復(fù)制數(shù)據(jù)。
u-boot.lds :linker scripte, 設(shè)置u-boot中各個(gè)目標(biāo)文件的連接地址.
網(wǎng)口設(shè)備控制程序
在drivers/目錄中網(wǎng)口設(shè)備控制程序cs8900, bcm570x等, 還可以添加其他網(wǎng)卡驅(qū)動(dòng)
int eth_init (bd_t *bd) : 初始化網(wǎng)絡(luò)設(shè)備;
void eth_halt (void) : 關(guān)閉網(wǎng)絡(luò)設(shè)備;
int eth_send (volatile void *packet,int len) : 發(fā)送數(shù)據(jù)包;
int eth_rx (void) : 接收數(shù)據(jù)包。
Makefile
在u-boot-1.0.0/Makefile中
at91rm9200dk_config : unconfig
./mkconfig $(@:_config=) arm at91rm9200 at91rm9200dk
1.8 編譯u-boot
make at91rm9200_config
Configuring for at91rm9200 board...
make all
生成三個(gè)文件:u-boot.bin, u-boot, u-boot.srec
u-boot.bin is a raw binary image
u-boot is an image in ELF binary format
u-boot.srec is in Motorola S-Record format (objcopy -O srec -R.note -R.comment -S [inputfile] [outfile]
以上工作完成我們可以通過串口將u-boot.bin下載到主板的SDRAM中,它會(huì)自動(dòng)執(zhí)行, 并出現(xiàn)uboot>
這里我們可以通過串口把boot.bin, u-boot.bin.gz下載到主板,再用u-boot的提供的寫flash功能分別
把boot.bin, u-boot.bin.gz寫入到flash中,完成以上工作后,對(duì)主板跳線選擇片外啟動(dòng),
板子復(fù)位后會(huì)自動(dòng)啟動(dòng)u-boot.
本文來自ChinaUnix博客,如果查看原文請(qǐng)點(diǎn):http://blog.chinaunix.net/u1/45211/showart_404116.html |
|