君正 T33 Sensor 驱动调试实践

内容纲要

Table of Contents

君正 T33 Sensor 驱动调试实践

以 GC1084 15FPS 驱动为例

适用对象:刚接触君正 tx-isp sensor 驱动,或者已经能改寄存器表,但还没有把“驱动框架、上电流程、出图链路、AE 调试、帧率调试”串起来的开发者。
参考源码:gc1084s1.c
目标平台:君正 T33 / tx-isp 框架
示例模式:GC1084 1280x720@15fps,MIPI 1lane,RAW10


1. 为什么选 GC1084 15FPS 作为例子

gc1084s1.c 是一个很典型的君正 sensor 驱动:

  • 它完整保留了君正 tx-isp 的标准 sensor 框架。
  • 它包含最核心的几条链路:probechip identinitstream on/offexpofps
  • 它的 15FPS 版本不是完全重写出来的,而是在 30FPS 初始化表基础上,主要通过修改 VTS 和属性参数实现,这非常适合讲清楚“寄存器模式”和“驱动框架”之间的关系。

对于初学者来说,最容易犯的错不是“某个寄存器写错”,而是:

  • 不知道哪个函数在什么时候被调用;
  • 不知道一张寄存器表到底对应什么状态;
  • 不知道为什么 sensor ID 对了却不出图;
  • 不知道曝光、增益、帧率分别是从哪条控制链路下来的。

这篇文章的目标,就是把这些问题串起来。


2. 先看整体:君正 Sensor 驱动到底在做什么

从本质上看,君正 sensor 驱动做四件事:

  1. 把 sensor 的硬件属性告诉 ISP。
  2. 把一套寄存器初始化表按时机写进 sensor。
  3. 把 ISP 下发的控制命令翻译成 sensor 寄存器写操作。
  4. 在系统启动、开流、停流、切 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_lineargc1084s1.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_mipigc1084s1.c:636

这张表做的事情是:

  • 初始化模拟/数字模块
  • 配置行长 HTS
  • 配置帧长 VTS
  • 配置输出窗口
  • 配置 MIPI
  • 配置 slave 同步相关寄存器

最关键的几项是:

  • 0x0d05 = 0x08
  • 0x0d06 = 0xae
  • 0x0d41 = 0x05
  • 0x0d42 = 0xdc
  • 0x0d03 = 0x02
  • 0x0d04 = 0xd0

大致对应:

  • 0x0d05/0x0d06:HTS
  • 0x0d41/0x0d42:VTS
  • 0x0d03/0x0d04:曝光时间

驱动注释里已经点明:

  • 30fps@vts=0x2ee=750
  • 15fps@vts=0x5dc=1500

也就是说,这个 15FPS 驱动的核心改法之一,就是把帧长从 750 拉到 1500

3.4 窗口配置 wsize

窗口配置在:

  • gc1084_win_sizesgc1084s1.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_read
  • gc1084_write
  • gc1084_write_array

这些函数本身不复杂,但它们决定了后续所有调试效率。

3.6 控制函数

这个驱动里最核心的控制函数有:

  • gc1084_setting_selectgc1084s1.c:1046
  • gc1084_attr_checkgc1084s1.c:1104
  • gc1084_g_chip_identgc1084s1.c:1190
  • gc1084_initgc1084s1.c:1255
  • gc1084_s_streamgc1084s1.c:1309
  • gc1084_set_expogc1084s1.c:1340
  • gc1084_set_fpsgc1084s1.c:1419
  • gc1084_sensor_ops_ioctlgc1084s1.c:1617

3.7 驱动注册入口

  • gc1084_probegc1084s1.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)

所以当 VTS750 变成 1500 时,帧率减半,30FPS 变成 15FPS。

4.2 驱动属性层

gc1084_setting_select() 里,对应模式参数被同步成:

  • integration_time.value = 0x5b8
  • integration_time.max = 1500 - 4
  • total_width = 2222
  • total_height = 1500

这一步非常关键。

因为:

  • 寄存器表控制 sensor 真正怎么出图;
  • gc1084_attr 控制 ISP 认为 sensor 应该怎么工作。

关系图如下:

+------------+            +------------------+
| 寄存器表   | ---------> | Sensor 真实输出  |
+------------+            +------------------+
       \                          /
        \                        /
         \                      /
          v                    v
          +--------------------+
          | 最终图像行为       |
          +--------------------+
                   ^
                   |
+------------+     |
| gc1084_attr| ----+
+------------+

结论很直接:

改模式时,一定要同时改“寄存器表”和“属性参数”,不能只改其中一边。


5. 驱动启动流程详解

下面按真实调用顺序,把整条链路展开。

5.1 probe:注册设备,但此时还没真正完成 sensor 初始化

入口函数:

  • gc1084_probe()

它主要做这些事情:

  1. 分配 struct tx_isp_sensor
  2. 初始化 sdvideo
  3. 设置 sensor->video.attr = &gc1084_attr
  4. 调用 tx_isp_subdev_init
  5. 绑定 I2C client 和 hostdata

这一阶段的重点不是图像,而是“把设备接到框架上”。

5.2 g_chip_ident:真正开始接触硬件

入口函数:

  • gc1084_g_chip_ident()

它会做:

  1. gc1084_attr_check()
  2. 拉 reset GPIO
  3. 拉 pwdn GPIO
  4. gc1084_detect()
  5. 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()

它的职责是:

  1. gc1084_setting_select(info->default_boot)
  2. 根据 video_interface 选择 MIPI / DVP
  3. 根据 mclk 配置 sensor 时钟
  4. 设置 sensor->video.mbus.code
  5. 设置 sensor->video.fps
  6. gc1084_attr_set() 同步 video attr

5.4 setting_select:选模式的地方

入口函数:

  • gc1084_setting_select()

对这个 15FPS 例子来说,case 0 就代表唯一工作模式。它在这里设置:

  • wsize = &gc1084_win_sizes[0]
  • data_type = LINEAR
  • again 范围
  • integration_time 默认值和上下限
  • total_width
  • total_height
  • mipi 参数

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()

开流时分两步:

  1. 如果状态还是 TX_ISP_MODULE_DEINIT,先写 wsize->regs
  2. 再写 gc1084_stream_on_mipi

对应寄存器:

  • stream on0x023e = 0x98
  • stream off0x023e = 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:1617
  • gc1084_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 传下来的增益值翻译成一组寄存器:

  • 0x00d1
  • 0x00d0
  • 0x0dc1
  • 0x00b8
  • 0x00b9
  • 0x0155
  • 0x00b1
  • 0x00b2

6.2 再写曝光时间

写:

  • 0x0d04 = exposure low
  • 0x0d03 = exposure high

这一步控制 integration time。


7. 帧率是怎么调的

入口函数:

  • gc1084_set_fps()gc1084s1.c:1419

逻辑很典型:

  1. 根据模式确定 sclk
  2. 从 sensor 读出 HTS
  3. 根据目标 fps 反算 VTS
  4. VTS 回写到 0x0d41/0x0d42
  5. 同步 sensor->video.attr->total_height
  6. 更新 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/0x0d42
  • 0x0d03/0x0d04
  • 0x023e

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 是否真的是 0x05dc
  • total_height 是否同步成 1500
  • set_fps() 是否又把 VTS 改掉了

10.4 曝光容易打满或偏暗

优先查:

  • integration_time.max = total_height - 4 是否合理
  • 当前默认曝光 0x5b8 是否太大
  • 行时间和帧长是否匹配

10.5 驱动能跑,但切模式后异常

优先查:

  • gc1084_setting_select() 是否切到正确模式
  • wsize->regs 是否指向正确寄存器表
  • gc1084_attrtotal_width/total_height 是否同步

11. 实战建议:如何改一个新模式

假设你后续要把这个 15FPS 版本改成 30FPS,或者增加另一个模式,建议按下面顺序做:

  1. 先确认新的寄存器表能在别的平台正常出图。
  2. 新建一份独立的 init_regs_xxx 表。
  3. 新建或修改对应 gc1084_win_sizes[] 模式项。
  4. gc1084_setting_select() 里同步修改:
    • integration_time.value
    • integration_time.max
    • total_width
    • total_height
    • mipi 参数
  5. 检查 set_fps()sclk 基准是否仍然正确。
  6. 最后验证 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. 附:建议在源码里重点阅读的函数

建议按这个顺序读:

  1. gc1084_probe()
  2. gc1084_g_chip_ident()
  3. gc1084_attr_check()
  4. gc1084_setting_select()
  5. gc1084_init()
  6. gc1084_s_stream()
  7. gc1084_sensor_ops_ioctl()
  8. gc1084_set_expo()
  9. gc1084_set_fps()

这样阅读最容易建立完整的调用链认知。

版权声明

版权声明

内容来源及使用限制

欢迎访问 TomgZHE研习社(网址:https://blog.tomgzhe.com)。本网站部分文章内容源自网络,仅作学习交流与参考分享;若您发现有内容涉嫌侵权,请立即联系 tomgzhe@qq.com,我们将在接到通知后的 48 小时内核实并删除相关侵权内容。

软件资源相关规定

本网站为个人非盈利性质的站点,所有软件资源均来自网络。这些资源仅用于个人学习、研究和参考,严禁用于任何商业用途。您下载和使用本网站软件资源即表示您同意仅将其用于学习目的,若因违反此规定导致任何法律纠纷或损失,责任由您自行承担。

原创版权

本网站上的原创内容,包括但不限于文字作品、自行设计的图片、独家制作的音频视频等,其版权均归本网站所有。未经本网站书面授权,任何组织或个人不得擅自复制、转载、摘编、传播或以其他任何方式使用这些原创内容。如需使用,请提前与我们联系并获得书面许可,同时需在显著位置注明出处及作者信息。

转载与引用规范

若您需转载本网站文章,务必注明文章来源为 “[TomgZHE研习社],原文链接:[ https://blog.tomgzhe.com/index.php/2026/07/16/君正-t33-sensor-驱动调试实践/ ]”;对于有明确作者署名的文章,还需完整保留作者姓名。在引用本网站内容时,请确保内容准确无误,并遵循学术及行业的引用规范。

Like (0)
Donate 微信扫一扫打赏 微信扫一扫打赏 支付宝扫一扫打赏 支付宝扫一扫打赏
tomgzhe的头像tomgzhe
Previous 2天前
Next 19小时前

相关推荐

发表回复

Please Login to Comment
联系我们

联系我们

400-800-6666

在线咨询: QQ交谈 邮件:tomgzhe@qq.com 工作时间:周一至周五,9:30-18:30,节假日休息

关注微信
关注微信
SHARE
TOP
蛇年新气象!从2025年2月起,本博客将在保留科技板块基础上,新增生活美学、个人成长等多元内容,希望能为大家带来更丰富的阅读体验,敬请期待!