简介:这份资源面向嵌入式驱动开发与视频处理方向的工程师,提供Sony IMX385 CMOS图像传感器在Hi3559平台上的驱动适配代码,解决传感器初始化、数据采集与控制命令下发等移植问题。压缩包共6个文件,以2个C源文件、1个头文件和1个Makefile为主,另含2个编译产物,整体约352KB,结构精简,便于直接阅读驱动实现与构建流程。内容围绕IMX385与Hi3559之间的接口识别、设备探测、图像数据获取、曝光与增益等参数配置展开,可帮助读者理解传感器与海思平台软件框架的匹配方式,并参考其错误处理与功能验证思路。目前已有925人学习下载,适合需要快速上手IMX385驱动移植或对照调试的开发者参考。
1. IMX385 上 Hi3559:一份能直接编译的驱动适配包
手里这块 Sony IMX385 是 STARVIS 系列里性价比很高的 1080P 全局曝光传感器,很多做安防、机器视觉、工业相机的团队会拿它配海思 Hi3559A/Hi3559V200 做方案。但海思原厂 SDK 里默认带的 sensor 驱动列表通常只有 IMX290、IMX334、IMX477 这些,IMX385 得自己补一份驱动进去,还要改 Makefile、改板级配置、对 I2C 地址、调 MIPI 时序。这份资源就是一套已经跑通的 IMX385 driver 适配 Hi3559 平台的源码包,包含 sensor 驱动 C 文件、寄存器初始化表、Makefile 补丁和板级配置示例。适合正在用 Hi3559 做相机开发、被 sensor 驱动卡住的嵌入式工程师,也适合想搞清楚海思 sensor 驱动框架怎么挂载的新手。下面按「驱动怎么进 SDK → 寄存器表怎么改 → 上板怎么调」的顺序拆开讲。
2. 驱动进 SDK:从文件放置到 Makefile 挂载
2.1 先搞清楚海思 sensor 驱动的目录约定
海思 Hi3559 SDK 的 sensor 驱动统一放在smp/a55_linux/mpp/component/isp/sensor/下面,每个 sensor 一个独立目录,比如imx290、imx334。目录里通常有这几个文件:imx385_cmos.c(驱动主体)、imx385_cmos_ex.h(寄存器表)、imx385_sensor_ctl.c(I2C 读写和初始化序列)、Makefile。这份资源里的文件命名和目录结构就是按这个约定组织的,直接拷进去就能对上。
常见做法是先把整个imx385目录复制到 sensor 目录下,然后确认三件事:目录名和 Makefile 里的SENSOR_TYPE一致、imx385_cmos.c里的g_sensor_name字符串和板级配置里引用的名字一致、I2C 地址和硬件原理图一致。这三处任何一处对不上,编译能过但上板会报sensor not found。
2.2 把驱动目录挂进编译系统
海思的 sensor 编译不是自动扫描目录的,得手动在上一级 Makefile 里加。打开sensor/Makefile,找到类似下面这段:
# sensor/Makefile 片段 SENSOR_DIRS := imx290 imx334 imx477改成:
SENSOR_DIRS := imx290 imx334 imx477 imx385然后在imx385/Makefile里确认编译目标名和源文件列表:
# imx385/Makefile SENSOR_TYPE := imx385 SRCS := imx385_cmos.c imx385_sensor_ctl.c逻辑说明:SENSOR_DIRS是编译系统遍历的入口,不加进去整个目录不会被编译;SENSOR_TYPE决定生成的.o和最终链接进 ISP 库的符号前缀。参数上要注意,如果你的 SDK 版本里SENSOR_DIRS用的是obj-y风格而不是变量列表,那就改成obj-y += imx385/,两种写法在不同 SDK 小版本里都出现过,别照抄。
2.3 板级配置里注册 sensor
驱动编译进去只是第一步,板级还得告诉 ISP 用哪个 sensor。在mpp/component/isp/user/sensor/或者板级cfg目录里找到 sensor 配置数组,加一条 IMX385 的记录:
/* sensor 板级注册片段 */ { .sensor_name = "imx385", .i2c_addr = 0x34, /* 7bit 地址,按原理图确认 */ .bus_id = 0, /* 挂在哪条 I2C 总线 */ .mipi_lane = 4, /* 4 lane MIPI */ .reset_gpio = 0x0A, /* 复位脚 GPIO 编号 */ }逻辑说明:i2c_addr是最容易翻车的地方,IMX385 的 7bit 地址常见是0x1A或0x34,取决于 SID 引脚接法,一定要对着原理图确认,写错了 I2C 读 chip id 直接返回失败。mipi_lane要和设备树里 MIPI 控制器配置一致,Hi3559 支持 4 lane,但如果你板子只走了 2 lane,这里写 4 会导致图像花屏或直接无数据。reset_gpio是 sensor 硬复位脚,海思驱动上电序列里会拉这个脚,编号按你板子的 GPIO 分配填。
3. 寄存器表与初始化序列:IMX385 的关键参数怎么设
3.1 寄存器表结构长什么样
IMX385 的初始化表在imx385_cmos_ex.h里,本质是一个二维数组,每行是「寄存器地址、值、延时」。海思的驱动框架会按顺序写这些寄存器。这份资源里的表已经按 1080P30 全帧率配好,核心结构如下:
/* imx385_cmos_ex.h 片段 */ static const unsigned int imx385_init_seq[][3] = { {0x3000, 0x01, 0x00}, /* 进入 standby */ {0x3002, 0x00, 0x00}, /* 时钟分频 */ {0x3400, 0x00, 0x00}, /* 工作模式 */ {0x3408, 0x00, 0x00}, /* 输出格式 */ /* ... 中间省略上百行 ... */ {0x3000, 0x00, 0x00}, /* 退出 standby */ };逻辑说明:第一列是 16bit 寄存器地址,第二列是写入值,第三列是写完后延时(单位 ms)。IMX385 上电后必须先写0x3000=0x01进 standby,再配时钟和模式,最后0x3000=0x00退出 standby 开始出图。顺序错了会出现「I2C 能通但没图像」的玄学问题。参数上,0x3002是系统时钟分频,和你的 INCK 输入频率有关,常见 27MHz 晶振对应值0x00,如果你板子用的是 24MHz,这个值要改,否则帧率会偏。
3.2 曝光和增益的寄存器映射
IMX385 的曝光和增益不是单一寄存器,而是分高低字节。这份驱动里封装了两个函数:
/* 设置曝光行数 */ static int imx385_set_exposure(unsigned int lines) { unsigned char hi = (lines >> 16) & 0x0F; unsigned char mid = (lines >> 8) & 0xFF; unsigned char lo = lines & 0xFF; /* SHR0 寄存器组 */ imx385_write_reg(0x3020, hi); imx385_write_reg(0x3021, mid); imx385_write_reg(0x3022, lo); return 0; }逻辑说明:IMX385 的曝光寄存器是 20bit,分三个字节写。lines是曝光行数,和实际曝光时间的关系是曝光时间 = lines / 帧率行频。参数上要注意,曝光行数不能超过一帧的总行数,1080P 下总行数约 1125,写超过会直接黑屏。增益类似,分GAIN和GAIN_FINE两组,粗调增益每步 0.3dB,细调补小数部分,这份驱动里已经做了换算,调用时直接传 dB 值即可。
3.3 上电时序和 MIPI 配置
IMX385 上电有严格顺序:先给 AVDD,再给 DOVDD,最后给 DVDD,复位脚在电源稳定后拉低至少 1ms 再拉高。这份驱动的imx385_sensor_ctl.c里sensor_init函数已经按这个顺序写好,但 GPIO 编号要改成你板子的实际分配。MIPI 部分,Hi3559 的 MIPI 控制器配置在设备树里,sensor 侧只需要配 lane 数和时钟模式:
/* MIPI 配置片段 */ imx385_write_reg(0x3408, 0x00); /* 4 lane, RAW10 */ imx385_write_reg(0x340A, 0x00); /* 连续时钟模式 */逻辑说明:0x3408决定输出格式和 lane 数,0x00对应 4 lane RAW10,如果你用 2 lane 要改成对应值。0x340A是时钟模式,连续时钟模式下 MIPI 时钟一直跑,非连续模式只在有数据时跑,Hi3559 一般用连续模式更稳。参数上,RAW10 意味着每个像素 10bit,ISP 那边要配成对应格式,否则颜色会偏。
4. 上板调试:I2C 不通、无图像、花屏怎么排查
4.1 I2C 读不到 chip id
现象:驱动加载后cat /proc/umap/isp显示 sensor 未识别,或者内核 log 里报imx385_read_chip_id failed。
原因:九成是 I2C 地址写错,或者 I2C 总线号不对。IMX385 的 SID 引脚决定地址,悬空和接地是两个不同地址。另外有些板子 I2C 挂了电平转换芯片,实际地址会偏移。
解决:先用i2cdetect -y 0扫一遍总线,看哪个地址有响应。如果扫不到任何设备,检查 sensor 供电和上拉电阻。扫到地址但驱动读不到,把驱动里的i2c_addr改成扫到的值再试。
4.2 有 I2C 通信但无图像
现象:I2C 能读到 chip id,驱动加载正常,但 ISP 拿不到数据,/proc/umap/vi里帧计数一直是 0。
原因:MIPI lane 数配错,或者 sensor 没退出 standby。也有可能是 MIPI 时钟频率和 Hi3559 控制器不匹配。
解决:先确认0x3000最后写的是0x00。然后检查设备树里 MIPI 控制器的 lane 数和 sensor 侧是否一致。如果 lane 数对但还没数据,用示波器量 MIPI 时钟脚,看有没有波形。没有波形说明 sensor 没真正出图,回去查初始化序列里有没有漏写的寄存器。
4.3 图像花屏或颜色异常
现象:能出图,但画面有横条纹、颜色偏绿或偏紫。
原因:RAW10 格式下 ISP 的 Bayer 顺序配错,或者 MIPI 时钟频率偏差导致数据错位。
解决:IMX385 默认 Bayer 顺序是 GRBG,检查 ISP 配置里bayer_format是否一致。颜色偏绿通常是 R 和 G 通道搞反了。横条纹多半是 MIPI 时钟频率不对,调设备树里clock-frequency参数,一般 1080P30 4 lane 对应 297MHz 左右,具体按 sensor 输出速率算。
4.4 帧率不对
现象:图像正常但帧率只有 15fps 或 60fps。
原因:0x3002时钟分频值和 INCK 输入频率不匹配,或者曝光行数设置影响了帧长。
解决:确认板子 INCK 是 27MHz 还是 24MHz,对应改0x3002。另外检查VMAX寄存器,帧长设大了帧率会降。这份驱动里默认按 1080P30 配的,如果你要 60fps,VMAX 要减半,同时确认 MIPI 带宽够。
4.5 驱动编译过但链接报符号缺失
现象:编译.o成功,但链接 ISP 库时报undefined reference to imx385_*。
原因:SENSOR_DIRS加了但SENSOR_TYPE没对上,或者板级注册数组里引用的函数名和驱动里导出的不一致。
解决:检查imx385/Makefile里SENSOR_TYPE和目录名是否完全一致,大小写敏感。再检查imx385_cmos.c里导出的sensor_obj结构体名字是否和板级注册里引用的一致。海思框架靠这个结构体做动态注册,名字对不上就不会被链接进去。
5. 进阶:把 IMX385 驱动改成多分辨率可切换
5.1 为什么需要多分辨率
实际项目里经常要在 1080P 全帧率和 720P 高帧率之间切换,比如白天用 1080P30,晚上切 720P60 提升低照度下的帧率。如果每次改分辨率都重新编译驱动,调试效率太低。更好的做法是在驱动里维护多套初始化表,通过参数选择。
5.2 用结构体数组管理多套寄存器表
把原来的单张imx385_init_seq拆成多张,用一个结构体数组索引:
/* 多分辨率寄存器表管理 */ typedef struct { unsigned int width; unsigned int height; unsigned int fps; const unsigned int (*seq)[3]; unsigned int seq_len; } imx385_mode_t; static const imx385_mode_t g_imx385_modes[] = { {1920, 1080, 30, imx385_1080p30_seq, ARRAY_SIZE(imx385_1080p30_seq)}, {1280, 720, 60, imx385_720p60_seq, ARRAY_SIZE(imx385_720p60_seq)}, };逻辑说明:每个模式带自己的宽高、帧率和寄存器表指针。驱动初始化时根据板级传入的参数选对应模式。参数上要注意,不同分辨率下 VMAX 和曝光行数上限不同,切换模式后要重新算曝光上限,否则高帧率模式下曝光会溢出。
5.3 通过 ioctl 动态切换
海思 ISP 框架支持在运行时通过 ioctl 改 sensor 模式,在驱动里实现sensor_set_mode回调:
static int imx385_set_mode(int mode_index) { if (mode_index >= ARRAY_SIZE(g_imx385_modes)) return -1; const imx385_mode_t *m = &g_imx385_modes[mode_index]; imx385_write_reg(0x3000, 0x01); /* 先 standby */ imx385_load_seq(m->seq, m->seq_len); imx385_write_reg(0x3000, 0x00); /* 退出 standby */ return 0; }逻辑说明:切换模式必须先回 standby 再写新表,直接写会出花屏。imx385_load_seq是遍历写寄存器并处理延时的辅助函数。参数上,切换后 ISP 那边也要重新配分辨率,否则会拿到错位的图像数据。
5.4 验证方法
改完之后用v4l2-ctl或者海思自带的 sample 程序抓帧,确认切换前后帧率和分辨率都对。我一般会连续切换十次,看有没有偶发失败,海思平台上 I2C 时序偶尔会有竞争,连续切换能暴露问题。从那以后我每次改 sensor 驱动,都强制走一遍「I2C 扫描 → chip id 读取 → 抓帧 → 切换模式」四步验证,少一步后面都可能翻车。希望帮到你。
本文还有配套的精品资源,点击获取