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

说实话,很多初学者一上来就急着写代码,结果卡在环境搭建上好几个星期。我见过太多人,明明代码逻辑没问题,编译却报一堆莫名其妙的错误——最后发现是交叉编译工具链没配好。这一章,咱们就把这些基础工作一次性搞定。

2.1 交叉编译工具链安装

先说说什么是交叉编译。你想想看,你的电脑是x86架构,但车载液晶屏用的芯片通常是ARM架构。在x86上编译出ARM能跑的程序,这就是交叉编译。说白了,就是「跨平台编译」。

我个人习惯用Linaro提供的工具链,稳定且社区活跃。安装步骤其实不复杂:

# 下载ARM交叉编译工具链
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

# 解压到指定目录
tar -xvf gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz -C /opt/

# 配置环境变量
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
小提示: 建议把环境变量写到 ~/.bashrc 里,这样每次打开终端就不用重新设置了。我一般还会加个别名,比如 alias arm-gcc='arm-linux-gnueabihf-gcc',省得每次敲那么长一串。

验证是否安装成功,跑一下这个命令:

arm-linux-gnueabihf-gcc --version

如果能看到版本信息,那就成了。嗯,这里要注意:不同芯片厂商可能推荐不同的工具链版本。比如NXP的i.MX系列,官方就建议用他们的Yocto SDK。我在项目中遇到过,用错工具链版本导致驱动死活加载不上的情况,折腾了两天才发现是ABI不兼容。

2.2 Linux驱动开发环境配置

驱动开发环境,核心就是三样东西:内核源码、设备树编译器、根文件系统。我一般这样配:

2.2.1 内核源码准备

从芯片厂商的官网下载对应板子的Linux内核。以全志T3为例:

git clone https://github.com/Allwinner-T3/linux-4.9.git
cd linux-4.9
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- sun8i_defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4

这里有个坑:defconfig 一定要选对。我曾经图省事,随便选了个通用配置,结果编译出来的内核在板子上起不来,串口打印到一半就卡死了。后来才发现是时钟配置不对。

2.2.2 设备树编译器

设备树(Device Tree)是描述硬件信息的文件。编译它需要 dtc 工具:

# 安装dtc
sudo apt-get install device-tree-compiler

# 编译设备树
dtc -I dts -O dtb -o sun8i-t3-evb.dtb sun8i-t3-evb.dts
警告: 设备树里引脚复用(pinctrl)配置错了,轻则某个外设不能用,重则整个系统崩溃。我见过有人把LCD的引脚配成了GPIO,结果屏幕直接烧了——虽然是个例,但小心驶得万年船。

2.2.3 根文件系统制作

用BusyBox制作最小根文件系统,这是嵌入式开发的标配:

# 下载BusyBox
wget https://busybox.net/downloads/busybox-1.31.1.tar.bz2
tar -xjf busybox-1.31.1.tar.bz2
cd busybox-1.31.1

# 配置并编译
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- install

编译完成后,在 _install 目录下就是根文件系统的基础内容。记得要手动创建 /dev/proc/sys 这些目录,不然系统启动时会报错。

2.3 硬件调试工具使用

写驱动离不开硬件调试。光靠printk打印日志,效率太低了。我强烈建议你学会用示波器和逻辑分析仪。

2.3.1 示波器使用要点

示波器主要看模拟信号的质量。比如调试LCD的RGB接口时,要检查时钟和数据线的时序是否满足要求:

信号 检查内容 常见问题
PCLK(像素时钟) 频率、占空比、抖动 频率偏差超过5%会导致显示花屏
HSYNC(行同步) 脉冲宽度、周期 脉宽太窄可能被误判为噪声
VSYNC(场同步) 帧率是否稳定 帧率波动大会感觉画面卡顿
DATA(数据线) 建立时间、保持时间 时序裕量不足时,高温下容易出错

实际操作时,我习惯把示波器的采样率设为信号频率的5倍以上。比如PCLK是33.3MHz,采样率至少设到200MSa/s。不然波形会失真,你看到的上升沿可能根本不是真实的。

经验之谈: 调试OLED屏的SPI接口时,用示波器抓一下CS(片选)信号和SCLK(时钟)信号的相对位置。我遇到过CS拉低后,SCLK的第一个时钟沿还没到,数据就已经被采走了——这就是典型的建立时间违例。

2.3.2 逻辑分析仪使用要点

逻辑分析仪看的是数字信号的逻辑关系。对于I2C、SPI这类协议,它比示波器好用得多。我常用的逻辑分析仪是Saleae的克隆版,24MHz采样率,对付大多数车载屏的调试足够了。

举个例子,调试I2C触摸屏驱动时,用逻辑分析仪抓一下通信波形:

# 用sigrok-cli命令行工具分析
sigrok-cli -i capture.sr -P i2c -A i2c

输出结果会显示每个I2C数据包的内容。如果看到NAK(无应答),那基本就是设备地址错了或者从设备没上电。我在项目中遇到过,触摸屏偶尔不响应,用逻辑分析仪一抓,发现是I2C时钟线被拉低超过100ms——原来是某个驱动把GPIO复用了,没释放干净。

2.3.3 调试流程建议

我个人总结了一套调试流程,分享给你:

  1. 先软件后硬件:先用printk确认驱动是否加载、probe是否执行
  2. 再逻辑分析仪:看协议层的通信是否正常,数据对不对
  3. 最后示波器:检查信号质量,确认时序裕量

为什么要这个顺序?因为大部分问题其实出在软件配置上。我曾经花了一整天调一个LCD的时序参数,用示波器反复测,最后发现是设备树里配错了时钟源——用逻辑分析仪看协议层,5分钟就定位到了。

避坑指南: 逻辑分析仪的接地夹子一定要夹好。我见过有人没夹地线,抓出来的波形全是毛刺,还以为是板子有问题。其实只是共模噪声没滤掉。

好了,环境搭建这部分就聊到这儿。下一章咱们开始写第一个字符设备驱动——点亮一块OLED屏。到时候你会用上今天配好的工具链和调试设备。