作者介紹
劉飛虎(kevin),擔任OpenHarmony社區SIG_DriverFramework組committer,主要負責傳感器驅動模型驅動開發工作,貢獻傳感器驅動模型驅動和加速度傳感器驅動。
概述
隨著物聯網,移動互聯網的快速發展,在數字時代,傳感器在智能交通,智能工業,智能穿戴等領域有著廣闊的應用空間。傳感器是檢測到被測量信息,將非電量信息轉換成電信號的檢測裝置。就像眼睛是人類心靈的窗戶,傳感器則是計算機感知世界萬物的眼睛。
近年來,傳感器技術和制造工藝的快速發展,目前市場可供開發者選擇的傳感器越來越多,比如:加速度傳感器,陀螺儀傳感器,磁力傳感器,溫度傳感器等類型。每種傳感器廠家都有各自的傳感器驅動。
在產品開發時就需要對不同廠家或者同一廠家的不同型號進行適配開發,就會增加開發者的開發難度。為了快速開發或者移植傳感器驅動,基于HDF(Hardware Driver Foundation)驅動框架開發了Sensor(傳感器)驅動模型。Sensor驅動模型主要為上層提供穩定接口能力,對驅動開發者提供開放的接口實現和抽象的配置接口能力。
傳感器模型框架介紹
Sensor設備作為外接設備重要組成模塊,Sensor驅動模型為上層Sensor服務系統提供穩定的Sensor基礎能力接口,包括Sensor列表查詢、Sensor啟停、Sensor訂閱及去訂閱,Sensor參數配置等功能。傳感器驅動模型總體框架如圖1所示。
圖1 傳感器驅動模型總體框架圖
Sensor驅動抽象模型主要位于OpenHarmony軟件的HAL層,其核心包括三個子模塊:
1)Sensor HDI子模塊:提供Sensor南向的標準接口定義和實現。
2)Sensor設備管理和通用配置子模塊:提供Sensor設備管理,Sensor通用配置能力,Sensor通用數據解析能力。
3)Sensor器件驅動子模塊:提供Sensor器件通用驅動和差異化驅動實現。
傳感器設備驅動模型介紹
Sensor設備作為外接設備重要組成模塊,通過Sensor驅動模型屏蔽硬件器件差異,為上層Sensor服務系統提供穩定的Sensor基礎能力接口,包括Sensor列表查詢、Sensor啟停、Sensor訂閱及取消訂閱,Sensor參數配置等功能;
Sensor設備驅動的開發是基于HDF驅動框架基礎上,結合操作系統適配層(OSAL)和平臺驅動接口(比如I2C/SPI/UART總線等平臺資源)能力,屏蔽不同操作系統和平臺總線資源差異,實現Sensor驅動“一次開發,多系統部署”的目標。傳感器設備驅動模型框圖如圖2。
圖2 傳感器驅動模型框圖
Sensor驅動模型作為HDF框架中一個Device Host(驅動宿主),完成對Sensor設備管理,包括Sensor驅動加載,注冊,卸載,綁定,配置管理,接口發布。
Sensor驅動模型主要包括Sensor HDI子模塊,Sensor設備管理和通用配置子模塊和Sensor器件驅動子模塊。Sensor HDI子模塊抽象出Sensor設備的基本能力Sensor列表查詢、Sensor啟停、Sensor訂閱及取消訂閱,Sensor參數配置接口,接口和類型定義參考sensor_if.h和sensor_type.h。
Sensor設備管理和通用配置子模塊,其中,Sensor設備管理完成Sensor設備的注冊、管理能力,數據報告能力,接口定義參考sensor_device_if.h;通用配置子模塊完成寄存器配置操作接口抽象,Sensor HCS通用配置解析能力,接口定義參考sensor_config_parser.h、sensor_config_controller.h。Sensor器件驅動子模塊完成每類Sensor類型驅動的抽象和器件差異化驅動實現。
傳感器驅動模型工作流程解析
通過介紹Sensor驅動模型的加載以及運行流程,對模型內部關鍵組件以及關聯組件之間的關系進行了劃分,整體加載流程如圖3。
圖3 Sensor驅動模型運行圖
Sensor驅動模型以標準系統Hi3516DV300產品中的加速度計驅動為例,介紹整個驅動加載及運行流程為:
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驅動模型加載的關鍵流程代碼進行說明。
Sensor設備管理驅動實現
HDF驅動框架從device info HCS 的Sensor Host里讀取Sensor設備管理配置信息,加載并初始化Sensor設備管理驅動。
步驟1-步驟4實現關鍵代碼介紹如下,參考完整代碼實現路徑driversframeworkmodelsensordrivercommonsrcsensor_device_manager.c。
定義Sensor設備管理驅動對應的HdfDriverEntry對象,其中Driver Entry入口函數定義如下:
struct HdfDriverEntry g_sensorDevManagerEntry = { .moduleVersion = 1, .moduleName = “HDF_SENSOR_MGR_AP”, // 值與設備信息HCS中的moduleName一樣 .Bind = BindSensorDevManager, .Init = InitSensorDevManager, .Release = ReleaseSensorDevManager,};
Sensor設備管理模塊負責系統中所有Sensor器件接口發布,在系統啟動過程中,HDF框架機制通過Sensor Host里設備HCS配置信息,加載設備管理驅動。
// Sensor host配置包含所有Sensor器件設備信息sensor :: host { hostName = “sensor_host”; // host 名字 device_sensor_manager :: device { // Sensor管理設備信息 device0 :: deviceNode { policy = 1; // 發布策略,1表示對內核態發布,2表示對用戶態和內核態發布 priority = 100; // device的加載優先級,同一host內有效,值越小優先級越高 preload = 0; // 設備驅動是否加載標志,0表示加載,2表示不加載 permission = 0664; // 驅動設備節點權限 moduleName = “HDF_SENSOR_MGR_AP”; // 驅動名稱,該字段的值必須和驅動入口結構的moduleName值一致 serviceName = “hdf_sensor_manager_ap”;// 驅動對外發布服務的名稱,必須唯一 } }}
Sensor設備管理驅動DispatchSensor接口完成Sensor設備對外能力的發布,DispatchSensor接口實現如下:
static int32_t DispatchSensor(struct HdfDeviceIoClient *client, int32_t cmd, struct HdfSBuf *data, struct HdfSBuf *reply){…… DLIST_FOR_EACH_ENTRY(pos, &manager-》sensorDevInfoHead, struct SensorDevInfoNode, node) { if (sensorId == pos-》devInfo.sensorInfo.sensorId) { // Dispatch函數處理Sensor對外發布的接口能力 ret = DispatchCmdHandle(&pos-》devInfo, data, reply); (void)OsalMutexUnlock(&manager-》mutex); return ret; } }…… return HDF_FAILURE;}int32_t BindSensorDevManager(struct HdfDeviceObject *device){ CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM);……// 通過ioService.Dispatch注冊Sensor對外接口能力 manager-》ioService.Dispatch = DispatchSensor; manager-》device = device; device-》service = &manager-》ioService; g_sensorDeviceManager = manager; return HDF_SUCCESS;}
加速度計抽象驅動實現HDF驅動框架從device info HCS 的Sensor Host里讀取加速度計抽象驅動配置信息,加載并初始化加速度計抽象驅動,完成Sensor器件驅動資源分配和數據處理隊列創建。
步驟5-步驟6實現關鍵代碼介紹如下,參考完整代碼實現路徑driversframeworkmodelsensordriveraccelsensor_accel_driver.c。
定義加速度計抽象驅動對應的HdfDriverEntry對象,其中,Driver Entry入口函數定義如下:
struct HdfDriverEntry g_sensorAccelDevEntry = { .moduleVersion = 1, .moduleName = “HDF_SENSOR_ACCEL”, // 值與設備信息HCS中的moduleName一樣 .Bind = AccelBindDriver, .Init = AccelInitDriver, .Release = AccelReleaseDriver,};
加速度計抽象驅動的配置信息在Sensor Host定義如下:
// Sensor Host配置包含所有Sensor器件設備信息sensor :: host { hostName = “sensor_host”; // host 名字 device_sensor_accel :: device { // Sensor管理設備信息 device0 :: deviceNode { policy = 1; // 發布策略,1表示對內核態發布服務,2表示對用戶態和內核態發布 priority = 110; // device的加載優先級,同一host內有效,值越小優先級越高 preload = 0; // 設備驅動是否加載標志,0表示加載,2表示不加載 permission = 0664; // 驅動設備節點權限 moduleName = “HDF_SENSOR_ACCEL”; // 驅動名稱,該字段的值必須和驅動入口結構的moduleName值一致 serviceName = “hdf_sensor_accel”;// 驅動對外發布服務的名稱,必須唯一 } }}
不同型號的加速度器件在初始化時,會進行器件探測,探測器件是否在位,如果在位,會對加速度器件分配資源,用于存放器件HCS配置信息。加速度計抽象驅動提供初始化過程中器件探測,器件屬性配置,寄存器配置資源分配和釋放接口。
1、創建加速度配置數據接口
此接口在差異化器件驅動初始化時調用,解析器件HCS私有配置,讀取sensor的基本信息,總線方式,器件探測寄存器,并校驗器件是否在位。如果器件探測成功,完成加速度器件資源分配,并返回傳感器配置數據結構體地址。
struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node){ struct AccelDrvData *drvData = AccelGetDrvData();…… // 器件是否已經探測成功 if (drvData-》detectFlag) { HDF_LOGE(“%s: Accel sensor have detected”, __func__); return NULL; }…… // 解析器件HCS私有配置,讀取sensor的基本信息,總線方式,器件探測寄存器。 if (GetSensorBaseConfigData(node, drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGE(“%s: Get sensor base config failed”, __func__); goto BASE_CONFIG_EXIT; } // 器件探測并校驗器件是否在位 if (DetectSensorDevice(drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGI(“%s: Accel sensor detect device no exist”, __func__); drvData-》detectFlag = false; goto BASE_CONFIG_EXIT; } // 器件在位,繼續解析剩余HCS寄存器配置。 drvData-》detectFlag = true; if (InitAccelAfterDetected(drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGE(“%s: Accel sensor detect device no exist”, __func__); goto INIT_EXIT; } return drvData-》accelCfg;……}
2、釋放加速度配置數據接口
此接口在差異化器件驅動初始化失敗,或者加速度抽象驅動卸載時調用,釋放已分配的資源。
void AccelReleaseCfgData(struct SensorCfgData *accelCfg){ CHECK_NULL_PTR_RETURN(accelCfg); (void)DeleteSensorDevice(&accelCfg-》sensorInfo); ReleaseSensorAllRegConfig(accelCfg); (void)ReleaseSensorBusHandle(&accelCfg-》busCfg); accelCfg-》root = NULL; (void)memset_s(&accelCfg-》sensorInfo, sizeof(struct SensorBasicInfo), 0, sizeof(struct SensorBasicInfo)); (void)memset_s(&accelCfg-》busCfg, sizeof(struct SensorBusCfg), 0, sizeof(struct SensorBusCfg)); (void)memset_s(&accelCfg-》sensorAttr, sizeof(struct SensorAttr), 0, sizeof(struct SensorAttr));}
3、注冊加速度差異化接口
此接口在差異化器件驅動初始化成功時,注冊差異實現接口,方便實現器件差異的驅動接口,此接口支持擴展。
int32_t AccelRegisterChipOps(const struct AccelOpsCall *ops){ struct AccelDrvData *drvData = AccelGetDrvData();…… drvData-》ops.Init = NULL; drvData-》ops.ReadData = ops-》ReadData; return HDF_SUCCESS;}
加速度計差異化驅動實現
加速度計差異化驅動主要實現因為器件差異無法通過加速度計HCS差異化配置文件實現的能力接口。HDF驅動框架從device info HCS 的Sensor Host里讀取加速度計差異化驅動配置信息,加載并初始化加速度計抽象驅動,完成器件探測,并分配加速度傳感器配置資源,完成加速度計差異化接口注冊。另外,初始化過程中會從accel_xxx_config HCS里讀取私有化配置信息。
步驟7-步驟9實現關鍵代碼介紹如下,參考完整代碼實現路徑driversframeworkmodelsensordriveraccelsensor_accel_driver.c。
定義加速度計差異化驅動對應的HdfDriverEntry對象,其中,Driver Entry入口函數定義如下:
struct HdfDriverEntry g_accelBmi160DevEntry = { .moduleVersion = 1, .moduleName = “HDF_SENSOR_ACCEL_BMI160”, // 值與設備信息HCS中的moduleName一樣 .Bind = Bmi160BindDriver, .Init = Bmi160InitDriver, .Release = Bmi160ReleaseDriver,
加速度計差異化驅動的配置信息在Sensor Host定義如下:
// Sensor Host配置包含所有Sensor器件設備信息sensor :: host { hostName = “sensor_host”; // host 名字 device_sensor_accel :: device { // Sensor管理設備信息 device0 :: deviceNode { policy = 1; // 發布策略,1表示對內核態發布 priority = 120; // device的加載優先級,同一host內有效,值越小優先級越高 preload = 0; // 設備驅動是否加載標志,0表示加載,2表示不加載 permission = 0664; // 驅動設備節點權限 moduleName = “HDF_SENSOR_ACCEL_BMI160”; // 驅動名稱,該字段的值必須和驅動入口結構的moduleName值一致 serviceName = “hdf_accel_bmi160”;// 驅動對外發布服務的名稱,必須唯一 deviceMatchAttr = “hdf_sensor_accel_bmi160_driver”; } }}
加速度計私有化配置信息主要包括總線信息,sensor信息,sensor寄存器等資源信息。加速度計私有化配置信息在如下路徑vendorhisiliconHi3516DV300hdf_configkhdfsensoraccelaccel_bmi160_config.hcs。
為了方面開發者使用傳感器HCS私有配置,在sensor_common.hcs里面定義通用的傳感器配置模板,其他器件直接引用模板修改對應的屬性值,如果需要新增功能,可以在私有的配置文件里擴展新的節點即可。
// accel sensor common config templateroot { sensorConfig { template sensorInfo { //在注冊設備時需要解析傳感器配置信息 sensorName = “accelerometer”; // 器件名字 vendorName = “vendor_xxx”; // 器件廠商名字 firmwareVersion = “1.0”;// 固件版本 hardwareVersion = “1.0”;// 硬件版本 sensorTypeId = 1; // 傳感器設備注冊時定義的類型,必須是系統定義類型enum SensorTypeTag sensorId = 1; // 用戶自定義傳感器ID,兼容不同廠商定義,ID值要求全局唯一,無特殊要求默認和sensorTypeId保持一致,設備訪問時采用SensorId作為系統中器件唯一標識 maxRange = 0; // 最大量程,根據器件需要定義 accuracy = 0; // 精度值,根據器件需要定義 power = 0; // 功耗(uA),根據器件需要定義 } template sensorBusConfig { // 器件支持的總線信息 busType = 0; // 0:i2c 1:spi busNum = 6; // 總線號 busAddr = 0; // 總線地址 regWidth = 1;// 數據寬度 regBigEndian = 0;// 字節序 } template sensorAttr { chipName = “”;// 器件名字 chipIdRegister = 0xf;// 器件探測地址 chipIdValue = 0xd1;// 器件探測校驗值 } }}
每個Sensor器件都要根據業務需求增加或者修改對應的Sensor 寄存器分組以滿足器件業務需求,當前基本業務分組如下:
enum SensorRegOpsType { SENSOR_INIT_GROUP = 0, // 初始寄存器組 SENSOR_ENABLE_GROUP, // 使能寄存器組 SENSOR_DISABLE_GROUP, // 去使能寄存器組 SENSOR_GROUP_MAX, };
通用配置子模塊提供寄存器配置操作和HCS通用配置解析接口。驅動開發者基于通用Sensor HCS配置模板實現的HCS,無需實現解析接口,直接調用如下抽象接口解析即可。
1、傳感器設備HCS抽象接口
Sensor器件驅動模型提供設備資源通用接口,解析配置文件中的通用節點信息。配置接口會在驅動加載過程中初始化的兩個階段調用,第一個階段調用GetSensorBaseConfigData接口,解析設備資源HCS中的節點(sensorInfo,sensorBusConfig,sensorAttr)信息。
第二個階段在Sensor器件探測成功之后,調用ParseSensorRegConfig接口,解析Sensor寄存器配置信息。最后器件驅動卸載時調用ReleaseSensorAllRegConfig接口釋放所有配置資源。接口定義在sensor_config_parser.h文件。
傳感器基本配置數據解析接口函數定義int32_t GetSensorBaseConfigData(const struct DeviceResourceNode *node, struct SensorCfgData *config);傳感器寄存器配置數據解析接口函數定義int32_t ParseSensorRegConfig(struct SensorCfgData *config);釋放傳感器所有配置數據接口函數定義void ReleaseSensorAllRegConfig(struct SensorCfgData *config);傳感器器件探測在位接口int32_t DetectSensorDevice(struct SensorCfgData *config);
2、傳感器讀寫寄存器接口
器件驅動開發時,需要用到不同總線接口,配置器件。由于不同操作系統或者平臺,總線接口總是有差異,導致開發過程中,需要不斷地進行適配修改。傳感器驅動模型依賴HDF框架提供的平臺接口能力,封裝了傳感器器讀寫設備的接口,支持的總線有I2C,SPI接口。
讀傳感器寄存器接口函數定義int32_t ReadSensor(struct SensorBusCfg *busCfg, uint16_t regAddr, uint8_t *data, uint16_t dataLen);讀傳感器寄存器接口函數定義int32_t WriteSensor(struct SensorBusCfg *busCfg, uint8_t *writeData, uint16_t len);
Sensor設備管理能力接口
加速度器件探測成功之后,加速度差異化驅動通知加速度抽象驅動,注冊加速度設備到Sensor設備管理中,對應步驟10。Sensor設備管理模塊還提供如下接口能力:
1、注冊設備
設備注冊接口AddSensorDevice把加速度計設備信息注冊到Sensor設備管理模塊。調用注冊設備函數時,系統要求sensorTpyeId和sensorId全局唯一,并實現Sensor信息和Sensor接口,才能確保Sensor設備注冊成功。
struct SensorOps { int32_t (*Enable)(void); // 使能傳感器 int32_t (*Disable)(void);// 使能傳感器 int32_t (*SetBatch)(int64_t samplingInterval, int64_t reportInterval);// 配置傳感器采樣率和上報時延 int32_t (*SetMode)(int32_t mode);// 配置傳感器模式 int32_t (*SetOption)(uint32_t option);// 配置傳感器可選項參數};struct SensorDeviceInfo { struct SensorBasicInfo sensorInfo; // 傳感器信息,包括傳感器名字,廠商名,傳感類型ID,傳感ID等信息
注冊設備接口函數定義如下:
int32_t AddSensorDevice(const struct SensorDeviceInfo *deviceInfo);
2、刪除設備
設備注冊失敗或者驅動需要卸載時,需要刪除注冊到Sensor設備管理里的設備信息。調用DeleteSensorDevice接口完成設備信息的刪除。
int32_t DeleteSensorDevice(const struct SensorBasicInfo *sensorBaseInfo);
3、設備數據報告
Sensor設備管理模塊提供了抽象的數據上報接口,器件驅動產生數據事件后,調用ReportSensorEvent接口,把數據事件上報給Sensor服務端
上報數據事件格式定義如下:
// 傳感器數據上報事件struct SensorReportEvent { int32_t sensorId; // 用戶自定義傳感器ID,兼容不同廠商定義,ID值要求全局唯一,無特殊要求默認和sensorTypeId保持一致,設備訪問時采用SensorId作為系統中器件唯一標識 int32_t version; // 傳感器版本號,有HAL層定義 int64_t timestamp; // 采樣數據產生時的時間戳 uint32_t option; // 傳感器可選配置,如量程,精度 int32_t mode; // 傳感器數據上報模式 uint8_t *data; // 采樣數據,根據器件特性定義傳感器數據格式和單位,此數據可以是一組采樣數據或者多組采樣數據 uint32_t dataLen; // 采樣數據存儲長度
數據事件上報接口函數定義如下:
int32_t ReportSensorEvent(const struct SensorReportEvent *events);
對于Sensor驅動模型來說,已經實現了Sensor HDI接口定義,設備管理驅動和通用配置解析接口,及一些平臺無關的讀寫寄存的接口能力,驅動開發者新增一款傳感器器件,只需要實現文件里struct SensorOps結構體定義接口,并調用AddSensorDevice接口添加。
傳感器驅動開發指導
本示例介紹新開發一款加速度BMI160器件傳感器驅動的實現步驟為例。設備的通訊方式采用I2C總線方式。
加速計傳感器驅動開發主要包括兩個部分:加速度抽象驅動和加速度差異化驅動。
1)基于HDF驅動框架,按照驅動Driver Entry程序,完成加速度抽象驅動開發,主要有Bind,Init,Release,Dispatch函數接口實現。
2)完成加速度傳感器驅動的設備信息配置。
3)完成加速度抽象驅動內部接口開發,包括定時器,工作隊列,Enable,Disable,SetBatch,SetMode,SetOption,AccelCreateCfgData,AccelReleaseCfgData,AccelRegisterChipOps接口實現。
4)基于HDF驅動框架,按照驅動Driver Entry程序,完成加速度差異化驅動開發,主要有Bind,Init,Release,Dispatch函數接口實現。
5)完成加速度傳感器差異化驅動中差異化接口ReadData函數實現。
6)新增文件腳本適配。
加速度抽象驅動實現示例
定義加速度抽象驅動對應的HdfDriverEntry對象,其中Driver Entry入口函數定義如下:
struct HdfDriverEntry g_sensorAccelDevEntry = { .moduleVersion = 1, .moduleName = “HDF_SENSOR_ACCEL”, .Bind = BindAccelDriver, .Init = InitAccelDriver, .Release = ReleaseAccelDriver,};HDF_INIT(g_sensorAccelDevEntry);
Bind接口實現驅動接口實例化,實現示例:
int32_t AccelBindDriver(struct HdfDeviceObject *device){ CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); // 私有數據分配資源 struct AccelDrvData *drvData = (struct AccelDrvData *)OsalMemCalloc(sizeof(*drvData)); …… // 需要發布接口函數 drvData-》ioService.Dispatch = DispatchAccel; drvData-》device = device; device-》service = &drvData-》ioService; g_accelDrvData = drvData; return HDF_SUCCESS;}
Init接口實現驅動接口實例化,實現示例:
int32_t AccelInitDriver(struct HdfDeviceObject *device){ …… // 工作隊列資源初始化 if (InitAccelData(drvData) != HDF_SUCCESS) { HDF_LOGE(“%s: Init accel config failed”, __func__); return HDF_FAILURE; } // 分配加速度配置信息資源 drvData-》accelCfg = (struct SensorCfgData *)OsalMemCalloc(sizeof(*drvData-》accelCfg)); if (drvData-》accelCfg == NULL) { HDF_LOGE(“%s: Malloc accel config data failed”, __func__); return HDF_FAILURE; } // 掛接寄存器分組信息 drvData-》accelCfg-》regCfgGroup = &g_regCfgGroup[0]; …… return HDF_SUCCESS;}
Release接口在驅動卸載或者Init執行失敗時,會調用此接口釋放資源:
void AccelReleaseDriver(struct HdfDeviceObject *device){ CHECK_NULL_PTR_RETURN(device); struct AccelDrvData *drvData = (struct AccelDrvData *)device-》service; CHECK_NULL_PTR_RETURN(drvData); // 器件在位,釋放已分配資源 if (drvData-》detectFlag) { AccelReleaseCfgData(drvData-》accelCfg); } OsalMemFree(drvData-》accelCfg); drvData-》accelCfg = NULL; // 器件在位,銷毀工作隊列資源 HdfWorkDestroy(&drvData-》accelWork); HdfWorkQueueDestroy(&drvData-》accelWorkQueue); OsalMemFree(drvData);}
加速度抽象驅動配置示例
加速度計設備配置信息在device_info.hcs文件Sensor_host里面,配置HCS文件在源碼倉位置為
// accel器件設備信息device_sensor_accel :: device { device0 :: deviceNode { policy = 1; // 加速計直接注冊到sensor管理模塊,無需對用戶態發布 priority = 110; // 優先級105低于Sensor管理模塊優先級100 preload = 0; permission = 0664; moduleName = “HDF_SENSOR_ACCEL”;// 加速計驅動名稱 serviceName = “sensor_accel”;// 加速計驅動對外發布的服務名稱 deviceMatchAttr = “hdf_sensor_accel_driver”; // 驅動私有數據匹配的關鍵字,必須和驅動私有數據配置表中的match_attr值相等 }}
vendorhisiliconHi3516DV300hdf_configkhdfdevice_infodevice_info.hcs:
加速度抽象驅動內部接口開發實現示例
提供給差異化驅動的初始化接口,完成加速度器件基本配置信息解析(加速度信息,加速度總線配置,加速度器件探測寄存器配置),器件探測,器件寄存器解析。
static int32_t InitAccelAfterDetected(struct SensorCfgData *config){ struct SensorDeviceInfo deviceInfo; CHECK_NULL_PTR_RETURN_VALUE(config, HDF_ERR_INVALID_PARAM); // 初始化加速度計接口函數 if (InitAccelOps(config, &deviceInfo) != HDF_SUCCESS) { HDF_LOGE(“%s: Init accel ops failed”, __func__); return HDF_FAILURE; } // 注冊加速度計設備到傳感器管理模塊 if (AddSensorDevice(&deviceInfo) != HDF_SUCCESS) { HDF_LOGE(“%s: Add accel 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;}struct SensorCfgData *AccelCreateCfgData(const struct DeviceResourceNode *node){ …… // 如果探測不到器件在位,返回進行下個器件探測 if (drvData-》detectFlag) { HDF_LOGE(“%s: Accel sensor have detected”, __func__); return NULL; } if (drvData-》accelCfg == NULL) { HDF_LOGE(“%s: Accel accelCfg pointer NULL”, __func__); return NULL; } // 設備基本配置信息解析 if (GetSensorBaseConfigData(node, drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGE(“%s: Get sensor base config failed”, __func__); goto BASE_CONFIG_EXIT; } // 如果探測不到器件在位,返回進行下個器件探測 if (DetectSensorDevice(drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGI(“%s: Accel sensor detect device no exist”, __func__); drvData-》detectFlag = false; goto BASE_CONFIG_EXIT; } drvData-》detectFlag = true; // 器件寄存器解析 if (InitAccelAfterDetected(drvData-》accelCfg) != HDF_SUCCESS) { HDF_LOGE(“%s: Accel sensor detect device no exist”, __func__); goto INIT_EXIT; } return drvData-》accelCfg; ……}
加速度計差異化驅動實現示例
定義加速度差異化驅動對應的HdfDriverEntry對象,其中Driver Entry入口函數定義如下:
struct HdfDriverEntry g_accelBmi160DevEntry = { .moduleVersion = 1, .moduleName = “HDF_SENSOR_ACCEL_BMI160”, .Bind = Bmi160BindDriver, .Init = Bmi160InitDriver, .Release = Bmi160ReleaseDriver,};HDF_INIT(g_accelBmi160DevEntry);
Bind驅動接口實例化,實現示例:
int32_t Bmi160BindDriver(struct HdfDeviceObject *device){ CHECK_NULL_PTR_RETURN_VALUE(device, HDF_ERR_INVALID_PARAM); struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)OsalMemCalloc(sizeof(*drvData)); if (drvData == NULL) { HDF_LOGE(“%s: Malloc Bmi160 drv data fail”, __func__); return HDF_ERR_MALLOC_FAIL; } drvData-》ioService.Dispatch = DispatchBMI160; drvData-》device = device; device-》service = &drvData-》ioService; g_bmi160DrvData = drvData; return HDF_SUCCESS;}
Init驅動接口實例化,實現示例:
int32_t Bmi160InitDriver(struct HdfDeviceObject *device){ …… // 加速度計差異化初始化配置 ret = InitAccelPreConfig(); if (ret != HDF_SUCCESS) { HDF_LOGE(“%s: Init BMI160 bus mux config”, __func__); return HDF_FAILURE; } // 創建傳感器配置數據接口,完成器件探測,私有數據配置解析 drvData-》sensorCfg = AccelCreateCfgData(device-》property); if (drvData-》sensorCfg == NULL) { return HDF_ERR_NOT_SUPPORT; } // 注冊差異化接口 ops.Init = NULL; ops.ReadData = ReadBmi160Data; ret = AccelRegisterChipOps(&ops); if (ret != HDF_SUCCESS) { HDF_LOGE(“%s: Register BMI160 accel failed”, __func__); return HDF_FAILURE; } // 初始化器件配置 ret = InitBmi160(drvData-》sensorCfg); if (ret != HDF_SUCCESS) { HDF_LOGE(“%s: Init BMI160 accel failed”, __func__); return HDF_FAILURE; } return HDF_SUCCESS;}
Release驅動接口實例化,實現示例:
void Bmi160ReleaseDriver(struct HdfDeviceObject *device){ CHECK_NULL_PTR_RETURN(device); struct Bmi160DrvData *drvData = (struct Bmi160DrvData *)device-》service; CHECK_NULL_PTR_RETURN(drvData); AccelReleaseCfgData(drvData-》sensorCfg); drvData-》sensorCfg = NULL; OsalMemFree(drvData);}
加速度計差異化驅動私有HCS配置實現示例
加速度計器件私有HCS配置在如下路徑vendorhisiliconHi3516DV300hdf_configkhdfsensoraccelaccel_bmi160_config.hcs。為了方面開發者使用傳感器HCS配置,在accel_config.hcs里面配置通用的傳感器模板,加速度計器件直接引用模板并修改對應的屬性值,在此基礎上新增寄存器配置,生成accel_bmi160_config.hcs配置文件。
#include “accel_config.hcs”root { accel_bmi160_chip_config : sensorConfig { match_attr = “hdf_sensor_accel_bmi160_driver”; sensorInfo :: sensorDeviceInfo { vendorName = “borsh_bmi160”; // max string length is 16 bytes sensorTypeId = 1; // enum SensorTypeTag sensorId = 1; // user define sensor id } sensorBusConfig:: sensorBusInfo { busType = 0; // 0:i2c 1:spi busNum = 6; busAddr = 0x68; regWidth = 1; // 1btye } sensorIdAttr :: sensorIdInfo{ chipName = “bmi160”; chipIdRegister = 0x00; chipIdValue = 0xd1; } 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 = [ 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 ]; } }}
加速度計差異化函數接口實現示例
需要開發者實現的ReadBmi160Data接口函數,在Bmi160InitDriver函數里面注冊此函數。
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) { HDF_LOGE(“%s: BMI160 read raw data failed”, __func__); return HDF_FAILURE; } event.sensorId = SENSOR_TAG_ACCELEROMETER; event.option = 0; event.mode = SENSOR_WORK_MODE_REALTIME; …… ret = ReportSensorEvent(&event); if (ret != HDF_SUCCESS) { HDF_LOGE(“%s: BMI160 report data failed”, __func__); } return ret;}
適配編譯入口示例
傳感器驅動實現在內核態,代碼參與編譯是通過適配makefile實現,并通過內核模塊宏定義,控制加速度設備驅動是否參與編譯。
標準系統Linux內核加速度模塊配置宏定義CONFIG_DRIVERS_HDF_SENSOR_ACCEL、CONFIG_DRIVERS_HDF_SENSOR_ACCEL_BMI160在kernel/linux/config/linux-4.19/arch/arm/configs/hi3516dv300_standard_defconfig文件,若開啟模塊則CONFIG_DRIVERS_HDF_SENSOR_ACCEL=y,
SENSOR_ROOT_DIR = 。。/。。/。。/。。/。。/framework/model/sensor/driverobj-$(CONFIG_DRIVERS_HDF_SENSOR) += $(SENSOR_ROOT_DIR)/common/src/sensor_config_controller.o $(SENSOR_ROOT_DIR)/common/src/sensor_config_parser.o $(SENSOR_ROOT_DIR)/common/src/sensor_device_manager.o $(SENSOR_ROOT_DIR)/common/src/sensor_platform_if.o obj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL) += $(SENSOR_ROOT_DIR)/accel/sensor_accel_driver.oobj-$(CONFIG_DRIVERS_HDF_SENSOR_ACCEL_BMI160) += $(SENSOR_ROOT_DIR)/chipset/accel/accel_bmi160.occflags-y += -Idrivers/hdf/framework/model/sensor/driver/include -Idrivers/hdf/framework/model/sensor/driver/common/include -Idrivers/hdf/framework/model/sensor/driver/chipset/accel -Idrivers/hdf/framework/model/sensor/driver/accel -Idrivers/hdf/framework/include/core -Idrivers/hdf/framework/core/common/include/host -Idrivers/hdf/framework/include/utils -Idrivers/hdf/framework/include/osal -Idrivers/hdf/framework/ability/sbuf/include -Idrivers/hdf/framework/include/platform -Idrivers/hdf/framework/include/config -Idrivers/hdf/khdf/osal/include -I$(PROJECT_ROOT)/third_party/bounds_checking_function/include
CONFIG_DRIVERS_HDF_SENSOR_ACCEL_BMI160=y,若關閉模塊則刪除宏即可。
Makefile腳本入口在drivers/adapter/khdf路徑下,根據不同操作系統選擇不同目錄,以標準系統為例說明腳本適配步驟,腳本路徑如下/drivers/adapter/khdf/linux/model/sensor/Makefile。
總結
本文主要和大家分享傳感器驅動模型,重點分析傳感驅動模型框架原理和傳感器抽象驅動適配開發過程。以開源板Hi3516DV300標準系統版本加速度計為例進行了詳細的代碼說明,希望通過本文檔您能初步掌握基于HDF框架的傳感器設備的開發步驟與流程。關于傳感器驅動框架的更多分析,請關注后續文章。
代碼參考原文鏈接:傳送門
編輯:jq
-
傳感器
+關注
關注
2552文章
51353瀏覽量
755611 -
接口
+關注
關注
33文章
8684瀏覽量
151629 -
定時器
+關注
關注
23文章
3254瀏覽量
115143 -
函數
+關注
關注
3文章
4344瀏覽量
62857 -
OpenHarmony
+關注
關注
25文章
3744瀏覽量
16470
原文標題:OpenHarmony HDF傳感器設備驅動模型分析與使用
文章出處:【微信號:gh_e4f28cfa3159,微信公眾號:OpenAtom OpenHarmony】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論