3、开发环境搭建:交叉编译工具链安装、Linux驱动开发环境配置、版本控制(Git)与项目管理
说实话,很多做嵌入式开发的朋友,一上来就急着写代码。我见过不少新人,代码写得挺溜,结果编译环境没搭好,折腾两天都跑不起来。嗯,这章咱们就把地基打牢。
POS机生产测试工具的开发,说白了就是要在PC上写代码,然后编译成ARM架构能跑的程序。这就离不开交叉编译工具链。我个人习惯先把整个环境梳理清楚,再动手。
3.1 交叉编译工具链安装
什么是交叉编译?你想想看,你的PC是x86架构,POS机主控芯片通常是ARM Cortex系列。在x86上编译出ARM能执行的二进制文件,这就是交叉编译。
核心思路: 工具链的选择取决于POS机的主控芯片型号。我做过的一个项目用的是全志A64芯片,当时踩了不少坑。
3.1.1 获取工具链
常见的获取方式有两种:
- 芯片厂商提供:比如全志、瑞芯微官网都会放出对应的交叉编译工具链。我建议优先用官方的,兼容性最好。
- Linaro开源版本:如果厂商没提供,可以用Linaro的gcc-arm-linux-gnueabihf。我在项目中用过这个,稳定可靠。
3.1.2 安装步骤(以Ubuntu 20.04为例)
# 下载工具链(以ARM 32位为例)
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/
# 配置环境变量
echo 'export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin' >> ~/.bashrc
source ~/.bashrc
# 验证安装
arm-linux-gnueabihf-gcc --version
小技巧: 我曾经在环境变量配置上吃过亏。建议把工具链路径放在 /opt/ 下,别放 /usr/local/,避免和系统自带的gcc冲突。
3.1.3 测试编译
写一个简单的hello world测试一下:
// test.c
#include <stdio.h>
int main() {
printf("POS Test Tool - Cross Compile OK!\n");
return 0;
}
// 编译
arm-linux-gnueabihf-gcc test.c -o test_arm
// 查看文件信息
file test_arm
// 输出:ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV)
看到ARM字样,说明工具链安装成功了。嗯,这一步很简单,但很多人会忽略验证。
3.2 Linux驱动开发环境配置
POS机的生产测试离不开底层驱动。比如你要测试串口通信、GPIO控制、I2C触摸屏,都得写驱动或者调用驱动接口。
3.2.1 内核源码准备
我建议从厂商的BSP包中获取内核源码。别自己去Linux官网下载主线内核,那上面没有POS机的外设驱动。
# 解压内核源码
tar -xvf kernel-4.9-bsp.tar.gz -C ~/workspace/
cd ~/workspace/kernel-4.9/
# 配置内核(使用厂商默认配置)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- defconfig
# 编译内核(第一次编译较慢)
make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- -j4
注意: 编译内核时,-j4 后面的数字是你的CPU核心数。我曾经用 -j8 在4核机器上编译,结果内存爆了。建议核数不超过物理核心数。
3.2.2 驱动模块编译环境
生产测试工具通常以内核模块的形式加载驱动。你需要配置好模块编译环境:
# 确保内核已编译,生成Module.symvers
make modules_prepare
# 编写一个简单的GPIO驱动模块
// gpio_test.c
#include <linux/module.h>
#include <linux/gpio.h>
static int __init gpio_test_init(void) {
printk("GPIO Test Module Loaded\n");
return 0;
}
static void __exit gpio_test_exit(void) {
printk("GPIO Test Module Unloaded\n");
}
module_init(gpio_test_init);
module_exit(gpio_test_exit);
MODULE_LICENSE("GPL");
// Makefile
obj-m += gpio_test.o
all:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
避坑指南: 我曾经在Makefile里直接写死了内核路径,换台机器就编译不过。建议用 $(shell uname -r) 动态获取当前内核版本。
3.2.3 设备树配置
POS机的外设引脚配置都在设备树里。比如你要测试的串口是UART3,就得在dts文件中确认:
&uart3 {
pinctrl-names = "default";
pinctrl-0 = &uart3_pins;
status = "okay";
};
说白了,设备树就是硬件的「户口本」。驱动通过它找到对应的寄存器地址和中断号。
3.3 版本控制(Git)与项目管理
这个环节我多说两句。很多嵌入式工程师觉得Git是软件工程师的事,硬件相关代码随便改改就行。我告诉你,这个想法很危险。
3.3.1 Git工作流设计
我习惯用这种分支策略:
| 分支名称 | 用途 | 说明 |
|---|---|---|
| master | 发布分支 | 只合并经过完整测试的代码 |
| develop | 开发主分支 | 日常开发合并到这里 |
| feature/* | 功能分支 | 比如 feature/uart-test, feature/gpio-calib |
| hotfix/* | 紧急修复 | 生产线上发现问题,直接基于master创建 |
3.3.2 实际项目中的Git操作
# 初始化仓库
git init pos_test_tool
cd pos_test_tool
# 创建开发分支
git checkout -b develop
# 开发串口测试功能
git checkout -b feature/uart-test
# 写代码、提交
git add .
git commit -m "feat: add uart loopback test function"
# 合并到develop
git checkout develop
git merge --no-ff feature/uart-test
# 打标签(版本发布时)
git tag -a v1.0.0 -m "First release for production test"
我的经验: 每次提交前,先 git diff 看看改了啥。我曾经手滑把调试用的死循环提交上去了,生产线上的POS机全部卡死。嗯,从那以后我养成了review的习惯。
3.3.3 项目管理要点
生产测试工具的项目管理,和普通软件不太一样。我总结了几点:
- 硬件版本管理:每个POS机硬件版本对应一套驱动参数。建议在仓库里建
hw_rev/目录,按版本存放设备树和配置文件。 - 测试用例管理:测试脚本和工具代码分开存放。我习惯用
tests/目录,里面按功能模块划分子目录。 - 文档同步更新:驱动接口变了,文档必须跟着改。我在项目中吃过这个亏,后来强制要求「代码合入前先更新文档」。
3.3.4 .gitignore配置
嵌入式项目有很多编译中间文件,别把它们提交到仓库:
# 编译产物
*.o
*.ko
*.mod.c
*.order
*.symvers
# 工具链相关
toolchain/
# 临时文件
*.swp
*.swo
*~
# 测试日志
logs/
*.log
小建议: 把 .gitignore 在项目一开始就创建好。我见过有人项目做了一半才加,结果历史记录里全是 .o 文件,清理起来很麻烦。
3.4 环境验证清单
搭建完环境后,我建议按这个清单检查一遍:
- 交叉编译工具链能否正常编译hello world?
- 内核源码能否编译通过?
- 能否编译一个空的内核模块并加载?
- Git仓库是否初始化?分支策略是否确定?
- .gitignore是否配置完整?
这五步都走通了,开发环境就算搭好了。别急着写代码,先把环境跑顺了。你想想看,如果编译环境有问题,后面调试起来会非常痛苦。
下一章,咱们开始写第一个生产测试程序——串口环回测试。到时候会用到今天搭的环境。