第1章:驱动开发环境搭建
做嵌入式驱动开发,第一件事就是搭环境。这事儿看着简单,但我在带新人时发现,环境问题往往能卡住好几天。今天我就把Linux和Windows两套环境的搭建方法,还有交叉编译工具链的配置,一次性给你讲清楚。
1.1 Linux下的开发环境:GCC + Makefile
我个人习惯在Ubuntu上做开发,版本选18.04或20.04 LTS都行。为什么?因为社区活跃,遇到问题好搜解决方案。
安装GCC工具链
打开终端,敲下面这行命令:
sudo apt-get update
sudo apt-get install build-essential
sudo apt-get install gcc-arm-linux-gnueabihf # 交叉编译用
build-essential这个包会把gcc、g++、make、libc-dev这些基础工具一次性装好。我在项目中遇到过有人只装了gcc没装make,结果Makefile跑不起来,折腾了半天才发现问题。
gcc --version 验证一下。如果显示版本号,说明装好了。
编写第一个Makefile
说白了,Makefile就是告诉编译器怎么干活。下面这个例子,是我做磁条卡读卡器驱动时常用的模板:
# 磁条卡读卡器驱动 Makefile
CC = arm-linux-gnueabihf-gcc
CFLAGS = -Wall -O2 -I./include
LDFLAGS = -lm
TARGET = magcard_drv
OBJS = main.o i2c_ops.o card_decode.o
$(TARGET): $(OBJS)
$(CC) -o $@ $^ $(LDFLAGS)
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f $(TARGET) $(OBJS)
install:
cp $(TARGET) /usr/local/bin/
你想想看,这里面的-Wall是打开所有警告,-O2是二级优化。我刚开始做驱动时,总嫌警告烦人,后来有一次因为没开-Wall,一个类型转换错误在产线上才暴露出来...嗯,从那以后我再也不敢关警告了。
arm-linux-gnueabihf-gcc,别用本地的gcc,否则编译出来的程序在目标板上跑不起来。
1.2 Windows下的开发环境:Visual Studio + WDK
Windows驱动开发和Linux完全是两码事。我记得第一次在Windows上写驱动时,光装环境就花了两天。这里我把步骤简化一下:
安装顺序很重要
- 先装Visual Studio 2019(社区版免费)
- 再装Windows 10 SDK
- 最后装WDK(Windows Driver Kit)
为什么是这个顺序?因为WDK安装时会检测VS和SDK的版本,顺序错了它会报错。我曾经试过先装WDK再装VS,结果WDK找不到编译器,只能卸载重来。
创建驱动项目
装好之后,打开VS,新建项目 -> 选择"Empty WDM Driver"模板。你会看到这样的代码框架:
#include <ntddk.h>
DRIVER_INITIALIZE DriverEntry;
DRIVER_UNLOAD DriverUnload;
NTSTATUS DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
DbgPrint("磁条卡读卡器驱动加载成功\n");
DriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
VOID DriverUnload(
_In_ PDRIVER_OBJECT DriverObject
)
{
DbgPrint("驱动卸载完成\n");
}
核心要点:Windows驱动用DbgPrint输出调试信息,用DebugView工具查看。这和Linux的printk是一个道理。
1.3 交叉编译工具链配置
做嵌入式开发,交叉编译是绕不开的坎。说白了,就是在PC上编译出能在ARM、MIPS等嵌入式芯片上跑的程序。
获取工具链
有三种方式:
- 官方提供:芯片厂商(如NXP、TI)会提供配套工具链
- Linaro:开源社区维护的ARM工具链,质量不错
- Buildroot/Yocto:自己编译工具链,适合定制化需求
我个人推荐用Linaro的,省事。下载后解压到/opt目录:
wget https://releases.linaro.org/components/toolchain/binaries/7.5-2019.12/arm-linux-gnueabihf/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf.tar.xz
sudo tar -xvf gcc-linaro-*.tar.xz -C /opt/
配置环境变量
编辑~/.bashrc,在末尾加上:
export PATH=$PATH:/opt/gcc-linaro-7.5.0-2019.12-x86_64_arm-linux-gnueabihf/bin
export CROSS_COMPILE=arm-linux-gnueabihf-
export ARCH=arm
然后执行source ~/.bashrc让它生效。验证方法:
arm-linux-gnueabihf-gcc --version
PATH写成了PTHA,结果终端里所有命令都找不到了。记住,环境变量名不能写错,否则连ls、cd这些基础命令都会失效。
测试交叉编译
写一个简单的测试程序:
// test.c
#include <stdio.h>
int main() {
printf("磁条卡读卡器驱动开发环境搭建成功!\n");
return 0;
}
编译:
arm-linux-gnueabihf-gcc test.c -o test_arm
用file命令查看生成的文件:
file test_arm
# 输出:test_arm: ELF 32-bit LSB executable, ARM, version 1 (SYSV)
看到"ARM"字样,说明交叉编译成功了。这个程序在x86的PC上跑不了,得放到ARM开发板上才能运行。
1.4 环境验证清单
最后,我整理了一份检查清单,你可以对着打勾:
| 检查项 | Linux | Windows |
|---|---|---|
| 编译器版本 | gcc --version | cl.exe /? |
| Make工具 | make --version | nmake /? |
| 交叉编译器 | arm-linux-gnueabihf-gcc --version | 不适用 |
| 调试工具 | gdb --version | WinDbg |
| 头文件路径 | /usr/include | WDK安装目录\inc |
环境搭好了,后面写驱动才能顺风顺水。下一章,我们开始真正接触磁条卡读卡器的硬件接口和通信协议。