编写程序
由于我们是在纯裸机上编程,没有uboot之类的程序为我们初始化硬件资源,所以我们要编写一个带有初始化功能的汇编文件。同时为了直观地感受到程序的运行,我们在里面添加一个流水灯的小程序。在工作目录新建一个 statup.s 的文件,编写初始化程序并根据电路板原理图配置LED的GPIO的模式和输出电平。
.global _start
_start:
// 把外设的基地址告诉CPU
ldr r0, =0x70000000 // 对于6410来说内存(0x00000000~0x60000000)
// 外设(0x70000000-0x7fffffff)
orr r0, r0, #0x13 // 外设大小:256M
mcr p15,0,r0,c15,c2,4 // 把r0的值(包括了外设基地址+外设大小)告诉cpu
// 关看门狗
ldr r0, =0x7E004000
mov r1, #0
str r1, [r0]
// 设置GPMCON
ldr r1, =0x7F008820
ldr r0, =0x00001111
str r0, [r1]
mov r2, #0x1000
led_blink:
// 设置GPMDAT,使GPM 1/2/3/4引脚输出低电平,LED亮
ldr r1, =0x7F008824
mov r0, #0x0
str r0, [r1]
// 延时
bl delay
// 设置GPMDAT,使GPM 1/2/3/4引脚输出高电平,LED灭
ldr r1, =0x7F008824
mov r0, #0xF
str r0, [r1]
// 延时
bl delay
sub r2, r2, #1
cmp r2,#0
bne led_blink
halt:
b halt
delay:
mov r0, #0x100000 // 延时时间
delay_loop:
cmp r0, #0
sub r0, r0, #1
bne delay_loop
mov pc, lr
这段程序的意思大家一个一个的查汇编指令和6410的寄存器说明书来理解,这里就不过多解释了。修改里面的寄存器地址来匹配你自己开发板的LED端口,然后我们保存并关闭该文件,开始编写makefile
makefile
我们这里用的makefile是我从stm32的那个标准工程复制修改过来的,删除了一些没用的参数,并修改了一些参数,我们先来看具体内容。
################################################################################
#
# 简介:编译S3C6410裸机程序的makefile
#
# 作者:tuzhi
# 日期:2017.9.1
#
################################################################################
#--------------------------------- 编译参数 ------------------------------------
ifneq ($(V),1)
Q := @
NULL := 2>/dev/null
endif
TARGET := LEDasm
# 设置内核型号
ARCH_FLAGS += -mcpu=arm1176jzf-s
# 搜索目录下asm文件
AS_SRC := $(shell find ./ -name '*.s')
AS_OBJ := $(AS_SRC:%.s=%.o)
# Linker flags
LDFLAGS := --static
LDFLAGS += -Ttext 0xc000000
# OBJ
OBJ = $(AS_OBJ)
#-------------------------------- 编译器调用指令 --------------------------------
PREFIX := arm-none-eabi
LD := $(PREFIX)-ld
AS := $(PREFIX)-as
OBJCOPY := $(PREFIX)-objcopy
OBJDUMP := $(PREFIX)-objdump
GDB := $(PREFIX)-gdb
#----------------------------------- 编译对象 -----------------------------------
.SUFFIXES: .elf .bin .list
.SECONDEXPANSION:
.SECONDARY:
all: elf
elf: $(TARGET).elf
bin: $(TARGET).bin
list: $(TARGET).list
%.bin: %.elf
@printf " OBJCOPY $(*).binn"
$(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin
%.list: %.elf
@printf " OBJDUMP $(*).listn"
$(Q)$(OBJDUMP) -S $(*).elf > $(*).list
%.elf: $(OBJ)
@printf " LD $(TARGET).elfn"
$(Q)$(LD) $(OBJ) $(LDFLAGS) -o $(TARGET).elf
$(AS_OBJ): %.o:%.s
@printf " AS $(*).sn"
$(Q)$(AS) $(ARCH_FLAGS) -o $(*).o -c $(*).s
clean:
@#printf " CLEANn"
$(Q)$(RM) $(shell find -name '*.o' -o -name '*.d' -o -name '*.elf' -o -name '*.bin')
$(Q)$(RM) $(shell find -name '*.hex' -o -name '*.srec' -o -name '*.list' -o -name '*.map')
$(Q)$(RM) $(shell find -name 'generated.*' -o -name '*.srec' -o -name '*.list' -o -name '*.map')
OOCD := openocd
OOCDFLAGS += -f openocd.cfg
debug: $(TARGET).elf
@printf " GDB DEBUG $ -iex 'monitor reset halt' -ex 'load' $(TARGET).elf .PHONY: clean elf bin list debug 先不要看下面debug目标的内容,我们先来看一看编译的参数,与stm32不同的是,由于我们这个工程内没有C语言文件,所以我们首先删除了与C有关的编译参数,然后将.s文件的编译器改回为as,将链接器改回为ld,之前这样设置是为了通用性和能将C和C++代码一起链接,此部分内容在工具链官方说明书中有讲解,而此处是为了不使编译报错(由于缺少C编译参数和main函数的)。 在文件夹下运行make,编译成功,你也可以运行make V=1来查看实际的编译指令 $ make V=1 AS start.s arm-none-eabi-as -mcpu=arm1176jzf-s -o start.o -c start.s LD LEDasm.elf arm-none-eabi-ld ./start.o --static -Ttext 0xc000000 -o LEDasm.elf 注意我们这里最后的链接部分没有使用链接规则文件,而直接使用了 -Ttext 0xc000000的参数表面的程序储存地址,这里0xc000000是6410中的内置ram地址,一共4K大小,原本是用来为bootloader运行启动准备的,系统上电后会自动将nand flash的前4K内容复制到此处运行,由于我们没有在程序中初始化ram的外部芯片,所以这里我们就只能将程序下载到这个地址上运行了。 运行并调试 同stm32一样,在makfile的最后我们使用了一段命令通过管道直接将开启了openOCD连接了目标板,并load了elf文件,不过在执行这个指令之前,我们还需要编写一个openOCD的配置文件,来供软件调用。我们在工程目录下新建一个文件 openocd.cfg source [find interface/jlink.cfg] adapter_khz 500 source [find target/samsung_s3c6410.cfg] 一切准备就绪后,我们运行make debug,启动jlink连接目标板 Reading symbols from LEDasm.elf...(no debugging symbols found)...done. Loading section .text, size 0x7c lma 0xc000000 Start address 0xc000000, load size 124 Error: 16 words out of 31 not transferred Transfer rate: 992 bits in <1 sec, 124 bytes/write. (gdb) 由于gdb不识别汇编文件,使用list是看不到源代码的(我试了几个办法都不行,貌似是因为汇编文件没有 -g 输出调试信息的原因,不知道大家有没有什么方法),我们使用display来显示当前运行的汇编代码。 (gdb) display /i $pc 1: x/i $pc => 0xc000000 <_start>: mov r0, #1879048192 ; 0x70000000 不同于C语言的调试这里我们需要使用 si 的指令来进行step操作,具体的可以大致参考博主Liigo GDB十分钟教程这篇文章来学习调试方式。这里我们直接使用 c 指令运行代码,blinblin~ 板子上的LED开始闪烁,证明我们的程序正确的加载到了内存中并运行了。
上一篇:S3C6410开发(2)-构建开发环境
下一篇:u-boot-2009.08在mini2440上的移植(一)---建立mini2440工程环境(3)
推荐阅读最新更新时间:2024-11-05 15:23
设计资源 培训 开发板 精华推荐
- 使用 Analog Devices 的 LTC3126IFE 的参考设计
- L4941 分布式电源的典型应用电路,带有板载 L4940 和 L4941 低压降稳压器
- TLV431系列限流稳压器的典型应用
- 使用 Omron 的 S8VS-18024A 的参考设计
- SPC584B-DISP:在eTQFP144中具有SPC58 4B线MCU的探索套件
- MCP43XXEV,MCP4251 数字电位器器件评估板
- STM32F103C8T6开发板
- 使用 Analog Devices 的 LTC3119MPFE 的参考设计
- LTC3646EDE-1 5V、1A 同步降压转换器的典型应用电路
- USB_KVM_CH9374B