跳到主要内容

Image Sensor

1. 简介​

M1000 MIPI CSI-2 可直连 CSI-2 摄像头,也可连接解串器,解串器再连接加串器与摄像头。

直连摄像头方式如下图所示:

直连 CSI-2 摄像头

连接解串器方式如下图所示:

通过解串器连接摄像头

通过解串器连接多个摄像头时,每个摄像头输出 1 路数据流;当数据流到达 M1000 CSI-2 侧时,每个 CSI-2 控制器将接收多达 4 路数据流。因此,每路数据流须使用不同的 CSI-2 virtual channel 号进行区分。

2. 软件说明​

2.1 软件栈特性​

Image Sensor 软件栈支持以下特性:

  • 支持 V4L2。
  • 支持通过 I2C 设备方式加载摄像头驱动。
  • 支持直连摄像头使用。
  • 支持通过解串器方式连接摄像头使用。
  • 支持基于设备列表自动检测摄像头/解串器是否在线并加载驱动。
  • 框架上支持用户自行添加解串器、加串器和摄像头驱动。
  • 支持管理摄像头/解串器的时钟、电源、复位等信号上下电时序。
  • 支持产生可配置频率与占空比的 FSync 信号,供摄像头进行帧同步。

Image Sensor 软件栈设计中,每个摄像头设备作为一个 V4L2 子设备,挂载在 CSI-2 设备上。每个摄像头与 CSI-2 数据流的绑定关系如下图所示:

摄像头与 CSI-2 数据流绑定关系

在 V4L2 软件架构中,CSI-2 设备与摄像头设备是绑定的。因此,当 CSI-2 侧的某个数据流开流时,对应摄像头驱动中的 stream_on 接口会被调用;同理,当 CSI-2 侧该数据流关流时,对应摄像头驱动中的 stream_off 接口会被调用。

需要注意的是,CSI-2 设备并不会管理解串器驱动,它只是基于 V4L2 机制调用摄像头的驱动接口。因此,摄像头驱动应该自行管理解串器驱动,如下图所示:

摄像头驱动与解串器驱动关系

2.2 驱动文件介绍​

文件说明
image_sensor.c负责控制器设备、子设备驱动管理,包含每个摄像头/解串器设备的挂载、初始化、V4L2 驱动封装等。
sensor_power.c提供摄像头/解串器设备的电源、时钟、复位开关 API。
sensor_i2c.c提供摄像头/解串器设备的 I2C API。
sensor_fsync.c提供帧同步管理 API。
sensor_list.c摄像头/解串器设备列表。
max96712.c解串器 MAX96712 的设备驱动文件。
max9295a_gw5200_ar0233.c加串器 MAX9295A 与摄像头 AR0233 的设备驱动文件。

2.3 API 介绍​

m_isensor_add_list​

void m_isensor_add_list(struct image_sensor_drv *ctrl);
  • 入参: ctrl,image sensor 控制器设备的结构体指针。
  • 返回值: 无。
  • 功能描述: 用户须在此函数中,将摄像头/解串器的操作集指针添加进设备列表,用于检测设备。此函数仅支持检测直接挂在 M1000 I2C 总线,或通过 I2C MUX 挂在 M1000 I2C 总线上的设备,不包含挂在加串器 I2C 侧的摄像头设备。

m_isensor_get_func_by_name​

struct m_isensor_func *m_isensor_get_func_by_name(const char *name);
  • 入参: name,连接到加串器侧的摄像头名称。
  • 返回值: 摄像头操作集指针。
  • 功能描述: 对于加串器侧的摄像头设备,用户必须在设备树中指定其名称,并在此函数中添加对比语句,匹配后返回操作集指针。

m_isensor_fsync_start 和 m_isensor_fsync_stop​

s32 m_isensor_fsync_start(struct m_isensor_dev *sdev);
s32 m_isensor_fsync_stop(struct m_isensor_dev *sdev);
  • 入参: sdev,子设备结构体指针。
  • 返回值: 成功返回 0,失败返回错误码。
  • 功能描述: m_isensor_fsync_start 启动帧同步发生器并产生方波;m_isensor_fsync_stop 停止帧同步发生器。如需软件栈提供帧同步功能,用户可在摄像头驱动内调用这两个接口。

m_isensor_power​

void m_isensor_power(struct m_isensor_dev *sdev, bool on);
  • 入参: sdev,子设备结构体指针;on,true 表示上电,false 表示下电。
  • 返回值: 无。
  • 功能描述: 对摄像头/解串器设备进行上下电,同时也包含时钟、复位、PWDN 管脚等开关操作。用户须在操作摄像头设备之前调用此接口上电。

以下是摄像头/解串器设备操作集的驱动接口,用户添加新摄像头驱动时需要逐一实现。

通用操作集接口​

接口说明
u32 i2c_default_addr默认的 7-bit I2C 设备地址,自动检测机制会使用。
void (*get_i2c_default_ops)(i2c_read_t *read, i2c_write_t *write)获取默认 I2C 读写方法。根据设备支持的 I2C 寄存器位数、数据位数对方法指针赋值。参数 read 和 write 分别为 I2C 读写方法的函数指针。
s32 (*detect)(struct m_isensor_dev *sensor, u32 ic_addr)读取摄像头/解串器设备内部寄存器,以检测设备是否在线。ic_addr 为 I2C 设备地址,0 表示使用默认地址检测,其他值表示使用指定地址检测。检测成功返回 I2C 设备地址,失败返回错误码。仅支持直接挂在 M1000 I2C 总线或通过 I2C MUX 挂载的设备。
s32 (*set_num_lanes)(struct m_isensor_dev *sensor, u32 num_lanes)配置摄像头/解串器的 CSI-2 lane 数量。num_lanes 为设备所支持的 CSI-2 lane 数量。加串器侧的摄像头无需配置。
s32 (*init)(struct m_isensor_dev *sensor)摄像头/解串器初始化函数,在子设备驱动 probe() 成功时调用。成功返回 0,失败返回错误码。
void (*deinit)(struct m_isensor_dev *sensor)摄像头/解串器反初始化函数,在子设备驱动 remove() 时调用。

摄像头驱动接口​

以下方法仅由摄像头驱动实现:

接口说明
s32 (*stream_on)(struct m_isensor_dev *sensor)摄像头开流函数。执行成功后,摄像头开始输出数据流。成功返回 0,失败返回错误码。
void (*stream_off)(struct m_isensor_dev *sensor)摄像头关流函数。执行后,摄像头停止输出数据流。
void (*get_cfg)(const struct m_isensor_param_info **info, u32 *num)将摄像头配置列表提供给子设备驱动。info 获取配置列表地址,num 获取配置列表项个数。
s32 (*set_format)(struct m_isensor_dev *sensor, struct v4l2_mbus_framefmt mbus)使用 mbus 参数设置摄像头的输出格式和尺寸。成功返回 0,失败返回错误码。

解串器驱动接口​

以下方法仅由解串器驱动实现:

接口说明
s32 (*check_link_valid)(struct m_isensor_dev *sensor, u32 link)检测 link 编号是否有效。link 为加串器连接到解串器侧的 link 编号,有效返回 0,无效返回错误码。
s32 (*bridge_init)(struct m_isensor_dev *sensor, u32 serdes_fsync_io)解串器专用的初始化函数,由摄像头驱动调用。serdes_fsync_io 为加串器侧输出帧同步信号的管脚号。
void (*bridge_deinit)(struct m_isensor_dev *sensor)解串器专用的反初始化函数,由摄像头驱动调用。
s32 (*bridge_stream_on)(struct m_isensor_dev *sensor, u32 link)解串器开流函数。所连接摄像头的驱动都调用并成功后,解串器才输出 CSI-2 数据流。
void (*bridge_stream_off)(struct m_isensor_dev *sensor, u32 link)解串器关流函数。所连接摄像头的驱动都调用此函数后,解串器停止输出 CSI-2 数据流。
s32 (*monopolize_link)(struct m_isensor_dev *sensor, u32 link_port)使能 link_port 指定的 link,并禁用其他 link,由摄像头驱动调用。
s32 (*setup_pipeline)(struct m_isensor_dev *sensor, u32 link, u32 src_vc, u32 dst_vc, u32 dt)将摄像头/加串器传递过来的 src_vc、dt 映射成解串器输出的 dst_vc、dt,由摄像头驱动调用。link 为解串器侧 link 编号,src_vc 为输入 CSI-2 virtual channel,dst_vc 为映射后的 CSI-2 virtual channel,dt 为输入 CSI-2 data type。

3. 设备树配置说明​

3.1 Image Sensor 控制器设备树​

如下图所示:

Image Sensor 控制器设备树

属性说明
pwr0-gpios所有子设备公用电源控制管脚 1。
pwr1-gpios所有子设备公用电源控制管脚 2。
pwr2-gpios所有子设备公用电源控制管脚 3。
fsync1-gpios配置 GPIO 作为帧同步发生器 1 的输出管脚。
t-fsync1-hi配置帧同步发生器 1 输出高电平的持续时间,单位为微秒。
t-fsync1-lo配置帧同步发生器 1 输出低电平的持续时间,单位为微秒。
fsync-init-state帧同步发生器 1 默认输出电平值。0 为低电平,1 为高电平。

3.2 直连 I2C 总线的摄像头设备树​

如下图所示:

直连 I2C 总线的摄像头设备树

属性说明
auto-detect如果存在此字段,在 Image Sensor 子设备驱动加载时,遍历设备列表中的摄像头/解串器驱动,并使用各自默认的 I2C 设备地址,依次调用 detect() 方法检测在线设备。如果不存在此字段,则使用设备树中 reg 字段作为 I2C 设备地址,遍历设备列表并依次调用 detect() 方法。
reg摄像头的 7-bit I2C 设备地址。auto-detect 字段不存在时,用户须确保该地址有效。
num-lanes摄像头使用的 CSI-2 lane 数量。
pwr0-gpios摄像头电源控制管脚 1。
pwr1-gpios摄像头电源控制管脚 2。
pwr2-gpios摄像头电源控制管脚 3。
reset-gpios摄像头复位管脚。
pdn-gpios摄像头 PWDN 管脚。
clock-frequency提供给摄像头的参考时钟频率。

M1000 Image Sensor 软件栈支持同时配置 4 个管脚作为摄像头的参考时钟输入,在设备树中分别对应 clkout0_default、clkout1_default、clkout2_default、clkout3_default。clock-frequency 的值从 600MHz 时钟源做整数分频而来,因此 24MHz、25MHz 等时钟频率均可支持。

3.3 连接 I2C 总线的解串器设备树​

连接 I2C 总线的解串器设备树

解串器设备可以直连 I2C 总线,也支持通过 I2C MUX(如 PCA9546)挂在 I2C 总线上,上图即为 I2C MUX 方式。deser0 是解串器的设备树节点。

属性说明
auto-detect同 3.2 直连 I2C 总线的摄像头设备树 所述。
reg同 3.2 直连 I2C 总线的摄像头设备树 所述。
num-lanes解串器使用的 CSI-2 lane 数量。
local-fsync-io解串器上用于传输帧同步信号的管脚号。

3.4 加串器及摄像头的设备树​

加串器及摄像头设备树

属性说明
reg加串器的 7-bit I2C 设备地址。
bridge所连接的解串器设备节点。
des-link连接到解串器侧的 link 编号。
sensor-name摄像头名称。
remote-i2c-addr连接加串器的摄像头 7-bit I2C 设备地址。
des-dst-vc映射到解串器侧的 CSI-2 virtual channel 号。
local-fsync-io加串器连接摄像头用于帧同步的管脚号。
remote-fsync控制器设备树中的帧同步发生器名称。当控制器中存在多个帧同步发生器时,须通过此字段绑定其中之一。若不需要帧同步可删除此字段。

4. 添加摄像头驱动示例​

4.1 直连 M1000 I2C 总线方式​

  1. 添加设备树节点,如 3.2 直连 I2C 总线的摄像头设备树 所示。
  2. 在 ./drivers/media/i2c/m1000/image_sensor/v4l2 下添加新摄像头驱动,可以从现有驱动(如 sensor_gc8613.c)复制一份进行修改。
  3. 填充新增摄像头驱动内各个函数的实现。
  4. 在 m_isensor_add_list 函数中,将新增摄像头驱动的操作集指针加入设备列表中,如下图所示。

添加直连摄像头驱动

4.2 连接解串器方式​

  1. 添加解串器设备树节点,如 3.3 连接 I2C 总线的解串器设备树 所示。
  2. 添加加串器及摄像头设备树节点,如 3.4 加串器及摄像头的设备树 所示。
  3. 在 ./drivers/media/i2c/m1000/image_sensor/v4l2 下添加新解串器驱动,可以从现有驱动(如 max96712.c)复制一份进行修改。
  4. 填充新增解串器驱动内各个函数的实现。
  5. 新增加串器与摄像头驱动,命名方式建议为“加串器名+传感器名”,例如 max9295a_gw5200_ar0233.c。
  6. 在 m_isensor_add_list 函数中,将新增解串器驱动的操作集指针加入设备列表中。
  7. 在 m_isensor_get_func_by_name 函数中,添加与设备树摄像头名称一致的判断语句,如下图所示。

添加解串器、加串器及摄像头驱动

5. 调试方法说明​

5.1 摄像头直连 I2C 总线方式​

系统启动后,使用以下命令查看日志,确认摄像头是否被检测到:

dmesg | grep "sensor"

直连摄像头检测日志

如果日志显示没有检测到设备,请依次测量摄像头的:

  • 各路电源是否就绪。
  • 复位、PWDN 管脚变化过程是否符合预期。
  • 参考时钟是否就绪。
  • 抓取 I2C 总线输出,分析发送的设备地址、寄存器地址等是否符合预期。

开流之后,查看数据传输是否正常:

watch -n 1 cat /sys/kernel/debug/videv/info

查看 CSI-2 PHY 是否收到数据且持续跳变,并检查是否有错误状态,具体方法参见 CSI-2 相关文档。

5.2 摄像头连接解串器方式​

系统启动后,使用以下命令查看日志,确认解串器是否被检测到:

dmesg | grep "sensor"

解串器检测日志

如果日志显示没有检测到设备,请依次测量解串器的:

  • 各路电源是否就绪。
  • 复位、PWDN 管脚变化过程是否符合预期。
  • 参考时钟是否就绪。
  • 抓取 I2C 总线输出,分析发送的设备地址、寄存器地址等是否符合预期。

在开流函数中,检查加串器的 I2C 读写是否正常,同时强烈建议将加串器的 I2C 设备地址重映射为设备树 reg 字段指定的值。

如果摄像头也需要在驱动中进行 I2C 读写,请检查 I2C 读写是否正常,同时强烈建议将摄像头的 I2C 设备地址重映射为设备树 remote-i2c-addr 字段指定的值,且此值不能是默认的 I2C 地址。

开流之后,查看数据传输是否正常:

watch -n 1 cat /sys/kernel/debug/videv/info

查看 CSI-2 PHY 是否收到数据且持续跳变,并检查是否有错误状态,具体方法参见 CSI-2 相关文档。

如果 CSI-2 PHY 没有数据跳变,说明没有收到来自解串器的数据流,请依次排查:

  • 查看加串器内部寄存器,是否收到来自摄像头的 CSI-2 数据流。
  • 查看解串器内部寄存器,是否收到来自加串器的 video 数据流。
  • 是否正确配置了解串器 CSI-2 相关寄存器(VC 映射、controller、PHY 等)。
  • 如果摄像头工作于从模式,测量 M1000 输出帧同步信号的波形是否符合预期。
  • 是否正确配置了加串器/解串器帧同步相关管脚的工作模式。