OpenHarmony开发——传感器驱动开发实例
Tiechui.Wang 2021-07-05 11:58:00 发布3716 浏览 17 点赞 15 收藏
传感器驱动开发实例
基于HDF驱动模型,加载启动加速度计传感器驱动,代码形式如下,具体原理可参考HDF驱动开发指南。加速度传感器选择通讯接口方式为I2C,厂家选择博世BMI160加速度传感器。
- 加速度计传感器驱动入口注册
- 加速度计传感器驱动入口函数实现
/* 注册加速度计传感器入口数据结构体对象 */
struct HdfDriverEntry g_sensorAccelDevEntry = {
.moduleVersion = 1, /* 加速度计传感器模块版本号 */
.moduleName = "HDF_SENSOR_ACCEL", /* 加速度计传感器模块名,要与device_info.hcs文件里的加速度计moduleName字段值一样*/
.Bind = BindAccelDriver, /* 加速度计传感器绑定函数 */
.Init = InitAccelDriver, /* 加速度计传感器初始化函数 */
.Release = ReleaseAccelDriver, /* 加速度计传感器资源释放函数 */
};
/* 调用HDF_INIT将驱动入口注册到HDF框架中,在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动,当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_sensorAccelDevEntry);
- 加速度计传感器设备配置描述
加速度传感器模型使用HCS作为配置描述源码,HCS配置字段详细介绍参考配置管理介绍。
/* 加速度计传感器设备HCS配置 */
device_sensor_accel :: device {
device0 :: deviceNode {
policy = 1; /* policy字段是驱动服务发布的策略 */
priority = 105; /* 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序 */
preload = 2; /* 驱动按需加载字段,0表示加载,2表示不加载 */
permission = 0664; /* 驱动创建设备节点权限 */
moduleName = "HDF_SENSOR_ACCEL"; /* 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致 */
serviceName = "sensor_accel"; /* 驱动对外发布服务的名称,必须唯一 */
deviceMatchAttr = "hdf_sensor_accel_driver"; /* 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等 */
}
}
- 加速度计传感器驱动初始化和去初始化
- 初始化入口函数init
- 加速度计传感器寄存器组配置信息
加速度计传感器数据配置只需要按照模板配置即可,基于模板配置的解析功能已经在InitSensorConfigData函数完成,只需初始化时调用即可。如果有新增配置项,需要同步修改此函数。
加速度传感器数据配置模板(accel_config.hcs)
root {
sensorAccelConfig {
accelChipConfig {
/* 传感器设备信息模板 */
template sensorInfo {
sensorName = "accelerometer"; /* 加速度计名字,字符最大长度16字节 */
vendorName = "borsh_bmi160"; /* 传感器设备厂商,字符最大长度16字节 */
firmwareVersion = "1.0"; /* 传感器固件版本号,默认1.0,字符最大长度16字节 */
hardwareVersion = "1.0"; /* 传感器硬件版本号,默认1.0,字符最大长度16字节 */
sensorTypeId = 1; /* 传感器类型编号,详见{@link SensorTypeTag} */
sensorId = 1; /* 传感器的标识号,有传感器驱动开发者定义,推荐用{@link SensorTypeTag}枚举 */
maxRange = 8; /* 传感器的最大量程,根据开发者需要配置 */
precision = 0; /* 传感器的精度,与上报数据配合使用,上报数据结构体{@link SensorEvents } */
power = 230; /* 传感器的功耗 */
}
/* 传感器使用的总线类型和配置信息模板 */
template sensorBusConfig {
busType = 0; /* 0:i2c 1:spi */
busNum = 6; /* 芯片上分配给传感器的器件号 */
busAddr = 0; /* 芯片上分配给传感器的地址 */
regWidth = 1; /* 传感器寄存器地址宽度 */
regBigEndian = 0; /* 传感器寄存器大小端 */
}
/* 传感器设备属性模板 */
template sensorAttr {
chipName = ""; /* 传感器芯片名字 */
chipIdRegister = 0xf; /* 传感器在位检测寄存器地址 */
chipIdValue = 0xd1; /* 校验传感器在位检测寄存器值 */
}
}
}
}
/* 根据不同器件硬件差异,修改模板配置,不修改的就会默认采用模板配置 */
root {
sensorAccelConfig {
accel_bmi160_chip_config : accelChipConfig {
match_attr = "hdf_sensor_accel_driver"; /* 需要和加速度传感器设备配置match_attr字段保持一致 */
accelInfo :: sensorInfo {
vendorName = "borsh_bmi160";
sensorTypeId = 1;
sensorId = 1;
}
accelBusConfig :: sensorBusConfig {
busType = 0; /* i2c通讯方式 */
busNum = 6;
busAddr = 0x68;
regWidth = 1; /* 1字节位宽 */
}
accelAttr :: sensorAttr {
chipName = "bmi160";
chipIdRegister = 0x00;
chipIdValue = 0xd1;
}
accelRegConfig {
/* regAddr: 寄存器地址
value: 寄存器值
mask: 寄存器值的掩码
len: 寄存器值的数据长度(字节)
delay: 配置寄存器延时(ms)
opsType:操作类型 0-无 1-读 2-写 3-读并检查 4-位更新
calType: 计算类型 0-无 1-写 2-取反 3-异或 4-左移 5-右移
shiftNum: 移动位数
debug: 调试开关,0-调试关闭 1-调试打开
save: 保存数据开关,0-不保存数据 1-保存数据
*/
/* 传感器寄存器操作分组,按照分组进行有序配置 */
/* 寄存器地址, 寄存器值, 寄存器值的掩码, 寄存器值的数据长度, 配置寄存器延时, 操作类型, 计算类型, 移动位数, 调试开关, 保存开关 */
/* 初始化寄存器组 */
initSeqConfig = [
0x7e, 0xb6, 0xff, 1, 5, 2, 0, 0, 0, 0,
0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0
];
/* 使能寄存器组 */
enableSeqConfig = [
0x7e, 0x11, 0xff, 1, 5, 2, 0, 0, 0, 0,
0x41, 0x03, 0xff, 1, 0, 2, 0, 0, 0, 0,
0x40, 0x08, 0xff, 1, 0, 2, 0, 0, 0, 0
];
/* 去使能寄存器组 */
disableSeqConfig = [
0x7e, 0x10, 0xff, 1, 5, 2, 0, 0, 0, 0
];
}
}
}
}
- 加速度计传感器驱动操作接口实现
开发者需要根据每种类型的传感器实现归一化接口。
/* 不使用函数暂时置空 */
static int32_t SetAccelInfo(struct SensorBasicInfo *info)
{
(void)info;
return HDF_ERR_NOT_SUPPORT;
}
/* 下发使能寄存器组的配置 */
static int32_t SetAccelEnable(void)
{
int32_t ret;
struct AccelDrvData *drvData = AccelGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM);
ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: accel sensor disable config failed", __func__);
return HDF_FAILURE;
}
drvData->threadStatus = SENSOR_THREAD_RUNNING;
return HDF_SUCCESS;
}
/* 下发去使能寄存器组的配置 */
static int32_t SetAccelDisable(void)
{
int32_t ret;
struct AccelDrvData *drvData = AccelGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData->accelCfg, HDF_ERR_INVALID_PARAM);
ret = SetSensorRegCfgArray(&drvData->accelCfg->busCfg, drvData->accelCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: accel sensor disable config failed", __func__);
return HDF_FAILURE;
}
drvData->threadStatus = SENSOR_THREAD_STOPPED;
return HDF_SUCCESS;
}
/* 配置传感器采样率和数据上报间隔 */
static int32_t SetAccelBatch(int64_t samplingInterval, int64_t interval)
{
(void)interval;
struct AccelDrvData *drvData = AccelGetDrvData();
drvData->interval = samplingInterval;
return HDF_SUCCESS;
}
/* 设置传感器工作模式,当前支持实时模式 */
static int32_t SetAccelMode(int32_t mode)
{
return (mode == SENSOR_WORK_MODE_REALTIME) ? HDF_SUCCESS : HDF_FAILURE;
}
/* 设置传感器可选配置 */
static int32_t SetAccelOption(uint32_t option)
{
(void)option;
return HDF_ERR_NOT_SUPPORT;
}
差异化处理接口
/* 器件探测时,如果探测成功,则注册差异化处理函数到accel驱动模型里 */
int32_t DetectAccelBim160Chip(struct SensorCfgData *data)
{
int32_t ret;
struct AccelOpsCall ops;
CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
if (strcmp(ACCEL_CHIP_NAME_BMI160, data->sensorAttr.chipName) != 0) {
return HDF_SUCCESS;
}
ret = InitAccelPreConfig();
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: init BMI160 bus mux config", __func__);
return HDF_FAILURE;
}
if (DetectSensorDevice(data) != HDF_SUCCESS) {
return HDF_FAILURE;
}
/* 差异化处理函数 */
ops.Init = InitBmi160;
ops.ReadData = ReadBmi160Data;
ret = RegisterAccelChipOps(&ops);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: register BMI160 accel failed", __func__);
(void)ReleaseSensorBusHandle(&data->busCfg);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
/* 初始化处理函数 */
static int32_t InitBmi160(struct SensorCfgData *data)
{
int32_t ret;
CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
ret = SetSensorRegCfgArray(&data->busCfg, data->regCfgGroup[SENSOR_INIT_GROUP]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: bmi160 sensor init config failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
/* 数据处理函数 */
int32_t ReadBmi160Data(struct SensorCfgData *data)
{
int32_t ret;
struct AccelData rawData = { 0, 0, 0 };
int32_t tmp[ACCEL_AXIS_NUM];
struct SensorReportEvent event;
(void)memset_s(&event, sizeof(event), 0, sizeof(event));
ret = ReadBmi160RawData(data, &rawData, &event.timestamp);
if (ret != HDF_SUCCESS) {
return HDF_FAILURE;
}
event.sensorId = SENSOR_TAG_ACCELEROMETER;
event.option = 0;
event.mode = SENSOR_WORK_MODE_REALTIME;
rawData.x = rawData.x * BMI160_ACC_SENSITIVITY_2G;
rawData.y = rawData.y * BMI160_ACC_SENSITIVITY_2G;
rawData.z = rawData.z * BMI160_ACC_SENSITIVITY_2G;
tmp[ACCEL_X_AXIS] = (rawData.x * SENSOR_1K_UNIT) / SENSOR_CONVERT_UNIT;
tmp[ACCEL_Y_AXIS] = (rawData.y * SENSOR_1K_UNIT) / SENSOR_CONVERT_UNIT;
tmp[ACCEL_Z_AXIS] = (rawData.z * SENSOR_1K_UNIT) / SENSOR_CONVERT_UNIT;
event.dataLen = sizeof(tmp);
event.data = (uint8_t *)&tmp;
ret = ReportSensorEvent(&event);
return ret;
}
- 数据处理函数
创建传感器定时器,按照配置的采样率定时采样,并上报给数据订阅者。
/* 传感器定时工作线程 */
static int32_t ReadAccelDataThreadWorker(void *arg)
{
(void)arg;
int64_t interval;
struct AccelDrvData *drvData = AccelGetDrvData();
drvData->threadStatus = SENSOR_THREAD_START;
while (true) {
if (drvData->threadStatus == SENSOR_THREAD_RUNNING) {
if (drvData->ops.ReadData != NULL) {
(void)drvData->ops.ReadData(drvData->accelCfg);
}
interval = OsalDivS64(drvData->interval, (SENSOR_CONVERT_UNIT * SENSOR_CONVERT_UNIT));
OsalMSleep(interval);
} else if (drvData->threadStatus == SENSOR_THREAD_DESTROY) {
break;
} else {
OsalMSleep(ACC_DEFAULT_SAMPLING_200_MS / SENSOR_CONVERT_UNIT / SENSOR_CONVERT_UNIT);
}
if ((!drvData->initStatus) || (drvData->interval < 0) || drvData->threadStatus != SENSOR_THREAD_RUNNING) {
continue;
}
}
return HDF_SUCCESS;
}
/* 创建传感器定时器和器件初始化 */
static int32_t InitAccelConfig(void)
{
int32_t ret;
struct AccelDrvData *drvData = AccelGetDrvData();
if (drvData->threadStatus != SENSOR_THREAD_NONE && drvData->threadStatus != SENSOR_THREAD_DESTROY) {
HDF_LOGE("%s: accel thread have created", __func__);
return HDF_SUCCESS;
}
ret = CreateSensorThread(&drvData->thread, ReadAccelDataThreadWorker, "hdf_sensor_accel", drvData);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: accel create thread failed", __func__);
drvData->threadStatus = SENSOR_THREAD_NONE;
return HDF_FAILURE;
}
CHECK_NULL_PTR_RETURN_VALUE(drvData->ops.Init, HDF_ERR_INVALID_PARAM);
ret = drvData->ops.Init(drvData->accelCfg);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: accel create thread failed", __func__);
drvData->threadStatus = SENSOR_THREAD_NONE;
return HDF_FAILURE;
}
drvData->initStatus = true;
return HDF_SUCCESS;
}
- 主要的数据结构
©本站发布的所有内容,包括但不限于文字、图片、音频、视频、图表、标志、标识、广告、商标、商号、域名、软件、程序等,除特别标明外,均来源于网络或用户投稿,版权归原作者或原出处所有。我们致力于保护原作者版权,若涉及版权问题,请及时联系我们进行处理。
分类
其它
标签
鸿蒙
操作系统
HarmonyOS
相关推荐
鸿蒙生物识别开发:从指纹识别到3D人脸识别的完整指南
周正
0
0鸿蒙NFC开发实战:从读卡器模式到卡模拟的完整实现
周正
1
0鸿蒙加密存储开发:数据安全保护的完整方案
周正
1
0鸿蒙模块化开发最佳实践:从单体应用到模块化架构的演进之路
周正
1
0鸿蒙组件库开发实战:从零打造可复用的UI组件库
周正
1
0
Tiechui.Wang
我还没有写个人简介......
1091
帖子
0
提问
893
粉丝
最新发布
华为应用市场增长优化师火热认证中
2025-03-10 10:16:02 发布华为应用市场斩获Pocket Gamer2023年移动游戏奖,全球第三大移动应用生态获行业认可
2024-04-27 11:06:07 发布热门推荐