首页 > 编程语言 >1.第一个ARM裸机程序

1.第一个ARM裸机程序

时间:2023-07-06 21:56:34浏览次数:47  
标签:led1 文件 r0 r1 程序 裸机 地址 寄存器 ARM

原文:(76条消息) 1.第一个ARM裸机程序_冷暖自知_源的博客-CSDN博客

目录

1.查看原理图和数据手册,设置IO口功能

2.S3C2440框架和启动过程

3.编写程序点亮LED灯思路

4.一些汇编语言的知识

5.编写汇编代码

6.编译文件

7.下载到开发版

8.查看伪指令解析后的汇编指令

练习1:修改led1.S驱动LED2

练习2:修改bin文件点亮LED3

9.用c语言控制LED灯

1.查看原理图和数据手册,设置IO口功能
提示:此处使用的芯片是三星的S3C2440A

1.1.LED1,连接到GPF4的IO口,从原理图看出是低电平点亮LED灯。

 

1.2查看数据手册,配置寄存器

 

寄存器的描述


查看这些寄存器的具体功能,直接定位到GPF这一组寄存器的端口


看GPF具体位的定义是什么?


配置好输出模式之后,设置GPF4的输出电平,写GPFDAT寄存器,具体描述如下:


小结:

控制GPF4需要设置两个寄存器,GPFCON,GPFDAT

1.设置GPF[9:8] = 0b01 --GPF4配置为输出

2.设置GPFDAT[4]= 0或者1; --GPF4输出低/高电平

2.S3C2440框架和启动过程
2.1.基本框架

S3C2440是一个SOC,在一块芯片上面集成了有CPU、GPIO控制器、Nand控制器、Nor控制器、以及4K的SRAM。

 

2.2.启动过程(大多数ARM芯片从0地址启动)

1.NoR启动,NoR Flash 基地址为0(片内RAM地址为:0x40000000),CPU读出NOR读出上的第一个指令(前四个字节)执行,CPU继续读出其他指令执行。

2.Nand启动,片内4K SRAM 基地之为0(Nor Falsh 不可访问),硬件2240把NAND前4K内容复制到片内内存SRAM中,然后CPU从0地址取出第一条指令(前四个字节)执行。

3.编写程序点亮LED灯思路
3.1.设置GPFCON寄存器的 【9:8】为 0 1 ,也就是网GOFCON这个地址(0x56000050)写值

使用寄存器助手看一下,设置的值为多少?设置的值为:0x100

 

即把值0x100写到地址:0x56000050 上

3.2.点亮或者熄灭LED灯

熄灭:设置GPFDAT寄存器的第4位为1,也就是网GOFDAT这个地址(0x56000054)写值,写的值为:0x10

 

点亮:设置GPFDAT寄存器的第4位为0,也就是网GOFDAT这个地址(0x56000054)写值,写的值为:0

注意:此方法会破坏寄存器原本的位,即改变这个寄存器所有的位,因为此时控制一个LED所以不管别的位。

4.一些汇编语言的知识
点我查看
5.编写汇编代码
5.1.新建给汇编文件

 

5.1.使用source insight 打开文件,编辑文件,代码如下:

/*
*点亮LED,GPF4
*/


.text
.global _start
_start:
/*配置GPF4为输出引脚*/
/*0x100写到地址0x56000050*/

//使用伪指令,把GPFCON的地址赋值给R1
ldr r1,=0x56000050
//把0x100赋值给R0
mov r0,#0x100 /*ldr r0,=0x100*/
//把r0的值写到地址r1去
str r0,[r1]

/*配置GPF4输出低电平,点亮LED*/
/*把0写到地址0x56000054*/

//使用伪指令,把GPFDAT的地址赋值给R1
ldr r1,=0x56000054
//把0赋值给R0
mov r0,#0 /*ldr r0,=0*/
//把r0的值写到地址r1去
str r0,[r1]

/*死循环*/
halt:
b halt
6.编译文件
6.1.打开Linux的虚拟机,查看虚拟机的IP地址

 

6.2.在window系统使用远程登陆工具(filezilla Pro),登陆Linux账户,进行文件的传输

 

6.3.双击led1.S,文件自动进行传输;

 

6.4.进入Linux系统,进入work目录

 

开始编译:

使用命令:

预编译:arm-linux-gcc -c -o led1.o led1.S

链接 :arm-linux-ld -Ttext 0 led1.o -o led1.elf

得到bin文件:arm-linux-objcopy -O binary -S led1.elf led1.bin

一次输入上面的命令得到,下面的编译文件:

 

提示:手动输入比较容易出错,所以在这里制作一个Makefile文件

 

使用NotePad打开,编辑如下:

 

上传Makefile到Linux系统上(使用filezilla Pro):

 

以后可以使用命令:

make clean --清除编译文件
make --编译


7.下载到开发版
7.1.把Linux系统编译好的led1.bin文件传回windows系统

 

7.2.使用oflash烧写bin文件到开发版

进入window命令行,跳转到bin文件所在目录,执行oflash led1.bin

 

选择eop烧写:

 

选择2440:

 

烧写到Nand Flash:

 

从0地址开始烧写:

 

烧写完成,拔掉开发板的eop烧写器,使开发板从Nand Flash启动,重启开发版。重启之后就可以在开开发版中看到连接到GPF4的LED被点亮了。

8.查看伪指令解析后的汇编指令
8.1.修改Makefile 把 .elf文件反汇编,查看真正的汇编指令

使用指令:arm-linux-objdump -D led1.elf > led1.dis

修改后入下:

all:
arm-linux-gcc -c -o led1.o led1.S
arm-linux-ld -Ttext 0 led1.o -o led1.elf
arm-linux-objcopy -O binary -S led1.elf led1.bin
arm-linux-objdump -D led1.elf > led1.dis

clean:
rm *.bin *.o *.elf
使用远程登陆工具(filezilla Pro)上传Makefile文件到Linux虚拟机(因为已经上传过一次,所以此处应该为覆盖文件)

 

8.2.回到Linux虚拟机,使用make命令进行编译

 

生成的 led1.dis文件传回到windows

 

使用Notepad打开这个文件

 

想要看懂汇编语言语句,需要对ARM寄存器有所了解:

 

注意:ARM的指令的运行采用的是流水线型,当指令地址A的指令时,CPU已经对地址A+4的指令进行译码,同时已经在读取地址A+8的指令。所以pc的值是当前的地址+8;

8.3汇编代码指令解析:

第一句指令:ldr r1, [pc, #20]

 

第二句指令:mov r0, #256

解析:把0x100的值赋值给寄存器r0

第三句指令:str r0, [r1]

解析:把ro的值(0x100)写到r1对应的内存,即把值0x100写入到内存:【0x56000050】

第四句指令:ldr r1, [pc, #12]

 

第五句指令:mov r0, #0

解析:把0赋值给r0寄存器

第六五句指令:str r0, [r1]

解析:把ro的值(0x0)写到r1对应的内存,即把值0x0写入到内存:【0x56000054】

小结:

在CPU的角度来看,GPFCON、GPFDAT他们没有本质的区别,都当作内存来用。

8.4.编译器的功能

编译过程,我们的编译器会把汇编码转换成机器码,而机器码就是bin文件(二进制文件)的内容

把Linux编译好的 .bin文件从Linux拉出来,用Hex工具打开和.dis文件的机器码进行比较

可以看出他们是一样的。

 

练习1:修改led1.S驱动LED2
修改led1.S文件驱动连接GPF5的LED灯

1.由原理图可知,需要操作的的是GPF5

 

 

通过查看寄存器GPFCON的描述可知,需要设置GPFCON[11:10] = 0b01

即:网0x56000050地址写 0x400

 

2.修改led1.S文件

代码如下:

.text
.global _start
_start:
/*配置GPF5为输出引脚*/
/*0x400写到地址0x56000050*/

//使用伪指令,把GPFCON的地址赋值给R1
ldr r1,=0x56000050
//把0x100赋值给R0
mov r0,#0x400 /*ldr r0,=0x400*/
//把r0的值写到地址r1去
str r0,[r1]

/*配置GPF5输出低电平,点亮LED1*/
/*把0写到地址0x56000054*/

//使用伪指令,把GPFDAT的地址赋值给R1
ldr r1,=0x56000054
//把0赋值给R0
mov r0,#0 /*ldr r0,=0*/
//把r0的值写到地址r1去
str r0,[r1]

/*死循环*/
halt:
b halt

3.上传到Linux进行编译:

 

4.传回windows 烧录到开发版

 

5.使用oflash 烧录到Nand Flash中,重启开发版,LED2被点亮。

附加:查看反编译的机器码是什么,下个练习用到

 

既然机器码是真正写到硬件的二进制代码,理论上我们通过修改二进制代码就可以修改他们的功能了。所以我们需要去查看RAM架构手册中对于 mov指令的描述,它每一个位的含义是什么?

MOV指令机器码如下所示:

 

当使用命令:mov r0 ,#1024 --把0x400赋值给r0的时候(也就是点亮LED2的时候)的机器码是:0xe3a00b01

把该值赋值到寄存器查看助手,查看一下哪一个位被设置了

 

如果想通过修改机器码去修改程序的执行结果,就是要修改mov指令机器码的立即数【11:0】的值

 

计算一下0x400的立即数是什么是否和上面的解释的一样

 

所以我们就可以通过改变机器码里边的立即数来改变最终程序的执行结果了。这样子的话,只要我们知道了我们需要设置的立即数,我们就可以推算出机器码,然后把这个机器码写入到硬件里面,程序就可以按我们的想法执行了。

具体看练习2的例子。

练习2:修改bin文件点亮LED3
1.由原理图可知,需要操作的的是GPF6

 

如果是使用汇编语言的话,那么和练习1的句子应该只有一句不同,只需要将上面的GPFCON[13:12]=0b01

 

使用寄存器助手看一下需要设置的值,设置为0x1000

 

可以看出这个程序的立即数是:0x1000,那么这个立即数 对应的机器码是什么?

0x1000可以转化成二进制可以表示为: 19个0加上1000000000000,用机器码表示成:1右移20位得到的数

那么机器码的rotate就是:20/2=10; immed_8=1;

那么整个机器码我们可以表示为:e3a00a01

 

直接复制练习1的例子中的bin文件,把e3a00b01 改成 e3a00a01

 

烧录修改后的bin文件到开发版中,烧录重启后,可以看到开发版的LED3亮灯。

9.用c语言控制LED灯
9.1.编写思路

通过查数据手册,知道了寄存器GPFCON和GPFDAT的数值,它们是32位的地址,其实本质来说也是内存,不过我们修改了这个内存的值就会使程序的运行结果发生变化,如果能根据数据手册的要求去改变这个寄存器所在地址的数值的话就能控制对应IO了。

 

在C语言中可以定义一个指针变量来存放这两个32位的地址,然后在程序中改变这个32位地址的(改变寄存器)值。

9.2.编写c代码

新建一个.c文件,很简单几条语句

int main()
{
unsigned int *pGPFCON=(unsigned int *)0x56000050;
unsigned int *pGPFDAT=(unsigned int *)0x56000054;
/*配置GPF4的引脚为输出引脚*/

*pGPFCON=0x100;

/*配置GPF4的引脚输出低电平(点亮LED)*/
*pGPFDAT=0;

return ;

}
问题:

1.编写的main函数谁来调用

2.main函数定义的变量保存在内存中,内存地址是多少

答:写一个汇编代码,给main函数设置使用的内存,调用main函数。

9.3.编写汇编代码

新建一个启动文件,命名为start.S,具体内容如下:

.text
.global _start

_start:

/*c语言中局部变量保存在栈中,栈对应的是一块内存*/
/*设置内存 :sp 栈*/
ldr sp ,=4096; //Nand Flash 启动

/*对于2440来说,当设置为Nand启动,从0开始的4k空间
对应的是片内内存,把栈设置在内存的顶部*/

// ldr sp ,=0x40000000+4096; //Nand Flash 启动
/*对于2440来说,当设置为Nor启动,片内4k内存的地址是0x40000000
对应的是片内内存,把栈设置在内存的顶部*/

/*调用main函数,跳转到main函数*/
bl main
halt:
b halt
9.4.编写一个Makefile,方便对于汇编文件的编译,内容如下:

all:
arm-linux-gcc -c -o led.o led.c
arm-linux-gcc -c -o start.o start.S
arm-linux-ld -Ttext 0 start.o led.o -o led.elf
arm-linux-objcopy -O binary -S led.elf led.bin
arm-linux-objdump -D led.elf > led.dis

clean:
rm *.bin *.o *.elf *.dis
9.5.上传到Linux系统进行编译

 

在Linux系统进入源文件所在目录进行编译

 

9.6.把Linux系统编译好的文件传回window,然后烧写led.bin文件到开发版,可以看到GPF4对应的led灯亮了,这样这个c语言代码就便宜完成了。

 


————————————————
版权声明:本文为CSDN博主「冷暖自知_源」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_36243942/article/details/84565389

标签:led1,文件,r0,r1,程序,裸机,地址,寄存器,ARM
From: https://www.cnblogs.com/bruce1992/p/17533429.html

相关文章

  • 小程序助力企业打造超级APP
    在互联网时代,不可否认移动应用程序(App)是最具代表性的产品之一,自2010年以来,整体发展呈现出快速增长和发展的趋势,并对消费者的生活和各个行业的发展产生了深远的影响。各个行业和领域都涌现出大量的产品,有的成为行业巨头,有的则被市场淘汰。而有两个产品我们不可忽视,那便是两个国民......
  • 作为程序员,可以关注哪些网站
    技术大牛博客2、陈浩:https://www.coolshell.cn/博客文章多,更新快,质量高!!!3、廖雪峰:https://www.liaoxuefeng.com/Python启蒙老师,Python,Git系列教程作者4、王垠:http://www.yinwang.org/5、阮一峰:http://www.ruanyifeng.com/home.html计算机科普博主国内技术社区6、博客......
  • 【资料分享】RK3568评估板规格书(4x ARM Cortex-A55(64bit),主频1.8GHz)
     1 评估板简介创龙科技TL3568-EVM是一款基于瑞芯微RK3568J/RK3568B2处理器设计的四核ARMCortex-A55国产工业评估板,每核主频高达1.8GHz/2.0GHz,由核心板和评估底板组成。核心板CPU、ROM、RAM、电源、晶振、连接器等所有器件均采用国产工业级方案,国产化率100%。同时,评估底板大部......
  • 融合Flutter与小程序容器助力业务创新
    Flutter是Google开源的构建用户界面(UI)工具包,帮助开发者通过一套代码库高效构建多平台精美应用,支持移动、桌面和嵌入式平台。Flutter开源、免费,拥有宽松的开源协议,适合商业项目。它可以使用户在单一代码的条件下构建出iOS和安卓应用,并且方式较为现代化,同时,从用户界面来看,整体页......
  • 小程序开发心得分享:优质小程序制作平台推荐
    当今,小程序已经成为许多企业和个人推广业务的首选方式。然而,对于缺乏开发能力的人们来说,制作一个高品质的小程序仍然是一个难题。这时,小程序制作平台应运而生。这些平台将小程序制作过程工具化,使得繁琐的代码编写、调试和上线等步骤都可以通过可视化操作轻松完成。这样,即使是非专......
  • 使用strace测试打开程序响应时间
    我们想要知道一个程序从运行到打开的响应时间可以使用strace命令测试写一个运行打开某个程序的脚本例如一下脚本可以打开wpstest.sh#!/bin/bash#/usr/bin/google-chrome-stablewww.baidu.com/usr/bin/wps#/usr/bin/kylin-software-center#/usr/bin/kylin-musicexit运行......
  • Qt 四种程序的架构设计方法
    四种常见的关于Qt程序的架构设计方法:1.使用MVC设计模式MVC是Model-View-Controller的缩写,是应用程序开发中常用的设计模式。在Qt中,可以使用QAbstractItemModel和QTreeView等类来实现MVC模式。 2.使用信号和槽机制Qt中的信号和槽机制是一种灵活的方式,可以将不同的组件连接在......
  • C++程序课程设计任务书[2023-07-06]
    C++程序课程设计任务书[2023-07-06]C++程序课程设计任务书班级学号姓名一、实践目的该实践在系统学习《C++程序设计基础》课程后进行。通过本实践,培养学生使用C++解决实际问题的能力。二、实践任务与要求(任选一个任务,独立完成)任务一:(一)......
  • 2023-07-06 微信开发者工具上传代码,在体验版查看时发现小程序的一些全局字体样式不生
    前言:在less中使用【@样式变量】如:@global_color:var(--global_color,red);问题描述:在开发工具中字体样式能正常显示,预览扫码到真机上也能显示字体颜色,结果上传代码到了提样版就不行了,样式不生效。这里用到了一个var函数,“var()函数用于插入自定义的属性值,如果一个属性值在......
  • gitlab+jenkins+pycharm持续集成环境搭建
    接口自动化虚拟机登录:root   sq若gitlab的容器打不开,关闭防火墙gitlab登录:http://192.168.31.128:9001/projects/new#blank_projectrooti3213941 Git:分布式版本控制系统本地仓库:是在开发人员自己电脑上的git仓库远程仓库:是在远程服务器上的git仓库Clone:克隆,就是将......