3. HDF驱动模型
环境搭建这件事,说难不难,说简单也不简单。我见过太多人卡在第一步——源码下载到一半断了、编译工具链版本不对、模拟器跑不起来。其实只要理清几个关键节点,半天时间就能把整套环境跑通。
这一章,我会把HDF开发环境拆成四个部分来讲:源码获取与编译配置、IDE工具链安装、模拟器与真机调试、以及工程目录结构。每个部分我都会穿插一些实际踩过的坑,希望能帮你少走弯路。
3.1 源码获取与编译环境配置
鸿蒙的源码托管在码云(Gitee)上,官方推荐用repo工具来管理多仓库。为什么用repo?因为鸿蒙的代码库有上百个,手动git clone会疯掉的。
核心要点:源码获取分三步走——安装repo、初始化仓库、同步代码。其中同步这一步最耗时,建议用稳定的网络环境,最好在凌晨跑。
3.1.1 安装repo工具
# 创建bin目录并加入PATH
mkdir -p ~/bin
export PATH=~/bin:$PATH
# 下载repo工具
curl https://gitee.com/oschina/repo/raw/fork_flow/repo-py3 > ~/bin/repo
chmod a+x ~/bin/repo
这里有个坑——curl命令如果网络不稳定,下载的repo文件可能不完整。我建议下载完后用md5sum校验一下。嗯,具体校验值可以去鸿蒙官网查。
3.1.2 初始化与同步
# 创建工作目录
mkdir -p ~/openharmony
cd ~/openharmony
# 初始化(以3.2 Release为例)
repo init -u https://gitee.com/openharmony/manifest.git -b OpenHarmony-3.2-Release --no-repo-verify
# 同步代码
repo sync -c -j4
-j4表示4个线程并行下载。我个人习惯设成-j8,前提是你的CPU够强。如果同步过程中断了,重新执行repo sync就行,它会断点续传。
注意:源码目录路径不要包含中文和空格。我曾经有个同事把项目放在“桌面/鸿蒙项目”下,编译时各种诡异报错,折腾了两天才发现是路径问题。
3.1.3 编译环境配置
鸿蒙的编译依赖Python 3.7+、gn、ninja等工具。官方提供了一个安装脚本,一键搞定:
# 进入源码根目录
cd ~/openharmony
# 安装编译依赖
bash build/prebuilts_download.sh
# 设置Python环境
export PATH=~/openharmony/prebuilts/python/linux-x86/3.9.2/bin:$PATH
编译命令也很直接:
# 编译Hi3516DV300开发板
./build.sh --product-name hi3516dv300 --ccache
# 编译RK3568开发板
./build.sh --product-name rk3568 --ccache
--ccache是缓存编译结果,第二次编译会快很多。我第一次编译Hi3516时没加这个参数,全量编译花了40分钟。加了之后增量编译只要5分钟。
3.2 IDE工具链安装
鸿蒙官方推荐的是DevEco Studio,基于IntelliJ IDEA定制。说实话,刚开始我用的是VS Code,后来发现DevEco对HDF驱动开发的支持更到位——有专门的驱动模板、代码补全、调试配置向导。
3.2.1 DevEco Studio安装步骤
- 下载安装包:从鸿蒙官网下载Linux版,约1.2GB
- 解压安装:
tar -xzf DevEco-Studio-*.tar.gz -C ~/deveco - 启动配置:运行
~/deveco/bin/studio.sh,按向导配置SDK路径 - 安装HDF插件:Settings → Plugins → 搜索"HDF" → 安装
小技巧:DevEco Studio默认内存分配是1GB,如果你编译大型项目,建议改成4GB以上。修改studio64.vmoptions文件中的-Xmx参数即可。
3.2.2 交叉编译工具链
HDF驱动最终要跑在目标硬件上,所以需要交叉编译工具链。不同芯片平台用的工具链不同:
| 芯片平台 | 工具链名称 | 下载方式 |
|---|---|---|
| Hi3516DV300 | arm-linux-gnueabi-gcc | 源码预置在prebuilts/gcc/下 |
| RK3568 | aarch64-linux-gnu-gcc | 源码预置在prebuilts/gcc/下 |
| STM32MP157 | arm-none-eabi-gcc | 需自行下载安装 |
对于预置的工具链,编译脚本会自动调用。如果是自行下载的,记得把工具链路径加到PATH环境变量里。
3.3 模拟器与真机调试环境准备
调试HDF驱动,我建议的路线是:先模拟器,后真机。模拟器能快速验证驱动的基本逻辑,真机用来做最终的功能和性能测试。
3.3.1 QEMU模拟器
鸿蒙支持QEMU模拟ARM64和RISC-V平台。搭建步骤:
# 安装QEMU
sudo apt-get install qemu-system-arm qemu-system-riscv64
# 编译QEMU镜像
./build.sh --product-name qemu_arm64_linux --ccache
# 启动模拟器
qemu-system-aarch64 -machine virt -cpu cortex-a57 \
-kernel out/qemu_arm64_linux/packages/phone/images/uImage \
-initrd out/qemu_arm64_linux/packages/phone/images/ramdisk.img \
-append "root=/dev/ram0 console=ttyAMA0" \
-nographic
启动后你会看到一个串口终端,鸿蒙内核已经跑起来了。这时候可以用hdf命令查看HDF设备列表。
注意:QEMU模拟器不支持所有硬件外设。比如GPIO中断、DMA传输这些,模拟器里是跑不了的。我一般用模拟器验证驱动的Bind、Init、Release这三个核心流程是否正常。
3.3.2 真机调试环境
真机调试需要准备三样东西:开发板、串口线、网线(或USB线)。以Hi3516DV300为例:
- 烧录镜像:用HiTool工具将编译好的
uImage、rootfs烧录到开发板 - 串口连接:用USB转串口线连接开发板的UART0,波特率115200
- 网络连接:开发板通过网线连接到路由器,与PC在同一网段
- NFS挂载:将PC上的驱动编译输出目录通过NFS挂载到开发板,实现快速迭代
我个人强烈推荐用NFS方式调试。每次修改驱动代码后,在PC上重新编译,开发板直接加载新模块,不用反复烧录。效率提升不是一点半点。
3.4 HDF工程目录结构解析
理解了目录结构,你才知道代码该放哪里、编译脚本怎么配。这是HDF开发的基本功。
下面这张图展示了HDF驱动在鸿蒙源码中的完整目录关系:
3.4.1 关键目录详解
drivers/framework/core/ — 这是HDF的心脏。里面实现了驱动对象的生命周期管理、设备匹配、消息通信机制。你写的驱动最终会被这里的代码加载和管理。
drivers/framework/osal/ — OS抽象层。它把Linux的spin_lock、mutex、workqueue等接口封装成HDF统一的API。这样做的好处是——你的驱动可以跨OS移植。我见过有人直接把Linux驱动搬过来,结果发现锁的接口对不上,改了一整天。
drivers/adapter/ — 平台适配层。每个芯片厂商在这里放自己的HAL实现。比如海思的hi3516目录下,有GPIO、I2C、SPI等外设的适配代码。
device/board/ — 板级配置。这里定义的是硬件资源——哪个GPIO接了LED、哪个I2C总线挂了传感器。配置以.hcs文件(鸿蒙配置脚本)形式存在。
3.4.2 驱动代码放置规范
假设你要写一个I2C温度传感器的驱动,代码应该放哪里?
- 驱动逻辑代码:放在
drivers/model/sensor/temperature/下 - HCS配置文件:放在
device/board/你的开发板/下 - 编译脚本:在
drivers/model/sensor/BUILD.gn中添加你的驱动编译目标
经验之谈:刚开始做HDF开发时,我建议你先在drivers/model/下找一个现成的驱动,比如gpio_led,把它的代码结构和配置文件完整看一遍。然后照着它的样子写自己的驱动。这是最快的学习路径。
3.5 环境验证:跑通第一个HDF驱动
环境搭好了,怎么确认一切正常?我的做法是跑一个最简单的HDF驱动——hdf_hello。
// hello_driver.c
#include "hdf_device_desc.h"
#include "hdf_log.h"
#define HDF_LOG_TAG hello_driver
static int32_t HelloDriverBind(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HelloDriver: Bind called");
return HDF_SUCCESS;
}
static int32_t HelloDriverInit(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HelloDriver: Init called");
return HDF_SUCCESS;
}
static void HelloDriverRelease(struct HdfDeviceObject *deviceObject)
{
HDF_LOGI("HelloDriver: Release called");
return;
}
struct HdfDriverEntry g_helloDriverEntry = {
.moduleVersion = 1,
.moduleName = "hello_driver",
.Bind = HelloDriverBind,
.Init = HelloDriverInit,
.Release = HelloDriverRelease,
};
HDF_INIT(g_helloDriverEntry);
编译后加载到开发板或模拟器,如果串口打印出HelloDriver: Init called,说明你的环境搭建成功了。
验证清单:
- ✅ 源码能正常同步和编译
- ✅ DevEco Studio能打开工程并识别HDF语法
- ✅ 模拟器或真机能启动并加载HDF驱动
- ✅ 串口日志能看到驱动的Bind/Init输出
环境搭建是HDF开发的第一步,也是最容易出问题的一步。但只要你按照上面的流程走一遍,把每个环节都验证通过,后面的开发就会顺畅很多。嗯,接下来就可以正式开始写驱动了。