在几个月前看2440视频的时候,发现太多知识欠缺,购买开发板期间补习makefile,linux,arm汇编和arm构架之后,现在重新开始学习。

先看板子LED硬件连接图:

可以看到LED 1,2,4连接GPF4,5,6。故,查看芯片手册GPF IO口:

有寄存器地址,有对应位的功能,剩下的就是我们的编程了。

写在前面:基本汇编拾遗

Load/Store 内存访问指令:

LDR:字 数据读取指令

LDRB:字节读取指令

LDR R0,[R1];把内存单元R1中的数据读取到R0寄存器中

。。。LDR,STR还有很多后缀的指令不详举例了,以后用到再说明

STR:字数据写入指令

STRB:字节数据写入指令

STR R0,[R1,#0X100];把R0中的数据保存到内存单元(R1+0X100)中

B:跳转

MOV:移动 MOV R1,R0;把R0的值赋值给R1

伪指令:LDR(上面一个LDR的用法是汇编指令,但是LDR也可以是伪指令)

LDR R0,=0X1234;表示把0x1234赋值给R0,你可能会想,MOV不就可以达到效果了吗?

但是,MOV只能处理立即数,当我们不能保证一个数是否是立即数的时候,请使用LDR伪指令。

关于什么样的数才能算是立即数,可以参考ARM体系结构 P24对立即数的叙述。

简单介绍一下:

每个立即数由一个8位的常数循环右移偶数位得到,循环右移的偶数由一个4位二进制数的两倍表示记作rotate_imm,8位常数记作immed_8,立即数记作<immediate>;

<immediate>=immed_8循环右移(2*rotate_imm)

现在开始编写汇编指令,linux与windows开发最大的不同就是linux一切靠自己,不用IDE。

/*
* 点亮LED1: gpf4
*/ .text/*文本段*/
.global _start/*全局标号_start*/ _start: /* 配置GPF4为输出引脚
* 把0x100写到地址0x56000050
*/
ldr r1, =0x56000050/*为什么不使用mov,因为立即数不是一眼就能看出来的*/
ldr r0, =0x100 /* mov r0, #0x100 */
str r0, [r1] /* 设置GPF4输出低电平
* 把0写到地址0x56000054
*/
ldr r1, =0x56000054
ldr r0, = /* mov r0, # */
str r0, [r1] /* 死循环 ,因为flash后面的数据不可预知,只能停留在这里*/
halt:
b halt

这里使用c/c++中的注释方式,其实汇编中应该使用分号; 代表注释。

上述代码只是简单粗暴的完成了任务,但是破坏了寄存器中其他位的数据,作为第一个程序,暂且先这样。

需要使用到上篇随笔安装的两个工具,交叉编译器arm-linux-gcc和samba服务器,这里简单说明一下makefile:

all:
arm-linux-gcc -c -o led_on.o led_on.S
arm-linux-ld -Ttext led_on.o -o led_on.elf
arm-linux-objcopy -O binary -S led_on.elf led_on.bin
arm-linux-objdump -D led_on.elf > led_on.dis
clean:
rm *.bin *.o *.elf

这个makefile显然只能是拿来入门使用,关于其中的工具链用法,在linux系列随笔中已经有过讲解。

是不是这样就完了呢?显然不是,还要进一步分析反汇编:

第一列表示地址,第二列表示机器码,第三列表示汇编码。

ARM9采用三级流水线工作方式,可以大大提高系统效率。三级流水线,取址,译码,执行。

当cpu在执行一条指令时,已经开始对下一条指令进行译码,对下下一条指令进行取址了。这也就是我们常说的PC值等于当前指令地址加上8的原因。

分析第一条汇编,r1=[pc+20];此时pc=当前指令地址(0)+8+20=28=0x1c

可以看到在地址1c处,存放的是0x56000050,这就相当于把[pc+20]地址的内容赋值给r1,此时就r1=0x56000050。

第二条指令把256即0x100赋值给r0;

第三条指令,把r0的值写在r1的地址内,即把0x100写进地址0x56000050。后面的以此类推。

分析了反汇编之后,我们就可以通过更改bin文件,即直接更改二进制文件达到点亮led灯的效果。

刚才我们点亮了GPF4,现在点亮GPF 5,只用把上面的0x100改成0x400,其他不变(后面说注意事项)。

我们知道上面的第二列表示机器码之后,需要达到直接写一串机器码,实现MOV R0,#0X400的功能,此时我们需要查看

MOV指令机器码:

上面生成的二进制文件,可以使用sublime text 或者Uedit32打开。

先看上面我们生成的MOV RO,#256机器码:

e3a00c01

对照上面的MOV机器码,做几点说明,12-15位表示Rd,此时我们使用的是R0,这四个位全为0,表示寄存器R0,最后0-11位(立即数)就是我们需要修改的了。

关于立即数,上面做了说明:

<immediate>=immed_8循环右移(2*rotate_imm)

这里的0-11位高4位就是rotate_imm,低八位就是8位常数immed_8。

0x100的表示如上图,

公式:<immediate>=immed_8循环右移(2*rotate_imm)

高4位12,低八位为1,1循环右移2*12,刚好等于0x100.

那么0x400的呢?

可以想到,0x400,二进制0x1后面10个0,前面就需要22位,所以,我们可以采用1循环右移22位。

/* 中途插播 */

NOTE:

右移本来就是不确定的,左移是确定的,但是,右移的不确定是根据cpu的具体实现来决定的,就是不同的cpu可以有不同的处理,在我们这里,就是特定这个cpu S3C2440,所以我们的右移补位方式这里就是对特定CPU的。这个符合我们的需求,但是在其他硬件平台上,右移如何补位,要查看它的参考资料。

/* 插播 完毕*/

所以我们0x400的立即数就可以表示为:高四位为11,低八位位1,这样就可以切合。有公式完成这个就不再赘述了。

最后得出:

现在我们更改之前的bin文件,把上面MOV r0,#256的机器码改成上图的e3a00b01

烧写进入单板,观察是否点亮GPF 5.

之前的bin文件做一点说明:

可以看到我们的e59f1014在图1和图2上似乎顺序不同,一个是反的,一个正的。这是因为我们采取单板默认的小端模式进行的开发,小端模式,高位在高地址,地位在低地址。

所以只用把图1中第五列的0c改成0b即可,下载进入,观看现象。当然是被点亮了。

最后,再说明一点,这个更改机器码确实麻烦,我们已经过去了那个写机器码的年代,但是知道这些,总会有好处的,

上面的改写0x400是因为我刚好的写入的是一个立即数,要是例如0x123这样的非立即数数据,是不会反汇编mov指令的,下面测试:

反汇编:

通过这些学习,我们可以和cpu的距离变得更近。

新的开始——LED灯汇编机器码的点亮方式的更多相关文章

  1. 第7章 使用寄存器点亮LED灯

    第7章     使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  2. 第7章 使用寄存器点亮LED灯—零死角玩转STM32-F429系列

    第7章     使用寄存器点亮LED灯 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/fir ...

  3. 灵动微电子ARM Cortex M0 MM32F0010 GPIO 的配置驱动LED灯

    灵动微电子ARM Cortex M0 MM32F0010 GPIO的配置 目录: 1.前言 2.学习方法简要说明 3.要点提示 4.注意事项 5.MM32F0010系统时钟的配置 6.MM32F001 ...

  4. 30个物联网传感器小实验:三行代码点亮LED灯

    30个物联网传感器小实验:三行代码点亮LED灯 三行代码点亮LED灯 LED灯闪烁 LED灯调亮度 LED淡入淡出 不写一行代码点亮LED灯 全彩RGB灯 面包板 30个物联网传感器小实验:三行代码点 ...

  5. linux IMX6 汇编点亮一个LED灯

    驱动Linux引脚与驱动STM32其实是一样的,都是在操作寄存器,在相应的寄存器上附上相应的值即可驱动. IMX6U手册上有各个管脚的命名,跟STM32不同,IOMUXC_SW_MUC_CTL_PAD ...

  6. AT89S52汇编实现l通过按键中断切换led灯的四种闪烁模式(单灯左移,单灯右移,双灯左移,双灯右移)

    ;通过P1口控制8路LED的四种闪烁模式,单独LED灯左移,单独LED灯右移,相邻两个灯左移,相邻两个灯右移;通过一个外部中断0来检测按键的跳变沿来切换闪烁模式,第一次按键按下弹起,灯的闪烁状态由单独 ...

  7. 25个led灯新玩法

    Microbit板子的25个led灯,是5X5的阵列,led(lights emitting diodes)中文叫发光二极管,有单向导电性,还发光,有各种颜色的,红,蓝,黄等等.mPython可以让你 ...

  8. C语言版——点亮LED灯,深入到栈

    在上一篇进行了汇编语言的编写之后,我们采用C语言来编写程序,毕竟C语言才是我们使用最多的语言. 仅仅是点亮LED灯显然太过于简单,我们需要分析最后的反汇编,了解函数调用栈,深入C语言骨髓去分析代码,并 ...

  9. 起航,第一个程序——还是LED灯

    如同学基本语言一样,helloworld是很多语言的第一个程序.在嵌入式开发中,点亮LED灯也是各种架构和开发板的第一个程序,其中很多东西是和单片机例如stm32是类似的,只是,现在我们没有了库函数, ...

随机推荐

  1. DPDK的安装与绑定网卡(转)

    from:http://www.cnblogs.com/mylinuxer/p/4274178.html DPDK的安装与绑定网卡 DPDK的安装有两种方法: 第一种是使用dpdk/tools/set ...

  2. centos7 安装遇到的问题

    win7系统下安装centos7 1:首先是在U盘启动时候遇到的,Warning: /dev/root does not exist.没找到U盘的位置.这个问题两种方法,一种是去找到对应的设备名字 然 ...

  3. 【exe4j】如何利用exe4j把java桌面程序生成exe文件

    前言: 我们都知道Java可以将二进制程序打包成可执行jar文件,双击这个jar和双击exe效果是一样一样的,但感觉还是不同.其实将java程序打包成exe也需要这个可执行jar文件. 准备: ecl ...

  4. C#设计模式(6)——原型模式(Prototype Pattern) C# 深浅复制 MemberwiseClone

    C#设计模式(6)——原型模式(Prototype Pattern)   一.引言 在软件系统中,当创建一个类的实例的过程很昂贵或很复杂,并且我们需要创建多个这样类的实例时,如果我们用new操作符去创 ...

  5. EasyUI 中GridView 满足某条件 改变行的背景色

    <table id='grid' class='easyui-datagrid' style='width:1500px;height:450px' url='Ajax-index.php?mo ...

  6. Android Studio:正确导入SO相关文件

      导入so文件有2种方式 第一种: 使用jniLibs文件夹导入so文件,则仅需将所有cpu类型的文件夹拷进去. 在project结构下,module目录下创建libs文件夹,放入jar文件:在sr ...

  7. 【转】Markdown 的一些问题

    Markdown 的一些问题 把我之前的博文基本上转换成了 markdown 格式.我发现 markdown 虽然在编辑器里看起来比 HTML 清晰一些,但也有一些不足. 这些 markup 语言的格 ...

  8. 实现超级简单的bug管理系统

    大家可以试着去实现一个超级简单的bug管理系统 不需要鉴权,也就是不需要登陆 有tag管理功能,缺陷上可以加tag,通过tag区分bug的状态和类型 bug的增删改查功能 bug描述支持markdow ...

  9. mysql 5.5数据库主从配置步骤详解

    上次给大家介绍了mysql 5.1主从搭建配置教程,这次我们来实现mysql 5.5的主从复制,其实大体上配置是差不多的,只有点细微的差别. 系统:centos 5.x 需要的软件包:mysql-5. ...

  10. proguard的简单配置说明

    #需要转换的jar文件路径-injars 'D:\fs-np.jar'#转换后的jar文件名称-outjars 'D:\fs-np-sec.jar' #关联的第三方jar-libraryjars 'C ...