高通平台sensor学习

本文详细介绍了在高通平台上进行Sensor驱动的移植和调试过程,包括SSC和SEE两种架构的区别,如何在SEE架构下进行驱动的添加、编译选项修改、I2C协议配置以及TZ权限管理。此外,还涉及AP部分的json文件修改以使Sensor运行,并提供了可能出现的问题及解决策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚入行驱动时最先接触调试的外设模块便是sensor,一直都是零零散散的记录,这次终于下定决心对自己所学做一个系统的总结。

sensor作为一款常用的外设,虽不起眼但是很多功能确实离不开它。比如我们手机上常用的步数记录,就要用到重力加速度传感器和陀螺仪,手机亮度自动调节离不开光感传感器,其它的诸如红外传感器、温湿度传感器、气压传感器等等在各种场景下发挥着不可或缺的作用。单论调试来说,基础的调试移植并不复杂,新人也很容易上手;如果要去调试效果就需要研读代码,对代码流程有一定的了解;再深一层,想弄清楚sensor的架构各部分代码是如何跑起来的,就需要花时间阅读相关文档,同时结合代码去逐步理解架构。不过专门深入搞sensor的不多,毕竟还没指甲盖大个料,几块钱,没钱途呀。调调屏去哪儿都能干,调调camera调的好进个大厂实现财富自由不是梦。

言归正传,下面就来介绍高通平台sensor相关的一些基础知识。

架构篇

目前市面常见平台模块使用的是SSC和SEE架构。前者用于一些老的平台诸如MSM8953、SDM660、QCM2150等等,新一点平台使用的都是SEE架构。直观来看,会觉得SEE架构使用起来更方便,尤其是移植的时候不用去改很多东西,因为他把SSC架构里的很多东西都封装了起来你可以直接使用,而不必再去逐个修改。就好比造一辆车,SSC架构需要从最小的零件开始拼起,而SEE架构则相当于把各个部件都组装好,你直接装配就行。当然方便的同时也有隐患,就是出问题的时候你更难排查,毕竟不是你自己从最底层一点点拼出来的, ·出了问题你当然不知道去哪儿找原因啦。从两者架构图中就能看出一二。

左边是SSC右边是SEE,可以明显的看到SEE架构要简洁了许多。当然光看这框图可没用,想要真正理解两种架构之间的具体区别,那得花时间打磨咯,咱目前还达不到这个水平哈哈哈。

移植篇

移植算是sensor调试最基本的工作了,即如何让sensor跑起来。这里主要介绍SEE架构的移植调试。

SEE架构移植

SEE架构下点亮一个sensor驱动,如果BP侧ADSP/SLPI下面已有驱动,则只需要修改AP侧对应的json文件中的配置即可;如果没有相关驱动,就需要手动添加相关驱动和编译选项,再修改AP侧配置。

这里以6490平台为例,后续有些平台位置换到了slpi里,但是换汤不换药。

(1)sensor驱动代码相关路径,根据平台不同有所差异。

  • adsp_proc\ssc_drivers

(2)sensor编译选项相关代码路径

  • adsp_proc/ssc/chipset/kodiak/por.py

(3)AP侧json文件路径

  • vendor\qcom\proprietary\sensors-see\registry\config\lahaina

(4)AP测hal层相关代码路径

  • vendor\qcom\proprietary\sensors-see\sensors-hal-2.0\sensors

依据高通文档说明,描述如何移植添加一个新的sensor驱动,以添加一个重力加速度传感器BMI160为例,并添加修改对应json文件。直接上代码

  • 添加编译选项,让新加的sensor驱动参与编译

把我们要添加的sensor型号添加到系统原生的代码里,不知道型号怎么写可以参考BMI160驱动代码下面build/目录,有一个sns_bmi16x.scons,这个就是驱动的编译相关文件,取前面sns_bmi16x就是sensor型号,其他sensor同理。有些童鞋可能有疑问了,不是添加bmi160么,怎么又变成bmi16x了?啊哈,盲生你发现了华点。这是因为sensor同一系列有时候会有好多型号,这些配置基本都是类似的,因此厂商在集成驱动代码的时候就把它们集成在一套里面啦。


if 'SSC_TARGET_X86' not in env['CPPDEFINES']:
        #POR sensors list
        include_sensor_vendor_libs.extend(['lsm6dst',         #ACCEL/GYRO/MD/TEMP
                                           'sns_ak0991x',     #MAGNETOMETER
                                           'sns_ltr556',
                                           'sns_bmi16x',
                                           'sns_tmd3702',     #ALS/PROX
                                           'sns_lps22hx',     #PRESSURE
                                           'sns_sx932x',      #CAPACITIVE
                                           'sns_bu52053nvx']) #HALL

  • 添加驱动代码

sensor驱动代码一般由对应厂商提供,把驱动代码放在adsp_proc\ssc_drivers目录下即可。

  • 修改I2C协议相关

该平台sensor使用的是i2c协议,需要在对应文件下修改协议为i2c。i2c对应的gpio为gpio161和gpio162,gpio161为数据lane,gpio162为时钟lane。从下图中看到两个gpio对应QUP_IO_0和QUP_IO_1,因此在对应文件中修改se0和se1协议为i2c。(实际使用时根据需求修改为i2c、i3c、spi)

adsp_proc/core/settings/buses/qup_fw/config/kodiak/fw_devcfg.c


// #elif defined BUS_PRESIL_CONFIG //same as MTP
////// RUMI //////  offset,        protocol,   mode,  load_fw, dfs_mode
se_cfg se0_cfg_rumi = { 0x80000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
se_cfg se1_cfg_rumi = { 0x84000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
se_cfg se2_cfg_rumi = { 0x88000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
//se_cfg se3_cfg_rumi = { 0x8C000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
//se_cfg se4_cfg_rumi = { 0x90000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE };
//se_cfg se5_cfg_rumi = { 0x94000, SE_PROTOCOL_UART,   FIFO,    FALSE, FALSE  };
se_cfg se6_cfg_rumi = { 0x98000, SE_PROTOCOL_UART,   FIFO,    FALSE,FALSE  };
//se_cfg se7_cfg_rumi = { 0x9C000, SE_PROTOCOL_UART,   FIFO,     FALSE,FALSE  };

// #else
////// MTP ///////  offset,        protocol,   mode,  load_fw, dfs_mode
se_cfg se0_cfg = { 0x80000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
se_cfg se1_cfg = { 0x84000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
se_cfg se2_cfg = { 0x88000, SE_PROTOCOL_I2C,    GSI,     TRUE, TRUE  };
se_cfg se3_cfg = { 0x8C000, SE_PROTOCOL_I2C,    GSI,     FALSE, TRUE  };
se_cfg se4_cfg = { 0x90000, SE_PROTOCOL_SPI,       GSI,     TRUE, TRUE };
se_cfg se5_cfg = { 0x94000, SE_PROTOCOL_UART,   FIFO,    TRUE,FALSE };
se_cfg se6_cfg = { 0x98000, SE_PROTOCOL_UART,   FIFO,    TRUE,FALSE  };
//se_cfg se7_cfg = { 0x9C000, SE_PROTOCOL_UART,   FIFO,     TRUE,FALSE  };
  • TZ中释放gpio权限

总线gpio相关的权限,i2c、spi、uart等都在TZ中管理。查看平台总线gpio对应哪一组se可以参考高通文档QCM6490/QCS6490 Linux Android Peripheral (UART, SPI, I2C, I3C) Technical Overview

每个平台都有类似的对应文档,可以在高通文档网站获取。(注意:修改总线权限相关容易导致死机,请谨慎修改)

本平台总线gpio对应关系表,图中LPI_QUP是专门给sensor用的,因为sensor需要用到LPIgpio,这里不做详细讲述,后面会说到。可以看到我们用的是se1,文件内默认的协议即为i2c,因此不需要做修改。

trustzone_images/core/settings/buses/qup_accesscontrol/qupv3/config/kodiak/QUPAC_Access.c


const uint32 ssc_qupv3_perms_size_default = sizeof(ssc_qupv3_perms_default)/sizeof(ssc_qupv3_perms_default[0]);
const QUPv3_se_security_permissions_type qupv3_perms_rumi[] =
{
  /*   PeriphID,         ProtocolID,               Mode,  NsOwner,       bAllowFifo, bLoad, bModExcl  */
  { QUPV3_0_SE0, QUPV3_PROTOCOL_I3C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // camera
  { QUPV3_0_SE1, QUPV3_PROTOCOL_I2C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // APPS I2C 给sensor i2c使用
  { QUPV3_0_SE2, QUPV3_PROTOCOL_I2C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // I2C
  { QUPV3_0_SE3, QUPV3_PROTOCOL_SPI,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // Broadcast SPI
  /*QUPV3_0_SE4*/
  { QUPV3_0_SE5, QUPV3_PROTOCOL_UART_2W, QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  FALSE, FALSE }, // Debug UART
  /* QUPV3_0_SE6, QUPV3_PROTOCOL_SPI */
  { QUPV3_0_SE7, QUPV3_PROTOCOL_UART_4W, QUPV3_MODE_FIFO, AC_MSS_MSA,         TRUE,  FALSE, FALSE }, // UART (MODEM  standalone)
  { QUPV3_1_SE0, QUPV3_PROTOCOL_SPI,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE },

trustzone_images/core/settings/buses/qup_accesscontrol/qupv3/config/kodiak/QUPAC_Access_RFCOMM.c


const uint32 ssc_qupv3_perms_size_default = sizeof(ssc_qupv3_perms_default)/sizeof(ssc_qupv3_perms_default[0]);
const QUPv3_se_security_permissions_type qupv3_perms_rumi[] =
{
  /*   PeriphID,         ProtocolID,               Mode,  NsOwner,       bAllowFifo, bLoad, bModExcl  */
  { QUPV3_0_SE0, QUPV3_PROTOCOL_I3C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // camera
  { QUPV3_0_SE1, QUPV3_PROTOCOL_I2C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // APPS I2C 
  { QUPV3_0_SE2, QUPV3_PROTOCOL_I2C,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // I2C
  { QUPV3_0_SE3, QUPV3_PROTOCOL_SPI,     QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  TRUE,  FALSE }, // Broadcast SPI
  /*QUPV3_0_SE4*/
  { QUPV3_0_SE5, QUPV3_PROTOCOL_UART_2W, QUPV3_MODE_FIFO, AC_HLOS,            TRUE,  FALSE, FALSE }, // Debug UART

以上这些修改部分完成之后,就可以进行编译验证,想要确定编译是否生效可以查看

adsp_proc/ssc/framework/build/sensor_img/qdsp6/kodiak.adsp.prod/sns_static_sensors.c

adsp_proc/ssc/framework/build/sensor_img/qdsp6/kodiak.adsp.prod/sns_static_drivers.c

看这两个文件内是否有你添加的sensor型号,如果有就是参与编译了,如果没有,说明你添加的驱动没有参与编译需要重新检查。sensor驱动部分最终打包到NON_HLOS.bin镜像中,TZ修改打包到devcfg.mbn中,验证时可以单独替换比较方便。

adb root
adb reboot bootloader
fastboot flash modem NON_HLOS.bin
fastboot flash devcfg devcfg.mbn

  • AP部分文件修改

vendor/qcom/proprietary/sensors-see/registry/config/lahaina/lahaina_qrd_bmi160_0.json

vendor/qcom/proprietary/sensors-see/sensors-hal-2.0/sensors/orientation.cpp

该目录下原本并没有bmi160对应的json文件,需要我们自己添加,可以复制高通原生重力加速度传感器的json文件来用,另目录下有很多同料但是名称不同的json文件,可以根据平台设备树来确认我们需要的,比如调试项目使用的QRD,那么我们就选带qrd的文件。hal层的修改是为了把g-sensor的数据通过算法转换为方向数据。

相关属性含义在文件内注释

{
  "config":
  { 
    "hw_platform": ["QRD"], //  cat /sys/devices/soc0/hw_platform获取
    "soc_id": ["497"] //cat /sys/devices/soc0/soc_id 获取
  },
  "bmi160_0":{
    "owner": "sns_bmi160",
    ".accel":{
      "owner": "sns_bmi160",
      ".config":{
        "owner": "sns_bmi160",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "1"
        },//配置中断模式或者轮训模式(“0”轮训模式,“1”中断模式)
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },//用来区分同一硬件多个传感器
        "res_idx":{ "type": "int", "ver": "0",
          "data": "2"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    },
    ".gyro":{
      "owner": "sns_bmi160",
      ".config":{
        "owner": "sns_bmi160",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "1"
        },
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "res_idx":{ "type": "int", "ver": "0",
          "data": "4"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    },
    ".md":{
      "owner": "sns_bmi160",
      ".config":{
        "owner": "sns_bmi160",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "1"
        },
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "res_idx":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    },
    ".temp":{
      "owner": "sns_bmi160",
      ".config":{
        "owner": "sns_bmi160",
        "is_dri":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "hw_id":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "res_idx":{ "type": "int", "ver": "0",
          "data": "2"
        },
        "sync_stream":{ "type": "int", "ver": "0",
          "data": "0"
        }
      }
    }
  },
  "bmi160_0_platform":{
    "owner": "sns_bmi160",
    ".config":{
      "owner": "sns_bmi160",
      "bus_type":{ "type": "int", "ver": "0",
        "data": "0"
      },//I2C 写 0、 SPI 写 1、 I3C 写 3
      "bus_instance":{ "type": "int", "ver": "0",
        "data": "2"
      },//bus_instance: = QUP 数 + 1
      "slave_config":{ "type": "int", "ver": "0",
        "data": "104"
      },//I2C 地址,参考规格书
      "min_bus_speed_khz":{ "type": "int", "ver": "0",
        "data": "400"
      },//最小 COM 总线时钟速度,默认配置 400khz
      "max_bus_speed_khz":{ "type": "int", "ver": "0",
        "data": "400"
      },//最大 COM 总线时钟速度,默认配置 400khz
      "reg_addr_type":{ "type": "int", "ver": "0",
        "data": "0"
      },//寄存器地址类型( 寄存器地址位数,“ 0” 8 bit “ 1” 16 bit “ 2” 32bit)
      "dri_irq_num":{ "type": "int", "ver": "0",
        "data": "102"
      },//中断引脚
      "irq_pull_type":{ "type": "int", "ver": "0",
        "data": "2"
      },//配置中断引脚内部电平类型
      "irq_is_chip_pin":{ "type": "int", "ver": "0",
        "data": "1"
      },//配置 MSM_GPIO 由于中断模式
      "irq_drive_strength":{ "type": "int", "ver": "0",
        "data": "0"
      },//配置 MSM_GPIO 由于中断模式
      "irq_trigger_type":{ "type": "int", "ver": "0",
        "data": "0"
      },//中断触发类型,这里我们配置为低电平触发
      "num_rail":{ "type": "int", "ver": "0",
        "data": "2"
      },//中断触发类型,这里我们配置为低电平触发
      "rail_on_state":{ "type": "int", "ver": "0",
        "data": "2"
      },//低功耗供电模式 LPM 还是常规供电模式 NPM
      "vddio_rail":{ "type": "str", "ver": "0",
        "data": "/pmic/client/sensor_vddio"
      }, 
      "vdd_rail":{ "type": "str", "ver": "0",
        "data": "/pmic/client/sensor_vdd"
      }, 
      "rigid_body_type":{ "type": "int", "ver": "0",
      "data": "0"
      }
    },
    ".orient":{
      "owner": "sns_bmi160",
      "x":{ "type": "str", "ver": "0",
        "data": "+y"
      },
      "y":{ "type": "str", "ver": "0",
        "data": "-x"
      },
      "z":{ "type": "str", "ver": "0",
        "data": "+z"
      }
    },
    ".gyro":{
      "owner": "sns_bmi160",
      ".fac_cal":{
        "owner": "sns_bmi160",
        ".corr_mat":{
          "owner": "sns_bmi160",
          "0_0":{ "type": "flt", "ver": "0",
            "data": "1.0"
          },
          "0_1":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "0_2":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "1_0":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "1_1":{ "type": "flt", "ver": "0",
            "data": "1.0"
          },
          "1_2":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_0":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_1":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_2":{ "type": "flt", "ver": "0",
            "data": "1.0"
          }
        },
        ".bias":{
          "owner": "sns_bmi160",
          "x":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "y":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "z":{ "type": "flt", "ver": "0",
            "data": "0.0"
          }
        }
      }
    },
    ".accel":{
      "owner": "sns_bmi160",
      ".fac_cal":{
        "owner": "sns_bmi160",
        ".corr_mat":{
          "owner": "sns_bmi160",
          "0_0":{ "type": "flt", "ver": "0",
            "data": "1.0"
          },
          "0_1":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "0_2":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "1_0":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "1_1":{ "type": "flt", "ver": "0",
            "data": "1.0"
          },
          "1_2":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_0":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_1":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "2_2":{ "type": "flt", "ver": "0",
            "data": "1.0"
          }
        },
        ".bias":{
          "owner": "sns_bmi160",
          "x":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "y":{ "type": "flt", "ver": "0",
            "data": "0.0"
          },
          "z":{ "type": "flt", "ver": "0",
            "data": "0.0"
          }
        }
      }
    },
    ".temp":{
      "owner": "sns_bmi160",
      ".fac_cal":
      {
        "owner": "sns_bmi160",
        ".scale":{
          "owner": "sns_bmi160",
          "x":{ "type": "flt", "ver": "0",
            "data": "1.0"
          }
        },
        ".bias":{
          "owner": "sns_bmi160",
          "x":{ "type": "flt", "ver": "0",
            "data": "0.0"
          }
        }
      }
    },
    ".md":{
      "owner": "sns_bmi160",
      ".config":{
        "owner": "sns_bmi160",
        "thresh":{ "type": "flt", "ver": "0",
            "data": "0.156"
        },
        "disable":{ "type": "int", "ver": "0",
          "data": "0"
        },
        "win":{ "type": "flt", "ver": "0",
          "data": "0.02"
        }
      }
    },
    ".placement":{
      "owner": "sns_bmi160",
      "0":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "1":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "2":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "3":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "4":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "5":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "6":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "7":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "8":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "9":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "10":{ "type": "flt", "ver": "0",
        "data": "0.0"
      },
      "11":{ "type": "flt", "ver": "0",
        "data": "0.0"
      }
    }
  }  
}

根据硬件设计配置完成后,可以直接把json文件push到设备的/vendor/etc/sensors/config/下面验证。

adb root
adb remount
adb push   xxx vendor/etc/sensors/config/
adb shell
rm -rf mnt/vendor/persist/sensors/registry/registry/*  (这步操作是删除由json文件生成的配置文件防止干扰验证)
adb reboot

修改都替换到设备之后,可以装个apk看下效果。

手头没有调试设备的话可以用自己的手机试一下哦,打开手机设置--关于手机--点击7此版本号,提示您已进入开发者模式--返回上一级,进入系统--点击开发人员选项--把调试下面相关的权限打开,然后就可以连上PC上的adb操作啦,如下就已经把app装到手机里啦。

(Ps:对普通用户来说开发者选项也没有什么用处啦,可能就一个阳光下阅读能力提升有点用,这个功能打开的话在太阳下面显示状况会好不少,但是因为太耗电了,所以一般都藏起来啦)

apk打开之后就是这个样子,这些也是一般移动设备常用的传感器类型。

Debug篇

  • 获取ADSP端sensor初始化log

因为sensor在开机过程中加载的时候,diag口还未识别因此无法抓到初始化log,因此可以重启ADSP子系统让sensor重新加载一编来抓取log。子系统要通过cat节点确认是否是adsp,这里只是示例。这也是最常用的debug手段,通过初始化log追踪定位问题发生位置。

adb root
adb shell "cat /sys/bus/msm_subsys/devices/subsys<N>/name"
adb shell "echo 'related' > /sys/bus/msm_subsys/devices/subsys<N>/restart_level

然后再QXDM工具上输入send_data 75 37 03 48 00

ADSP

send_data 75 37 03 48 00

SLPI

send_data 75 37 03 64 00

工具里可以把不需要的信息列隐藏掉,这样log起来更方便一点。

调试问题篇

这部分主要介绍一些移植调试过程中可能遇到的一些问题以及应对方法

  1. 编译环境

该问题在sm4350平台调试中遇到,调试过程中一直出现G-sensor导致死机问题,尝试过替换同平台项目的persist镜像,json文件,生成文件,甚至升级基线都试过还是无法解决死机问题,最后高通方面建议我们查看下是否是编译环境有问题。通过查看4350平台sensor文档,编译ADSP之前需要更新nanopb工具包作为基础,编译服务器需要ubuntu版本16以上,更新之后重新编译ADSP不再死机,最后解决方案是把nanopb压缩工具包一并提交上去,并修改编译脚本在编译ADSP之前先升级工具。

下载后放入指定位置,执行指令打印如图信息表示成功,即可继续编译ADSP


python ssc_api/build/config_nanopb_dependency.py -f nanopb-0.3.9.5-linux-x86

2. 供电问题

在移植初期常常会遇到供电问题,通常sensor都是由两路供电1.8V和2.8V,如果用万用表量不到供电,可以尝试下先把电常供。

查找给sensor供电的LDO代码路径

adsp_proc\core\settings\pmic\pm\config\adsp\kodiak\pm_config_pam.c

修改sensor供电为常供代码路径(或者在rpm下)

aop_proc\core\pmic\pm\config\kodiak\pm_config_target.c


{.AccessAllowed = PM_ACCESS_ALLOWED,    .RsrcCategory = VRM_RSRC_REGULATOR, .AlwaysOn = PM_ON,  .MinMode = PM_NPM_MODE_VAL, .SafetyHR = 32,  .MinVoltage = 1800, .MaxVoltage = 2000, .EnableFixedTime = 300, .EnableStepperWarmUpTime = 0, .VoltFixedUpTime = 0, .VoltFixedDownTime = 0, .VoltStepperExtraUpTime = 0, .VoltStepperExtraDownTime = 0, .VoltDischargeTime = 0, .ModeFixedTime = 20, .VregReadyEn = PM_SETTLING_EN, .VregReadyErrEn = PM_SETTLING_ERR_EN,  .VregWdogTimer = VRM_8X_SETTLING_TIMER, .AopHandling = 0, .VoltSeqType = VRM_GENERIC_SEQ, .EnableSeqType = VRM_GENERIC_SEQ, .ModeSeqType = VRM_GENERIC_SEQ, .DrvOwnMask = PM_DRV_AUD|PM_DRV_HLOS,  .Reserved = 0},  //LDO8 Sensors

其中.AlwaysOn = PM_ON,属性就表示该LDO长供,如果改为PM_OFF就是关闭掉长供,其它的属性尽量不要驱动,比如电压上下限.MinVoltage = 1800, .MaxVoltage = 2000,有时候修改会导致死机。

长供电可以解决大部分供电问题,但是如果长供电之后还是不行,就要看下原理图是不是该LDO还受其他地方的控制,列举两种可能的情况:

  • 供电脚由gpio控制

如果是普通的gpio可以在lk阶段把gpio拉高即可正常供电,如果是在pmi芯片上,就比较复杂一些,这两种状况下如何控制gpio会在后面其他帖子专门列出。

  • LDO供电默认没有打开

这种情况比较少见,只在660平台上某项目见到过,默认LDO未启用,需要在xbl中打开


a/boot_images/QcomPkg/Library/PmicLib/target/sdm660_pm660_pm660l/system/src/pm_sbl_boot_oem.c
+++ b/boot_images/QcomPkg/Library/PmicLib/target/sdm660_pm660_pm660l/system/src/pm_sbl_boot_oem.c
@@ -214,6 +214,8 @@ pm_driver_post_init (void)
  //SW WA to Enable LDO2B (SDCARD LDO), This should go in OTP.
      err_flag |= pm_ldo_sw_enable(PM_DEVICE_1,PM_LDO_2,PM_ON);
+     //SW WA to Enable LDO3B (SENSOR LDO), This should go in OTP.
+     err_flag |= pm_ldo_sw_enable(PM_DEVICE_1,PM_LDO_3,PM_ON);
      //Configure MISC.VSET_LB to stable solution(0x02)
      /* This should have been handled in SBL config, but SBL config has the best power optimised solution as default,

3.中断脚选择不合适

此问题出现于某平台光距传感器上。供电与I2c都正常,apk显示sensor也是点亮的,但是手覆盖上去亮度值和距离值都不会变化。查阅PIN定义表格并询问高通,高通告知是中断脚选用有问题,sensor的中断脚需要是LPI gpio,也就是带有唤醒功能,普通的gpio就会出现功能异常的现象,这种问题较少出现,出现一般就需要硬件改版。

4.json文件不解析

此问题出现在最近调试的6690平台,新添加的json文件一直不解析,无意之中发现跟名字有关系,默认的json命名是以volcano_开头的,系统默认的ak0991那个物料是可以正常解析加载的,但是我新加这样命名就不行,最后把volcano_改成了别的替代,成功解析加载。

小结

sensor作为驱动调试中常见的外设之一,看起来没有其它外设那么复杂,但是个中流程等等还是值得我们去研读代码、深度探究。后面调试过程中遇到的问题和心得也会继续汇总分享出来,文章写得有问题的地方还望大家多多指正,欢迎一起讨论~

<think>好的,我现在需要帮助用户解决关于Dify循环实现的问题。首先,我需要明确用户的具体需求。他们提到“dify 循环实现”或“dify 如何处理循环”,但Dify本身可能没有直接称为“循环”的功能,所以需要结合现有文档中的信息来推断可能的解决方案。 根据用户提供的引用内容,Dify工作流中有迭代节点[^1]。这可能类似于编程中的循环结构,用于重复执行某个任务。例如,在处理列表数据或需要多次执行同一操作时,迭代节点可以派上用场。我需要详细解释迭代节点的配置和使用步骤,确保用户能够理解如何设置循环次数或遍历数据集。 另外,用户可能对如何处理循环中的错误或性能问题感兴趣。引用[2]提到在Dify中处理PEM文件的问题,这可能涉及在循环中正确处理数据格式,避免错误积累。需要提醒用户在循环中注意错误处理和资源管理,确保每次迭代的稳定性。 引用[3]中的例子展示了如何结合FastAPI和Selenium进行实时监控并生成GIF,这可能涉及循环截取浏览器内容。虽然Dify本身可能不直接控制这类循环,但可以通过外部脚本或定时任务触发工作流,模拟循环执行。这部分需要说明如何将外部循环机制与Dify结合使用。 接下来,我需要组织回答结构。首先介绍迭代节点的基本概念和配置步骤,然后讨论循环中的数据处理和错误处理,最后补充外部触发循环的方法。同时,生成相关问题以帮助用户进一步探索,比如优化循环性能或处理复杂数据结构。 需要确保回答符合格式要求,使用正确的中文表达,行内公式用$...$,独立公式用$$...$$,但当前问题不涉及数学公式,所以可能不需要使用。同时,引用标识要自然地添加到相关段落末尾,如、[^2]、[^3]。 最后,检查是否有遗漏点,比如Dify的其他循环相关功能或用户可能遇到的常见问题,确保回答全面且易于理解。</think>在Dify中处理循环逻辑主要通过**迭代节点**实现,以下是具体实现方式和应用场景的解析: ### 一、Dify的循环实现机制 Dify通过**工作流设计器**中的迭代节点处理循环需求,其核心原理类似编程中的`for循环`。迭代节点可遍历以下数据类型: - 数组列表:`["A","B","C"]` - 字典集合:`{"key1":"value1", "key2":"value2"}` - 数值范围:通过`range()`函数生成序列 配置示例: ```python # 模拟迭代节点的数据输入 input_data = { "dataset": [1,2,3,4,5], "process_logic": "item * 2" # 对每个元素执行乘以2的操作 } ``` ### 二、迭代节点的关键配置步骤 1. **数据源绑定**:将数组/字典类型变量连接到迭代节点的输入端口 2. **循环变量命名**:设定当前元素的变量名(默认为`item`) 3. **子流程设计**:在迭代节点内部构建需要重复执行的逻辑模块 4. **结果聚合**:通过`outputs`收集所有迭代结果,支持数组或对象格式 $$ \text{总耗时} = \sum_{i=1}^{n}(单次迭代时间_i) + 系统开销 $$ ### 三、循环中的特殊处理 1. **错误中断控制**: - 启用`continueOnError`参数可跳过失败迭代 - 通过`try-catch`模块包裹敏感操作 2. **并行优化**: ```python # 伪代码示例 Parallel.forEach(dataset, lambda item: process(item)) ``` 3. **结果过滤**: ```python filtered = filter(lambda x: x%2==0, processed_results) ``` ### 四、应用场景案例 1. **批量文件处理**:遍历存储桶中的文件列表进行格式转换 2. **数据清洗**:对数据库查询结果集进行逐条校验 3. **API轮询**:定时循环调用第三方接口直到满足特定条件
评论 23
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值