通过查阅s3c6410英文手册,有以下一段话:
Address range of internal ROM is from 0x0800_0000 to 0x0BFF_FFFF, but real storage is only 32KB. This region is read-only, and can be mapped to boot image area when internal ROM booting is selected. Address range of internal SRAM is from 0x0C00_0000 to 0x0FFF_FFFF, but real storage is only 4KB.
大概意思是:IROM的地址范围是0x0800_0000至0x0BFF_FFFF,但实际的空间大小只有32KB。并且这个区域是只读的;当选择从IROM启动设备时,这个区域会映射到启动映射区(即0地址处)。内部SRAM(即stepping stone)地址范围从0x0c00_0000到0x0fff_ffff,但实际只有4KB的存储空间。
使用C语言的重点就是设置栈区域!!
从IROM中启动设备,再从SDHC卡中加载LED程序。这段LED程序使用汇编和C语言混合编写的。从《OK6410---点亮led灯》博文中的介绍可知,IROM中的程序会执行如下的操作:
我们在使用C语言写LED程序时,可以暂时使用IROM中初始化好的栈区域,所以就有下面的代码:
start.S
.text
.global _start
_start:
/*异常向量表*/
b reset /*复位异常,地址0x0000_0000*/
ldr pc, _undefined_instruction /*未定义指令异常,地址0x0000_0004*/
ldr pc, _software_interrupt /*软中断异常,地址0x0000_0008*/
ldr pc, _prefetch_abort /*预取指令异常,地址0x0000_000c*/
ldr pc, _data_abort /*数据访问异常,地址0x0000_0010*/
ldr pc, _not_use /*没用到的向量地址,地址0x0000_0014*/
ldr pc, _irq /*外部中断异常,地址0x0000_0018*/
ldr pc, _fiq /*快速中断异常,地址0x0000_001c*/
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_use:
.word not_use
_irq:
.word irq
_fiq:
.word fiq
/*复位处理程序*/
reset:
bl main /*跳转到C语言编写的程序*/
/*死循环程序,防止程序跑丢了*/
stop_here:
b stop_here
undefined_instruction:
/*未定义指令异常处理函数*/
b undefined_instruction
software_interrupt:
/*软中断异常处理函数*/
b software_interrupt
prefetch_abort:
/*预取指令异常处理函数*/
b prefetch_abort
data_abort:
/*数据访问异常处理函数*/
b data_abort
not_use:
/*未使用的向量地址处理函数*/
b not_use
irq:
/*中断处理函数*/
b irq
fiq:
/*快速中断处理函数*/
b fiq
.end /*标识文件结尾,之后的内容无效*/
led.c
void delay(void)
{
volatile int i = 0x100000;
while (i--);
}
int main(void){
int i = 0;
volatile unsigned long *gpmcon = (volatile unsigned long *)0x7F008820;
volatile unsigned long *gpmdat = (volatile unsigned long *)0x7F008824;
/* gpm0,1,2,3设为输出引脚 */
*gpmcon = 0x1111;
while(1)
{
*gpmdat = i;
i++;
if (i == 16)
i = 0;
delay();
}
return 0;
}
当然,由于IROM初始化的栈区域,在一些文档中说明得不是很清晰,所以我们也可以定义自己的栈区域。但是这里需要注意,栈区域只能定义在stepping stone中(即0x0c000000+4*1024)。因为DRAM还没有初始化,不能直接使用,只有stepping stone是不用初始化就可以直接使用的。以后还要注意程序的大小和栈区域增长的大小,两者不要重叠了,以免导致程序运行出错。只需要修改一下start.S文件就好。
.text
.global _start
_start:
/*异常向量表*/
b reset /*复位异常,地址0x0000_0000*/
ldr pc, _undefined_instruction /*未定义指令异常,地址0x0000_0004*/
ldr pc, _software_interrupt /*软中断异常,地址0x0000_0008*/
ldr pc, _prefetch_abort /*预取指令异常,地址0x0000_000c*/
ldr pc, _data_abort /*数据访问异常,地址0x0000_0010*/
ldr pc, _not_use /*没用到的向量地址,地址0x0000_0014*/
ldr pc, _irq /*外部中断异常,地址0x0000_0018*/
ldr pc, _fiq /*快速中断异常,地址0x0000_001c*/
_undefined_instruction:
.word undefined_instruction
_software_interrupt:
.word software_interrupt
_prefetch_abort:
.word prefetch_abort
_data_abort:
.word data_abort
_not_use:
.word not_use
_irq:
.word irq
_fiq:
.word fiq
/*复位处理程序*/
reset:
ldr sp, =(0x0c000000+4*1024) /*增加了这一句,自定义栈区域*/
bl main
/*死循环程序,防止程序跑丢了*/
stop_here:
b stop_here
undefined_instruction:
/*未定义指令异常处理函数*/
b undefined_instruction
software_interrupt:
/*软中断异常处理函数*/
b software_interrupt
prefetch_abort:
/*预取指令异常处理函数*/
b prefetch_abort
data_abort:
/*数据访问异常处理函数*/
b data_abort
not_use:
/*未使用的向量地址处理函数*/
b not_use
irq:
/*中断处理函数*/
b irq
fiq:
/*快速中断处理函数*/
b fiq
.end /*标识文件结尾,之后的内容无效*/
链接脚本文件:
/*链接脚本*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS{
. = 0x0c000000; /*注意位置计数器的设置,也可以设置为0x00000000*/
. = ALIGN(4); /*4字节对齐*/
.text : {
start.o(.text) /*首先链接start.o文件*/
*(.text)
}
. = ALIGN(4);
.rodata : { /*只读数据段*/
*(.rodata)
}
. = ALIGN(4);
.data : { /*已初始化全局数据段*/
*(.data)
}
. = ALIGN(4);
bss_start = .; /*bss段的开始地址*/
.bss : { /*未初始化全局数据段*/
*(.bss)
}
bss_end = .; /*bss段的结束地址*/
}
最后是Makefile文件:
#使用的工具链
CROSS_COMPILE = arm-none-eabi-
#编译工具
AS = $(CROSS_COMPILE)as
LD = $(CROSS_COMPILE)ld
CC = $(CROSS_COMPILE)gcc
OBJCOPY = $(CROSS_COMPILE)objcopy
OBJDUMP = $(CROSS_COMPILE)objdump
#编译选项
#ASFLAGS = -gstabs -mcpu=arm1176jzf-s -march=armv6 -mfpu=vfpv2 -o
LDFLAGS = -T linkscript.lds -o
#最终目标为led.bin
ALL:led.bin
$(OBJDUMP) -S -D led.elf > led.dump
led.bin:led.elf
$(OBJCOPY) -O binary $^ $@
led.elf:start.o led.o
$(LD) $(LDFLAGS) $@ $^
%.o:%.S
$(CC) -g -c -o $@ $^
%.o:%.c
$(CC) -g -c -o $@ $^
.PHONY:clean
clean:
del *.bin *.o *.elf *.dump
以上的代码都是位置无关的代码,讨论一下下面的问题。
将语句bl main改成语句ldr pc,=main会有什么结果?相应的其他文件怎么改才能让LED点亮?