I.MX6UL:汇编LED驱动实验
一、前言
I.MX6UL 使用的是 Cortex-A7 架构,Cortex-A 芯片一上电 SP 指针还没初始化,C 环境还没准备好,所以肯定不能运行 C 代码,必须先用汇编语言设置好 C 环境,比如初始化 DDR、设置 SP指针等等,当汇编把 C 环境设置好了以后才可以运行 C 代码。所以Cortex-A 一开始肯定是汇编代码,其实STM32也一样的,一开始也是汇编,以 STM32F103 为例,启动文件startup_stm32f10x_hd.s 就是汇编文件,只是这个文件ST已经写好了,我们根本不用去修改。
二、硬件原理
从可以看出,LED0 接到了 GPIO_3 上,GPIO_3 就是 GPIO1_IO03。
三、IMX6U GPIO学习
STM32 IO 初始化流程:
(1)使能GPIO时钟
(2)配置IO复用,将其复用为GPIO
* (3)配置GPIO的电气属性
(4)使能GPIO,输出高低电平
IMX6ULL IO初始化:
(1)使能时钟,CCGR0--CCGR6这7个寄存器控制着IMX6ULL所有外设时钟的使能。为了简单,设置CCGR0--CCGR6这7个寄存器全部为0XFFFFFFFF,相当于使能所有外设时钟。
(2)IO复用,将寄存器IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03的bit3-0设置为0x5,复用GPIO1_IO03为GPIO。
(3)寄存器IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03是设置GPIO1_IO03的电气属性,包括压摆率、速度、驱动能力、开漏,上下拉等等。
(4)配置GPIO功能,设置输入输出。设置 GPIO1_GDIR 寄存器bit3位为1,也就是设置为输出模式。向 GPIO1_DR 寄存器的 bit3位来控制 GPIO1_IO03 输出高低电平。
3.1 I.MX6UL的外设时钟
IMX6ULL参考手册699页中( 手册中有:此字段保留(未用到的意思)),CCGR0-CCGR6这七个寄存器控制着所有外设时钟的使能。
3.2 I.MX6UL的IO复用
从图可以看出,I.MX6ULL的IO分为两类:SNVS域的和通用的,这两类IO本质上都是一样的。图中的形如“IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO00”的就是GPIO命名,命名形式就是“IOMUXC_SW_MUC_CTL_PAD_XX_XX”,后面的“XX_XX”就是GPIO命名,比如:GPIO1_IO01、UART1_TX_DATA、JTAG_MOD等等。I.MX6ULL的GPIO并不像STM32一样以PA0~15这样命名,他是根据某个IO所拥有的功能来命名的。比如我们一看到GPIO1_IO01就知道这个肯定能做GPIO。
手册中1571页,IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03 的寄存器,这个寄存器是32位的,但是只用到了最低5位,其中bit0~bit3(MUX_MODE)就是设置 GPIO1_IO03 的复用功能的。GPIO1_IO03 一共可以复用为9种功能 IO,分别对应 ALT0~ALT8,其中 ALT5 就是作为 GPIO1_IO03。
3.3 I.MX6UL的IO配置
如图所示,手册中1793页展示了寄存器 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03
(1)HYS(bit16): 用来使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。如果需要对输入波形进行整形的话可以使能此位。此位为 0 的时候禁止迟滞比较器,为 1 的时候使能迟滞比较器。(暂时用不到)
(2)PUS(bit15:14): 用来设置上下拉电阻的,一共有四种选项可以选择,如图所示。
(3)PUE(bit13):当 IO 作为输入的时候,这个位用来设置 IO 使用上下拉还是状态保持器。当为 0 的时候使用状态保持器,当为 1 的时候使用上下拉。状态保持器在IO 作为输入的时候才有用,就是当外部电路断电以后此 IO 口可以保持住以前的状态。
(4)PKE(bit12):此位用来使能或者禁止上下拉/状态保持器功能,为 0 时禁止上下拉/状态保持器,为 1 时使能上下拉和状态保持器。
(5)ODE(bit11): 当 IO 作为输出的时候,此位用来禁止或者使能开路输出,此位为 0 的时候禁止开路输出,当此位为 1 的时候就使能开路输出功能。
(6)SPEED(bit7:6):当 IO 用作输出的时候,此位用来设置 IO 速度,设置如图所示。
(7)DSE(bit5:3):当 IO 用作输出的时候用来设置 IO 的驱动能力,总共有 8 个可选选项,如图所示,电阻越小驱动能力越强。
(8)SRE(bit0):设置压摆率,当此位为 0 的时候是低压摆率,当为 1 的时候是高压摆率。这里的压摆率就是 IO 电平跳变所需要的时间,比如从 0 到 1 需要多少时间,时间越小波形就越陡,说明压摆率越高;反之,时间越多波形就越缓,压摆率就越低。如果你的产品要过 EMC 的话那就可以使用小的压摆率,因为波形缓和,如果你当前所使用的 IO做高速通信的话就可以使用高压摆率。
3.4 MX6U GPIO 配置
手册1358页,此寄存器是 32 位的,一个 GPIO 组最大只有 32 个 IO,因此 DR 寄存器中的每个位都对应一个 GPIO。当 GPIO 被配置为输出功能以后,向指定的位写入数据那么相应的 IO 就会输出相应的高低电平,比如要设置 GPIO1_IO00 输出高电平,那么就应该设GPIO1.DR=1。当 GPIO被配置为输入模式以后,此寄存器就保存着对应 IO 的电平值,每个位对对应一个GPIO,例如,当 GPIO1_IO00 这个引脚接地的话,那么 GPIO1.DR 的 bit0 就是 0。
GDIR 寄存器,这是方向寄存器,用来设置某个 GPIO 的工作方向的,即输入/输出,GDIR 寄存器结构如图所示。GDIR 寄存器也是 32 位的,此寄存器用来设置某个 IO 的工作方向,是输入还是输出。同样的,每个 IO 对应一个位,如果要设置 GPIO 为输入的话就设置相应的位为 0,如果要设置为输出的话就设置为 1。比如要设置 GPIO1_IO00 为输入,那么 GPIO1.GDIR=0;
四、汇编程序编写
下图来自IMX6ULL参考手册699页,可查询到CCM_CCGR0的地址。
.global_start @全局标号_start:ldr r0, =0X020C4068 /* 寄存器 CCGR0 */ldr r1, = 0xffffffffstr 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]/* 2、设置 GPIO1_IO03 复用为 GPIO1_IO03 */ldr r0, =0X020E0068 /* 将寄存器 SW_MUX_GPIO1_IO03_BASE 加载到 r0 中 */ldr r1, =0X5 /* 设置寄存器 SW_MUX_GPIO1_IO03_BASE 的 MUX_MODE 为 5 */str r1,[r0]/* 3、配置 GPIO1_IO03 的 IO 属性*bit 16:0 HYS 关闭*bit [15:14]: 00 默认下拉*bit [13]: 0 kepper 功能*bit [12]: 1 pull/keeper 使能*bit [11]: 0 关闭开路输出*bit [7:6]: 10 速度 100Mhz*bit [5:3]: 110 R0/6 驱动能力*bit [0]: 0 低转换率*/ldr r0, =0X020E02F4 /*寄存器 SW_PAD_GPIO1_IO03_BASE */ldr r1, =0X10B0str r1,[r0]/* 4、设置 GPIO1_IO03 为输出 */ldr r0, =0X0209C004 /*寄存器 GPIO1_GDIR */ldr r1, =0X0000008str r1,[r0]/* 5、打开 LED0* 设置 GPIO1_IO03 输出低电平*/ldr r0, =0X0209C000 /*寄存器 GPIO1_DR */ldr r1, =0str r1,[r0]loop:b loop