第3章开发裸机程序

3.1概述

所谓裸机程序就是指嵌入式系统的软件在没有操作系统的支持下运行,有时也称谓“裸跑”。一般来说裸机程序涉及到汇编语言程序的编写,以及汇编语言与C语言的混合编程等。但是一般来说,汇编语言部分的内容较少,主要是编写系统启动代码,为后面的C语言程序设置运行环境等(主要是设置堆栈),有51系列微处理器开发经验者对这点是应该有印象的。一般51系列处理器主要采用keil开发工具,其本身提供了汇编语言的启动代码。目前对ARM系列处理器来说,keil也进行了支持。但是实际上我们完全可以用gcc进行开发。

本部分主要涉及两部分内容:1)纯汇编语言程序的编写;2)汇编语言与C语言混合编写。因为汇编语言难学,可移植性差,真正的产品中是很少采用这种方式的,一般裸机程序都采用第2种方式,并且汇编语言编写的主要是启动代码,这部分内容完全可以作为模板,一次编写以后不再编写,将开发者的主要精力集中到系统功能的实现上来。所以对ARM处理器的汇编指令我们不做讲解,对汇编程序的编写规则也不做介绍。

本章我们将采用这两种不同的方式实现通过GPIO端口控制LED,实现LED的闪烁。另外至于芯片的具体硬件功能的详细分析,我们将在后续章节关于外设部分介绍。

3.2硬件原理

本教程采用的开发板是Tiny6410,也摘录了其教程部分内容,其他的开发板也是类似的。

LED原理图

 在原理图中搜索引脚“nLED_1”,可得:

LED引脚图

 可见,LED1,2,3,4 分别使用的 CPU 端口资源为 GPK_4,5,6,7。

3.3汇编语言实现

由原理图可知,点亮 Tiny6410 的 4 个 LED 需如下3 个步骤:
1)把外设的基地址告诉 CPU;对于 6410 来说,内存的地址范围为 0x00000000~0x60000000,外设的地址范围为 0x70000000 - 0x7fffffff。
2)关闭看门狗,防止程序不断重启;设置寄存器 GPKCON0,使 GPK_4/5/6/7 四个引脚为输出功能。
3)往寄存器 GPKDAT 写 0,使 GPK_4/5/6/7 四个引脚输出低电平,4 个 LED 会亮;相反,往寄存器 GPKDAT 写 1,使 GPK_4/5/6/7 四个引脚输出高电平,4 个 LED 会灭。以上步骤即为 start.S 中的核心内容。
1.start.S
.global _start

_start:
   // 把外设的基地址告诉CPU
   //对于6410来说,内存(0x00000000~0x60000000)
   //外设(0x70000000-0x7fffffff)
    ldr r0, =0x70000000 

    //外设大小:256M
    orr r0, r0, #0x13	
					
   //把r0的值(包括了外设基地址+外设大小)告诉cpu
    mcr p15,0,r0,c15,c2,4       			
  
    
	// 关看门狗
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0] 

	// 设置GPKCON0
	ldr r1, =0x7F008800 					
	ldr r0, =0x11110000																  
	str r0, [r1]

	mov r2, #0x1000
led_blink:
	// 设置GPKDAT,使GPK_4/5/6/7引脚输出低电平,LED亮
	ldr r1, =0x7F008808 					
	mov r0, #0
	str r0, [r1]

	// 延时
	bl delay							

	// 设置GPKDAT,使GPK_4/5/6/7引脚输出高电平,LED灭
	ldr r1, =0x7F008808 					
	mov r0, #0xf0
	str r0, [r1]

	// 延时
	bl delay	

	sub r2, r2, #1
	cmp r2,#0
	bne led_blink

halt:
	b halt


delay:
	mov r0, #0x1000000
delay_loop:
	cmp r0, #0
	sub r0, r0, #1
	bne delay_loop
	mov pc, lr
2. Makefile
led.bin: start.o
	arm-linux-ld -Ttext 0x50000000 -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led_elf.dis
%.o : %.S
	arm-linux-gcc -o $@ $< -c

%.o : %.c
	arm-linux-gcc -o $@ $< -c 

clean:
	rm *.o *.elf *.bin *.dis  -rf

3.3汇编语言与C语言混合编程

1.start.S

// 启动代码
.global _start
_start:

	// 把外设的基地址告诉CPU
	ldr r0, =0x70000000
        orr r0, r0, #0x13
        mcr p15,0,r0,c15,c2,4       @ 256M(0x70000000-0x7fffffff)
    
	// 关看门狗
	ldr r0, =0x7E004000
	mov r1, #0
	str r1, [r0]

	// 设置栈
	ldr sp, =8*1024

		
	// 跳转
	ldr pc, =main
halt:
	b halt	

此处的功能和汇编程序基本相同,在关闭了看门狗,设置了栈之后,然后跳转到main函数,main函数也就是我们编写的应用程序。从这里我们实际上也可以看出C语言程序实际上并不一定非要从main函数开始执行的。

2.main.c

#include"common.h"
void delay(){
	volatile int i = 0x10000;
	while (i--);
}

int main(){
	int i = 0;
	
	clock_init();// 初始化时钟
	sdram_init();// 初始化内存
	copy2ddr();// 重定位
        mmu_init();// 初始化mmu  

	// 虚拟地址
	volatile unsigned long *gpkcon0 = (volatile unsigned long *)0x10008800;
	volatile unsigned long *gpkdat = (volatile unsigned long *)0x10008808;
	
	*gpkcon0 = (*gpkcon0 & ~(0xffff<<16)) | (0x1111<<16);
	
	while (1){
		*gpkdat = (*gpkdat & ~(0xf<<4)) | (i<<4);
		i++;
		if (i == 16)
			i = 0;
		delay(0x10000);
	}
	
	return 0;
}

从代码中我们可以看出系统首先进行了初始化,然后设置了MMU(这一步也并不是必须的),接着进入一个死循环,不停地改变端口的值。这里详细的初始化代码不再列出,具体可查看如下https://pan.baidu.com/s/1CSPa_I-obpSylrHIeKMUNg 提取码:pf99

3.makefile

led.bin: start.o clock.o sdram.o mmu.o main.o
	arm-linux-ld -T led.lds -o led.elf $^
	arm-linux-objcopy -O binary led.elf led.bin
	arm-linux-objdump -D led.elf > led.dis

%.o : %.S
	arm-linux-gcc -o $@ $< -c

%.o : %.c
	arm-linux-gcc -o $@ $< -c
	
clean:
	rm *.o *.elf *.bin *.dis -f

我们可以看到本节的makefile和上一节的几乎完全相同。但是因为涉及到多段代码,所以还必须要有连接文件,不能使用缺省连接文件。

4.led.lds

SECTIONS {
    . = 0x50000000;
    .text : {
			start.o
			sdram.o
			mmu.o
			clock.o
			* (.text)
	}
	.rodata : {
			* (.rodata)
	}
	.data : {
			* (.data)
	}
    bss_start = .;
    .bss ALIGN(4)  : { *(.bss)  *(COMMON) }
    bss_end = .;
}

3.4编译代码和烧写运行

编译代码
在主机端的终端中执行如下命令,假设代码位于~/led
cd ~/led
make
执行 make 后会生成 led.bin 文件。
烧写运行
烧写的方式有很多,我们采用最基本,最简单的方式运行:利用u-boot的串口下载功能
开发板上电,然后在主机端的终端中按任意键,使开发板进入uboot下载模式
loady 0x50000000 led.bin
go 0x50000000

我们采用Ymodem协议,将主机编译好的二进制文件下载到0x5000000位置(在makefile和lds文件中已经进行了设定)然后运行。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值