ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

海思hi35xx平台IMX307与IMX377 sensor驱动适配与调试实战

海思hi35xx平台IMX307与IMX377 sensor驱动适配与调试实战 简介这是一份面向海思hi35xx平台开发者的索尼IMX307传感器驱动源码包适用于安防监控、智能硬件等场景帮助解决CMOS图像传感器在嵌入式平台上的驱动适配与初始化配置问题。资源共4个文件压缩包仅54KB其中两个C源文件分别承担主驱动逻辑与传感器控制逻辑一个H头文件定义关键结构体和接口常量一个Makefile用于编译构建结构精简便于直接融入已有海思SDK工程。已有828人学习下载属于轻量级核心代码参考。源码覆盖分辨率、帧率、曝光时间等参数配置以及I2C通信、电源管理等关键控制路径开发者可据此理解IMX307寄存器映射、控制时序与海思ISP的对接流程结合官方文档快速完成驱动移植和调试显著减少底层协议梳理时间。1. 从这串命名看海思 hi35xx 的 sensor 适配到底在做什么把sony_imx307_sonyimx377_SONYIMX307_hi35xx_海思_COm307拆开来看它不是一个软件包名而是一个「工程目录级」的命名习惯前半段是索尼两颗 sensor 的型号中间是海思 hi35xx 平台的代号最后COm307是板级适配目录的缩写常见写法是把 sensor 型号和板子代号拼在一起。串在一条里的意思是——这块板子上IMX307 和 IMX377 都要跑通海思的 ISP 链路需要在 SDK 里为它们各写一份 sensor 驱动并编进库。这篇文章就是把这件事从头到尾拆给你IMX307 和 IMX377 在海思平台上各管什么、驱动怎么写、Makefile 怎么改、参数怎么调、烧录后怎么验证。适合正在做 IPC 或多目相机方案、手里有海思 SDK 却不知道从哪下手的人。2. 先看 sensor 选型IMX307 与 IMX377 在 hi35xx 上的分工2.1 IMX307 和 IMX377 的硬件差异直接决定你该对齐哪份寄存器手册IMX307 是索尼 STARVIS 系列里的 200 万像素级 sensor目标场景非常明确低照度监控。它采用背照式像素结构在 0.1 lux 以下仍能输出可用的彩色画面像素尺寸比普通 200 万 sensor 大所以暗部噪声控制得好。IMX307 的输出接口一般是 MIPI分辨率以 1920x1080 为主也能输出 2048x1536 左右的分辨率但工程上大家最常用的是 1080P60fps 或 120fps 两档。如果你做的是夜视 IPC、双光相机、带红外补光的枪机选 IMX307 是合理的。IMX377 则是另一个量级1200 万像素级别1/2.3 英寸左右的光学格式主打高解析力常用于多目全景相机、4K 出图或者需要大视野裁剪的场景。它和 IMX307 在寄存器地图、曝光方式、增益范围都不一样不能拿一份驱动通用。两颗 sensor 的驱动文件名都在标题里出现了说明这个工程是「一颗 sensor 板子同时兼容两套 sensor 驱动」这在多目产品里很常见主路用 IMX377 拍全景辅路用 IMX307 做细节抓拍或者一颗做彩色一颗做黑白。选型的另一个判断维度是海思平台。IMX307 对带宽和 ISP 处理能力的要求不高配 Hi3516CV500 这类单核 A7 平台就能跑满 1080P。IMX377 因为输出像素量大MIPI lane 数更多带宽占用高常见搭配是 Hi3516DV300 或 Hi3519AV100这两个平台有更充裕的 ISP 吞吐和内存带宽。你手里的 SDK 到底是哪个平台决定你编译时要选哪套工具链——后面讲 Makefile 时会回到这一点。2.2 hi35xx 平台的 sensor 接入链路sensor 驱动、ISP 与 sample 的关系海思平台上 sensor 出图像不是「接上就能看」的。硬件上 sensor 通过 MIPI 接到海思 MIPI RX控制通路走 I2C时钟由海思给一个 MCLK。上层软件链路由三层组成第一层是 sensor 驱动。这一层做的事情是把 sensor 的寄存器操作封装成海思定义的接口包括上电、下电、初始化寄存器流、设置曝光、设置增益、设置镜像翻转、设置 WDR 模式等。海思不关心你 sensor 内部寄存器具体是多少它只管调用你提供的回调函数。第二层是 ISP。海思的 ISP 负责 3AAE、AWB、AF 可选、降噪、坏点校正、宽动态合成等。ISP 在做 AE 和 AWB 时需要知道 sensor 当前的曝光和增益是多少所以它通过 sensor 驱动里的sensor_get_exposure、sensor_set_exposure这类函数来获取和设置。这一层是项目中最容易出问题的地方——sensor 驱动里的曝光单位、增益换算跟 ISP 算法期望不一致画面就过曝或过暗。第三层是 sample。海思 SDK 的 sample 代码是拿来跑通整个采集编码流程的。sample_comm_isp.c里维护着一张 sensor 注册表声明了板子上支持哪些 sensor。你新增一颗 sensor 时必须把它的名字加进这张表否则 sample 编译进去了也不知道去哪找驱动。2.3 sensor 驱动怎么被加载从sensor_t注册表到libsns_xxx.so海思 SDK 的 sensor 驱动最终编译成一个.so文件命名一般是libsns_imx307.so、libsns_imx377.so这样。sample 程序在运行时会动态加载这个库然后从库里拿到一个sensor_t结构体指针。senosr_t实际命名可能是sensor_t或SENSOR_T不同 SDK 有细节差异大致长这样typedef struct { const char *name; // 传感器名称如 sony_imx307 int i2c_addr; // I2C 从设备地址 int i2c_bus; // I2C 总线号 int mclk; // MCLK 频率一般是 27000000 int gpio_reset; // reset 引脚 int gpio_pwdn; // power down 引脚 void (*sensor_init)(int bus, int addr); // 初始化寄存器流 void (*sensor_exit)(int bus, int addr); // 退出时恢复状态 int (*sensor_set_exposure)(int bus, int addr, int exposure); int (*sensor_set_gain)(int bus, int addr, int gain); int (*sensor_get_exposure)(int bus, int addr, int *exposure); int (*sensor_get_gain)(int bus, int addr, int *gain); } sensor_t;接口名在不同 SDK 版本有出入但职责不会变。你在亿智、安霸、君正这些平台也会看到类似的结构这套「回调函数注册」的思路各家一致。工程上最省事的复用方式是直接复制 SDK 里已有的sony_imx335.c或sony_imx291.c作为模板改寄存器序列——IMX307 和 IMX335 同属 200 万级 STARVIS 系列不少操作流程相似比从零看手册快得多。3. 写进 Makefile 并编出 sensor 库最小可用的改动过程3.1 海思 SDK 里sensor 驱动代码该放在哪个目录拿到海思 hi35xx SDK 解压后不要满盘找「sensor」关键词。你需要的目录一般在mpp/component/isp/sensor/下或者mpp/sample/下的某个 sensor 子目录。老一点 SDK 是mpp/component/isp/sensor/新 SDK 把 sensor 驱动收敛到了统一目录同时维护一个sensor_list.c或sensor_comm.c来综合注册。我建议先跑一条命令看目录结构再动手find . -type d -name *sensor* 2/dev/null典型的输出会是这样./mpp/component/isp/sensor ./mpp/component/isp/sensor/sony_imx307 ./mpp/component/isp/sensor/sony_imx377 ./mpp/component/isp/sensor/coms307注意coms307这种目录它不是海思标准目录而是板级适配目录里面一般放的是板子相关的 GPIO、电源控制、MCLK 配置等。有人会把COm307理解为「Camera On Module 307」本质上就是个板级代号。看一下里面的文件就明白分工了。3.2 手写 sensor 目录下的 MakefileCC、CFLAGS 与产物类型海思 SDK 的 sensor 驱动用 Makefile 构建不是 CMake。原因放到下一小节说。这里先给出一个能用的 Makefile 模板适配 IMX307 或 IMX377 时只需要换源文件名# sensor 子目录 Makefile # 目标产物是动态库供 sample 进程运行时 dlopen LIB_NAME : libsns_imx307 SRCS : sony_imx307.c comm_sensor.c OBJS : $(SRCS:.c.o) # 交叉编译工具链——由 SDK 顶层变量传入 CC ? arm-himix100-linux-gcc AR ? arm-himix100-linux-ar CFLAGS -fPIC -Wall -O2 CFLAGS -I$(MW_INC) -I$(ISP_INC) # MW_INC 指向 mpp 公共头文件ISP_INC 指向 isp 头文件 all: $(LIB_NAME).so $(LIB_NAME).so: $(OBJS) $(CC) -shared -o $ $(OBJS) -lpthread %.o: %.c $(CC) $(CFLAGS) -c $ -o $ clean: rm -f $(OBJS) $(LIB_NAME).so这段 Makefile 的核心有两点-fPIC是生成位置无关代码供动态库使用MW_INC、ISP_INC这两条头文件路径要由外层 Makefile 传进来。海思 SDK 的顶层 Makefile 通常会定义MW_INC指向mpp/include你不需要自己写死绝对路径。编译命令在 sensor 目录下执行即可make clean make MW_INC/path/to/sdk/mpp/include ISP_INC/path/to/sdk/mpp/component/isp/include编出来的libsns_imx307.so会放在当前目录或lib目录。把它拷到板子的/usr/lib或 sample 运行目录sample 加载时按sensor_t里的名字去 dlopen。3.3 用 make 逐层构建而不是在 SDK 根目录一把梭海思 SDK 构建顺序是有依赖的先编 mpp 公共库和 isp 库再编 sensor 库最后编 sample。很多人刚拿到 SDK 就直接在根目录make -j8大概率报make: *** No rule to make target或者链接找不到 libisp因为底层库还没生成。我常用的构建姿势是分三步走# 第一步编译 mpp 底层生成 libisp、libhisi 等静态库 cd mpp make clean make -j8 # 第二步回到 sensor 目录单独编 sensor 库 cd component/isp/sensor/sony_imx307 make # 第三步编 sample确认能链接到刚才的 sensor 库 cd ../../../sample make这一步别急着加-j并行。第一次构建建议单线程跑输出日志里能看到每个模块的编译顺序和依赖是否就绪。等整条链路跑通过一次后面增量编译再上并行。3.4 为什么海思这套 SDK 只用 Makefile和 CMake 的差异在实际工程里的体现很多刚从 Linux 应用层转过来的朋友会问海思为什么不用 CMake这里不是海思守旧而是这套 SDK 的构建模型是「目录树 嵌套 Makefile」每个子目录只负责自己那一层产物靠顶层 Makefile 递归调度。CMake 的构建模型是「生成一套独立构建目录再在构建目录里编」——这套模型对海思这种有大量交叉编译变量、多平台宏、私有头文件依赖的场景反而需要额外处理入门成本更高。如果你一定要在某个子工程里用 CMake也不是不行但至少要处理好三件事交叉工具链的CMAKE_C_COMPILER、头文件依赖的include_directories、以及产物命名对齐。实际经验是在海思 SDK 里混入 CMake最常遇到的坑就是——你编出来的 sensor 库是.so但 sample 里加载时还要求同时导出sensor_t的符号表用 Makefile 时这些符号默认全导出了换 CMake 后容易受-fvisibilityhidden之类参数影响导致符号丢失。所以我的建议是sensor 目录的 Makefile 老老实实按 SDK 原有格式改不要另起炉灶。4. 让 IMX307 正常出图的 4 个必调参数MCLK、I2C、曝光步进与 DOL4.1 MCLK 与上电时序先有时钟再谈 I2C 通路sensor 不上电或没时钟I2C 是读不出东西的。IMX307 的 MCLK 主时钟常见配置是 27MHz也有用 37.125MHz 和 74.25MHz 的场景具体看 sensor 手册的时钟范围表。海思平台的 MCLK 由sample_comm_isp.c或板级 GPIO 初始化文件里配置。上电时序在 sensor 驱动里体现为sensor_power_on回调一般写法是static void sensor_power_on(int bus, int addr) { // 先拉低 reset让 sensor 处于复位状态 hi_gpio_set_direction(HI_GPIO_IDX_RESET, GPIO_DIR_OUT); hi_gpio_write(HI_GPIO_IDX_RESET, HI_GPIO_LOW); // 开启 sensor 供电 hi_pmu_enable_ldo(LDO_AVDD, 1); hi_pmu_enable_ldo(LDO_DOVDD, 1); hi_pmu_enable_ldo(LDO_DVDD, 1); // 供电稳定后延时再拉高 reset进入工作状态 usleep(5 * 1000); hi_gpio_write(HI_GPIO_IDX_RESET, HI_GPIO_HIGH); usleep(10 * 1000); }这段代码的顺序是「先复位后供电再释放复位」。如果把供电放在复位之后或者 reset 高低电平逻辑反了sensor 的 I2C 从设备是不会 ACK 的后面的寄存器读写全部失败。注意不同板子的 GPIO 极性可能不同有的板子 reset 是高有效复位需要把最后一步反过来。4.2 I2C 从地址与寄存器页别凭经验写死地址IMX307 和 IMX377 的 I2C 从地址不同而且同一颗 sensor 在不同 lanes 配置下地址可能还会变。不要相信「网上说 IMX307 地址是 0x34」这类结论你需要打开 sensor 手册看从地址设置引脚通常是XCE或I2C_Addr引脚再看手册的从地址表。驱动里常见的写法是允许外部传入地址static int sensor_i2c_read(int bus, int addr, unsigned int reg, unsigned int *value) { // 海思 i2c 控制接口先写寄存器地址再读数据 int ret hi_i2c_write(bus, addr, reg, I2C_LEN_16, NULL, 0); if (ret ! 0) { return ret; } ret hi_i2c_read(bus, addr, reg, I2C_LEN_16, value, I2C_LEN_8); return ret; }调试时先用一条命令验证通路别急着写整个驱动。最常见的手段是在板子上用海思自带的 i2c 工具读 sensor 芯片 ID 寄存器i2c_read 2 0x34 0x0016 2这条命令的含义是从 I2C 总线 2 上的地址 0x34 读寄存器 0x0016长度为 2 字节。IMX307 的型号 ID 寄存器如果读出来是期望值 0x0307实际值以手册为准就说明通路没问题可以继续写初始化序列。如果返回 0xff 或 I2C ACK 超时先从 MCLK 和电源查起不要怀疑是寄存器地址写错。4.3 曝光与增益换算AE 算法和 sensor 驱动之间最容易翻车的接口ISP 的 AE 算法和 sensor 驱动之间曝光和增益的单位必须一致。海思 AE 的曝光单位是 line行增益单位是倍率乘以某个精度值。IMX307 的曝光步进是 1 line但它的最大曝光行数受帧率和 PLL 配置约束不是无限大。如果你发现 AE 刚开始收敛就过曝然后闪烁八成是 sensor 驱动里设置的曝光值超出了 sensor 允许的最大行数。更好的写法是曝光回调里顺手做钳位static int sensor_set_exposure(int bus, int addr, int exposure) { int max_line 0; int reg_value 0; // 根据当前帧率计算最大曝光行数 max_line (int)(fps * 1000 / 30); // 示例30fps 下按 sensor 手册折算 if (exposure max_line) { exposure max_line; } if (exposure 2) { exposure 2; } // 写入 IMX307 曝光寄存器示例地址实际以手册为准 reg_value exposure 0xFFFF; sensor_i2c_write(bus, addr, 0x0001, I2C_LEN_16, reg_value, I2C_LEN_16); return 0; }增益同理。IMX307 的增益分为模拟增益和数字增益模拟增益一般直接映射到 sensor 的 GAIN 寄存器数字增益在 ISP 侧做。不要把两段增益全部塞给 sensor 寄存器否则高增益下噪声会被二次放大。4.4 DOL HDR 的长短帧配置IMX307 的优势与坑IMX307 支持 DOLDigital Overlap宽动态模式原理是让 sensor 在短曝光和长曝光各出一帧ISP 再将两帧合成为高动态图像。这个功能是这颗 sensor 的卖点但适配坑也多。DOL 模式下ISP 需要知道哪一路是长帧、哪一路是短帧并且要求两条链路的曝光比例在一个合理的范围内。实际调参时我建议手动设一组曝光比比如长帧 16 毫秒、短帧 2 毫秒先看合成效果再交给 AE 自动跑。如果你的板子在开启 DOL 后画面出现半幅断裂或闪烁优先检查长短帧的时序对齐配置而不是 ISP 的合成强度参数。// DOL 模式下设置长短曝光的示例伪代码 sensor_set_dol_frame(bus, addr, long_exp, short_exp); // long_exp 和 short_exp 单位都是 ms内部换算成行数 // 注意海思 ISP 的 WDR 模式需要和 sensor 的 DOL 模式严格对应海思 ISP 里 WDR 有 Mode2 和 Mode3 等配置你必须在sample_comm_isp.c里把 WDR 模式和 sensor 的实际输出模式设为一致。两边对不上画面要么过曝要么暗部死黑。5. 避坑IMX307/377 适配中最常见的 5 类问题与排查过程5.1make找不到 Makefile或报了makefile:18: libs错误现象在 SDK 某个子目录执行make终端提示make: *** No rule to make target或Nothing to be done有时报错行号直接指向 Makefile 的libs目标。原因这不是 Makefile 写错了而是你站错了目录。海思 SDK 的 Makefile 是分层递归的必须在 sensor 库所在目录执行 make或者通过顶层的make component之类目标间接进入。另外海思早期 SDK 的 Makefile 里libs是公共目标如果你在根目录直接make libs它只会编公共库不会编 sample造成 sample 里libs依赖目标接不上。解决先pwd确认目录层级再ls看当前目录有没有 Makefile然后按 3.3 的步骤分层构建。我在基于 Makefile 的嵌入式 SDK 里踩过太多次这种坑现在习惯是先跑make help看看定义了哪些合法目标避免拿根目录目标名硬套子目录执行逻辑。5.2 上电不按手册时序sensor ID 怎么都读不出来现象编译链接全部通过但板子启动后 I2C 读 sensor 芯片 ID 返回0xff或者读寄存器超时。原因sensor 上电时序不对。常见的有三类——GPIO 方向没设置为输出reset 拉高后被复用为其他片选引脚供电压差不对导致 sensor 没进工作模式。解决用示波器量 MCLK 波形确认有 27MHz 方波输出再查复位引脚电平极性最后查电源轨电压。我在实际调试中遇到过 IMX377 被系统默认 GPIO 配置拉死的情况现象就是 sensor 完全不应答。另外别忘了把 I2C 总线地址从 0x34 这种 8 位写法换算成 7 位有些 SDK 的 I2C 接口收的是 7 位地址换算错了同样通信失败。5.3 编译过了但 venc 起不来日志停在 ISP init现象sample_venc 启动后日志打印到[ISP] init附近就停住或者直接报sensor init failed。过一会儿进程崩溃。原因多半是 sensor 驱动里初始化寄存器序列太长或太慢触发了 watchdog另一种可能是sensor_t结构体中初始化函数指针是空的dlopen 拿到库后符号解析失败流程没往下走。解决在sensor_init回调里第一行加打印确认库被加载进来了。然后把初始化寄存器流分批注释用二分法定位是哪个寄存器初始化挂住。IMX307 配置序列通常有几十条寄存器不要一条条去猜优先检查和时钟分频、PLL 相关的寄存器地址这类写错会卡死 sensor。5.4 画面整体偏绿或偏红AWB 不收敛现象出图正常但色彩明显不对白色物体拍出来偏色而且长时间不收敛。原因sensor 初始化寄存器流里把 R、Gr、Gb、B 的增益寄存器设置值不合适ISP 的 AWB 无法用默认参考点收敛到正确色温。有时是新板子 IR-CUT 颜色不同但驱动里的白平衡参考还是从旧板子继承来的。解决先用标准光源照白板让 ISP 做一次静态 AWB 校准把算出的 RGB 增益写回 sensor 初始化序列末尾作为默认增益。再把sample_comm_isp.c里sns_type注册顺序核实一遍——如果 IMX307 和 IMX377 共用同一个 ISP 通道确认没有串到 IMX377 的 AWB 参数上去。5.5 烧录后新 sensor 生效但旧 sensor 的注册表冲突现象同时适配了 IMX307 和 IMX377 的板子烧录后只有其中一个能出图另一个启动报sensor type mismatch。原因海思 sample 的sensor_t注册表是数组结构两个 sensor 如果主型号枚举值相同后面注册的会覆盖前面。COm307这种板级适配目录里如果写死了 sensor ID 判断逻辑也会导致运行起来只认其中一颗。解决在sample_comm_isp.c里核对两个 sensor 的sns_type枚举确实不同。如果平台只允许一个 ISP sensor 入口就要通过 GPIO 或 I2C 探测来区分当前硬件挂的是哪一颗。最土的办法是加打印注册时打印 sensor 名字启动时一眼就能看清是谁被加载了。6. 用海思烧录工具跑通整条链路从编译产物到板端验证6.1 烧录前要确认三件事全志、瑞芯微、海思都有各自的烧录工具海思的烧录工具一般叫 HiTool通过串口或网口把镜像烧进 flash。烧录前我习惯确认三件事编译出来的libsns_imx307.so是否已被打包进根文件系统镜像sensor 驱动文件名和sensor_t里name字段是否一致sample 程序运行目录下有没有正确的libsensor软链接。少做一步都会出现白屏或灰屏。特别是.so打包镜像后因为根文件系统是 squashfs 或者 jffs2文件权限和符号链接容易丢烧录进去后 dlopen 找不到库。我的做法是烧录后启动完第一件事就是进板子执行ls -l /usr/lib/libsns*把文件存在性和链接都确认一遍再跑 sample。6.2 板端验证的命令序列烧录完成后串口登录板子按下面的顺序验证整条链路# 1. 确认 sensor 库存在 ls -l /usr/lib/libsns_imx307.so # 2. 确认 I2C 通路读取 sensor 型号 ID i2c_read 2 0x34 0x0016 2 # 3. 确认 ISP 识别到 sensor cat /proc/isp/status # 4. 运行 venc sample 输出视频流 ./sample_venc -i 0 -o /tmp/test.h264第 2 步是整条链路里最关键的一环——如果 sensor ID 读不出来后面 ISP 和 sample 跑起来也看不到图像。ID 读出来后再跑 sample用 VLC 或其他播放器打开test.h264检查画面颜色和亮度。/proc/isp/status是海思实现的 ISP 调试节点能看到当前曝光时间、增益、帧率这些数据能帮你判断 3A 是否在正常收敛。我个人的习惯是第一次跑通 IMX307 后用一条命令记下关键调试参数包括 I2C 总线号、从地址、曝光行数和 AE 目标亮度。下次换 IMX377 时直接对照这份记录去查差异比重新翻手册快得多。这套把 sensor 适配、Makefile 构建和板端验证串起来的流程多走两遍你也会有自己的检查清单——希望帮到你。本文还有配套的精品资源点击获取
返回列表