OpenHarmony HDF 传感器驱动:设备休眠唤醒后 Sensor 失效问题修复
一、问题背景
在 OpenHarmony 设备上,当系统进入休眠(Suspend)后再次唤醒(Resume)时,加速度传感器(Accelerometer)会出现数据异常或完全失效的问题。具体表现为:
- 设备休眠前 Sensor 工作正常,能正常上报数据;
- 设备唤醒后,Sensor 不再上报数据,或上报的数据为异常值;
- 需要重启设备或重新加载驱动才能恢复。
这个问题在依赖 Sensor 数据的应用场景中(如屏幕旋转、计步、重力感应等)影响尤为严重,直接导致用户体验中断。
二、根因分析
2.1 Sensor 硬件特性
加速度传感器芯片(如常见的 LSM6DS3、BMA 系列、ADXL 系列等)通过 I2C/SPI 总线与 SoC 通信。芯片内部有一组寄存器,控制着采样率、量程、工作模式、中断配置等。这些寄存器的状态决定了芯片能否正确采集和输出数据。
当系统进入休眠时,可能发生以下情况之一:
- 传感器芯片供电被切断:部分硬件设计中,Sensor 的电源域在系统休眠时会被关断以省电,芯片内部寄存器全部丢失。
- 芯片进入低功耗模式:即使供电未断,芯片也可能因总线上无活动而进入待机状态,部分寄存器值被重置。
- 总线控制器状态丢失:I2C/SPI 控制器在休眠/唤醒过程中可能需要重新初始化。
无论哪种情况,唤醒后 Sensor 芯片的寄存器状态都不可靠,需要重新配置才能正常工作。
2.2 原驱动代码的缺陷
在原始 drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c 中,驱动注册了 HDF_INIT 入口,完成了传感器初始化、设备注册、工作队列创建等流程。但是,驱动没有注册任何电源管理回调(Power Listener)。
这意味着:
系统休眠 → 驱动无感知 → 不做任何处理
系统唤醒 → 驱动无感知 → 不恢复寄存器配置
唤醒后,驱动层的软件状态(如 drvData->enable、定时器、工作队列)可能依然认为 Sensor 处于"已使能"状态,但底层硬件的寄存器配置已经丢失。于是定时器继续触发 AccelDataWorkEntry 读取数据,但芯片实际并未被正确配置,导致读取失败或读到垃圾数据。
三、解决方案
核心思路:利用 HDF 框架的电源管理机制,在设备唤醒时重新配置 Sensor 芯片寄存器。
具体改动分为三部分:
3.1 注册电源管理监听器
引入 hdf_pm.h 头文件,在驱动初始化时注册 IPowerEventListener,使驱动能够感知系统的休眠/唤醒事件。
3.2 实现唤醒回调
在 Resume 回调中,如果 Sensor 在休眠前处于使能状态(drvData->enable == true),则重新下发 SENSOR_INIT_GROUP 和 SENSOR_ENABLE_GROUP 两组寄存器配置,恢复芯片到正常工作状态。
3.3 增强使能流程
在 SetAccelEnable() 中,除了配置 ENABLE 寄存器组外,额外增加 INIT 寄存器组的配置,确保每次使能时芯片都处于已初始化状态。
四、代码改动详解
文件位置:
drivers\hdf_core\framework\model\sensor\driver\accel\sensor_accel_driver.c
改动点一:引入电源管理头文件
#include "hdf_pm.h"
新增 hdf_pm.h 头文件,提供 HdfPmRegisterPowerListener、HdfPmUnregisterPowerListener 等 API 声明。
改动点二:前向声明
static struct AccelDrvData *AccelGetDrvData(void);
由于电源管理回调函数定义在 AccelGetDrvData() 之前,需要提前声明,以便回调函数内部调用。
改动点三:实现电源管理回调函数
新增四个回调函数:
static int32_t AccelDriverResume(struct HdfDeviceObject *deviceObject)
{
(void)deviceObject;
struct AccelDrvData *drvData = AccelGetDrvData();
// 如果驱动未初始化、配置为空、或 Sensor 未使能,直接返回
if (drvData == NULL || drvData->accelCfg == NULL || !drvData->enable) {
return HDF_SUCCESS;
}
HDF_LOGI("%s: Accel re-init after resume", __func__);
// 关键:重新下发 INIT 寄存器组,恢复芯片基础配置
(void)SetSensorRegCfgArray(&drvData->accelCfg->busCfg,
drvData->accelCfg->regCfgGroup[SENSOR_INIT_GROUP]);
// 重新下发 ENABLE 寄存器组,使芯片进入工作模式
(void)SetSensorRegCfgArray(&drvData->accelCfg->busCfg,
drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
return HDF_SUCCESS;
}
这是本次修复的核心代码。 逻辑如下:
- 获取驱动数据指针;
- 判断 Sensor 是否处于使能状态——如果休眠前没开 Sensor,唤醒后也不需要做任何事;
- 重新下发
SENSOR_INIT_GROUP(初始化寄存器组),恢复芯片的基础配置(如采样率、量程、分辨率等); - 重新下发
SENSOR_ENABLE_GROUP(使能寄存器组),让芯片进入测量模式。
其余三个回调:
// 浅度唤醒(Doze Resume),处理方式与普通唤醒一致
static int32_t AccelDriverDozeResume(struct HdfDeviceObject *deviceObject)
{
return AccelDriverResume(deviceObject);
}
// 休眠回调,仅打印日志
static int32_t AccelDriverSuspend(struct HdfDeviceObject *deviceObject)
{
(void)deviceObject;
HDF_LOGI("%s: Accel suspending", __func__);
return HDF_SUCCESS;
}
// 浅度休眠(Doze Suspend),无需额外处理
static int32_t AccelDriverDozeSuspend(struct HdfDeviceObject *deviceObject)
{
(void)deviceObject;
return HDF_SUCCESS;
}
改动点四:定义电源监听器结构体
static const struct IPowerEventListener g_accelPowerListener = {
.DozeResume = AccelDriverDozeResume,
.DozeSuspend = AccelDriverDozeSuspend,
.Resume = AccelDriverResume,
.Suspend = AccelDriverSuspend,
};
改动点五:SetAccelEnable() 增加 INIT 寄存器组配置
if (drvData->enable) {
HDF_LOGE("%s: Accel sensor is enabled", __func__);
return HDF_SUCCESS;
}
+
+ (void)SetSensorRegCfgArray(&drvData->accelCfg->busCfg,
+ drvData->accelCfg->regCfgGroup[SENSOR_INIT_GROUP]);
+
ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg,
drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
在使能 Sensor 时,先下发 SENSOR_INIT_GROUP 初始化寄存器组,再下发 SENSOR_ENABLE_GROUP 使能寄存器组。这样做的好处是:无论芯片当前处于什么状态,先做一次完整初始化再使能,保证状态一致。
改动点六:驱动初始化时注册电源监听器
在 AccelInitDriver() 中新增:
drvData->accelCfg->regCfgGroup = &g_regCfgGroup[0];
drvData->cb = NULL;
+
+ if (HdfPmRegisterPowerListener(device, &g_accelPowerListener) != HDF_SUCCESS) {
+ HDF_LOGE("%s: Accel register power listener failed", __func__);
+ }
在驱动 Init 阶段注册电源监听器,之后系统每次休眠/唤醒时,HDF 框架都会调用对应的回调函数。
改动点七:驱动释放时注销电源监听器
在 AccelReleaseDriver() 中新增:
struct AccelDrvData *drvData = (struct AccelDrvData *)device->service;
CHECK_NULL_PTR_RETURN(drvData);
+
+ (void)HdfPmUnregisterPowerListener(device, &g_accelPowerListener);
在驱动卸载时注销监听器,避免回调悬空指针。
五、总结
本次修复方案不仅适用于加速度传感器,对于其他类型的传感器(陀螺仪、磁力计、气压计等)如果遇到休眠唤醒后失效的问题,同样可以参考此方案:
- 注册
IPowerEventListener; - 在
Resume回调中根据enable状态重新下发INIT和ENABLE寄存器组; - 在
SetXxxEnable()中增加INIT寄存器组的配置。
更多推荐

所有评论(0)