【ARM自学笔记】裸机汇编语言点灯

储备知识(部分)

GNU:

GNU编译器套装,指一套编程语言编译器,以GPL及LGPL许可证所发行的自由软件,也是GNU计划的关键部分,也是GNU工具链的主要组成部分之一。GCC(特别是其中的C语言编译器)也常被认为是跨平台编译器的事实标准。1985年由理查德·马修·斯托曼开始发展,现在由自由软件基金会负责维护工作。

原名为GNU C语言编译器(GNU CCompiler),因为它原本只能处理C语言。GCC在发布后很快地得到扩展,变得可处理C++。之后也变得可处理Fortran、Pascal、Objective-C、Java、Ada,Go与其他语言。许多操作系统,包括许多类Unix系统,如Linux及BSD家族都采用GCC作为标准编译器。

GCC原本用C开发,后来因为LLVM、Clang的崛起,它更快地将开发语言转换为 C++ 。许多C的爱好者在对 C++ 一知半解的情况下主观认定 C++ 的性能一定会输给C,但是Ian Lance Taylor给出了不同的意见,并表明C++不但性能不输给C,而且能设计出更好,更容易维护的程序。

基本语句:

label: instuction @ comment
  • label 标号,表示地址位置,有些指令前面可能会有标号,这样就可以通过这个标号得到指令的地址,标号也可以用来表示数据地址。注意 label 后面的“:”,任何以“:”结尾的标识符都会被识别为一个标号。
  • instruction 指令,汇编指令或伪指令
  • @ 符号,表示后边的是注释
  • comment 是注释内容

指令、伪指令、伪操作等不能大小写混用

eg:

    add:
        MOVS R0,#0X12 @设置 R0 = 0X12

伪操作:
系统预定段名:

  • .text 代码段
  • .data 初始化的数据段
  • .bss 未初始化的数据段
  • .rodata 只读数据段

也可以使用.section伪操作来定义一个段

.section .testsection @定义一个 testsetcion 段

函数

函数名:
    函数体
    返回语句(非必须)

Cortex-A7 常用汇编指令

常用的指令有三个: MOV、MRS和MSR

指令 目的 描述
MOV R0 R1 将R1里面的数据复制到R0种
MRS R0 CPSR 将特殊寄存器CPSR里面的数据复制到R0里
MSR CPSR R1 将R1里面的数据复制到特殊寄存器CPSR里

储存器访问指令

ARM不能直接访问储存器 一般先将要配置的值写入到 Rx(x=0~12)寄存器中,然后借助存储器访问指令将 Rx 中的数据写入到ARM寄存器种。取出过程则相反。

指令 描述
LDR Rd,[Rn,#offset] 从存储器Rn+offset的位置读取数据存放到Rd中
STR Rd,[Rn,#offset] 将Rd中的数据写入到存储器中的Rn+offset位置

原理分析

原理图如下:
【ARM自学笔记】裸机汇编语言点灯_第1张图片
【ARM自学笔记】裸机汇编语言点灯_第2张图片

只要把GPIO 3的输出电平拉低就可以亮。

流程

  1. 使能GPIO1时钟
    将CCM_CCGR1的bit27、bit26两个控制位都置11。
  2. 设置GPIO1_IO03的服用功能。
    复用寄存器“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03”的地址为0X020E0068,设置此寄存器,将GPIO1_IO03这个IO复用为GPIO功能
  3. 配置GPIO1_IO03
    配置寄存器“IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03”
  4. 设置GPIO
    配置GPIO的工作模式
  5. 控制GPIO的输出电平
    (寄存器具体配置参考数据手册)

编写代码

在Ubuntu系统下进行编写(不用再从Windows传到Linux上)

/*
 * 裸机汇编电灯
 */

 .global _start

 // 从此函数开始执行此函数完成时钟使能、初始化等

 _start:

 // 1.使能所有时钟
 ldr r0, =0x020c4068
 ldr r1, =0xFFFFFFFF
 str r1, [r0]

 ldr r0, =0x020c406c
 str r1, [r0]

 ldr r0, =0x020c4070
 str r1, [r0]

 ldr r0, =0x020c4074
 str r1, [r0]

 ldr r0, =0x020c4078
 str r1, [r0]

 ldr r0, =0x020c407c
 str r1, [r0]

 ldr r0, =0x020c4080
 str r1, [r0]

 // 2.设置复用为GPIO1_IO03
 ldr r0, =0x02E0068
 ldr r1, =0x5
 str r1,[r0]

 // 3. 配置IO的属性
ldr r0, =0x020E02F4
ldr r1, =0x10B0
str r1, [r0]

// 4. 设置为输出
ldr r0, =0x0209C004
ldr r1, =0x0000008
str r1, [r0]

// 5. 打开LED0
ldr r0, =0x0209C000
ldr r1, =0
str r1, [r0]

// 死循环
loop:
    b loop
    

编译代码

  1. 编译文件

使用交叉编译器将 .s文件编译为 .o文件。命令如下:

arm-linux-gnueabihf-gcc -g -c led.s -o led.o
  1. 链接文件
    将工程所需的全部.o文件与地址链接起来生产 .elf文件。命令如下:
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
  1. 格式转换
    因为最终要烧录的文件格式为.bin文件(二进制文件),所以需要进行转换。 命令如下:
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
  1. 反汇编(检验)
    检查上述过程是否正确。命令如下:
arm-linux-gnueabihf-objdump -D led.elf > led.dis

当文件多时可以通过make进行完成上述过程。
在工程目录下创建“Makefile”文件,并写入代码:

led.bin:led.s
    arm-linux-gnueabihf-gcc -g -c led.s -o led.o
    arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
    arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
    arm-linux-gnueabihf-objdump -D led.elf > led.dis
clean:

代码烧写(SD卡烧录启动)

采用imxdownload进行下载SD卡。
其中遇到这样一个问题:
当正常读卡器插入电脑时, /dev/ sd* 文件中应该含有 /dev/sdd , /dev/sdd1。
然而,我的读卡器插上去却多了 /dev/sdb /dev/sdb1
sda是系统的第一块磁盘空间,sdb是第二块,sdb1是第二块磁盘的第一分区,也就是Ubuntu将读卡器当作一个磁盘或者说是U盘。
但这个并不影响往SD卡里写入数据,大概率是读卡器的问题。

结果

【ARM自学笔记】裸机汇编语言点灯_第3张图片

你可能感兴趣的:(ARM,arma,嵌入式,linux)