開發(fā)板在上電之后,GPIO都有一個默認初始狀態(tài),這個狀態(tài)可能是高電平也可能是低電平。而我們的應(yīng)用程序在正式接管控制這些GPIO,是在內(nèi)核起來并成功加載根文件系統(tǒng)之后。所以在內(nèi)核啟動的這段時間內(nèi),這些GPIO保持在一種不受控的狀態(tài)。但是我們實際應(yīng)用的時候,可能需要這些GPIO在此階段處于穩(wěn)定的某種狀態(tài),所以我們可以在uboot中設(shè)置此狀態(tài),并一直保持到應(yīng)用成功接管之后。
現(xiàn)在以開發(fā)板主板上三個LED燈為例,講解如何在uboot階段設(shè)置GPIO的電平狀態(tài)。設(shè)置LED燈相關(guān)GPIO電平狀態(tài),一是需要設(shè)置GPIO引腳IOMUX復用功能相關(guān)寄存器,二是要設(shè)置GPIO控制器相關(guān)寄存器,如設(shè)置GPIO為輸出功能,設(shè)置輸出電平高低。
在前面章節(jié)中講了配置一個引腳IOMUX復用功能需要配置三個寄存器:IOMUXC_SW_MUX_CTL_PAD、IOMUXC_SW_PAD_CTL_PAD、SELECT_INPUT。
但是在配置之前我們需要知道,我們將要配置的是哪一個引腳,以LED_Y黃燈為例。
一、確定LED_Y引腳
我們打開硬件原理圖,查找LED_Y,發(fā)現(xiàn)該引腳CPU球號為K15。
然后通過球號K15查找該引腳的名稱PAD NAME。通過查找ELF 1開發(fā)板資料包5-硬件資料5-4 管腳分配表/ ELF 1引腳復用對照表.xlsx,我們知道,K15的PAD NAME為UART1_CTS_B。
二、查看IOMUX相關(guān)寄存器
在ELF 1開發(fā)板資料包5-硬件資料5-2 芯片數(shù)據(jù)手冊IMX6ULLRM手冊中查找引腳PAD NAME為UART1_CTS_B的相關(guān)寄存器,打開參考手冊Chapter 32 IOMUX Controller (IOMUXC)章節(jié),
然后打開IOMUXC Memory Map/Register Definition,可以看到各個引腳按照PAD NAME對應(yīng)的寄存器:
找到UART1_CTS_B對應(yīng)IOMUXC_SW_MUX_CTL_PAD寄存器:
IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B
對應(yīng)的IOMUXC_SW_PAD_CTL_PAD寄存器:
IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B
由于我們使用UART1_CTS_B引腳復用成為GPIO1_IO08,而GPIO1_IO08只能復用到UART1_CTS_B引腳,所以沒有相應(yīng)的SELECT_INPUT寄存器。
打開IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B寄存器的描述:
看到此寄存器地址為0X20E008C。有效位為MUX_MODE[0:3],SION[4]。其中SION是否強制將該引腳復用成為UART1_CTS_B,一般情況下用不到,將其設(shè)置成默認的0即可。
MUX_MODE就是選擇復用模式配置,這里設(shè)置成為0101。所以可設(shè)置0X20E008C值為0x05。
打開IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器的描述:
可以看到該寄存器地址為:0x20E0318。此寄存器很多配置項包括上下拉,驅(qū)動能力等,作為GPIO控制LED燈輸出功能,我們一般不需要做配置,使用默認配置即可。
三、查看GPIO控制器相關(guān)寄存器
在官方參考手冊的28章,有GPIO控制器相關(guān)寄存器說明:
我們主要需要配置的寄存器是GPIOx_DR設(shè)置數(shù)據(jù)寄存器和GPIOx_GDIR設(shè)置輸入輸出方向的寄存器。
四、在uboot代碼中我們設(shè)置寄存器
在文件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)函數(shù)中添加:
imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads));
led_init(); |
五、測試
修改完成之后,編譯uboot,并使用tftp加載到內(nèi)存,然后使用mmc write命令將鏡像燒寫到eMMC Flash。具體的tftp網(wǎng)絡(luò)環(huán)境搭建,請參考之前章節(jié)內(nèi)容。
首先建立編譯腳本:
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ touch build.sh
elf@ubuntu:~/work/elf1_uboot/uboot-imx-2016.03$ vim build.sh |
在腳本中輸入以下內(nèi)容:
#!/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} |
注意:將上面的內(nèi)容復制到開發(fā)環(huán)境中可能會存在格式問題,正確格式內(nèi)容如下圖所示,請參考下圖進行調(diào)整:
給腳本可執(zhí)行權(quán)限:
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 |
在開發(fā)板uboot命令行,使用tftp命令將uboot.imx下載到內(nèi)存:
=>?tftp 80800000 u-boot.imx |
設(shè)置mmc設(shè)備及分區(qū):
=> mmc dev 1 1
switch to partitions #1, OK mmc1(part 1) is current device |
執(zhí)行命令寫入到mmc(該命令的count長度,請根據(jù)uboot.imx實際大小設(shè)置,具體計算方法可參考8.4.3.3 eMMc/SD卡命令章節(jié))
=> mmc write 80800000 2 346
MMC write: dev # 1,block #2, count 838 ... 838 blocks written: OK |
燒寫完成之后,我們執(zhí)行reset命令,重啟:
=> reset |
重啟之后可以看到LED_Y黃燈點亮。
六、代碼說明
下面分析調(diào)用過程,board_init會在commn/board_r.c的初始化序列中調(diào)用。
board_init首先調(diào)用imx_iomux_v3_setup_multiple_pads(led_pads, ARRAY_SIZE(led_pads));
此函數(shù)在arch/arm/imx-common/iomux-v3.c中定義:
該函數(shù)又調(diào)用imx_iomux_v3_setup_pad函數(shù),imx_iomux_v3_setup_pad函數(shù)通過傳入的參數(shù)獲取三個寄存器的地址和要寫入的值,最后將值寫入到寄存器中。傳入的參數(shù)為:
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)) |
從參數(shù)名稱可以看出,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,即是要設(shè)置成IOMUXC_SW_PAD_CTL_PAD_UART1_CTS_B寄存器的值;
后面第一個0,是設(shè)置成SELECT_INPUT的值,這里沒有意義;
最后一個參數(shù)0表示對該寄存器不做配置,而該寄存器的值由MUX_PAD_CTRL(NO_PAD_CTRL)宏來配置,該宏不再展開看,NO_PAD_CTRL的意思就是,使用寄存器默認的配置參數(shù);
至此,IOMUX寄存器配置值配置完成;
七、輸出電平,控制LED
在board_init中通過調(diào)用led_init函數(shù),設(shè)置GPIO輸出低電平,使LED_Y點亮:
gpio_direction_output(IMX_GPIO_NR(1,18), 0); |
按照這四個步驟再將LED_G和LED_R進行初始化配置即可。