版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。


本文链接:https://blog.csdn.net/huilin9960/article/details/80929499

–所有的存在都是为了走向毁灭而设计的。
–我们被囚禁在这…
–生与死的无尽螺旋里。
–这是诅咒?
–还是惩罚?
–面对着将无解谜题交予我们的神明,我们会有反抗的一天吗?

本系列导航:

Android简单的计步器应用实现

Android Native到HAL源码剖析,以sensor为例

Android Sensor HAL层初始化流程(基于Qualcomm平台)

Sensor系列之Sensor HAL层数据获取,基于Qualcomm平台

Sensor系列之SensorDaemon服务端流程解析

Sensor系列之dsps架构分析

Sensor系列之SensorDaemon与DSPS端通信过程

Sensor专栏:Android Sensor架构全解析

Sensor在最初的时候都是直接挂在处理器上处理的,其驱动都是和linux或android标准的驱动一样,都是生成对应的设备节点给上层提供数据。但是,由于sensor可能需要一直处于工作状态,产生了功耗的问题,故而各个芯片厂商才推出了自己的解决方案。而高通则将sensor的处理放到了application digital signal processor(aDSP)中,这样待机时主处理器休眠以降低功耗,由这个aDSP在处理音频数据的间隙捎带着就能把sensor的数据处理了,真是高明。

今天我们就开始窥探一下高通是怎样具体实现的,先看一下高通给出的架构图。

上面两张图完整的展示了高通SSC的架构,其中上半部分为AP,下半部分则是aDSP,下半部分图我们在之前的dsps架构分析中已经列举了各个组成模块以及相应的功能特点。我们之前的文章已经分析到SMR/QMI发送消息的流程,接下来我们就要进入Sensor Manager(SMGR),深入驱动程序了。

MAIN

aDSP模块的启动从main函数开始执行,该函数定义在sns_pd.c中,路径为adsp_proc/Sensors/dsps/src/common/。

int main (void)
{/* Core Init for user PD */coremain_main();printf("Core Init for sensors image done\n");/* Sensors Initialization */sns_init();return 0; /* never reaches, no user exit handling yet */
}

这里的coremain_main方法是定义在modem端的,在modem_proc/中,我们暂不关注,而sns_init则是对sensor的初始化过程,其方法主体就是调用sns_init_once方法执行one-time的初始化过程,它会调用各个模块的初始化方法。

static void sns_init_once( void )
{int      i;INT8U    err;OS_FLAGS flags = 0;const sns_init_fcn init_ptrs[] = SNS_INIT_FUNCTIONS;if ( SNS_SUCCESS != sns_heap_init()) {MSG(MSG_SSID_SNS, DBG_ERROR_PRIO, "Sensors Heap Init failed, using Default heap ID");sns_heap_id = QURT_ELITE_HEAP_DEFAULT;}sns_init_flag_grp = sns_os_sigs_create( SNS_INIT_FLAG_DONE, &err );SNS_ASSERT(NULL != sns_init_flag_grp);for( i = 0; NULL != init_ptrs[i]; i++ ) {//MSG_1(MSG_SSID_QDSP6, DBG_HIGH_PRIO, "Sensors Init : %d", i);if( SNS_SUCCESS != init_ptrs[i]() ) {/* Handle error *///MSG_1(MSG_SSID_QDSP6, DBG_HIGH_PRIO, "Sensors Init FAIL: %d", i);sns_init_done();}while( !(SNS_INIT_FLAG_DONE & flags) ) {/* Continue polling for the flag until module init is done */flags = sns_os_sigs_pend( sns_init_flag_grp,SNS_INIT_FLAG_DONE,OS_FLAG_WAIT_SET_ANY,0,&err );MSG_1(MSG_SSID_QDSP6, DBG_HIGH_PRIO, "Sensors Init : waiting(%x)", flags);}flags = 0;}MSG(MSG_SSID_QDSP6, DBG_HIGH_PRIO, "Sensors Init : ///init once completed///");
}

我们又看到了类似的场景了,通过定义的全局SNS_INIT_FUNCTIONS函数指针,依次进行调用。当所有init方法执行完成,发送init done的信号。

我们这里以MSM8960板子的初始化函数定义列表为例,来分析aDSP的初始化流程,如下:

#ifdef FEATURE_MSM8960
#  define SNS_INIT_FUNCTIONS   \{   sns_memmgr_init,         \  // 内存管理器sns_init_dsps,           \  // 各种dsps服务的初始化sns_em_init,             \  // 事件管理器sns_smr_init,            \  // Message Router用于传递消息(resp/ind)sns_dl_init,             \  // Dynamic Loading servicesns_smgr_init,           \  // Sensor Manager(核心部分)sns_scm_init,            \  // 检验管理器sns_sam_init,            \  // 算法管理器sns_pm_test_task_init,   \  // dog_init,                \NULL }

其中最重要的当属SMGR的初始化了。

SMGR INIT

SMGR的init方法是直接启动了一个sns_smgr_task,所有的任务都放在task中完成的。

SNS_SMGR_UIMAGE_CODE sns_err_code_e sns_smgr_init(void)
{sns_os_task_create_ext(sns_smgr_task, NULL,(OS_STK *)&sns_smgr_task_stack[SNS_MODULE_STK_SIZE_DSPS_SMGR-1],SNS_MODULE_PRI_DSPS_SMGR,SNS_MODULE_PRI_DSPS_SMGR,(OS_STK *)&sns_smgr_task_stack[0],SNS_MODULE_STK_SIZE_DSPS_SMGR,(void *)0,OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR |OS_TASK_OPT_ISLAND,(uint8_t *)"SNS_SMGR");return SNS_SUCCESS;
}

这里我直接给出大致的流程图:

上图中,Communication Library通过I2C以及GPIO,SPI等,直接和sensor device通信了,通过下面的图可以了解这个流程:

I2C挂载图:

上图中,外围期间1,2等便可以是我们的sensor设备或其他可使用I2C通信的电子器件了。

ddf打开的过程如下:

sns_ddf_status_e sns_ddf_open_port(sns_ddf_handle_t*             handle,const sns_ddf_port_config_s*  cfg )
{sns_ddf_status_e status = SNS_DDF_SUCCESS;if ( cfg == NULL || handle == NULL ){return SNS_DDF_EINVALID_PARAM;}*handle = NULL;status  = sns_ddf_comm_malloc( (void **)handle, sizeof(sns_ddf_sensor_info_s) );if ( SNS_DDF_SUCCESS != status ){SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_DSPS_DDF, "Malloc fail, size = %d",sizeof(sns_ddf_sensor_info_s) );return status;}switch( cfg->bus ){// 根据设备配置的config bus,如果是I2C,则调用sns_ddf_comm_bus_i2c_open,如果是SPI,则调用sns_ddf_comm_bus_spi_opencase SNS_DDF_BUS_I2C:status = sns_ddf_comm_bus_i2c_open( *handle, cfg );break;case SNS_DDF_BUS_SPI:status = sns_ddf_comm_bus_spi_open( *handle, cfg );break;default:status = SNS_DDF_EINVALID_PARAM;}if ( SNS_DDF_SUCCESS != status ){SNS_PRINTF_STRING_ERROR_1(SNS_DBG_MOD_DSPS_DDF, "open_port, result = %d", status);sns_ddf_comm_mfree( *handle );*handle = NULL;return SNS_DDF_EBUS;}return status;
}
// initializes and configures SPI communication bus.
static sns_ddf_status_e sns_ddf_comm_bus_spi_open
(sns_ddf_handle_t              handle,const sns_ddf_port_config_s*  cfg
)
{
#if SNS_DDF_COMM_BUS_SPI_ENABLE_DRIVERstatic const spi_device_id_t spi_bus_instances[] ={0,SPI_DEVICE_1,SPI_DEVICE_2,SPI_DEVICE_3,SPI_DEVICE_4,SPI_DEVICE_5,SPI_DEVICE_6,SPI_DEVICE_7,SPI_DEVICE_8,SPI_DEVICE_9,SPI_DEVICE_10,SPI_DEVICE_11,SPI_DEVICE_12,};SPI_RESULT              result; //spi_errors.hsns_ddf_sensor_info_s*  sns_info = (sns_ddf_sensor_info_s*)handle;if ( cfg->bus_instance >= ARR_SIZE(spi_bus_instances) ){return SNS_DDF_EINVALID_PARAM;}/* Initialize member params */sns_info->bus          = SNS_DDF_BUS_SPI;sns_info->spi_s.dev_id = spi_bus_instances[cfg->bus_instance];sns_info->spi_s.cfg    = cfg->bus_config.spi;if ( EnableSPI == false ){return SNS_DDF_SUCCESS;}/* Open SPI port*/result = spi_open(sns_info->spi_s.dev_id);if ( result != SPI_SUCCESS ){SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_DSPS_DDF, "spi_open fail result=%d", result );return SNS_DDF_EBUS;}//TODO: fake write switching sensor to SPI mode? ------------------------/* Close device - this only turns the clocks off */result = spi_close(sns_info->spi_s.dev_id);if ( result != SPI_SUCCESS ){SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_DSPS_DDF, "spi_close fail result=%d", result );return SNS_DDF_EBUS;}
#endifreturn SNS_DDF_SUCCESS;
}
// Initializes and configures I2C communication bus.
static sns_ddf_status_e sns_ddf_comm_bus_i2c_open
(sns_ddf_handle_t              handle,const sns_ddf_port_config_s*  cfg
)
{//TODO: table declared twice! Check sns_smgr_hw.c I2cDrv_I2cBusId sns_i2c_bus_table[]static const I2cDrv_I2cBusId i2c_bus_instances[] ={0,I2CDRV_I2C_1,I2CDRV_I2C_2,I2CDRV_I2C_3,I2CDRV_I2C_4,I2CDRV_I2C_5,I2CDRV_I2C_6,I2CDRV_I2C_7,I2CDRV_I2C_8,I2CDRV_I2C_9,I2CDRV_I2C_10,I2CDRV_I2C_11,I2CDRV_I2C_12};int32                   result;sns_ddf_sensor_info_s*  sns_info = (sns_ddf_sensor_info_s*)handle;if ( cfg->bus_instance >= ARR_SIZE(i2c_bus_instances) ){return SNS_DDF_EINVALID_PARAM;}/* Initialize member params */sns_info->bus = SNS_DDF_BUS_I2C;sns_info->i2c_s.reg_addr_type               = cfg->bus_config.i2c->reg_addr_type;sns_info->i2c_s.i2c_bus.clntCfg.uSlaveAddr  = cfg->bus_config.i2c->slave_addr;sns_info->i2c_s.i2c_bus.clntCfg.uBusFreqKhz = SNS_DDF_DEFAULT_I2C_BUS_FREQ;sns_info->i2c_s.i2c_bus.clntCfg.uByteTransferTimeoutUs = SNS_DDF_DEFAULT_BYTE_XFER_TMO;if ( EnableI2C == false ){return SNS_DDF_SUCCESS;}if (i2c_bus_instances[cfg->bus_instance] == I2CDRV_I2C_5)sns_info->i2c_s.i2c_bus.clntCfg.uBusFreqKhz = 100;/* Obtain the handle for the port. */result = I2cDrv_Open(i2c_bus_instances[cfg->bus_instance], &sns_info->i2c_s.i2c_bus, 0);if ( I2C_RES_SUCCESS != result ){SNS_PRINTF_STRING_ERROR_1( SNS_DBG_MOD_DSPS_DDF, "I2cDrv_Open, result = %d", result );return SNS_DDF_EBUS;}return SNS_DDF_SUCCESS;
}

由此可见,挂载SPI上的设备终会调用spi_open打开设备,而I2C上的则用I2cDrv_Open来进行处理。

以上便是整个aDSP的流程了,结合代码,相信你会很快掌握这个过程,RTFSC,Go!

App processor 与aDSP端数据流图

AP侧从libsensor1开始的数据流走向如下图所示,其中上层到libsensor1的调用逻辑已经在之前的文章中理清了。无非是通过SensorContext的poll从Queue中读取数据,请自行查找回顾,这里只贴出HAL层的框架图及相关的API供参考。

1.HAL层数据处理

2 aDSP层数据处理

Sensor数据获取方式

Sensor上报数据的三种方式:

1(Polling)0x00

调用一次get_data后启动timer,等到timer到时间后调用sns_ddf_driver_if_s中指定的handle_timer()函数上报一组传感器数据

2(DRI)0x80

调用enable_sched_data()启用DRI(Data ReadyInterrupt,数据完成中断),按照set_cycle_time指定的ODR(Output Data Rate,数据输出速率)进行数据采集,采集完成后调用sns_ddf_driver_if_s中指定的handle_irq()函数上报传感器数据。

3(FIFO)0xD0

调用trigger_fifo_data()函数启动FIFO模式,当数据量到达指定的阈值,触发sns_ddf_smgr_data_notify()函数上报一批数据。

Sensor系列之aDSP端Sensor Driver流程相关推荐

  1. Qcom_Sensor(九)--- 之 aDSP端Sensor Driver流程

    Qcom_Sensor(九)--- 之 aDSP端Sensor Driver流程 MAIN SMGR INIT 1. HAL层数据处理 2. aDSP层数据处理 Sensor Probe过程: pus ...

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

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

  3. linux驱动由浅入深系列:高通sensor架构实例分析之一

    点击打开链接 本系列导航: linux驱动由浅入深系列:高通sensor架构实例分析之一(整体概览+AP侧代码分析) linux驱动由浅入深系列:高通sensor架构实例分析之二(adsp驱动代码结构 ...

  4. Camera和Image sensor技术基础笔记(10) -- sensor器件适配需要注意的地方

    本篇笔记为一个简单总结,主要为了说明一下在软件项目中对于新的sensor器件适配所需要注意的点(个人经验,仅供参考). 数据手册 一般通过FAE拿到器件手册.拿到手册后重点查看: sensor的管脚描 ...

  5. Android音视频学习系列(九) — Android端实现rtmp推流

    系列文章 Android音视频学习系列(一) - JNI从入门到精通 Android音视频学习系列(二) - 交叉编译动态库.静态库的入门 Android音视频学习系列(三) - Shell脚本入门 ...

  6. Netty源码分析系列之服务端Channel的端口绑定

    扫描下方二维码或者微信搜索公众号菜鸟飞呀飞,即可关注微信公众号,Spring源码分析和Java并发编程文章. 微信公众号 问题 本文内容是接着前两篇文章写的,有兴趣的朋友可以先去阅读下两篇文章: Ne ...

  7. 深入解析 Dubbo 3.0 服务端暴露全流程

    简介:随着云原生时代的到来,Dubbo 3.0 的一个很重要的目标就是全面拥抱云原生.正因如此,Dubbo 3.0 为了能够更好的适配云原生,将原来的接口级服务发现机制演进为应用级服务发现机制. 作者 ...

  8. Dubbo服务端暴露全流程

    本文来说下Dubbo服务端暴露全流程 文章目录 概述 什么是应用级服务发现 服务端暴露全流程 暴露injvm协议的服务 注册service-discovery-registry协议 暴露Triple协 ...

  9. 跨平台跨端的登录流程及其安全设计

    跨平台跨端的登录流程及其安全设计 目录 跨平台跨端的登录流程及其安全设计 一.登录流程 1.1.登录流程时序图 1.2.三方App 登录 1.3.请求的路由守卫 二.注册流程 2.1.注册流程时序图 ...

  10. uni-app APP端-微信登录流程

    uni-app APP端-微信登录流程 手把手教学 1.前期准备 在微信开放平台注册账户 微信开放平台 (qq.com) 在管理中心中创建移动应用项目,按要求填写相关信息 审核通过后即可获得我们所需的 ...

最新文章

  1. php-5.3.3安装注意问题
  2. 两两对应成排的 表格 样式
  3. linux makefile 编译标记 EXTRA_CFLAGS 简介
  4. 对分查找的最多次数_Java数据结构与算法:多路查找树
  5. #define const typedef
  6. 我对架构师的理解(如何成为一个合格的架构师)
  7. 一个简单的PHP邮件列表管理器
  8. vim打开出现的文档^M什么
  9. java hashmap putall_Java ConcurrentHashMap.putAll方法代码示例
  10. 解决fatal: unable to connect to github.com问题
  11. Flink on Zeppelin (1) - 入门篇
  12. 阶段3 1.Mybatis_09.Mybatis的多表操作_3 完成account的一对一操作-通过写account的子类方式查询...
  13. 通过自动化接口调用InstallShield 报错的解决办法
  14. [Android][Kernel]基于crash工具搭建分析ramdump的平台
  15. MySQL一些随机函数记录
  16. Aleo提高高算力的解决方法(精选)
  17. 三轴加速度传感器bma150驱动解析
  18. 凤凰大视野----冷暖人生: 记录平凡人的普通人生
  19. 电脑diy配件产品导购,装机硬件资讯
  20. 什么是GB/T50430

热门文章

  1. 响应式架构:消息模式Actor实现与Scala、Akka应用集成
  2. 模块化分析设计(简单的注册登录模块)
  3. db2字符串定位_DB2/Oracle/SQL server判断某个字符串或单个字符在源字符串中出现的位置...
  4. flume学习(三):Flume Interceptors的使用
  5. 2019年第四次课程设计实验报告
  6. shell脚本一键安装jdk
  7. laravel中修改默认时区
  8. shell逻辑判断、文件属性判断、if特殊用法、case判断
  9. 正则表达式案例分析 (二)
  10. 向窗口输入文字--TextOut和DrawText函数