OK6410---点亮led灯

有关Makefile的博客在这里!

有关链接脚本的博客在这里!

1 准备

  1. 开发板OK6410
  2. SDHC卡,因为写好的程序会拷贝到SDHC中
  3. 安装交叉编译工具链arm-none-eabi-
  4. J-Link仿真器及相关软件

2 分析

2.1 IROM启动过程

S3C6410处理器支持NAND FLASH、SROM和 IROM等多种启动方式,通过系统上电时配置引脚的不同状态来确定相应的启动方式。OK6410开发板通过配置拨码开关SW2选择启动方式,如下图所示:

开发板启动模式的原理图如下:

  •  OM[0]:OM0下拉接地,即OM[0] = 0;
  • 其他引脚解析如下文。

通过s3c6410手册可以找到下图表格,XSELNAND、OM[4:0]、GPN[15:13]三类引脚决定芯片的启动模式。

  •  XSELNAND:(即上面原理图中的SELNAND引脚)为1时,从NAND Flash启动;为0时,从OneNAND Flash启动;当不使用NAND Flash和OneNAND Flash作为启动设备时(如从SDHC卡中启动),可以为1或0。我选择从SDHC卡中启动,所以XSELNAND引脚的配置忽略。
  • OM[0]:(即上面原理图中的OM0引脚)为1时,选择的时钟源为EXTCLK(外部时钟);为0时,选择的时钟源为XTlpll(外部晶振)。OK6410开发板的OM[0] = 0,即选择XTlpll为时钟源。
  • OM[4:1]:决定开发板以哪个设备作为启动设备,OK6410支持从NAND Flash(OM[4:1] = 0011)和IROM(OM[4:1] = 1111)中启动。我选择从SDHC卡中启动,所以OM[4:1] = 1111。
  • GPN[15:13]:当从IROM(厂商在其中固化了启动程序)中启动时,GPN[15:13]用于选择启动设备,如SD卡、NAND Flash、OneNAND等,具体引脚配置如上图。我选择从SDHC卡中启动,所以GPN[15:13] = 000(CH0)。

下图就是具体的IROM启动过程:

 1.IROM中储存的是厂商固化的启动程序,一般称为BL0,它会做以下操作:

  • 禁止看门狗
  • 初始化TCM
  • 初始化块设备复制功能
  • 初始化栈区
  • 初始化PLL
  • 初始化指令缓存
  • 初始化堆区
  • 复制BL1到Stepping Stone
  • 校验BL1的完整性
  • 跳到Stepping Stone

 2.当我们将GPN[15:13]引脚配置为000时,表示BL1这段程序储存在SDHC卡中,BL0就会复制SDHC卡中4KB大小的BL1到Stepping Stone。

3.BL1就是我们将来要自己编写的引导加载程序中的8KB大小的代码段,用于初始化系统时钟、串口等设备,并将引导加载程序剩余的部分(称为BL2)以及Kernel、文件系统等程序复制到SDRAM中。各个程序在SDHC中的规划如下图:

4.跳到SDRAM中执行BL2(为使用系统创造良好的环境),并启动操作系统。

2.2 简单理解异常向量表

通过内部或外部源产生的异常信号,会使处理器去处理一个事件,例如产生一个外部中断或尝试执行一个未定义指令。通常会保留处理异常之前的处理器状态,以便在异常例程完成时可以恢复原始程序。同一时间可能出现多个异常。

ARM体系结构支持七种类型的异常。表A2-4列出了异常类型和用于处理每种类型的处理器模式。发生异常时,强制从与异常类型对应的固定内存地址执行。这些固定地址称为异常向量。注意:地址0x00000014处的向量和地址0xFFFF0014处的向量
保留用于将来扩展。

2.3 上电复位

当打开开发板的电源,芯片s3c6410的复位输入有效后,ARM处理器会以Supervisor模式从0x00000000地址处(默认的情况)执行指令。要注意的是,这个地址只可以放一条32位的指令,实际就是一条跳转指令,跳转到真正的reset处理程序。

2.4 点亮LED灯的原理

从以上小节分析可以知道,要点亮LED灯就是把点亮LED灯的程序写入到SDHC卡中BL1的位置。当我们选择IROM启动,从SDHC中加载BL1到Stepping Stone中运行时,就会执行点亮LED灯的程序。

下面看看LED灯的原理图:

从上图可以知道,GPIO端口输出低电平时,就可以点亮LED灯了。 

 从上图可以知道,4盏LED灯分别接在GPM[0:3]引脚上,所以编写程序,配置好GPM[0:3]引脚就可以控制LED的亮和灭的操作了。

3 实践

要编写点亮LED的程序,需要编写三个文件用于产生最终的二进制文件。他们分别是用gnu语法编写的arm汇编语言文件、用于构建工程项目的gnu make的Makefile文件、用于链接目标文件(即.o文件)的链接脚本.lds文件。有了这三个文件(在同一目录下),在命令行中直接输入make命令就可自动生成我们想要的二进制文件led.bin。具体实现见下面的小节。

3.1 start.S

.equ GPMCON,0x7F008820           /*作用类似于C语言的#define*/
.equ GPMDAT,0x7F008824           /*这句相当于#define GPMDAT 0x7F008824*/ 
.equ GPMPUD,0x7F008828

.text                            /*表示代码段*/
.global _start                   /*全局标识符,外部文件可见*/
_start:
	/*异常向量表*/
	b reset                      /*复位异常,地址0x0000_0000*/
	b _undefined_instruction 	 /*未定义指令异常,地址0x0000_0004*/
	b _software_interrupt    	 /*软中断异常,地址0x0000_0008*/
	b _prefetch_abort        	 /*预取指令异常,地址0x0000_000c*/
	b _data_abort            	 /*数据访问异常,地址0x0000_0010*/
	b _not_use               	 /*没用到的向量地址,地址0x0000_0014*/
	b _irq                   	 /*外部中断异常,地址0x0000_0018*/
	b _fiq                   	 /*快速中断异常,地址0x0000_001c*/
	
/*******************************************************************
*指令解析:
***b指令:分支指令,这是一个相对于PC指针的跳转指令,跳转范围+32MB~-32MB
*****B{L}{cond} <target_address>
*******L:表示带返回值的分支指令,返回值为<target_address + 4>(即当前BL指令的下一条指令),存储在R14(LR)寄存器中;写法BL <target_address>,效果是先跳转到<target_address>处执行指令;当遇到mov pc,lr指令时,返回到BL指令的下一条指令(即pc指针指向<target_address + 4>地址)。
*******cond:条件执行,如BEQ <target_address>,表示如果相等(通常配合比较指令cmp一起使用)就跳转到<target_address>。
*******target_address:指定要跳转到的地址
*******************************************************************/

/*-------------注意-----------*/
/*这里的异常跳转指令到使用B指令,这是一条相对跳转指令,在以后可能会出现BUG*/
/*这里都使用B指令,只是实验性的,以后会参考U-Boot,使用ldr指令修改PC指针,变成绝对地址跳转*/
/*----------------------------*/

/*复位处理程序*/
reset:
	/*点亮LED灯的程序*/
	ldr r0, =GPMCON				 /*配置GPIO端口GPM[0:3]引脚为输出模式*/
	ldr r1, [r0]
	ldr r2, =0xffff0000
	and r1, r1, r2
	ldr r2, =0x00001111
	orr r1, r1, r2
	str r1, [r0]
	
	ldr r0, =GPMPUD				 /*禁止上下拉电路*/
	ldr r1, [r0]
	bic r1, r1, #0x000000ff
	str r1, [r0]
	
	ldr r0, =GPMDAT				 /*关LED*/
	ldr r1, [r0]
	orr r1, r1, #0x0000000f
	str r1, [r0]
	
	ldr r1, [r0]				/*点亮LED灯*/
	bic r1, r1, #0x0000000a
	str r1, [r0]
	
/*************************************************************************
*以上用到的指令有:
**ldr:从内存地址加载一个字的数据(32位);带等号的,如ldr r2, =0xffff0000,为伪指令,用于将32位数据加载到r2寄存器,mov指令做不到这样的操作。
**and:逻辑与
**orr:逻辑或
**str:将一个字(32位)从寄存器存储到内存中。
**bic:位清除
**具体可以参考手册《ARM Architecture Reference Manual》
*************************************************************************/

loop_1:
	b loop_1
	
_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					 /*标识文件结尾,之后的内容无效*/
	

3.2 Makefile

在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:led.o
	$(LD) $(LDFLAGS) $@ $^ 

#-gstabs选项表示生成调试信息	
led.o:start.S
	$(AS) -gstabs -o $@ $^
	
#清除编译后产生的文件
.PHONY:clean
clean:
	del *.bin *.o *.elf *.dump

3.3 链接脚本

/*链接脚本*/
/*指定输出文件的BFD输出格式*/
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*指定输出架构*/
OUTPUT_ARCH(arm)
/*指定程序入口*/
ENTRY(_start)
/*定义各个段*/
SECTIONS{
	. = 0x0c000000;            /*当前地址从0x0c000000开始*/
	
	. = ALIGN(4);              /*4字节对齐*/
	.text : {                  /*代码段放这里*/
		*(.text)
	}
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值