1. 启动流程
根据"S3C6410 Internal ROM Booting"手册,6410的启动流程如下:
① iROM(BL0)自动进行初始化启动:初始化系统时钟、D-TCM,、设备控制器、启动设备(SD/MMC Card, OneNand, Nand)。
② iROM将启动设备中的bootloader中的4KB代码加载到SRAM中,这8KB boot loader叫做BL1。
③ BL1: 初始化系统时钟、串口、SDRAM,然后将剩余的bootloader(BL2)加载到SDRAM中。
④ 最后,跳转到BL2的起始地址,为用户系统做好环境准备。
2. SD卡启动设备的块分配
博主的启动设备为SDHC卡(8GB), 代码应该拷贝到倒数1042个扇区(sectors)开始的地方。 用fdisk命令查看一下SD卡的扇区:
[root@localhost 22]# fdisk -l
Disk /dev/sda: 21.5 GB, 21474836480 bytes
255 heads, 63 sectors/track, 2610 cylinders, total 41943040 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00053920
Device Boot Start End Blocks Id System
/dev/sda1 * 2048 616447 307200 83 Linux
/dev/sda2 616448 618495 1024 83 Linux
/dev/sda3 618496 37814271 18597888 83 Linux
/dev/sda4 37814272 41943039 2064384 5 Extended
/dev/sda5 37816320 41943039 2063360 82 Linux swap / Solaris
Disk /dev/sdb: 7948 MB, 7948206080 bytes
255 heads, 63 sectors/track, 966 cylinders, total 15523840 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0xe62818a6
Device Boot Start End Blocks Id System
/dev/sdb1 2048 15521791 7759872 c W95 FAT32 (LBA)
2.1 根据扇区计算拷贝位置
计算一下代码应该拷贝的扇区位置为: 15523840 - 1042 = 15522798
使用dd命令将事先准备好的LED闪烁程序下载到SD卡的15522798扇区位置
注意:一定要带“iflag=dsync oflag=dsync”,否则程序不会运行!
[root@localhost 22.sdboot]# dd iflag=dsync oflag=dsync if=led.bin of=/dev/sdb seek=15522798 bs=512
0+1 records in
0+1 records out
162 bytes (162 B) copied, 0.0246958 s, 6.6 kB/s
2.2 根据字节计算拷贝位置
计算一下代码应该拷贝的字节位置:7948206080 - 1042*512 = 7947672576
使用dd命令将事先准备好的LED闪烁程序下载到SD卡的7947672576字节位置:
注意:一定要带“iflag=dsync oflag=dsync”,否则程序不会运行!
[root@localhost 22.sdboot]# dd iflag=dsync oflag=dsync if=led.bin of=/dev/sdb seek=7947672576 bs=1
162+0 records in
162+0 records out
162 bytes (162 B) copied, 0.820881 s, 0.2 kB/s
将SD卡插入开发板,将开关拨到SDBOOT位置,启动电源开关,可以看到4个LED闪烁。
3. 代码
3.1 start.S
/* start.S */
.global _start
_start:
//外设基地址及大小告诉CPU
ldr r0, =0x70000000 //ldr: load
orr r0, r0, #0x13 //0x13=b10011=256M, 参见arm1176jzfs内核参考手册Page3-130
mcr p15,0,r0,c15,c2,4 //把r0的值(包括了外设基地址+外设大小)告诉cpu
//关看门狗
ldr r0, =0x7E004000 //watch dog timer base address
mov r1, #0
str r1, [r0] //disable watch dog. str: Store
//设置GPKCON0
ldr r0, =0x7F008800 //GPKCON0 address
ldr r1, =0x11110000 //GPK_4,5,6,7设置为输出, GPKn设置为0001时,GPKn引脚设置为输出
str r1, [r0]
mov r2, #0x1000 //LED循环计数
led_blink:
ldr r0, =0x7F008808 //GPKDAT address
mov r1, #0xF0 //设置GPK_4,5,6,7为高电平,Led熄灭
str r1, [r0]
bl delay
ldr r0, =0x7F008808
mov r1, #0x00 //设置GPK_4,5,6,7为低电平,Led点亮
str r1, [r0]
bl delay
sub r2, r2, #1 //r2=r2-1
cmp r2, #0
bne led_blink //如果r2!=0,则跳转至led_blink处执行。bne:Branch Not Equal
halt:
b halt //b: Branch
delay:
mov r0, #0x1000000
delay_loop:
sub r0, r0, #1
cmp r0, #0
bne delay_loop
mov pc, lr //从delay子程序返回
3.2 链接脚本
/* led.lds */
SECTIONS
{
. = 0x0C000000; /*BL1 start address*/
.text : {
start.o
* (.text)
}
.data : {
* (.data)
}
.bss_start = .;
.bss : {
* (.bss)
}
.bss_end = .;
}
注意,BL1的起始地址为0x0C000000(见Memory Map)
3.3 Makefile
led.bin: start.o
arm-linux-ld -Tled.lds -o led.elf $^
arm-linux-objcopy -O binary led.elf led.bin
arm-linux-objdump -D led.elf > led_elf.dis
%.o : %.S
arm-linux-gcc -o $@ $< -c
%.o : %.c
arm-linux-gcc -o $@ $< -c
clean:
rm *.o *.elf *.bin *.dis -rf