您当前的位置:首页 > 电脑百科 > 程序开发 > 移动端 > 鸿蒙

OpenHarmony南向之旅之HDF传感器驱动开发

时间:2023-03-16 14:25:35  来源:  作者:Haoc_小源同学

前言

南向小白在AlgoIdeas指导下的一次基于HDF框架开发温度传感器驱动之旅,主要内容为开发温度传感器通用驱动代码以及针对SHT31传感器开发差异化驱动代码,读者可以和基于HDF驱动框架的温度传感器驱动开发一起看。本文旨在分享笔者开发过程中的一些经验,文章可能存在用词不专业或说法有误之处,欢迎各位指正

开发准备

硬件环境

  1. Unionpi Tiger开发板
  2. SHT31温湿度传感器

关于SHT31温湿度传感器的介绍不在本篇的讨论范围内,在开发中需要用到的一些寄存器地址信息读者可以自行查找阅读该器件的datasheet

在开发之前我们先简单了解一下源码驱动目录

在OpenHarmony根目录下的drivershdf_coreframeworkmodelsensordriver目录,这里存放的是通用传感器驱动代码目录,主要是由HDF Sensor驱动框架提供的Init、Enable、Disable等接口实现

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

而在driversperipheralsensorchipset目录下存放的是传感器差异化驱动代码,主要是根据不同的传感器芯片型号在通用传感器驱动代码提供出来的接口上进行开发适配,例如温度传感器有SHT3x、AHT系列等,这就需要分别进行开发

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

开发流程

添加配置

在HDF框架的配置文件(例如笔者这里是vendorunionmanunionpi_tigerhdf_configkhdfdevice_infodevice_info.hcs)中的Sensor Host添加该驱动的配置信息

/* 温度计传感器设备HCS配置 */
device_sensor_temperature :: device {
    device0 :: deviceNode {
        policy = 1;
        priority = 130;
        preload = 0;
        permission = 0664;
        moduleName = "HDF_SENSOR_TEMPERATURE";
        serviceName = "sensor_temperature";
        deviceMatchAttr = "hdf_sensor_temperature_driver";
    }
}
device_sensor_sht31 :: device {
    device0 :: deviceNode {
        policy = 1;              // 驱动对外发布服务的策略(0-4),具体可以查看参考资料[3]
        priority = 140;          // 驱动启动优先级(0-200),值越大优先级越低,建议默认配100,优先级相同则不保证device的加载顺序。
        preload = 0;             // 驱动按需加载字段。
        permission = 0664;       // 驱动创建设备节点权限
        moduleName = "HDF_SENSOR_TEMPERATURE_SHT31";      // 驱动名称,该字段的值必须和驱动入口结构的moduleName值一致。
        serviceName = "hdf_temperature_sht31";    // 驱动对外发布服务的名称,必须唯一。
        deviceMatchAttr = "hdf_sensor_temperature_sht31_driver"; // 驱动私有数据匹配的关键字,必须和驱动私有数据配置表中的match_attr值相等。
    }
}
 

对应关系如下
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

通用驱动代码开发

1.基于HDF驱动框架,按照驱动Driver Entry程序,完成温度抽象驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现

  • 温度传感器驱动入口函数实现
/* 注册温度计传感器入口数据结构体对象 */
struct HdfDriverEntry g_sensorTemperatureDevEntry = {
    .moduleVersion = 1,                // 温度计传感器模块版本号
    .moduleName = "HDF_SENSOR_TEMPERATURE",  // 温度计传感器模块名,要与device_info.hcs文件里的温度计moduleName字段值一样
    .Bind = TemperatureBindDriver,           // 温度计传感器绑定函数
    .Init = TemperatureInitDriver,           // 温度计传感器初始化函数
    .Release = TemperatureReleaseDriver,     // 温度计传感器资源释放函数
};

/* 调用HDF_INIT将驱动入口注册到HDF框架中。在加载驱动时HDF框架会先调用Bind函数,再调用Init函数加载该驱动。当Init调用异常时,HDF框架会调用Release释放驱动资源并退出 */
HDF_INIT(g_sensorTemperatureDevEntry);
 
  • 温度传感器驱动操作接口实现
/* 温度计传感器驱动对外提供的服务绑定到HDF框架 */
int32_t TemperatureBindDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) {
        HDF_LOGI("%s: malloc temperature drv data fAIl!", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    drvData->IOService.Dispatch = DispatchTemperature;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_temperatureDrvData = drvData;
    return HDF_SUCCESS;
}

/* 注册温度计传感器驱动归一化的接口函数 */
static int32_t InitTemperatureOps(struct SensorCfgData *config, struct SensorDeviceInfo *deviceInfo)
{
    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    deviceInfo->ops.Enable = SetTemperatureEnable;
    deviceInfo->ops.Disable = SetTemperaturedisable;
    deviceInfo->ops.SetBatch = SetTemperatureBatch;
    deviceInfo->ops.SetMode = SetTemperatureMode;
    deviceInfo->ops.SetOption = SetTemperatureOption;

    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;
}

/* 提供给差异化驱动的初始化接口,完成温度器件基本配置信息解析(温度信息、温度总线配置、温度器件探测寄存器配置)、器件探测、器件寄存器解析 */
static int32_t InitTemperatureAfterDetected(struct SensorCfgData *config)
{
    struct SensorDeviceInfo deviceInfo;
    CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM);

    if (InitTemperatureOps(config, &deviceInfo) != HDF_SUCCESS) {
        HDF_LOGE("%s: Init temperature ops failed", __func__);
        return HDF_FAILURE;
    }

    if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) {
        HDF_LOGE("%s: Add temperature device failed", __func__);
        return HDF_FAILURE;
    }

    if (ParseSensorRegConfig(config) != HDF_SUCCESS) {
        HDF_LOGE("%s: Parse sensor register failed", __func__);
        (void)DeleteSensorDevice(&config->sensorInfo);
        ReleaseSensorAllRegConfig(config);
        return HDF_FAILURE;
    }
    return HDF_SUCCESS;
}

/* 温度计传感器驱动初始化入口函数,主要功能为对传感器私有数据的结构体对象进行初始化,传感器HCS数据配置对象空间分配,传感器HCS数据配置初始化入口函数调用,传感器设备探测是否在位功能,传感器数据上报定时器创建,传感器归一化接口注册,传感器设备注册功能 */ 
int32_t TemperatureInitDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    /* 工作队列资源初始化 */
    if (InitTemperatureData(drvData) != HDF_SUCCESS) {
        HDF_LOGE("%s: Init accel config failed", __func__);
        return HDF_FAILURE;
    }
    /* 分配温度配置信息资源 */
    drvData->temperatureCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData->temperatureCfg));
    if (drvData->temperatureCfg == NULL) {
        HDF_LOGE("%s: Malloc temperature config data failed", __func__);
        return HDF_FAILURE;
    }
    /* 注册寄存器分组信息 */
    drvData->temperatureCfg->regCfgGroup = &g_regCfgGroup[0];

    HDF_LOGI("%s: Init temperature driver success", __func__);
    return HDF_SUCCESS;
}
/* 释放驱动初始化时分配的资源 */
void TemperatureReleaseDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN(device);

    struct TemperatureDrvData *drvData = (struct TemperatureDrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);
    /* 器件在位,释放已分配资源 */
    if (drvData->detectFlag && drvData->temperatureCfg != NULL) {
        TemperatureReleaseCfgData(drvData->temperatureCfg);
    }

    OsalMemFree(drvData->temperatureCfg);
    drvData->temperatureCfg = NULL;
    /* 器件在位,销毁工作队列资源 */
    HdfWorkDestroy(&drvData->temperatureWork);
    HdfWorkQueueDestroy(&drvData->temperatureWorkQueue);
    OsalMemFree(drvData);
}
 

2.完成温度传感器抽象驱动内部接口开发,包括Enable、Disable、SetBatch、SetMode、SetOption、AccelCreateCfgData、AccelReleaseCfgData、AccelRegisterChipOps接口实现

/* 下发使能寄存器组的配置 */
static int32_t SetTemperatureEnable(void)
{
    int32_t ret;
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    CHECK_NULL_PTR_RETURN_VALUE(drvData->temperatureCfg, HDF_ERR_INVALID_PARAM);

    if (drvData->enable) {
        HDF_LOGE("%s: temperature sensor is enabled", __func__);
        return HDF_SUCCESS;
    }

    ret = SetSensorRegCfgArray(
        &drvData->temperatureCfg->busCfg, drvData->temperatureCfg->regCfgGroup[SENSOR_ENABLE_GROUP]);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: temperature sensor enable config failed", __func__);
        return ret;
    }

    ret = OsalTimerCreate(&drvData->temperatureTimer, SENSOR_TIMER_MIN_TIME, TemperatureTimerEntry, (uintptr_t)drvData);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: temperature create timer failed[%d]", __func__, ret);
        return ret;
    }

    ret = OsalTimerStartLoop(&drvData->temperatureTimer);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: temperature start timer failed[%d]", __func__, ret);
        return ret;
    }
    drvData->enable = true;

    return HDF_SUCCESS;
}
/* 下发去使能寄存器组的配置 */
static int32_t SetTemperatureDisable(void)
{
    int32_t ret;
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);
    CHECK_NULL_PTR_RETURN_VALUE(drvData->temperatureCfg, HDF_ERR_INVALID_PARAM);

    if (!drvData->enable) {
        HDF_LOGE("%s: temperature sensor had disable", __func__);
        return HDF_SUCCESS;
    }

    ret = SetSensorRegCfgArray(
        &drvData->temperatureCfg->busCfg, drvData->temperatureCfg->regCfgGroup[SENSOR_DISABLE_GROUP]);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: temperature sensor disable config failed", __func__);
        return ret;
    }

    ret = OsalTimerDelete(&drvData->temperatureTimer);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: temperature delete timer failed", __func__);
        return ret;
    }
    drvData->enable = false;
    return HDF_SUCCESS;
}
/* 配置传感器采样率和数据上报间隔 */
static int32_t SetTemperatureBatch(int64_t samplingInterval, int64_t interval)
{
    (void)interval;

    struct TemperatureDrvData *drvData = NULL;

    drvData = TemperatureGetDrvData();
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    drvData->interval = samplingInterval;

    return HDF_SUCCESS;
}
/* 设置传感器工作模式,当前支持实时模式 */
static int32_t SetTemperatureMode(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 SetTemperatureOption(uint32_t option)
{
    (void)option;
    return HDF_SUCCESS;
}
/* 创建传感器配置数据接口 */
struct SensorCfgData *TemperatureCreateCfgData(const struct DeviceResourceNode *node)
{
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    if (drvData == NULL || node == NULL) {
        HDF_LOGE("%s: Temperature node pointer NULL", __func__);
        return NULL;
    }
    /* 如果探测不到器件在位,返回进行下个器件探测 */
    if (drvData->detectFlag) {
        HDF_LOGE("%s: Temperature sensor have detected", __func__);
        return NULL;
    }

    if (drvData->temperatureCfg == NULL) {
        HDF_LOGE("%s: Temperature temperatureCfg pointer NULL", __func__);
        return NULL;
    }
	/* 解析器件HCS私有配置信息 */
    if (GetSensorBaseConfigData(node, drvData->temperatureCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: Get sensor base config failed", __func__);
        goto BASE_CONFIG_EXIT;
    }
    /* 如果探测不到器件在位,返回进行下个器件探测 */
    if (DetectSensorDevice(drvData->temperatureCfg) != HDF_SUCCESS) {
        HDF_LOGI("%s: Temperature sensor detect device no exist", __func__);
        drvData->detectFlag = false;
        goto BASE_CONFIG_EXIT;
    }

    drvData->detectFlag = true;
    /* 器件寄存器解析 */
    if (InitTemperatureAfterDetected(drvData->temperatureCfg) != HDF_SUCCESS) {
        HDF_LOGE("%s: Temperature sensor detect device no exist", __func__);
        goto INIT_EXIT;
    }
    return drvData->temperatureCfg;

INIT_EXIT:
    (void)ReleaseSensorBusHandle(&drvData->temperatureCfg->busCfg);
BASE_CONFIG_EXIT:
    drvData->temperatureCfg->root = NULL;
    (void)memset_s(
        &drvData->temperatureCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));
    (void)memset_s(&drvData->temperatureCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
    (void)memset_s(&drvData->temperatureCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));
    return drvData->temperatureCfg;
}
/* 释放传感器配置数据接口 */
void TemperatureReleaseCfgData(struct SensorCfgData *temperatureCfg)
{
    CHECK_NULL_PTR_RETURN(temperatureCfg);

    (void)DeleteSensorDevice(&temperatureCfg->sensorInfo);
    ReleaseSensorAllRegConfig(temperatureCfg);
    (void)ReleaseSensorBusHandle(&temperatureCfg->busCfg);

    temperatureCfg->root = NULL;
    (void)memset_s(&temperatureCfg->sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo));
    (void)memset_s(&temperatureCfg->busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg));
    (void)memset_s(&temperatureCfg->sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));
}
/* 注册传感器差异化接口 */
int32_t TemperatureRegisterChipOps(const struct TemperatureOpsCall *ops)
{
    struct TemperatureDrvData *drvData = TemperatureGetDrvData();

    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;
}
 

差异化驱动代码开发

1.基于HDF驱动框架,按照驱动Driver Entry程序,完成温度传感器差异化驱动开发,主要由Bind、Init、Release、Dispatch函数接口实现

/* 温度计传感器差异化驱动消息交互 */
static int32_t DispatchSHT31(struct HdfDeviceIoClient *client, int cmd, struct HdfSBuf *data, struct HdfSBuf *reply)
{
    (void)client;
    (void)cmd;
    (void)data;
    (void)reply;

    return HDF_SUCCESS;
}
/* 温度计传感器差异化驱动对外提供的服务绑定到HDF框架 */
int32_t SHT31BindDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)OsalMemCalloc(sizeof(*drvData));
    if (drvData == NULL) {
        HDF_LOGE("%s: Malloc SHT31 drv data fail", __func__);
        return HDF_ERR_MALLOC_FAIL;
    }

    drvData->ioService.Dispatch = DispatchSHT31;
    drvData->device = device;
    device->service = &drvData->ioService;
    g_sht31DrvData = drvData;

    return HDF_SUCCESS;
}
/* 温度计传感器差异化驱动初始化 */
int32_t SHT31InitDriver(struct HdfDeviceObject *device)
{
    int32_t ret;
    struct TemperatureOpsCall ops;

    CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);
    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN_VALUE(drvData, HDF_ERR_INVALID_PARAM);

    drvData->sensorCfg = TemperatureCreateCfgData(device->property);
    if (drvData->sensorCfg == NULL || drvData->sensorCfg->root == NULL) {
        HDF_LOGD("%s: Creating temperaturecfg failed because detection failed", __func__);
        return HDF_ERR_NOT_SUPPORT;
    }

    ops.Init = NULL;
    ops.ReadData = ReadSHT31Data;
    ret = TemperatureRegisterChipOps(&ops);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Register SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    }

    ret = InitSHT31(drvData->sensorCfg);
    if (ret != HDF_SUCCESS) {
        HDF_LOGE("%s: Init SHT31 temperature failed", __func__);
        return HDF_FAILURE;
    }

    HDF_LOGI("%s: Init SHT31 temperature success", __func__);
    return HDF_SUCCESS;
}
/* 释放驱动初始化时分配的资源 */
void SHT31ReleaseDriver(struct HdfDeviceObject *device)
{
    CHECK_NULL_PTR_RETURN(device);

    struct SHT31DrvData *drvData = (struct SHT31DrvData *)device->service;
    CHECK_NULL_PTR_RETURN(drvData);

    if (drvData->sensorCfg != NULL) {
        TemperatureReleaseCfgData(drvData->sensorCfg);
        drvData->sensorCfg = NULL;
    }
    OsalMemFree(drvData);
}
/* 温度传感器差异化驱动对应的HdfDriverEntry对象 */
struct HdfDriverEntry g_temperatureSHT31DevEntry = {
    .moduleVersion = 1,
    .moduleName = "HDF_SENSOR_TEMPERATURE_SHT31",
    .Bind = SHT31BindDriver,
    .Init = SHT31InitDriver,
    .Release = SHT31ReleaseDriver,
};

HDF_INIT(g_temperatureSHT31DevEntry);
 

2.完成温度传感器差异化驱动中差异化接口ReadData函数实现

int32_t ReadSHT31Data(struct SensorCfgData *data)
{
    int32_t ret;
    static int32_t tmp;
    struct TemperaturemeterData temperaturemeterData = {0};
    OsalTimespec time;
    struct SensorReportEvent event;

    (void)memset_s(&time, sizeof(time), 0, sizeof(time));
    (void)memset_s(&event, sizeof(event), 0, sizeof(event));

    if (OsalGetTime(&time) != HDF_SUCCESS) {
        HDF_LOGE("%s: Get time failed", __func__);
        return HDF_FAILURE;
    }
    event.timestamp = time.sec * SENSOR_SECOND_CONVERT_NANOSECOND + time.usec * SENSOR_CONVERT_UNIT;

    ret = ReadSHT31RawData(data, &temperaturemeterData);
    if (ret != HDF_SUCCESS) {
        return HDF_FAILURE;
    }

    event.sensorId = data->sensorInfo.sensorId;
    event.mode = SENSOR_WORK_MODE_REALTIME;

    tmp = temperaturemeterData.temperature;

    event.dataLen = sizeof(tmp);
    event.data = (uint8_t *)&tmp;
    ret = ReportSensorEvent(&event);
    return ret;
}
 

添加差异化配置文件

sht31_config.hcs文件参考

文件路径

vendorunionmanunionpi_tigerhdf_configkhdfsensortemperaturesht31_config.hcs
 
#include "../sensor_common.hcs"
root {
    temperature_sht31_chip_config : sensorConfig {
        match_attr = "hdf_sensor_temperature_sht31_driver";
        sensorInfo :: sensorDeviceInfo {
            sensorName = "temperaturemeter";
            vendorName = "sensirion_sht31"; // max string length is 16 bytes
            sensorTypeId = 9; // enum SensorTypeTag
            sensorId = 1; // user define sensor id
            power = 230;
            minDelay = 0;
            maxDelay = 0;
        }
        sensorBusConfig :: sensorBusInfo {
            busType = 0; // 0:i2c 1:spi
            busNum = 5;
            busAddr = 0x45;
            regWidth = 2; // 2 byte
        }
        sensorIdAttr :: sensorIdInfo {
            chipName = "sht31";
            chipIdRegister = 0xF32D;
            chipIdValue = 0x80;
        }
        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_check 4-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 = [
                0x30A2,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
            enableSeqConfig = [
                0x2C06,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
            disableSeqConfig = [
                0x2400,    0x0, 0x0,   0,     5,       2,       0,        0,     0,    0
            ];
        }
    }
}
 

对应关系如下
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

编译准备

打开vendorunionmanunionpi_tigerhdf_configkhdfsensorsensor_config.hcs文件并include差异化配置文件

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

修改drivershdf_coreadapterkhdflinuxmodelsensorMakefile编译文件

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

修改drivershdf_coreadapterkhdflinuxmodelsensorKconfig配置文件

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

deviceboardunionmanunionpi_tigerkernelbuildunionpi_tiger_standard_defconfig打开CONFIG_DRIVERS_HDF_SENSOR
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区
对应关系如下
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

运行结果

成功初始化SHT31传感器驱动
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

测试

测试代码参考

代码路径

vendorunionmanunionpi_tigersamplehdftemperaturetemperature.cpp
 
#include <unistd.h>
#include <stdio.h>
#include "hdf_base.h"
#include "hdf_log.h"
#include "hdf_sbuf.h"
#include "hdf_io_service_if.h"
#include "sensor_if.h"
#include "sensor_type.h"

/* 创建回调函数 */
int32_t SensorDataCallback(const struct SensorEvents *event)
{
    if (event == NULL) {
        return HDF_FAILURE;
    }
    float *data = (float *)event->data;
    printf("sensor data %.2f°Cn", *data);
    return HDF_SUCCESS;
}

void SensorSample(void)
{
    int ret;
    struct SensorInformation *sensorInfo = NULL;
    int32_t count = 0;
    int32_t sensorInterval = 200000000; /* 数据采样率设置200毫秒,单位纳秒 */
    int32_t reportInterval = 400000000;

    /* 1.创建传感器接口实例 */
    const struct SensorInterface *sensorDev = NewSensorInterfaceInstance();
    if (sensorDev == NULL) {
        return;
    }
    printf("NewSensorInterfaceInstance successn");
    /* 2.订阅者注册传感器数据回调处理函数 */
    ret = sensorDev->Register(0, SensorDataCallback);
    if (ret != 0) {
        return;
    }
    printf("Register successn");
    /* 3.获取设备支持的Sensor列表 */
    ret = sensorDev->GetAllSensors(&sensorInfo, &count);
    if (ret != 0) {
        return;
    }
    printf("GetAllSensors success,count: %dn sensorName:%sn vendorName:%sn sensorTypeId:%dn sensorId:%dn", count,
           sensorInfo->sensorName, sensorInfo->vendorName, sensorInfo->sensorTypeId, sensorInfo->sensorId);
    /* 4.设置传感器采样率 */
    ret = sensorDev->SetBatch(sensorInfo->sensorId, sensorInterval, reportInterval);
    if (ret != 0) {
        printf("SetBatch failedn ,ret: %d", ret);
        return;
    }
    printf("SetBatch successn");
    /* 5.使能传感器 */
    ret = sensorDev->Enable(sensorInfo->sensorId);
    if (ret != 0) {
        return;
    }
    printf("Enable successn");

    usleep(2000 * 1000);

    /* 6.去使能传感器 */
    ret = sensorDev->Disable(sensorInfo->sensorId);
    if (ret != 0) {
        printf("Disable failedn ,ret: %d", ret);
        return;
    }
    printf("Disable successn");
    /* 7.取消传感器数据订阅函数 */
    ret = sensorDev->Unregister(0, SensorDataCallback);
    if (ret != 0) {
        return;
    }
    printf("Unregister successn");
    /* 8.释放传感器接口实例 */
    ret = FreeSensorInterfaceInstance();
    if (ret != 0) {
        return;
    }
    printf("FreeSensorInterfaceInstance successn");
}

int main(int argc, char *argv[])
{
    SensorSample();
    return HDF_SUCCESS;
}
 

BUILD.gn参考

import("//build/ohos.gni")

ohos_executable("temperature") {
  sources = [ "temperature.cpp" ]

  deps = [ "//drivers/peripheral/sensor/hal:hdi_sensor" ]

  external_deps = [
    "hiviewdfx_hilog_native:libhilog",
  ]

  cflags = [
    "-Wall",
    "-Wextra",
    "-Werror",
    "-Wno-format",
    "-Wno-format-extra-args",
  ]

  install_enable = true
  install_images = [ "vendor" ]
  module_install_dir = "bin"
  part_name = "unionman_products"
}
 

编译命令

./build.sh --product-name unionpi_tiger --build-target vendor/unionman/unionpi_tiger/sample/hdf/temperature:temperature
 

生成可执行文件所在位置

outunionpi_tigerdevice_unionpi_tigerunionman_products
 

将可执行文件push到system/bin目录下,添加执行权限

hdc shell mount -o remount,rw /
hdc file send <PATH>outunionpi_tigerdevice_unionpi_tigerunionman_productstemperature /system/bin
hdc shell chmod 744 system/bin/temperature
 

运行结果

成功打印驱动上报的温度数据
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

踩坑记录

基本上按照HDF框架开发步骤来还是比较简单的,笔者是第一次玩驱动开发,相信对驱动开发熟悉的开发者来说HDF框架是很友好的。笔者踩的一些坑主要是因为笔者对南向开发不熟悉,没有玩过硬件

1.这款传感器的寄存器地址是两个字节,而HDF框架源码的逻辑只能处理一个字节,会出现以下错误
OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

这里就不放出笔者修改的代码了,这部分源码后续官方应该会优化

2.由于这款传感器没有chipId,所以私有化配置文件中的chipIdValue字段的值填写打印出来的128,也就是0x80(这样做可能不太正规,有更好的做法欢迎指出)

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

3.由于笔者不太理解ReadSensor接口中的regAddr参数,传了不正确的值

int32_t ReadSensor(struct SensorBusCfg *busCfg, uint16_t regAddr, uint8_t *data, uint16_t dataLen)

导致出现了如下结果

OpenHarmony南向之旅之HDF传感器驱动开发-开源基础软件社区

结语

以上仅为个人浅见,如有疑问,欢迎留言交流

参考文档

[1]Sensor驱动模型接口说明

[2]drivers_peripheral

[3]驱动服务管理



Tags:OpenHarmony   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
OpenHarmony - 基于ArkUI框架实现日历应用
前言对于刚刚接触OpenHarmony应用开发的开发者,最快的入门方式就是开发一个简单的应用,下面记录了一个日历应用的开发过程,通过日历应用的开发,来熟悉基本图形的绘制,ArkUI的组件...【详细内容】
2024-01-16  Search: OpenHarmony  点击:(54)  评论:(0)  加入收藏
OpenHarmony4.0发布:新增4000多个API接口,交互及隐私能力增强
钛媒体App 11月6日消息,以“技术筑生态,智联赢未来”为主题的第二届OpenHarmony技术大会在北京举办,活动中,OpenHarmony 4.0版本正式发布。据介绍,OpenHarmony4.0版本开发套件同...【详细内容】
2023-11-07  Search: OpenHarmony  点击:(139)  评论:(0)  加入收藏
OpenHarmony,奏响中国基础软件的“光辉岁月”
梦想需要多久的时间,多少血和泪,才能慢慢实现?天地间任我展翅高飞,谁说那是天真的预言?《光辉岁月》歌词中的这两个问题,恰好可以送给今天的中国基础软件事业。曾几何时,我们认为中...【详细内容】
2023-11-07  Search: OpenHarmony  点击:(101)  评论:(0)  加入收藏
OpenHarmony:如何使用HDF驱动控制LED灯
一、程序简介该程序是基于OpenHarmony标准系统编写的基础外设类:RGB LED。目前已在凌蒙派-RK3568开发板跑通。详细资料请参考官网:https://gitee.com/Lockzhiner-Electronics/...【详细内容】
2023-09-08  Search: OpenHarmony  点击:(263)  评论:(0)  加入收藏
深入了解华为OpenHarmony开源系统的架构与功能
当下最火的科技圈新闻,莫过于华为即将发布的Mate 60系列手机,但是今天摸鱼君不讲这些,毕竟我也没抢到,我也不是专业测评。但是以我所长说说它搭载鸿蒙系统的一些内容。 鸿蒙系...【详细内容】
2023-09-07  Search: OpenHarmony  点击:(208)  评论:(0)  加入收藏
OpenHarmony中使用MQTT
MQTT**(**消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而...【详细内容】
2023-08-29  Search: OpenHarmony  点击:(432)  评论:(0)  加入收藏
OpenHarmony组件复用示例
OpenHarmony组件复用示例 摘要:在开发应用时,有些场景下的自定义组件具有相同的组件布局结构,仅有状态变量等承载数据的差异。这样的组件缓存起来,需要使用到该组件时直接复用,...【详细内容】
2023-08-28  Search: OpenHarmony  点击:(352)  评论:(0)  加入收藏
OpenHarmony运行docker详细步骤
本文将介绍如何在OpenHarmony内核上运行docker容器。 目录 1.环境和设备 2.准备支持Docker容器的OpenHarmony内核 3.编译烧录镜像 4.安装docker容器引擎组件 5.格式...【详细内容】
2023-07-28  Search: OpenHarmony  点击:(399)  评论:(0)  加入收藏
OpenHarmony 3.2 Release新特性解读之驱动HCS
HCS(HDF Configuration Source)是HDF驱动框架的配置描述源码,内容以Key-Value为主要形式。它实现了配置代码与驱动代码解耦,便于开发者进行配置管理。OpenAtom OpenHarmony(以下...【详细内容】
2023-06-01  Search: OpenHarmony  点击:(328)  评论:(0)  加入收藏
OpenHarmony系统之Service代码一键生成工具介绍
作者:苟晶晶前言当开发者为OpenHarmony系统框架开发某些功能时,有时需要将这个功能包装成一个独立的服务进程运行在系统中,为了其它应用进程能够调用此服务,开发人员需要基于系...【详细内容】
2023-05-31  Search: OpenHarmony  点击:(287)  评论:(0)  加入收藏
▌简易百科推荐
OpenHarmony - 基于ArkUI框架实现日历应用
前言对于刚刚接触OpenHarmony应用开发的开发者,最快的入门方式就是开发一个简单的应用,下面记录了一个日历应用的开发过程,通过日历应用的开发,来熟悉基本图形的绘制,ArkUI的组件...【详细内容】
2024-01-16    51CTO  Tags:OpenHarmony   点击:(54)  评论:(0)  加入收藏
鸿蒙工程师,熬来了「造富时代」
  作者|张俊  来源|新浪科技  ID|techsina  “套壳安卓”的质疑言犹在耳,如今华为正在计划将鸿蒙OS与安卓完全脱离。  此前,鸿蒙OS为了迅速扩大用户规模,采取了兼容安卓...【详细内容】
2023-11-20    锌财经  Tags:鸿蒙   点击:(213)  评论:(0)  加入收藏
OpenHarmony:如何使用HDF驱动控制LED灯
一、程序简介该程序是基于OpenHarmony标准系统编写的基础外设类:RGB LED。目前已在凌蒙派-RK3568开发板跑通。详细资料请参考官网:https://gitee.com/Lockzhiner-Electronics/...【详细内容】
2023-09-08    51CTO  Tags:OpenHarmony   点击:(263)  评论:(0)  加入收藏
深入了解华为OpenHarmony开源系统的架构与功能
当下最火的科技圈新闻,莫过于华为即将发布的Mate 60系列手机,但是今天摸鱼君不讲这些,毕竟我也没抢到,我也不是专业测评。但是以我所长说说它搭载鸿蒙系统的一些内容。 鸿蒙系...【详细内容】
2023-09-07  摸鱼IT  微信公众号  Tags:OpenHarmony   点击:(208)  评论:(0)  加入收藏
鸿蒙操作系统开发 搭建环境
2019年8月9日,华为在东莞举行华为开发者大会,正式发布鸿蒙操作系统;2020年9月推出了鸿蒙2.0,全面使能全场景生态,具备跨设备、服务流转、极速直达、可视可说、隐私安全五大能力。...【详细内容】
2023-09-07  清华计算机学堂  微信公众号  Tags:鸿蒙   点击:(198)  评论:(0)  加入收藏
OpenHarmony中使用MQTT
MQTT**(**消息队列遥测传输)是ISO 标准(ISO/IEC PRF 20922)下基于发布/订阅范式的消息协议。它工作在TCP/IP协议族上,是为硬件性能低下的远程设备以及网络状况糟糕的情况下而...【详细内容】
2023-08-29    51CTO  Tags:OpenHarmony   点击:(432)  评论:(0)  加入收藏
OpenHarmony组件复用示例
OpenHarmony组件复用示例 摘要:在开发应用时,有些场景下的自定义组件具有相同的组件布局结构,仅有状态变量等承载数据的差异。这样的组件缓存起来,需要使用到该组件时直接复用,...【详细内容】
2023-08-28  zhushangyuan  51CTO  Tags:OpenHarmony   点击:(352)  评论:(0)  加入收藏
HarmonyOS开发第一步,熟知开发工具DevEco Studio
俗话说的好,工欲善其事,必先利其器,走进HarmonyOS第一步,开发工具必须先行,当然了,关于开发工具的使用,官网和其他的博客也有很多的讲解,但是并没有按照常用的功能进行概述,如果需要...【详细内容】
2023-08-22  程序员一鸣  今日头条  Tags:HarmonyOS   点击:(205)  评论:(0)  加入收藏
鸿蒙元服务开发实例:桌面卡片上的电动自行车助手E-Bike
E-Bike是一款基于HarmonyOS开发的元服务,以万能卡片的形式给骑行提供便捷服务。首先需要完成HarmonyOS开发环境搭建。一、元服务E-Bike简介E-Bike是一款基于HarmonyOS开发的...【详细内容】
2023-08-16    51CTO  Tags:鸿蒙   点击:(302)  评论:(0)  加入收藏
OpenHarmony运行docker详细步骤
本文将介绍如何在OpenHarmony内核上运行docker容器。 目录 1.环境和设备 2.准备支持Docker容器的OpenHarmony内核 3.编译烧录镜像 4.安装docker容器引擎组件 5.格式...【详细内容】
2023-07-28  离北况归  51CTO  Tags:OpenHarmony   点击:(399)  评论:(0)  加入收藏
站内最新
站内热门
站内头条