I.MX6U处理器LED灯点亮汇编程序代码编写

2019-11-18 08:43发布


LED硬件原理图如下图所示:

0ed99e3bf69c412da381a72b0ee5b1bb

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 页,如图所示:

cd7e69fad9e443409e0a682f6da11ced

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”文件夹如图所示:

5819cf5635584c498a017fd41c0442fe

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 函数执行,进入一个死循环。