第二章 嵌入式Linux开发环境搭建

说实话,搭建开发环境这件事,看着琐碎,但真不能马虎。我见过太多新手,代码写得挺溜,结果卡在环境配置上,一卡就是好几天。这一章,咱们就把这些基础工作捋清楚。

2.1 交叉编译工具链安装

嵌入式设备资源有限,没法直接在板子上编译大型程序。所以我们在PC上编译,生成目标板能运行的二进制文件。这就是交叉编译。

工具链的选择

我个人习惯用Linaro提供的工具链,稳定且社区活跃。以ARM Cortex-A7为例,常用的是gcc-arm-linux-gnueabihf

安装步骤:

  1. 下载工具链:wget https://releases.linaro.org/components/toolchain/binaries/latest-7/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
  2. 解压到指定目录:tar -xvf gcc-linaro-*.tar.xz -C /opt/
  3. 添加环境变量:编辑~/.bashrc,加入export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
  4. 验证安装:arm-linux-gnueabihf-gcc --version

小技巧:我曾经在项目里遇到过工具链版本不匹配的问题,导致编译出来的程序在板子上段错误。后来我养成了一个习惯——每次拿到新板子,先确认官方推荐的工具链版本,再动手安装。省心不少。

2.2 TFTP/NFS服务器配置

开发阶段,频繁烧写文件系统太浪费时间。TFTP和NFS就是用来解决这个问题的。TFTP传内核和设备树,NFS挂载根文件系统。

TFTP服务器配置

说白了,TFTP就是一个轻量级的文件传输协议。我一般在Ubuntu上这样配:

sudo apt-get install tftpd-hpa
sudo mkdir -p /tftpboot
sudo chmod 777 /tftpboot
sudo vim /etc/default/tftpd-hpa

配置文件内容:

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftpboot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"

重启服务:sudo systemctl restart tftpd-hpa

NFS服务器配置

NFS允许开发板通过网络挂载PC上的目录作为根文件系统。调试时改代码、重启,立竿见影。

sudo apt-get install nfs-kernel-server
sudo mkdir -p /nfsroot
sudo chmod 777 /nfsroot
sudo vim /etc/exports

添加一行:

/nfsroot *(rw,sync,no_subtree_check,no_root_squash)

重启服务:sudo systemctl restart nfs-kernel-server

注意:我曾经因为no_root_squash没加,导致开发板上的进程无法以root权限写文件。折腾了半天才发现是权限问题。嗯,这里一定要加上。

2.3 开发板与PC的网络连接

网络连接是开发环境的基础。我建议用静态IP,避免DHCP带来的不确定性。

PC端设置:

  • 有线网卡设置静态IP,比如192.168.1.100
  • 子网掩码255.255.255.0
  • 网关可以不设,或者设成192.168.1.1

开发板端设置(U-Boot中):

setenv ipaddr 192.168.1.200
setenv serverip 192.168.1.100
setenv gatewayip 192.168.1.1
setenv netmask 255.255.255.0
saveenv

测试连通性:在PC上ping 192.168.1.200,在板子上ping 192.168.1.100。能通,就说明网络没问题。

避坑指南:我曾经遇到过网线直连但ping不通的情况。后来发现是PC的防火墙把ICMP包给拦了。关掉防火墙或者加一条规则,问题就解决了。

2.4 SSH与串口终端的使用

开发板跑起来后,我们得有个方式跟它交互。串口是基础,SSH是进阶。

串口终端

串口是嵌入式开发的「生命线」。我用的是minicom或者screen

sudo apt-get install minicom
sudo minicom -s

配置串口参数:

  • 波特率:115200
  • 数据位:8
  • 停止位:1
  • 无校验
  • 硬件流控:关闭

SSH连接

系统启动后,如果网络正常,就可以用SSH登录了。

ssh root@192.168.1.200

第一次连接会提示确认主机密钥,输入yes即可。默认密码一般是root或空密码。

我的习惯:我一般同时开两个终端。一个串口看内核启动日志,一个SSH做日常操作。串口用来排查启动问题,SSH用来传输文件和执行命令。分工明确,效率高。

2.5 文件系统烧录与启动

终于到了让板子跑起来的环节。文件系统烧录,说白了就是把根文件系统镜像写到存储介质上。

烧录方式

常见的有两种:通过SD卡烧录,或者通过网络烧录到NAND/MMC。

SD卡烧录:

  1. 将SD卡插入PC,用lsblk确认设备名(比如/dev/sdb
  2. 使用dd命令写入镜像:sudo dd if=rootfs.ext4 of=/dev/sdb bs=4M status=progress
  3. 同步并卸载:sync && sudo umount /dev/sdb

警告:我曾经有一次不小心把of参数写成了/dev/sda,结果把系统盘给覆盖了。嗯,血的教训。操作前一定再三确认设备名。

网络烧录(通过U-Boot):

如果板子支持网络启动,可以在U-Boot中直接烧录:

tftp 0x82000000 rootfs.ext4
mmc write 0x82000000 0x800 0x2000

这里的0x8000x2000是MMC的起始扇区和扇区数,具体值要看你的分区表。

启动配置

烧录完成后,设置U-Boot的启动参数:

setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rw rootfstype=ext4'
setenv bootcmd 'mmc read 0x82000000 0x800 0x4000; bootz 0x82000000'
saveenv
boot

如果一切顺利,你会看到内核启动日志,最后出现登录提示符。那一刻,成就感满满。

个人经验:第一次启动时,我建议用串口盯着看。如果卡住了,看最后一条日志,十有八九是文件系统路径或者分区号写错了。别慌,改一下U-Boot参数再试。

好了,环境搭建这部分就到这里。这些基础工作虽然繁琐,但做扎实了,后面的开发会顺畅很多。下一章,咱们开始写第一个TBOX应用。