S3C6410开发(3)-编译运行第一个流水灯程序

xiaoxiao2021-02-28  87

我们正式开始编程~


编写程序

由于我们是在纯裸机上编程,没有uboot之类的程序为我们初始化硬件资源,所以我们要编写一个带有初始化功能的汇编文件。同时为了直观地感受到程序的运行,我们在里面添加一个流水灯的小程序。在工作目录新建一个 statup.s 的文件,编写初始化程序并根据电路板原理图配置LED的GPIO的模式和输出电平。

.global _start _start: // 把外设的基地址告诉CPU ldr r0, =0x70000000 // 对于6410来说内存(0x000000000x60000000) // 外设(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 $(*).bin\n" $(Q)$(OBJCOPY) -Obinary $(*).elf $(*).bin %.list: %.elf @printf " OBJDUMP $(*).list\n" $(Q)$(OBJDUMP) -S $(*).elf > $(*).list %.elf: $(OBJ) @printf " LD $(TARGET).elf\n" $(Q)$(LD) $(OBJ) $(LDFLAGS) -o $(TARGET).elf $(AS_OBJ): %.o:%.s @printf " AS $(*).s\n" $(Q)$(AS) $(ARCH_FLAGS) -o $(*).o -c $(*).s clean: @#printf " CLEAN\n" $(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 $<\n" $(Q)$(GDB) -iex 'target extended | $(OOCD) $(OOCDFLAGS) -c "gdb_port pipe"' \ -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开始闪烁,证明我们的程序正确的加载到了内存中并运行了。


目前这就是我今天所测试完成的全部内容,包含了完整的从裸机到编写程序并加载运行的过程,可以算是起步了吧,在下一篇中,我将开始加入C文件,从汇编阶段进入高级语言的时代~~

转载请注明原文地址: https://www.6miu.com/read-85654.html

最新回复(0)