5.汇编实现裸机LED
首先:操作LED就要操作GPIO alpha的芯片是NXP的IMX6ULL 其GPIO和STM32的命名有所区别
可以看到IMX6ULL的GPIO以其功能进行命名,对应上图中PAD之后的部分
即GPIO_IO00~GPIO_IO09 和JTAG_MOD等,用户按照名字就可以知道对应引脚的功能。并且IMX6ULL的GPIO也是可以复用的。
I.MX6U 的 GPIO 一共有 5 组: GPIO1、 GPIO2、 GPIO3、 GPIO4 和 GPIO5
其中 GPIO1 有 32 个 IO, GPIO2 有 22 个 IO, GPIO3 有 29 个 IO、 GPIO4 有 29 个 IO, GPIO5最少,只有 12 个 IO,这样一共有 124 个 GPIO
对IO的配置
首先要确定IO的复用功能是GPIO,看一下控制复用功能的寄存器(这里截取的是GPIO1_IO00的复用控制寄存器)
显然,bit4是复用功能的“总开关”,设置为1时强制为GPIO1_IO00功能;置0时由bit3:0来决定
bit3:0决定该IO复用为什么功能,可以看到这里ALT5就是复用为GPIO1_IO00功能,除此之外还有八种可选
再看一下IO的功能图
功能图中
HYS:用来使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。
如果需要对输入波形进行整形的话可以使能此位。此位为 0 的时候禁止迟滞比较器,为 1 的时候使能迟滞比较器。
PUS:用来设置上下拉电阻的,一共有四种选项可以选择,分别为100K下拉,47K上拉,100K上拉,22K上拉。
PUE(图中未给出):当 IO 作为输入的时候,这个位用来设置 IO 使用上下拉还是状态保持器。
当为 0 的时候使用状态保持器,当为 1 的时候使用上下拉。
状态保持器在IO 作为输入的时候才有用,顾名思义,就是当外部电路断电以后此 IO 口可以保持住以前的状态。
PKE:此为用来使能或者禁止上下拉/状态保持器功能,为0 时禁止上下拉/状态保持器,为 1 时使能上下拉和状态保持器。
ODE:当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。
SPEED:当 IO 用作输出的时候,此位用来设置 IO 速度,分别为低俗50M,中速100M,中速100M,最大速度200M。
DSE:当 IO 用作输出的时候用来设置 IO 的驱动能力,总共有 8 个可选选项
SRE:设置压摆率,当此位为 0 的时候是低压摆率,当为 1的时候是高压摆率。
这里的压摆率就是 IO 电平跳变所需要的时间,比如从 0 到 1 需要多少时间,时间越小波形就越陡,说明压摆率越高;
对应每个IO,都有一组寄存器去控制,这是毋庸置疑的,下面是GPIO_IO00的控制寄存器
可见 对于IO的每个功能端都有相应的寄存器位进行配置。
GPIO功能配置
但是我们没有看到如何设置 IO 为输入还是输出? 因为上面的配置只是针对IO的配置,对于GPIO来说,它只是IO的一个复用功能而已,所以还要对GPIO的功能进行配置。
所以对于GPIO来说,也需要有相应的寄存器来控制,GPIO的控制框图如下:
可见,配置好SW_MUX_CTL_PAD和SW_PAD_CTL_PAD两个寄存器后,还需要对GPIO进行单独配置,共有DR/GDIR/PSR/ICR1/ICR2/EDGE_SEL/IMR/ISR八个寄存器
I.MX6U 一共有GPIO1~GPIO5 共五组 GPIO,每组 GPIO 都有这 8 个寄存器。
DR寄存器:数据寄存器(data register)
此寄存器是 32 位的,一个 GPIO 组最大只有 32 个 IO,因此 DR 寄存器中的每个位都对应一个 GPIO。
当 GPIO 被配置为输出功能以后,向指定的位写入数据那么相应的 IO 就会输出相应的高低电平,比如要设置 GPIO1_IO00 输出高电平,那么就应该设置 GPIO1.DR=1。
当 GPIO 被配置为输入模式以后,此寄存器就保存着对应 IO 的电平值,每个位对对应一个 GPIO,例如,当 GPIO1_IO00 这个引脚接地的话,那么 GPIO1.DR 的 bit0 就是 0。
这里注意:如果GDIR[n]设置为输入,但该IO复用功能不是GPIO,那么读DR[n]始终是0值,所以读之前请确认IO是否复用为GPIO。
GDIR寄存器:方向寄存器(GPIO direction register)
很简单,每一个位对应一个GPIO,对应位为0则该位为输入模式,反之为输出模式。
PSR寄存器:GPIO状态寄存器(pad status register)
这个寄存器是只读的,读取相应的位即可获取对应的 GPIO 的状态,也就是 GPIO 的高低电平值。功能和输入状态下的 DR 寄存器一样。
ICR寄存器:中断配置寄存器(interrupt configuration register)
分为ICR1和ICR2两个寄存器,分别配置低16位和高16位GPIO,即每个GPIO占两位。
通过每个GPIO对应的两位设置可以配置低电平、高电平、上升沿、下降沿四种模式。
IMR寄存器:中断屏蔽寄存器(interrupt mask register)
每个GPIO对应一位,0为屏蔽中断,1为使能中断
(个人认为这里的屏蔽翻译不恰当,因为下面UNMASKED和MASKED的功能和使用中屏蔽的意思好像是相反的呢?)
ISR寄存器:中断状态寄存器(interrupt status register)
当中断发生时,相应中短线对应的位被置1,用来在特定中断组中查询是哪条中短线发生了中断。
在每次处理中断完成后必须手动清零,清除的方法是向要清除的位写1。
EDGE_SEL寄存器:边沿选择寄存器(edge select register)
EDGE_SEL 寄存器用来设置边沿中断,这个寄存器会覆盖 ICR1 和 ICR2 的设置,同样是一个 GPIO 对应一个位。
如果相应的位被置 1,那么就相当与设置了对应的 GPIO 是上升沿和下降沿(双边沿)触发。
例如,我们设置 GPIO1.EDGE_SEL=1,那么就表示 GPIO1_IO01 是双边沿触发中断,无论 GFPIO1_CR1 的设置为多少,都是双边沿触发。
因为ICR中没有双边沿的设置选项。
GPIO时钟配置
配置完相应GPIO的功能还不能使GPIO工作起来,还要对GPIO的时钟进行使能,I.MX6U 的系统时钟参考《I.MX6UL 参考手册》的第 18 章“Chapter 18: Clock Controller Module(CCM)”
先不研究 I.MX6U 的时钟系统,只看一下 CCM 里面的外设时钟使能寄存器。
CMM 有 CCM_CCGR0~CCM_CCGR6 这 7 个寄存器,这 7 个寄存器控制着 I.MX6U 的所有外设时钟开关
CCM_CCGR0 寄存器:CCM时钟门控寄存器(CCM Clock Gating Register 1)
CCM_CCGR0 是个 32 为寄存器,其中每 2 位控制一个外设的时钟 ,例如这里的bit31:30控制GPIO2的时钟
其设置方法为:对于GPIO来说,开启时钟即两位都置1,关闭则两位都置0。
总结起来,要将 I.MX6U 的 IO 作为 GPIO 使用,我们需要以下几步:
①、使能 GPIO 对应的时钟。
②、设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用为 GPIO 功能。
③、设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。
④、第②步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使用中断、默认输出电平等。
硬件分析
显然,低电平点灯,高电平灭灯。
点灯程序编写
对 GPIO1_IO03 做如下设置:
1、使能 GPIO1 时钟
GPIO1 的时钟由 CCM_CCGR1 的 bit27 和 bit26 这两个位控制,将这两个位都设置为11即可。本教程所有例程已经将 I.MX6U 的所有外设时钟都已经打开了,因此这一步可以不用做。
2、设置 GPIO1_IO03 的复用功能
找到 GPIO1_IO03 的复用寄存器“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03”的地址为0X020E0068,然后设置此寄存器,将 GPIO1_IO03 这个 IO 复用为 GPIO 功能,也就是 ALT5。
3、配置 GPIO1_IO03
找到 GPIO1_IO03 的配置寄存器“IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03”的地址为0X020E02F4,根据实际使用情况,配置此寄存器。
4、设置 GPIO
我们已经将 GPIO1_IO03 复用为了 GPIO 功能,所以我们需要配置 GPIO。找到 GPIO3 对应的 GPIO 组寄存器地址
本实验中 GPIO1_IO03 是作为输出功能的,因此 GPIO1_GDIR 的 bit3 要设置为 1,表示输出。
5、控制 GPIO 的输出电平
经过前面几步, GPIO1_IO03 已经配置好了,只需要向 GPIO1_DR 寄存器的 bit3 写入 0 即可控制 GPIO1_IO03 输出低电平,打开 LED,向 bit3 写入 1 可控制 GPIO1_IO03 输出高电平,关闭 LED。
具体程序
1 /*
2 * @Author: qjx
3 * @Date: 2020-05-02 14:16:50
4 * @Last Modified by: qjx
5 * @Last Modified time: 2020-05-02 14:48:38
6 * 汇编点灯程序
7 */
8
9 /*全局标号 */
10 .global _start
11
12 /*
13 * _start函数,程序从这里开始
14 * 分别完成: 1、时钟使能
15 2、IO复用
16 3、GPIO配置
17 4、控制GPIO.DR寄存器点灯
18 */
19
20 _start:
21 /*第一步:使能所有时钟 */
22
23 ldr r0,=0X020C4068 @CCGR0地址
24 ldr r1,=0XFFFFFFFF @设置的值(全1)
25
26 str r1,[r0] @把r1存到r0指向的地址中
27
28 ldr r0,=0X020C406C @CCGR1地址
29 str r1,[r0] @把r1存到r0指向的地址中
30
31 ldr r0,=0X020C4070 @CCGR2地址
32 str r1,[r0] @把r1存到r0指向的地址中
33
34 ldr r0,=0X020C4074 @CCGR3地址
35 str r1,[r0] @把r1存到r0指向的地址中
36
37 ldr r0,=0X020C4078 @CCGR4地址
38 str r1,[r0] @把r1存到r0指向的地址中
39
40 ldr r0,=0X020C407C @CCGR5地址
41 str r1,[r0] @把r1存到r0指向的地址中
42
43 ldr r0,=0X020C4080 @CCGR6地址
44 str r1,[r0] @把r1存到r0指向的地址中
45
46 /*第二步、设置GPIO1_IO03复用为GPIO_IO03 */
47 ldr r0,=0X020E0068 @SW_MUX_CTL_PAD_GPIO1_IO03的地址
48 ldr r1,=0X00000005 @设置低4位为0101
49 str r1,[r0] @把r1存到r0指向的地址中
50
51 /*第三步、配置GPIO */
52 /*
53 *bit 16:0 HYS 关闭
54 *bit [15:14]: 00 默认下拉
55 *bit [13]: 0 kepper 功能
56 *bit [12]: 1 pull/keeper 使能
57 *bit [11]: 0 关闭开路输出
58 *bit [7:6]: 10 速度 100Mhz
59 *bit [5:3]: 110 R0/6 驱动能力
60 *bit [0]: 0 低转换率
61 */
62 ldr r0,=0X020E02F4 @SW_PAD_CTL_PAD_GPIO1_IO03的地址
63 ldr r1,=0X000010B0 @设置对应属性
64 str r1,[r0] @把r1存到r0指向的地址中
65
66 /*第四步、设置GPIO_IO03为输出 */
67 ldr r0,=0X0209C004 @GPIO1_GDIR的地址
68 ldr r1,=0X00000008 @设置bit3为1
69 str r1,[r0] @把r1存到r0指向的地址中
70
71 /*第五步、打开LED 设置输出低电平 */
72 ldr r0,=0X0209C000 @GPIO1_DR的地址
73 ldr r1,=0X00000000 @全为0
74 str r1,[r0] @把r1存到r0指向的地址中
75
76 loop:
77 b loop
编译代码
1、 arm-linux-gnueabihf-gcc 编译文件
1 arm-linux-gnueabihf-gcc -g -c led.s -o led.o
上述命令就是将 led.s 编译为 led.o,其中“-g”选项是产生调试信息, GDB 能够使用这些调试信息进行代码调试。
“-c”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字,这里我们指定 led.s 编译完成以后的文件名字为 led.o。执行上述命令以后就会编译生成一个 led.o 文件
2、 arm-linux-gnueabihf-ld 链接文件
1 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件
注:这里的链接地址可以是0X80000000 为了和后面Uboot的地址统一 不容易记混 这里取了0X87800000
3、 arm-linux-gnueabihf-objcopy 格式转换
1 arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
.elf不是最终烧写到SD的文件,需要转换为.bin文件
上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
到这里就已经具备烧录条件了,alpha需要SD卡启动,要把imxdownload拷贝到工程文件夹下(只能在linux下运行)
给予它可执行权限
1 chmod 777 imxdownload
确定要烧写的SD卡名称后进行烧录
1 ./imxdownload led.bin /dev/(对应的sd卡名称)
然后把SD卡插入卡槽,调整拨码开关至 1 7开
上电可以看到LED微闪一下,稍后正常点亮,说明烧录成功。
续上:
4、 arm-linux-gnueabihf-objdump 反汇编
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:
1 arm-linux-gnueabihf-objdump -D led.elf > led.dis
上述代码中的“-D”选项表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为 led.dis 文件
将上面的步骤做成Makefile
1 led.bin:led.s
2 arm-linux-gnueabihf-gcc -g -c led.s -o led.o
3 arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
4 arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin
5 arm-linux-gnueabihf-objdump -D led.elf > led.dis
6 clean:
7 rm -rf *.o led.bin led.elf led.dis
2020-05-02 15:38:07
5.汇编实现裸机LED的更多相关文章
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作【转】
本转载自:http://www.techbulo.com/1313.html Tiny4412汇编流水灯代码,Tiny4412裸机LED操作 2014年10月20日 ⁄ 裸机程序 ⁄ 共 4171字 ...
- Tiny4412汇编流水灯代码,Tiny4412裸机LED操作[1]
从今天开始就正式进入到tiny4412的开发学习中了,今天主要看了一下Tiny4412的启动流程及存储器映射及Exynos4412数据手册,用汇编写了一个跑马灯程序(后续会有C语言版本的出来),先说一 ...
- 从点亮一个LED开始,Cortex-A9裸机程序设计
电路原理图: 如何点亮一个LED? 通过对原理图进行分析,我们能够发现给三极管的基极加上一个高点平时,三级管be结导通构成通路,此时二极管就点亮了.若要将LED熄灭只需取消高电平输出. 如何使三级管基 ...
- Tiny4412之C语言实现流水灯,Tiny4412裸机程序[3]
在前边我们使用汇编完成了一个流水灯实验: Tiny4412汇编流水灯代码,Tiny4412裸机LED操作 ---- - -- -- -- - -- -- 修改: # ${MKBL2} ${SOURCE ...
- c语言环境初始化&c语言和汇编混合编程
bootloader通常会分为两个阶段:第一阶段采用汇编语言来编写,主要是一些核心的初始化工作(内存,时钟的初始化),第二阶段使用C语言来编写,主要是它会完成一些板载硬件的初始化(串口,网口)然后其启 ...
- Exynos4412 中断处理流程详解
Linux 中,当外设触发中断后,大体处理流程如下: a -- 具体CPU architecture相关的模块会进行现场保护,然后调用machine driver对应的中断处理handler; b - ...
- arm:jlink调试和直接烧写运行的不同 [mdk s3c2440]
1.对全局变量的初始化. 2.还没发现的事例. /*************************************************/ 先上连接文件sct LR_ROM1 0x3000 ...
- Part10-C语言环境初始化-一跃进入C大门lesson3
1.跳转到c代码 因为内存中的代码来自于垫脚石SRAM,他们是相同的. 采用绝对跳转方式来完成. 因为我们是从汇编代码跳转到c语言的程序,所以我们要提前准备一个main.c文件. 修改makefile ...
- 基于 Keil MDK 移植 RT-Thread Nano
后文rtt代表RT-Thread 在官网公众号中,看到rtt发布了rtt nano,这个就很轻量级的rtos内核,把多余的驱动都裁剪了,因此移植工作量小,可以哪来学习一番,体验rtt之美 rtt现在也 ...
随机推荐
- 第10.9节 Python子包的导入方式介绍
在<第10.8节 Python包的导入方式详解>详细介绍了包的导入方式,子包也是包,子包的导入与包的导入方法上没有本质区别,但二者还是有所不同.本节对照二者的方式介绍子包与包导入的关系: ...
- 第14.14节 爬虫实战准备:csdn博文点赞过程http请求和响应信息分析
如果要对csdn博文点赞,首先要登录CSDN,然后打开一篇需要点赞的文章,如<第14.1节 通过Python爬取网页的学习步骤>按<第14.3节 使用google浏览器获取网站访问的 ...
- PyQt(Python+Qt)学习随笔:QAbstractItemView的defaultDropAction属性
老猿Python博文目录 老猿Python博客地址# 一.概述 defaultDropAction属性用于控制QAbstractItemView及其子类的实例视图中拖放时放下的默认操作.该属性的类型为 ...
- 安装pyspider出现的问题
本文来自微信公众号:coder_xiaobu,欢迎关注 一.安装pyspider pip install pyspider 二.启动 pyspider all 三.安装中出现的问题处理 安装的时候出现 ...
- 团队作业6(A)-Alpha阶段项目复审
Alpha阶段项目复审 复审团队: 莫政 (3118005067). 卢耀恒(3118005065) . 许梓莹(3218005083). 梁小燕(3218005081).高嘉淳(3118005047 ...
- 利用IDEA把Java项目打成jar包
第一步:按如下步骤或Ctrl+Shift+Alt+S打开 Project Structure第二步:第三步:选择要执行的文件, 依次选择项目, main方法所在的文件, 保存如果出现以下错误:则根据 ...
- 原创:DynamicDataDisplay波形显示自定义格式
原创:DynamicDataDisplay 原版本在日期显示的格式上与我们的习惯不一样,特做如下修改: 自定义日期格式修改: //MainWindow.cs中 var ds = new Enumera ...
- oracle归档空间不足的问题(rman删除归档日志)
案例一:归档日志满,数据库用户无法登陆,业务异常 解决方案一(可以登录rman): rman target / RMAN> crosscheck archivelog all; RM ...
- INS-06004 file operation on user's .ssh directory is not permitted
在搭建rac的时候不能先ssh到另一台服务器,否则安装程序无法自动创建/home/oracle/.ssh这个目录,然后就会报INS-06004这个错误了. 原因:在/home/oracle/这个路径下 ...
- svn工具包+安装教程+使用ip访问
SVN使用 简介: SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS.CVS,它采用了分支管理系统,它的设计目标就是取代CVS. Server界面 1: 安装这两个文 ...