从零开始写一个arm下的裸板程序

从零开始写一个arm下的裸板程序.我们整个程序是基于uboot运行的.
所有我们可以借助uboot中的printf来输出,默认开发版的标准输出是串口.
电脑的默认标准输出的屏幕.

1.需要创建的文件由include文件夹,用来存放头文件.
2.创建一个hw.h头文件.
3.编写一个common.h,它定义了借用uboot的printf的宏.和NULL这个宏的定义.
4.hw.c     硬件相关的文件.
5.main.c   c文件.
6.start.s  汇编文件.
7.ld.lds   链接脚本,
8.Makefile 用来管理编写项目的配置文件.

下面开始是每个步骤的详细解析:

/**********************************************/
1.创建include文件.

[email protected]:~/work/android/code/hardware$ mkdir my01porject               //创建一个项目文件.
[email protected]:~/work/android/code/hardware$ cd my01porject/                 //切换到当前项目路径.
[email protected]:~/work/android/code/hardware/my01porject$ mkdir include       //创建一个include文件夹.

/**********************************************/

2.创建hw.h硬件相关的操作, 

#ifndef __MY_HW_H
#define __MY_HW_H

extern int hw_init(void);//这个是硬件初始化操作.
extern int hw_opts(void);//这个是硬件操作函数.
#endif

/**********************************************/
3创建一个common.h.

#ifndef __MY_COMMON_H
#define __MY_COMMON_H

#define NULL (void *)0                                                        //定义了宏 NULL

//定义了一个printf宏,(__VA_ARGS__)在定义变参数的时候必须要加这个表示,
// int (*)(const char *, ...)是一个函数指针的类型.
// 我们把这个0x43e11434数字转化成当前类型的函数指针类型.
#define printf(...) (((int (*)(const char *, ...))0x43e11434)(__VA_ARGS__))   

#if 0 

//需要注意的是我们需要说下他的由来.0x43e11434,
//切换到uboot源代码所在目录.
[email protected]:~/work/arm/arm资料/exynos4412_lzy/src/uboot/uboot-2012-12$ ls
api         COPYING      examples     Makefile     README           u-boot
arch        COPYING.txt  fs           mkconfig     rules.mk         u-boot.bin
board       CREDITS      include      nand_spl     sd_fuse          u-boot.lds
boards.cfg  disk         lib          net          snapshot.commit  u-boot.map
common      doc          MAINTAINERS  onenand_ipl  System.map       u-boot.srec
config.mk   drivers      MAKEALL      post         tools
#endif

在Makefile中有怎么一段,就是告示你,当前函数的所有链接地址都放在.System.map中.
SYSTEM_MAP = 		$(NM) $1 | 		grep -v '\(compiled\)\|\(\.o$$\)\|\( [aUw] \)\|\(\.\.ng$$\)\|\(LASH[RL]DI\)' | 		LC_ALL=C sort
$(obj)System.map:	$(obj)u-boot
		@$(call SYSTEM_MAP,$<) > $(obj)System.map

这个是我拷贝这个System.map打开的一部分.其中43e11434 T printf就是uboot的链接地址.
43e11294 T serial_printf
43e112d8 T fgetc
43e11304 T ftstc
43e11330 T fputc
43e11358 T fputs
43e11380 T fprintf
43e113cc T getc
43e113e4 T tstc
43e113fc T putc
43e11418 T puts
43e11434 T printf
43e11478 T vprintf
//再c中我们找到一个函数的地址.就可以调用给函数.方式如上.

#endif

/**********************************************/

4.编写一个测试类hw.c 文件.

#include<hw.h>

//初始化当前设置的值,
int hw_init(void)
{
	//我们做个参数.只输出当前函数的名称,和当前行所在的值.
	printf("%s ,%d",__FUNCTION__, __LINE__);
	return 0 ;
}

//对当前设备进行操作.
int hw_opts(void)
{

	//我们做个参数.只输出当前函数的名称,和当前行所在的值.
	printf("%s ,%d",__FUNCTION__, __LINE__);
	return 0 ;
}

/**********************************************/
5.编写main.c进行调用.

#include<stdio.h>
int main(void)
{
	hw_init();
	hw_opts();
	return 0;
}

/**********************************************/
6.编写start.s文件.这个是程序执行的入口.
//这个表示该_start是一个外部标号,如果不使用.global,进行修饰它默认是是一个内部标号.
//当你你可以把他下载到内存的某个地址上.如何使用go 50000000执行.它相当于执行了
//如下操作. bl _start,再跳转之前他会把uboot中的bl _start的下一条指令存放的 lr寄存器中.

.global _start    
_start:
	b reset      //b reset则是跳转到reset:标号下执行.
reset:
	stmfd sp!, {r0-r12, lr} //这句话的意思是讲.r0-r12, 和lr进行压栈.是为了保存这些值,
	bl main                 //这只就是跳转到我们c函数中的main中执行.再跳转之前它会讲当前lr赋值为ldmfd的值.
				//执行完毕之后.会跳转回来执行.ldmfd sp!, {r0-r12, lr} ,将压栈的东西拿出来,
	ldmfd sp!, {r0-r12, lr}
	@mov pc, lr	       //这个是注释行.在汇编中使用@进行注释.
	bx lr                  //之后跳转会uboot执行.为什么步b指针进行跳转,
                               //是以为lr是一个寄存器.b不能操作寄存器,它只能操作标号.而bx可以.因为他只能操作寄存器.

/**********************************************/
7.
每一个链接过程都由链接脚本(linker script, 一般以lds作为文件的后缀名)控制.
链接脚本主要用于规定如何把输入文件内的section放入输出文件内,
并控制输出文件内各部分在程序地址空间内的布局.
但你也可以用连接命令做一些其他事情.

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")  // 定义三种输出文件的格式(大小端)
OUTPUT_ARCH(arm)//设置输出文件的machine architecture(体系结构),BFDARCH为被BFD库使用的名字之一。可以用命令objdump -f查看
ENTRY(_start)   //ENTRY(SYMBOL) :将符号SYMBOL的值设置成入口地址。
SECTIONS
{
 . = 0x50000000;       //这个说明的是一个链接地址.
 . = ALIGN(4);         //进行4字节对齐.
 .text :               //定义一个.text段.
 {
  ./start.o (.text)    //链接的第一个文件是./start.o 其他的文件链接.
  *(.text)             //其他文件的文件.不管他们的顺序.  下面是定义其他段.
 }

 . = ALIGN(4);
 .rodata : { *(.rodata) }

 . = ALIGN(4);
 .data : {
  *(.data)
 }

 . = ALIGN(4);
 .bss : {
  *(.bss)
 }
}
/**********************************************/
编写Makefile文件.

TARGET			:=arm                    //定义目标变量名称.
BIN			:=$(TARGET).bin          //定义生成目标文件的bin文件.
START_OBJ		:=start.o		 //定义start.s生成的目标名称.
OBJS			:=main.o hw.o		 //定义其他 需要编译的.c文件生成的.o文件的名称.
LD_ADDR			:=0x50000000             //定义链接地址.

CFLAGS += -Wall -I./include                      //CFLAGES += -Wall表示打开警告.编译是自动查找./include目录下的头文件. 

CROSS_COMPILE	:=arm-linux-		         //定义一个前缀名称.
CC				:=$(CROSS_COMPILE)gcc $(CFLAGS)    //定义编译编译命令
AS				:=$(CROSS_COMPILE)as               //定义汇编命令.
LD				:=$(CROSS_COMPILE)ld               //定义链接命令.
OBJCOPY			:=$(CROSS_COMPILE)objcopy -O binary        //定义去掉elf格式的命令.
OBJDUMP			:=$(CROSS_COMPILE)objdump -D               //定义反汇编命令.
NM				:=$(CROSS_COMPILE)nm               //定义链接之后各个函数对应的链接地址.命令.

RM				:=rm -rf                           //定义一个rm 命令.也就是删除命令.

##############################################
all:$(TARGET)                     				   //定义一个目标.
	@$(OBJCOPY) $< $(BIN)
	@echo OBJCOPY	$<
	@$(OBJDUMP) $< >$<.s
	@echo OBJDUMP	$<
	@$(NM) $< >System.map
	@echo NM	$<
	@$(RM) $<

#	./down.sh

$(TARGET):$(START_OBJ) $(OBJS)
	#@$(LD) $^ -o [email protected] -Ttext $(LD_ADDR)
	@$(LD) $(OBJS) -o [email protected] -T ld.lds
	@echo LD	[email protected]

%.o:%.s                       //这里是要生成start.o依赖start.s文件.
	@$(AS) $< -o [email protected]       //$<会自动匹配所有的依赖, [email protected]会自动匹配所有目标.
	@echo AS     [email protected]       //输出生成的目标.

%.o:%.c
	@$(CC) $< -c -o [email protected]
	@echo CC	[email protected]

clean:
	@$(RM) $(START_OBJ) $(OBJS) $(BIN)
	@echo RM	./

时间: 2024-08-13 03:18:31

从零开始写一个arm下的裸板程序的相关文章

深入浅出React Native 3: 从零开始写一个Hello World

这是深入浅出React Native的第三篇文章. 1. 环境配置 2. 我的第一个应用 将index.ios.js中的代码全部删掉,为什么要删掉呢?因为我们准备从零开始写一个应用~学习技术最好的方式就是自己动手写,看别人的代码一百遍的效果也不如自己写一遍来的效果大~ 我们要做的事情主要分成以下两步: 1. 创建组件 2. 将创建好的组件显示在app上 打开index.ios.js文件,输入 var HelloWorld = React.createClass({ render: functio

刚接触开发板之烧写裸板程序

使用串口操作开发板的前提是开发板上已经有烧好的程序,因此开发板在没有烧好程序时,应先烧写程序.方法有: 1.使用并口工具烧写:接线(参考百问网JZ2440V2开发板使用手册),使用oflash烧写(速度比较慢),可烧写.bin文件,从新上电观察效果.可烧写u_boot. 2.使用openJTAG烧写,接线,使用oflash烧写(oflash烧写完后,会复位开发板). 3.使用Jlink烧写,请看如何烧写S3C2440裸板程序:JLink只支持烧写Nor Flash,不支持Nand Flash.要

从零开始写一个Tomcat(叁)--请求解析

挖坑挖了这么长时间也该继续填坑了,上文书讲到从零开始写一个Tomcat(贰)--建立动态服务器,讲了如何让服务器解析请求,分离servlet请求和静态资源请求,读取静态资源文件输出或是通过URLClassLoader找到我们请求的servlet,反射生成对应的实例,调用其service方法,传递初级解析的request和response,完成请求. 这很tomcat,but too simple 阅读本文,你将了解 连接器(connector),处理器(processor)逻辑分离 如何高效的解

我想写一个Linux下的C++程序库--记我的C++库设计历程:设计一个TCP服务程序

我想写一个Linux下的C++程序库,实现一些常用的功能. 我首先想到的就是实现一个TCP监听程序.该程序应该具有哪些功能呢? 1: 启动/停止监听 2: 有客户端连接时,通知调用者 3: 与客户端断开时,通知调用者 4: 有消息到达时,通知调用者 5: 尽量避免程序退出时有没有close的socket. 该程序的大体接口及结构主要用一个类表示,内容如下: #pragma once #include <functional> namespace Hi { /* * @ brief TCP监听会

Cordova webapp实战开发:(6)如何写一个iOS下自动更新的插件?

上一篇我们学习了如何写一个Andorid下自动更新的插件,我想还有一部分看本系列blog的开发人员希望学习在iOS下如何做插件的吧,那么今天你就可以来看看这篇文字了. 本次练习你能学到的 学习如何获取iOS当前版本号 学习iOS下插件类的编写 学习iOS下插件的配置 学习iOS下插件的调用 主要内容 APP中[检查更新]显示当前版本号 插件类的编写 在上一篇介绍Andorid插件时我们贴出了很多源码,这里也直接贴出代码,首先是iOS下插件的代码. 我们在Plugins下新建两个文件,一个头文件

Cordova webapp实战开发:(5)如何写一个Andorid下自动更新的插件?

在 <Cordova webapp实战开发:(4)Android环境搭建>中我们搭建好了开发环境,也给大家布置了调用插件的预习作业,做得如何了呢?今天我们来学一下如何自己从头建立一个Andorid下的cordova插件. 本次练习你能学到的 学习如何实现自动更新功能 学习插件类的编写 学习插件的配置 学习插件的调用 主要内容 打开APP后检查版本更新,如果有更新则弹出更新对话框 APP中[检查更新]显示当前版本号,并可以点击进行版本检查更新 如何实现自动更新功能 你可以自己写代码,也可以网上找

嵌入式开发之路(1)裸板程序LED

开发板:TX2440 开发环境:ubuntu12.04 在linux下用vim工具编写程序代码(启动代码,主程序,makefile),在linux下进行交叉编译,生成二进制arm可执行文件,通过vmware共享目录传输到window环境下,用jFlash烧写到arm norflash中直接运行. 实现目标:1)点亮单个LED灯 2)点亮多个LED灯   3)流水灯实验 实验心得:1)要学会自己编写启动代码,arm的启动代码汇编和传统汇编有一定的差异.启动代码主要是对硬件的初始化,关闭WATCHD

[python] 1、python鼠标点击、移动事件应用——写一个自动下载百度音乐的程序

1.问题描述: 最近百度总爱做一些破坏用户信任度的事——文库金币变券.网盘限速,吓得我赶紧想办法把存在百度云音乐中的歌曲下载到本地. http://yinyueyun.baidu.com/ 可问题是云音乐中并没有批量下载,而上面我总共存了700多首音乐! 因此:有必要写一个脚本自动下载这些音乐了!!! 2.解决问题 自动下载歌曲有两种方法: JS法 模拟鼠标点击法 由于考虑到JS法需要分析网页结构.寻找下载链接,工作量有点大,于是选择用模拟鼠标点击法! 在linux上我首先想到用python来做

Python写一个Windows下的android设备截图工具

利用python的wx库写个ui界面,用来把android设备的截图输出到电脑屏幕,前提需要安装adb,涉及到的python库也要安装.代码如下: import wx,subprocess,os,platform class AutyFrame(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, -1, 'Android Auty', size=(350, 300)) self.panel = wx.Panel(self, -