100ASK-IMX6ULL開發板移值NXP官方UBOOT

1. 開發環境

  1. gcc: 100ask_imx6ull-sdk\ToolChain\gcc-linaro-6.2.1-2016.11-x86_64_arm-linux-gnueabihf
  2. uboot: uboot-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
    gcc可以在百問網提供的bsp包找到,uboot使用的是nxp官方的uboot, 點擊下載uboot。本文參考了正點原子的imx6ull左神的uboot移值教程(非常感謝左神的教程)。

2. 在UBOOT中添加自己的開發板

2.1 添加開發板配置文件

configs目錄下創建開發板配置文件,複製configs/mx6ull_14x14_evk_emmc_defconfig並重命名爲mx6ull_100ask_emmc_defconfig,並修改內容爲:

CONFIG_SYS_EXTRA_OPTIONS="IMX_CONFIG=board/freescale/mx6ull_100ask_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK"
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_100ASK_EMMC=y
CONFIG_CMD_GPIO=y

PS:將MX6ULL_EVK_EMMC_REWORK修改爲MX6ULL_100ASK_EMMC_REWORK後,uboot的MMC驅動不能用了,識別不了sd卡和eMMC,不知道爲什麼。

2.2 添加開發板對應的頭文件

在目錄include/configs下添加100ask開發板對應的頭文件,複製include/configs/mx6ullevk.h,並重命名爲mx6ull_100ask_emmc.h,將:

#ifndef __MX6ULLEVK_CONFIG_H
#define __MX6ULLEVK_CONFIG_H

修改爲:

#ifndef __MX6ULL_100ASK_EMMC_CONFIG_H
#define __MX6ULL_100ASK_EMMC_CONFIG_H

2.3 添加開發板對應的板級文件夾

uboot 中每個板子都有一個對應的文件夾來存放板級文件,比如開發板上外設驅動文件等,nxp的imx系列芯片的板級文件夾都存放在board/freescale中,因爲飛思卡爾被nxp收購了,所以文件夾名字是freescale

  1. 複製board/freescale/mx6ullevk文件夾並重命名爲mx6ull_100ask_emmc
  2. board/freescale/mx6ull_100ask_emmc下的mx6ullevk.c重命爲mx6ull_100ask_emmc.c
  3. 修改board/freescale/mx6ull_100ask_emmc下的Makefile文件,將
obj-y  := mx6ullevk.o

修改爲:

obj-y  := mx6ul_100ask_emmc.o

這樣纔會編譯mx6ull_100ask_emmc.c
   4. 修改board/freescale/mx6ull_100ask_emmc下的imximage.cfg 文件,將34行的

PLUGIN	board/freescale/mx6ullevk/plugin.bin 0x00907000

修改爲:

PLUGIN	board/freescale/mx6ull_100ask_emmc/plugin.bin 0x00907000
  1. 修改board/freescale/mx6ull_100ask_emmc目錄下的 Kconfig 文件,修改後內容如下:
if TARGET_MX6ULL_100ASK_EMMC

config SYS_BOARD
	default "mx6ull_100ask_emmc"

config SYS_VENDOR
	default "freescale"

config SYS_CONFIG_NAME
	default "mx6ull_100ask_emmc"

endif
  1. 修改board/freescale/mx6ull_100ask_emmc目錄下的 MAINTAINERS 文件,修改後內容如下:
MX6ULL_100ASK_EMMC BOARD
M:	Peng Fan <peng.fan@nxp.com>
S:	Maintained
F:	board/freescale/mx6ull_100ask_emmc/
F:	include/configs/mx6ull_100ask_emmc.h
F:	configs/mx6ull_100ask_emmc_defconfig

2.4 修改UBOOT圖形界面配置文件

修改文件修改文件arch/arm/cpu/armv7/mx6/Kconfig,在207行加入以下內容:

config TARGET_MX6ULL_100ASK_EMMC
	bool "Support mx6ull_100ask_emmc"
	select MX6ULL
	select DM
	select DM_THERMAL

在endif前加入:

source "board/freescale/mx6ull_100ask_emmc/Kconfig"

2.5 編譯下載測試新添加的開發板

編譯新添加的開發板:

make distclean
make mx6ull_100ask_emmc_defconfig
make -j4

查看串口輸出如下:
uboot輸出
從上圖可看出uboot的LCD和網絡是不能用的,接下來需要修改LCD和網絡驅動。

3. LCD驅動修改

一般uboot的驅動都是在xxx.c和xxx.h中修改,xxx爲板子名稱,比如mx6ull_100ask_emmc.cmx6ull_100ask_emmc.h兩個文件,修改LCD驅動時應注意一下幾點:

  1. LCD所使用的GPIO。
  2. LCD背光控制和RESET引腳。
  3. LCD參數配置。

imx6ull的LCD有固定的引腳,所以只需要修改背光引腳和參數。

3.1 LCD背光和RESET引腳修改

mx6ull_100ask_emmc.c中的第777行可以看出,nxp官方使用的也是GPIO1_IO8來控制LCD背光的,所以不用修改,而RESET引腳在100ask開發板中是接了電阻上拉的,如下圖所示:
在這裏插入圖片描述
這裏的電路應該是上電自動復位,上電後通過電容c18復位一下LCD,所以不需要設置RESET引腳,但是nxp官方使用了LCD的reset引腳,代碼如下:

771 /* Reset the LCD */
772 gpio_direction_output(IMX_GPIO_NR(5, 9) , 0);
773 udelay(500);
774 gpio_direction_output(IMX_GPIO_NR(5, 9) , 1);

直接註釋掉該代碼即可。

3.2 LCD參數配置

由於nxp官方的開發板是不支持100ask的1024x600的屏的,所以需要修改,在mx6ull_100ask_emmc.c中的第780的display_info_t結構體中定義了LCD相關參數:

struct display_info_t const displays[] = {{
	.bus = MX6UL_LCDIF1_BASE_ADDR,
	.addr = 0,
	.pixfmt = 24,
	.detect = NULL,
	.enable	= do_enable_parallel_lcd,
	.mode	= {
		.name			= "TFT43AB",
		.xres           = 480,
		.yres           = 272,
		.pixclock       = 108695,
		.left_margin    = 8,
		.right_margin   = 4,
		.upper_margin   = 2,
		.lower_margin   = 4,
		.hsync_len      = 41,
		.vsync_len      = 10,
		.sync           = 0,
		.vmode          = FB_VMODE_NONINTERLACED
} } };
size_t display_count = ARRAY_SIZE(displays);

其中do_enable_parallel_lcd函數就是lcd的引腳初始化函數,打開LCD背光就是在此函數中完成的。
100ask開發板所使用的LCD爲1024x600,數據手冊路徑:100ask_imx6ull_2020.02.29_v2.0/06_Da
tasheet/Extend_modules/7寸LCD模塊/7.0-13SPEC(7寸1024600TN-RGB).pdf
,查看數據手冊得到參數:
LCD參數修改後的結構體如下:

struct display_info_t const displays[] = {{
	.bus = MX6UL_LCDIF1_BASE_ADDR,
	.addr = 0,
	.pixfmt = 24,
	.detect = NULL,
	.enable	= do_enable_parallel_lcd,
	.mode	= {
		.name			= "TFT7016",
		.xres           = 1024,
		.yres           = 600,
		.pixclock       = 19531,
		.left_margin    = 140,
		.right_margin   = 160,
		.upper_margin   = 20,
		.lower_margin   = 12,
		.hsync_len      = 20,
		.vsync_len      = 3,
		.sync           = 0,
		.vmode          = FB_VMODE_NONINTERLACED
} } };

其中pixclock是像素時鐘,計算方法爲:
1(TH+TV)601012 \frac {1}{(TH+TV)*60}*10^{12}
通過上圖的參數計算出爲19531(單位應該是ps,皮秒(1ns=1000ps)),name修改爲TFT7016,表示7寸,1024x600。最後將mx6ull_100ask_emmc.h中的TFT43AB替換爲TFT7016

3.3 編譯測試修改後的UBOOT

編譯下載並插上LCD後,uboot串口輸出:
uboot輸出
LCD顯示NXP的logo:
在這裏插入圖片描述
如果LCD沒有顯示,查看uboot環境變量panel是否是TFT7016,不是的話修改爲TFT7016重啓測試,還是沒有顯示的話,可能是之前SD/eMMC中有環境變量,所以uboot沒有使用代碼中的環境變量,需要將eMMC/SD完全格式化之後就可以了。格式化可以在uboot中使用mmc erase命令來擦除環境變量:

/*SD卡啓動*/
mmc dev 0
mmc erase 600 10
/*eMMC啓動*/
mmc dev 1
mmc erase 600 10

重啓開發板即可。

3.4 其它修改

mx6ull_100ask_emmc.c中找到checkboard函數,修改如下:

int checkboard(void)
{
	puts("Board: MX6ULL 100ASK EMMC\n");
	return 0;
}

4. 網絡驅動移值

IMX6ULL有兩個網絡外設,分別爲ENET1和ENET2,100ask開發板使用LAN8720A作爲PHY芯片,接在了ENET2上,LAN8720A芯片有一個地址引腳,RXER/PHYAD0,在開發板上接到了高電平,所以LAN8720A的網絡PHY地址爲1,RESET引腳接在了SNVS_TAMPER6上,由於PHY網絡芯片有規定,所有PHY芯片前16個寄存器都是一樣的功能,並且使用這16個寄存器就可以讓網絡正常工作,所以需要修改三個地方:

  1. LAN8720A的PHY網絡地址爲1
  2. RESET引腳
  3. LAN8720A驅動

4.1 網絡PHY地址修改

打開mx6ull_100ask_emmc.h,找到如下代碼:

#define CONFIG_FEC_ENET_DEV		1

該代碼定義了默認使用的ENET,說明使用ENET2,0使用ENET1,緊接着是ENET配置代碼:

#if (CONFIG_FEC_ENET_DEV == 0)
#define IMX_FEC_BASE			ENET_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR          0x2
#define CONFIG_FEC_XCV_TYPE             RMII
#elif (CONFIG_FEC_ENET_DEV == 1)
#define IMX_FEC_BASE			ENET2_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR		0x1
#define CONFIG_FEC_XCV_TYPE		RMII
#endif
#define CONFIG_ETHPRIME			"FEC"

我們使用ENET2,所以設置地址的代碼爲:

#elif (CONFIG_FEC_ENET_DEV == 1)
#define IMX_FEC_BASE			ENET2_BASE_ADDR
#define CONFIG_FEC_MXC_PHYADDR		0x1
#define CONFIG_FEC_XCV_TYPE		RMII
#endif
#define CONFIG_ETHPRIME			"FEC"

nxp默認使用的也是ENET2,所以不用修改。
第345行定義了一個宏:

#define CONFIG_PHY_MICREL

此宏用於使能 uboot 中 Micrel 公司的 PHY驅動,NXP使用的KSZ8081 這顆 PHY 芯片就是 Micrel 公司生產的,如果要使用 LAN8720A,那麼就得將 CONFIG_PHY_MICREL 改爲 CONFIG_PHY_SMSC,也就是使能 uboot 中的 SMSC 公司中的 PHY 驅動,因爲 LAN8720A 就是 SMSC 公司生產的,將該宏修改爲:

#define CONFIG_PHY_SMSC

4.2 刪除uboot 中 74LV595 的驅動代碼,修改RESET引腳

打開mx6ull_100ask_emmc.c,找到如下代碼:

#define IOX_SDI IMX_GPIO_NR(5, 10)
#define IOX_STCP IMX_GPIO_NR(5, 7)
#define IOX_SHCP IMX_GPIO_NR(5, 11)
#define IOX_OE IMX_GPIO_NR(5, 8)

刪除並替換爲:

#define ENET2_RESET IMX_GPIO_NR(5, 6)

因爲SNVS_TAMPER6複用爲IO時是GPIO5_IO6,繼續在 mx6ull_alientek_emmc.c 中找到如下代碼:

static iomux_v3_cfg_t const iox_pads[] = {
	/* IOX_SDI */
	MX6_PAD_BOOT_MODE0__GPIO5_IO10 | MUX_PAD_CTRL(NO_PAD_CTRL),
	/* IOX_SHCP */
	MX6_PAD_BOOT_MODE1__GPIO5_IO11 | MUX_PAD_CTRL(NO_PAD_CTRL),
	/* IOX_STCP */
	MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL),
	/* IOX_nOE */
	MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

該代碼是74lv595的驅動代碼,將其刪除,同理,將iox74lv_init,iox74lv_set函數刪除,將board_init中調用74lv595的代碼刪掉:

	imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));

	iox74lv_init();

4.3 添加100ask開發板網絡復位引腳驅動

mx6ull_100ask_emmc.c中找到如下代碼:

static iomux_v3_cfg_t const fec2_pads[] = {
	MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
	MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
	MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
};

該數組是網絡接口引腳初始化數組,添加復位引腳後:

static iomux_v3_cfg_t const fec2_pads[] = {
	MX6_PAD_GPIO1_IO06__ENET2_MDIO | MUX_PAD_CTRL(MDIO_PAD_CTRL),
	MX6_PAD_GPIO1_IO07__ENET2_MDC | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_TX_DATA0__ENET2_TDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_DATA1__ENET2_TDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 | MUX_PAD_CTRL(ENET_CLK_PAD_CTRL),
	MX6_PAD_ENET2_TX_EN__ENET2_TX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),

	MX6_PAD_ENET2_RX_DATA0__ENET2_RDATA00 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_DATA1__ENET2_RDATA01 | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_EN__ENET2_RX_EN | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_ENET2_RX_ER__ENET2_RX_ER | MUX_PAD_CTRL(ENET_PAD_CTRL),
	MX6_PAD_SNVS_TAMPER6__GPIO5_IO06 | MUX_PAD_CTRL(NO_PAD_CTRL),
};

繼續在mx6ull_100ask_emmc.c中找到setup_iomux_fec函數:

static void setup_iomux_fec(int fec_id)
{
	if (fec_id == 0)
		imx_iomux_v3_setup_multiple_pads(fec1_pads,
						 ARRAY_SIZE(fec1_pads));
	else
		imx_iomux_v3_setup_multiple_pads(fec2_pads,
						 ARRAY_SIZE(fec2_pads));
}

該函數就是通過fec1_pads和fec2_pads數組來初始化ENET引腳,修改後如下:

static void setup_iomux_fec(int fec_id)
{
	if (fec_id == 0)
		imx_iomux_v3_setup_multiple_pads(fec1_pads,
						 ARRAY_SIZE(fec1_pads));
	else
	{
		imx_iomux_v3_setup_multiple_pads(fec2_pads,
						 ARRAY_SIZE(fec2_pads));
		gpio_direction_output(ENET2_RESET, 1); 
		gpio_set_value(ENET2_RESET, 0);  /*復位LAN8720A*/
		mdelay(20);
		gpio_set_value(ENET2_RESET, 1);
	}
}

如果不復位LAN8720A,uboot可能識別不了LAN8720A。

4.4 修改 drivers/net/phy/phy.c 文件中的函數genphy_update_link

該函數的部分代碼如下:

int genphy_update_link(struct phy_device *phydev)
{
	unsigned int mii_reg;

	/*
	 * Wait if the link is up, and autonegotiation is in progress
	 * (ie - we're capable and it's not done)
	 */
	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);

	/*
	 * If we already saw the link up, and it hasn't gone down, then
	 * we don't need to wait for autoneg again
	 */
	if (phydev->link && mii_reg & BMSR_LSTATUS)
		return 0;

修改後:

int genphy_update_link(struct phy_device *phydev)
{
	unsigned int mii_reg;

	static int lan8720_flag = 0;
	int bmcr_reg = 0;
	if (lan8720_flag == 0) {
		bmcr_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR);
		phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, BMCR_RESET);
		while(phy_read(phydev, MDIO_DEVAD_NONE, MII_BMCR) & 0X8000) {
			udelay(100);
		}
		phy_write(phydev, MDIO_DEVAD_NONE, MII_BMCR, bmcr_reg);
		lan8720_flag = 1;
	}

	/*
	 * Wait if the link is up, and autonegotiation is in progress
	 * (ie - we're capable and it's not done)
	 */
	mii_reg = phy_read(phydev, MDIO_DEVAD_NONE, MII_BMSR);

添加的代碼用於將LAN8720A軟件復位一下。
至此uboot的網絡驅動修改完成,可以編譯下載測試了。

4.5 下載測試網絡驅動

下載後uboot輸出:
在這裏插入圖片描述
可以看到Net: FEC1,說明uboot可以識別出LAN8720A了,只是沒有設置IP地址,設置環境變量:

setenv ipaddr 192.168.101.6 //開發板 IP 地址
setenv ethaddr 00:04:9f:04:d2:35 //開發板網卡 MAC 地址
setenv gatewayip 192.168.101.1 //開發板默認網關
setenv netmask 255.255.255.0 //開發板子網掩碼
setenv serverip 192.168.101.5 //服務器地址,也就是 Ubuntu 地址
saveenv //保存環境變量

使用ping命令測試:

ping 192.168.101.5

192.168.101.5是ubuntu的ip地址,也可以是pc的ip地址,輸出如下:

uboot輸出
說明網絡驅動修改成功。可以通過tftp來下載zImage內核試驗一下:

tftp 80800000 zImage

uboot輸出:
uboot輸出
此時就可以通過tftp來加載內核鏡像和設備樹來啓動Linux了。如果使用nfs下載時末尾出現卡頓現象,在主機/etc/hosts文件加入192.168.101.6 /home/book/nfs_rootfs,192.168.101.6是開發板uboot的ip地址, /home/book/nfs_rootfs是主機的nfs目錄。如果u-boot NFS下載文件報錯:Loading: *** ERROR: File lookup fail,導致此錯誤得原因是:uboot中使用得NFS版本爲V2版本,而ubuntu中的NFS版本爲V3,V4及以上版本,從而導致uboot不能再NFS服務器中找到文件,解決方法

5. 設置環境變量自動下載uboot到SD卡(無需插拔SD卡)

在調試uboot時,如果從sd卡啓動,就會頻繁的插拔讀卡器,頻繁重啓開發板,很麻煩,解決方法:uboot網絡調試完成後,可以將調試好的uboot先下載到eMMC中,如果想將uboot下載進sd卡,可以先使用eMMC中的uboot啓動開發板,然後用tftp從ubuntu中將uboot.imx下載到DRAM中,然後利用uboot的mmc write命令將DRAM中的uboot.imx寫入到SD卡,然後從SD卡啓動,這樣就不需要頻繁插拔SD卡和讀卡器了。前提是ubuntu中要安裝好tftp服務,可以設置一個環境變量:

setenv tosd 'tftp 80000000 u-boot.imx; mmc dev 0; mmc write 80000000 2 900'
saveenv

mmc write 80000000 2 900表示將DRAM中0x80000000開始的900個blk(1blk=512byte)寫入sd卡第2個blk開始的地方,因爲uboot.imx是存放在sd卡第1kbyte後的,然後使用run tosd來將uboot下載到sd卡中(使用eMMC中的uboot下載到內存中,然後使用go命令理論上可以,但是我測試的時候初始化mmc後就卡住了,不知道爲什麼,有大神可以解答一下嗎,嘿嘿,不勝感激)。
完整的測試:
編譯完uboot後,執行:

cp u-boot.imx ~/tftpboot

然後在uboot中運行:

run tosd

等待完成即可從sd卡啓動。裸機程序也可使用此方法,但是裸機直接在內存中使用go命令運行應該更方便。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章