
简介这份资源是面向嵌入式Linux驱动开发者的Sony IMX335传感器驱动适配代码针对海思Hi3559高性能视频处理平台定制解决IMX335在Hi3559系统上无法正常初始化、取流与图像处理的问题。包内共6个文件以C源码与头文件为核心包含imx335_cmos.c、imx335_sensor_ctl.c及对应头文件另有Makefile构建脚本和两个编译生成的.o目标文件压缩包约362KB结构精简便于直接集成到V4L2驱动框架中编译验证。驱动已针对Hi3559的接口协议、时序控制与电源管理完成适配调试功能验证无误可帮助读者理解CMOS传感器驱动的设备初始化、数据传输与错误处理流程快速完成图像采集链路的搭建与排错。目前已有1072人学习下载适合从事安防监控、无人机或工业相机开发的中高级工程师参考借鉴。1. 拿到 sony_imx335 driver 适配 hi3559 的源码包先别急着 make如果你正在调 hi3559 平台上的 IMX335 摄像头大概率经历过这样的场景sensor 上电了I2C 能读到 ID但 /dev/video0 死活出不了图dmesg 里一堆 i2c timeout 或者 mipi 报错。这时候你需要的不是从头撸一个驱动而是一份已经在 hi3559 上跑通过的参考实现。手上这个 sony_imx335 hi3559.zip 就是干这个的——它包含 imx335_cmos.c、imx335_sensor_ctl.c、imx335_cmos_ex.h 以及对应的 Makefile是海思 MPP 框架下 sensor 驱动的标准骨架编译产物是 imx335_cmos.o 和 imx335_sensor_ctl.o。适合谁用正在 hi3559 系列hi3559A / hi3559C / hi3559V200上做多路摄像头接入的嵌入式工程师尤其是需要把 IMX335 这颗 500 万像素 sensor 跑起来、但又不想从 sample 代码一行行改的人。这篇笔记就按我实际拆包、编译、上板、出图的顺序把关键参数和踩过的坑一次讲清。2. 拆开源码包hi3559 sensor 驱动的文件分工与调用链2.1 三个核心文件各自管什么海思平台的 sensor 驱动不像 Linux 主线那样走 V4L2 完整框架而是 MPPMedia Process Platform自己的一套注册机制。你拿到的这几个文件分工非常明确imx335_cmos.c驱动主体。负责 sensor 的注册、初始化、分辨率切换、帧率配置、镜像翻转等。里面会实现一个sensor_obj结构体挂到 MPP 的 sensor 链表上。imx335_sensor_ctl.c底层寄存器操作。I2C 读写、上电时序、复位、时钟使能都在这。它不关心上层业务只负责把寄存器值写进去、读出来。imx335_cmos_ex.h对外暴露的宏和结构体定义。比如IMX335_I2C_ADDR、IMX335_WIDTH、IMX335_HEIGHT、IMX335_MIPI_ATTR这些都在这里改。Makefile交叉编译脚本。指定工具链、内核头文件路径、输出 .o 文件。调用链是这样的MPP 启动时通过sensor_register_callback把 imx335 的sensor_obj注册进去然后 ISP 初始化时调用sensor_initsensor_init再调imx335_sensor_ctl.c里的 I2C 写序列完成上电和寄存器配置。出图失败时你要顺着这条链一段段查。2.2 先确认你的 SDK 版本和 sensor 类型宏在动任何代码之前先做一件事确认你用的 hi3559 SDK 版本。不同版本的 MPP 接口有差异尤其是ISP_SNS_OBJ_S结构体的成员。常见做法是去 SDK 的mpp/sample/common/下看sample_comm_isp.c里怎么注册 sensor 的对照你的 imx335_cmos.c 是否匹配。然后检查imx335_cmos_ex.h里的 sensor 类型宏。hi3559 SDK 通常要求你在sensor_type里选一个比如// imx335_cmos_ex.h 中常见的宏定义 #define IMX335_I2C_ADDR 0x34 // 7bit 地址实际写寄存器时左移一位 #define IMX335_WIDTH 2592 // 有效像素宽 #define IMX335_HEIGHT 1944 // 有效像素高 #define IMX335_MIPI_LANE 4 // MIPI 通道数hi3559 常用 4 lane #define IMX335_MIPI_CLK 891 // MIPI 时钟频率单位 Mbps按实际晶振算 #define IMX335_FRAME_RATE 30 // 默认帧率这几个值必须和你的硬件一致。I2C 地址错了连 ID 都读不到MIPI lane 数错了出图花屏或者直接没图MIPI 时钟错了图像会撕裂或者 ISP 报错。我一般会先拿示波器量一下 MIPI 时钟引脚确认实际频率再反推寄存器配置。2.3 Makefile 里的交叉编译参数怎么改Makefile 是这份资源里最容易被忽略、但最容易翻车的地方。它通常长这样# 交叉编译工具链按你的实际路径改 CROSS_COMPILE arm-himix200-linux- CC $(CROSS_COMPILE)gcc # 内核头文件路径必须指向你当前使用的 SDK 内核 KERNEL_DIR /home/xxx/hi3559_sdk/osdrv/linux-4.9.y # MPP 头文件路径 MPP_DIR /home/xxx/hi3559_sdk/mpp # 编译选项 CFLAGS -Wall -O2 -I$(KERNEL_DIR)/include -I$(MPP_DIR)/include # 目标文件 obj-m imx335_cmos.o obj-m imx335_sensor_ctl.o all: make -C $(KERNEL_DIR) M$(PWD) modules clean: make -C $(KERNEL_DIR) M$(PWD) clean这里有几个参数必须改CROSS_COMPILE要换成你 SDK 里的工具链前缀KERNEL_DIR要指向你实际编译内核时用的源码目录MPP_DIR要指向 MPP 的 include 目录。改完执行make如果报xxx.h: No such file or directory八成是路径没指对。编译成功后会生成imx335_cmos.ko和imx335_sensor_ctl.ko用insmod加载。提示有些 SDK 版本要求把 sensor 驱动直接编进内核而不是做成 .ko。这时候你需要把 .c 文件放到内核的drivers/media/platform/下改 Kconfig 和 Makefile。具体看你的 SDK 文档。3. 上板调试I2C 通信、MIPI 配置与出图验证3.1 I2C 地址确认与读写测试驱动加载后第一件事是确认 I2C 能通。IMX335 的 7bit 地址通常是 0x34但有些模组会通过 SID 引脚改成 0x35 或 0x36。上板后先跑# 查看 i2c 总线上的设备 i2cdetect -y 0 # 读 IMX335 的 Chip ID 寄存器地址 0x3000 和 0x3001 i2cget -y 0 0x34 0x3000 w正常应该读到0x33 0x54IMX335 的 Chip ID。如果读不到先查硬件SID 引脚电平、上拉电阻、电源是否正常。软件层面查imx335_sensor_ctl.c里的imx335_i2c_init函数确认总线号、地址、速率配置对不对。常见错误是总线号写死成 0但实际接在 1 上。3.2 MIPI 参数配置与 ISP 对接I2C 通了之后下一步是 MIPI 和 ISP。hi3559 的 MPP 里sensor 的 MIPI 属性通过combo_dev_attr配置。在imx335_cmos.c的sensor_init里你会看到类似这样的代码// 配置 MIPI 属性 combo_dev_attr_t mipi_attr; mipi_attr.input_mode INPUT_MODE_MIPI; mipi_attr.data_rate MIPI_DATA_RATE_X1; mipi_attr.img_rect.width IMX335_WIDTH; mipi_attr.img_rect.height IMX335_HEIGHT; mipi_attr.mipi_attr.lane_id[0] 0; mipi_attr.mipi_attr.lane_id[1] 1; mipi_attr.mipi_attr.lane_id[2] 2; mipi_attr.mipi_attr.lane_id[3] -1; // 4 lane 时最后一 lane 不用 mipi_attr.mipi_attr.output_rect.x 0; mipi_attr.mipi_attr.output_rect.y 0; mipi_attr.mipi_attr.output_rect.width IMX335_WIDTH; mipi_attr.mipi_attr.output_rect.height IMX335_HEIGHT; mipi_attr.mipi_attr.output_rect.w IMX335_WIDTH; mipi_attr.mipi_attr.output_rect.h IMX335_HEIGHT;这里lane_id的顺序必须和硬件走线一致。我遇到过一块板子lane 顺序接反了结果图像上半部分正常、下半部分绿屏。后来把lane_id[0]和lane_id[1]对调才解决。另外data_rate要选对IMX335 在 4 lane 下通常用 X12 lane 下用 X2选错了 ISP 会报mipi error。3.3 出图验证从 /dev/video0 抓一帧驱动加载、ISP 初始化完成后用 sample 里的sample_venc或者sample_vio跑一遍。如果一切正常你会看到类似这样的日志[ISP] sensor imx335 init success [ISP] mipi lane 0-3 locked [VPSS] chn 0 start success然后抓一帧图# 用 sample_vio 抓图输出到 /tmp/out.yuv ./sample_vio 0 1 # 把 YUV 转成 JPG 看效果 ffmpeg -f rawvideo -pix_fmt nv12 -s 2592x1944 -i /tmp/out.yuv -frames:v 1 /tmp/out.jpg如果图是黑的先查曝光和增益寄存器如果图是绿的查 MIPI lane 顺序和 ISP 的 Bayer 格式配置如果图有横条纹查 MIPI 时钟频率和电源纹波。这些在imx335_sensor_ctl.c的寄存器序列里都能找到对应的调整点。4. 避坑记录IMX335 在 hi3559 上最容易翻车的五个点4.1 现象i2cdetect 能扫到地址但读 Chip ID 返回 0xFF原因I2C 地址是 7bit但i2cget默认按 8bit 处理或者 sensor 的 SID 引脚电平不对。IMX335 的地址由 SID 引脚决定悬空、接地、接 VCC 对应三个不同地址。解决先用万用表量 SID 引脚电平确认实际地址。然后在imx335_sensor_ctl.c里把IMX335_I2C_ADDR改成对应的 7bit 地址。注意海思的 I2C 读写函数通常要求传入 8bit 地址7bit 左移一位别搞混。4.2 现象驱动加载成功但 ISP 初始化时报 sensor not found原因MPP 的 sensor 注册链表里没有你的 imx335或者注册的 sensor 名字和sensor_type不匹配。hi3559 SDK 里sensor_register_callback注册时用的名字必须和sample_comm_isp.c里sensor_type枚举一致。解决检查imx335_cmos.c里sensor_obj.sensor_name的值确保和 SDK 里定义的一致。常见做法是直接搜 SDK 里SENSOR_TYPE_IMX335这个宏看它对应的字符串是什么然后改成一样的。4.3 现象出图花屏上半部分正常下半部分绿原因MIPI lane 顺序和硬件走线不一致。hi3559 的 MIPI 接收器对 lane 顺序敏感尤其是 4 lane 模式下lane0 和 lane1 对调会导致数据错位。解决在imx335_cmos.c的 MIPI 配置里调整lane_id数组的顺序。如果硬件是 lane0→lane2、lane1→lane3 这种交叉走线软件里也要对应改。我一般会先按 0,1,2,3 试一遍不行再试 1,0,3,2最多试四种组合就能找到对的。4.4 现象图像有横条纹或撕裂原因MIPI 时钟频率和 sensor 实际输出不匹配或者电源纹波太大。IMX335 在 4 lane 下 MIPI 时钟通常是 891Mbps但有些模组因为晶振精度问题会偏。解决先用示波器量 MIPI 时钟引脚的实际频率然后调整imx335_cmos_ex.h里的IMX335_MIPI_CLK值。如果频率没问题查电源——IMX335 对 AVDD 和 DVDD 的纹波很敏感建议在电源引脚附近加 10uF 和 0.1uF 电容。4.5 现象编译报错 implicit declaration of function sensor_register_callback原因Makefile 里的 MPP 头文件路径没指对或者 SDK 版本不匹配。不同版本的 hi3559 SDKsensor_register_callback的声明位置可能不同。解决在 SDK 里搜sensor_register_callback的定义找到它所在的头文件然后把该头文件所在目录加到 Makefile 的CFLAGS里。如果 SDK 版本太老没有这个函数那就得用老的注册方式具体看 SDK 里的 sample 代码。5. 进阶技巧用 sensor_ctl 做寄存器级调试与多路复用5.1 直接读写寄存器定位问题imx335_sensor_ctl.c里的 I2C 读写函数不只是初始化时用调试阶段也可以直接调。我习惯在驱动里加一个 debug 节点通过ioctl或者proc文件系统暴露寄存器读写接口。比如// 在 imx335_sensor_ctl.c 里加一个简单的 debug 函数 int imx335_read_reg(unsigned int reg_addr, unsigned int *value) { unsigned int buf[2]; buf[0] reg_addr; // 调用海思的 I2C 读接口具体函数名看 SDK if (hi_i2c_read(IMX335_I2C_ADDR, buf, 2, value, 1) ! 0) { printk(imx335 read reg 0x%x failed\n, reg_addr); return -1; } return 0; }然后通过insmod参数或者proc文件触发。这样当图像异常时你可以直接读曝光、增益、帧率相关的寄存器看值对不对。比如读0x3A00曝光高字节和0x3A01曝光低字节确认自动曝光有没有生效。5.2 多路 IMX335 复用时的注意事项hi3559 支持多路 sensor 同时接入但 IMX335 多路复用时有两个坑一是 I2C 地址冲突二是 MIPI lane 资源分配。I2C 地址冲突可以通过 SID 引脚解决但 MIPI lane 是硬件固定的不能两路共用同一组 lane。常见做法是路数I2C 地址MIPI lane备注路 10x34lane 0-3主摄路 20x35lane 4-7副摄需确认 hi3559 是否支持路 30x36lane 8-11部分型号支持如果你的 hi3559 型号不支持这么多 lane那就只能分时复用或者降低分辨率用 2 lane 模式。具体看芯片手册的 MIPI 通道数。5.3 验证驱动稳定性的一个习惯从那以后我每次调完 sensor 驱动都会强制走一遍 24 小时烤机连续抓图、切换分辨率、开关流看有没有内存泄漏或者 I2C 超时。具体命令是# 循环抓图 1000 次每次间隔 1 秒 for i in $(seq 1 1000); do ./sample_vio 0 1 sleep 1 done # 同时监控 dmesg 里的错误 dmesg -w | grep -i error\|timeout\|fail如果 1000 次里有一次失败就说明驱动有稳定性问题通常是 I2C 锁没释放或者 MIPI 中断没清。这时候回去查imx335_sensor_ctl.c里的错误处理分支看有没有漏掉mutex_unlock或者free_irq。希望帮到你。本文还有配套的精品资源点击获取