第二章 嵌入式开发环境搭建
说实话,很多初学者一上来就急着写代码,结果卡在环境搭建上好几个星期。我见过太多人,明明代码逻辑没问题,编译却报一堆莫名其妙的错误——最后发现是交叉编译工具链没配好。这一章,咱们就把这些基础工作一次性搞定。
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
验证是否安装成功,跑一下这个命令:
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
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。不然波形会失真,你看到的上升沿可能根本不是真实的。
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 调试流程建议
我个人总结了一套调试流程,分享给你:
- 先软件后硬件:先用printk确认驱动是否加载、probe是否执行
- 再逻辑分析仪:看协议层的通信是否正常,数据对不对
- 最后示波器:检查信号质量,确认时序裕量
为什么要这个顺序?因为大部分问题其实出在软件配置上。我曾经花了一整天调一个LCD的时序参数,用示波器反复测,最后发现是设备树里配错了时钟源——用逻辑分析仪看协议层,5分钟就定位到了。
好了,环境搭建这部分就聊到这儿。下一章咱们开始写第一个字符设备驱动——点亮一块OLED屏。到时候你会用上今天配好的工具链和调试设备。