uboot移植之GPIO上电初始状态的调整
开发板在上电之后,GPIO都有一个默认初始状态,这个状态可能是高电平也可能是低电平。而我们的应用程序在正式接管控制这些GPIO,是在内核起来并成功加载根文件系统之后。所以在内核启动的这段时间内,这些GPIO保持在一种不受控的状态。但是我们实际应用的时候,可能需要这些GPIO在此阶段处于稳定的某种状态,所以我们可以在uboot中设置此状态,并一直保持到应用成功接管之后。
现在以开发板主板上三个LED灯为例,讲解如何在uboot阶段设置GPIO的电平状态。设置LED灯相关GPIO电平状态,一是需要设置GPIO引脚IOMUX复用功能相关寄存器,二是要设置GPIO控制器相关寄存器,如设置GPIO为输出功能,设置输出电平高低。
在前面章节中讲了配置一个引脚IOMUX复用功能需要配置三个寄存器:IOMUXC_SW_MUX_CTL_PAD、IOMUXC_SW_PAD_CTL_PAD、SELECT_INPUT。
但是在配置之前我们需要知道,我们将要配置的是哪一个引脚,以LED_Y黄灯为例。
一、确定LED_Y引脚
我们打开硬件原理图,查找LED_Y,发现该引脚CPU球号为K15。
然后通过球号K15查找该引脚的名称PAD NAME。通过查找ELF 1开发板资料包\05-硬件资料\05-4 管脚分配表/ ELF 1引脚复用对照表.xlsx,我们知道,K15的PAD NAME为UART1_CTS_B。
二、查看IOMUX相关寄存器
在ELF 1开发板资料包\05-硬件资料\05-2 芯片数据手册\IMX6ULLRM手册中查找引脚PAD NAME为UART1_CTS_B的相关寄存器,打开参考手册Chapter 32 IOMUX Controller (IOMUXC)章节,
然后打开IOMUXC Memory Map/Register Definition,可以看到各个引脚按照PAD NAME对应的寄存器:
找到UART1_CTS_B对应IOMUXC_SW_MUX_CTL_PAD寄存器:
IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
对应的IOMUXC_SW_PAD_CTL_PAD寄存器:
IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B
由于我们使用UART1_CTS_B引脚复用成为GPIO1_IO08,而GPIO1_IO08只能复用到UART1_CTS_B引脚,所以没有相应的SELECT_INPUT寄存器。
打开IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B寄存器的描述:
看到此寄存器地址为0X20E008C。有效位为MUX_MODE[0:3],SION[4]。其中SION是否强制将该引脚复用成为UART1_CTS_B,一般情况下用不到,将其设置成默认的0即可。
MUX_MODE就是选择复用模式配置,这里设置成为0101。所以可设置0X20E008C值为0x05。
打开IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器的描述:
可以看到该寄存器地址为:0x20E0318。此寄存器很多配置项包括上下拉,驱动能力等,作为GPIO控制LED灯输出功能,我们一般不需要做配置,使用默认配置即可。
三、查看GPIO控制器相关寄存器
在官方参考手册的28章,有GPIO控制器相关寄存器说明:
我们主要需要配置的寄存器是GPIOx_DR设置数据寄存器和GPIOx_GDIR设置输入输出方向的寄存器。
四、在uboot代码中我们设置寄存器
在文件board/freescale/mx6ullevk/mx6ullevk.c中添加:
static iomux_v3_cfg_t const led_pads[] = { MX6_PAD_UART1_CTS_B__GPIO1_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL), }; static void led_init(void){ gpio_direction_output(IMX_GPIO_NR(1,18), 0); }; |
在int board_init(void)函数中添加:
imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads)); led_init(); |
五、测试
修改完成之后,编译uboot,并使用tftp加载到内存,然后使用mmc write命令将镜像烧写到eMMC Flash。具体的tftp网络环境搭建,请参考之前章节内容。
首先建立编译脚本:
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ touch build.sh elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ vim build.sh |
在脚本中输入以下内容:
#!/bin/bash export CPU='grep -c processor /proc/cpuinfo' source /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi make distclean make imx6ull_elf1_defconfig make -j${CPUS} |
注意:将上面的内容复制到开发环境中可能会存在格式问题,正确格式内容如下图所示,请参考下图进行调整:
给脚本可执行权限:
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ chmod u+x build.sh |
然后直接使用build.sh脚本进行编译:
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ ./build.sh |
将u-boot.imx复制到/home/elf/tftp下:
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ cp u-boot.imx /home/elf/tftp |
在开发板uboot命令行,使用tftp命令将uboot.imx下载到内存:
=> tftp 80800000 u-boot.imx |
设置mmc设备及分区:
=> mmc dev 1 1 switch to partitions #1, OK mmc1(part 1) is current device |
执行命令写入到mmc(该命令的count长度,请根据uboot.imx实际大小设置,具体计算方法可参考8.4.3.3 eMMc/SD卡命令章节)
=> mmc write 80800000 2 346 MMC write: dev # 1,block #2, count 838 ... 838 blocks written: OK |
烧写完成之后,我们执行reset命令,重启:
=> reset |
重启之后可以看到LED_Y黄灯点亮。
六、代码说明
下面分析调用过程,board_init会在commn/board_r.c的初始化序列中调用。
board_init首先调用imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads));
此函数在arch/arm/imx-common/iomux-v3.c中定义:
该函数又调用imx_iomux_v3_setup_pad函数,imx_iomux_v3_setup_pad函数通过传入的参数获取三个寄存器的地址和要写入的值,最后将值写入到寄存器中。传入的参数为:
MX6_PAD_UART1_CTS_B__GPIO1_IO18 | MUX_PAD_CTRL(NO_PAD_CTRL) |
我们展开第一个宏定义,在arch/arm/include/asm/arch-mx6/mx6ull_pins.h中:
MX6_PAD_UART1_CTS_B__GPIO1_IO18 = IOMUX_PAD(0x0318, 0x008C, 5, 0x0000, 0, 0), |
再次展开IOMUX_PAD宏,在arch/arm/include/asm/imx-common/iomux-v3.h文件中:
#define IOMUX_PAD(pad_ctrl_ofs, mux_ctrl_ofs, mux_mode, sel_input_ofs, \ sel_input, pad_ctrl) \ (((iomux_v3_cfg_t)(mux_ctrl_ofs) << MUX_CTRL_OFS_SHIFT) | \ ((iomux_v3_cfg_t)(mux_mode) << MUX_MODE_SHIFT) | \ ((iomux_v3_cfg_t)(pad_ctrl_ofs) << MUX_PAD_CTRL_OFS_SHIFT) | \ ((iomux_v3_cfg_t)(pad_ctrl) << MUX_PAD_CTRL_SHIFT) | \ ((iomux_v3_cfg_t)(sel_input_ofs) << MUX_SEL_INPUT_OFS_SHIFT)| \ ((iomux_v3_cfg_t)(sel_input) << MUX_SEL_INPUT_SHIFT)) |
从参数名称可以看出,IOMUX_PAD(0x0318, 0x008C, 5, 0x0000, 0, 0),中的
0x0318是IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器偏移地址;
0x008C是IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器偏移地址;
0x0000是SELECT_INPUT偏移地址,这里是0,说明没有此项寄存器;
其中的mux_mode的值5,即是要设置成IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器的值;
后面第一个0,是设置成SELECT_INPUT的值,这里没有意义;
最后一个参数0表示对该寄存器不做配置,而该寄存器的值由MUX_PAD_CTRL(NO_PAD_CTRL)宏来配置,该宏不再展开看,NO_PAD_CTRL的意思就是,使用寄存器默认的配置参数;
至此,IOMUX寄存器配置值配置完成;
七、输出电平,控制LED
在board_init中通过调用led_init函数,设置GPIO输出低电平,使LED_Y点亮:
gpio_direction_output(IMX_GPIO_NR(1,18), 0); |
按照这四个步骤再将LED_G和LED_R进行初始化配置即可。