OpenHarmony传感器驱动开发示例(基于HDF Sensor驱动模型)
基于HDF驱动框架的Sensor驱动模型开发RK3568-外接环境光传感器驱动程序
一、外接环境光传感器驱动程序
1.目标
基于HDF驱动框架的Sensor驱动模型开发RK3568-外接环境光传感器驱动程序(包括环境光传感器抽象驱动、环境光传感器差异化驱动),从而可以通过Sensor HDI能力接口为上层应用提供服务。
2.开发环境
硬件平台:润和DAYU200开发板
软件版本:OpenHarmony v3.1 Release
外接传感器:ROHM BH1750FVI
3.准备工作
根据扩展IO原理图,使用杜邦线将BH1750FVI环境光传感器连接上开发板。
扩展IO原理图如下:
连接示意图:
4.Sensor驱动模型介绍
Sensor驱动模型屏蔽硬件器件差异,为上层Sensor服务系统提供稳定的Sensor基础能力接口,包括Sensor列表查询、Sensor启停、Sensor订阅及取消订阅,Sensor参数配置等功能,具体如下:
接口名
|
功能描述
|
int32_t GetAllSensors(struct SensorInformation **sensorInfo, int32_t *count) | 获取系统中注册的所有传感器信息,一组完整传感器信息包括传感器名字、设备厂商、固件版本号、硬件版本号、传感器类型编号、传感器标识、最大量程、精度、功耗。 |
int32_t Enable(int32_t sensorId) | 使能指定传感器设备,只有数据订阅者使能传感器后,才能获取订阅的传感器数据。 |
int32_t Disable(int32_t sensorId) | 去使能指定传感器设备。 |
int32_t SetBatch(iint32_t sensorId, int64_t samplingInterval, int64_t reportInterval) | 设置指定传感器的数据采样间隔和数据上报间隔 |
int32_t SetMode(int32_t sensorId, int32_t mode) | 设置指定传感器的工作模式,不同的工作模式,上报数据方式不同。 |
int32_t SetOption(int32_t sensorId, uint32_t option) | 设置指定传感器量程,精度等可选配置。 |
int32_t Register(int32_t groupId, RecordDataCallback cb) | 订阅者根据不同groupId注册传感器数据回调函数,系统会将获 取到的传感器数据上报给订阅者。 |
int32_t Unregister(int32_t groupId, RecordDataCallback cb) | 订阅者根据groupId和回调函数注销对应订阅者的传感器数据回 调函数。 |
以加速度传感器驱动为例,Sensor驱动模型的加载以及运行流程如下:
1. 从device info HCS 的Sensor Host读取Sensor设备管理配置信息。
2. HDF配置框架从HCB数据库解析Sensor设备管理配置信息,并关联对应设备驱动。
3. 加载并初始化Sensor设备管理驱动。
4. Sensor设备管理驱动向HDI发布Sensor基础能力接口。
5. 从device info HCS 的Sensor Host读取加速度传感器驱动配置信息。
6. 加载加速度传感器抽象驱动,调用初始化接口,完成Sensor器件驱动资源分配和数据处理队列创建。
7. 从accel_xxx_config HCS读取加速度传感器差异化驱动配置和私有化配置信息。
8. 加速度传感器差异化驱动,调用通用配置解析接口,完成器件属性信息解析,器件寄存器解析。
9. 加速度传感器差异化驱动完成器件探测,并分配加速度传感器配置资源,完成加速度传感器差异化接口注册。
10. 加速度传感器探测成功之后,加速度传感器差异化驱动通知加速度传感器抽象驱动,注册加速度传感器设备到Sensor设备管理中。
Sensor驱动模型包括三种驱动:Sensor设备管理驱动、传感器抽象驱动、传感器差异化驱动。
OpenHarmony自带有Sensor设备管理驱动,所以基于Sensor驱动模型开发某一类传感器驱动,需要实现对应的传感器抽象驱动、传感器差异化驱动,以环境光传感器为例,需要实现:环境光传感器抽象驱动、环境光传感器差异化驱动。
5.目录结构
基于HDF驱动框架的Sensor驱动模型进行环境光传感器驱动开发需要实现:环境光传感器抽象驱动、环境光传感器差异化驱动,涉及的源码文件如下:
OpenHarmony
├──drivers/framework/model/sensor/driver
│ │ ├──als
│ │ │ ├──sensor_als_driver.h
│ │ │ └──sensor_als_driver.c
│ │ │
│ │ └──chipset/als
│ │ ├──als_bh1750.h
│ │ └──als_bh1750.c
│ │
│ └──adapter/khdf/linux/model/sensor
│ ├──Kconfig
│ └──Makefile
│
└──vendor/hihope/rk3568/hdf_config/khdf
├──device_info
│ └──device_info.hcs
└──sensor
├──als
│ └──bh1750_config.hcs
└──sensor_config.hcs
6.开发步骤
6.1 驱动源文件编写
6.1.1 环境光传感器抽象驱动源文件
OpenHarmony自带有环境光传感器抽象驱动,以下仅展示使用或修改的部分代码。
sensor_als_driver.h文件
......
struct AlsOpsCall { // 差异化接口对象
int32_t (*Init)(struct SensorCfgData *data);
int32_t (*ReadData)(struct SensorCfgData *data);
};
struct AlsDrvData { // Als驱动数据结构体
struct IDeviceIoService ioService;
struct HdfDeviceObject *device;
HdfWorkQueue alsWorkQueue;
HdfWork alsWork;
OsalTimer alsTimer;
bool detectFlag;
bool enable;
int64_t interval;
struct SensorCfgData *alsCfg;
struct AlsOpsCall ops;
};
int32_t AlsRegisterChipOps(const struct AlsOpsCall *ops); // 注册差异化接口
struct SensorCfgData *AlsCreateCfgData(const struct DeviceResourceNode *node);
// 获取传感器配置信息
void AlsReleaseCfgData(struct SensorCfgData *alsCfg); // 资源释放
......
sensor_als_driver.c文件
- 定义并注册驱动入口对象HdfDriverEntry
// 抽象驱动入口
struct HdfDriverEntry g_sensorAlsDevEntry = {
.moduleVersion = 1,
.moduleName = "HDF_SENSOR_ALS",
.Bind = AlsBindDriver,
.Init = AlsInitDriver,
.Release = AlsReleaseDriver,
};
HDF_INIT(g_sensorAlsDevEntry);
- 实现Bind函数、Dispatch函数——AlsBindDriver、DispatchAls
/* Dispatch函数 */
static int32_t DispatchAls(struct HdfDeviceIoClient *client,int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
(void)client;
(void)cmd;
(void)data;
(void)reply;
return HDF_SUCCESS;
}
/* Bind函数 */
int32_t AlsBindDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct AlsDrvData *drvData = (struct AlsDrvData*)OsalMemCalloc(sizeof(*drvData));
if (drvData == NULL) {
HDF_LOGE("%s: Malloc als drv data fail!", __func__);
return HDF_ERR_MALLOC_FAIL;
}
drvData->ioService.Dispatch = DispatchAls;
drvData->device = device;
device->service = &drvData->ioService;
g_alsDrvData = drvData;
return HDF_SUCCESS;
}
- 实现Init函数——AlsInitDriver、InitAlsData、AlsDataWorkEntry
/* Init函数 */
int32_t AlsInitDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct AlsDrvData *drvData = (struct AlsDrvData *)device->service;
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
if (InitAlsData(drvData) != HDF_SUCCESS) {
HDF_LOGE("%s: Init als config failed", __func__);
return HDF_FAILURE;
}
drvData->alsCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->alsCfg));
if (drvData->alsCfg == NULL) {
HDF_LOGE("%s: Malloc als config data failed", __func__);
return HDF_FAILURE;
}
drvData->alsCfg->regCfgGroup = &g_regCfgGroup[0];
drvData->alsCfg->extendedRegCfgGroup = &g_extendAlsRegCfgGroup[0];
return HDF_SUCCESS;
}
static int32_t InitAlsData(struct AlsDrvData *drvData)
{
if (HdfWorkQueueInit(&drvData->alsWorkQueue, HDF_ALS_WORK_QUEUE_NAME) != HDF_SUCCESS) {
HDF_LOGE("%s: Als init work queue failed", __func__);
return HDF_FAILURE;
}
if (HdfWorkInit(&drvData->alsWork, AlsDataWorkEntry, drvData) != HDF_SUCCESS) {
HDF_LOGE("%s: Als create thread failed", __func__);
return HDF_FAILURE;
}
drvData->interval = SENSOR_TIMER_MIN_TIME;
drvData->enable = false;
drvData->detectFlag = false;
return HDF_SUCCESS;
}
static void AlsDataWorkEntry(void *arg)
{
struct AlsDrvData *drvData = NULL;
drvData = (struct AlsDrvData *)arg;
CHECK_NULL_PTR_RETURN(drvData);
if (drvData->ops.ReadData == NULL) {
HDF_LOGI("%s: Als ReadData function NULl", __func__);
return;
}
if (drvData->ops.ReadData(drvData->alsCfg) != HDF_SUCCESS) {
HDF_LOGE("%s: Als read data failed", __func__);
}
}
- 实现Release函数——AlsReleaseDriver、AlsReleaseCfgData
/* Release函数 */
void AlsReleaseDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN(device);
struct AlsDrvData *drvData = (struct AlsDrvData *)device->service;
CHECK_NULL_PTR_RETURN(drvData);
if (drvData->detectFlag && drvData->alsCfg != NULL) {
AlsReleaseCfgData(drvData->alsCfg);
}
OsalMemFree(drvData->alsCfg);
drvData->alsCfg = NULL;
HdfWorkDestroy(&drvData->alsWork);
HdfWorkQueueDestroy(&drvData->alsWorkQueue);
OsalMemFree(drvData);
}
void AlsReleaseCfgData(struct SensorCfgData *alsCfg)
{
CHECK_NULL_PTR_RETURN(alsCfg);
(void)DeleteSensorDevice(&alsCfg->sensorInfo);
ReleaseSensorAllRegConfig(alsCfg);
ReleaseExtendedAlsRegConfig(alsCfg);
(void)ReleaseSensorBusHandle(&alsCfg->busCfg);
alsCfg->root = NULL;
(void)memset_s(&alsCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0,sizeof(struct SensorBasicInfo));
(void)memset_s(&alsCfg->busCfg, sizeof(struct SensorBusCfg), 0,sizeof(struct SensorBusCfg));
(void)memset_s(&alsCfg->sensorAttr, sizeof(struct SensorAttr), 0,sizeof(struct SensorAttr));
}
- 实现Als传感器配置信息获取函数——AlsCreateCfgData、InitAlsAfterDetected、InitAlsOps
/* 提供给差异化驱动的初始化接口,完成器件基本配置信息解析(光信息,总线配置,器件探测寄存器配置),器件探测,器件寄存器解析 */
struct SensorCfgData *AlsCreateCfgData(const struct DeviceResourceNode *node)
{
struct AlsDrvData *drvData = AlsGetDrvData();
if (drvData == NULL || node == NULL) {
HDF_LOGE("%s: Als node pointer NULL", __func__);
return NULL;
}
if (drvData->detectFlag) {
HDF_LOGE("%s: Als sensor have detected", __func__);
return NULL;
}
if (drvData->alsCfg == NULL) {
HDF_LOGE("%s: Als alsCfg pointer NULL", __func__);
return NULL;
}
// 设备基本配置信息解析
if (GetSensorBaseConfigData(node, drvData->alsCfg) != HDF_SUCCESS) {
HDF_LOGE("%s: Get sensor base config failed", __func__);
goto BASE_CONFIG_EXIT;
}
/* 如果探测不到器件在位,返回进行下个器件探测 */
// if (DetectSensorDevice(drvData->alsCfg) != HDF_SUCCESS) {
// HDF_LOGI("%s: Als sensor detect device no exist", __func__);
// drvData->detectFlag = false;
// goto BASE_CONFIG_EXIT;
// }
drvData->detectFlag = true;
// 器件探测成功后的初始化操作
if (InitAlsAfterDetected(drvData->alsCfg) != HDF_SUCCESS) {
HDF_LOGE("%s: Als sensor detect device no exist", __func__);
goto INIT_EXIT;
}
return drvData->alsCfg;
INIT_EXIT:
(void)ReleaseSensorBusHandle(&drvData->alsCfg->busCfg);
BASE_CONFIG_EXIT:
drvData->alsCfg->root = NULL;
(void)memset_s(&drvData->alsCfg->sensorInfo, sizeof(struct SensorBasicInfo),0, sizeof(struct SensorBasicInfo));
(void)memset_s(&drvData->alsCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
(void)memset_s(&drvData->alsCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));
return drvData->alsCfg;
}
static int32_t InitAlsAfterDetected(struct SensorCfgData *config)
{
struct SensorDeviceInfo deviceInfo;
CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);
/* 初始化接口函数 */
if (InitAlsOps(config, &deviceInfo) != HDF_SUCCESS) {
HDF_LOGE("%s: Init als ops failed", __func__);
return HDF_FAILURE;
}
/* 注册设备到传感器管理模块 */
if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) {
HDF_LOGE("%s: Add als device failed", __func__);
return HDF_FAILURE;
}
/* 器件寄存器解析 */
// if (ParseSensorRegConfig(config) != HDF_SUCCESS) {
// HDF_LOGE("%s: Parse sensor register failed", __func__);
// goto SENSOR_REG_CONFIG_EXIT;
// }
// if (ParseExtendedAlsRegConfig(config) != HDF_SUCCESS) {
// HDF_LOGE("%s: Parse sensor extendedRegCfgGroup register failed",__func__);
// goto EXTENDED_ALS_REG_CONFIG_EXIT;
// }
return HDF_SUCCESS;
// EXTENDED_ALS_REG_CONFIG_EXIT:
// ReleaseSensorAllRegConfig(config);
// SENSOR_REG_CONFIG_EXIT:
// (void)DeleteSensorDevice(&config->sensorInfo);
// return HDF_FAILURE;
}
/* 注册传感器驱动归一化的接口函数 */
static int32_t InitAlsOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo)
{
CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);
deviceInfo->ops.Enable = SetAlsEnable;
deviceInfo->ops.Disable = SetAlsDisable;
deviceInfo->ops.SetBatch = SetAlsBatch;
deviceInfo->ops.SetMode = SetAlsMode;
deviceInfo->ops.SetOption = SetAlsOption;
if (memcpy_s(&deviceInfo->sensorInfo, sizeof(deviceInfo->sensorInfo), &config->sensorInfo, sizeof(config->sensorInfo)) != EOK) {
HDF_LOGE("%s: Copy sensor info failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
- 接口函数实现—SetAlsEnable、SetAlsDisable、SetAlsBatch、SetAlsMode、SetAlsOption
SetAlsEnable、SetAlsDisable
/* 下发使能寄存器组的配置 */
static int32_t SetAlsEnable(void)
{
int32_t ret;
struct AlsDrvData *drvData = AlsGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
CHECK_NULL_PTR_RETURN_VALUE(drvData->alsCfg, HDF_ERR_INVALID_PARAM);
if (drvData->enable) {
HDF_LOGE("%s: Als sensor is enabled", __func__);
return HDF_SUCCESS;
}
ret = SetSensorRegCfgArray(&drvData->alsCfg->busCfg, drvData->alsCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als sensor enable config failed", __func__);
return ret;
}
// 创建定时器
ret = OsalTimerCreate(&drvData->alsTimer, SENSOR_TIMER_MIN_TIME,
AlsTimerEntry, (uintptr_t)drvData);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als create timer failed[%d]", __func__, ret);
return ret;
}
// 激活定时器周期循环
ret = OsalTimerStartLoop(&drvData->alsTimer);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als start timer failed[%d]", __func__, ret);
return ret;
}
drvData->enable = true;
return HDF_SUCCESS;
}
// 定时器执行的函数
static void AlsTimerEntry(uintptr_t arg)
{
int64_t interval;
int32_t ret;
struct AlsDrvData *drvData = (struct AlsDrvData *)arg;
CHECK_NULL_PTR_RETURN(drvData);
if (!HdfAddWork(&drvData->alsWorkQueue, &drvData->alsWork)) {
HDF_LOGE("%s: Als add work queue failed", __func__);
}
interval = OsalDivS64(drvData->interval, (SENSOR_CONVERT_UNIT *SENSOR_CONVERT_UNIT));
interval = (interval < SENSOR_TIMER_MIN_TIME) ? SENSOR_TIMER_MIN_TIME : interval;
ret = OsalTimerSetTimeout(&drvData->alsTimer, interval);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als modify time failed", __func__);
}
}
/* 下发去使能寄存器组的配置 */
static int32_t SetAlsDisable(void)
{
int32_t ret;
struct AlsDrvData *drvData = AlsGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
CHECK_NULL_PTR_RETURN_VALUE(drvData->alsCfg, HDF_ERR_INVALID_PARAM);
if (!drvData->enable) {
HDF_LOGE("%s: Als sensor had disable", __func__);
return HDF_SUCCESS;
}
ret = SetSensorRegCfgArray(&drvData->alsCfg->busCfg, drvData->alsCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als sensor disable config failed", __func__);
return ret;
}
ret = OsalTimerDelete(&drvData->alsTimer);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Als delete timer failed", __func__);
return ret;
}
drvData->enable = false;
return HDF_SUCCESS;
}
SetAlsBatch、SetAlsMode、SetAlsOption
/* 配置传感器采样率和数据上报间隔 */
static int32_t SetAlsBatch(int64_t samplingInterval, int64_t interval)
{
(void)interval;
struct AlsDrvData *drvData = NULL;
drvData = AlsGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
drvData->interval = samplingInterval;
return HDF_SUCCESS;
}
/* 设置传感器工作模式 */
static int32_t SetAlsMode(int32_t mode)
{
if (mode <= SENSOR_WORK_MODE_DEFAULT || mode >= SENSOR_WORK_MODE_MAX) {
HDF_LOGE("%s: The current mode is not supported", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
/* 设置传感器可选配置 */
static int32_t SetAlsOption(uint32_t option)
{
(void)option;
return HDF_SUCCESS;
}
- 注册差异化接口函数——AlsRegisterChipOps
/*在探测到器件在位后,需要调用AlsRegisterChipOps注册差异化适配函数*/
int32_t AlsRegisterChipOps(const struct AlsOpsCall *ops)
{
struct AlsDrvData *drvData = AlsGetDrvData();
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
CHECK_NULL_PTR_RETURN_VALUE(ops, HDF_ERR_INVALID_PARAM);
drvData->ops.Init = ops->Init;
drvData->ops.ReadData = ops->ReadData;
return HDF_SUCCESS;
}
6.1.2 环境光传感器差异化驱动
在OpenHarmony/drivers/framework/model/sensor/driver/chipset/als下新建als_bh1750.h、als_bh1750.c文件;
als_bh1750.h文件:
#ifndef ALS_BH1750_H
#define ALS_BH1750_H
#include "sensor_als_driver.h"
#include "sensor_config_parser.h"
int32_t ReadBh1750Data(struct SensorCfgData *data); // 差异化接口ReadData函数
struct Bh1750DrvData { // Bh1750驱动数据结构体
struct IDeviceIoService ioService;
struct HdfDeviceObject *device;
struct SensorCfgData *sensorCfg;
};
#endif
als_bh1750.c文件:
- 定义并注册驱动入口对象HdfDriverEntry
struct HdfDriverEntry g_alsBh1750DevEntry = {
.moduleVersion = 1,
.moduleName = "HDF_SENSOR_ALS_BH1750",
.Bind = Bh1750BindDriver,
.Init = Bh1750InitDriver,
.Release = Bh1750ReleaseDriver,
};
HDF_INIT(g_alsBh1750DevEntry);
- 实现Bind函数、Dispatch函数、Release函数
/* Dispatch函数 */
static int32_t DispatchBH1750(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
(void)client;
(void)cmd;
(void)data;
(void)reply;
return HDF_SUCCESS;
}
/* Bind函数 */
int32_t Bh1750BindDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Bh1750DrvData *drvData = (struct Bh1750DrvData*)OsalMemCalloc(sizeof(*drvData));
if (drvData == NULL) {
HDF_LOGE("%s: Malloc Bh1750 drv data fail", __func__);
return HDF_ERR_MALLOC_FAIL;
}
drvData->ioService.Dispatch = DispatchBH1750;
drvData->device = device;
device->service = &drvData->ioService;
g_bh1750DrvData = drvData;
return HDF_SUCCESS;
}
/* Release函数 */
void Bh1750ReleaseDriver(struct HdfDeviceObject *device)
{
CHECK_NULL_PTR_RETURN(device);
struct Bh1750DrvData *drvData = (struct Bh1750DrvData *)device->service;
CHECK_NULL_PTR_RETURN(drvData);
if (drvData->sensorCfg != NULL) {
AlsReleaseCfgData(drvData->sensorCfg);
drvData->sensorCfg = NULL;
}
OsalMemFree(drvData);
}
- 实现Init函数
/* Init函数 */
int32_t Bh1750InitDriver(struct HdfDeviceObject *device)
{
int32_t ret;
struct AlsOpsCall ops; // 差异化接口对象
CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
struct Bh1750DrvData *drvData = (struct Bh1750DrvData *)device->service;
CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
drvData->sensorCfg = AlsCreateCfgData(device->property); // 获取传感器配置信息,初始化接口
if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
HDF_LOGD("%s: Creating alscfg failed because detection failed",__func__);
return HDF_ERR_NOT_SUPPORT;
}
ops.Init = NULL;
ops.ReadData = ReadBh1750Data; // 绑定差异化接口ReadData函数
ret = AlsRegisterChipOps(&ops); // 注册差异化适配函数
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Register BH1750 als failed", __func__);
return HDF_FAILURE;
}
ret = InitBh1750(drvData->sensorCfg); // 初始化通信
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: Init BH1750 als failed", __func__);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
static int32_t InitBh1750(struct SensorCfgData *data)
{
CHECK_NULL_PTR_RETURN_VALUE(data, HDF_ERR_INVALID_PARAM);
uint8_t wbuff[2] = { 0x01, 0x10 };
struct I2cMsg msgs[2]; /* 自定义传输的消息结构体数组 */
msgs[0].buf = &wbuff[0]; /* 写入的数据 */
msgs[0].len = 1; /* 写入数据长度 */
msgs[0].addr = 0x23; /* 写入设备地址 */
msgs[0].flags = 0; /* 传输标记为0,默认为写 */
msgs[1].buf = &wbuff[1];
msgs[1].len = 1;
msgs[1].addr = 0x23;
msgs[1].flags = 0;
i2cHandle = I2cOpen(3); // 开启I2C控制器
if (i2cHandle == NULL) {
HDF_LOGE("I2cOpen: failed\n");
return HDF_FAILURE;
}
int32_t ret = -1;
ret = I2cTransfer(i2cHandle, &msgs[0], 2); // 写入指令至传感器
if (ret != 2) {
HDF_LOGE("I2cTransfer: write failed, ret %d\n", ret);
HDF_LOGE("I2cTransfer: write failed, busNum %d\n", 3);
HDF_LOGE("I2cTransfer: write failed, addr %x\n", msgs[0].addr);
return HDF_FAILURE;
}
return HDF_SUCCESS;
}
- 实现差异化接口ReadData函数
int32_t ReadBh1750Data(struct SensorCfgData *data)
{
int32_t ret;
uint8_t rbuff[2] = { 0 };
struct I2cMsg msgs[1]; /* 自定义传输的消息结构体数组 */
msgs[0].buf = rbuff; /* 要读取的数据 */
msgs[0].len = 2; /* 读取数据长度为2 */
msgs[0].addr = 0x23; /* 读取设备地址 */
msgs[0].flags = I2C_FLAG_READ ; /* 标记为读 */
// 阻塞180ms,等待传感器获取光照强度数据
OsalMSleep(180);
// 读取传感器光照强度数据
ret = I2cTransfer(i2cHandle, &msgs[0], 1);
if (ret != 1) {
HDF_LOGE("I2cTransfer: read failed, ret %d\n", ret);
HDF_LOGE("I2cTransfer: read failed, busNum %d\n", 3);
HDF_LOGE("I2cTransfer: read failed, addr %x\n", msgs[2].addr);
return HDF_FAILURE;
}
// 数据转换
uint16_t temp = (rbuff[0]<<8) | rbuff[1];
static uint32_t alsData = 0;
alsData = temp / 1.2;
struct SensorReportEvent event; // 创建报告事件对象
(void)memset_s(&event, sizeof(event), 0, sizeof(event));
event.sensorId = SENSOR_TAG_AMBIENT_LIGHT;
event.option = alsData;
event.mode = SENSOR_WORK_MODE_REALTIME;
event.timestamp = 180 * SENSOR_CONVERT_UNIT * SENSOR_CONVERT_UNIT;
event.dataLen = sizeof(alsData);
event.data = (uint8_t *)&alsData;
ret = ReportSensorEvent(&event); // 通过event上报数据
if (ret != HDF_SUCCESS) {
HDF_LOGE("%s: BH1750 report data failed", __func__);
}
return ret;
}
6.2 驱动编译文件编写
基于HDF驱动框架的Sensor驱动模型进行驱动开发,所有的编译文件都写在以下两个文件中:
OpenHarmony/drivers/adapter/khdf/linux/model/sensor
├──Kconfig
└──Makefile
在OpenHarmony/drivers/adapter/khdf/linux/model/sensor/Kconfig中添加以下模块控制宏,默认为开启:
......
config DRIVERS_HDF_SENSOR_ALS
bool "Enable HDF als sensor driver"
default y
depends on DRIVERS_HDF_SENSOR
help
Answer Y to enable HDF als sensor driver.
config DRIVERS_HDF_SENSOR_ALS_BH1750
bool "Enable HDF als bh1745 sensor driver"
default y
depends on DRIVERS_HDF_SENSOR_ALS
help
Answer Y to enable HDF als bh1745 sensor driver.
......
在OpenHarmony/drivers/adapter/khdf/linux/model/sensor/Makefile下添加以下语句:
......
obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS) +=
$(SENSOR_ROOT_DIR)/als/sensor_als_driver.o
obj-$(CONFIG_DRIVERS_HDF_SENSOR_ALS_BH1750) +=
$(SENSOR_ROOT_DIR)/chipset/als/als_bh1750.o
......
6.3 驱动配置文件编写
相关配置文件的路径如下所示:
OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf
├──device_info
│ └──device_info.hcs
└──sensor
├──als
│ └──bh1750_config.hcs
└──sensor_config.hcs
6.3.1 驱动设备描述
在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/device_info/device_info.hcs文件中配置驱动设备描述信息:
root {
device_info {
......
sensor :: host {
......
device_sensor_als :: device {
device0 :: deviceNode {
policy = 1;
priority = 110;
preload = 0;
permission = 0664;
moduleName = "HDF_SENSOR_ALS";
serviceName = "sensor_als";
deviceMatchAttr = "hdf_sensor_als_driver";
}
}
device_sensor_bh1750 :: device {
device0 :: deviceNode {
policy = 1;
priority = 120;
preload = 0;
permission = 0664;
moduleName = "HDF_SENSOR_ALS_BH1750";
serviceName = "hdf_als_bh1750";
deviceMatchAttr = "hdf_sensor_als_bh1750_driver";
}
}
......
}
......
}
}
6.3.2 驱动私有配置信息
在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/sensor文件夹下新建立als文件夹;
在als文件夹下新建立bh1750_config.hcs文件;
在bh1750_config.hcs文件中配置差异化驱动私有信息:
#include "../sensor_common.hcs"
root {
als_bh1750_chip_config : sensorConfig {
match_attr = "hdf_sensor_als_bh1750_driver";
sensorInfo :: sensorDeviceInfo {
sensorName = "als";
vendorName = "rohm_bh1750"; // max string length is 16 bytes
sensorTypeId = 5; // enum SensorTypeTag
sensorId = 5; // user define sensor id
power = 260;
}
sensorBusConfig :: sensorBusInfo {
busType = 0; // 0:i2c 1:spi
busNum = 3;
busAddr = 0x23;
}
sensorIdAttr :: sensorIdInfo {
chipName = "bh1750";
chipIdRegister = 0x00;
chipIdValue = 0x00;
}
sensorRegConfig {
/* regAddr: register address
value: config register value
len: size of value
mask: mask of value
delay: config register delay time (ms)
opsType: enum SensorOpsType 0-none 1-read 2-write 3-read_check4-update_bit
calType: enum SensorBitCalType 0-none 1-set 2-revert 3-xor 4-left shift 5-right shift
shiftNum: shift bits
debug: 0-no debug 1-debug
save: 0-no save 1-save
*/
/* regAddr, value, mask, len, delay, opsType, calType, shiftNum,debug, save */
initSeqConfig = [
];
enableSeqConfig = [
];
disableSeqConfig = [
];
}
}
}
在OpenHarmony/vendor/hihope/rk3568/hdf_config/khdf/sensor/sensor_config.hcs文件中添加以下语句:
#include "als/bh1750_config.hcs"
7.编译
进入vendor/hihope/rk3568/hdf_config/khdf/hdf_test目录,删除编译hdf.hcs所产生的相关文件:
cd vendor/hihope/rk3568/hdf_config/khdf/hdf_test
rm .*.cmd .*.d *.a *.o *.hcb *.order
具体删除文件如下:
.built-in.a.cmd
.hcs_macro_cases.o.d
.hdf_hcs_hex.o.d
.modules.order.cmd
built-in.a
hcs_macro_cases.o
hdf_hcs.hcb
hdf_hcs_hex.o
modules.order
然后进入out/kernel/src_tmp/linux-5.10目录,执行命令重新编译内核:
cd out/kernel/src_tmp/linux-5.10
./make-ohos.sh TB-RK3568X0 enable_ramdisk
最后回到源码根目录,执行如下命令进行版本编译:
cd -
./build.sh --product-name rk3568 --ccache
8.补充
BH1750FVI是一款用于I2C总线接口的数字环境光传感器,获取的光照强度数据长度为2字节,常用指令如下:
BH1750FV I2C器件地址如下:
- ADDR引脚接高电平:0X5C
- ADDR引脚接低电平:0X23
二、外接环境光传感器应用程序
1.目标
开发实现一个环境光传感器应用程序,通过调用Sensor HDI能力接口来获取光照强度数据。
2.开发环境
硬件平台:润和DAYU200开发板
软件版本:OpenHarmony v3.1 Release
3.目录结构
OpenHarmony
├──applications/sample/als/src
│ │ └──als.c
│ │
│ ├──BUILD.gn
│ └──bundle.json
│
├──build
│ └──subsystem_config.json
│
└──productdefine/common/products
└──rk3568.json
4.开发步骤
4.1 应用程序源文件编写
在OpenHarmony/applications/sample/下新建文件夹目录als/src;
在als/src/下新建als.c文件;
编写als.c文件,通过调用Sensor HDI能力接口来获取光照强度数据。
#include <stdio.h>
#include "stdlib.h"
#include "hdf_base.h"
#include "hdf_io_service_if.h"
#include "sensor_if.h"
#include "sensor_type.h"
#include "osal_time.h"
#define ALS_SERVICE_NAME "als_service"
static const struct SensorInterface *g_sensorDev = NULL; // 保持获取的传感器接口实例地址
/* 订阅者注册数据上报函数 */
static int SensorTestDataCallback(const struct SensorEvents *event)
{
if (event == NULL) {
return -1;
}
printf("ALS Data: [%d lx] \n\r", event->option);
return 0;
}
int main(int argc, char* argv[])
{
int ret = HDF_SUCCESS;
g_sensorDev = NewSensorInterfaceInstance(); // 初始化传感器接口实例
if (g_sensorDev == NULL) {
printf("sensorHdi get Module instace failed\n\r");
}
int32_t count = 0;
struct SensorInformation *sensorInfo = NULL;
ret = g_sensorDev->GetAllSensors(&sensorInfo, &count); // 获取传感器信息
if(ret == HDF_FAILURE){
printf("GetAllSensors failed\n\r");
}
// for (int i = 0; i < count; i++) {
// printf("get sensoriId[%d], info name[%s]\n\r",sensorInfo[i].sensorId, sensorInfo[i].sensorName);
// }
ret = g_sensorDev->Register(0, SensorTestDataCallback); // 注册数据上报回调函数
if(ret == HDF_FAILURE){
printf("Als Register failed\n\r");
}
int32_t sensorInterval = 1000000000; // 数据采样率单位纳秒
ret = g_sensorDev->SetBatch(5, sensorInterval, 1); // 设置数据采样间隔与上报间隔
if(ret == HDF_FAILURE){
printf("Als SetBatch failed\n\r");
}
ret = g_sensorDev->Enable(5); // 使能指定传感器设备
if(ret == HDF_FAILURE){
printf("Als Enable failed\n\r");
}
OsalSleep(10); /* 10s内,观察输出数据 */
ret = g_sensorDev->Disable(5); // 去使能指定传感器设备
if(ret == HDF_FAILURE){
printf("Als Disable failed\n\r");
}
ret = g_sensorDev->Unregister(0, SensorTestDataCallback); // 注销回调函数
if(ret == HDF_FAILURE){
printf("Als Unregister failed\n\r");
}
return ret;
}
4.2 编译组织文件编写
在OpenHarmony/applications/sample/als/下新建BUILD.gn文件,内容如下:
HDF_FRAMEWORKS = "//drivers/framework"
# compile 'als' for ohos_standard(linux)
import("//build/ohos.gni")
import("//drivers/adapter/uhdf2/uhdf.gni")
print("als:: compile 'als' for ohos_standard(linux)")
ohos_executable("als") {
defines = [ "__USER__" ]
sources = [
"src/als.c"
]
include_dirs = [
"$HDF_FRAMEWORKS/include",
"$HDF_FRAMEWORKS/include/core",
"$HDF_FRAMEWORKS/include/osal",
"$HDF_FRAMEWORKS/include/platform",
"$HDF_FRAMEWORKS/include/utils",
"//third_party/bounds_checking_function/include",
"//drivers/adapter/uhdf2/ipc/include",
"//drivers/adapter/uhdf2/osal/include",
"//base/hiviewdfx/hilog/interfaces/native/innerkits/include",
"//drivers/peripheral/sensor/interfaces/include",
]
deps = [
"//base/hiviewdfx/hilog/interfaces/native/innerkits:libhilog",
"//drivers/adapter/uhdf2/utils:libhdf_utils",
"//drivers/peripheral/sensor/hal:hdi_sensor",
]
cflags = [
"-Wall",
"-Wextra",
"-Werror",
"-Wno-format",
"-Wno-format-extra-args",
]
subsystem_name = "als"
part_name = "als"
}
在OpenHarmony/applications/sample/als/下新建bundle.json文件,内容如下:
{
"name": "@ohos/als",
"description": "als.",
"version": "3.1",
"license": "Apache License 2.0",
"publishAs": "code-segment",
"segment": {
"destPath": "applications/sample/als"
},
"dirs": {},
"scripts": {},
"component": {
"name": "als",
"subsystem": "als",
"syscap": [],
"features": [],
"adapted_system_type": [ "mini", "small", "standard" ],
"rom": "10KB",
"ram": "10KB",
"deps": {
"components": [],
"third_party": []
},
"build": {
"sub_component": [
"//applications/sample/als:als"
],
"inner_kits": [],
"test": []
}
}
}
4.3 相关配置文件修改
在OpenHarmony/build/subsystem_config.json中添加新建的子系统的配置:
"als": {
"path": "applications/sample/als",
"name": "als"
},
在OpenHarmony/productdefine/common/products/rk3568.json中添加对应的部件:
"als:als":{},
5.编译验证
进入源码根目录,执行如下命令进行版本编译:
./build.sh --product-name rk3568 --ccache
编译完成后,通过工具RKDevTool将镜像烧录到单板;
烧录完成后,通过串口调试执行als程序,示例如下:
# als
ALS Data: [225 lx]
ALS Data: [226 lx]
ALS Data: [222 lx]
ALS Data: [225 lx]
ALS Data: [226 lx]
ALS Data: [226 lx]
ALS Data: [65 lx]
ALS Data: [75 lx]
ALS Data: [60 lx]
ALS Data: [18 lx]
更多推荐
所有评论(0)