【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)

文章目录

  • 0. 引言
  • 1. 开发环境配置
    • 1.1 硬件环境
      • 1.1.1 开发板
      • 1.1.2 网络环境
    • 1.2 软件环境
      • 1.2.1 交叉工具链
        • 1.2.1.1 工具链选择
        • 1.2.1.2 工具链安装
      • 1.2.2 TFTP服务器
        • 1.2.2.1 windows
        • 1.2.2.2 Linux
      • 1.2.3 NFS
    • 1.3 资料选择
  • 2. 编译
    • 2.1 编译uboot
      • 2.1.1 编译指令
      • 2.1.2 Uboot环境变量
    • 2.2 编译内核
      • 2.2.1 编译指令
      • 2.2.2 zImage & uImage 区别
      • 2.2.3 bootm和bootz区别
    • 2.3 根文件系统
    • 2.3.1 编译
    • 2.3.2 格式
    • 2.4 memory分配
  • 3. 开发方式
    • 3.1 调试环境
      • 3.1.1 本地Uboot启动 + TFTP zImage + TFTP dtb + nfs rootfs
      • 3.1.2 本地Uboot启动 + nfs zImage + nfs dtb + nfs rootfs
  • 参考链接

0. 引言

因为之前linux的经验基本都在应用层,内核和驱动这块涉及的不是很多,直接做实验感觉还是有很多不很清楚和没有准备好的地方,在这里做一个总结,更像一个流水账的备忘,也可以帮助同样入门经历的朋友,做一些借鉴吧。
也可能会存在一些错误,对于我来说,也是边收集边验证边总结,请大家不吝指教,后面也会持续更新。
这部分我可能会尽量写的比较细碎,请大神们无视。

1. 开发环境配置

1.1 硬件环境

1.1.1 开发板

开发板用的正点原子 ALTHA 阿尔法 开发板,配置应该是原子主推的一个配置

  • 主控: I.MX6ULL (MCIMX6Y2CVM05AB/MX6Y2CVM05AB)
  • EMMC 8G
  • DDR3 512M
  • 屏幕 【480*272分辨率:RGB接口】正点原子4.3寸RGB电容触摸液晶屏

1.1.2 网络环境

家里有一个不怎么用的笔记本,被我改成了Linux服务器,做了SSH(SFTP)的端口映射到外网,用来做自己的编译服务器(这部分实现可以参见我的 免费内网穿透方案)

  • Ubuntu 服务器在内网的IP是192.168.0.110(有线网卡) 和 192.168.0.111(无线网卡)
    nfs目录是/home/tao/smb/nfs
    tftp目录是/home/tao/smb/tftp
  • windows 开发笔记本是192.168.0.100、192.168.0.101、192.168.0.102
  • 阿尔法开发板被我分在 192.168.0.200 (eth0网卡,开发板ENET2接口)

1.2 软件环境

1.2.1 交叉工具链

1.2.1.1 工具链选择

主要是配置交叉工具链。
这里刚开始遇到一个疑惑,正点原子书《Linux驱动开发指南 v1.0》第四章里是让用 gcc-linaro-4.9.4-2017.01-x86_64_arm-linux-gnueabihf。在《用户快速体验v1.0》,又让用的是arm-poky-linux-gnueabi-。
其实两个编译器,用哪个都可以,但是推荐看什么文档就先用什么编译器。
这个带了poky字眼的编译器,是yocto 编译产生的arm-poky-linux-gnueabi-gcc,可以说是freescale的IMX6平台用的交叉编译

arm-none-linux-gnueabi-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-linux-gnueabihf-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM(32位)系统中所有环节的代码,包括裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
aarch64-linux-gnu-gcc:是由 Linaro 公司基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARMv8 64位目标中的裸机程序、u-boot、Linux kernel、filesystem和App应用程序。
arm-none-elf-gcc:是 Codesourcery 公司(目前已经被Mentor收购)基于GCC推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。
arm-none-eabi-gcc:是 GNU 推出的的ARM交叉编译工具。可用于交叉编译ARM MCU(32位)芯片,如ARM7、ARM9、Cortex-M/R芯片程序。

不同工具链具体对比可以参见结尾的参考链接,不过没有找到poky的说明,倒是觉得
Linaro 的 arm-linux-gnueabihf-gcc 和 aarch64-linux-gnu-gcc基本够用了。
这里我们就用 arm-linux-gnueabihf-gcc

1.2.1.2 工具链安装

这个比较简单,网上教程很多,把下载到的工具链放到一个路径下,添加到环境变量里能找到即可,就像windows下的添加:
【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第1张图片
linux也是一样,不过不是图形化的。
要把交叉工具链的bin路径加到系统中。
【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第2张图片
简单说一下,几个文件的区别:

  1. etc 和 ~ 目录区别

etc下的是公共的配置

  • /etc/bashrc:为每一个运行bash shell的用户执行此文件.当bash shell被打开时,该文件被读取。有些linux版本中的/etc目录下已经没有了bashrc文件。
  • /etc/profile:此文件为系统的每个用户设置环境信息,当第一个用户登录时,该文件被执行.

~下的是个人配置

  • ~/. profile每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,它设置一些环境变量,然后执行用户的.bashrc文件.
  • ~/.bashrc:该文件包含专用于某个用户的bash shell的bash信息,当该用户登录时以及每次打开新的shell时,该文件被读取.
  1. profile 和 bashrc的区别
  • 当shell是交互式登录shell时,读取.bash_profile文件,如在系统启动、远程登录或使用su -切换用户时;
  • 当shell是交互式登录和非登录shell时都会读取.bashrc文件,如:在图形界面中打开新终端或使用su切换用户时,均属于非登录shell的情况。
    . bashrc是在系统启动后就会自动运行。 . profile是在用户登录后才会运行

就我个人,我是直接写在 /etc/profile 下的。

1.2.2 TFTP服务器

有时候要从PC向开发板传输文件,这时候,TFTP用的就比较多。在PC上架一个TFTP的服务器,开发板就可以通过TFTP命令来获取文件。

命令:

//Uboot中,下载zImage到内存0x80800000处(已经配置过severip这个环境变量)
tftp 80800000 zImage

//linux中,下载zImage文件到当前目录
tftp 192.168.0.111 -g -r zImage

1.2.2.1 windows

windows自带了tftp的客户端,服务器可以使用tftpd32软件来实现。

1.2.2.2 Linux

在linux中搭建tftp服务器的步骤网上介绍的很多,就是通过tftp-hpa、tftpd-hpa 和 xinetd来实现。
具体可以参考结尾的参考链接。

  1. 安装方法:
    安装xinetd 和 tftp软件。
sudo apt-get install xinetd
sudo apt-get install tftp-hpa tftpd-hpa

配置各自的配置文件,配置内容参见参考链接。

sudo vi /etc/xinetd.conf
vi /etc/default/tftpd-hpa
  1. 验证方法:
    在Ubuntu服务器输入 netstat -a | grep tftp,出现upd 0 0 *:tftp ,则说明TFTP正常服务。
    在板端测试一下TFTP传输功能。
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第3张图片

1.2.3 NFS

NFS也是一种网络传输文件的常用方法,同时也可以作为根文件系统的挂载方式。
安装方法在结尾的参考链接。

//Uboot 传输文件
nfs [loadAddress] [[hostIPaddr:]bootfilename]
nfs 80800000 192.168.0.110:/home/tao/smb/nfs/zImage 
//挂载根文件系统
root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.0.110:/home/tao/smb/tftp/rootfs ip=192.168.0.200:192.168.0.110:192.168.0.1:255.255.255.0::eth0:off'

1.3 资料选择

目前使用的是原子的阿尔法开发板,配置资料用的是原子的资料包。

  • uBoot & Linux 源码用的是:
    驱动学习:单片夹 arm imx6 正点原子\开发板光盘A-基础资料V1.2\1、例程源码\11、开发板教程对应的uboot和linux源码.zip
    (3/4/11 三个文件夹很绕,就像教程里介绍了不同的交叉工具链一样。)

【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第4张图片

2. 编译

2.1 编译uboot

2.1.1 编译指令

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- mx6ull_14x14_ddr512_emmc_defconfig
make V=1 ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j12

三句话的意思就是:

  1. 清理
  2. 设置配置文件 mx6ull_14x14_ddr512_emmc_defconfig(这个配置文件在 uboot-imxrel_imx_4.1.15_2.1.0_ga_alientek /configs)
  3. 开始编译(12线程)
    其中 v=1 ,就是显示比较全的信息,类似
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第5张图片
    如果是v=2,就是类似CC xxxx 这样的打印。
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第6张图片
    编译结束之后,uboot会在当前目录生成。
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第7张图片
    编译出来的一个uboot.imx 是我们烧录进去的镜像。
    一般都是uboot.bin , imx文件是NXP在IMX6系统中为bin文件加了头。
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第8张图片

2.1.2 Uboot环境变量

Uboot中最重要的环境变量就是bootcmd 和 bootargs。可以说,其他所有的变量都是为这两个变量服务

  • bootcmd 是 uboot会自动运行的命令,主要的流程写在这里
  • bootargs 是 uBoot 传递给内核的命令,挂载之类的功能写在这里。

一些指令

  • && 和 ; 的区别

2.2 编译内核

2.2.1 编译指令

#!/bin/sh
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- distclean
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- imx_v7_defconfig
#make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- all -j16
  1. menuconfig如果报错,还需要安装库支持
  2. 配置文件imx_v7_defconfig在 \arch\arm\configs
  3. 编译出来的文件在
    设备树文件在 linux-imx-4.1.15-2.1.0-g52f6b26-v1.2/arch/arm/boot/dts
    内核文件Image 和 zImage 在 linux-imx-4.1.15-2.1.0-g52f6b26-v1.2/arch/arm/boot
    如果编译完没有生成zImage,则改用单线程编译,看下报错信息。
    【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第9张图片
    如图需要 sudo apt-get install lzop 安装lzop

2.2.2 zImage & uImage 区别

  • Image 编译出来的最原始的内核文件,未压缩。
  • zImage 是vmlinux经过gzip压缩后的文件,使用bootz启动。
  • uImage U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40(64)的tag。在生成的时候,需要添加“LOADADDR=0x8000”。它是在zImage之前加上一个长度为64字节的“头”,说明这个内核的版本、加载位置、生成时间、大小等信息;其0x40之后与zImage没区别,使用bootm启动。

2.2.3 bootm和bootz区别

  • bootm用于加载uImage和ramdisk

bootm ${kernel_load_address} ${ramdisk_load_address} ${devicetree_load_address};

  • bootz用于加载zImage和ext4文件系统

bootz ${kernel_load_address} - ${devicetree_load_address}

2.3 根文件系统

2.3.1 编译

这部分流程比较多,使用busybox的话,就按照《I.MX6U嵌入式Linux驱动开发指南V1.0》第三十八章。
书里的附录也给了buildroot 、 yocto 等方式。

2.3.2 格式

根文件系统有挺多种格式的,这里一开始有点晕的。
jffs2/yaffs/…

  • 文件夹格式:就是正常的文件夹,可以使用nfs挂载。
  • 二进制镜像:jffs2 、yaffs2、ramdisk,用于直接下载到ddr或者flash等等
    对应的格式的文件系统的镜像,比如用mk.jffs2制作成jffs2的镜像,用mkyaffs2image制作成yaffs2的镜像等等
    具体可以看尾部参考链接。
  • 压缩包格式:rootfs.tar.bz2。 可以使用NXP的官方工具来烧录到EMMC
cd rootfs/
tar -vcjf rootfs.tar.bz2

2.4 memory分配

看I.MK6ULL的memory map,0x80000000以上是DDR。
【LINUX】i.MX6学习笔记(2) Linux开发基础知识储备(开发环境 + 编译方式 + 调试环境)_第10张图片

目前使用的是原子自带的系统,
内存分配是

  • zImage 8080 0000
  • dtb 8300 0000

3. 开发方式

3.1 调试环境

目前有这么几种调试方式:

  • 烧到SD卡,从SD卡启动
  • 烧到EMMC,从EMMC启动
  • NFS
  • tftp
  1. uBoot是一定要烧录到本地的(EMMC/SD),Uboot下载一定要通过 mfg 等工具的USB烧到本地的nand或者emmc等存储介质,或者烧到tf卡通过tf卡启动。
  2. rootfs/Image/dtb这些可以通过USB等 和Uboot一样烧录到本地、tf卡,也可以依靠Uboot的功能从nfs启动或者tftp更新到本地
  3. 在EMMC是一篇空白,什么都没有的时候,只能通过芯片自带的USB启动更新功能和mfgtools工具来把最初的uboot等数据烧录进去,才能拥有后面的nfs、tftp等功能。

总结一下:

Uboot zImage dtb rootfs
EMMC
tf卡
tftp X
nfs X
其他

注意:rootfs没法通过TFTP的方式,把压缩包tar.bz2下载到内存某个地址来运行,压缩包我目前只看到mfgtools使用了。

常用的方法主要有:

  1. 本地Uboot启动 + TFTP zImage + TFTP dtb + nfs rootfs
  2. 本地Uboot启动 + nfs zImage + nfs dtb + nfs rootfs

3.1.1 本地Uboot启动 + TFTP zImage + TFTP dtb + nfs rootfs

如果uboot 和 zImage从tftp下载,rootfs从nfs启动

root=/dev/nfs nfsroot=[<server-ip>:]<root-dir>[,<nfs-options>] ip=<client-ip>:<server-ip>:<gwip>:<netmask>:<hostname>:<device>:<autoconf>:<dns0-ip>:<dns1-ip>

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.0.110:/home/tao/smb/tftp/rootfs ip=192.168.0.200:192.168.0.110:192.168.0.1:255.255.255.0::eth0:off'
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000

完整写起来就是

setenv bootcmd 'tftp 80800000 zImage;tftp 83000000 imx6ull-14x14-evk.dtb;bootz 80800000 - 83000000;'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.0.110:/home/tao/smb/tftp/rootfs ip=192.168.0.200:192.168.0.110:192.168.0.1:255.255.255.0::eth0:off'
boot

3.1.2 本地Uboot启动 + nfs zImage + nfs dtb + nfs rootfs

如果需要zImage、dtb、rootfs这些都从nfs启动。
即先通过nfs获取zImage和dtb,然后挂载nfs的文件系统

setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.0.110:/home/tao/smb/nfs/rootfs ip=192.168.0.200:192.168.0.110:192.168.0.1:255.255.255.0::eth0:off'
nfs 80800000 192.168.0.110:/home/tao/smb/nfs/zImage
nfs 83000000 192.168.0.110:/home/tao/smb/nfs/imx6ull-14x14-emmc-4.3-480x272-c.dtb
bootz 80800000 - 83000000

完整写起来就是

setenv bootcmd 'nfs 80800000 192.168.0.110:/home/tao/smb/nfs/zImage;nfs 83000000 192.168.0.110:/home/tao/smb/nfs/imx6ull-14x14-emmc-4.3-480x272-c.dtb;bootz 80800000 - 83000000;'
setenv bootargs 'console=ttymxc0,115200 root=/dev/nfs rw nfsroot=192.168.0.110:/home/tao/smb/nfs/rootfs ip=192.168.0.200:192.168.0.110:192.168.0.1:255.255.255.0::eth0:off'
boot

参考链接

  • ARM交叉编译工具链分类说明
  • TFTP+NFS环境搭建以及TFTP加载内核和设备数,NFS挂载文件系统的方法
  • 嵌入式系统文件系统比较 jffs2, yaffs, cramfs, romfs, ramdisk, ramfs/tmpfs

你可能感兴趣的:(LINUX)