前言
主要介绍linux系统的移植,有待完善
一、uboot简介
1.1 uboot命令
①环境变量操作命令:
(1)命令 setenv 用于设置或者修改环境变量的值
(2)命令 saveenv 用于保存修改后的环境变量
②网络操作命令
(1)ping验证是否可以与主机通信
(2)dhcp 用于从路由器获取 IP 地址
(3)通过 nfs 在计算机之间通过网络来分享资源,如:
nfs 80800000 192.168.1.253:/home/sky/linux/nfs/zImage
(4)通过tftp在计算机之间通过网络来分享资源,如:
tftp 80800000 zImage
③ EMMC 和 SD 卡操作命令
④BOOT 操作命令
(1)bootz 命令用于启动 zImage 镜像文件
(2)bootm 用于启动 uImage 镜像文件
(3) boot 会读取环境变量 bootcmd 来启动 Linux 系统,如:
setenv bootcmd ‘tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-7-1024x600-c.dtb; bootz 80800000 - 83000000’
saveenv
boot
1.2 make 命令流程
1.3 bootz 命令执行过程
二、uboot移植
2.1 uboot编译环境搭建
①在 Ubuntu 中安装 ncurses 库,生成基于文本的图形界面
sudo apt-get install build-essential
sudo apt-get install libncurses5-dev
②在 Ubuntu 上搭建 TFTP 服务器(作用类似nfs)
(1)安装服务
sudo apt-get install tftp-hpa tftpd-hpa
sudo apt-get install xinetd
(2)创建文件夹
mkdir /home/zuozhongkai/linux/tftpboot
chmod 777 /home/zuozhongkai/linux/tftpboot
(3)配置tftp
sudo vi /etc/xinetd.d/tftp #输入:
server tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /home/sky/linux/tftpboot/
disable = no
per_source = 11
cps = 100 2
flags = IPv4
}
sudo service tftpd-hpa start(启动 tftp 服务)
(4)修改预设值
sudo vi /etc/default/tftpd-hpa #输入:
#/etc/default/tftpd-hpa
TFTP_USERNAME=“tftp”
TFTP_DIRECTORY=“/home/sky/linux/tftpboot”
TFTP_ADDRESS=“:69”
TFTP_OPTIONS=“-1 -c -s”
sudo service tftpd-hpa restart(重启 tftp 服务器)
(5)赋文件夹权限
cd /home/sky/linux/tftpboot/
chmod 777 zImage
2.2 创建默认配置文件
在configs 目录下,复制 mx6ull_14x14_evk_emmc_defconfig,
cp mx6ull_14x14_evk_emmc_defconfig mx6ull_alientek_emmc_defconfig
并修改内容为:
CONFIG_SYS_EXTRA_OPTIONS=“IMX_CONFIG=board/freescale/mx6ull_alientek_emmc/imximage.cfg,MX6ULL_EVK_EMMC_REWORK”
CONFIG_ARM=y
CONFIG_ARCH_MX6=y
CONFIG_TARGET_MX6ULL_ALIENTEK_EMMC=y
CONFIG_CMD_GPIO=y
2.3 添加开发板对应的头文件
在目录 include/configs 下添加 I.MX6ULL-ALPHA开发板对应的头文件 , 复 制include/configs/mx6ullevk.h,cp mx6ullevk.h mx6ull_alientek_emmc.h并修改宏定义
#ifndef __MX6ULL_ALIENTEK_EMMC_CONFIG_H
2.4 添加开发板对应的板级文件夹
在 board/freescale 目录下,复制 mx6ullevk文件夹将其重命名为 mx6ull_alientek_emmc,命令为:
cp mx6ullevk/ -r mx6ull_alientek_emmc
① 将 其 中 的 mx6ullevk.c 文 件 重 命 名 为mx6ull_alientek_emmc.c:
mv mx6ullevk.c mx6ull_alientek_emmc.c
②修改 mx6ull_alientek_emmc 目录下的 Makefile 文件,第 6 行的 obj-y,改为 mx6ull_alientek_emmc.o,这样才会编译 mx6ull_alientek_emmc.c这个文件
③修改 mx6ull_alientek_emmc 目录下的 imximage.cfg 文件,将PLUGIN改成:
PLUGIN board/freescale/mx6ull_alientek_emmc /plugin.bin 0x00907000
④修改 mx6ull_alientek_emmc 目录下的 Kconfig 文件,改为
if TARGET_MX6ULL_ALIENTEK_EMMC
config SYS_BOARD
default "mx6ull_alientek_emmc"
config SYS_VENDOR
default "freescale"
config SYS_SOC
default "mx6"
config SYS_CONFIG_NAME
default "mx6ull_alientek_emmc"
endif
⑤修改 mx6ull_alientek_emmc 目录下的 MAINTAINERS 文件,改为:
MX6ULL_ALIENTEK_EMMC BOARD
M: Peng Fan <peng.fan@nxp.com>
S: Maintained
F: board/freescale/mx6ull_alientek_emmc/
F: include/configs/mx6ull_alientek_emmc.h
2.5 修改 U-Boot 图形界面配置文件
修改文件arch/arm/cpu/armv7/mx6/Kconfig(如果用的 I.MX6UL 的话,应该修改 arch/arm/Kconfig 这个文件),这样就将自己的开发板名称添加进来,在207行添加:
config TARGET_MX6ULL_ALIENTEK_EMMC
bool "Support mx6ull_alientek_emmc"
select MX6ULL
select DM
select DM_THERMAL
在最后endif前添加:
source "board/freescale/mx6ull_alientek_emmc/Kconfig"
2.6 LCD 驱动修改
①LCD 所使用的 GPIO,查看 uboot 中 LCD 的 IO 配置是否正确。
②LCD 背光引脚 GPIO 的配置。
③LCD 配置参数是否正确
(1)打开文件 mx6ull_alientek_emmc.c,找到类型为 display_info_t,这个结构体是 LCD信息结构体,display_info_t 定义在文件 arch/arm/include/asm/imx-common/video.h 中,pixfmt 是像素格式,如果是 888 的话就是 24 位,一般使用 RGB888。像素时钟31.5MHz,所以 pixclock=(1/31500000)*10^12=31,746,所以将其修改为
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, //HBPD
.right_margin = 160, //HFPD
.upper_margin = 20, //VBPD
.lower_margin = 12, //VFBD
.hsync_len = 20, //HSPW
.vsync_len = 3, //VSPW
.sync = 0,
.vmode = FB_VMODE_NONINTERLACED
} } };
(2)在mx6ull_alientek_emmc.h将panel=TFT43AB改成panel=TFT7016
2.7 网络驱动修改
①修改内容:
(1)ENET1 、ENET2复位引脚初始化。
(2)LAN8720A 的器件 ID(即PHY芯片地址)。
(3)LAN8720 驱动
② PHY 芯片器件地址,打开 mx6ull_alientek_emmc.h
(1)335行修改 ENET1 网络 PHY 的地址
#define CONFIG_FEC_MXC_PHYADDR 0x0
(2)339行修改 ENET2 网络 PHY 的地址
#define CONFIG_FEC_MXC_PHYADDR 0x1
(3)345行使能 SMSC 公司的 PHY 驱动
#define CONFIG_PHY_SMSC
③删除 uboot 中 74LV595 的驱动代码,在 mx6ull_alientek_emmc.c中
(1)删除 uboot 中 74LV595 的复位相关GPIO
#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)
并将其改为ENET1 、ENET2复位引脚:
#define ENET1_RESET IMX_GPIO_NR(5, 7)
#define ENET2_RESET IMX_GPIO_NR(5, 8)
(2)删除74LV595 的 IO 配置参数结构体iomux_v3_cfg_t const iox_pads[],初始化函数 iox74lv_init,和74LV595 的 IO 输出函数iox74lv_set,并且删除板子初始化函数board_init里的下面两行:
imx_iomux_v3_setup_multiple_pads(iox_pads, ARRAY_SIZE(iox_pads));
iox74lv_init();
④添加ENET1 和 ENET2网络复位引脚驱动,在 mx6ull_alientek_emmc.c 中
(1)对 ENET1 和 ENET2 这两个网口的 IO 配置参数,在结构体数组 fec1_pads 里添加:
MX6_PAD_SNVS_TAMPER7__GPIO5_IO07 | MUX_PAD_CTRL(NO_PAD_CTRL)
在fec2_pads 里添加:
MX6_PAD_SNVS_TAMPER8__GPIO5_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
(2)函数 setup_iomux_fec 就是根据 fec1_pads 和 fec2_pads 这两个网络 IO 配置数组来初始化I.MX6ULL 的网络 IO,将这两个 IO 设置为输出并且硬件复位一下 LAN8720A:
static void setup_iomux_fec(int fec_id)
{
if (fec_id == 0)
{
imx_iomux_v3_setup_multiple_pads(fec1_pads,
ARRAY_SIZE(fec1_pads));
gpio_direction_output(ENET1_RESET, 1);
gpio_set_value(ENET1_RESET, 0);
mdelay(100);
gpio_set_value(ENET1_RESET, 1);
}
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);
mdelay(100);
gpio_set_value(ENET2_RESET, 1);
}
}
⑤修改 drivers/net/phy/phy.c 文件中的函数 genphy_update_link,此函数用于更新 PHY 的连接状态和速度
#ifdef CONFIG_PHY_SMSC
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;
}
#endif
2.8 修改uboot启动板子名字
打开文件 mx6ull_alientek_emmc.c,找到函数checkboard
int checkboard(void)
{
if (is_mx6ull_9x9_evk())
puts("Board: MX6ULL 9x9 EVK\n");
else
puts("Board: MX6ULL ALIENTEK EMMC\n");
return 0;
}
2.9 bootcmd 和 bootargs 环境变量
文 件 mx6ull_alientek_emmc.h 中的宏CONFIG_EXTRA_ENV_SETTINGS 保存着这些环境变量的默认值
①bootcmd 保存着 uboot 默认命令,uboot 倒计时结束以后就会执行 bootcmd 中的命令,这些命令一般都是用来启动 Linux 内核的,我们可以在mx6ull_alientek_emmc.h 文件中通过设置宏 CONFIG_BOOTCOMMAND 来设置 bootcmd 的默认值,如:
#define CONFIG_BOOTCOMMAND \
"mmc dev 1;" \
"fatload mmc 1:1 0x80800000 zImage;" \
"fatload mmc 1:1 0x83000000 imx6ull-alientek-emmc.dtb;" \
"bootz 0x80800000 - 0x83000000;"
②bootargs 保存着 uboot 传递给 Linux 内核的参数,bootargs 环境变量是由 mmcargs 设置:
mmcargs=setenv bootargs console=${console},${baudrate} root=${mmcroot}
2.10 uboot 启动 Linux 测试
①编译uboot
(1)在uboot根目录下编写mx6ull_alientek_emmc.sh 脚本,内容如下:
#!/bin/bash
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #打开图形化界面
make V=0 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j16
(2)或者在顶层Makefile里249行下面添加,来减少命令
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
(3)编译好后查 看一下添加的mx6ull_alientek_emmc.h 这个头文件有没有引用,可以使用命令:
grep -nR "mx6ull_alientek_emmc.h"
(4)下载到SD卡:
chmod 777 imxdownload
./imxdownload u-boot.bin /dev/sdb
②在uboot里配置启动方式环境变量,并使用boot命令启动,复位后按回车键回uboot
(1)从 EMMC 启动 Linux 系统
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'mmc dev 1; fatload mmc 1:1 80800000 zImage; fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000;'
saveenv
(2)从网络启动 Linux 系统
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-14x14-emmc-4.3-800x480-c.dtb; bootz 80800000 - 83000000'
saveenv
③修改LCD环境变量:
setenv panel TFT7016
saveenv
④设置网络环境变量
setenv ipaddr 192.168.31.55
setenv ethaddr b8:ae:1d:01:00:00
setenv gatewayip 192.168.31.1
setenv netmask 255.255.255.0
setenv serverip 192.168.31.141
saveenv
三、Linux 内核移植
3.1 添加开发板默认配置文件
将 arch/arm/configs 目 录 下 的 imx_v7_mfg_defconfig 重 新 复 制 一 份 , 命 名 为imx_alientek_emmc_defconfig,之后就可以使用make imx_alientek_emmc_defconfig配置
cp imx_v7_mfg_defconfig imx_alientek_emmc_defconfig
3.2 添加开发板对应的设备树文件
①进入目录 arch/arm/boot/dts 中,复制 imx6ull-14x14-evk.dts,然后将其重命名为 imx6ull-alientek-emmc.dts,.dts 是设备树源码文件,编译 Linux 的时候会将其编译为.dtb 文件
cp imx6ull-14x14-evk.dts imx6ull-alientek-emmc.dts
②修改文件arch/arm/boot/dts/Makefile ,找到“dtb-$(CONFIG_SOC_IMX6ULL)”配置项,在此配置项中加入“imx6ull-alientek-emmc.dtb”
3.3 CPU 主频修改
当前 CPU 支持 198MHz、396MHz、528Mhz 和 792MHz 四种频率切换,想让 CPU 一直工作在 792MHz
①配置 Linux 内核,将调频策略 scaling_governor选择为 performance
②修改imx_alientek_emmc_defconfig为:
#CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND=y
CONFIG_CPU_FREQ_GOV_ONDEMAND=y
③过图形化界面配置 Linux 内核的 CPU 调频策略,输入“make menuconfig”
CPU Power Management
-> CPU Frequency scaling
-> Default CPUFreq governor
3.4 使能 8 线 EMMC 驱动
Linux 内核驱动里面 EMMC 默认是 4 线模式的,正点原子 EMMC 版本核心板上的 EMMC 采用的 8 位数据线,打开文件 imx6ull-alientek-emmc.dts,在linux根目录下使用命令“make dtbs”重新编译设备树
&usdhc2 {
pinctrl-names = "default", "state_100mhz", "state_200mhz";
pinctrl-0 = <&pinctrl_usdhc2_8bit>;
pinctrl-1 = <&pinctrl_usdhc2_8bit_100mhz>;
pinctrl-2 = <&pinctrl_usdhc2_8bit_200mhz>;
bus-width = <8>;
non-removable;
status = "okay";
};
3.5 修改网络驱动
打开设备树文件 imx6ullalientek-emmc.dts
①修改 LAN8720 的复位以及网络时钟引脚驱动
(1)在pinctrl_spi4: spi4grp里删掉初始化 SNVS_TAMPER7 和 SNVS_TAMPER8 引脚
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x70a1
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x80000000
(2)在spi4里删掉GPIO5_IO07 和 GPIO5_IO08 功能引脚,与 ENET1 和 ENET2 的复位引脚冲突:
pinctrl-assert-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
cs-gpios = <&gpio5 7 0>;
(3)在iomuxc_snvs函数里,imx6ul-evk{}中添加 ENET1 和 ENET2网络复位引脚信息:
pinctrl_enet1_reset: enet1resetgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER7__GPIO5_IO07 0x10B0
>;
};
pinctrl_enet2_reset: enet2resetgrp {
fsl,pins = <
MX6ULL_PAD_SNVS_TAMPER8__GPIO5_IO08 0x10B0
>;
};
(4)在pinctrl_enet1: enet1grp里修改一下 ENET1 和 ENET2 的网络时钟引脚配置
MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1 0x4001b009
MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2 0x4001b009
②修改 fec1 和 fec2 节点的 pinctrl-0 属性找到名为“fec1”和“fec2”的这两个节点,修改其中的“pinctrl-0”属性值,修改 LAN8720A 的 PHY 地址0x0和0x1
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1
&pinctrl_enet1_reset>;
phy-mode = "rmii";
phy-handle = <ðphy0>;
phy-reset-gpios = <&gpio5 7 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
};
&fec2 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet2
&pinctrl_enet2_reset>;
phy-mode = "rmii";
phy-handle = <ðphy1>;
phy-reset-gpios = <&gpio5 8 GPIO_ACTIVE_LOW>;
phy-reset-duration = <200>;
status = "okay";
mdio {
#address-cells = <1>;
#size-cells = <0>;
ethphy0: ethernet-phy@0 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <0>;
};
ethphy1: ethernet-phy@1 {
compatible = "ethernet-phy-ieee802.3-c22";
reg = <1>;
};
};
};
④修改 fec_main.c 文件, 打开drivers/net/ethernet/freescale/fec_main.c,找到函数 fec_probe,在3452行添加代码:
/*设置 MX6UL_PAD_ENET1_TX_CLK 和 MX6UL_PAD_ENET2_TX_CLK这
两个 IO 的复用寄存器的 SION 位为 1。*/
void __iomem *IMX6U_ENET1_TX_CLK;
void __iomem *IMX6U_ENET2_TX_CLK;
IMX6U_ENET1_TX_CLK = ioremap(0X020E00DC, 4);
writel(0X14, IMX6U_ENET1_TX_CLK);
IMX6U_ENET2_TX_CLK = ioremap(0X020E00FC, 4);
writel(0X14, IMX6U_ENET2_TX_CLK);
⑤配置 Linux 内核,使能 LAN8720 驱动输入命令“make menuconfig”,打开图形化配置界面”
-> Device Drivers
-> Network device support
-> PHY Device support and infrastructure
-> Drivers for SMSC PHYs
使能了 LAN8720A 的驱动,会在.config中存在如下代码:CONFIG_SMSC_PHY=y,当我们执行“make clean”清理工程以后.config 文件就会被删除掉,保存.config 文件方法:
(1)直接将.config 文件另存为 imx_alientek_emmc_defconfig,然后将其复制到 arch/arm/configs 目录下,替换以前的imx_alientek_emmc_defconfig
(2)通过图形界面保存配置文件
General setup->Save->输入“arch/arm/configs/imx_alientek_emmc_defconfig”->OK
⑥设置 LAN8720A 的 BMCR寄存器 bit15 为 1,所以在 Linux 中也需要对 LAN8720A 进行一次软复位,修改 LAN8720A 的驱动文件是 drivers/net/phy/smsc.c:
(1)添加头文件
#include <linux/of_gpio.h>
#include <linux/io.h>
(2)修改此文件中有个叫做 smsc_phy_reset 的函数
static int smsc_phy_reset(struct phy_device *phydev)
{
int err, phy_reset;
int msec = 1;
struct device_node *np;
if(phydev->addr == 0) /* FEC1 */ {
np = of_find_node_by_path("/soc/aips-bus@02100000/ethernet@02188000");
if(np == NULL) {
return -EINVAL;
}
}
if(phydev->addr == 1) /* FEC2 */ {
np = of_find_node_by_path("/soc/aips-bus@02000000/ethernet@020b4000");
if(np == NULL) {
return -EINVAL;
}
}
err = of_property_read_u32(np, "phy-reset-duration", &msec);
/* A sane reset duration should not be longer than 1s */
if (!err && msec > 1000)
msec = 1;
phy_reset = of_get_named_gpio(np, "phy-reset-gpios", 0);
if (!gpio_is_valid(phy_reset))
return;
gpio_direction_output(phy_reset, 0);
gpio_set_value(phy_reset, 0);
msleep(msec);
gpio_set_value(phy_reset, 1);
int rc = phy_read(phydev, MII_LAN83C185_SPECIAL_MODES);
if (rc < 0)
return rc;
/* If the SMSC PHY is in power down mode, then set it
* in all capable mode before using it.
*/
if ((rc & MII_LAN83C185_MODE_MASK) == MII_LAN83C185_MODE_POWERDOWN) {
/* set "all capable" mode and reset the phy */
rc |= MII_LAN83C185_MODE_ALL;
phy_write(phydev, MII_LAN83C185_SPECIAL_MODES, rc);
}
phy_write(phydev, MII_BMCR, BMCR_RESET);
/* wait end of reset (max 500 ms) */
int timeout = 50000;
do {
udelay(10);
if (timeout-- == 0)
return -1;
rc = phy_read(phydev, MII_BMCR);
} while (rc & BMCR_RESET);
return 0;
}
3.6 Linux 内核编译
①Ubuntu下Linux 内核编译环境搭建(LZO 压缩库的压缩软件):
sudo apt-get install lzop
②解压缩Linux 内核:
tar -vxjf linux-imx-rel_imx_4.1.15_2.1.0_ga.tar.bz2
③修改顶层Makefile
ARCH ?= arm
CROSS_COMPILE ?= arm-linux-gnueabihf-
④编写编译脚本imx6ull_alientek_emmc.sh
#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_alientek_emmc_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig #图形化配置可删
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
⑤并将以下生成文件复制到tftpboot文件夹里
(1)Linux 内核镜像文件,在 arch/arm/boot/zImage。
(2)NXP 官方 I.MX6ULL EVK 开发板对应的设备树文件(使用make dtbs可以单独将.dts文件编译成.dtb文件),在 arch/arm/boot/dts/imx6ull-alientek-emmc.dtb
⑥在uboot 命令模式中使用 tftp 命令下载这两个文件并启动下载
tftp 80800000 zImage
tftp 83000000 imx6ull-alientek-emmc.dtb
bootz 80800000 - 83000000
⑦给两个网卡配置 IP 地址
ifconfig eth0 192.168.31.251
ifconfig eth1 192.168.31.252
四、根文件系统BusyBox的构建
4.1 修改 Makefile,添加编译器
CROSS_COMPILE ?= /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/bin/arm-linux-gnueabihf-
ARCH ?= arm
4.2 busybox 中文字符支持
①打开文件 busybox-1.29.0/libbb/printable_string.c,找到函数 printable_string
(1)/注释掉 if (c >= 0x7f)
break;/
(2)将if (c < ’ ’ || c >= 0x7f) 改为if( c < ’ ')
②打开文件 busybox-1.29.0/libbb/unicode.c,找函数unicode_conv_to_printable2
(1)将d++ = (c >= ’ ’ && c < 0x7f) ? c : ‘?’;改为d++ = (c >= ’ ') ? c : ‘?’;
(2)将if (c < ’ ’ || c >= 0x7f)改为if(c < ’ ')
4.3 配置 busybox
①make defconfig(默认配置)和make menuconfig(图形配置)
(1)选项“Build static binary (no shared libs)”用来决定是静态编译 busybox 还是动态编译,静态编译的话就不需要库文件,但是编译出来的库会很大,所以不要选中
Location:
-> Settings
-> Build static binary (no shared libs)
(2)-> Settings
-> vi-style line editing commands(设置*)
(3)-> Linux Module Utilities
-> Simplified modutils(取消勾选)
(4)使能 busybox 的 unicode 编码以支持中文
-> Settings
-> Support Unicode //选中
-> Check $ LC_ALL, $ LC_CTYPE and $ LANG environment variables //选中
②编译 busybox,并指定编译结果的存放目录
make #编译
make install CONFIG_PREFIX=/home/sky/linux/nfs/rootfs
4.4 向根文件系统添加 lib 库
①向 的“/lib”目录添加库文件
mkdir lib dev proc mnt sys tmp root
cd lib/usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/lib/ -d
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/lib/ -d
由于rootfs /lib里的ld-linuxarmhf.so.3 是快捷方式不能作为符号链接,故重新复制:
rm ld-linux-armhf.so.3
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/lib
cp ld-linux-armhf.so.3 /home/sky/linux/nfs/rootfs/lib/
②向 rootfs 的“usr/lib”目录添加库文件
mkdir usr/lib
cd /usr/local/arm/gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf/arm-linux-gnueabihf/libc/usr/lib
cp *so* *.a /home/sky/linux/nfs/rootfs/usr/lib/ -d
4.5 在 rootfs 中创建/etc配置文件
①创建/etc/init.d/rcS 文件,内容如下:
#!/bin/sh
PATH=/sbin:/bin:/usr/sbin:/usr/bin:$PATH
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/lib:/usr/lib
export PATH LD_LIBRARY_PATH
mount -a
mkdir /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
②在 rootfs 中创建/etc/fstab ,fstab 在 Linux 开机以后自动配置哪些需要自动挂载的分区:
#<file system> <mount point> <type> <options> <dump> <pass>
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
③创建/etc/inittab 文件:
(1)格式:< id>:< runlevels>:< action>:< process>
< id>:每个指令的标识符,不能重复。但是对于 busybox 的 init 来说,有着特殊意义。对于 busybox 而言< id>用来指定启动进程的控制 tty,一般我们将串口或者 LCD 屏幕设置为控制 tty。
< runlevels>:对 busybox 来说此项完全没用,所以空着。
< process>:具体的动作,比如程序、脚本或命令等。
< action>:用于指定< process>可能用到的动作。busybox 支持的动作如表所示:
(2)参考 busybox 下的文件 examples/inittab创建一个/etc/inittab
#etc/inittab
::sysinit:/etc/init.d/rcS
console::askfirst:-/bin/sh
::restart:/sbin/init
::ctrlaltdel:/sbin/reboot
::shutdown:/bin/umount -a -r
::shutdown:/sbin/swapoff -a
4.6 根文件系统的功能测试
①重新设置 uboot里bootargs 环境变量的 root 值,使用boot命令启动linux内核
setenv bootcmd 'tftp 80800000 zImage; tftp 83000000 imx6ull-alientek-emmc.dtb; bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs nfsroot=192.168.31.141:/home/sky/linux/nfs/rootfs,proto=tcp rw ip=192.168.31.50:192.168.31.141:192.168.31.1:255.255.255.0::eth0:off'
saveenv
②软件运行测试
将编译生成的可执行文件拷贝到 rootfs/drivers 目录下,终端输入如下命令:
cd /drivers #进入 drivers 目录
./hello & #执行 hello, &就是让 hello 在后台运行
ps #查看软件PID
kill -9 pid #关闭运行
③开机启动测试,在/etc/init.d/rcS 这个 shell 脚本添加:
#开机自启动
cd /drivers
./hello &
cd /
④外网连接测试,在 rootfs 中新建文件/etc/resolv.conf,然后在里面输入如下内容:
nameserver 114.114.114.114
nameserver 192.168.31.1
五、系统烧写
5.1 MfgTool 工作过程
①将 firmware 目录中的 uboot、linux kernel 和.dtb(设备树),然后通过 USB OTG 将这个文件下载到开发板的 DDR 中,目的就是在 DDR 中启动 Linux 系统,为后面的烧写做准备。
②经过第①步的操作,此时 Linux 系统已经运行起来了,系统运行起来以后就可以很方便的完成对 EMMC 的格式化、分区等操作。EMMC 分区建立好以后就可以从 files 中读取要烧写的 uboot、linux kernel、.dtb(设备树)和 rootfs 这 4 个文件,然后将其烧写到 EMMC 中,这个就是 MfgTool 的大概工作流程。
5.2 OS Firmware目录下文件简介
在L4.1.15_2.0.0-ga_mfg-tools/mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware目录下:
①firmeare 文件夹(第一阶段)
②files 文件夹
③ucl2.xml 文件
files 和 firmware 目录下有众多的 uboot 和设备树,那么烧写的时候究竟选择哪一个呢?这个工作就是由 ucl2.xml 文件来完成的。ucl2.xml 首先会判断当前要向 I.MX 系列的哪个芯片烧写系统,确定了处理器以后就要确定向什么存储设备烧写系统,这个时候就要有请 mfgtool2-yocto-mx-evk-emmc.vbs 再次登场
5.3 系统烧写
①备好原材料u-boot.imx、 zImage 镜像文件和开发板对应的.dtb(设备树)imx6ull-alientek-emmc.dtb、根文件系统 rootfs压缩打包
②将上面四个文件重命名
③先将图中的 zImage、u-bootimx6ull14x14evk_emmc.imx 和 zImage-imx6ull-14x14-evk-emmc.dtb 这三个文件拷贝到 mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware/firmware 目录中,替换掉原来的文件
④将4 个文件都拷贝到 mfgtools-with-rootfs/mfgtools/Profiles/Linux/OS Firmware/files目录中
5.4 网络开机自启动
设置ifconfig eth0 up,或者设置网卡 IP 地址的命令添加到/etc/init.d/rcS 文件中就行
#网络开机自启动设置
ifconfig eth0 up
#udhcpc -i eth0
ifconfig eth0 192.168.31.251 netmask 255.255.255.0
route add default gw 192.168.31.1
5.5 烧写 NXP 官方系统
①连接好 USB,拨码开关拨到 USB 下载模式。
②弹出 TF 卡,然后按下开发板复位按键。
③双击“mfgtool2-yocto-mx-evk-emmc.vbs”,打开下载软件,如果出现“符合 HID 标准的供应商定义设备”等字样就说明下载软件已经准备就绪。点击“Start”按钮开发烧写 NXP 官方系统,好了之后Stop然后退出
5.6 解决 Linux 内核启动失败
①重新设置 bootcmd 环境变量值
setenv bootcmd 'mmc dev 1;fatload mmc 1:1 80800000 zImage;fatload mmc 1:1 83000000 imx6ull-alientek-emmc.dtb;bootz 80800000 - 83000000'
setenv bootargs 'console=ttymxc0,115200 root=/dev/mmcblk1p2 rootwait rw'
saveenv
②修改 uboot 源码
打开 uboot 源码中的文件include/configs/mx6ull_alientek_emmc.h,在宏 CONFIG_EXTRA_ENV_SETTINGS 中findfdt 的值修改为:
"findfdt="\
"if test $fdt_file = undefined; then " \
"setenv fdt_file imx6ull-alientek-emmc.dtb; " \
"fi;\0" \