很多产品几乎采用u-boot引导,44B0X板当然也少不了跑个u-boot,网上很多攻略,可以参考,但是不建议直接基于上面修改,自己下载一份完整的源代码,自己完完全全修改对流程更清晰
调试的话,很少有人用到的BDM和TRACE,太奢侈了,山寨板里面已经有了u-boot,配上网络就可以tftp下载调试了;还有一个比较牛B的方法,用arm-elf-gdb+ocdremot,可以gdb单步调试,但是用wiggler,加载代码到SDRAM中的速度太慢了,简直无法忍受;实际应用过程中,肯定刚开始是没有loader的,只能每次烧写到FLASH中看串口信息了呢
1. u-boot解析
搭好编译环境,会发现u-boot.bin和u-boot两个文件,其中u-boot.bin是data的二进制文件,用于下载到启动ROM进行系统引导,u-boot是elf格式的,可加载到SDRAM或SRAM中进行调试,可以objdump这个的,elf比bin要大,因为它填充了很多空白,调试中和RAM中对应的,还有一个u-boot.srec,是Motorola S-Records格式映像,下面是编译窗口
arm-elf-ld -Bstatic -T /home/huangyonggang/u-boot-1.1.1/board/dave/B2/u-boot.lds -Ttext 0x00000000 $UNDEF_SYM cpu/s3c44b0/start.o /
--start-group lib_generic/libgeneric.a board/dave/B2/libB2.a cpu/s3c44b0/libs3c44b0.a lib_arm/libarm.a fs/cramfs/libcramfs.a fs/fat/libfat.a fs/fdos/libfdos.a fs/jffs2/libjffs2.a fs/reiserfs/libreiserfs.a net/libnet.a disk/libdisk.a rtc/librtc.a dtt/libdtt.a drivers/libdrivers.a drivers/sk98lin/libsk98lin.a post/libpost.a post/cpu/libcpu.a common/libcommon.a --no-warn-mismatch -L /usr/local/lib/gcc-lib/arm-elf/2.95.3 -lgcc --end-group /
-Map u-boot.map -o u-boot
arm-elf-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
arm-elf-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
2. 修改u-boot
u-boot实际就是一个小应用了,和修改ucos一样,最基础的就是,IO口初始化,时钟,串口,中断
既然是应用了,SDRAM大小,FLASH大小及驱动,网卡的驱动程序都要跑起来
一般说来,u-boot都提供了类似的芯片的start.s,汇编代码改动很少,s3c44b0x和B2类似,这里选择B2的代码来修改,下面就按照一步步的需要做修改
SDRAM和FLASH的大小,网卡芯片的使能以及网卡CS片选的地址,默认配置参数放在EEPROM中,改为FLASH中,并设置好起址地址,在B2.h中先修改好,顺便把config.mk的TEXT_BASE修改为0x0C700000(SDRAM的最高处)
#define CONFIG_DRIVER_RTL8019
#define RTL8019_BASE 0x06000300 /* base address */
/* 使能8019,按照CS选择起址地址 */
#define PHYS_SDRAM_1 0x0c000000 /* SDRAM Bank #1 */
#define PHYS_SDRAM_1_SIZE 0x00800000 /* 8 MB */
/* 按照硬件SDRAM大小修改 */
#define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */
#define PHYS_FLASH_SIZE 0x00200000 /* 2 MB */
/* 按照硬件FLASH大小修改 */
#define CFG_ENV_IS_IN_FLASH 1 /* use FLASH for environment vars */
#define CFG_ENV_ADDR (PHYS_FLASH_1+0x40000)
#define CFG_ENV_OFFSET 0x40000
/* 在FLASH中储存ENV信息,并规定起址地址 */
//#define CFG_ENV_IS_IN_EEPROM 1 /* use EEPROM for environment vars */
/* 默认是用EEPROM储存ENV信息 */
在B2.c中修改board_init,这个严格按照硬件电路图IO的功能,配合spec设置好,涉及到GPIO啊,串口啊,SDRAM、FLASH并行通信,网口接口以及中端口,我是从ucos中copy过来的
FCLK 串口时钟
FLASH用的芯片同B2一样,不需要修改
8019也是一样的,唯一的修改是16B和8B的区别,8019的寄存器地址会有差别的
3. u-boot中断
下面代码将把ROM中从real_vectors开始的1024字节内容,复制0x0c000008开始的目标区域中去,相当于在RAM中建立一个二级跳转表。
疑惑:为什么从0x0c000008开始?不是和最开始的跳转错开了吗?IRQ的0x0c000018不是跳转到了data_abort了?
/*
now copy to sram the interrupt vector
*/
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
......
/*************************************************/
/* interrupt vectors */
/*************************************************/
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
这是vector的跳转表,比如如果一个IRQ中断来了,直接跳到FLASH的0x18处,代码这里跳转到了0x0c000018,这里应该就是b irq了,跳转到irq:的函数处理,因为u-boot没有中断,这里是直接复位操作的,这里应用程序可以自己接管的
/*
* Jump vector table
*/
.globl _start
_start: b reset
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
/* 其实等价于下面的 */
ldr pc, =0x0c000004
ldr pc, =0x0c000008
ldr pc, =0x0c00000c
ldr pc, =0x0c000010
ldr pc, =0x0c000014
ldr pc, =0x0c000018
ldr pc, =0x0c00001c
如果要用u-boot加载自己编译的ucos调试的话,因为ucos的二级中断向量表在0xc7f ff00,而u-boot的跳转地址是0x0c000008处,所以只需要修改u-boot的汇编成,这样ucos就接管了u-boot的中断了
/*
* Jump vector table
*/
.globl _start
_start: b reset
ldr pc, =0x0c7fff04
ldr pc, =0x0c7fff08
ldr pc, =0x0c7fff0c
ldr pc, =0x0c7fff00
ldr pc, =0x0c7fff04
ldr pc, =0x0c7fff08
ldr pc, =0x0c7fff0c
.balignl 16,0xdeadbeef
4. u-boot FLASH和SDRAM中分布
1,u-boot和应用烧入FLASH后的分布
|0x0020 0000
|
| 应用程序
|
|0x0008 0000
|
|
|
|0x0005 0000
|
| u-boot env
|
|0x0004 0000
|
| u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改
|
|_start = 0x0000 0000
2,运行起来后SDRAM的分布
|0x0C80 0000
| ucos的代码会把二级中断向量表放这里的
|0xc7f ff00
|
| stack栈
|
|0xc7f f000 堆heap end地址,紧跟的是stack栈
|
| 堆heap
|
|
|0x0C70 0000=0x0C80 0000-1MB
|
|
| rw段+bss
|
|0x0C50 0000 :ucos rw段 紧跟的是ZI段(BSS)
|
|
|
| .... 把应用程序ucos加载到这里开始跑
|
|0x0C10 0000:ucos ro段
|
|
|0xc00 0000+1024
|
| u-boot指向的二级中断(可以修改为ucos的二级中断)
|
|0xc00 0000
.
.
.
|0x0020 0000
|
| 应用程序(ro+rw)
|
|0x0008 0000
|
|
|
|0x0005 0000
|
| u-boot env
|
|0x0004 0000
|
| u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改
|
|_start = 0x0000 0000
3,直接网络加载u-boot后SDRAM的分布
|0x0C80 0000
|
|0xc7f ff00
|
|
| 运行中的:从flash拷贝过来的u-boot代码
|
|0x0C70 0000=0x0C80 0000-1MB
|
|0x0C10 0000
|
|0xc00 0000+1024
|
| u-boot指向的二级中断(可以修改为ucos的二级中断)
|
|0xc00 0000
.
.
.
|0x0020 0000
|
|
|
|0x0008 0000
|
|
|
|0x0005 0000
|
| u-boot env
|
|0x0004 0000
|
| u-boot程序,44b0x的中断,指向u-boot的二级中断0x0c000000,可修改
|
|_start = 0x0000 0000
一边对照代码,一边对照串口打印信息,整个u-boot的思路很明确
-->cpu/s3c44b0/start.s(CONFIG_USE_IRQ 没有定义的,flash中时候,经过start,start_code,cpu_init_crit;拷贝code+data;拷贝0xc00 0008;stack_setup)
-->lib_arm/board.c(start_armboot)
-->board/.../flash.c
-->board/.../lowlevel_init.s
-->start_armboot
-->init_fnc_ptr
-->
init_fnc_t *init_sequence[] = {
cpu_init, /* basic cpu dependent setup */
board_init, /* basic board dependent setup */
interrupt_init, /* set up exceptions */
env_init, /* initialize environment */
init_baudrate, /* initialze baudrate settings */
serial_init, /* serial communications setup */
console_init_f, /* stage 1 init of console */
display_banner, /* say that we are here */
dram_init, /* configure available RAM banks */
display_dram_config,
#if defined(CONFIG_VCMA9)
checkboard,
#endif
NULL,
};
-->这是一个函数数组,会逐步调下面函数做初始化
board_init(board/...)
env_init(common/env_eeprom.c)
serial_init(cpu/s3c44b0/serial.c)
console_init_f(common/console.c)
display_banner(lia_arm/board.c)
(到这里就开始打印下面信息了)
U-Boot 1.1.1 (Oct 21 2008 - 04:54:09)
U-Boot code: 0C700000 -> 0C719218 BSS: -> 0C71D9E4
display_dram_config(lia_arm/board.c):
RAM Configuration:
Bank #0: 0c000000 8 MB
display_flash_config(lia_arm/board.c)
(到这里就开始打印下面信息了)
Flash: 2 MB
env_relocate
*** Warning - bad CRC, using default environment
console_init_r(lia_arm/board.c)
(到这里就开始打印下面信息了)
In: serial
Out: serial
Err: serial
main_loop(lia_arm/board.c)
-->abortboot若没有键按下则run_command (s, 0)(s为默认的bootcmd,这个是事先设置好的env bootcmd=run jffsboot) do_bootm do_bootm_linux
(到这里就开始打印下面信息了)
Hit any key to stop autoboot:
5. 小结
先把u-boot代码流程弄清楚,要不然都不知道在哪里改代码,最好是参考类似的板子操作,走了不少弯路,有TRACE这样的牛B工具最好,不过我用gdb+ocdremot单步调试也很爽,那里初始化不对一目了然,就是下载到SDRAM时速度有点慢
MCLK这个我搞糊涂了,MCLK到底是根据外部的晶振来判断的吗???