news 2026/5/13 3:39:21

(复习记录)I2C子系统-----结合RK3588MIPI摄像头实例讲解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
(复习记录)I2C子系统-----结合RK3588MIPI摄像头实例讲解

文章目录

  • 前言
  • 一、I2C 物理结构以及基本原理
    • 1.1硬件连接结构
    • 1.2主从关系
  • 二、Linux系统下的 I2C 节点结构
    • 2.1Linux I2C 子系统三大部分
  • 三、具体实验代码内容
    • 3.1 修改设备树
    • 3.2 写寄存器头文件
    • 3.3写 AP3216C I2C 驱动:把 I2C 设备包装成 Linux 可访问设备
    • 3.4 写用户态测试 APP:用 open/read 验证驱动是否工作
  • 四、MIPI摄像头 V4L2相关设备搭建
  • 总结

前言

本章内容:了解I2C控制器驱动,并在理解适配器驱动下,自己写挂在 I2C 总线下面的设备驱动

一、I2C 物理结构以及基本原理

1.1硬件连接结构

共有两条线:SCL-串行时钟线,SDA-串行数据线,支持一个主机挂多个从机,每个从机通过不同的 I2C 地址区分。

1.2主从关系

主机一般负责数据发送(包括从机地址,读写数据,开始结束信号等),从机只根据主机命令接收或发送数据。

二、Linux系统下的 I2C 节点结构

第一层:SoC 的 I2C 控制器
第二层:挂在 I2C 控制器下面的 I2C 从设备

2.1Linux I2C 子系统三大部分

大致可以分成三部分

  1. I2C core:负责统一管理 I2C 总线、设备、驱动注册和匹配
  2. I2C adapter:表示 SoC 里的一个 I2C 控制器,比如 i2c5
  3. I2C client; driver:表示挂在 I2C 总线下面的某个从设备,比如 AP3216C;表示这个从设备对应的软件驱动,比如 ap3216c_driver

rk3x_i2c_probe的作用:

  1. 申请 rk3x_i2c 私有结构体
  2. 解析设备树里的 I2C 时序和频率
  3. 初始化 i2c_adapter
  4. 设置 i2c_algorithm
  5. 映射 I2C 控制器寄存器
  6. 获取中断号并注册中断
  7. 获取并准备时钟
  8. 调用 i2c_add_adapter() 注册 adapter

具体流程再platform驱动有讲(后续讲解)

三、具体实验代码内容

可以分为五个部分
3.1 修改设备树
3.2 写 AP3216C 寄存器头文件
3.3 写 AP3216C I2C 驱动
3.4 写用户态测试 APP
3.5 编译、加载、运行测试

3.1 修改设备树

修改设备树,增加节点,以及节点内的compatible和从机地址等其他硬件资源(I2C的reg是从机地址,但是其他的不一定,spi:片选号 chip select)

3.2 写寄存器头文件

AP3216C 是一个真实存在的 I2C 外设芯片。
它有自己的数据手册,里面规定了 I2C 地址、寄存器地址、寄存器含义、数据格式和初始化时序。

驱动开发的工作,就是把这些手册内容翻译成内核代码:
1. 设备树描述这个芯片挂在哪条 I2C 总线上
2. 驱动代码根据 compatible 匹配这个芯片
3. 驱动通过 I2C 读写 AP3216C 的寄存器
4. 驱动把这个芯片注册成 Linux 能管理的设备
5. 如果需要用户态访问,再创建 /dev/ap3216c 这种设备节点

头文件中需要写数据寄存器的地址,同时设置子设备的工作模式,需要把芯片手册里的“寄存器表/命令表”翻译成驱动代码能直接使用的宏。

PS:0x0F 对应什么功能,不是我们自己定的,而是芯片厂商在硬件内部已经设计好的。数据手册只是把这个固定规则告诉我们。

3.3写 AP3216C I2C 驱动:把 I2C 设备包装成 Linux 可访问设备

第一件事:注册 i2c_driver,让驱动能和设备树里的 i2c_client 匹配。
第二件事:注册字符设备,让用户态能通过 /dev/ap3216c 访问传感器。

AP3216C 实验其实有两条线。

第一条线:设备发现和驱动匹配线->i2c_client、i2c_driver、bus、probe绑定client和字符设备节点,实现用户和内核间的数据交换(这里具体是驱动拿到client就可以通过驱动内部读写函数函数访问硬件了)

第二条线:用户态访问线->alloc_chrdev_region()、cdev_init()、cdev_add()等创建用户态节点
只有这样才可以实现用户与内核态的数据交换

在 device 和 driver 匹配成功、probe 被调用之后,
驱动会进一步把这个client绑定某设备(字符设备、subv4l2设备)到某个 Linux 子系统中。
如果注册到字符设备框架,就形成 /dev/xxx;
如果注册到 V4L2/media 框架,就形成 v4l2_subdev/media entity;

根据设备所在总线类型,选择对应 driver 结构体;根据设备通信方式,封装对应读写函数;根据用户态访问方式,注册对应 Linux 子系统接口。

3.4 写用户态测试 APP:用 open/read 验证驱动是否工作

四、MIPI摄像头 V4L2相关设备搭建

具体流程如下(这里是从我记得笔记拉下来的,csdn的引用不太好看,需要的同学可以直接复制下来让AI给你详细讲清楚):

设备树:
&i2c2 {
ov13855@36 {
compatible = “ovti,ov13855”;
reg = <0x36>;
reset-gpios = <…>;
clocks = <…>;
port {
endpoint {
remote-endpoint = <&csi_in>; };
};

内核解析设备树:
创建 i2c_client
/sys/bus/i2c/devices/2-0036

加载 ov13855 驱动:
i2c_add_driver(&ov13855_i2c_driver)

I2C bus 匹配:
compatible 匹配成功

调用 ov13855_probe(client)

probe 中:
申请 ov13855 私有结构体
保存 client
获取 clk/gpio/regulator
power on
I2C 读 chip ID
初始化 v4l2_subdev
初始化 media pad
初始化 controls
注册 async subdev

media framework:
sensor subdev 等待和 CSI/ISP 绑定
形成 media graph

用户态:
open(“/dev/videoX”)
VIDIOC_S_FMT
VIDIOC_REQBUFS
VIDIOC_STREAMON

capture 驱动启动 pipeline:
调用 sensor s_stream(1)

sensor 驱动:
I2C 写寄存器表
I2C 写 stream on

sensor 开始通过 MIPI CSI-2 输出图像

CSI / ISP / video capture 接收图像

用户态 DQBUF 获取图像帧

总结

下面以正点原子教程中的I2C字符实验内容来总结,V4L2结构可以看上面的流程,基本原理是一样的,只不过根据注册的不同设备(字符设备、V4L2等可能具体驱动和字符设备注册流程不同):

AP3216C 的寄存器地址由芯片数据手册规定,驱动文件通过引用 ap3216creg.h,把这些寄存器地址宏用于 I2C 读写函数中。

设备树负责描述 AP3216C 挂在哪条 I2C 总线上、I2C 地址是多少,以及可能需要的 GPIO、clock、regulator 等资源。内核解析设备树后创建 i2c_client,i2c_client 表示 AP3216C 在 I2C 总线模型中的设备对象,里面保存 I2C 地址、所属 adapter 以及通用 device 信息。

ap3216c_driver 注册到 I2C 子系统后,与 i2c_client 匹配成功并进入 probe。probe 中申请驱动私有结构体 ap3216c_dev,把 i2c_client 保存进去,同时注册字符设备 cdev,创建 /dev/ap3216c。这样用户态通过 /dev/ap3216c 调用 open/read 时,会进入 file_operations 对应函数,而这些函数内部再通过 ap3216c_read_regs/ap3216c_write_regs 和 i2c_transfer 访问 AP3216C 硬件寄存器。

注意client中储存了:

  1. I2C 地址
  2. 所属 I2C adapter 表示这个设备挂在哪个 I2C 控制器下面
    3.compatible = “ovti,ov13855” 参与和 i2c_driver 的 of_match_table 匹配
  3. 通用 struct device
  4. 这个 struct device 里关联着原始设备树节点(后续其他内容需要驱动来读取并储存)
    本质上因为client是适配很多的,他们可能有不同的子设备都叫做client,都写进去太臃肿了
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/13 3:36:06

如何构建高效的个人游戏串流服务器:Sunshine完整部署指南

如何构建高效的个人游戏串流服务器&#xff1a;Sunshine完整部署指南 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine 在当今数字娱乐时代&#xff0c;游戏玩家面临着设备限制与体验…

作者头像 李华
网站建设 2026/5/13 3:33:05

AI代码上下文助手:提升大模型编程协作效率的智能工具

1. 项目概述&#xff1a;AI代码上下文助手的诞生与价值最近在GitHub上看到一个挺有意思的项目&#xff0c;叫sansan0/ai-code-context-helper。光看名字&#xff0c;你大概能猜到它和AI编程、代码上下文有关。没错&#xff0c;这是一个专门为大型语言模型&#xff08;比如ChatG…

作者头像 李华
网站建设 2026/5/13 3:25:15

基于Next.js 14与AI SDK构建智能菜谱生成器全栈实践

1. 项目概述&#xff1a;一个由AI驱动的智能菜谱生成器 最近在捣鼓一些AI应用落地的项目&#xff0c;发现了一个挺有意思的开源项目——Chef Genie。简单来说&#xff0c;这就是一个“AI大厨”&#xff0c;你告诉它你冰箱里有什么、想吃什么口味、有什么忌口&#xff0c;它就能…

作者头像 李华
网站建设 2026/5/13 3:24:10

双模CIM加速器架构与DACO编译优化实践

1. 双模CIM加速器的架构创新与挑战存内计算&#xff08;Computing-in-Memory, CIM&#xff09;技术正在彻底改变传统计算架构的设计范式。这种架构的核心突破在于打破了冯诺依曼体系中计算与存储分离的桎梏&#xff0c;通过在存储阵列中直接嵌入计算逻辑单元&#xff0c;实现了…

作者头像 李华
网站建设 2026/5/13 3:23:06

oh-my-prompt:打造高效终端提示符的模块化方案与实战配置

1. 项目概述&#xff1a;为什么我们需要一个现代化的终端提示符&#xff1f;如果你和我一样&#xff0c;每天有超过一半的工作时间是在终端&#xff08;Terminal&#xff09;里度过的&#xff0c;那么终端提示符&#xff08;Prompt&#xff09;就是你最熟悉的“工作台面”。默认…

作者头像 李华
网站建设 2026/5/13 3:23:02

企业级AI中台MCP-X架构实战:一站式工作流平台设计与实现

1. 项目概述&#xff1a;从零到一&#xff0c;构建企业级AI中台MCP-X的实战复盘最近几年&#xff0c;AI领域的发展速度堪称“日新月异”&#xff0c;从最初的文本对话&#xff0c;到图像生成&#xff0c;再到如今的视频创作&#xff0c;各种模型和工具层出不穷。作为一名长期在…

作者头像 李华