ARTICLE DETAIL

资讯详情

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

IMX335驱动适配Hi3559:从源码到出图的完整指南

IMX335驱动适配Hi3559:从源码到出图的完整指南 简介这份资源面向嵌入式Linux驱动开发者与海思平台音视频工程师提供Sony IMX335图像传感器在Hi3559芯片上的适配驱动代码解决传感器与主控之间接口协议、时序控制、电源管理等兼容性问题适用于安防监控、智能分析、工业相机等场景的二次开发与移植参考。压缩包共6个文件约362KB包含2个C源文件、2个编译生成的.o目标文件、1个Makefile构建脚本和1个头文件覆盖传感器寄存器配置、CMOS驱动逻辑与编译规则结构紧凑便于直接集成到V4L2框架工程中。目前已有1069人学习下载说明该适配方案在同类平台移植中具备一定参考价值。读者可据此了解IMX335在Hi3559上的初始化流程、数据传输机制与错误处理思路并借助已验证的驱动代码缩短调试周期快速完成传感器点亮与图像采集验证。1. IMX335 驱动适配 Hi3559从源码包到出图的完整路径手里拿到一个sony_imx335 hi3559.zip解压后是imx335_cmos.c、imx335_sensor_ctl.c、imx335_cmos_ex.h、Makefile和几个.o文件很多人第一反应是「这不就是海思 SDK 里 sensor 目录下那套东西吗」。但真正把它塞进 Hi3559 的工程里跑起来才会发现事情没那么简单——I2C 地址对不上、MIPI 时序差一拍、曝光接口挂错 ISP 通道任何一个环节翻车VI 通道就是黑屏或者花屏。这份资源的价值在于它把 Sony IMX335 在 Hi3559 平台上的 sensor 驱动层代码整理成了一个可直接对照的参考实现包含寄存器初始化序列、cmos 参数结构体和 sensor 控制接口。适合正在做安防 IPC、工业相机、多路视频采集的嵌入式工程师尤其是手上已经有 Hi3559 开发板、需要把 IMX335 点亮的人。下面按「这份代码是什么 → 怎么编进去 → 怎么调出图 → 坑在哪」的顺序拆一遍。2. 拆解驱动包IMX335 在 Hi3559 上的 sensor 层到底管什么2.1 海思 sensor 驱动的三层结构海思平台的摄像头驱动不是一个大文件搞定它分三层sensor 层、ISP 层、VI 层。这份资源里的文件全部属于 sensor 层具体来说imx335_cmos.c实现 sensor 的注册、初始化、曝光/增益设置、帧率控制等回调函数是驱动的主体。imx335_sensor_ctl.c封装 I2C 读写和 sensor 寄存器操作负责把具体的寄存器值写进 IMX335。imx335_cmos_ex.h定义 sensor 的寄存器地址宏、结构体、以及不同分辨率模式下的参数。Makefile编译规则把上面几个.c编成.o最终链接进海思的libsns_imx335.a或直接编入内核模块。理解这个分层很关键。很多人改驱动时直接在imx335_cmos.c里硬编码 I2C 地址结果换一块板子就挂就是因为没搞清楚sensor_ctl和cmos的职责边界。常见做法是I2C 地址、复位引脚、时钟配置放在sensor_ctl里曝光增益的换算逻辑放在cmos里寄存器表放在cmos_ex.h里。2.2 IMX335 的关键参数与 Hi3559 的匹配点IMX335 是一颗 1/2.8 英寸的 CMOS最高 5120×384030fpsMIPI CSI-2 接口4 lane 输出。Hi3559 的 MIPI 接收端支持 4 lane但需要确认几个参数参数项IMX335 典型值Hi3559 侧配置位置MIPI lane 数4 lanesensor_ctl.c中 MIPI_ATTR输入时钟24MHzhi3559_vo或hi3559_vi的 clk 配置I2C 地址0x347bitsensor_ctl.c中 I2C_ADDR数据格式RAW10 / RAW12cmos.c中stSnsImageMode最大帧率30fps5Mcmos_ex.h中stSnsExp结构这里最容易出问题的是 I2C 地址。IMX335 的 7bit 地址是 0x34但海思的 I2C 读写函数通常要求传 8bit 地址也就是 0x68。如果你在sensor_ctl.c里看到I2C_ADDR 0x34而实际读写用的是0x68不要慌这是海思的惯例——底层驱动会自动左移一位。但如果你自己写了一个裸机 I2C 测试程序就得用 0x68。2.3 寄存器初始化序列的读取方式imx335_cmos_ex.h里通常有一个很大的数组类似static const unsigned int imx335_init_regs[] { 0x3000, 0x01, 0x3001, 0x00, 0x3002, 0x01, // ... 几百行 };这个数组就是 IMX335 的上电初始化序列。不同分辨率、不同帧率对应的序列不一样有的驱动包里会按模式拆成多个数组比如imx335_5m_30fps[]、imx335_4m_30fps[]。拿到这份资源后第一件事是确认你需要的模式在不在里面。如果只有 5M 序列而你要跑 1080P就得自己从 Sony 的 datasheet 里补寄存器或者用海思自带的sensor_cfg工具生成。提示不要直接改imx335_cmos_ex.h里的寄存器值来「试」。IMX335 的 PLL 配置和 MIPI 时序是联动的改一个寄存器可能导致整个链路不输出。正确做法是先用示波器确认 MIPI 时钟有没有出来再查 I2C 通信是否正常。3. 把驱动编进 Hi3559 工程Makefile 与交叉编译链配置3.1 确认交叉编译工具链Hi3559 的 SDK 通常自带arm-himix200-linux-或aarch64-himix100-linux-工具链。先确认你的环境变量echo $PATH | grep himix which arm-himix200-linux-gcc如果输出为空说明工具链没装或者没加进 PATH。海思的 SDK 一般在osdrv/tools/pc/或osdrv/tools/board/下有工具链安装脚本跑一遍source就行。这一步不做后面make会直接报arm-himix200-linux-gcc: command not found。3.2 修改 Makefile 适配你的 SDK 路径资源里的Makefile大概率是参考模板不能直接make。打开后重点看三个变量CROSS_COMPILE ? arm-himix200-linux- SDK_DIR ? /home/xxx/Hi3559V200_SDK SENSOR_DIR ? $(SDK_DIR)/mpp/component/isp/sensorCROSS_COMPILE要和你的工具链前缀一致。SDK_DIR指向你的海思 SDK 根目录。SENSOR_DIR是 sensor 驱动最终要放的位置。常见做法是先把整个sony_imx335文件夹拷到$(SDK_DIR)/mpp/component/isp/sensor/下再改 Makefile 里的相对路径。改完后执行make clean make如果编译通过会在当前目录生成imx335_cmos.o、imx335_sensor_ctl.o以及最终的libsns_imx335.a。如果报错imx335_cmos_ex.h: No such file or directory检查-I包含路径有没有把当前目录加进去。3.3 把 sensor 注册进 ISP 的 sensor 列表光编出.a文件还不够Hi3559 的 ISP 启动时要遍历一个 sensor 列表找到匹配的 sensor 类型才会加载驱动。这个列表通常在mpp/component/isp/sensor/sensor_list.c或类似文件里。你需要加一行extern SENSOR_EXPORT_S g_sns_imx335_obj; // 在 sensor_list 数组里加 { SENSOR_TYPE_IMX335, g_sns_imx335_obj },SENSOR_TYPE_IMX335这个宏要在hi_sensor.h或sensor_define.h里定义值不能和已有的冲突。有的 SDK 版本已经预留了 IMX335 的类型号直接搜IMX335就能找到。如果没有自己加一个比如#define SENSOR_TYPE_IMX335 0x40但要确认这个值没被其他 sensor 占用。3.4 重新编译整个 MPP 并烧录sensor 列表改动后不能只重编 sensor 目录要回到 MPP 根目录重新编cd $(SDK_DIR)/mpp make clean make -j8编完后把生成的ko文件和lib推到板子上。常见做法是用nfs挂载根文件系统直接替换板子上的libsns_imx335.a和hi3559_isp.ko。如果板子跑的是 squashfs 只读文件系统就得重新打包固件烧录。注意替换ko后一定要rmmod旧的 ISP 模块再insmod新的否则内核里跑的还是旧驱动。lsmod | grep isp确认模块版本号变了才算生效。4. 调出第一帧图像VI 通道配置与 I2C 时序排查4.1 用 sample_vi 快速验证 sensor 是否出图海思 SDK 里自带sample_vi例程这是验证 sensor 驱动最直接的工具。在板子上跑./sample_vi 0 1参数0表示 VI 设备号1表示启用 ISP 的 sensor 0。如果驱动正常终端会打印帧率统计类似vi frame rate: 30.00。如果一直打印vi get frame timeout说明 VI 没收到数据问题出在 sensor 初始化或 MIPI 链路上。先查 I2Ci2c_read 0x68 0x3000 2这条命令读 IMX335 的 0x3000 寄存器正常应该返回0x01。如果返回0xff或超时说明 I2C 没通。检查三件事sensor 的电源有没有上1.2V 核心、1.8V IO、2.8V 模拟、复位引脚有没有拉高、I2C 上拉电阻有没有焊。4.2 MIPI 时序的示波器验证点I2C 通了但 VI 还是没帧大概率是 MIPI 时序问题。用示波器测三个点MIPI CLK 差分对应该有 400MHz 左右的差分时钟取决于 IMX335 的 PLL 配置。MIPI DATA0 差分对在 CLK 稳定后应该有数据突发。sensor 的 XVS/FSIN 引脚应该有 30Hz 的帧同步信号。如果 CLK 没有查imx335_cmos_ex.h里的 PLL 寄存器。IMX335 的 PLL 配置涉及 0x3030 到 0x3035 几个寄存器常见值是0x30300x02、0x30310x00、0x30320x00、0x30330x00、0x30340x00、0x30350x00但具体值取决于输入时钟是 24MHz 还是 27MHz。如果你板子上的晶振不是 24MHz这组值必须改。4.3 曝光和增益的接口对接出图之后下一步是调曝光。海思的 ISP 通过cmos.c里的pfn_cmos_set_exposure回调控制 sensor。这个回调的入参是unsigned int exposure和unsigned int gain但 IMX335 的寄存器不是直接写这两个值需要换算static int imx335_set_exposure(VI_PIPE vi_pipe, unsigned int exposure, unsigned int gain) { unsigned int exp_reg exposure / 2; // IMX335 一行对应 2 个时钟 unsigned int gain_reg gain_to_reg(gain); // 查表或公式换算 imx335_write_reg(0x3050, exp_reg 16); imx335_write_reg(0x3051, exp_reg 0xffff); imx335_write_reg(0x3058, gain_reg); return 0; }这里的坑是不同驱动包里exposure的单位可能不一样。有的用「行数」有的用「微秒」。如果你发现调曝光时画面亮度变化不对先确认cmos_ex.h里stSnsExp结构体的u32LinesPer500ms和u32Fps有没有配对。常见做法是拿一个已知亮度的灰卡从最小曝光逐步加到最大看画面亮度是否线性变化。如果不是就是换算公式错了。4.4 多路 IMX335 的 I2C 地址冲突处理Hi3559 支持多路 sensor 同时输入但 IMX335 的 I2C 地址是固定的 0x34两路接同一个 I2C 总线就会冲突。解决办法有两个一是用 I2C 多路复用器如 PCA9548每路 sensor 挂在不同通道二是把其中一路的 I2C 地址改掉——IMX335 支持通过 0x300A 寄存器改地址但需要先给 sensor 上电、在默认地址下写改址寄存器、再复位。第二种方法时序很紧容易翻车我一般推荐第一种。提示多路场景下每路 sensor 的sensor_ctl.c里的 I2C 地址要改成复用器对应的通道地址而不是 sensor 本身的 0x34。比如 PCA9548 的通道 0 对应 0x70通道 1 对应 0x71写寄存器前要先切通道。5. 避坑与排查IMX335 在 Hi3559 上最容易翻车的五个点5.1 现象I2C 能读到 ID 但 VI 无帧原因IMX335 的 ID 寄存器0x3000-0x3002在 sensor 上电后就能读不需要 MIPI 链路工作。所以 I2C 通只说明电源和 I2C 正常不代表 MIPI 配置对了。解决先查imx335_cmos_ex.h里的 MIPI lane 数是否和硬件一致。有的驱动包默认写 4 lane但你的板子只接了 2 lane这时候要改sensor_ctl.c里的MIPI_LANE_NUM和cmos_ex.h里的stSnsImageMode的 lane 配置。改完重新编libsns_imx335.a并替换。5.2 现象出图但颜色偏绿或偏紫原因ISP 的 AWB 没收敛或者 sensor 输出的 Bayer 顺序和 ISP 配置不匹配。IMX335 默认输出 Bayer RGGB但有的驱动包里cmos.c的enBayer写成了 BGGR。解决在imx335_cmos.c里找到stSnsImageMode结构体确认enBayer的值。海思的定义是BAYER_RGGB、BAYER_BGGR、BAYER_GRBG、BAYER_GBRG四种。如果颜色不对先改这个再跑sample_vi看。如果改了还是偏色检查 ISP 的 AWB 算法有没有使能在sample_vi的配置文件里把bAwbEn设为HI_TRUE。5.3 现象帧率只有 15fps 而不是 30fps原因IMX335 的帧率由 VMAX 和 HMAX 决定而 VMAX 又和曝光时间联动。如果曝光时间设得太大VMAX 会自动拉长帧率就掉下来了。解决查cmos_ex.h里的u32Vmax和u32Hmax。5M30fps 的典型值是 VMAX0x0A20、HMAX0x04B0。如果 VMAX 被改大了帧率必然掉。另外确认u32LinesPer500ms的值这个值不对会导致曝光换算错误间接影响帧率。5.4 现象编译通过但 insmod 时报 undefined symbol原因libsns_imx335.a里引用了海思 ISP 的符号但链接顺序不对或者hi3559_isp.ko的版本和 sensor 库不匹配。解决先确认hi3559_isp.ko和libsns_imx335.a是同一个 SDK 版本编出来的。如果 SDK 升级过sensor 库必须重新编。另外在 Makefile 里把-lhi_isp放在-lsns_imx335后面链接器从左到右解析符号顺序反了就会报 undefined。5.5 现象替换驱动后板子启动卡死原因sensor 列表里加了 IMX335但板子上实际没接 IMX335ISP 初始化时一直等 sensor 响应导致启动阻塞。解决在sensor_list.c里加一个条件编译或者运行时检测只有检测到 IMX335 的 ID 才注册。常见做法是在sensor_register函数里先读一次 I2C读不到就返回错误让 ISP 跳过这个 sensor。海思的sensor_list机制支持这种「探测失败则跳过」的逻辑但需要你在cmos.c的pfn_cmos_init里返回非零值。6. 进阶用 sensor_cfg 工具生成自定义分辨率寄存器表6.1 为什么需要自己生成寄存器表资源包里的寄存器表通常只覆盖 5M30fps 和 1080P30fps 两个模式。如果你的项目需要 3M60fps 或者 4M25fps就得自己生成。Sony 的 datasheet 有几百页手动算 PLL 和时序不现实。海思 SDK 里自带sensor_cfg工具可以输入分辨率、帧率、MIPI 时钟等参数自动生成寄存器序列。6.2 sensor_cfg 的输入参数与输出格式工具一般在$(SDK_DIR)/mpp/tools/sensor_cfg/下跑起来是一个交互式命令行./sensor_cfg # 选择 sensor 类型IMX335 # 输入分辨率2560x1440 # 输入帧率60 # 输入 MIPI 时钟594 # 输入 Bayer 顺序RGGB输出是一个.h文件里面包含imx335_3m_60fps_regs[]数组和对应的stSnsImageMode结构体。把这个文件替换掉原来的imx335_cmos_ex.h重新编译即可。6.3 验证新寄存器表的三个步骤第一步用 I2C 逐条对比把新生成的寄存器序列和 datasheet 里的推荐值对一遍重点看 PLL 和 MIPI 相关的寄存器。第二步跑sample_vi看帧率是否达到预期如果只有一半检查 VMAX 是不是被工具算大了。第三步用hi_isp的调试工具看 ISP 的输入统计确认 Bayer 顺序和位宽RAW10 还是 RAW12匹配。注意sensor_cfg 生成的寄存器表不一定完全准确尤其是 MIPI 时钟的计算。我一般会拿示波器实测 MIPI CLK 频率和工具算出来的值对比偏差超过 5% 就手动调 PLL 寄存器。6.4 一个实际踩过的坑有一次我用 sensor_cfg 生成 4M25fps 的寄存器表跑起来帧率只有 12.5fps。查了半天发现是工具的 VMAX 计算逻辑有 bug——它把 VMAX 算成了两倍。后来我手动把 VMAX 除以 2帧率就正常了。从那以后我每次用工具生成寄存器表都会先跑一遍sample_vi看帧率再拿示波器量 XVS 的周期两个数据对上了才敢往产品里合。希望帮到你。本文还有配套的精品资源点击获取
返回列表