2. 内核编译环境搭建:获取源码、配置工具链、编译与烧录验证

说实话,很多初学者一上来就急着写驱动代码,结果连内核都编译不过。我见过太多人卡在环境搭建这一步,白白浪费好几天。这一章,咱们就把地基打牢。

你要做 WM8960 音频驱动,首先得有一套能跑起来的内核环境。说白了,就是三件事:拿到源码、配好工具链、编译烧录验证。每一步都有坑,我一个个说。

2.1 获取 Linux 内核源码

我个人习惯用 LTS 版本,稳定,社区支持时间长。WM8960 驱动在 4.19 以上版本就已经很成熟了。

推荐内核版本:5.10.x LTS 或 6.1.x LTS

这两个版本对 I2S 和 WM8960 的支持最完善,我在项目中踩过的坑最少。

获取方式有两种:

  1. 从 kernel.org 下载:直接拿完整源码包,适合网络稳定的环境。
  2. 从厂商 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 编译最小系统镜像

嗯,这里要注意。我们不是编译完整的内核,而是先编译一个最小系统镜像——只包含内核、设备树和必要的驱动。这样烧录快,验证也快。

步骤分四步:

  1. 清理旧配置:make distclean
  2. 加载默认配置:用厂商提供的 defconfig,或者自己配
  3. 编译内核:make zImage(ARM)或 make Image(ARM64)
  4. 编译设备树: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 本章知识结构图

下面这张图把整个流程串起来了,你保存下来,以后每次搭建环境都可以对照着走:

内核编译环境搭建流程 获取内核源码 配置交叉工具链 编译最小系统 kernel.org 下载 或厂商 BSP 仓库 (推荐 LTS 版本) 安装 gcc-arm-* 设置 ARCH 和 CROSS_COMPILE make distclean make defconfig make zImage dtbs 烧录到 SD 卡 / EMMC / TFTP 验证启动:检查 ALSA device list 关键检查点: 内核版本匹配 → 工具链架构正确 → 设备树 I2C 地址 → WM8960 出现在 ALSA 设备列表

这张图把整个流程分成了四个阶段。你每次搭建环境,就按这个顺序走。哪一步卡住了,就回头看那一步的详细操作。