嵌入式linux学习第三天汇编语言点灯

嵌入式linux学习第三天汇编语言点灯

今天学习如何在linux板子上点灯。

I.MX6U GPIO 详解

我们发现I.MX6U GPIO是分为两类的,:SNVS 域的和通用的。在讨论i.MX6U或类似的复杂微处理器时,了解其GPIO(通用输入输出)引脚的不同分类是很重要的。i.MX6U的GPIO引脚被分为两大类:SNVS(Secure Non-Volatile Storage)域的GPIO和通用GPIO。这种分类反映了它们不同的用途和特性。

IO:Input Output,用于CPU与外界进行信息交互
GPIO:General Purpose IO ports,通用IO口
SNVS:Secure Non-Volatile Storage 安全的非易失性存储
IOMUX:Input Output Multiplexer 输入/输出多路复用器
IOMUXC:Input Output Multiplexer Controller 输入/输出多路复用控制器
SW:Switch 开关

SNVS域的GPIO

SNVS域是指与安全和非易失性存储相关的功能区域。这个域主要关注的是安全功能,比如加密、安全启动、电源管理和保护敏感数据等。

  • 用途:SNVS域的GPIO通常用于安全相关的功能,例如检测篡改事件、管理安全启动过程中的信号或者控制与安全相关的外设。
  • 特性:这些GPIO在系统的低功耗模式下仍然可以工作,因此它们特别适合于那些需要在系统休眠或低功耗状态下监视外部事件的应用。此外,它们还可能支持一些特定的安全功能,比如硬件加密引擎的控制信号。
  • 电源域:SNVS域的GPIO与特定的电源域相关联,即使在系统其它部分关闭电源的情况下,这部分电源域仍然保持供电。这样可以确保安全功能在系统的各种电源状态下都能正常工作。

通用GPIO

与SNVS域的GPIO相比,通用GPIO没有那么多特定的安全或电源管理功能。它们被设计用于更广泛的目的,从简单的LED控制到与外部设备的复杂通信等。

  • 用途:通用GPIO用于各种标准输入输出任务,如数据收发、信号触发、电机控制等。
  • 灵活性:这些GPIO通常提供高度的配置灵活性,包括但不限于方向控制(输入或输出)、上拉/下拉电阻配置、中断触发设置等。
  • 电源域:通用GPIO通常随主系统电源一起工作,这意味着它们在系统进入低功耗模式时可能不可用。

在这里插入图片描述
STM32 的很多 IO 是可以复用为其它功能的,那么 I.MX6ULL 的其它 IO 也 是 可 以 复 用 为 GPIO 功能。同样的,GPIO1_IO00~GPIO_IO09 也是可以复用为其它外设引脚的,
一般来说配置GPIO步骤分为以下几步:
①、使能 GPIO 对应的时钟。
②、设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用
为 GPIO 功能。
③、设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。
④、第②步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使
用中断、默认输出电平等

1:使能对应GPIO时钟

CCM 里 面 的 外 设 时 钟 使 能 寄 存 器 。 CMM 有CCM_CCGR0~CCM_CCGR6 这 7 个寄存器,这 7 个寄存器控制着 I.MX6U 的所有外设时钟开关,
在这里插入图片描述
在这里插入图片描述
CCM_CCGR0 是个 32 位寄存器,其中每 2 位控制一个外设的时钟,比如 bit31:30 控制着GPIO2 的外设时钟,两个位就有 4 种操作方式.

在这里插入图片描述

2:设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用 为 GPIO 功能。

在这里插入图片描述
IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00 的寄存器,寄存器地址为 0X020E005C,这个寄存器是 32 位的,但是只用到了最低 5 位,其中bit0~bit3(MUX_MODE)就是设置 GPIO1_IO00 的复用功能的。GPIO1_IO00 一共可以复用为 9种功能 IO,分别对应 ALT0~ALT8,

3: 设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。

在这里插入图片描述

IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO00 也是个寄存器,寄存器地址为 0X020E02E8。这也是个 32 位寄存器,但是只用到了其中的低 17 位,下面是GPIO功能图的具体配置。

在这里插入图片描述
HYS(bit16):对应图 8.1.4.2 中 HYS,用来使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。如果需要对输入波形进行整形的话可以使能此位。此位为 0 的时候禁止迟滞比较器,为 1 的时候使能迟滞比较器。
PUS(bit15:14):对应图 8.1.4.2 中的 PUS,用来设置上下拉电阻的,一共有四种选项可以选择,如表 8.1.4.1 所示:
在这里插入图片描述
PUE(bit13):图 8.1.4.2 没有给出来,当 IO 作为输入的时候,这个位用来设置 IO 使用上下拉还是状态保持器。当为 0 的时候使用状态保持器,当为 1 的时候使用上下拉。状态保持器在IO 作为输入的时候才有用,顾名思义,就是当外部电路断电以后此 IO 口可以保持住以前的状态。
PKE(bit12):对应图 8.1.4.2 中的 PKE,此位用来使能或者禁止上下拉/状态保持器功能,为0 时禁止上下拉/状态保持器,为 1 时使能上下拉和状态保持器。
ODE(bit11):对应图 8.1.4.2 中的 ODE,当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。
SPEED(bit7:6):对应图 8.1.4.2 中的 SPEED,当 IO 用作输出的时候,此位用来设置 IO 速度,设置如表所示:
在这里插入图片描述
DSE(bit5:3):对应图 8.1.4.2 中的 DSE,当 IO 用作输出的时候用来设置 IO 的驱动能力,总共有 8 个可选选项,如表 8.1.4.3 所示:
在这里插入图片描述
SRE(bit0):对应图 8.1.4.2 中的 SRE,设置压摆率,当此位为 0 的时候是低压摆率,当为 1的时候是高压摆率。这里的压摆率就是 IO 电平跳变所需要的时间,比如从 0 到 1 需要多少时间,时间越小波形就越陡,说明压摆率越高;反之,时间越多波形就越缓,压摆率就越低。如果你的产品要过 EMC 的话那就可以使用小的压摆率,因为波形缓和,如果你当前所使用的 IO做高速通信的话就可以使用高压摆率。

4: I.MX6U GPIO 配置

IOMUXC_SW_MUX_CTL_PAD_XX_XX 和 IOMUXC_SW_PAD_CTL_PAD_XX_XX 这两种寄存器都是配置 IO 的,注意是 IO!不是 GPIO,GPIO 是一个 IO 众多复用功能中的一种。如果我们要用 GPIO1_IO00 来点个灯、作为按键输入啥的就是使用其 GPIO(通用输入输出)的功能。将其复用为 GPIO 以后还需要对其 GPIO 的功能进行配置,
在这里插入图片描述
这两种寄存器前面说了用来设置 IO 的复用功能和 IO 属性配置。左上角部分的 GPIO 框图就是,当 IO 用作 GPIO 的时候需要设置的寄存器,一共有八个:DR、GDIR、PSR、ICR1、ICR2、EDGE_SEL、IMR 和 ISR。前面我们说了 I.MX6U 一共有
GPIO1~GPIO5 共五组 GPIO,每组 GPIO 都有这 8 个寄存器。
在这里插入图片描述此寄存器是 32 位的,一个 GPIO 组最大只有 32 个 IO,因此 DR 寄存器中的每个位都对应一个 GPIO。当 GPIO 被配置为输出功能以后,向指定的位写入数据那么相应的 IO 就会输出相应的高低电平,比如要设置 GPIO1_IO00 输出高电平,那么就应该设置 GPIO1.DR=1。被配置为输入模式以后,此寄存器就保存着对应 IO 的电平值,每个位对对应一个 GPIO,例如,当 GPIO1_IO00 这个引脚接地的话,那么 GPIO1.DR 的 bit0 就是 0。
在这里插入图片描述
GDIR 寄存器也是 32 位的,此寄存器用来设置某个 IO 的工作方向,是输入还是输出。同样的,每个 IO 对应一个位,如果要设置 GPIO 为输入的话就设置相应的位为 0,如果要设置为输出的话就设置为 1。比如要设置 GPIO1_IO00 为输入,那么 GPIO1.GDIR=0;

在这里插入图片描述
接下来来看ICR1和ICR2寄存器,ICR1 用于 IO0~15 的配置, ICR2 用于 IO16~31 的配置。ICR1 寄存器中一个 GPIO 用两个
位,这两个位用来配置中断的触发方式,和 STM32 的中断很类似,可配置的选线如图所示:
在这里插入图片描述
在这里插入图片描述
IMR 寄存器,这是中断屏蔽寄存器。

在这里插入图片描述
IMR 寄存器也是一个 GPIO 对应一个位,IMR 寄存器用来控制 GPIO 的中断禁止和使能,如果使能某个 GPIO 的中断,那么设置相应的位为 1 即可,反之,如果要禁止中断,那么就设置相应的位为 0 即可。例如,要使能 GPIO1_IO00 的中断,那么就可以设置 GPIO1.MIR=1 即可。
接下来看寄存器 ISR,ISR 是中断状态寄存器。

在这里插入图片描述
ISR 寄存器也是 32 位寄存器,一个 GPIO 对应一个位,只要某个 GPIO 的中断发生,那么ISR 中相应的位就会被置 1。所以,我们可以通过读取 ISR 寄存器来判断 GPIO 中断是否发生,相当于 ISR 中的这些位就是中断标志位。当我们处理完中断以后,必须清除中断标志位,清除方法就是向 ISR 中相应的位写 1,也就是写 1 清零。
EDGE_SEL 寄存器,这是边沿选择寄存器,
在这里插入图片描述

硬件原理图

以上就是配置GPIO的过程。接下来看具体的硬件原理图。LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03,当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当 GPIO1_IO03 输出高电平(1)的时候发
光二极管 LED0 不会导通,因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03
的输出电平,输出 0 就亮,输出 1 就灭。
在这里插入图片描述

汇编程序编写

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 组寄存器地址,
在这里插入图片描述
具体汇编程序如下:
我们在虚拟机系统进行程序编写以及编译。

.global _start
_start:
ldr r0, =0X020C4068 /* 寄存器 CCGR0 */
ldr r1, =0XFFFFFFFF
str r1,[r0]ldr r0, =0X020C406C /* 寄存器 CCGR1 */
str r1,[r0]ldr r0, =0X020C4070 /* 寄存器 CCGR2 */
str r1,[r0]ldr r0, =0X020C4074 /* 寄存器 CCGR3 */
str r1,[r0]ldr r0, =0X020C4078 /* 寄存器 CCGR4 */
str r1,[r0]ldr r0, =0X020C407C /* 寄存器 CCGR5 */
str r1,[r0]ldr r0, =0X020C4080 /* 寄存器 CCGR6 */
str r1,[r0]
@将GPIO1_IO03复用为GPIO
ldr r0,=0x020E0068
ldr r1,=0x5
str r1,[r0]ldr r0,=0x020E02F4
ldr r1,=0x10B0
str r1,[r0]ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */
ldr r1, =0X0000008 
str r1,[r0]ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */
ldr r1, =0 
str r1,[r0]loop:b loop

上面汇编的操作并不复杂,只是按照上面已经列出的步骤对对应寄存器进行赋值。

编译下载验证

1、arm-linux-gnueabihf-gcc 编译文件
我们是要编译出在 ARM 开发板上运行的可执行文件,所以要使用安装的交叉编译器 arm-linux-gnueabihf-gcc 来编译。就一个 led.s 源文件,所以编译比较简单。先将 led.s 编译为对应的.o 文件,在终端中输入如下命令:

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 链接文件
arm-linux-gnueabihf-ld 用来将众多的.o 文件链接到一个指定的链接位置。因此我们现在需要做的就是确定一下本试验最终的可执行文件其运行起始地址,也就是链接地址。这里我们要区分“存储地址”和“运行地址”这两个概念,“存储地址”就是可执
行文件存储在哪里,可执行文件的存储地址可以随意选择。“运行地址”就是代码运行的时候所处的地址,这个我们在链接的时候就已经确定好了,代码要运行,那就必须处于运行地址处,否则代码肯定运行出错。比如 I.MX6U 支持 SD 卡、EMMC、NAND 启动,因此代码可以存储到 SD 卡、EMMC 或者 NAND 中,但是要运行的话就必须将代码从 SD 卡、EMMC 或者
NAND 中拷贝到其运行地址(链接地址)处,“存储地址”和“运行地址”可以一样,比如STM32 的存储起始地址和运行起始地址都是 0X08000000。
上电以后 I.MX6U 的内部 boot rom 程序会将可执行文件拷贝到链接地址处,这个链接地址可以在 I.MX6U 的内部 128KB RAM 中(0X900000~0X91FFFF),也可以在外部的 DDR 中。本教程所有裸机例程的链接地址都在 DDR中,链接起始地址为 0X87800000。I.MX6U-ALPHA 开发板的 DDR 容量有两种:512MB 和256MB,起始地址都为 0X80000000,只不过 512MB 的终止地址为 0X9FFFFFFF,而 256MB 容量的终止地址为 0X8FFFFFFF。之所以选择 0X87800000 这个地址是因为后面要讲的 Uboot 其链接地址就是 0X87800000,

arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf

在这里插入图片描述

3、arm-linux-gnueabihf-objcopy 格式转换
arm-linux-gnueabihf-objcopy 更像一个格式转换工具,我们需要用它将 led.elf 文件转换为led.bin 文件,命令如下:

arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。
在这里插入图片描述
4、arm-linux-gnueabihf-objdump 反汇编
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:

arm-linux-gnueabihf-objdump -D led.elf > led.dis

在这里插入图片描述
5:创建Makefile文件:

  1 led.bin:led.s2     arm-linux-gnueabihf-gcc -g -c led.s -o led.o3     arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf4     arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin5     arm-linux-gnueabihf-objdump -D led.elf > led.dis6 clean:7     rm -rf *.o led.bin led.elf led.dis

代码烧写

烧写使用正点原子提供的
1、将 imxdownload 拷贝到工程根目录下
2、给予 imxdownload 可执行权限
3、确定要烧写的 SD 卡。
在这里插入图片描述
比如我们插入sb多出了几个,烧写的确认的就是/dev/sdc。

./imxdownload led.bin /dev/sd

在这里插入图片描述
烧写速度226kb每秒证明烧写成功。
然后还要设置板子的启动方式为sd卡启动。拨码开关组合为:
在这里插入图片描述
插入板子按下复位,发现这个灯亮起,证明点灯成功!!!
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/674675.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker jenkins 部署springboot项目

1、创建jenkins容器 1,首先,我们需要创建一个 Jenkins 数据卷,用于存储 Jenkins 的配置信息。可以通过以下命令创建一个数据卷: docker volume create jenkins_data启动 Jenkins 容器并挂载数据卷: docker run -dit…

笔记本连接不上远程桌面,笔记本无法连接远程桌面的可能原因及解决方法

在使用远程桌面功能时,笔记本无法成功连接的情况可能由多种原因引起。为了有效地解决这个问题,我们需要逐一排查这些可能的原因,并采取相应的解决措施。 首先,网络连接稳定性是远程桌面连接成功的关键。请确保笔记本和远程计算机之…

【Linux】Docker 安装部署 Nacos

个人简介:Java领域新星创作者;阿里云技术博主、星级博主、专家博主;正在Java学习的路上摸爬滚打,记录学习的过程~ 个人主页:.29.的博客 学习社区:进去逛一逛~ 【Linux】Docker 安装部署 Nacos docker搜索na…

跟TED演讲学英文:4 pillars of college success in science by Freeman Hrabowski

4 pillars of college success in science Link: https://www.ted.com/talks/freeman_hrabowski_4_pillars_of_college_success_in_science Speaker: Freeman Hrabowski Date: February 2013 文章目录 4 pillars of college success in scienceIntroductionVocabularyTranscr…

IP规划案例

整个OSPF环境IP基于172.16.0.0/16划分 172.16.0.0/16 先分成2个网段(OSPF RIP),借1位172.16.0.0/17 ---OSPF 再按区域划分(5个区域),借3位 172.16.0.0/20 ---Area 0 三个环回 MGRE 4个网…

1-2 ARM单片机GPIO

def:通用输入输出口 GPIO输出模式原理讲解 1:推挽输出 2:复用推挽输出 电流最大是20mA,对于单片机来说总体的输出是由范围的 开漏/复用开漏输出 外部接上拉电阻的开漏输出 线与的概念 注: 与的概念:全1为1&…

解决Python中的 `ModuleNotFoundError: No module named ‘fcmeans‘` 错误

ModuleNotFoundError: No module named fcmeans 解决Python中的 ModuleNotFoundError: No module named fcmeans 错误如何解决这个错误fcmeans 库简介应用实例 解决Python中的 ModuleNotFoundError: No module named fcmeans 错误 在进行数据科学或机器学习项目时,…

什么是多模态大模型,有了大模型,为什么还要多模态大模型?

随着人工智能技术的愈演愈烈,其技术可以说是日新月异,每隔一段时间就会有新的技术和理念被创造出来;而多模态大模型也是其中之一。 什么是多模态 想弄明白什么是多模态大模型,那么首先就要弄明白什么是多模态。 简单来说&#x…

Baidu Comate——一款能让我开发效率翻倍的AI插件助手

Baidu Comate 背景 百度 Comate,Coding Mate Powered by AI。是文心大模型的智能代码助手,结合百度积累多年的编程现场大数据和外部优秀开源数据,可以生成更符合实际研发场景的优质代码。功能非常多可以推荐代码、生成代码注释、查找代码缺陷…

Python基础详解二

一,函数 函数是组织好的,可重复使用的,用来实现某个功能的代码段 def myMethod(data):print("数据长度为",len(data))myMethod("dsdsdsds") 函数的定义: def 函数名(传入参数):函数体return 返回值 def m…

选择了软件测试,你后悔吗?

记得在求职的时候,面试官经常问我:“为什么要选择软件测试工作?”而我也会经常说一堆自己有的没的优势去应付。 工作这么久了,也不再浮躁,静下心来回忆当初选择软件测试工作的历程,也是对自己职业生涯的一次回顾。 下…

数据结构-二叉树结尾+排序

一、二叉树结尾 1、如何判断一棵树是完全二叉树。 我们可以使用层序遍历的思路,利用一个队列,去完成层序遍历,但是这里会有些许的不同,我们需要让空也进队列。如果队列里到最后只剩下空那么这棵树就是完全二叉树。具体的实现如下…