君正 T33 Sensor 驱动调试实践
以 GC1084 15FPS 驱动为例
适用对象:刚接触君正
tx-ispsensor 驱动,或者已经能改寄存器表,但还没有把“驱动框架、上电流程、出图链路、AE 调试、帧率调试”串起来的开发者。
参考源码:gc1084s1.c
目标平台:君正 T33 /tx-isp框架
示例模式:GC10841280x720@15fps,MIPI 1lane,RAW10
1. 为什么选 GC1084 15FPS 作为例子
gc1084s1.c 是一个很典型的君正 sensor 驱动:
- 它完整保留了君正
tx-isp的标准 sensor 框架。 - 它包含最核心的几条链路:
probe、chip ident、init、stream on/off、expo、fps。 - 它的 15FPS 版本不是完全重写出来的,而是在 30FPS 初始化表基础上,主要通过修改
VTS和属性参数实现,这非常适合讲清楚“寄存器模式”和“驱动框架”之间的关系。
对于初学者来说,最容易犯的错不是“某个寄存器写错”,而是:
- 不知道哪个函数在什么时候被调用;
- 不知道一张寄存器表到底对应什么状态;
- 不知道为什么 sensor ID 对了却不出图;
- 不知道曝光、增益、帧率分别是从哪条控制链路下来的。
这篇文章的目标,就是把这些问题串起来。
2. 先看整体:君正 Sensor 驱动到底在做什么
从本质上看,君正 sensor 驱动做四件事:
- 把 sensor 的硬件属性告诉 ISP。
- 把一套寄存器初始化表按时机写进 sensor。
- 把 ISP 下发的控制命令翻译成 sensor 寄存器写操作。
- 在系统启动、开流、停流、切 fps、切曝光时,维持 sensor 和 ISP 的参数一致。
先看总流程图:
+------------------------+
| Linux 加载 I2C 驱动 |
+-----------+------------+
|
v
+------------------------+
| gc1084_probe() |
+-----------+------------+
|
v
+------------------------+
| tx_isp_subdev_init() |
+-----------+------------+
|
v
+------------------------+
| 注册 sensor ops |
+-----------+------------+
|
v
+------------------------+
| gc1084_g_chip_ident() |
+-----------+------------+
|
v
+------------------------+
| gc1084_attr_check() |
+-----------+------------+
|
v
+------------------------+
| gc1084_setting_select()|
+-----------+------------+
|
v
+------------------------+
| 配置属性/时钟/MIPI |
+-----------+------------+
|
v
+------------------------+
| 读取 sensor ID |
+-----------+------------+
|
v
+------------------------+
| gc1084_init() |
+-----------+------------+
|
v
+------------------------+
| gc1084_s_stream() |
+-----------+------------+
|
v
+------------------------+
| 写初始化寄存器表 |
+-----------+------------+
|
v
+------------------------+
| stream on |
+-----------+------------+
|
v
+------------------------+
| ISP 开始收图 |
+------------------------+
如果只记一句话:
君正 sensor 驱动的主线,就是“先告诉 ISP 这颗 sensor 是谁、怎么连、当前工作模式是什么,再在合适时机把寄存器写进去,最后响应 ISP 的控制命令”。
3. GC1084 15FPS 驱动的关键组成
在 gc1084s1.c 里,可以把驱动拆成 7 个部分。
3.1 硬件总线描述
gc1084_mipi_linear:描述 MIPI 口、lane 数、时钟、图像尺寸。gc1084_dvp:DVP 配置,这个例子里主要走 MIPI。
源码锚点:
gc1084_mipi_linear:gc1084s1.c:577
它告诉 ISP:
- 这是一颗 RAW10 sensor;
- 当前走 MIPI;
- 图像宽高是
1280x720; - lane 数是
1; - mipi clk 配置为
500。
这一步不负责“写 sensor 寄存器”,而是负责“告诉 ISP 连接方式”。
3.2 Sensor 属性结构体
gc1084_attr 是整个驱动最关键的数据结构之一。
它里面描述:
- sensor 名字
- I2C 地址
- 控制总线类型
- 增益分配函数
- 当前模式的总宽度、总高度
- 曝光上下限
- 数据接口类型
- MIPI 参数
可以把它理解为:
这是 ISP 眼中的“sensor 说明书”。
3.3 模式寄存器表
GC1084 15FPS 的初始化寄存器表在:
gc1084_init_regs_1280_720_15fps_mipi:gc1084s1.c:636
这张表做的事情是:
- 初始化模拟/数字模块
- 配置行长 HTS
- 配置帧长 VTS
- 配置输出窗口
- 配置 MIPI
- 配置 slave 同步相关寄存器
最关键的几项是:
0x0d05 = 0x080x0d06 = 0xae0x0d41 = 0x050x0d42 = 0xdc0x0d03 = 0x020x0d04 = 0xd0
大致对应:
0x0d05/0x0d06:HTS0x0d41/0x0d42:VTS0x0d03/0x0d04:曝光时间
驱动注释里已经点明:
30fps@vts=0x2ee=75015fps@vts=0x5dc=1500
也就是说,这个 15FPS 驱动的核心改法之一,就是把帧长从 750 拉到 1500。
3.4 窗口配置 wsize
窗口配置在:
gc1084_win_sizes:gc1084s1.c:776
这里定义了:
- 分辨率:
1280x720 - 帧率:
15 << 16 | 1 - Bayer 格式:
TISP_VI_FMT_SGRBG10_1X10 - colorspace:
TISP_COLORSPACE_SRGB - 对应初始化表:
gc1084_init_regs_1280_720_15fps_mipi
也就是说,wsize 不是单纯宽高,而是:
- 分辨率
- 像素格式
- fps
- 对应寄存器表
一起打包的模式对象。
3.5 I2C 读写接口
典型函数:
gc1084_readgc1084_writegc1084_write_array
这些函数本身不复杂,但它们决定了后续所有调试效率。
3.6 控制函数
这个驱动里最核心的控制函数有:
gc1084_setting_select:gc1084s1.c:1046gc1084_attr_check:gc1084s1.c:1104gc1084_g_chip_ident:gc1084s1.c:1190gc1084_init:gc1084s1.c:1255gc1084_s_stream:gc1084s1.c:1309gc1084_set_expo:gc1084s1.c:1340gc1084_set_fps:gc1084s1.c:1419gc1084_sensor_ops_ioctl:gc1084s1.c:1617
3.7 驱动注册入口
gc1084_probe:gc1084s1.c:1740
它负责:
- 申请 sensor 结构体
- 初始化 subdev
- 绑定
ops - 绑定 I2C client
4. 15FPS 版本到底是怎么来的
这个例子很有代表性,因为它不是一份“完全独立的 15FPS 新驱动”,而是:
- 主体框架沿用君正标准 sensor 模板;
- 寄存器表主体沿用 GC1084 线性模式;
- 通过修改
VTS和属性,把输出模式固定为 15FPS。
4.1 寄存器层
15FPS 表里:
VTS = 0x05dc = 1500
而 30FPS 常见配置里:
VTS = 0x02ee = 750
在行时间不变的情况下:
帧率 = 像素时钟 / (HTS × VTS)
所以当 VTS 从 750 变成 1500 时,帧率减半,30FPS 变成 15FPS。
4.2 驱动属性层
在 gc1084_setting_select() 里,对应模式参数被同步成:
integration_time.value = 0x5b8integration_time.max = 1500 - 4total_width = 2222total_height = 1500
这一步非常关键。
因为:
- 寄存器表控制 sensor 真正怎么出图;
gc1084_attr控制 ISP 认为 sensor 应该怎么工作。
关系图如下:
+------------+ +------------------+
| 寄存器表 | ---------> | Sensor 真实输出 |
+------------+ +------------------+
\ /
\ /
\ /
v v
+--------------------+
| 最终图像行为 |
+--------------------+
^
|
+------------+ |
| gc1084_attr| ----+
+------------+
结论很直接:
改模式时,一定要同时改“寄存器表”和“属性参数”,不能只改其中一边。
5. 驱动启动流程详解
下面按真实调用顺序,把整条链路展开。
5.1 probe:注册设备,但此时还没真正完成 sensor 初始化
入口函数:
gc1084_probe()
它主要做这些事情:
- 分配
struct tx_isp_sensor - 初始化
sd和video - 设置
sensor->video.attr = &gc1084_attr - 调用
tx_isp_subdev_init - 绑定 I2C client 和 hostdata
这一阶段的重点不是图像,而是“把设备接到框架上”。
5.2 g_chip_ident:真正开始接触硬件
入口函数:
gc1084_g_chip_ident()
它会做:
gc1084_attr_check()- 拉 reset GPIO
- 拉 pwdn GPIO
- 调
gc1084_detect() - 读
0x03f0/0x03f1校验 chip id
时序图:
tx-isp
|
| gc1084_g_chip_ident()
v
driver
|
|--> gc1084_attr_check()
|--> reset/pwdn 时序
|--> 读 0x03f0
|<-- 0x10
|--> 读 0x03f1
|<-- 0x84
|
+--> chip identify success
5.3 attr_check:把当前模式同步给 ISP
入口函数:
gc1084_attr_check()
它的职责是:
- 调
gc1084_setting_select(info->default_boot) - 根据
video_interface选择 MIPI / DVP - 根据
mclk配置 sensor 时钟 - 设置
sensor->video.mbus.code - 设置
sensor->video.fps - 调
gc1084_attr_set()同步 video attr
5.4 setting_select:选模式的地方
入口函数:
gc1084_setting_select()
对这个 15FPS 例子来说,case 0 就代表唯一工作模式。它在这里设置:
wsize = &gc1084_win_sizes[0]data_type = LINEARagain范围integration_time默认值和上下限total_widthtotal_heightmipi参数
5.5 init:同步初始化状态,但还没真正出流
入口函数:
gc1084_init()
它主要做:
- 设置
sensor->video.mbus.code - 设置
sensor->video.fps.value - 设置
sensor->video.fps.max - 再调一次
gc1084_attr_set()
注意,这里并没有把初始化寄存器表整体写进去。
5.6 s_stream:真正写初始化表并出流
入口函数:
gc1084_s_stream()
开流时分两步:
- 如果状态还是
TX_ISP_MODULE_DEINIT,先写wsize->regs - 再写
gc1084_stream_on_mipi
对应寄存器:
stream on:0x023e = 0x98stream off:0x023e = 0x00
开流流程图:
s_stream(enable=1)
|
+-- video.state == DEINIT ?
| |
| +-- yes --> 写初始化寄存器表 --> state = INIT
|
+-- video.state == INIT ?
|
+-- yes --> 写 0x023e = 0x98 --> state = RUNNING
6. 曝光和增益是怎么打下去的
GC1084 这个驱动开启了:
#define SENSOR_EXPO#define SENSOR_AGAIN_TABLE
因此曝光和模拟增益是打包一起下发的。
入口函数:
gc1084_sensor_ops_ioctl():gc1084s1.c:1617gc1084_set_expo():gc1084s1.c:1340
调用链路如下:
ISP AE 算法
|
v
TX_ISP_EVENT_SENSOR_EXPO
|
v
gc1084_sensor_ops_ioctl()
|
v
gc1084_set_expo()
|\
| +--> 写 gain 寄存器
|
+----> 写曝光寄存器 0x0d03 / 0x0d04
gc1084_set_expo() 做了两件事。
6.1 先写模拟增益
通过 again_lut 查表,把 ISP 传下来的增益值翻译成一组寄存器:
0x00d10x00d00x0dc10x00b80x00b90x01550x00b10x00b2
6.2 再写曝光时间
写:
0x0d04 = exposure low0x0d03 = exposure high
这一步控制 integration time。
7. 帧率是怎么调的
入口函数:
gc1084_set_fps():gc1084s1.c:1419
逻辑很典型:
- 根据模式确定
sclk - 从 sensor 读出
HTS - 根据目标 fps 反算
VTS - 把
VTS回写到0x0d41/0x0d42 - 同步
sensor->video.attr->total_height - 更新
integration_time.max
公式:
VTS = sclk * fps_den / HTS / fps_num
在这个驱动里:
sclk = 2222 * 1500 * 15
虽然当前默认模式是 15FPS,但它允许你在 1~30fps 范围内调帧率,因此 max_fps = 30。
8. 从“加载驱动”到“出图成功”的完整时序
Kernel
|
+--> gc1084_probe()
|
+--> tx_isp_subdev_init()
|
+--> gc1084_g_chip_ident()
|
+--> gc1084_attr_check()
+--> reset/pwdn/mclk/i2c detect
+--> 读 chip id 成功
|
+--> gc1084_init()
|
+--> gc1084_s_stream(enable=1)
|
+--> 写初始化寄存器表
+--> 写 0x023e = 0x98
|
+--> Sensor 输出 MIPI RAW10
|
+--> ISP 收图
|
+--> TX_ISP_EVENT_SENSOR_EXPO
|
+--> driver 写曝光/增益
9. 调试君正 Sensor 驱动的推荐方法
9.1 第一步:先确认 probe
看这些日志是否出现:
probe ok- 驱动名是否正确
- 是否匹配到 I2C 设备
9.2 第二步:确认 chip_ident
重点确认:
gc1084_g_chip_ident()是否执行gc1084_detect()是否执行0x03f0/0x03f1是否读到正确 ID
9.3 第三步:确认初始化表真的写了
重点看:
gc1084_s_stream(enable=1)是否被调用gc1084_write_array(sd, wsize->regs)是否执行- 有没有某个寄存器写失败
建议至少抽查这些关键寄存器:
0x0d41/0x0d420x0d03/0x0d040x023e
9.4 第四步:确认 sensor 正在出流
一定要确认:
0x023e = 0x98
如果不是,就说明没有真正 stream on。
9.5 第五步:确认 MIPI 接收链路
如果 sensor 已经出流但仍然黑屏,要转到链路侧排查:
- lane 数是否匹配
- RAW 格式是否匹配
- MIPI 时钟是否匹配
image_twidth/image_theight是否匹配- ISP 输入格式是否匹配
GRBG10
9.6 第六步:确认 AE 和 fps 控制是否正常
图出来后,再看控制链路:
- 曝光下发是否生效
- 增益下发是否生效
- 改 fps 是否真的改 VTS
10. 常见故障和定位思路
10.1 能读 ID,但不出图
优先查:
s_stream()是否执行- 初始化表是否写成功
0x023e是否变成0x98- MIPI lane / clk / format 是否一致
10.2 有图,但 AE 不工作
优先查:
TX_ISP_EVENT_SENSOR_EXPO是否进gc1084_sensor_ops_ioctl()gc1084_set_expo()是否执行0x0d03/0x0d04是否变化again_lut是否匹配当前 sensor 模式
10.3 改了 15FPS 但实际不是 15FPS
优先查:
0x0d41/0x0d42是否真的是0x05dctotal_height是否同步成1500set_fps()是否又把 VTS 改掉了
10.4 曝光容易打满或偏暗
优先查:
integration_time.max = total_height - 4是否合理- 当前默认曝光
0x5b8是否太大 - 行时间和帧长是否匹配
10.5 驱动能跑,但切模式后异常
优先查:
gc1084_setting_select()是否切到正确模式wsize->regs是否指向正确寄存器表gc1084_attr中total_width/total_height是否同步
11. 实战建议:如何改一个新模式
假设你后续要把这个 15FPS 版本改成 30FPS,或者增加另一个模式,建议按下面顺序做:
- 先确认新的寄存器表能在别的平台正常出图。
- 新建一份独立的
init_regs_xxx表。 - 新建或修改对应
gc1084_win_sizes[]模式项。 - 在
gc1084_setting_select()里同步修改:integration_time.valueintegration_time.maxtotal_widthtotal_heightmipi参数
- 检查
set_fps()的sclk基准是否仍然正确。 - 最后验证
stream on/off、曝光、增益、fps 是否都能工作。
一句话总结:
改模式时,寄存器表只是第一步,属性同步才是稳定运行的关键。
12. 一套适合现场排查的调试闭环
驱动加载失败?
|
+-- 是 --> 查 probe / i2c match
|
+-- 否 --> 能读 chip id?
|
+-- 否 --> 查 mclk/reset/pwdn/i2c
|
+-- 是 --> 能 stream on?
|
+-- 否 --> 查 init regs / 0x023e
|
+-- 是 --> ISP 能收图?
|
+-- 否 --> 查 mipi lane/clk/raw format
|
+-- 是 --> AE/fps 正常?
|
+-- 否 --> 查 expo/fps ioctl 和 attr 同步
|
+-- 是 --> 驱动基本稳定
13. 本例的关键参数速查表
| 项目 | 值 |
|---|---|
| Sensor | GC1084 |
| 分辨率 | 1280×720 |
| 默认帧率 | 15fps |
| 接口 | MIPI 1lane |
| 数据格式 | RAW10 / GRBG |
| MCLK | 24MHz |
| MIPI clk | 500 |
| HTS | 2222 |
| VTS | 1500 |
| 默认曝光 | 0x02d0 寄存器表初值 |
| 属性默认曝光 | 0x05b8 |
| stream on | 0x023e = 0x98 |
| stream off | 0x023e = 0x00 |
| chip id high | 0x03f0 = 0x10 |
| chip id low | 0x03f1 = 0x84 |
说明:
- “寄存器表初值”和“属性默认曝光”不一定完全一致,前者是 sensor 上电初始化值,后者是 ISP 同步时认为的默认 integration time。
- 现场排查时,如果二者差异过大,要重点关注 AE 接管前后画面是否会突变。
14. 总结
GC1084 15FPS 这个例子非常适合用来理解君正 sensor 驱动,因为它把最核心的几件事情都展示出来了:
- 用
probe把 sensor 接入tx-isp - 用
g_chip_ident完成硬件探测 - 用
setting_select + attr_check把模式参数同步给 ISP - 用
s_stream真正把初始化表写进 sensor 并开流 - 用
ioctl响应曝光、增益、fps 等控制命令
如果用一句话概括整篇文章:
君正 sensor 驱动调试,本质上是把“硬件时序、寄存器配置、ISP 属性、控制链路”这四条线同时对齐。
当你能把这四条线串起来,再看任何一颗新 sensor,思路都会清晰很多。
15. 附:建议在源码里重点阅读的函数
建议按这个顺序读:
gc1084_probe()gc1084_g_chip_ident()gc1084_attr_check()gc1084_setting_select()gc1084_init()gc1084_s_stream()gc1084_sensor_ops_ioctl()gc1084_set_expo()gc1084_set_fps()
这样阅读最容易建立完整的调用链认知。
版权声明
内容来源及使用限制
欢迎访问 TomgZHE研习社(网址:https://blog.tomgzhe.com)。本网站部分文章内容源自网络,仅作学习交流与参考分享;若您发现有内容涉嫌侵权,请立即联系 tomgzhe@qq.com,我们将在接到通知后的 48 小时内核实并删除相关侵权内容。
软件资源相关规定
本网站为个人非盈利性质的站点,所有软件资源均来自网络。这些资源仅用于个人学习、研究和参考,严禁用于任何商业用途。您下载和使用本网站软件资源即表示您同意仅将其用于学习目的,若因违反此规定导致任何法律纠纷或损失,责任由您自行承担。
原创版权
本网站上的原创内容,包括但不限于文字作品、自行设计的图片、独家制作的音频视频等,其版权均归本网站所有。未经本网站书面授权,任何组织或个人不得擅自复制、转载、摘编、传播或以其他任何方式使用这些原创内容。如需使用,请提前与我们联系并获得书面许可,同时需在显著位置注明出处及作者信息。
转载与引用规范
若您需转载本网站文章,务必注明文章来源为 “[TomgZHE研习社],原文链接:[ https://blog.tomgzhe.com/index.php/2026/07/16/君正-t33-sensor-驱动调试实践/ ]”;对于有明确作者署名的文章,还需完整保留作者姓名。在引用本网站内容时,请确保内容准确无误,并遵循学术及行业的引用规范。
微信扫一扫打赏
支付宝扫一扫打赏