高通sensor架构实例分析之一

本文深入剖析了高通Sensor架构,介绍了从传统架构到引入独立音频DSP (aDSP) 的转变,以降低功耗并提高效率。文章详细阐述了aDSP上的软件组件,并通过Sensor1 API接口展示了应用处理器与aDSP之间的通信机制。

本系列导航:

linux驱动由浅入深系列:高通sensor架构实例分析之一(整体概览+AP侧代码分析)

linux驱动由浅入深系列:高通sensor架构实例分析之二(adsp驱动代码结构)
Linux驱动由浅入深系列:高通sensor架构例分析之三(adsp上报数据详解、校准流程详解)


最初的时候芯片厂家对sensor的处理和对待其它外设一样都是直接挂在processor上,sensor的驱动也和其他linux或android的驱动一样,生成对应的设备节点给上层提供数据(关于此类linux基础驱动的知识,可以参考本博客其他博文)。但后来这一切发生了变化,最主要的原因就是功耗。Sensor希望自己能够一直处于工作状态下,如计步器等应用场景。这样如果sensor还挂在主processor上(这时候处理器就分多核啦)势必影响待机功耗。因此各个芯片厂推出了各自的方案,如sensor-hub等等。高通在MSM8960之后就将sensor的处理塞到了一个单独的音频dsp中了(MSM8953中这个dsp叫作aDSP),这样待机时主处理器休眠降低功耗,由这个aDSP在处理音频数据的间隙捎带着就能把sensor的数据处理了^^。下面以MSM8953为例分析一下其结构。

 

高通sensor软件架构

首先来看一下高通sensor处理的软件框图:


1,  框图上半部分是应用处理器,下半部分是aDSP。

2,  aDSP中包含了log接口,电源管理,sensor算法库,sensor校准,各个sensor的管理模块。最后一个是直接挂载各个传感器的(Prox、Press、Mag、Gyro、Acc),软件中的主要部分叫作SMGR。[上图文字怎么乱了,补充一张^-^]


3,  在应用处理器中,软件接口中不再有每个sensor的设备节点了。那有的是什么呢,只有Sensor1 API Socket Remoting Layer层对应的API接口。这个接口是本文的重点,下文详细解释。

4,  那么aDSP与应用处理器之间用什么机制进行通信呢?图中可以看到一个叫QMI的东西,就是它了,这个高通基于共享内存机制开发的多核间通信技术,在应用处理器侧和aDSP侧都有相应的库已经完成了底层实现。之后有机会分析一下这种号称最为有效的多核间通信技术。

5,  应用处理器侧还有些乱七八糟的蓝色框,这部分是运行在应用处理器侧的sensor算法、校准相关的东西。这是些只会在非待机模式运行的算法,就适合放在这个地方了。

 

android中sensor架构

在android中sensor的架构图如下:


在Sensor1 API Socket Remoting Layer层的基础上转换成了android的Framwork层就可以被APP调用了,目前我们先以linux 应用程序的直接调用Sensor1 API Socket Remoting Layer层接口为例进行演示。


高通sensor测试工具

高通为sensor的测试提供了默认的工具,代码位于:

vendor\qcom\proprietary\sensors\dsps\test\src\sns_dsps_tc0001.c

vendor\qcom\proprietary\sensors\dsps\test\src\sns_cm_test.cpp

编译后生成对应的bin文件:

1,sns_dsps_tc0001用来查看当前系统挂载的sensor的相关信息:



2,sns_cm_test用来获取对应sensor_id的传感器数据:



Sensor的API接口:

1,

sensor1_error_e sensor1_open(sensor1_handle_s**hndl, sensor1_notify_data_cb_t data_cbf,  intptr_t cb_data );

hndl

Opaque handle used to identify this client

data_cbf

Pointer to the client’s callback function to process received data

cb_data

This data is set by the client and will be passed unmodified as a
parameter to the callback function

2,

typedef void (*sensor1_notify_data_cb_t) (uint32 cb_data, sensor1_msg_header_s* msg_hdr,  sensor1_msg_type_e msg_type, void *msg_ptr);

cb_data

Unmodified value passed in when the callback was registered in
sensor1_open()

msg_hdr

Message header defining the message

msg_type

Type of message

msg_ptr

Pointer to the QMI-based message; these messages are defined in their
respective service header files; client shall free this pointer via
sensor1_free_msg_buf()

3,

sensor1_error_e sensor1_close(sensor1_handle_s* hndl );

hndl

Opaque handle used to identify this client


4,

sensor1_error_e sensor1_write(sensor1_handle_s* hndl, sensor1_msg_header_s* msg_hdr, void *msg_ptr);

hndl

Opaque handle to identify this client

msg_hdr

Message header defining the message

msg_ptr

Pointer to the QMI-based request message; these messages are defined
in their respective service header files; memory pointed to shall be
allocated by sensor1_alloc_msg_buf()


5,

sensor1_error_e sensor1_writeable(sensor1_handle_s* hndl, sensor1_write_cb_t cbf, intptr_t cb_data, uint32_t service_number );

hndl

Opaque handle to identify this client

cbf

Pointer to the client’s callback function

cb_data

This data is set by the client and will be passed unmodified as a
parameter to the callback function

service_number

Client callback function will be called when it is possible that this
Service ID can accept new requests via sensor1_write


6,

typedef void (*sensor1_write_cb_t) (intptr_t cb_data, uint32_t service_number);

cb_data

Unmodified value passed in when the callback was registered in
sensor1_writable()

service_number

Service ID to which this callback refers


7,

sensor1_error_e sensor1_alloc_msg_buf(sensor1_handle_s* hndl,  uint16_t size,  void **buffer );

hndl

Opaque handle to identify this client

size

Size of the message structure

buffer

Address of a pointer to the memory address where the message should be
placed


8,

sensor1_error_e sensor1_free_msg_buf(sensor1_handle_s* hndl,  void* msg_buf );

hndl

Opaque handle to identify this client

msg_buf

Buffer to free



sns_cm_test.cpp代码实例

有了上面的api接口介绍,来看一下sns_cm_test.cpp中对其使用就比较清晰了:

  1. 好吧,为了避免麻烦,删除了高通私有代码演示,有代码的去上面指出的文件分析即可。相信没有代码的也不会看这篇文章^^ 本文仅做学习交流目的,如有侵权请联系博主。 
<think> 嗯,用户这次聚焦在高通传感器的唯一标识符(SUID)上,看来是对传感器管理机制有深入研究需求。从引用[1][2]来看,用户已经注意到SUID在传感器抽象层的关键作用——它不仅是硬件标识,更是高通传感器框架中数据流和控制流的枢纽。 用户可能正在开发多传感器应用,需要精确区分不同物理传感器实例。有趣的是引用[1]提到“各传感器的唯一标识符(SUID)例如BMA150为SUID X”,这暗示SUID的分配具有确定性:相同型号传感器在不同设备上可能有固定SUID前缀,但后缀应该包含设备实例信息。这个细节在开发通用传感器驱动时很重要。 注意到用户引用的材料来自传感器框架文档(sns_acel.proto)和初始化流程(/system/etc/init),说明用户可能在调试HAL层或系统服务。需要强调SUID的生命周期管理:根据引用[2],SUID是在sensor driver加载时动态注册的,但高通平台通常会在/vendor/etc/init的启动脚本中预定义核心传感器映射关系。 用户没有问但可能困惑的点是虚拟传感器的SUID机制。其实像“QTI Gravity”这种复合传感器(引用[1]),其SUID虽然指向虚拟实体,但底层仍关联物理IMU的SUID。在回答里补充这个逻辑能预防后续疑问。 安全方面要提醒SUID的访问权限。从引用[3]的目录结构看,ODM厂商可能在/odm/etc/init里重写SUID绑定,这解释为什么同型号手机传感器行为可能不同——这个坑开发者常踩。 </think>高通传感器框架中的**唯一标识符(SUID)** 是传感器管理与通信的核心机制,其设计遵循统一的标准化架构。以下是关键要点分析: --- ### **SUID 的核心作用与设计原理** 1. **全局唯一标识** - **硬件绑定**:每个物理传感器(如加速度计 BMA150、LIS3DH)在初始化时由系统分配唯一的 SUID(例如 `SUID_X`, `SUID_Y`)[^1]。 - **虚拟传感器标识**:算法生成的虚拟传感器(如 QTI Gravity)同样拥有独立 SUID(例如 `SUID_Z`)[^1]。 - **标识符结构**:SUID 通常包含传感器类型、厂商ID、实例编号等字段,确保全局唯一性。 2. **传感器通信与发现机制** - **动态注册流程**: ```mermaid graph TB A[传感器驱动加载] --> B[向Sensor Core注册] B --> C{分配SUID} C --> D[发布属性至框架] D --> E[客户端通过SUID请求数据] ``` - **请求-响应模型**: 客户端(如应用或服务)通过发送 **SUID Request** 定位目标传感器,框架通过回调返回匹配的 SUID Event[^2]。 - **属性发布**:每个传感器通过 SUID 公布其特性(采样率、功耗、精度等),供客户端动态适配[^1]。 3. **分层管理架构** | **层级** | **SUID 管理主体** | **案例路径** | |-------------------|------------------------|----------------------------------| | 系统核心层 | Android 原生服务 | `/system/etc/init` [^3] | | SOC 厂商层 | 高通芯片专用服务 | `/vendor/etc/init` [^3] | | OEM/ODM 定制层 | 设备厂商扩展服务 | `/odm/etc/init` [^3] | --- ### **SUID 的技术实现细节** 1. **数据接口标准化** - **统一协议**:所有同类传感器(如加速度计)遵循相同的接口规范(例如 `sns_accel.proto` 定义的数据格式)[^1]。 - **跨硬件兼容**:不同厂商的传感器(BOSCH BMI260、ST LSM6DSO)通过相同 SUID 接口提供服务。 2. **动态加载机制** - 传感器驱动按需加载,SUID 在运行时动态生成,支持热插拔场景[^1]。 - 示例代码(伪代码): ```c // 客户端请求传感器示例 void request_suid(int sensor_type) { sns_suid_req req = build_request(sensor_type); // 构建SUID请求 sensor_core->send_request(req, suid_event_callback); // 发送请求并注册回调 } void suid_event_callback(sns_suid_event *event) { suid = event->suid; // 从事件中解析SUID start_streaming(suid); // 通过SUID启动数据流 } ``` 3. **故障隔离与冗余** - 多实例传感器(如3个IMU)通过不同 SUID 独立寻址,单个传感器故障不影响整体系统[^1]。 - 客户端可通过 SUID 动态切换备用传感器。 --- ### **典型应用场景** 1. **多传感器协同** AR/VR 设备中,头部与手柄的 IMU 分别通过独立 SUID 传输数据,实现分离式姿态追踪。 2. **功耗优化** 系统根据 SUID 识别低功耗传感器(如采样率 50Hz 的 IMU),在待机时仅激活必要传感器[^1]。 3. **工业冗余设计** AGV 小车通过 3 个 IMU 的 SUID 并行获取数据,融合算法提升导航可靠性。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值