I.MX6ULL ARM裸机开发---汇编LED实验

引言

  本次点亮LED实验基于NXP的I.MX6ULL开发板,I.MX6ULL使用的是Cortex-A7 架构,通过汇编进行裸机开发。

一、I.MX6ULL GPIO详解

1、初始化IO口分为四个步骤:

(1)使能指定的GPIO的时钟。
(2)初始化GPIO,比如输出功能、上拉、速度等等。
(3)指定IO如需复用,设置IO的复用功能。
(4)设置GPIO输出高电平或低电平。

2、I.MX6ULL IO命名

  STM32 中的 IO 都是 PA0-15、PB0-15 这样命名的,I.MX6ULL 的 IO 是怎么命名的呢?如下图可以看出,I.MX6ULL 的IO分为SNVS域和通用的,这两类IO的本质是一样的。同时,这些IO实际上是寄存器,通过配置寄存器可以设置不同属性。

I.MX6ULL ARM裸机开发---汇编LED实验_第1张图片

3、I.MX6ULL IO复用

  以IOMUXC_SW_MUX_CTL_PAD_GPIO1_IO03寄存器为例,介绍IO复用配置。

I.MX6ULL ARM裸机开发---汇编LED实验_第2张图片

  该寄存器地址为0X020E0068,是32位寄存器,但只用到了低5位,其中bit0-bit3(MUX_MODE)设置GPIO1_IO03的复用功能,GPIO1_IO03总共有9个复用功能,分别对应ALT0~ALT8,其中ALT5对应GPIO1_IO03。GPIO_IO03还可作为I2C_SDA、GPT1_COMPARE3等。

4、I.MX6ULL IO配置

  以IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO03寄存器为例,介绍IO电气属性配置。

I.MX6ULL ARM裸机开发---汇编LED实验_第3张图片
I.MX6ULL ARM裸机开发---汇编LED实验_第4张图片
I.MX6ULL ARM裸机开发---汇编LED实验_第5张图片

  该寄存器地址为0X020E02F4,是32位寄存器,但只用到了低17位。

  寄存器 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO00 的各个位的含义:

  (1)HYS(bit16):用来使能迟滞比较器,当 IO 作为输入功能的时候有效,用于设置输入接收器的施密特触发器是否使能。
  (2)PUS(bit15:14):用来设置上下拉电阻。
  (3)PUE(bit13):当 IO 作为输入的时,设置 IO 使用上下拉还是状态保持器。
  (4)PKE(bit12):使能或者禁止上下拉/状态保持器功能。
  (5)ODE(bit11):当 IO 作为输出的时候,用来禁止或者使能开路输出。
  (6)SPEDD(bit7:6):当 IO 用作输出的时候,用来设置 IO 速度。
  (7)DSE(bit5:3):当 IO 用作输出的时候,用来设置 IO 的驱动能力。
  (8)SRE(bit0):设置压摆率,当此位为 0 的时候是低压摆率,当为1的时候是高压摆率,这里的压摆率就是 IO 电平跳变所需要的时间。

5、I.MX6ULL GPIO配置

  GPIO等于IO吗?当然不是!GPIO只是IO复用功能中的一种,比如GPIO01_IO03这个IO可以作为GPIO01_IO03外,还可以复用为I2C_SDA。LED点亮实验中,除了对IO进行配置外,还需要对GPIO进行配置。
当 IO 用作 GPIO 的时候需要设置的寄存器,一共有八个: DR、GDIR、PSR、ICR1、ICR2、EDGE_SEL、IMR 和 ISR。我们重点介绍下DR和GDIR两种寄存器。

  (1)DR 寄存器是数据寄存器,结构图如下图所示:

I.MX6ULL ARM裸机开发---汇编LED实验_第6张图片

  一个 GPIO 组最大只有32个IO,因此 DR 寄存器中的每个位都对应一个 GPIO。当 GPIO 被配置为输出功能以后,向指定的位写入数据那么相应的 IO 就会输出相应的高低电平,比如要设置 GPIO1_IO03 输出高电平,那么就应该设置 GPIO1.DR=0x01<<3。

  (2)GDIR 寄存器,这是方向寄存器,用来设置某个 GPIO 的工作方向的,即输入/输出,GDIR 寄存器结构如下图所示:

I.MX6ULL ARM裸机开发---汇编LED实验_第7张图片

  GDIR 寄存器也是32位的,此寄存器用来设置某个 IO 的工作方向,是输入还是输出。同样的,每个 IO 对应一个位,如果要设置 GPIO 为输入的话就设置相应的位为0,如果要设置为输出的话就设置为1。比如要设置 GPIO1_IO03为输出,那么GPIO1.GDIR=0x01<<3;

6、I.MX6ULL GPIO时钟使能

  I.MX6ULL每个外设的时钟都可以独立的使能或禁止,这样可以关闭掉不使用的外设时钟,起到省电的目的。I.MX6ULL与STM32一样,需要使能GPIO对应的时钟。

I.MX6ULL ARM裸机开发---汇编LED实验_第8张图片
I.MX6ULL ARM裸机开发---汇编LED实验_第9张图片
I.MX6ULL ARM裸机开发---汇编LED实验_第10张图片

  CCM_CCGR0 是个 32 位寄存器,其中每 2 位控制一个外设的时钟,比如 bit31:30 控制着 GPIO2 的外设时钟,两个位就有 4 种操作方式,如表 8.1.6.1 所示:

  为了方便开发,将 I.MX6U 的所有外设时钟都打开。

7、I.MX6ULL 硬件原理分析

I.MX6ULL ARM裸机开发---汇编LED实验_第11张图片

  从上图可以看出,LED0接GPIO3,GPIO3就是GPIO1_IO03。当GPIO1_IO03输出高电平时,LED不导通,因此LED不会点亮。当GPIO1_IO03输出低电平时,LED导通,因此LED点亮。

二、I.MX6ULL实验程序编写步骤

(1)使能GPIO1对应的时钟。
(2)设置IO的复用功能,使其复用为GPIO功能。
(3)设置IO的上下拉、速度等等。
(4)设置GPIO1_03为输出模式。
(5)控制GPIO1_03的输出电平。

三、汇编

.global _start  /* 全局标号 */

/*
 * 描述:	_start函数,程序从此函数开始执行此函数完成时钟使能、
 *		  GPIO初始化、最终控制GPIO输出低电平来点亮LED灯。
 */
_start:
	/* 1、使能所有时钟 */
	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]
	

	/* 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, =0X10B0
    str r1,[r0]

	/* 4、设置GPIO1_IO03为输出 */
    ldr r0, =0X0209C004	/*寄存器GPIO1_GDIR */
    ldr r1, =0X0000008		
    str r1,[r0]

	/* 5、打开LED0
	 * 设置GPIO1_IO03输出低电平
	 */
	ldr r0, =0X0209C000	/*寄存器GPIO1_DR */
	ldr r1, =0		
	str r1,[r0]

/*
 * 描述:	loop死循环
 */
loop:
	b loop 				

四、编译代码

1、arm-linux-gnueabihf-gcc 编译文件

arm-linux-gnueabihf-gcc -g -c led.s -o led.o

  上述命令就是将 led.s 编译为 led.o,其中“-g”选项是产生调试信息,GDB 能够使用这些调试信息进行代码调试。“-c”选项是编译源文件,但是不链接。“-o”选项是指定编译产生的文件名字,这里我们指定 led.s 编译完成以后的文件名字为 led.o。

2、arm-linux-gnueabihf-ld 链接文件

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

  上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。

3、arm-linux-gnueabihf-objcopy 格式转换

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

  上述命令中,“-O”选项指定以什么格式输出,后面的“binary”表示以二进制格式输出,选项“-S”表示不要复制源文件中的重定位信息和符号信息,“-g”表示不复制源文件中的调试信息。

4、arm-linux-gnueabihf-objdump 反汇编

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

  上述代码中的“-D”选项表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为 led.dis 文件。

5、Makefile

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

  创建好 Makefile 以后我们就只需要执行一次“make”命令即可完成编译,如果我们要清理工程的话执行“make clean”即可。

  执行“make”命令后,该目录下生成文件如下图所示。

I.MX6ULL ARM裸机开发---汇编LED实验_第12张图片

五、代码烧写

  如何将我们前面编译出来的 led.bin 烧写到 SD 卡中呢?肯定有人会认为直接复制led.bin 到 SD 卡中不就行了,错!编译出来的可执行文件是怎么存放到 SD 中的,存放的位置是什么?这个 NXP 是有详细规定的!我们必须按照 NXP 的规定来将代码烧写到 SD 卡中,否则,代码是绝对运行不起来的。

  imxdownload可以将编译出来的.bin文件烧写到SD卡中。

1、将imxdownload拷贝到工程根目录下

  我们要将 imxdownload 拷贝到工程根目录下,也就是和 led.bin 处于同一个文件夹下,要不然烧写会失败的,拷贝完成以后如图 8.4.3.1 所示:

2、给予imxdownload可执行权限

chmod +x imxdownload

  通过chmod命令给予imxdownload可执行权限。

3、向SD卡烧写代码

  使用 imxdownload 向 SD 卡烧写 led.bin 文件,命令格式如下:

./imxdownload < .bin file > < SD Card >

  其中.bin 就是要烧写的.bin 文件,SD Card 就是你要烧写的 SD 卡,比如我的电脑使用如下命令烧写 led.bin 到/dev/sdc 中,插入读卡器后,可以用ls /dev/sd*命令查看。

I.MX6ULL ARM裸机开发---汇编LED实验_第13张图片

  插入读卡器前后对比,可以看到SD卡路径是/dev/sdc。

./imxdownload led.bin /dev/sdc         //不能烧写到/dev/sda 或 sda1 设备里面!那是系统磁盘

I.MX6ULL ARM裸机开发---汇编LED实验_第14张图片

  烧写完成后,在当前工程目录下生成load.imx文件,正是烧写到SD卡的文件,而不是led.bin。

六、代码验证

  代码已经烧写到了 SD 卡中了,接下来就是将 SD 卡插到开发板的 SD 卡槽中,然后设置拨码开关为 SD 卡启动,拨码开关设置如下图所示:

I.MX6ULL ARM裸机开发---汇编LED实验_第15张图片

  设置好以后按一下开发板的复位键,如果代码运行正常的话 LED0就会被点亮,如下图所示,LED0成功被点亮。

I.MX6ULL ARM裸机开发---汇编LED实验_第16张图片

你可能感兴趣的:(ARM裸机开发,arm,单片机,stm32)