2. 内核编译环境搭建:获取源码、配置工具链、编译与烧录验证
说实话,很多初学者一上来就急着写驱动代码,结果连内核都编译不过。我见过太多人卡在环境搭建这一步,白白浪费好几天。这一章,咱们就把地基打牢。
你要做 WM8960 音频驱动,首先得有一套能跑起来的内核环境。说白了,就是三件事:拿到源码、配好工具链、编译烧录验证。每一步都有坑,我一个个说。
2.1 获取 Linux 内核源码
我个人习惯用 LTS 版本,稳定,社区支持时间长。WM8960 驱动在 4.19 以上版本就已经很成熟了。
推荐内核版本:5.10.x LTS 或 6.1.x LTS
这两个版本对 I2S 和 WM8960 的支持最完善,我在项目中踩过的坑最少。
获取方式有两种:
- 从 kernel.org 下载:直接拿完整源码包,适合网络稳定的环境。
- 从厂商 BSP 获取:如果你用的是全志、瑞芯微、NXP 的板子,厂商会提供打过补丁的内核树。我建议优先用这个,因为里面已经配好了设备树和默认配置。
# 方式一:从 kernel.org 下载
wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.200.tar.xz
tar -xf linux-5.10.200.tar.xz
cd linux-5.10.200
# 方式二:从厂商 git 仓库克隆(以瑞芯微为例)
git clone -b rk3399-linux-5.10 https://github.com/rockchip-linux/kernel.git
我的经验:别用太新的主线内核做产品开发。6.x 主线对某些老款 WM8960 的寄存器映射有变动,我去年就因为这个翻过车。LTS 版本最稳。
2.2 配置交叉编译工具链
你想想看,你的开发机是 x86 架构,但目标板是 ARM(比如 i.MX6ULL、STM32MP1、RK3568)。你不能直接在 PC 上编译 ARM 程序,得用交叉编译器。
工具链的选择取决于你的目标芯片:
| 目标芯片系列 | 推荐工具链 | 架构 |
|---|---|---|
| ARM Cortex-A7/A9 | arm-linux-gnueabihf- | armv7l |
| ARM Cortex-A53/A72 | aarch64-linux-gnu- | armv8-a |
| RISC-V 系列 | riscv64-linux-gnu- | rv64gc |
安装步骤其实很简单,但路径别搞错:
# 以 ARM 32 位工具链为例
sudo apt-get install gcc-arm-linux-gnueabihf
# 验证安装
arm-linux-gnueabihf-gcc --version
# 设置环境变量(建议写到 ~/.bashrc 里)
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabihf-
注意:ARCH 和 CROSS_COMPILE 这两个变量必须配对。ARCH=arm 配 aarch64 工具链,编译会直接报错。我曾经帮一个同事排查了半天,最后发现他 ARCH 设成了 arm64 但工具链是 arm-linux-……这种低级错误最耗时间。
2.3 编译最小系统镜像
嗯,这里要注意。我们不是编译完整的内核,而是先编译一个最小系统镜像——只包含内核、设备树和必要的驱动。这样烧录快,验证也快。
步骤分四步:
- 清理旧配置:make distclean
- 加载默认配置:用厂商提供的 defconfig,或者自己配
- 编译内核:make zImage(ARM)或 make Image(ARM64)
- 编译设备树:make dtbs
# 第一步:清理
make distclean
# 第二步:加载配置(以 i.MX6ULL 为例)
make imx_v7_defconfig
# 如果你想自己裁剪,可以执行:
make menuconfig
# 第三步:编译内核
make -j$(nproc) zImage
# 第四步:编译设备树
make -j$(nproc) dtbs
# 编译完成后,镜像在 arch/arm/boot/zImage
# 设备树在 arch/arm/boot/dts/imx6ull-14x14-evk.dtb
关键点:WM8960 驱动在内核配置中对应 CONFIG_SND_SOC_WM8960。你需要在 menuconfig 里把它选上:
Device Drivers → Sound card support → Advanced Linux Sound Architecture → ALSA for SoC audio support → CODEC drivers → Wolfson WM8960 CODEC
我个人习惯在第一次编译时只选最少的驱动,能启动到控制台就行。音频驱动后面再加,这样排查问题范围小。
2.4 烧录与验证启动流程
烧录方式取决于你的板子。常见的有三种:
- SD 卡启动:把 zImage 和 dtb 拷到 SD 卡第一个分区,用 U-Boot 引导。适合开发阶段。
- TFTP + NFS:通过网络加载内核和根文件系统。适合频繁修改内核的场景。
- EMMC 烧录:用工具把镜像写入板载存储。适合定型后批量部署。
我以最常用的 SD 卡启动为例:
# 假设 SD 卡设备是 /dev/sdb
# 第一步:分区(第一个分区 FAT32,放内核和设备树)
sudo fdisk /dev/sdb
# 创建主分区,类型 c (W95 FAT32)
# 第二步:格式化
sudo mkfs.vfat /dev/sdb1
# 第三步:拷贝文件
sudo mount /dev/sdb1 /mnt
sudo cp arch/arm/boot/zImage /mnt/
sudo cp arch/arm/boot/dts/imx6ull-14x14-evk.dtb /mnt/
sudo umount /mnt
# 第四步:插入板子,上电启动
验证启动是否成功,看串口输出:
U-Boot 2020.04 (Jan 10 2025 - 10:30:00)
...
Loading kernel from SD Card...
Starting kernel ...
[ 0.000000] Booting Linux on physical CPU 0x0
[ 0.000000] Linux version 5.10.200
...
[ 1.234567] ALSA device list:
[ 1.237890] #0: wm8960-audio
看到 wm8960-audio 出现在 ALSA device list 里,说明你的内核已经识别到了 WM8960 编解码器。嗯,这一步走通了,后面调试 I2S 接口才有意义。
避坑指南:如果启动后没有看到 wm8960-audio,别急着怀疑驱动。先检查设备树里 I2C 地址对不对。WM8960 的默认 I2C 地址是 0x1a,但有些板子硬件设计用了 0x1b。我曾经在这个问题上浪费了两天——硬件工程师改了地址没告诉我。
2.5 本章知识结构图
下面这张图把整个流程串起来了,你保存下来,以后每次搭建环境都可以对照着走:
这张图把整个流程分成了四个阶段。你每次搭建环境,就按这个顺序走。哪一步卡住了,就回头看那一步的详细操作。