嵌入式学习:裸机开发_L1_汇编LED实验

裸机开发_L1_汇编LED实验

  • 0. 本节目标
  • 1. 硬件层电路
    • 1.1 使用正点原子 i.MX6ULL ALPHA V2.2 开发板
    • 1.2 飞凌i.MX6UL-C开发板
  • 2. 初识 i.MX6ULL 寄存器
    • 2.1 i.MX6ULL 时钟控制寄存器
    • 2.2 i.MX6ULL IO复用寄存器
    • 2.3 i.MX6ULL 电气属性寄存器
    • 2.4 i.MX6ULL GPIO控制寄存器
  • 3. ARM 汇编指令集简介
    • 3.1 处理器工作模式
    • 3.2 汇编语言基本格式
    • 3.3 伪指令指定“段”
    • 3.4 汇编程序入口
      • 3.4.1 默认入口标号 _start
      • 3.4.2 链接脚本 ENTRY
    • 3.5 ARM 9种寻址模式
      • 3.5.1 立即寻址
      • 3.5.2 寄存器寻址
      • 3.5.3 寄存器偏移寻址
      • 3.5.4 寄存器间接寻址
      • 3.5.5 基址寻址
      • 3.5.6 多寄存器寻址
      • 3.5.7 堆栈寻址
      • 3.5.8 块拷贝寻址
      • 3.5.9 相对寻址
    • 3.6 数据传输指令
      • 3.6.1 内部数据传输操作
      • 3.6.2 栈存储器相关的数据传输
      • 3.6.3 数据交换指令
      • 3.6.4 外部数据存储器指令
    • 3.7 算术运算指令
      • 3.7.1 加法与减法
      • 3.7.2 乘法与除法
      • 3.7.3 递增与递减
      • 3.7.4 十进制调整指令
    • 3.8 逻辑运算指令
    • 3.9 布尔运算指令
    • 3.10 程序控制转移指令
      • 3.10.1 无条件转移指令
      • 3.10.2 条件转移指令
  • 4. 内存映射
  • 5. 代码编写
    • 5.1 代码框图
    • 5.2 使用正点原子 i.MX6ULL ALPHA V2.2 开发板
      • 5.2.1 leds.S
      • 5.2.3 Makefile
    • 5.3 飞凌i.MX6UL-C开发板
      • 5.3.1 leds.S
      • 5.3.2 Makefile

0. 本节目标

  • 了解时钟控制寄存器
  • 了解复用配置寄存器
  • 了解电气属性寄存器
  • 了解GPIO控制相关寄存器

1. 硬件层电路

1.1 使用正点原子 i.MX6ULL ALPHA V2.2 开发板

查看底板原理图可知:

功能管脚 芯片引脚
LED0 GPIO3

嵌入式学习:裸机开发_L1_汇编LED实验_第1张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第2张图片

1.2 飞凌i.MX6UL-C开发板

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 初识 i.MX6ULL 寄存器

2.1 i.MX6ULL 时钟控制寄存器

嵌入式学习:裸机开发_L1_汇编LED实验_第3张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第4张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第5张图片

2.2 i.MX6ULL IO复用寄存器

嵌入式学习:裸机开发_L1_汇编LED实验_第6张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第7张图片

2.3 i.MX6ULL 电气属性寄存器

嵌入式学习:裸机开发_L1_汇编LED实验_第8张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第9张图片

在这里插入图片描述
在这里插入图片描述
嵌入式学习:裸机开发_L1_汇编LED实验_第10张图片
嵌入式学习:裸机开发_L1_汇编LED实验_第11张图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
嵌入式学习:裸机开发_L1_汇编LED实验_第12张图片
在这里插入图片描述
在这里插入图片描述

2.4 i.MX6ULL GPIO控制寄存器

嵌入式学习:裸机开发_L1_汇编LED实验_第13张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第14张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第15张图片
嵌入式学习:裸机开发_L1_汇编LED实验_第16张图片

3. ARM 汇编指令集简介

使用指令集:ARMv7-A 汇编指令集,32位,load/store架构。

大多数ARM处理器支持超过一种指令集:
 > ARM —— 一种32位指令集
 > Thumb —— 一种16位指令集,具有更好的代码密度(但是相比ARM代码,性能有所降低)
 
在程序的控制之下,处理器可以在这两种指令集之间来回切换。

所有的 Cortex-A 系列处理器实现了 Thumb-2 技术,它扩展了Thumb指令集。混合使用32位和16位指令,以Thumb指令集的代码密度和接近ARM指令集的性能。自从所有的Cortex-A系列处理器支持这一扩展,针对它们的软件常被编译成Thumb指令集。

3.1 处理器工作模式

嵌入式学习:裸机开发_L1_汇编LED实验_第17张图片

嵌入式学习:裸机开发_L1_汇编LED实验_第18张图片

3.2 汇编语言基本格式

label: instruction @ comment
说明 备注
label 标号 可不写
instruction 指令 必须写
@ comment 注释 可不写

GNU汇编语言,函数定义

函数名:
	函数体
	返回语句

3.3 伪指令指定“段”

预定义段名 含义
.text 代码段
.data 初始化的数据段
.bss 未初始化的数据段
.rodata 只读数据段

3.4 汇编程序入口

3.4.1 默认入口标号 _start

.global _start

_start:
	ldr r0, =0x12 @ r0=0x12

3.4.2 链接脚本 ENTRY

3.5 ARM 9种寻址模式

3.5.1 立即寻址

操作数是立即数,以“#”为前缀,表示 16 进制数值时以“0x”表示。

例:

MOV R0, #0xFF00 @ 0xFF00 ->  R0
SUBS R0, R0, #1 @ R0 – 1 ->  R0

3.5.2 寄存器寻址

操作数的值在寄存器中,指令执行时直接取出寄存器值操作。
例:

MOV R1, R2 @ R2 -> R1
SUB R0, R1, R2 @ R1 - R2 -> R0

3.5.3 寄存器偏移寻址

当第二操作数是寄存器偏移方式时,第二个寄存器操作数在与第一个操作数结合之前,选择进行移位操作。

例:

MOV R0, R2, LSL #3 @ R2 的值左移 3 位,结果放入 R0,即 R0 = R2 * 8
ANDS R1, R1, R2, LSL #3 @ R2 的值左移 3 位,然后和 R1 相与操作,结果放入 R1

可采用的移位操作:

指令 解释 补充说明
LSL 逻辑左移(Logical Shift Left) 低端空出位补 0
LSR 逻辑右移(Logical Shift Right) 高端空出位补 0
ASR 算术右移(Arithmetic Shift Right) 移位过程中符号位不变,即源操作数为正数,则高端空出位补 0,否则补 1
ROR 循环右移(Rotate Right) 由低端移出位填入高端空出位
RRX 带扩展的循环右移(Rotate Right eXtended by 1 place) 操作数右移一位,高端空出位用原 C 标志值填充。

3.5.4 寄存器间接寻址

操作数保存在寄存器指定地址的存储单元中,即寄存器为操作数的地址指针。

例:

LDR R1, [R2] @ 将 R2 中的数值作为地址,取出此地址中的数据保存在 R1 中
SWP R1, R1, [R2] @ 将R2中的数值作为地址,取出此地址中的数值与 R1 中的值**

3.5.5 基址寻址

将基址寄存器的值与偏移量相加,形成操作数的有效地址,基址寻址用于访问基址附近的存储单元,常用于查表、数组操作、功能寄存器访问等。

例:

LDR R2, [R3,#0x0F] @ 将R3中的数值加 0x0F 作为地址,取此地址的值保存在 R2 中
STR R1, [R0,#-2] @ 将R0中的数值减 2 作为地址,把 R1的值保存到此地址中

3.5.6 多寄存器寻址

一次传送多个寄存器值,允许一条指令传送 16 个寄存器的任何子集或所有寄存器。多寄存器寻址时,寄存器子集按由小到大的顺序排列,连续的寄存器可用“-”连接,否则,用“,”分隔书写。

例:

LDMIA R1!, {R2-R7,R12} @ 将 R1的值读出到 R2-R7,R12,过程中R1 自动加 1
STMIA R0!, {R3-R6,R10} @ 将 R3-R6,R10的值保存到 R0 指向的地址,过程中R0 自动加 1

3.5.7 堆栈寻址

堆栈寻址使用堆栈指针SP,即R13,指向堆栈的栈顶。堆栈可分为两种:

向上生长:向高地址方向生长,称为递增堆栈,

向下生长:向低地址方向生长,称为递减堆栈,

堆栈指针指向最后压入的有效数据项,称为满堆栈,

堆栈指针指向下一个要放入的空位置,称为空堆栈,这样就有 4 种类型的堆栈。

A) 满递增:堆栈地址向上增长,堆栈指针指向有效数据的最高地址。如 LDMFA,STMFA。

B) 空递增:堆栈地址向上增长,堆栈指针指向堆栈上的第一个空位置。如 LDMEA,STMEA 。

C) 满递减:堆栈地址向下增长,堆栈指针指向有效数据项的最低地址。如 LDMFD,STMFD。

D) 空递减:堆栈地址向下增长,堆栈指针指向堆栈下的第一个空位置。如 LDMED,STMED 。

例:

STMFD SP!, {R1-R7,LR} @ 将 R1~R7,LR 入栈。满递减堆栈。
LDMFD SP!, {R1-R7,LR} @ 数据出栈,放入 R1~R7,LR 寄存器。满递减堆栈。

3.5.8 块拷贝寻址

用于将一块数据从存储器的某一位置拷贝到另一位置。

例:

STMIA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向上增长。

STMIB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向上增长。

STMDA R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之后增加,增长方向为向下增长。

STMDB R0!,{R1-R7} ;将R1~R7的数据保存到存储器中,存储器指针在保存第一个值之前增加,增长方向为向下增长。

3.5.9 相对寻址

相对寻址是基址寻址的一种变通,由程序计数器 PC 提供基准地址,指令中的地址

码字段作为偏移量,两者相加后得到有效地址。

例:

BL ROUTE1 @ 调用ROUTE1 子程序
BEQ LOOP @ 条件跳转到 LOOP 标号处
…
LOOP  MOV R2,#2
…
ROUTE1
…

3.6 数据传输指令

3.6.1 内部数据传输操作

3.6.2 栈存储器相关的数据传输

3.6.3 数据交换指令

3.6.4 外部数据存储器指令

3.7 算术运算指令

3.7.1 加法与减法

3.7.2 乘法与除法

3.7.3 递增与递减

3.7.4 十进制调整指令

3.8 逻辑运算指令

3.9 布尔运算指令

3.10 程序控制转移指令

3.10.1 无条件转移指令

3.10.2 条件转移指令

4. 内存映射

0x8000_0000 提供2G空间,用于16位 DDR内存。
MMDC——multiple model DDR controller,多模式DDR控制器。
嵌入式学习:裸机开发_L1_汇编LED实验_第19张图片

0x0200_0000, AIPS-1, ARM IP Bus,

5. 代码编写

5.1 代码框图

1
开启外设时钟
引脚复用功能配置
引脚电气属性配置
GPIO特性配置
loop

5.2 使用正点原子 i.MX6ULL ALPHA V2.2 开发板

5.2.1 leds.S

/**
@brief 实现点亮led功能,led——GPIO1_IO03
@note  要学习的寄存器: CCM_CCGR0 ~ CCM_CCGR6

*/
.global _start

_start:
    
    /** 
    开启时钟:CCM_CCGR0
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4068
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR0
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4068
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR1
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C406C
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR2
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4070
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR3
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4074
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR4
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4078
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR5
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C407C
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR6
    i.MX6ULL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4080
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /**
    配置复用寄存器:IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03
                低四位:MUX_MODE[3:0] = ALT5(0101) —— GPIO1_IO03
    */
    ldr r0, =0x020E0068
    ldr r1, =0x5
    str r1, [r0]

    /**
    配置电气属性寄存器:IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
                SRE[0] 压摆率,0 —— 低压摆率
                Reserved[2:1]
                DSE[5:3] 驱动能力,110 —— R0/6
                SPEED[7:6] 速度,10 —— 100MHz
                Reserved[10:8]
                ODE[11] 开漏输出,0 —— 关闭开漏输出
                PKE[12] 上拉/保持使能位,1 —— 使能上拉/保持控制
                PUE[13] 上拉/保持选择,0 —— 保持
                PUS[15:14] 上拉/下拉电阻, 00 —— 100K欧姆下拉;10 —— 100K欧姆上拉
                HYS[16] 施密特触发器使能位,0 —— 不使能
                Reserved[31:17]
    */
    ldr r0, =0x020E02F4
    ldr r1, =0x10B0
    str r1, [r0]

    /** 
    配置GPIO方向:GPIO1_GDIR
            0 —— 输入 1 —— 输出
    */
    ldr r0, =0x0209C004
    ldr r1, =1<<3
    str r1, [r0]

    /** 
    配置GPIO数据:GPIO1_DR
            0 —— 低电平 1 —— 高电平
    */
    ldr r0, =0x0209C000
    ldr r1, =0<<3
    str r1, [r0]

loop:
    b loop

5.2.3 Makefile

led.bin : leds.s
	arm-linux-gnueabihf-gcc -g -c leds.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 :
	rm -rf *.o led.elf led.bin led.dis

5.3 飞凌i.MX6UL-C开发板

5.3.1 leds.S

/**
@brief 实现点亮led功能,led——GPIO1_IO09
@note  要学习的寄存器: CCM_CCGR0 ~ CCM_CCGR6

*/
.global _start

_start:
    /** 
    开启时钟:CCM_CCGR0
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4068
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR1
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C406C
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR2
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4070
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR3
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4074
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR4
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4078
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR5
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C407C
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /** 
    开启时钟:CCM_CCGR6
    i.MX6UL参考手册:第18章(CCM)
    */
    ldr r0, =0x020C4080
    ldr r1, =0xFFFFFFFF
    str r1, [r0]

    /**
    配置复用寄存器:IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO09
                低四位:MUX_MODE[3:0] = ALT5(0101) —— GPIO1_IO09
    */
    ldr r0, =0x020E0080
    ldr r1, =0x5
    str r1, [r0]

    /**
    配置电气属性寄存器:IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO09
                SRE[0] 压摆率,0 —— 低压摆率
                Reserved[2:1]
                DSE[5:3] 驱动能力,110 —— R0/6
                SPEED[7:6] 速度,10 —— 100MHz
                Reserved[10:8]
                ODE[11] 开漏输出,0 —— 关闭开漏输出
                PKE[12] 上拉/保持使能位,1 —— 使能上拉/保持控制
                PUE[13] 上拉/保持选择,0 —— 保持
                PUS[15:14] 上拉/下拉电阻, 00 —— 100K欧姆下拉;10 —— 100K欧姆上拉
                HYS[16] 施密特触发器使能位,0 —— 不使能
                Reserved[31:17]
    */
    ldr r0, =0x020E030C
    ldr r1, =0x10B0
    str r1, [r0]

    /** 
    配置GPIO方向:GPIO1_GDIR
            0 —— 输入 1 —— 输出
    */
    ldr r0, =0x0209C004
    ldr r1, =1<<9
    str r1, [r0]

    /** 
    配置GPIO数据:GPIO1_DR
            0 —— 低电平 1 —— 高电平
    */
    ldr r0, =0x0209C000
    ldr r1, =0<<9
    str r1, [r0]

    /**
    配置复用寄存器:IOMUXC_SW_MUX_CTL_PAD_SNVS_TAMPER9
                低四位:MUX_MODE[3:0] = ALT5(0101) —— GPIO1_IO09
    */
    ldr r0, =0x020E0080
    ldr r1, =0x5
    str r1, [r0]

    /**
    配置电气属性寄存器:IOMUXC_SW_PAD_CTL_PAD_SNVS_TAMPER9
                SRE[0] 压摆率,0 —— 低压摆率
                Reserved[2:1]
                DSE[5:3] 驱动能力,110 —— R0/6
                SPEED[7:6] 速度,10 —— 100MHz
                Reserved[10:8]
                ODE[11] 开漏输出,0 —— 关闭开漏输出
                PKE[12] 上拉/保持使能位,1 —— 使能上拉/保持控制
                PUE[13] 上拉/保持选择,0 —— 保持
                PUS[15:14] 上拉/下拉电阻, 00 —— 100K欧姆下拉;10 —— 100K欧姆上拉
                HYS[16] 施密特触发器使能位,0 —— 不使能
                Reserved[31:17]
    */
    ldr r0, =0x020E02CC
    ldr r1, =0x10B0
    str r1, [r0]

    /** 
    配置GPIO方向:GPIO5_GDIR
            0 —— 输入 1 —— 输出
    */
    ldr r0, =0x020AC004
    ldr r1, =1<<9
    str r1, [r0]

    /** 
    配置GPIO数据:GPIO5_DR
            0 —— 低电平 1 —— 高电平
    */
    ldr r0, =0x020AC000
    ldr r1, =0<<9
    str r1, [r0]

loop:
    b loop

5.3.2 Makefile

leds.bin : leds.S
	arm-linux-gnueabihf-gcc -g -c $< -o leds.o
	arm-linux-gnueabihf-ld -Ttext 0x87800000 leds.o -o leds.elf
	arm-linux-gnueabihf-objcopy -O binary -S -g leds.elf $@
	arm-linux-gnueabihf-objdump -D leds.elf > leds.dis

clean :
	rm -rf *.o leds.elf leds.bin leds.dis

你可能感兴趣的:(嵌入式学习:裸机开发_L1_汇编LED实验)