2、调试环境搭建:交叉编译工具链配置、内核源码树准备、NFS/TFTP网络启动环境搭建、串口终端(minicom/Putty)设置、逻辑分析仪与示波器基础操作

调试环境搭建,说白了就是给你的开发板配齐「吃饭的家伙」。我见过太多新手,代码写得挺溜,结果卡在环境配置上好几天。其实这步搞定了,后面调试会顺很多。

2.1 交叉编译工具链配置

机顶盒芯片大多是 ARM 或 MIPS 架构,你的 PC 是 x86 架构。所以你得用交叉编译工具链——在 PC 上编译出能在机顶盒上跑的程序。

工具链的选择,我一般看芯片厂商的 SDK 里带了什么。比如海思的 HiLinux、晶晨的 Android 源码包,里面都有现成的工具链。我个人习惯用 Linaro 的 GCC 工具链,稳定且社区活跃。

配置步骤:

  1. 下载对应架构的工具链(arm-linux-gnueabihf- 或 mips-linux-gnu-)
  2. 解压到 /opt/toolchains/ 目录
  3. 添加环境变量到 ~/.bashrc
export PATH=$PATH:/opt/toolchains/gcc-arm-8.3-2019.03-x86_64-arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm

配置完记得 source ~/.bashrc。然后跑一下 arm-linux-gnueabihf-gcc --version,看到版本号就说明成了。

小技巧:我曾经在某个项目里,工具链版本和内核版本不匹配,编译出来的驱动模块 insmod 时直接报错。后来发现是 GCC 版本太新,内核头文件不兼容。建议用芯片厂商推荐的工具链版本,别盲目追新。

2.2 内核源码树准备

驱动调试离不开内核源码树。说白了,就是你要编译驱动模块,得有内核的头文件和 Makefile 结构。

两种常见做法:

  • 完整内核源码:从芯片厂商拿到内核包,解压后配置编译一遍。这样最保险,但耗时长。
  • 仅内核头文件:如果只是调试驱动模块,可以只安装内核头文件包。但要注意版本必须完全一致。

我一般用第一种。拿到源码后,先配置内核:

make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- xxx_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- menuconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- zImage -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules -j4

编译完内核和模块后,把 arch/arm/boot/zImagearch/arm/boot/dts/ 下的设备树文件拷贝出来备用。

注意:内核源码树路径不要有中文或空格。我见过有人把源码放在「我的文档」里,结果编译时各种奇葩错误。老老实实用 /home/user/kernel/ 这种路径。

2.3 NFS/TFTP 网络启动环境搭建

调试驱动时,最烦的就是每次改代码都要重新烧写固件。用网络启动就方便多了——内核和文件系统都放在服务器上,开发板通过网络加载。

TFTP 服务器(传输内核和设备树)

TFTP 用来传内核镜像和设备树文件。配置很简单:

sudo apt install tftpd-hpa
sudo vim /etc/default/tftpd-hpa

配置文件里指定 TFTP_DIRECTORY="/srv/tftp",然后把 zImage 和 .dtb 文件丢进去。

开发板 U-Boot 里设置:

setenv serverip 192.168.1.100
setenv ipaddr 192.168.1.10
setenv bootcmd 'tftp 0x82000000 zImage; tftp 0x83000000 board.dtb; bootz 0x82000000 - 0x83000000'
saveenv
boot

NFS 文件系统(挂载根文件系统)

NFS 让开发板把服务器上的目录当作根文件系统来用。这样你改完驱动,重启开发板就能看到效果。

sudo apt install nfs-kernel-server
sudo vim /etc/exports

添加一行:

/srv/nfs/rootfs 192.168.1.0/24(rw,sync,no_subtree_check,no_root_squash)

然后在 U-Boot 里设置内核启动参数:

setenv bootargs 'console=ttyS0,115200 root=/dev/nfs nfsroot=192.168.1.100:/srv/nfs/rootfs rw ip=192.168.1.10'

避坑指南:我曾经在调试网卡驱动时,NFS 死活挂不上。折腾了半天,发现是开发板和服务器的网段不一致。还有一次是防火墙没关。记住:调试阶段先把防火墙关了,省得自己坑自己。

2.4 串口终端(minicom/Putty)设置

串口是嵌入式调试的「生命线」。内核打印、驱动日志、甚至紧急 shell,都靠它。

minicom(Linux 下常用)

sudo minicom -s

进入配置界面,设置:

  • 串口设备:/dev/ttyUSB0(看你的 USB 转串口设备)
  • 波特率:115200
  • 数据位:8
  • 停止位:1
  • 无校验
  • 硬件流控:No

Putty(Windows 下常用)

选 Serial,填上 COM 口和波特率。注意 Windows 下 COM 口编号可以在设备管理器里查到。

关键设置:流控一定要关掉!我见过太多人开着硬件流控,结果串口只能收不能发,或者乱码。另外,如果出现乱码,先检查波特率是否匹配,再检查电平是否一致(3.3V vs 1.8V)。

2.5 逻辑分析仪与示波器基础操作

软件调试搞不定的时候,就得请出硬件工具了。逻辑分析仪看时序,示波器看波形。

逻辑分析仪

调试 I2C、SPI、UART 这些协议时,逻辑分析仪是神器。我常用的有 Saleae Logic 和国产的梦源。

基本操作:

  1. 把通道夹子接到要测的信号线上(记得共地)
  2. 设置采样率(一般 24MHz 够用,高速信号要更高)
  3. 设置触发条件(比如 I2C 的 START 条件)
  4. 点击开始采集,然后让开发板跑相关操作

举个例子,调试 I2C 驱动时,用逻辑分析仪抓一下 SCL 和 SDA 的波形。如果看到 START 条件后没有 ACK,那多半是设备地址错了或者从设备没上电。

示波器

示波器看模拟信号更在行。比如调试 HDMI 输出、音频信号、电源纹波。

基础操作:

  • 探头补偿:用示波器自带的 1kHz 方波信号校准探头
  • 垂直档位:根据信号幅度调整(一般先设 1V/div)
  • 水平时基:根据信号频率调整(比如 1MHz 信号设 500ns/div)
  • 触发设置:边沿触发最常用,触发电平设在信号中间

安全提醒:示波器探头的地线夹子一定要接开发板的 GND,千万别接到 VCC 上,否则直接短路烧板。我刚开始用示波器时就犯过这错,烧了一块价值 2000 块的开发板……嗯,从那以后我每次接线都先确认一遍。

小结

调试环境搭建看起来琐碎,但每一步都关系到后续调试效率。工具链配好了,编译不报错;网络启动配好了,迭代速度快;串口调通了,能看到内核日志;逻辑分析仪和示波器会用,硬件问题也能定位。

我个人建议,把这套环境搭好后,写个脚本一键配置。下次换项目或者换电脑,直接跑脚本就行,省得重复劳动。