LED硬件原理图如下图所示:
LED硬件原理图
从图中可以看出,LED0 接到了GPIO_3 上,GPIO_3 就是 GPIO1_IO03,当 GPIO1_IO03输出低电平(0)的时候发光二极管 LED0 就会导通点亮,当 GPIO1_IO03 输出高电平(1)的时候发光二极管 LED0 不会导通,因此 LED0 也就不会点亮。所以 LED0 的亮灭取决于 GPIO1_IO03的输出电平,输出 0 就亮,输出 1 就灭。
按照我们前面文章《I.MX6U处理器GPIO的命名复用与IO配置》中讲的,我们需要对GPIO1_IO03 做如下设置:
1、使能 GPIO1 时钟
GPIO1 的时钟由CCM_CCGR1 的bit27 和bit26 这两个位控制,将这两个位都设置位 11 即可。
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 组寄存器地址,在官方文档《IMX6UL 参考手册》的 1154 页,如图所示:
GPIO3 对应的 GPIO 寄存器地址
本实验中 GPIO1_IO03 是作为输出功能的,因此 GPIO3_GDIR 的 bit3 要设置为 1,表示输出。
5、控制 GPIO 的输出电平
经过前面几步,GPIO1_IO03 已经配置好了,只需要向 GPIO3_DR 寄存器的 bit3 写入 0 即可控制 GPIO1_IO03 输出低电平,打开LED,向 bit3 写入 1 可控制GPIO1_IO03 输出高电平,关闭LED。
所有的裸机实验我们都在Ubuntu 下完成,使用 VSCode 编辑器!所有的裸机实验我们都在Ubuntu 下完成,使用 VSCode 编辑器!所有的裸机实验我们都在Ubuntu 下完成,使用 VSCode 编辑器!
既然是实验,肯定要自己动手创建工程,新建一个名为“1_leds”的文件夹,然后在“1_leds”这个目录下新建一个名为“led.s”的汇编文件和一个名为“.vscode”的目录,创建好以后“1_leds”文件夹如图所示:
VSCode 工程
在 led.s 中输入如下代码:
1
2 .global _start /* 全局标号 */
3
4 /*
5 * 描述: _start 函数,程序从此函数开始执行此函数完成时钟使能、
6 * GPIO 初始化、最终控制 GPIO 输出低电平来点亮 LED 灯。
7 */
8 _start:
9 /* 例程代码 */
10 /* 1、使能所有时钟 */
11 ldr r0, =0X020C4068 /* 寄存器 CCGR0 */
12 ldr r1, =0XFFFFFFFF
13 str r1, [r0]
14
15 ldr r0, =0X020C406C /* 寄存器 CCGR1 */
16 str r1, [r0]
17
18 ldr r0, =0X020C4070 /* 寄存器 CCGR2 */
19 str r1, [r0]
20
21 ldr r0, =0X020C4074 /* 寄存器 CCGR3 */
22 str r1, [r0]
23
24 ldr r0, =0X020C4078 /* 寄存器 CCGR4 */
25 str r1, [r0]
26
27 ldr r0, =0X020C407C /* 寄存器 CCGR5 */
28 str r1, [r0]
29
30 ldr r0, =0X020C4080 /* 寄存器 CCGR6 */
31 str r1, [r0]
32
33
34 /* 2、设置 GPIO1_IO03 复用为 GPIO1_IO03 */
35 ldr r0, =0X020E0068 /* 将寄存器 SW_MUX_GPIO1_IO03_BASE 加载到 r0 中 */
36 ldr r1, =0X5 /* 设置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MUX_MODE 为 5 */
37 str r1,[r0] 38
39 /* 3、配置 GPIO1_IO03 的 IO 属性
40 *bit 16:0 HYS 关闭
41 *bit [15:14]: 00 默认下拉
42 *bit [13]: 0 kepper 功能
43 *bit [12]: 1 pull/keeper 使能
44 *bit [11]: 0 关闭开路输出
45 *bit [7:6]: 10 速度 100Mhz
46 *bit [5:3]: 110 R0/6 驱动能力
47 *bit [0]: 0 低转换率
48 */
49 ldr r0, =0X020E02F4 /*寄存器 SW_PAD_GPIO1_IO03_BASE */ 50 ldr r1, =0X10B0
51 str r1,[r0] 52
53 /* 4、设置 GPIO1_IO03 为输出 */
54 ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */
55 ldr r1, =0X0000008
56 str r1,[r0] 57
58 /* 5、打开 LED0
59 * 设置 GPIO1_IO03 输出低电平
60 */
61 ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */
62 ldr r1, =0
63 str r1,[r0] 64
65 /*
66 * 描述: loop 死循环
67 */
68 loop:
69 b loop
我们来详细的分析一下上面的汇编代码,我们以后分析代码都根据行号来分析。
第 2 行定义了一个全局标号_start,代码就是从_start 这个标号开始顺序往下执行的。
第 11 行使用 ldr 指令向寄存器 r0 写入 0X020C4068,也就是 r0=0X020C4068,这个是CCM_CCGR0 寄存器的地址。
第 12 行使用 ldr 指令向寄存器 r1 写入 0XFFFFFFFF,也就是人 r1=0XFFFFFFFF。因为我们要开启所有的外设时钟,因此 CCM_CCGR0~CCM_CCGR6 所有的寄存器都 32 为位都要置1,也就是写入 0XFFFFFFFF。
第 13 行使用 str 将 r1 中的值写入到 r0 所保存的地址中去,也就是给 0X020C4068 这个地址写入 0XFFFFFFFF,相当于 CCM_CCGR0=0XFFFFFFFF,就是打开 CCM_CCGR0 寄存器所控制的所有外设时钟。
第 15~31 行都是向 CCM_CCGRX(X=1~6)寄存器写入 0XFFFFFFFF。这样我就通过汇编代码使能了 I.MX6U 的所有外设时钟。
第35~37 行是设置GPIO1_IO03 的复用功能,GPIO1_IO03 的复用寄存器地址为0X020E0068,寄存器 IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的 MUX_MODE 设置为 5 就是将 GPIO1_IO03 设置为GPIO。
第 49~51 行 是 设 置 GPIO1_IO03 的 配 置 寄 存 器 , 也 就 是 寄 存 器IOMUX_SW_PAD_CTL_PAD_GPIO1_IO03 的值,此寄存器地址为 0X020E02F4,代码里面已经给出了这个寄存器详细的位设置。
第 54~63 行是设置GPIO 功能,经过上面几步操作,GPIO1_IO03 这个 IO 已经被配置为了GPIO 功能,所以还需要设置跟 GPIO 有关的寄存器。第 54~56 行是设置GPIO1->GDIR 寄存器,将 GPIO1_IO03 设置为输出模式,也就是寄存器的GPIO1_GDIR 的 bit3 置 1。
第 61~63 行设置 GPIO1->DR 寄存器,也就是设置 GPIO1_IO03 的输出,我们要点亮开发板上的 LED0,那么GPIO1_IO03 就必须输出低电平,所以这里设置 GPIO1_DR 寄存器为 0。
第 68~69 行是死循环,通过 b 指令,CPU 重复不断的跳到 loop 函数执行,进入一个死循环。