做过ARM7+ucos的项目,可是都是写一些外围驱动和应用代码,有一些细节还是有些模糊,空闲时间买块ARM板学习,淘宝上44b0x价格便宜,挺有性价比的。
山寨的板子当然就是抄袭“龚俊“的,所以资料什么的,很多学习资料;但用官方的SDK,一是放心,可以自己任意修改;二是练手也有益。
考虑移植u-boot过去,跑个uclinux,但是初级点的还是先跑个ucos,另外跑个lwip,参考主要的代码有:
44b0x的bsp参考sumsung的SDK
ucos+lwip的porting参考README
u-boot直接去soureforge上download一个
有了这些就可以干活了,ucos调试工具:ADS(armgcc)+HJTAG+WIGGLER;当然如果要调试u-boot的话就arm-elf-gcc+arm-elf-gdb+ocdremot;或者直接用wiggler将u-boot烧到flash原始调试方法
1. 44b0x详解
下图是山寨板的内存分布,其中SDRAM为16M:0x0c00 0000~0x0c80 0000,FLASH为2M:0~0x0020 0000
2. LD链接
对以ADS调试来讲,LD直接在ADS中填写相应地址,比如调试
-info totals -ro-base 0xc100000 -rw-base 0xc500000 -first 44binit.o(init)
(
ro-base、rw-base这个设置对代码烧入flash以后的分布没有关系,只是把RAM中的code和data分段了一下.
RAM中一般来说ro段后面紧跟着rw段,rw段后面紧跟着zi段。
)
0x0C10 0000其实是可以比较随意的,0xc00 5000~0xc70 0000都可以
这个时候可以用ADS加载到调试版调试:ADS是加载到0x0C10 0000的
或者U-boot加载运行:
tftp 0xc100000 ucos.bin
go 0xc100000
从0xc10 0000开始跑
反汇编elf文件,得到结果如下
Init
0x0c100000: ea000125 %... B ResetHandler ; 0xc10049c
0x0c100004: ea00005d ]... B HandlerUndef ; 0xc100180
......
** Section #2 'ER_RW' (SHT_PROGBITS) [SHF_ALLOC + SHF_WRITE]
Size : 64 bytes (alignment 4)
Address: 0x0c500000
** Section #3 'ER_ZI' (SHT_NOBITS) [SHF_ALLOC + SHF_WRITE]
Size : 79216 bytes (alignment 4)
Address: 0x0c500040
下面是一个u-boot加载的ucos运行中的内存分布图
|0x0C80 0000
| ucos的代码会把二级中断向量表放这里的
|0xc7f ff00-main在栈底,先进后出
|
| 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
只读的代码段和常量被称作RO段(ReadOnly),可读写的全局变量和静态变量被称作RW段(ReadWrite),RW段中要被初始化为零的变量被称为ZI段(ZeroInit),也叫未初始化段BSS,下面是编译对比图,清楚比较了代码的分布
另外局部变量,临时变量在栈stack中,malloc声明变量在堆heap中
Code RO Data RW Data ZI Data Debug
2900 1491 61 20 Grand Totals
=======================================================
char tmp = 10;或者static char tmp = 10;之后结果是
=======================================================
Code RO Data RW Data ZI Data Debug
2900 1491 62 20 Grand Totals
========================================================
char tmp = 0;或者char tmp;之后结果是
========================================================
Code RO Data RW Data ZI Data Debug
2900 1491 61 21 Grand Totals
========================================================
ADS中的处理ro-base和rw-base是定死的,下面就是汇编中拷贝的代码部分,拷贝RO和RW到RAM中
;********************************************************
;* Copy and paste RW data/zero initialized data *
;********************************************************
LDR r0, =|Image$RO$Limit| ; Get pointer to ROM data
LDR r1, =|Image$RW$Base| ; and RAM copy
LDR r3, =|Image$ZI$Base|
;Zero init base => top of initialised data
CMP r0, r1 ; Check that they are different
BEQ %F1
0
CMP r1, r3 ; Copy init data
LDRCC r2, [r0], #4 ;--> LDRCC r2, [r0] + ADD r0, r0, #4
STRCC r2, [r1], #4 ;--> STRCC r2, [r1] + ADD r1, r1, #4
BCC %B0
1
LDR r1, =|Image$ZI$Limit| ; Top of zero init segment
MOV r2, #0
2
CMP r3, r1 ; Zero init
STRCC r2, [r3], #4
BCC %B2
3. u-boot的差异处理
u-boot相对更智能,它可以自己判断是从SDRAM中跑还是FLASH中跑,在u-boot的lds文件中定义的是从0地址开始的(这个链接起始地址实际上被-Ttest $(TEST_BASE)更新了)
/U-Boot/config.mk:
LDFLAGS += -Bstatic -T $(LDSCRIPT) -Ttext $(TEXT_BASE) $(PLATFORM_LDFLAGS)
反汇编地址是TEST_BASE开始的
可以理解为u-boot也是一个带BSP的应用,只不过它带的BSP比上面那个BSP功能强
adr r0, _start /* r0 <- current position of code */
adr这里的_start是相对的,如果从FLASH运行的话,r0就是0,如果从ram运行的话,r0就是0x0c70 0000,在SDRAM中就不拷贝,在FLASH中就拷贝
/* lds代码 */
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
/* u-boot start.s代码*/
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop