led汇编点灯
1. 汇编LED原理
为什么使用Cortex-A汇编
- 使用汇编初始化soc外设
- 使用汇编初始化DDR,I.MX不需要,因为它内部的96k ROM中存放了自己编写的启动代码,这些代码可以读取DDR配置信息
- 设置sp指针,一般指向ddr,设置好C语言的运行环境
Alpah开发板原理硬件分析

LED0为低电平,DS0就会亮,再看一下LED0接到哪里

由图可知,LED0接到GPIO 3,可以查找参考手册了
2. 初始化流程
stm32初始化流程
- 使能GPIO时钟
- 设置复用,但是32的LED灯默认就是GPIO的功能
- 配置GPIO的电气属性
- 使用GPIO,输出高低电平
I.MX6ULL初始化流程
- 首先找到时钟控制模块CCM

这七个寄存器控制6ULL所有时钟外设使能

可以看到11就是任何模式下都使能,除了STOP
可以把这七个时钟都使能一遍(0xFFFFFFFF)(32位)
- MUX复用,首先找到GPIO1_IO3的复用

看一下前四位,是复用为什么管脚

由图中可以看到,需要设为GPIO的是0101
- PAD电气属性

- SRE(0):压摆率,0为低压摆率,1为高压摆率。压摆率是指电平跳变所需时间。时间越小波形越抖,压摆率过高。如果你使用的产品要过EMC(电磁兼容性,定义为设备和系统在其电磁环境中能正常工作且不对环境中任何事物构成不能承受的电磁骚扰的能力)的话就要使用低压摆率,如果要是高速通信就是高压摆率。
- 1-2:保留,没用
- DSE(3-5) : 当IO用作输出的时候用来设置IO的驱动能力,001是R0,3.3V下R0是260欧姆,1.8v是150欧姆,DDR是240欧姆, 010电阻减半,以后会越来越小,电阻越来越小,驱动能力越来越强。内阻小,那分压就会小,这样外部负载的分压就会大,外部负载的电阻就会大,这样选择性比较好,又可以大又可以小。
- SPEED(6.7) : 速度,没什么可说的
- 8-10: 没用
- ODE : 开路输出,1开启0关闭
- PKE : 用来使能禁止上下拉保持
- PUE : 0保持,1上下拉
- PUS (14.15): 上下拉配置
- HYS :电气属性寄存器
- 配置GPIO功能,设置输入输出

都是32位,每一个位代表一个GPIO的输入输出
- DR:可以向DR的指定bit来实现高低电平
- GDIR:控制设置GPIO是输入还是输出
- PSR:只读状态寄存器
- ICR1:中断,设置中断的触发电平,低电平,高电平,上升沿下降沿
- ICR2:中断,因为是两个位控制一个GPIO,所以两个ICR
- IMR:中断掩码,通过它控制中断的使能关闭
- ISR:中断状态寄存器,判断GPIO对应的中断有没有发生
综上,对于点灯,就是GDIR的bit3设置为输出模式,DR控制高低电平。
3. ARM汇编基础
作用:
- 恢复现场保护现场sp指针
- 初始化DDR寄存器
我们使用的GCC交叉编译器,汇编需要符合GNU语法,GNU汇编语法适用于所有的架构,每条语句有三个可选地方:
label: instruction @ comment
label即标号,表示地址位置,有些指令前面可能会有标号,标号也可以用来表示数据地址,后面以:结尾。任何以:结尾的标志符都是一个标号
instruction是指令,也就是汇编指令或者伪指令
@标号,表示后面的是注释,comment是注释内容。
比如:
add:
MOVS R0,#0X12 @设置R0 = 0X12
add就是标号,下面就是指令和注释
会变系统预定义了一些段名:
- .text代码段
- .data初始化的数据段
- .bss未初始化的数据段
- .rodata只读数据段
我们也可以自己使用.section来定义一个段,每个段以段名开始,以下一段名或者文件结尾结束
.section .testsection @定义一个testsection段
汇编程序的默认入口标号是_start,也可以在链接脚本中ENTRY来指明入口点,比如
.global _start
_start:
ldr r0,=0x12 @r0 = 0x12
.global是伪操作,表示_start是一个全局标号,类似于C语言里面的全局变量一样,常见的伪操作有:
- .byte 定义单字节数据,比如 .byte 0x12
- .short 定义双字节数据, 比如 .short 0x1234
- .long 四字节 .long 0x12345678
- .equ 赋值语句,.equ num,0x12 等于 num = 0x12
- .align 数据字节对齐, 比如 .align 4字节对齐
- .end 表示源文件结束
- .global 定义一个全局标号
GNU也支持函数:
函数名称:
函数体
返回语句
例如:
/*未定义中断*/
Undefined_Handler:
ldr r0,=Undefined_Handler
bx r0 @返回指令
/*SVC*/
SVC_Handler:
ldr r0,=SVC_Handler
bx r0
3.1 处理器内部数据传输指令
常见的操作有:
- 将数据从一个寄存器传递到另一个寄存器
- 将数据从一个寄存器传递到特殊寄存器,如CPSR和SPSR
- 将立即数传递到寄存器
MOV指令
将R1里面的数据复制到R0中,或者一个立即数(常数)复制到R0中
MOV R0 R1
MOV R0 #0x12 @立即数前面加一个#
MRS指令
用于将特殊寄存器(如CPSR和SPSR)中的数据传递到通用寄存器,即要读取通用寄存器里面的数据必须用MRS
MRS R0,CPSR @将CPSR里面的数据读取到R0中
MSR指令
用于将通用寄存器的数据传递给特殊寄存器(如CPSR和SPSR)
MSR CPSR,R0 @将CPSR里面的数据读取到R0中
3.2 存储器访问指令
ARM中不能直接访问存储器,比如RAM中的数据,我们用汇编来配置寄存器的时候需要借助存储器访问指令,一般先写到通用寄存器中,然后借助存储器访问指令将通用寄存器中的数据写入到寄存器中,读取寄存器也是一样。
LDR
LDR主要用于存储加载数据到寄存器Rx中,LDR也可以将一个立即数加载到寄存器Rx中, LDR加载立即数的时候要用等于不是#
LDR R0, =0x0209C004 @将存储器地址加载到R0中,即R0 = 0x0209C004
LDR R1, [R0] @读取地址的数据到R1中
STR
LDR是从存储器读取数据,STR是将数据写入存储器中。
LDR R0, =0x0209C004
LDR R1, =0x20000002 @R1 = 0x20000002
STR R1, [R0] @将R1中的值写入到R0保存的地址中
如果按照字节半字就在后面加上B或者H
例子 a = b, a的地址为0x20, b为0x30
LDR R0, =0x30
LDR R1, [R0]
LDR R0, =0x20
STR R1, [R0]
3.3 压栈和出栈指令
通常在A函数中调用B函数,当B函数执行完之后继续A,所以需要保存现场和恢复现场,现场就是寄存器的值,用到POP和PUSH,可以一次性操作多个存储器,他们利用当前的栈指针来生成地址
如果当前SP指针指向0x80000000
PUSH {R0~R3, R12}
此时SP就是原来-4*5 0x7FFFFFEC。
出栈也是从栈顶出栈,原理类似。
也可以使用STMFD SP!和LDMFD SP!代替上面的指令。
STM和LDM对应STR和LDR,就是多寄存器的,多个连续数据。
FD是满递减的意思。 地址是向下增长的,编号小对应低地址,编号大对应高地址。
3.4 跳转指令
- 直接使用跳转指令B,BL,BX等
- 直接向PC寄存器里面写入数据
B
最简单的跳转指令,B指令会将PC寄存器的值设置为跳转目标地址,一旦执行B指令,ARM就会立即跳转到指定的目标地址。如果调用的函数不会再返回到原来执行地方,可以用B指令
_start:
ldr sp,=0x80200000
b main
常用的初始化C语言环境
BL
BL在跳转之前会在寄存器LR中保存当前PC的值,所以可以通过将LR的值重新加载到PC寄存器中来恢复现场,即保护现场,跳转到C中处理中断,再恢复现场。
push {r0, r1}
cps #0x13 @进入SVC模式,允许其他中断再次进去
bl system_irqhandler @加载函数到r2中
cps #0x12 @进入IRQ模式
pop {r0, r1}
str r0,[r1, #0x10] @写EDIR
3.5 其他运算
算数运算

逻辑运算

4. Cortex-A内核寄存器组
除了R0到R14,还有R15(PC)程序计数器,CPSR当前状态寄存器和SPSR备用状态寄存器。R13是sp,R14是LR寄存器。

LR寄存器
恢复现场:
MOV PC, LR @将LR保存的值传递给PC
或者:
PUSH {LR} @压栈
POP {PC} @弹栈,并将值赋给PC
当异常发生以后,该异常模式对应的 R14 寄存器被设置成该异常模式将要返回的地址,R14 也可以当作普通寄存器使用。
程序计数器PC
pc = 当前执行位置+8个字节
解释一下:

5. 汇编代码
.global _start
_start:
@ 使能所有时钟
@ CCM_CCGR0的内存地址为20C_4068
ldr r0,=0x020c4068 @取得时钟0的地址
ldr r1,=0xffffffff @要赋的值
str r1, [r0] @赋值
ldr r0,=0x020c406c @取得时钟1的地址
@或者 add r0, r0, #0x04
str r1, [r0] @赋值
ldr r0,=0x020c4070 @取得时钟2的地址
str r1, [r0] @赋值
ldr r0,=0x020c4074 @取得时钟3的地址
str r1, [r0] @赋值
ldr r0,=0x020c4078 @取得时钟4的地址
str r1, [r0] @赋值
ldr r0,=0x020c407c @取得时钟5的地址
str r1, [r0] @赋值
ldr r0,=0x020c4080 @取得时钟6的地址
str r1, [r0] @赋值
/* 配置IO复用 */ @ ctrl+shift+A
ldr r0,=0x020e0068 @MUX复用地址
ldr r1,=0x5 @要赋的值,16进制,0101是二进制
str r1, [r0] @赋值
/* 电气属性
* bit0 : 0 低速率
* bit5-3 : 110 R0/6驱动能力
* bit7-6 : 10 100MHz速度
* bit11 : 0 关闭开路输出
* bit12 : 1 使能上拉保持
* bit13 : 0 保持
* bit15-14 : 00 默认100K下拉
* bit16 : 0 关闭hys
* 综上:
* 0000_0000_0000_0000_0001_0000_1011_0000
* 0x000010C0
*/
ldr r0,=0x020e02f4 @电气属性地址
ldr r1,=0x10b0
str r1, [r0]
/* 设置GPIO */
@ GPIO1_GDIR的bit3
ldr r0,=0x0209c004 @GDIR
ldr r1,=0x8 @8是1000, 输入输出设置
str r1, [r0]
/* 打开LED GPIO1_IO03为0 */
ldr r0,=0x0209c000 @DR
ldr r1,=0xfffffff7 @默认全是1,要配成0
str r1, [r0]
/* 程序执行到这的时候,不知道会有什么事情,所以要有个死循环 */
loop:
b loop
6. 编译程序
使用arm-linux-gnueabihf-gcc把所有的.s文件编译成点o
arm-linux-gnueabihf-gcc -g -c led.s -o led.o
-g产生调试信息,
-c是选择编译源文件,并且不链接
使用arm-linux-gnueabihf-ld将所有的.o文件链接为elf格式的可执行文件
把所有的o链接到一起,要有起始位置。本实验链接的时候要链接起始地址,链接起始地址就是代码运行的起始地址,或者保存的起始地址(一定是运行的,一般运行的和保存的是一个地址)
对于6ULL,链接起始地址应该指向RAM地址。
RAM分为内部RAM和外部RAM,DDR。内部为0x90000-0x91FFFFF,外部DDR中, 对于开发板0x80000000-0xA0000000(512MB)。
起始地址为0x8780000,后面UBOOT也是这个,所以要统一起来。要使用DDR必须要初始化DDR,bin文件不能直接烧写到mmc等外置存储中启动运行,需要添加一个头部,头部包含了DDR初始化参数。bootrom会从SD卡,EMMC等外置存储中读取头部信息,初始化DDr,并且将bin拷贝到链接起始地址,bin的运行地址一定要和链接起始地址一致。位置无关代码除外。
arm-linux-gnueabihf-ld -Ttext 0x87800000 led.o -o led.elf
- -Ttext指定链接起始地址
使用arm-linux-gnueabihf-objcopy将elf文件转化为bin文件
arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
- -O 以什么形式输出
- -S 表示不要复制源文件的重定位信息和符号信息
- -g 不要复制源文件的调试信息
使用arm-linux-gnueabihf-objdump elf转为汇编,反汇编
arm-linux-gnueabihf-objdump -D led.elf > led.dis
- -D表示反汇编所有的段
7. 烧写
将bin文件烧写到mmc中。
在Ubuntu下烧写SD卡:

插入U盘链接

将bin文件烧写到SD卡绝对地址上,对于I.MX而言必须在bin文件添加头部,使用imxdownload

两次插拔可知

烧在sdb1上
先给imx可执行权限

烧写成功

添加了头部的.bin文件就是load.imx
8.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:
rm -rf *.o *.bin *.elf *.dis
9.download.sh
chmod 777 imxdownload
./imxdownload led.bin /dev/sdb
led汇编点灯的更多相关文章
- 5.汇编实现裸机LED
首先:操作LED就要操作GPIO alpha的芯片是NXP的IMX6ULL 其GPIO和STM32的命名有所区别 可以看到IMX6ULL的GPIO以其功能进行命名,对应上图中PAD之后的部分 即G ...
- 嵌入式linux——点亮led灯(二)
刚才在jz2440板子上写了一个点亮中间led的程序,前前后后十几分钟才好.最终代码 本节内容: 1. 汇编点灯 2. C点灯 3. 参数选择点灯 4. 按键点灯 1. 汇编点灯 .text .glo ...
- Part10-C语言环境初始化-一跃进入C大门lesson3
1.跳转到c代码 因为内存中的代码来自于垫脚石SRAM,他们是相同的. 采用绝对跳转方式来完成. 因为我们是从汇编代码跳转到c语言的程序,所以我们要提前准备一个main.c文件. 修改makefile ...
- 002_linux之点灯(汇编深度解析)
1. 开发板采用韦山东的开发板 2. 芯片CPU三星S3C2440A 3. 控制引脚:GPF4 4. linux操作系统 5. 芯片手册下载地址:https://eyun.ba ...
- u-boot移植总结(二)LED点灯调试 和 u-boot加载地址
(一)LED点灯调试 FL2440电路总共有4个LED0,LED1,LED2,LED3,分别接到板子GPB5,GPB6,GPB8,GPB10引脚.通过设置三个寄存器GPBCON(0x56000010) ...
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]
从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...
- ARM入门实践(一)----Mini6410上最简单的LED点灯裸机程序
Mini6410上最简单的LED点灯裸机程序 : 实验环境: 根据友善教程,要用ADS,据说现在都不用这个了,但是为了打开友善给的mcp工程,就下了一个,Win7下弄上兼容模式和管理员权限,再下一个S ...
- 四、使用汇编编写LED裸机驱动
1. 确定硬件连接 打开OK6410底板电路图,找到LED,可以发现NLEDx为0时LED点亮. 找到LED的控制引脚,发现LED控制引脚通过连接器连到了核心板: 打开核心板电路图,找到对应的连接器中 ...
- 新的开始——LED灯汇编机器码的点亮方式
在几个月前看2440视频的时候,发现太多知识欠缺,购买开发板期间补习makefile,linux,arm汇编和arm构架之后,现在重新开始学习. 先看板子LED硬件连接图: 可以看到LED 1,2,4 ...
随机推荐
- bzoj3073Journeys(线段树优化最短路)
这里还是一道涉及到区间连边的问题. 如果暴力去做,那么就会爆炸 那么这时候就需要线段树来优化了. 因为是双向边 所以需要两颗线段树来分别对应入边和出边 QwQ然后做就好了咯 不过需要注意的是,这个边数 ...
- 关于SSTI的坑
SSTI注入 进过几天的CSDN和博客园以及个人博客的查询,我大概讲一下我对SSTI模板注入的理解. SSTI注入指的是模板注入(应该翻译就是模板注入) 就站在我所了解的知识水平(大概就是大一随便水了 ...
- 苹果的最新MacbookPro,炸到你了么?
一 苹果秋季发布会如期而至.我不是一个标准的果粉.但是我今年用上了macbook pro m1,最期待的就是新款的搭载了M1X的Macbook. 苹果官方也放出了要炸翻全场的宣传语... 这次发布会围 ...
- python编写学习助手0
项目原因 为了解决学习知识后不及时复习而导致遗忘的问题,准备写一个桌面助手,采用艾宾浩斯记忆法,对每次学习的内容排布复习计划. 第一步是做出最简单的文本列表,里面是待办事项,每个复习待办事项都会有符合 ...
- iNeuOS工业互联网操作系统,智慧用电测控应用案例
目 录 1. 概述... 2 2. 系统部署结构... 2 3. 用电测控终端... 3 4. 系统应用介绍... 6 1. 概述 通过物联网技 ...
- 『学了就忘』Linux基础 — 3、CentOS镜像下载
下载CentOS镜像可以从官网下载:https://www.centos.org/download/. 也可以从国内的镜像网站下载. 阿里云:https://mirrors.aliyun.com/ce ...
- 2021.9.14考试总结[NOIP模拟53]
T1 ZYB和售货机 容易发现把每个物品都买成$1$是没有影响的. 然后考虑最后一个物品的方案,如果从$f_i$向$i$连边,发现每个点有一个出度多个入度,可以先默认每个物品都能买且最大获利,这样可以 ...
- [CSP-S2021] 回文
链接: P7915 题意: 给出一个长度为 \(2n\) 的序列 \(a\),其中 \(1\sim n\) 每个数出现了 2 次.有 L,R 两种操作分别是将 \(a\) 的开头或末尾元素加入到初始为 ...
- IM服务器:我的千万级在线聊天服务器集群
一.服务器特点 01.傻瓜式部署,一键式启动: 02.单机支持10万以上在线用户聊天(8G内存,如果内存足够大,并发量可超过10万): 03.支持服务器集群,集群间高内聚.低耦合,可动态横向扩展IM服 ...
- python doc os 参考
os --- 操作系统接口模块 源代码: Lib/os.py 该模块提供了一些方便使用操作系统相关功能的函数. 如果你是想读写一个文件,请参阅 open(),如果你想操作路径,请参阅 os.path ...