前段时间因为工作需要,研究了一下如何使用GNU工具链(arm-linux-)
编译ARM裸机程序,中间遇到了许多的问题,下面把整个过程给大家分享一下
整个过程的思想是使用GNU工具链编译、链接出bin档的可执行程序,然后使用
vivi自带的(load ram、go)功能将bin档的程序下载到内存的指定位置进行调试,
最后改造vivi的MTD分区,参考“boot kernel”命令编写“boot_simple”命令实现
裸机程序的脱机运行(可参考 《改造vivi 烧写ARM裸机程序》)。暂时无法实现调试功能。
好了,言归正传,一步步讲解我的制作过程吧。
1、首先是思路的确认,使用GNU工具链编译裸机程序要解决的几个问题:
"arm-linux-"编译出的程序是在MMU模式下的虚拟地址,而我们需要的是绝对地址
"arm-linux-"对硬件的操作是通过驱动设备文件(/dev/..)进行的,我需要直接
对硬件地址进行操作,所以必须熟悉arm-linux-ld的一些相关知识才可以
本人的对这方面的了解非常的浅,所以。。。baigoogledo一下,呵呵,成为必然选择,最终在网上查到这么一段程序:
"LED_on.S"
.text
.global _start
_start:
LDR R0,=0x56000010 @ R0设为GPBCON寄存器。此寄存器
@LDR R0,=0x56000060 @ 是输出、是输入、还是其他
LDR R1,=0x00005555 @ 设置GPB5,GPB6,GPB7,GPB8,为输出口 #表示后面的是立即数,0x表示是十六进制数。
STR R1,[R0] @ 将R1中的值,送到地z址:0x56000010中
LDR R0,=0x56000014 @ R0设为GPBDAT寄存器。此寄存器
@LDR R0,=0x56000064 @ 用于读/写端口B各引脚的数据
MOV R1,#0x0000000f @ 此值改为0x00000020,
@ 可让LED1熄灭
STR R1,[R0] @ GPB5输出0,LED1点亮
MAIN_LOOP:
B MAIN_LOOP
"Makefile"
led_on.bin : led_on.S
arm-linux-gcc -g -c -o led_on.o led_on.S
arm-linux-ld -Ttext 0x00000000(0x30000000) -g led_on.o -o led_on_elf
arm-linux-objcopy -O binary -S led_on_elf led_on.bin
clean:
rm -f led_on.bin led_on_elf *.o
于是,摘下来,修改了几个地方,我的开发板LED用的是GPG,所以将端口地址改为
0x56000064(GPG),下面的链接地址改为0x30000000,我的开发板SDRAM地址从0x30000000开始
使用:make得到led_on.bin;vivi>load ram 0x30000000 0x010000 x; go 0x30000000
LED灯被点亮了,呵呵,很是兴奋,证明了我的想法是对的,下面就是要一步步去实现了。
2、简单分析了一下上面的makefile:
"Makefile"
led_on.bin : led_on.S
arm-linux-gcc -g -c -o led_on.o led_on.S //-c:生成目标文件(里面为相对地址)
arm-linux-ld -Ttext 0x00000000(0x30000000) -g led_on.o -o led_on_elf
//-Ttest:指定连接地址,生成elf格式的可执行程序
arm-linux-objcopy -O binary -S led_on_elf led_on.bin
//使用二进制工具链 -objcopy将elf转化为bin档
clean:
rm -f led_on.bin led_on_elf *.o //清除编译信息
接下来尝试用C语言写一个简单跑马灯程序,按上述过程进行编译
/*端口F寄存器预定义*/
#define GPGCON (*(volatile unsigned *)0x56000060) //Port G control
#define GPGDAT (*(volatile unsigned *)0x56000064) //Port G data
#define GPGUP (*(volatile unsigned *)0x56000068) //Pull-up control G
#define MPLL100MHz 0x0007f022
#define CLKDIV2 0x02 // 1/2分频 PCLK=100/2=50MHz
#define rMPLLCON (*(volatile unsigned *)0x4c000004) //MPLL Control
#define rCLKDIVN (*(volatile unsigned *)0x4c000014) //Clock divider control
int main()
{
int i = 0;
int LEDON = 0x01 ; //LED1点亮值为0x01
rMPLLCON = MPLL100MHz;
rCLKDIVN = CLKDIV2; /*系统时钟设置MPLL=100MHz,PCLK=50MHz*/
GPGCON = 0x00005555; //GPG0--GPG7设置为output
GPGUP = GPGUP & 0xFF00; //使能GPG上拉电阻
GPGDAT = 0xFF; //GPG低八位初始化为1
while(1)
{
GPGDAT = LEDON; //点亮LED
LEDON = LEDON<<1; //移位
if ((LEDON & 0x100) == 0x100)
{
LEDON =0x01;
}
for(i = 0; i<0x30000;i++ );
}
}
编译通过,但是有一个警告,于是上网搜,在连接后面加了一句:-e main
ok,再次顺利运行,很高兴
3、C和汇编的简单程序都可以运行起来了,下一个非常艰巨的任务就是
如何跑起复杂的裸机程序,主要是带中断的程序,我分了一下几步来实现:
使用三星公司给出的2410库函数来编译,主要包括“2410ddr.h、2410lib.h..”
中断需要启动代码进行中断向量分配,需要start.s的支持
下面的问题就非常多了,首先我就犯了一个大错误,由于太激进,一下子把所有
的库函数都加了进来,2410addr.h、timer.c、2410lib.c、2410slib.s、option.h等
那简直是一踏糊涂,错误没有八百也有一千,呵呵,最后决定从简到繁:
从最简单的头文件“2410addr.h”头文件着手,剩下的需要什么再加什么!!
于是把上面的程序小小的改造了一下,将原有寄存器的定义全部去掉,改为
#include "./system/inc/2410addr.h"
编译也没有出错,本以为会很顺利,结果怎么都出不来~~~郁闷了好一会,最后检查了一下
#include "2410addr.h",发现在最后面有这么几句:
__inline void ClearPending(int bit)
{
register i;
rSRCPND = bit;
rINTPND = bit;
i = rINTPND;
}
__inline void ClearSubPending(int bit)
{
register i;
rSUBSRCPND = bit;
i = rINTPND;
}
于是把他们屏蔽掉,OK,原来是因为这两个内链函数,在连接时,链到了main函数前面,从而
无法执行。于是把他们改为用宏来实现:
#define ClearPending(bit) {\
rSRCPND = bit;\
rINTPND = bit;\
rINTPND;\
}
#define ClearSubPending(bit) {\
rSUBSRCPND = bit;\
rINTPND;\
}
OK!
4、下面的任务就是加入启动代码(start.s)引导中断
这次又犯了一个大错,选取测试程序,前面做的比较顺利,这次就选了RTC(实时时钟)作为中断
测试程序,里面涉及到了很多的 uart_printf()函数及其它2410库函数,需要自己重新实现printf();
弄着弄着就偏移了初衷,一直陷在如何实现2410的库函数上了,结果越弄越乱,将近费了一上午的时间。
最后也还没完全弄好。
辛亏及时悬崖勒马,将测试程序改为 定时器中断,才回到了正轨~~
中断是本工程最难的一点,也是费时间最常的一部分工作,我将近做了两天才搞定。
arm的中断机制非常特别,同时结构化也非常好。
它一般有两级中断向量表:
第一级位于0x00000000 - 0x0000001c的位置
b ResetHandler
b HandleUndef1 @handler for Undefined mode
b HandleSWI1 @handler for SWI interrupt
b HandlePrefetchAbort1 @handler for PAbort
b HandleDataAbort1 @handler for DAbort
b . @reserved
b IsrIRQ @handler for IRQ interrupt
b HandleFIQ1 @handler for FIQ interrupt
注:这级中断向量表必须位于整个存储空间的最开始部分,这是由arm硬件来决定的,
比如:一旦系统复位(看门狗、复位键按下等)PC 会被强制跳转到0x00000000执行此处的
指令,再比如:一旦来了irq中断,系统会强制PC跳到0x00000018( bl IsrIRQ),这点跟msc-51
非常的相似,但这样也会带来一个非常棘手的问题: arm的irq中断最多可有55个,他们全都执行
一个irq中断那是不现实的,如何解决??
所以在arm系统中,人为的建立了一个二级中断向量表,当irq中断来了之后,均会进入irq处理阶段,
在执行真正的中断服务程序之前,我们建立了一个“中断分发”程序,他完成根据中断向量号将irq中断分发到
不同的二级中断向量表中:
IsrIRQ:
sub sp,sp,#4
stmfd sp!,{r8-r9}
ldr r9,=INTOFFSET //中断偏移寄存器,记录了产生中断的类型
ldr r9,[r9]
@ ldr r8,=HandleEINT0 //二级中断向量表的首地址,在SDRAM中
ldr r8,=0x33ffff20
add r8,r8,r9,lsl #2 //根据中断偏移寄存器找到对应的中断服务程序
ldr r8,[r8]
str r8,[sp,#8]
ldmfd sp!,{r8-r9,pc}
所以现在的问题就是如何建立整个过程。
由于我的整个程序都被链接到0x30000000开始的位置,而一级中断向量表必须在0x00000000
开始的位置,所以必须处理这个情况。我想了三个方案:
1、连接的时候,写一个连接脚本(.lds),将start.s段链接到0x0000000开始的位置,而应用程序继续在0x3000000
这样做,就需要生成两个bin档文件,调试,使用都很麻烦
2、因为我编译出的程序的运行环境是在vivi下,所以我可以改造一下vivi的第一阶段的代码(head.S)
把相关的中断处理程序加入其中,这样中断应该也可以跑起来
3、比较极端了,你不是要呆在0x00000000上么?我就把你拷过去,呵呵,说白了就是我在程序中直接
用memcpy()把start.s拷过去,什么都搞定了~~,呵呵。
最后采用的就是第三种方法,另外两种还没来得及验证,相信问题不大。
5、方案有了,那么就是如何实
没有合适的资源?快使用搜索试试~ 我知道了~
No_OS.rar_tq2440
共254个文件
h:62个
o:44个
tdt:30个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 25 浏览量
2022-09-19
16:08:15
上传
评论
收藏 1.22MB RAR 举报
温馨提示
TQ2440的无操作系统裸跑程序, 有一些基本外围设备的测试程序
资源推荐
资源详情
资源评论
收起资源包目录
No_OS.rar_tq2440 (254个子文件)
7 uart.axf 61KB
4 rtc.axf 58KB
8 ADC1.axf 55KB
5 pwm.axf 55KB
6 watchdog.axf 55KB
UART.axf 33KB
key.axf 14KB
key.axf 14KB
myled.axf 14KB
myled.axf 14KB
4 rtc.bin 20KB
5 pwm.bin 19KB
uart.bin 18KB
uart.bin 8KB
mykey.bin 2KB
myled.bin 2KB
myled.bin 2KB
2440lib.c 18KB
2440lib.c 18KB
2440lib.c 18KB
2440lib.c 18KB
2440lib.c 18KB
2440lib.c 11KB
2440lib.c 8KB
2440lib.c 8KB
2440lib.c 8KB
2440lib.c 8KB
uart.c 5KB
main.c 5KB
rtcalarm.c 4KB
watchdog.c 4KB
pwm.c 3KB
main.c 3KB
main.c 3KB
main.c 3KB
main.c 2KB
rtc.c 2KB
Adc.c 2KB
2440main.c 965B
2440addr.h 40KB
2440addr.h 40KB
2440addr.h 40KB
2440addr.h 40KB
2440addr.h 40KB
2440addr.h 39KB
2440addr.h 39KB
2440addr.h 39KB
2440addr.h 39KB
2440addr.h 39KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
Option.h 3KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440lib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
2440slib.h 2KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
mmu.h 1KB
Def.h 418B
Def.h 418B
Def.h 418B
Def.h 418B
Def.h 418B
Def.h 309B
Def.h 309B
Def.h 309B
Def.h 309B
Def.h 309B
Adc.h 206B
共 254 条
- 1
- 2
- 3
资源评论
钱亚锋
- 粉丝: 85
- 资源: 1万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功