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

我们正式开始编程~


编写程序

由于我们是在纯裸机上编程,没有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文件,从汇编阶段进入高级语言的时代~~

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值