【1】I.MX6U IO 命名
I.MX6ULL 的 IO 分为两类: SNVS 域的和通用的,这两类 IO 本质上都是一样的。
以常用 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 等等 ,他是根据某个 IO 所拥有的功能来命名的
【2】I.MX6U IO 复用
I.MX6U 的 GPIO 不止 GPIO1_IO00~GPIO1_IO09 这 10 个,其它的 IO 都可以复用为 GPIO 来使用。 I.MX6U 的 GPIO 一共有 5 组: GPIO1、 GPIO2、 GPIO3、 GPIO4 和 GPIO5,其中 GPIO1 有 32 个 IO, GPIO2 有 22 个 IO, GPIO3 有 29 个 IO、 GPIO4 有 29 个 IO, GPIO5最少,只有 12 个 IO,这样一共有 124 个 GPIO。如果只想看每个 IO 能复用什么外设的话可以直接查阅《IMX6ULL 参考手册》的第 4 章“Chapter 4 External Signals and Pin Multiplexing”。如果我们要编写代码,设置某个 IO 的复用功能的话就需要查阅第 32 章“Chapter 32: IOMUX
Controller(IOMUXC)” ,第 32 章详细的列出了所有 IO 对应的复用配置寄存器。
I.MX6U 的 IO 是有复用功能的,和 STM32一样,如果某个 IO 要作为某个外设引脚使用的话, 是需要配置复用寄存器的。
【3】I.MX6U IO 配置
寄存器 IOMUXC_SW_PAD_CTL_PAD_GPIO1_IO00 是用来配置 GPIO1_IO00 的,包括速度设置、驱动能力设置、压摆率设置等等。
【4】I.MX6U GPIO 配置
GPIO 是一个 IO 众多复用功能中的一种。比如 GPIO1_IO00 这个 IO 可以复用为: I2C2_SCL、 GPT1_CAPTURE1、 ANATOP_OTG1_ID、ENET1_REF_CLK 、 MQS_RIGHT 、 GPIO1_IO00 、 ENET1_1588_EVENT0_IN 、SRC_SYSTEM_RESET 和 WDOG3_WDOG_B 这 9 个功能, GPIO1_IO00 是其中的一种,我们想要把 GPIO1_IO00 用作哪个外设就复用为哪个外设功能即可。
I.MX6U 的 IO 是需要配置和输出的、是可以设置输出高低电平,也可以读取 GPIO 对应的电平。
【5】I.MX6U GPIO 时钟使能
I.MX6U 要使用某个外设,必须要先使能对应的时钟 ,每个外设的时钟都可以独立的使能或禁止,这样可以关闭掉不使用的外设时钟,起到省电的目的。
总结一下,要将 I.MX6U 的 IO 作为 GPIO 使用,我们需要一下几步:
①、使能 GPIO 对应的时钟。
②、设置寄存器 IOMUXC_SW_MUX_CTL_PAD_XX_XX,设置 IO 的复用功能,使其复用
为 GPIO 功能。
③、设置寄存器 IOMUXC_SW_PAD_CTL_PAD_XX_XX,设置 IO 的上下拉、速度等等。
④、第②步已经将 IO 复用为了 GPIO 功能,所以需要配置 GPIO,设置输入/输出、是否使
用中断、默认输出电平等。
【1】arm-linux-gnueabihf-gcc 编译文件
我们是要编译出在 ARM 开发板上运行的可执行文件,所以要使用交叉编译器 arm-linux-gnueabihf-gcc 来编译,
先将 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。
本教程所有裸机例程的链接地址都在 DDR中,链接起始地址为 0X87800000。 I.MX6U-ALPHA 开发板的 DDR 容量有两种: 512MB 和256MB,起始地址都为 0X80000000,只不过 512MB 的终止地址为 0X9FFFFFFF,而 256MB 容量的终止地址为 0X8FFFFFFF。之所以选择 0X87800000 这个地址是因为后面要讲的 Uboot 其链接地址就是 0X87800000,这样我们统一使用 0X87800000 这个链接地址,不容易记混。
确定了链接地址以后就可以使用 arm-linux-gnueabihf-ld 来将前面编译出来的 led.o 文件链接到 0X87800000 这个地址,使用如下命令:
arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf
上述命令中-Ttext 就是指定链接地址,“-o”选项指定链接生成的 elf 文件名,这里我们命名为 led.elf。上述命令执行完以后就会在工程目录下多一个 led.elf 文件, led.elf 文件也不是我们最终烧写到 SD 卡中的可执行文件,我们要烧写的.bin 文件,因此还需要将 led.elf 文件转换为.bin 文件,这里我们就需要用到 arm-linux-gnueabihf-objcopy 这个工具了。
【4】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”表示不复制源文件中的调试信息。
【5】arm-linux-gnueabihf-objdump 反汇编
大多数情况下我们都是用 C 语言写试验例程的,有时候需要查看其汇编代码来调试代码,因此就需要进行反汇编,一般可以将 elf 文件反汇编,比如如下命令:
arm-linux-gnueabihf-objdump -D led.elf > led.dis
上述代码中的“-D”选项表示反汇编所有的段,反汇编完成以后就会在当前目录下出现一个名为 led.dis 文件 。
led.dis 里面是汇编代码,而且还可以看到内存分配情况。
总结一下我们为了编译 ARM 开发板上运行的 led.o 这个文件使用了如下命令:
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
I.MX6U 虽然内部有 96K 的 ROM,但是这 96K 的 ROM 是 NXP自己用的,不向用户开放。所以相当于说 I.MX6U 是没有内部 flash 的,但是我们的代码得有地方存放啊,为此, I.MX6U 支持从外置的 NOR Flash、 NAND Flash、 SD/EMMC、 SPI NOR Flash和 QSPI Flash 这些存储介质中启动,所以我们可以将代码烧写到这些存储介质中中。在这些存储介质中,除了 SD 卡以外,其他的一般都是焊接到了板子上的,我们没法直接烧写。但是 SD
卡是活动的,是可以从板子上插拔的,我们可以将 SD 卡插到电脑上,在电脑上使用软件将.bin文件烧写到 SD 卡中,然后再插到板子上就可以了。其他的几种存储介质是我们量产的时候用到的,量产的时候代码就不可能放到 SD 卡里面了,毕竟 SD 是活动的,不牢固,而其他的都是焊接到板子上的,很牢固。
我们在调试裸机和 Uboot 的时候是将代码下载到 SD 中,是因为这样方便,当调试完成以后量产的时候要将裸机或者 Uboot 烧写到 SPI NOR Flash、 EMMC、 NAND 等这些存储介质中的。
正点原子专门编写了一个软件来将编译出来的.bin 文件烧写到 SD 卡中,这个软件叫做“imxdownload”
【1】将 imxdownload 拷贝到工程根目录下
【2】给予 imxdownload 可执行权限
我们直接将软件 imxdownload 从 Windows 下复制到 Ubuntu 中以后, imxdownload 默认是没有可执行权限的。我们需要给予 imxdownload 可执行权限,使用命令“chmod”,命令如下:
chmod 777 imxdownload
当给予 imxdownload 可执行权限以后其名字变成了绿色的,如果没有可执行权限的话其名字颜色是白色的。所以在 Ubuntu 中我们可以初步的从文件名字的颜色判断其是否具有可执行权限。
【3】确定要烧写的 SD 卡。
准备一张新的 SD(TF)卡,确保 SD 卡里面没有数据,因为我们在烧写代码的时候可能会格式化 SD 卡!!!
Ubuntu 下所有的设备文件都在目录“/dev”里面,所以插上 SD 卡以后也会出现在“/dev”里面,其中存储设备都是以“/dev/sd”开头的。我们要先看一下不插 SD 卡的时候电脑都有哪些存储设备,以防插入 SD 卡以后分不清谁是谁。输入如下所示命令:
ls /dev/sd*
如果你的电脑没有找到 SD 卡的话,尝试重启一下 Ubuntu 操作!
拓展:
如果你的电脑没有找到 SD 卡,且重启Ubuntu 也还是无法识别到SD卡(U盘)可尝试做如下操作:
这种情况一般是插入USB设备后,”USB设备“都无法在Ubuntu下识别,且VMware中“连接(断开与主机连接)©”为灰色不可选中状态,如下图:
解决:首先关闭虚拟机系统,找到当前虚拟机的安装目录,找到【.vmx】文件,如下图
选用记事本工具打开,找到【usb.restrictions.defaultAllow = “FALSE”】配置,将“FALSE”修改为“TRUE”,然后保存并关闭文件,再次启动虚拟机系统,此时虚拟机就能正常识别“U盘设备”了。
然后我们再次输入【ls /dev/sd* 】指令,即可确认我们的SD卡的设备类型,【/dev/sdb】即是我的 SD 卡
【4】向 SD 卡烧写 bin 文件
使用 imxdownload 向 SD 卡烧写 led.bin 文件,命令格式如下:
./imxdownload <.bin file> <SD Card>
其中.bin 就是要烧写的.bin 文件, SD Card 就是你要烧写的 SD 卡
例如:烧写 led.bin 到/dev/sdb 中:
./imxdownload led.bin /dev/sdb // 不能烧写到/dev/sda 或 sda1 设备里面!那是系统磁盘
烧写的过程中可能会让你输入密码,输入你的 Ubuntu 密码即可完成烧写,烧写的最后一行会显示烧写大小、用时和速度 。注意这个烧写速度,如果这个烧写速度在几百 KB/s 以下那么就是正常烧写。如果这个烧写速度大于几十 MB/s、甚至几百 MB/s 那么肯定是烧写失败了!
解决方法就是重新插拔 SD 卡,一般出现这种情况,重新插拔 SD 卡基本没啥用,只有重启Ubuntu,至于原因,尚不明确。
烧写完成以后会在当前工程目录下生成一个 load.imx 的文件 ,load.imx 这个文件就是软件 imxdownload 根据 NXP 官方启动方式介绍的内容,在 led.bin 文件前面添加了一些数据头以后生成的。最终烧写到 SD 卡里面的就是这个 load.imx 文件,而非led.bin。
代码已经烧写到了 SD 卡中了,接下来就是将 SD 卡插到开发板的 SD 卡槽中,然后设置拨码开关为 SD 卡启动,拨码开关设置如图 8.4.4.1 所示:
设置好以后按一下开发板的复位键,如果代码运行正常的话 LED0 就会被点亮 ,能 LED0 之前会有一点微亮,那是因为 I.MX6U的 IO 默认电平可能让 LED0 导通了,但是 IO 的默认配置内部可能有很大的电阻,所以电流就很小,导致 LED0 微亮。但是我们自己编写代码、配置好 IO 以后就不会有这个问题, LED0 就很亮了。