IMX6Ull内核移植详细过程讲解


借鉴学长的博客然后加上自己的理解:[内核移植]内核移植过程

  • 开发板介绍:
    IGKBoard(IoT Gateway Kit Board)ARM Linux物联网网关开发板。此开发板基于 NXP i.MX6ULL系列 Cortex-A7 高性能处理器设计。

  • 移植内核版本:

     root@igkboard:~# uname -a
     Linux igkboard 5.15.32 #3 SMP PREEMPT Sun Apr 9 16:17:47 CST 2023 armv7l armv7l armv7l GNU/Linux
    
  • 内核官网: The Linux Kernel Archives


一、安装相应依赖包

在移植 Linux 内核时,需要安装 lzop、libncurses5-dev 和 libssl-dev 这三个包如下:

  • lzopsudo apt-get install lzop 内核编译过程中需要使用到 lzop 压缩工具,以便将内核镜像等文件压缩成 .lzop 格式。
  • libncurses5-devsudo apt-get install libncurses5-dev 内核编译过程中需要使用 ncurses 库,以便在字符终端上显示菜单界面。
  • libssl-devsudo apt-get install libssl-dev 在内核中有一些功能需要使用 OpenSSL 库,例如 TLS 加密协议、数字证书等。

这三个包的安装是为了保证内核编译过程中所需的软件工具和库都具备。如果没有安装这些包,可能会导致在编译内核时出现相关的错误或警告信息。因此,在进行内核移植之前,需要先检查和安装相关的依赖包。


二、下载相应的内核版本库

(1)讲解官网内核分支

Kernel.org 是一个专门用于存储和发布 Linux 内核源代码的网站,也是 Linux 内核最早和最主要的代码托管平台之一。在 Kernel.org 上可以找到各个版本的 Linux 内核源码包以及相应的补丁包。另外,Kernel.org 还提供了内核开发和维护所需的各种工具和资源。

进入官网: The Linux Kernel Archives
在这里插入图片描述

  • Mainline 分支:也称为主线分支,是 Linux 内核开发的主要分支。这里的代码是最新、最先进的,包含了最新的特性、修复和改进。但也因此可能会不够稳定,存在一定的风险。
  • Stable 分支:该分支是针对针对生产环境的 bug 修复版本。一旦主线分支的代码出现问题,就会立刻在 Stable 分支中寻找并修复 bug。稳定版本相对来说比较可靠,但并不包含最新的特性。
  • Longterm 分支:该分支是长期维护版本,保持与主线分支相同的稳定性和实用性,并在此基础上提供长时间的维护支持。适合希望长期稳定运行的企业或组织使用。
  • Linux-next 分支:该分支包含了下一个内核版本的候选代码,也可以视为开发版的分支。优先考虑最新的特性、驱动程序和平台支持,但相较于 Mainline 分支更加不稳定。

所以我们一般选择比较稳定的长期维护的Lingtrem分支下的版本。

(2)下载内核版本库【官网】

点击你想下载的版本库:在这里插入图片描述
在这里插入图片描述
wget命令下载:
在这里插入图片描述
然后就可以看见我们的压缩包文件(我下载的是自己实验室版本的,大家根据自己的版本下载):

wangdengtao@wangdengtao-virtual-machine:~/kernel$ ls
linux-imx  linux-imx.tar.xz

(3)下载内核版本库【NXPgithub】

SOC厂商会从kernel官网下载某一个版本的kernel,然后在这个版本的kernel进行修改。这就是SOC厂商定制版的kernel, NXP官方肯定对i.IMX系列的板子熟悉啊,所以我们要下载的话肯定去NXP官方的github下载比较靠谱。

NXP的官网github下去下载相应的内核版本库:NXP(恩智浦)官方github

当然,这个需要梯子的,不会的可以去先搞一个。

在这里插入图片描述

在这里插入图片描述

都有相应的版本,直接拉下来就可以了。

(4)解压压缩包

要解压 .tar.xz 文件,可以使用 tar 命令行工具和 xz 工具一起进行解压。

如果系统尚未安装 tar 和 xz 工具,可以在 Ubuntu 或 Debian 系统上通过以下命令来安装:sudo apt-get install tar xz-utils

安装完成后,可以使用以下命令来解压 .tar.xz 文件:tar -xf filename.tar.xz

(5)内核目录文件讲解

我们进入解压缩的内核文件夹下,可以看见很多的文件,我们着重讲解一些比较重要的文件夹:

wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx$ ls
arch     CREDITS        fs       Kbuild   LICENSES         mm                       modules.order   samples   System.map  vmlinux
block    crypto         include  Kconfig  MAINTAINERS      modules.builtin          Module.symvers  scripts   tools       vmlinux.o
certs    Documentation  init     kernel   MAINTAINERS.NXP  modules.builtin.modinfo  net             security  usr         vmlinux.symvers
COPYING  drivers        ipc      lib      Makefile         modules-only.symvers     README          sound     virt
  • arch:arch 目录是一个非常重要的目录,其中包含了 Linux 内核所有体系结构相关的代码,每一个体系结构(架构)都有一个相应的子目录。这些子目录包括了体系结构相关的代码、头文件和 Makefile 等。例如,在 arch/x86 这个目录下,存放的是 x86 架构的 CPU、设备驱动、指令集体系结构等代码,而在 arch/arm64 这个目录下则是 arm64 架构的代码和头文件等。
  • block:该目录包含块设备I/O和缓存管理的代码。
  • crypto:该目录包含了加密和 hash 算法的实现。
  • drivers:该目录包含了大部分设备驱动程序的源代码。
  • fs:该目录包含了 Linux 文件系统的代码,包括虚拟文件系统、磁盘文件系统和网络文件系统等。
  • include:该目录包含了内核头文件,为内核提供了各种数据类型与宏定义。
  • init:该目录包含内核启动和初始化代码。
  • kernel:该目录包含了大部分内核的核心功能,例如进程调度、内存管理、时间管理等。
  • mm:该目录包含了内存管理的代码,包括虚拟内存和物理内存的管理。
  • net:该目录包含了网络协议栈的实现。
  • security:该目录包含了 Linux 内核安全子系统的代码。

三、开始内核移植过程

i.MX6ULL是i.MX系列处理器中的一种,其内核移植的具体代码步骤如下:

  1. 下载 i.MX6ULL 平台的开发板原理图、CPU 手册、芯片手册等硬件资料,了解该平台的硬件信息。
  2. 下载适用于 i.MX6ULL 处理器的 Linux 内核源码,并将其解压到本地目录中。
  3. 安装交叉编译工具链,以便针对 i.MX6ULL 处理器进行交叉编译。可使用 Ubuntu 下的 apt-get 工具进行安装,例如:sudo apt-get install gcc-arm-linux-gnueabihf
  4. 使用 make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xxxconfig 命令配置内核选项,包括交叉编译器、CPU架构、驱动程序和文件系统等选项。这里需要根据实际硬件情况进行相应的配置,我们下面会详细讲解。
  5. 编译内核并生成 zImage 和 xxx.dtb 等文件。其中xxx.dtb 文件是设备树文件,需要根据开发板的硬件资料编写并编译。
  6. 将 zImage 和 xxx.dtb 文件拷贝到 TFTP 服务器的目录下。在开发板上启动 U-Boot 并设置启动参数,以便从 TFTP 服务器下载内核并启动。
  7. 启动开发板,观察内核启动过程,确保内核启动成功。如果内核启动失败,则需要检查设备树文件和配置选项是否正确,以及驱动程序是否正确编译和加载。

总体而言,在移植 i.MX6ULL 内核时,需要关注交叉编译工具链、内核选项配置、设备树的编写和使用等方面。需要根据实际硬件情况进行调试和优化。

(1)步骤一、修改默认架构和默认交叉编译器

针对 ARM 架构的处理器进行编译的相关命令,解释一下【ARCH 参数指定了编译的目标处理器架构为 ARM,CROSS_COMPILE 参数指定了交叉编译工具链的路径。】:

make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- distclean
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- xxx_defconfig
make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- -j16

make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- distclean:该命令用于清理之前编译生成的文件,以便重新开始编译。

make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- xxx_defconfig:该命令用于生成配置文件,其中 xxx 表示具体的板子型号或配置文件名称。生成的配置文件包含了编译内核所需的各种选项和参数。如果不指定配置文件,则使用默认的配置。

make ARCH=arm CROSS_COMPILE=/opt/buildroot/cortexA7/bin/arm-linux- -j4:该命令用于编译内核,并指定同时使用的线程数为 4。其中,-j 参数用于指定并发编译的线程数。这样可以加速编译过程,提高编译效率。最终编译成功后,会在当前目录下生成内核镜像、设备树等文件。

总之,这些命令是在 Linux 系统下进行 ARM 架构的内核移植时常用的命令,需要根据具体的情况进行修改和适配。

但是为了方便,不打打这三串这么长的命令,我们需要在根源码目录下修改Makefile(添加下面的代码):

 386 ARCH = arm
 387 CROSS_COMPILE ?= /usr/bin/arm-linux-gnueabihf-

在这里插入图片描述
这里的交叉编译链的路径需要注意:如果你是直接用sudo apt-get install gcc-arm-linux-gnueabihf安装的交叉编译器的话就用我上面的路径,如果不是的话需要自己去找(你自己应该知道在哪儿的)

修改之后我们后面只需要执行下面的三个命令编译内核就可:

make distclean
make xxx_defconfig
make -j4

(2)步骤二、添加需要忽略的文件类型

打开Makefile,添加下面需要在编译过程中忽略的文件类型【有的话就补充,没有的话就添加】:

        -o -name '*.ko.*' \
        -o -name '*.dtbo' \
        -o -name '*.dtb' -o -name '*.dtbo' -o -name '*.dtb.S' -o -name '*.dt.yaml' \
        -o -name '*.dwo' -o -name '*.lst' \
        -o -name '*.su' -o -name '*.mod' \

在这里插入图片描述
解释:

上述的 Makefile 中的代码实现了内核模块的清理功能。在 Linux 内核模块的编译过程中,会生成许多中间文件和最终目标文件,而这些文件在下一次重新编译时可能不再需要,因此需要及时清理以释放磁盘空间。

具体来说,这里使用了 find 命令查找当前目录(如果有外部模块,则查找外部模块目录)中符合特定条件的文件,然后使用 xargs rm 命令删除这些文件。这些条件包括:

  • *.o:内核模块编译后生成的目标文件
  • *.ko:编译后生成的内核模块文件
  • .*.cmd:make 命令执行时生成的编译命令文件
  • *.dtbo 和 *.dtb:设备树和 overlay 配
  • *.dtb.S:通过 dtc 工具从设备树源文件生成的汇编代码文件
  • *.dt.yaml:.dts 原始文件的 YAML 版本
  • *.dwo:编译时生成的 debug 信息文件
  • *.lst:汇编和链接过程中生成的汇编列表文件
  • *.su 和 *.mod:GCC 生成的编译辅助文件,用于支持增量编译和调试
  • .*d 和 .*tmp:编译时生成的临时文件
  • *.mod.c:内核模块生成的 C 源代码文件
  • *.lex.c 和 *.tab.[ch]:用于 lex 和 yacc 工具的中间文件
  • *.asn1.[ch]:ASN.1 编码文件
  • *.symtypes 和 …symversions:用于内核模块版本控制和符号类型管理的文件

通过这些条件,可以删除一些不再需要的中间文件和目标文件,释放磁盘空间。

(3)步骤三、添加设备树以及补丁文件

【1】添加设备树

打开 /arch/arm/boot/dts 添加 igkboard 自己的设备树文件 igkboard.dts 这个设备树文件【直接拿的开头介绍的学长博客中的代码】:

/*
 * Device Tree Source for LingYun IGKBoard(IoT Gateway Kit Board)
 * Based on imx6ul-14x14-evk.dts/imx6ul-14x14-evk.dtsi
 *
 * Copyright (C) 2022 LingYun IoT System Studio.
 * Author: Linke<731253265@qq.com>
 */

/dts-v1/;

#include "imx6ull.dtsi"

/ {
    model = "LingYun IoT System Studio IoT Gateway Board";
	compatible = "fsl,imx6ull-14x14-evk", "fsl,imx6ull";

	chosen {
		stdout-path = &uart1;
	};

	memory@80000000 {
		device_type = "memory";
		reg = <0x80000000 0x20000000>;
	};

	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		linux,cma {
			compatible = "shared-dma-pool";
			reusable;
			size = <0xa000000>;
			linux,cma-default;
		};
	};

	mq2 {
		#address-cells = <1>;
		#size-cells = <1>;
		compatible = "my_mq2";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_mq2>;
		mq2-gpio = <&gpio5 1 GPIO_ACTIVE_LOW>;
		interrupt-parent = <&gpio5>;
		interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
		status = "okay";
	};

	buzzer: pwm-buzzer {
		compatible = "pwm-beeper";
		pwms = <&pwm2 0 500000>;
		status = "okay";
	};

	pxp_v4l2 {
		compatible = "fsl,imx6ul-pxp-v4l2", "fsl,imx6sx-pxp-v4l2", "fsl,imx6sl-pxp-v4l2";
		status = "okay";
	};

	reg_sd1_vmmc: regulator-sd1-vmmc {
		compatible = "regulator-fixed";
		regulator-name = "VSD_3V3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio1 9 GPIO_ACTIVE_HIGH>;
		off-on-delay-us = <20000>;
		enable-active-high;
	};

	reg_peri_3v3: regulator-peri-3v3 {
		compatible = "regulator-fixed";
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_peri_3v3>;
		regulator-name = "VPERI_3V3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
		gpio = <&gpio5 2 GPIO_ACTIVE_LOW>;
		/*
		 * If you want to want to make this dynamic please
		 * check schematics and test all affected peripherals:
		 *
		 * - sensors
		 * - ethernet phy
		 * - can
		 * - bluetooth
		 * - wm8960 audio codec
		 * - ov5640 camera
		 */
		regulator-always-on;
	};

	reg_can_3v3: regulator-can-3v3 {
		compatible = "regulator-fixed";
		regulator-name = "can-3v3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
	};

	reg_vref_adc: regulator@2 {
		compatible = "regulator-fixed";
		regulator-name = "VREF_3V3";
		regulator-min-microvolt = <3300000>;
		regulator-max-microvolt = <3300000>;
	};
};

/*+--------------+
  | Misc Modules |
  +--------------+*/

&snvs_poweroff {
	status = "okay";
};

&snvs_pwrkey {
	status = "okay";
};

&uart1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_uart1>;
	status = "okay";
};

&pwm2 { 
	#pwm-cells = <2>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_pwm2>;
	status = "okay";
};

/*+-------------------+
  | i2c Device Module |
  +-------------------+*/

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";
};

/*+-------------------+
  | iio Device Module |
  +-------------------+*/

&adc1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_adc1>;
	num-channels = <2>;
	vref-supply = <&reg_vref_adc>;
	status = "okay";
};

/*+---------------+
  | Camera Module |
  +---------------+*/

&i2c2 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c2>;
	status = "okay";

	ov5640: ov5640@3c {
		compatible = "ovti,ov5640";
		reg = <0x3c>;
		pinctrl-names = "default";
		pinctrl-0 = <&pinctrl_csi1 &pinctrl_camera_clock>;
		clocks = <&clks IMX6UL_CLK_CSI>;
		clock-names = "csi_mclk";
		csi_id = <0>;
		mclk = <24000000>;
		mclk_source = <0>;
		status = "disabled";
		port {
			ov5640_ep: endpoint {
				remote-endpoint = <&csi1_ep>;
			};
		};
	};

};

&csi {
	status = "disabled";

	port {
		csi1_ep: endpoint {
			remote-endpoint = <&ov5640_ep>;
		};
	};
};

/*+--------------+
  | Audio Module |
  +--------------+*/

&clks {
	assigned-clocks = <&clks IMX6UL_CLK_PLL4_AUDIO_DIV>;
	assigned-clock-rates = <786432000>;
};

/*+------------------+
  | Ethernet Modules |
  +------------------+*/

&fec1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet1>;
	phy-mode = "rmii";
	phy-handle = <&ethphy0>;
	phy-supply = <&reg_peri_3v3>;
	status = "okay";
};

&fec2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_enet2>;
	phy-mode = "rmii";
	phy-handle = <&ethphy1>;
	phy-supply = <&reg_peri_3v3>;
	status = "okay";

	mdio {
		#address-cells = <1>;
		#size-cells = <0>;

		ethphy0: ethernet-phy@0 {
			compatible = "ethernet-phy-id0022.1560";
			reg = <0>;
			micrel,led-mode = <1>;
			clocks = <&clks IMX6UL_CLK_ENET_REF>;
			clock-names = "rmii-ref";

		};

		ethphy1: ethernet-phy@1 {
			compatible = "ethernet-phy-id0022.1560";
			reg = <1>;
			micrel,led-mode = <1>;
			clocks = <&clks IMX6UL_CLK_ENET2_REF>;
			clock-names = "rmii-ref";
		};
	};
};

&can1 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_flexcan1>;
	xceiver-supply = <&reg_can_3v3>;
	status = "okay";
};

&can2 {
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_flexcan2>;
	xceiver-supply = <&reg_can_3v3>;
	status = "okay";
};

/*+---------------+
  | USB interface |
  +---------------+*/

&usbotg1 {
	dr_mode = "otg";
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_usb_otg1>;
	status = "okay";
};

&usbotg2 {
	dr_mode = "host";
	disable-over-current;
	status = "okay";
};

&usbphy1 {
	fsl,tx-d-cal = <106>;
};

&usbphy2 {
	fsl,tx-d-cal = <106>;
};

/*+------------------+
  | USDCHC interface |
  +------------------+*/

&usdhc1 {
	pinctrl-names = "default", "state_100mhz", "state_200mhz";
	pinctrl-0 = <&pinctrl_usdhc1>;
	pinctrl-1 = <&pinctrl_usdhc1_100mhz>;
	pinctrl-2 = <&pinctrl_usdhc1_200mhz>;
	cd-gpios = <&gpio1 19 GPIO_ACTIVE_LOW>;
	keep-power-in-suspend;
	wakeup-source;
	vmmc-supply = <&reg_sd1_vmmc>;
	status = "okay";
};

&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>;
    non-removable;
	bus-width = <8>;
    keep-power-in-suspend;
	wakeup-source;
	status = "okay";
};

/*+----------------------+
  | Basic pinctrl iomuxc |
  +----------------------+*/

&iomuxc {
	pinctrl-names = "default";

	pinctrl_camera_clock: cameraclockgrp {
		fsl,pins = <
			MX6UL_PAD_CSI_MCLK__CSI_MCLK		0x1b088
		>;
	};

	pinctrl_csi1: csi1grp {
		fsl,pins = <
			MX6UL_PAD_CSI_PIXCLK__CSI_PIXCLK	0x1b088
			MX6UL_PAD_CSI_VSYNC__CSI_VSYNC		0x1b088
			MX6UL_PAD_CSI_HSYNC__CSI_HSYNC		0x1b088
			MX6UL_PAD_CSI_DATA00__CSI_DATA02	0x1b088
			MX6UL_PAD_CSI_DATA01__CSI_DATA03	0x1b088
			MX6UL_PAD_CSI_DATA02__CSI_DATA04	0x1b088
			MX6UL_PAD_CSI_DATA03__CSI_DATA05	0x1b088
			MX6UL_PAD_CSI_DATA04__CSI_DATA06	0x1b088
			MX6UL_PAD_CSI_DATA05__CSI_DATA07	0x1b088
			MX6UL_PAD_CSI_DATA06__CSI_DATA08	0x1b088
			MX6UL_PAD_CSI_DATA07__CSI_DATA09	0x1b088
		>;
	};

	pinctrl_enet1: enet1grp {
		fsl,pins = <
			MX6UL_PAD_ENET1_RX_EN__ENET1_RX_EN	0x1b0b0
			MX6UL_PAD_ENET1_RX_ER__ENET1_RX_ER	0x1b0b0
			MX6UL_PAD_ENET1_RX_DATA0__ENET1_RDATA00	0x1b0b0
			MX6UL_PAD_ENET1_RX_DATA1__ENET1_RDATA01	0x1b0b0
			MX6UL_PAD_ENET1_TX_EN__ENET1_TX_EN	0x1b0b0
			MX6UL_PAD_ENET1_TX_DATA0__ENET1_TDATA00	0x1b0b0
			MX6UL_PAD_ENET1_TX_DATA1__ENET1_TDATA01	0x1b0b0
			MX6UL_PAD_ENET1_TX_CLK__ENET1_REF_CLK1	0x4001b031
		>;
	};

	pinctrl_enet2: enet2grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO07__ENET2_MDC		0x1b0b0
			MX6UL_PAD_GPIO1_IO06__ENET2_MDIO	0x1b0b0
			MX6UL_PAD_ENET2_RX_EN__ENET2_RX_EN	0x1b0b0
			MX6UL_PAD_ENET2_RX_ER__ENET2_RX_ER	0x1b0b0
			MX6UL_PAD_ENET2_RX_DATA0__ENET2_RDATA00	0x1b0b0
			MX6UL_PAD_ENET2_RX_DATA1__ENET2_RDATA01	0x1b0b0
			MX6UL_PAD_ENET2_TX_EN__ENET2_TX_EN	0x1b0b0
			MX6UL_PAD_ENET2_TX_DATA0__ENET2_TDATA00	0x1b0b0
			MX6UL_PAD_ENET2_TX_DATA1__ENET2_TDATA01	0x1b0b0
			MX6UL_PAD_ENET2_TX_CLK__ENET2_REF_CLK2	0x4001b031
		>;
	};

	pinctrl_flexcan1: flexcan1grp{
		fsl,pins = <
			MX6UL_PAD_UART3_RTS_B__FLEXCAN1_RX	0x1b020
			MX6UL_PAD_UART3_CTS_B__FLEXCAN1_TX	0x1b020
		>;
	};

	pinctrl_flexcan2: flexcan2grp{
		fsl,pins = <
			MX6UL_PAD_UART2_RTS_B__FLEXCAN2_RX	0x1b020
			MX6UL_PAD_UART2_CTS_B__FLEXCAN2_TX	0x1b020
		>;
	};

	pinctrl_i2c1: i2c1grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO02__I2C1_SCL	0x4001b8b0
			MX6UL_PAD_GPIO1_IO03__I2C1_SDA	0x4001b8b0
		>;
	};	

	pinctrl_i2c2: i2c2grp {
		fsl,pins = <
			MX6UL_PAD_UART5_TX_DATA__I2C2_SCL 0x4001b8b0
			MX6UL_PAD_UART5_RX_DATA__I2C2_SDA 0x4001b8b0
		>;
	};

	pinctrl_lcdif_dat: lcdifdatgrp {
		fsl,pins = <
			MX6UL_PAD_LCD_DATA00__LCDIF_DATA00  0x79
			MX6UL_PAD_LCD_DATA01__LCDIF_DATA01  0x79
			MX6UL_PAD_LCD_DATA02__LCDIF_DATA02  0x79
			MX6UL_PAD_LCD_DATA03__LCDIF_DATA03  0x79
			MX6UL_PAD_LCD_DATA04__LCDIF_DATA04  0x79
			MX6UL_PAD_LCD_DATA05__LCDIF_DATA05  0x79
			MX6UL_PAD_LCD_DATA06__LCDIF_DATA06  0x79
			MX6UL_PAD_LCD_DATA07__LCDIF_DATA07  0x79
			MX6UL_PAD_LCD_DATA08__LCDIF_DATA08  0x79
			MX6UL_PAD_LCD_DATA09__LCDIF_DATA09  0x79
			MX6UL_PAD_LCD_DATA10__LCDIF_DATA10  0x79
			MX6UL_PAD_LCD_DATA11__LCDIF_DATA11  0x79
			MX6UL_PAD_LCD_DATA12__LCDIF_DATA12  0x79
			MX6UL_PAD_LCD_DATA13__LCDIF_DATA13  0x79
			MX6UL_PAD_LCD_DATA14__LCDIF_DATA14  0x79
			MX6UL_PAD_LCD_DATA15__LCDIF_DATA15  0x79
			MX6UL_PAD_LCD_DATA16__LCDIF_DATA16  0x79
			MX6UL_PAD_LCD_DATA17__LCDIF_DATA17  0x79
			MX6UL_PAD_LCD_DATA18__LCDIF_DATA18  0x79
			MX6UL_PAD_LCD_DATA19__LCDIF_DATA19  0x79
			MX6UL_PAD_LCD_DATA20__LCDIF_DATA20  0x79
			MX6UL_PAD_LCD_DATA21__LCDIF_DATA21  0x79
			MX6UL_PAD_LCD_DATA22__LCDIF_DATA22  0x79
			MX6UL_PAD_LCD_DATA23__LCDIF_DATA23  0x79
		>;
	};

	pinctrl_lcdif_ctrl: lcdifctrlgrp {
		fsl,pins = <
			MX6UL_PAD_LCD_CLK__LCDIF_CLK	    0x79
			MX6UL_PAD_LCD_ENABLE__LCDIF_ENABLE  0x79
			MX6UL_PAD_LCD_HSYNC__LCDIF_HSYNC    0x79
			MX6UL_PAD_LCD_VSYNC__LCDIF_VSYNC    0x79
			/* used for lcd reset */
			MX6UL_PAD_SNVS_TAMPER9__GPIO5_IO09  0x79
		>;
	};

	pinctrl_peri_3v3: peri3v3grp {
		fsl,pins = <
			MX6UL_PAD_SNVS_TAMPER2__GPIO5_IO02	0x1b0b0
		>;
	};

	pinctrl_pwm1: pwm1grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO08__PWM1_OUT			0x110b0 
		>;
	};

	pinctrl_pwm7: pwm7grp {
		fsl,pins = <
			MX6UL_PAD_JTAG_TCK__PWM7_OUT	0x110b0
		>;
	};

	pinctrl_pwm8_nbiot: pwm8nbiotgrp {
		fsl,pins = <
			MX6UL_PAD_JTAG_TRST_B__PWM8_OUT	0x110b0
		>;
	};

	pinctrl_spi4: spi4grp {
		fsl,pins = <
			MX6UL_PAD_BOOT_MODE0__GPIO5_IO10	0x70a1
			MX6UL_PAD_BOOT_MODE1__GPIO5_IO11	0x70a1
			MX6UL_PAD_SNVS_TAMPER7__GPIO5_IO07	0x70a1
			MX6UL_PAD_SNVS_TAMPER8__GPIO5_IO08	0x80000000
		>;
	};

	pinctrl_uart1: uart1grp {
		fsl,pins = <
			MX6UL_PAD_UART1_TX_DATA__UART1_DCE_TX 0x1b0b1
			MX6UL_PAD_UART1_RX_DATA__UART1_DCE_RX 0x1b0b1
		>;
	};

	pinctrl_usb_otg1: usbotg1grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO00__ANATOP_OTG1_ID	0x17059
		>;
	};

	pinctrl_usdhc1: usdhc1grp {
		fsl,pins = <
			MX6UL_PAD_SD1_CMD__USDHC1_CMD     	0x17059
			MX6UL_PAD_SD1_CLK__USDHC1_CLK		0x10071
			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 	0x17059
			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 	0x17059
			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 	0x17059
			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 	0x17059
			MX6UL_PAD_UART1_RTS_B__GPIO1_IO19       0x17059 
			MX6UL_PAD_GPIO1_IO05__USDHC1_VSELECT    0x17059 
			MX6UL_PAD_GPIO1_IO09__GPIO1_IO09        0x17059 
		>;
	};

	pinctrl_usdhc1_100mhz: usdhc1grp100mhz {
		fsl,pins = <
			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170b9
			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100b9
			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170b9
			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170b9
			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170b9
			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170b9

		>;
	};

	pinctrl_usdhc1_200mhz: usdhc1grp200mhz {
		fsl,pins = <
			MX6UL_PAD_SD1_CMD__USDHC1_CMD     0x170f9
			MX6UL_PAD_SD1_CLK__USDHC1_CLK     0x100f9
			MX6UL_PAD_SD1_DATA0__USDHC1_DATA0 0x170f9
			MX6UL_PAD_SD1_DATA1__USDHC1_DATA1 0x170f9
			MX6UL_PAD_SD1_DATA2__USDHC1_DATA2 0x170f9
			MX6UL_PAD_SD1_DATA3__USDHC1_DATA3 0x170f9
		>;
	};

	pinctrl_usdhc2: usdhc2grp {
		fsl,pins = <
			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x17059
			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
		>;
	};

	pinctrl_usdhc2_8bit: usdhc2grp_8bit {
		fsl,pins = <
			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x10069
			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x17059
			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x17059
			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x17059
			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x17059
			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x17059
			MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x17059
			MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x17059
			MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x17059
			MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x17059
		>;
	};

	pinctrl_usdhc2_8bit_100mhz: usdhc2grp_8bit_100mhz {
		fsl,pins = <
			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x100b9
			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x170b9
			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170b9
			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170b9
			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170b9
			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170b9
			MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170b9
			MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170b9
			MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170b9
			MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170b9
		>;
	};

	pinctrl_usdhc2_8bit_200mhz: usdhc2grp_8bit_200mhz {
		fsl,pins = <
			MX6UL_PAD_NAND_RE_B__USDHC2_CLK     0x100f9
			MX6UL_PAD_NAND_WE_B__USDHC2_CMD     0x170f9
			MX6UL_PAD_NAND_DATA00__USDHC2_DATA0 0x170f9
			MX6UL_PAD_NAND_DATA01__USDHC2_DATA1 0x170f9
			MX6UL_PAD_NAND_DATA02__USDHC2_DATA2 0x170f9
			MX6UL_PAD_NAND_DATA03__USDHC2_DATA3 0x170f9
			MX6UL_PAD_NAND_DATA04__USDHC2_DATA4 0x170f9
			MX6UL_PAD_NAND_DATA05__USDHC2_DATA5 0x170f9
			MX6UL_PAD_NAND_DATA06__USDHC2_DATA6 0x170f9
			MX6UL_PAD_NAND_DATA07__USDHC2_DATA7 0x170f9
		>;
	};

	pinctrl_spi_uart8: spi_uart8_grp {
		fsl,pins = <
			MX6UL_PAD_LCD_DATA20__ECSPI1_SCLK	0x10b0
			MX6UL_PAD_LCD_DATA22__ECSPI1_MOSI	0x10b0
			MX6UL_PAD_LCD_DATA23__ECSPI1_MISO	0x10b0
			MX6UL_PAD_LCD_DATA21__GPIO3_IO26	0x10b0
		>;
	};	

	pinctrl_mq2: mq2_grp {
		fsl,pins = <
			MX6UL_PAD_SNVS_TAMPER1__GPIO5_IO01 0x17059 
		>;
	};

	pinctrl_pwm2: pwm2grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO09__PWM2_OUT 0x110b0
		>;
	};

	pinctrl_adc1: adc1grp {
		fsl,pins = <
			MX6UL_PAD_GPIO1_IO01__GPIO1_IO01 0xb0
		>;
	};
};

然后修改(添加)这个目录下的Makefile文件:

【定义 igkboard 设备树的编译选项和编译输出目录,并将 igkboard.dtb 添加到设备树文件列表中进行编译。同时,还将 overlays 目录添加到子目录列表中,表示编译完成后需要将该目录下的文件一同输出到内核镜像中】

DTC_FLAGS_igkboard := -@
dtb-$(CONFIG_SOC_IMX6UL) += igkboard.dtb
subdir-$(CONFIG_SOC_IMX6UL) += overlays

在内核的 Makefile 中定义了一个名为 DTC_FLAGS_igkboard 的变量,并将其设置为 -@。之后通过将 igkboard.dtb 添加到 dtb - $ (CONFIG_SOC_IMX6UL) 变量中,表示该设备树二进制文件将会被编译。同时,将 overlays 添加到 subdir-$(CONFIG_SOC_IMX6UL) 变量中,表示该目录下的文件也将会被编译。

具体来说,DTC_FLAGS_igkboard 是一个 DTC 程序(Device Tree Compiler)的编译选项,用于定义 igkboard 设备树的编译参数。其中,-@ 表示禁止 DTC 输出命令行信息。dtb-$ (CONFIG_SOC_IMX6UL) 是一个 Makefile 变量,表示在编译 soc_imx6ul 内核时需要生成的设备树文件列表。igkboard.dtb 是一个 igkboard 设备树的二进制文件,将会添加到设备树文件列表中进行编译。subdir-$ (CONFIG_SOC_IMX6UL) 则是一个 Makefile 变量,表示 soc_imx6ul 内核编译完成后需要生成的子目录列表。在该 Makefile 中,将 overlays 目录添加到 subdir-$(CONFIG_SOC_IMX6UL) 变量中,表示编译完成后需要将该目录下的文件一同输出到内核镜像中。

【2】添加补丁文件

/arch/arm/boot/dts下添加overlays 文件夹,在这个文件夹下的添加的 dts 文件,我们会在之后对其 Makefile 进行修改,并将其编译成 dtbo 文件。
如果对设备树插件不理解的可以参考这篇文章:
GIC中断控制器、设备树插件(Device Tree Overlay)以及内核定时器介绍

wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx/arch/arm/boot/dts/overlays$ cat i2c1.dts
/dts-v1/;
/plugin/;

#include "../imx6ul-pinfunc.h"

/* 40-pin extended GPIO, I2C1 interfaces */

&i2c1 {
	clock-frequency = <100000>;
	pinctrl-names = "default";
	pinctrl-0 = <&pinctrl_i2c1>;
	status = "okay";

	i2c_sht20@40{
		compatible = "imx_i2c_sht20";
		status = "okay";
		reg = <0x40>;
	};
};

&iomuxc {
pinctrl_i2c1: i2c1grp {
				  fsl,pins = <
					  MX6UL_PAD_GPIO1_IO02__I2C1_SCL	0x4001b8b0
					  MX6UL_PAD_GPIO1_IO03__I2C1_SDA	0x4001b8b0
					  >;
			  };	
};

我添加了这一个i2c的设备树插件。
/arch/arm/boot/dts/overlays 文件夹中添加 Makefile 文件,并添加如下内容,用于将该文件下的所有 dts 文件都编译成 dtbo 文件,作为备用,给 igkboard.dtb 打补丁:

# SPDX-License-Identifier: GPL-2.0

# required for overlay support
DTC_FLAGS += -@

dtb-y += i2c1.dtbo

(4)步骤四、添加 defconfig 配置文件

到目录/arch/arm/configs下,将imx_v7_defconfig修改为igkboard_defconfig即可。

【1】/arch/arm/configs

/arch/arm/configs 目录是 Linux 内核代码中专门用于存放 ARM 架构相关的配置文件的目录。在 Linux 内核的构建过程中,这些配置文件可以通过编译器和链接器的指定来生成可执行的内核镜像,并被用于驱动硬件设备和支持各种系统功能。

这些 ARM 架构的配置文件位于 /arch/arm/configs 目录下,以 .config 文件格式存储。这些配置文件通常包含内核构建选项、系统设置、外围设备驱动程序、虚拟文件系统等设置。在进行内核编译时,使用 make ARCH=arm menuconfig 命令可以通过菜单界面对这些选项进行选择和配置。

在 ARM 平台的开发中,使用这些预定义的 ARM 配置文件可以大大加快内核构建的速度,因为这些配置文件已经包含了 ARM 硬件平台的主要特性和功能。同时,这些 ARM 配置文件也为开发者提供了一个模板,可以调整内核的编译选项、功能和驱动程序,以满足特定的需求和限制。

总之,/arch/arm/configs 目录中存储着一些预定义的 ARM 架构配置文件,这些配置文件包含了内核构建选项、系统设置、外围设备驱动程序、虚拟文件系统等设置,可以帮助开发者快速构建适用于特定 ARM 硬件平台的 Linux 内核镜像。

【2】imx_v7_defconfig

imx_v7_defconfig 是 Linux 内核针对 i.MX 系列 ARMv7 处理器的一个默认配置文件。存放位置在 /arch/arm/configs/imx_v7_defconfig

该配置文件包含了内核编译所需的所有选项,以生成适用于 i.MX 系列 ARMv7 处理器的预定义内核二进制镜像。这些选项涵盖了以下方面:

  • CPU 架构和型号(ARMv7 Cortex-A 核心)
  • 内核启动参数(内核命令行等)
  • 内核功能开关(调试信息、内存管理、调度程序、定时器、时钟、IRQ 控制器、访问控制、加密支持、虚拟文件系统等)
  • 文件系统支持(EXT4、FAT、NTFS、SquashFS、JFFS2、UBIFS 等)
  • 块设备驱动程序(MMC/SD/SDIO、NAND、eMMC、SPI NOR 等)
  • 网络驱动程序(有线网卡、Wi-Fi、蓝牙等)
  • 开发者可以通过命令 make ARCH=arm imx_v7_defconfig生成内核配置文件 .config,然后可
  • 使用 make ARCH=arm menuconfig 或其他内核配置工具对其进行修改和优化。之后,运行 make ARCH=arm 即可开始编译 i.MX 系列 ARMv7 处理器的 Linux 内核。

总之,imx_v7_defconfig 是针对 i.MX 系列 ARMv7 处理器的默认内核配置文件,包含了所有内核编译所需的选项。它为开发者提供了一个快速生成适用于 i.MX 系列 ARMv7 处理器的 Linux 内核镜像的方式。


四、编译结果

使用之前提到的命令编译内核:

make distclean
make igkboard_defconfig
make -j4

等待一定的时间之后我们可以在内核源码文件夹下看到 vmlinux 以及 /arch/arm/boot 文件夹下看到 ImagezImage 文件。

对于内核文件,vmlinux 就是最原始的内核文件,但是该文件太大,不利于传输,因此对其进行压缩,这个过程是,先利用 objcopy 取消掉 vmlinux 中的一些信息,比如符号之类的,然后生成 Image 文件,然后用 gzip 工具,对=Image 文件进行压缩,最后生成 zImage 文件,然后将 zImage 烧录到开发板即可。
在这里插入图片描述

wangdengtao@wangdengtao-virtual-machine:~/kernel/linux-imx/arch/arm/boot$ ls
bootp  compressed  deflate_xip_data.sh  dts  Image  install.sh  Makefile  zImage

然后将igkboard.dts和zImage文件放在tftp目录下,tftp网络启动试着启动。
tftp网络启动不会的参考这篇文章:Linux嵌入式uboot使用tftp网络启动加载zImage、设备树


多余:对vlinux的理解:

vmlinux 是 Linux 内核编译成功后生成的一个文件,它是内核代码经过编译、链接后的可执行文件。

在 Linux 内核编译的过程中,内核源代码被先进行预处理、编译、汇编等过程生成目标文件,然后在链接阶段将这些目标文件链接成可执行文件。最终生成的可执行文件就是 vmlinux。

vmlinux 是一个非压缩的 ELF 格式(Executable and Linkable Format)的可执行文件,包含了内核的所有代码和数据。它不同于 bzImage 或 zImage,这两个文件是经过压缩的内核镜像文件,可以直接用于引导启动操作系统。

一般来说,如果用户要将内核文件放到 bootloader 中引导 bootloader 的话,需要将 vmlinux 文件进行压缩处理,然后生成 bzImage 或 zImage 文件。另外,内核开发者也可以通过 objdump 等工具分析 vmlinux 文件,以了解内核代码的结构和实现细节。


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
1. 硬件准备 在移植lwip之前,首先需要准备好硬件环境。IMX6ULL是一款基于ARM Cortex-A7内核的嵌入式处理器,具有高性能、低功耗、高集成度等特点,可以广泛应用于物联网、智能家居、工业控制等领域。 在移植lwip时,需要使用IMX6ULL开发板以及一些外设,如网卡、串口等,具体硬件配置如下: - IMX6ULL开发板:可选评估板或自己设计的板子; - 网卡:推荐使用支持TCP/IP协议栈的网卡,如RTL8111、RTL8168等; - 串口:用于调试和输出信息,需要连接到PC机。 2. 软件准备 在移植lwip之前,需要准备好相关的软件环境。这里推荐使用Linux系统进行开发,具体软件环境如下: - Ubuntu14.04或以上版本的Linux系统; - ARM交叉编译工具链:用于编译和链接程序; - IMX6ULL BSP:包含IMX6ULL芯片的底层驱动程序和相关库; - lwip源代码:从官网下载最新版本的lwip源代码。 3. 移植lwip 移植lwip的过程主要包括以下几个步骤: (1)配置lwip 首先需要配置lwip,使其适配IMX6ULL开发板的硬件环境。这里我们可以使用lwip提供的Makefile来进行配置,具体步骤如下: - 在lwip源代码根目录下执行make menuconfig命令; - 进入配置界面,配置网络接口、协议栈、应用程序等选项; - 保存配置文件并退出。 (2)编写驱动程序 接下来需要编写驱动程序,将lwip的网络数据包与底层网卡进行交互。这里我们可以参考IMX6ULL BSP中的网卡驱动程序,将其修改为适配lwip的形式。 (3)编写应用程序 最后需要编写应用程序,通过lwip协议栈进行网络通信。这里我们可以参考lwip官方提供的示例程序,进行相应的修改和适配。 (4)编译和烧录程序 完成以上步骤后,即可使用ARM交叉编译工具链进行编译和链接,生成可执行文件。最后将可执行文件烧录到IMX6ULL开发板中,即可进行测试和调试。 4. 总结 通过以上步骤,我们就可以成功地在IMX6ULL裸机环境下移植lwip协议栈,并实现网络通信功能。在实际应用中,还可以结合其他外设和功能模块,实现更加丰富的应用场景。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值