如何适配Sensor#

概述#

K230 Sensor 框架分为驱动层和应用层,底层为硬件层(如 ov9732、ov9286 等 Sensor),中间为驱动层(对应 /dev/sensor_xxx 设备节点),上层通过媒体接口层(kd_mpi_sensor_xxx)和 sensor_ops 实现对 Sensor 的操作。本文将以 IMX219 为例,详细介绍在 RTOS 操作系统中新增 Sensor 适配的完整流程,包括配置、驱动开发、应用层适配、编译运行及问题调试。

1740391632750

开发步骤#

整体配置#

增加 Sensor 开关配置#

~/src/rtsmart/mpp/Kconfig中添加 IMX219 的配置项,支持通过make menuconfig控制该摄像头驱动的启用 / 禁用,并针对不同 CSI 接口(CSI0/CSI1/CSI2)配置 MCLK 使用选项。

menuconfig MPP_ENABLE_SENSOR_IMX219

   bool "Enable IMX219"

   if MPP_ENABLE_SENSOR_IMX219

       config MPP_SENSOR_IMX219_ON_CSI0_USE_CHIP_CLK

           bool "IMX219 On CSI0 Use CHIP MCLK"

           default n

           depends on MPP_ENABLE_CSI_DEV_0

       config MPP_SENSOR_IMX219_ON_CSI1_USE_CHIP_CLK

           bool "IMX219 On CSI1 Use CHIP MCLK"

           default n

           depends on MPP_ENABLE_CSI_DEV_1

       config MPP_SENSOR_IMX219_ON_CSI2_USE_CHIP_CLK

           bool "IMX219 On CSI2 Use CHIP MCLK"

           default n

           depends on MPP_ENABLE_CSI_DEV_2

   endif

驱动层开发#

Makefile 编译配置#

~/src/rtsmart/mpp/kernel/sensor/Makefile中添加 IMX219 的编译规则,确保启用配置后自动编译对应驱动文件。

src-$(CONFIG_MPP_ENABLE_SENSOR_IMX219) += src/imx219/imx219.c

Sensor 模式定义#

~/src/rtsmart/mpp/include/comm/k_sensor_comm.h中,新增 IMX219 支持的分辨率、帧率、CSI 接口组合模式,共 3 种分辨率 ×3 个 CSI 接口 = 9 个宏定义。

typedef enum {

...

#if defined (CONFIG_MPP_ENABLE_SENSOR_IMX219)

   IMX219_MIPI_CSI0_2LANE_3280x2464_21FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI0_2LANE_1920x1080_30FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI0_2LANE_1080x1920_30FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI1_2LANE_3280x2464_21FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI1_2LANE_1920x1080_30FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI1_2LANE_1080x1920_30FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI2_2LANE_3280x2464_21FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI2_2LANE_1920x1080_30FPS_12BIT_LINEAR,

   IMX219_MIPI_CSI2_2LANE_1080x1920_30FPS_12BIT_LINEAR,

#endif

   SENSOR_TYPE_MAX,

} k_vicap_sensor_type;

开机扫描检测配置#

在驱动初始化扫描逻辑中添加 IMX219 的检测支持,包括探针函数注册和类型名称映射。

探针函数注册#

修改~/src/rtsmart/mpp/kernel/sensor/src/sensor_dev.c,在sensor_probes数组中添加 IMX219 的探针函数,在sth_table中添加模式名称映射。

static sensor_probe_impl sensor_probes[] = {

...

#if defined (CONFIG_MPP_ENABLE_SENSOR_IMX219)

   sensor_imx219_probe,

#endif // CONFIG_MPP_ENABLE_SENSOR_BF3238

   0, // end

};

static const struct sensor_type_name sth_table[] = {

...

#if defined (CONFIG_MPP_ENABLE_SENSOR_IMX219)

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI0_2LANE_3280x2464_21FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI0_2LANE_1920x1080_30FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI0_2LANE_1080x1920_30FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI1_2LANE_3280x2464_21FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI1_2LANE_1920x1080_30FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI1_2LANE_1080x1920_30FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI2_2LANE_3280x2464_21FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI2_2LANE_1920x1080_30FPS_12BIT_LINEAR),

   SENSOR_TYPE_NAME(IMX219_MIPI_CSI2_2LANE_1080x1920_30FPS_12BIT_LINEAR),

#endif

   /* last type set to U32 MAX */

   {__UINT32_MAX__, "UNKNOWN"},

};
探针函数声明#

~/src/rtsmart/mpp/kernel/sensor/src/sensor_dev.h中声明 IMX219 的探针函数。

extern k_s32 sensor_imx219_probe(struct k_sensor_probe_cfg *cfg, struct sensor_driver_dev *dev);

驱动文件目录创建#

拷贝现有类似 Sensor(如 gc2093)的驱动目录,修改为 IMX219 专属目录及文件名称。

cp -rf gc2093 imx219

cd imx219

mv gc2093.c imx219.c

# 新增目录结构如下

aaa@DESKTOP-OSN5BJK:~/canmv_k230_mmp/src/rtsmart/mpp/kernel/sensor/src/imx219$ ls

imx219.c  sensor_csi0_mode_list.c  sensor_csi1_mode_list.c  sensor_csi2_mode_list.c  sensor_reg_table.c

寄存器配置#

针对 3 种分辨率模式,添加对应的寄存器初始化序列(需从摄像头模组厂获取),序列以{REG_NULL, 0x00}结束。

/* MCLK:24MHz  3280x2464  21.2fps   MIPI LANE2 */

static const k_sensor_reg imx219_mipi2lane_3280_2464_21fps[] = {

   {0x30EB, 0x05},     /* Access Code for address over 0x3000 */

   {0x30EB, 0x0C},     /* Access Code for address over 0x3000 */

   {0x300A, 0xFF},     /* Access Code for address over 0x3000 */

   {0x300B, 0xFF},     /* Access Code for address over 0x3000 */

   {0x30EB, 0x05},     /* Access Code for address over 0x3000 */

   {0x30EB, 0x09},     /* Access Code for address over 0x3000 */

   {0x0114, 0x01},     /* CSI_LANE_MODE[1:0} */

   {0x0128, 0x00},     /* DPHY_CNTRL */

   {0x012A, 0x18},     /* EXCK_FREQ[15:8] */

   {0x012B, 0x00},     /* EXCK_FREQ[7:0] */

   {0x015A, 0x01},     /* INTEG TIME[15:8] */

   {0x015B, 0xF4},     /* INTEG TIME[7:0] */

   {0x0160, 0x09},     /* FRM_LENGTH_A[15:8] */

   {0x0161, 0xC4},     /* FRM_LENGTH_A[7:0] */

   {0x0162, 0x0D},     /* LINE_LENGTH_A[15:8] */

   {0x0163, 0x78},     /* LINE_LENGTH_A[7:0] */

   {0x0260, 0x09},     /* FRM_LENGTH_B[15:8] */

   {0x0261, 0xC4},     /* FRM_LENGTH_B[7:0] */

   {0x0262, 0x0D},     /* LINE_LENGTH_B[15:8] */

   {0x0263, 0x78},     /* LINE_LENGTH_B[7:0] */

   {0x0170, 0x01},     /* X_ODD_INC_A[2:0] */

   {0x0171, 0x01},     /* Y_ODD_INC_A[2:0] */

   {0x0270, 0x01},     /* X_ODD_INC_B[2:0] */

   {0x0271, 0x01},     /* Y_ODD_INC_B[2:0] */

   {0x0174, 0x00},     /* BINNING_MODE_H_A */

   {0x0175, 0x00},     /* BINNING_MODE_V_A */

   {0x0274, 0x00},     /* BINNING_MODE_H_B */

   {0x0275, 0x00},     /* BINNING_MODE_V_B */

   {0x018C, 0x0A},     /* CSI_DATA_FORMAT_A[15:8] */

   {0x018D, 0x0A},     /* CSI_DATA_FORMAT_A[7:0] */

   {0x028C, 0x0A},     /* CSI_DATA_FORMAT_B[15:8] */

   {0x028D, 0x0A},     /* CSI_DATA_FORMAT_B[7:0] */

   {0x0301, 0x05},     /* VTPXCK_DIV */

   {0x0303, 0x01},     /* VTSYCK_DIV */

   {0x0304, 0x03},     /* PREPLLCK_VT_DIV[3:0] */

   {0x0305, 0x03},     /* PREPLLCK_OP_DIV[3:0] */

   {0x0306, 0x00},     /* PLL_VT_MPY[10:8] */

   {0x0307, 0x39},     /* PLL_VT_MPY[7:0] */

   {0x0309, 0x0A},     /* OPPXCK_DIV[4:0] */

   {0x030B, 0x01},     /* OPSYCK_DIV */

   {0x030C, 0x00},     /* PLL_OP_MPY[10:8] */

   {0x030D, 0x72},     /* PLL_OP_MPY[7:0] */

   {0x455E, 0x00},     /* CIS Tuning */

   {0x471E, 0x4B},     /* CIS Tuning */

   {0x4767, 0x0F},     /* CIS Tuning */

   {0x4750, 0x14},     /* CIS Tuning */

   {0x47B4, 0x14},     /* CIS Tuning */

   {REG_NULL, 0x00},

};

/* MCLK:24MHz  1920x1080  30fps   MIPI LANE2 */

static const k_sensor_reg imx219_mipi2lane_1920_1080_30fps[] = {

   {0x30eb, 0x05},

   {0x30eb, 0x0c},

   {0x300a, 0xff},

   {0x300b, 0xff},

   {0x30eb, 0x05},

   {0x30eb, 0x09},

   {0x0114, 0x01}, //REG_CSI_LANE 01 -2lanes 03-4lanes

   {0x0128, 0x00}, //REG_DPHY_CTRL

   {0x012a, 0x18}, //REG_EXCK_FREQ_MSB

   {0x012b, 0x00}, //REG_EXCK_FREQ_LSB

   {0x0160, 0x04},//FRM_LENGTH_A[15:8] 1166

   {0x0161, 0x8e},//FRM_LENGTH_A[7:0] 1166    

   {0x0162, 0x0d},//0x0d},//LINE_LENGTH_A[15:8] 3448

   {0x0163, 0x94},//0x78},//LINE_LENGTH_A[7:0]

   {0x0164, 0x02}, //X_ADD_STA_A[11:8]

   {0x0165, 0xa8},//X_ADD_STA_A[7:0]

   {0x0166, 0x0a}, //X_ADD_END_A[11:8]

   {0x0167, 0x27}, //X_ADD_END_A[7:0]

   {0x0168, 0x02},//Y_ADD_STA_A[11:8]

   {0x0169, 0xb4},//Y_ADD_STA_A[7:0]

   {0x016a, 0x06},//Y_ADD_END_A[11:8]

   {0x016b, 0xeb},//Y_ADD_END_A[7:0]

   {0x016c, 0x07},//x_output_size[11:8]

   {0x016d, 0x80},//x_output_size[7:0]

   {0x016e, 0x04},//y_output_size[11:8]

   {0x016f, 0x38},// y_output_size[7:0]

   {0x0170, 0x01},//X_ODD_INC_A

   {0x0171, 0x01},//Y_ODD_INC_A

   {0x0174, 0x00},//BINNING_MODE_H_A

   {0x0175, 0x00},//BINNING_MODE_V_A

   {0x0301, 0x05},//VTPXCK_DIV

   {0x0303, 0x01},//VTSYCK_DIV

   {0x0304, 0x03},//PREPLLCK_VT_DIV

   {0x0305, 0x03},//PREPLLCK_OP_DIV

   {0x0306, 0x00},//PLL_VT_MPY[10:8]

   {0x0307, 0x26},//0x25},//PLL_VT_MPY[7:0] 0x39

   {0x030b, 0x01},//OPSYCK_DIV

   {0x030c, 0x00},//PLL_OP_MPY[10:8]

   {0x030d, 0x30},//PLL_OP_MPY[7:0] 0x72

   {0x0624, 0x07},

   {0x0625, 0x80},

   {0x0626, 0x04},

   {0x0627, 0x38},

   {0x455e, 0x00},

   {0x471e, 0x4b},

   {0x4767, 0x0f},

   {0x4750, 0x14},

   {0x4540, 0x00},

   {0x47b4, 0x14},

   {0x4713, 0x30},

   {0x478b, 0x10},

   {0x478f, 0x10},

   {0x4793, 0x10},

   {0x4797, 0x0e},

   {0x479b, 0x0e},

   {0x0157, 0x40},

   {REG_NULL, 0x00},

};

/* MCLK:24MHz  1080x1920  30fps   MIPI LANE2 */

static const k_sensor_reg imx219_mipi2lane_1080_1920_30fps[] = {

   //Access command sequence

   {0x30eb, 0x05},

   {0x30eb, 0x0c},

   {0x300a, 0xff},

   {0x300b, 0xff},

   {0x30eb, 0x05},

   {0x30eb, 0x09},

   {0x0114, 0x01}, //REG_CSI_LANE 01 -2lanes 03-4lanes

   {0x0128, 0x00}, //REG_DPHY_CTRL

   {0x012a, 0x18}, //REG_EXCK_FREQ_MSB

   {0x012b, 0x00}, //REG_EXCK_FREQ_LSB

   {0x0160, 0x08},//FRM_LENGTH_A[15:8] 1166

   {0x0161, 0x98},//FRM_LENGTH_A[7:0] 1166    

   {0x0162, 0x0d},//0x0d},//LINE_LENGTH_A[15:8] 3476

   {0x0163, 0x94},//0x78},//LINE_LENGTH_A[7:0]

   {0x0164, 0x02}, //X_ADD_STA_A[11:8]    680 + 1080 - 1                      3476 * 2200

   {0x0165, 0xb4},//X_ADD_STA_A[7:0]

   {0x0166, 0x06}, //X_ADD_END_A[11:8]  1771

   {0x0167, 0xeb}, //X_ADD_END_A[7:0]

   {0x0168, 0x01},//Y_ADD_STA_A[11:8]

   {0x0169, 0x00},//Y_ADD_STA_A[7:0]

   {0x016a, 0x08},//Y_ADD_END_A[11:8]          2175   

   {0x016b, 0x7f},//Y_ADD_END_A[7:0]

   {0x016c, 0x04},//x_output_size[11:8]

   {0x016d, 0x38},//x_output_size[7:0]

   {0x016e, 0x07},//y_output_size[11:8]

   {0x016f, 0x80},// y_output_size[7:0]

   {0x0170, 0x01},//X_ODD_INC_A

   {0x0171, 0x01},//Y_ODD_INC_A

   {0x0172, 0x00},//IMG_ORIENTATION_A

   {0x0174, 0x00},//BINNING_MODE_H_A

   {0x0175, 0x00},//BINNING_MODE_V_A

   {0x0301, 0x05},//VTPXCK_DIV

   {0x0303, 0x01},//VTSYCK_DIV

   {0x0304, 0x03},//PREPLLCK_VT_DIV

   {0x0305, 0x03},//PREPLLCK_OP_DIV

   {0x0306, 0x00},//PLL_VT_MPY[10:8]

   {0x0307, 0x48},//0x25},//PLL_VT_MPY[7:0] 0x39

   {0x030b, 0x01},//OPSYCK_DIV

   {0x030c, 0x00},//PLL_OP_MPY[10:8]

   {0x030d, 0x40},//PLL_OP_MPY[7:0] 0x72  0x56  0x51  0x40

   {0x0624, 0x07},

   {0x0625, 0x80},

   {0x0626, 0x04},

   {0x0627, 0x38},

   {0x455e, 0x00},

   {0x471e, 0x4b},

   {0x4767, 0x0f},

   {0x4750, 0x14},

   {0x4540, 0x00},

   {0x47b4, 0x14},

   {0x4713, 0x30},

   {0x478b, 0x10},

   {0x478f, 0x10},

   {0x4793, 0x10},

   {0x4797, 0x0e},

   {0x479b, 0x0e},

   {0x0157, 0x40},

   { REG_NULL, 0x00 }

};

CSI 模式配置(sensor_csi*_mode_list.c)#

修改sensor_csi0_mode_list.csensor_csi1_mode_list.csensor_csi2_mode_list.c,添加对应 CSI 接口的模式配置,包括分辨率、帧率、MIPI 通道数、数据格式等参数(注:目前仅 CSI0 支持 MCLK)。

static const k_sensor_mode sensor_csi0_mode_list[] = {

   {

       .index = 0,

       .sensor_type = IMX219_MIPI_CSI0_2LANE_1920x1080_30FPS_12BIT_LINEAR,

       .size = {

           .bounds_width = 1920,

           .bounds_height = 1080,

           .top = 0,

           .left = 0,

           .width = 1920,

           .height = 1080,

       },

       .fps = 30000,

       .hdr_mode = SENSOR_MODE_LINEAR,

       .bit_width = 10,

       .bayer_pattern = BAYER_PAT_RGGB, //BAYER_PAT_RGGB,

       .mipi_info = {

           .csi_id = 0,

           .mipi_lanes = 2,

           .data_type = 0x2B,

       },

#if defined (CONFIG_MPP_SENSOR_GC2093_ON_CSI0_USE_CHIP_CLK)

       .mclk_setting = {

           {

               .mclk_setting_en = K_TRUE,

               .setting.id = CONFIG_MPP_CSI_DEV0_MCLK_NUM,

               .setting.mclk_sel = SENSOR_PLL1_CLK_DIV4,

               .setting.mclk_div = 25, // 594/25 = 23.76MHz

           },

           {K_FALSE},

           {K_FALSE},

       },

       .reg_list = gc2093_mipi2lane_1080p_30fps_linear,

       .sensor_ae_info = &sensor_csi0_ae_info[0],

#else

       .mclk_setting = {

           {K_FALSE},

           {K_FALSE},

           {K_FALSE},

       },

       .reg_list = gc2093_mipi2lane_1080p_30fps_mclk_24m_linear,

       .sensor_ae_info = &sensor_csi0_ae_info[4],

#endif

   },

};

AE 参数配置#

sensor_csi*_mode_list.c中添加自动曝光(AE)参数配置,包括帧长、曝光时间增量、增益范围等。

static k_sensor_ae_info sensor_csi2_ae_info[] = {

    // list  for external  clk 23.76M

   // 1920x1080

   {

       .frame_length = 1206,

       .cur_frame_length = 1206,

       .one_line_exp_time = 0.000027652,

       .gain_accuracy = 1024,

       .min_gain = 1,

       .max_gain = 18,

       .int_time_delay_frame = 2,

       .gain_delay_frame = 2,

       .color_type = SENSOR_COLOR,

       .integration_time_increment = 0.000027652, // 计算方式:1000/(FPS×frame_length) = 1000/(30×1166)≈0.02858

       .gain_increment = IMX219_MIN_GAIN_STEP,

       .max_integraion_line = 1206 - 1,

       .min_integraion_line = 1,

       .max_integraion_time = 0.000027652 * (1206 - 1),

       .min_integraion_time = 0.000027652 * 1,

       .cur_integration_time = 0.0,

       .cur_again = 1.0,

       .cur_dgain = 1.0,

       .a_gain = {

           .min = 1.0,

           .max = 63.984375,

           .step = (1.0f/64.0f),

       },

       .d_gain = {

           .min = 1.0,

           .max = 63.984375,

           .step = (1.0f/1024.0f),

       },

       .cur_fps = 30,

   },

};

核心驱动实现(imx219.c)#

寄存器定义#

根据 IMX219 芯片手册,定义芯片 ID、曝光、增益等关键寄存器地址。

/* Chip ID */

#define IMX219_CHIP_ID                  (219)

#define IMX219_REG_ID                   (0x10)  

/* Exposure control */

#define IMX219_REG_EXP_SHORT_TIME_H     (0x018a)

#define IMX219_REG_EXP_SHORT_TIME_L     (0x018b)

#define IMX219_REG_EXP_TIME_H           (0x015a)

#define IMX219_REG_EXP_TIME_L           (0x015b)

/* Analog gain control */

#define IMX219_REG_DGAIN_H              (0x0158)

#define IMX219_REG_DGAIN_L              (0x0159)

#define IMX219_MIN_GAIN_STEP            (1.0f/64.0f)
探针函数实现#

开机时通过 I2C 读取芯片 ID,确认 IMX219 是否接入,并初始化对应 CSI 接口的模式列表。

k_s32 sensor_imx219_probe(struct k_sensor_probe_cfg *cfg, struct sensor_driver_dev *dev)

{

   k_s32 ret = 0;

   k_u32 chip_id = 0;

   const k_sensor_mode *sensor_mode = NULL;

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_0)

   if(0x00 == cfg->csi_num) {

       dev->mode_count = sizeof(sensor_csi0_mode_list) / sizeof(sensor_csi0_mode_list[0]);

       dev->sensor_mode_list = &sensor_csi0_mode_list[0];

       sensor_mode = &dev->sensor_mode_list[0];

   } else

#endif // CONFIG_MPP_ENABLE_CSI_DEV_0

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_1)

   if(0x01 == cfg->csi_num) {

       dev->mode_count = sizeof(sensor_csi1_mode_list) / sizeof(sensor_csi1_mode_list[0]);

       dev->sensor_mode_list = &sensor_csi1_mode_list[0];

       sensor_mode = &dev->sensor_mode_list[0];

   } else

#endif // CONFIG_MPP_ENABLE_CSI_DEV_1

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_2)

   if(0x02 == cfg->csi_num) {

       dev->mode_count = sizeof(sensor_csi2_mode_list) / sizeof(sensor_csi2_mode_list[0]);

       dev->sensor_mode_list = &sensor_csi2_mode_list[0];

       sensor_mode = &dev->sensor_mode_list[0];

   }

#endif // CONFIG_MPP_ENABLE_CSI_DEV_2

   if(0x00 == dev->mode_count) {

       goto _on_failed;

   }

   if(NULL == sensor_mode) {

       rt_kprintf("FATAL error, %sn", __func__);

       goto _on_failed;

   }

   /* update dev */

   dev->pwd_gpio = cfg->pwd_gpio;

   dev->reset_gpio = cfg->reset_gpio;

   if(NULL == (dev->i2c_info.i2c_bus = rt_i2c_bus_device_find(cfg->i2c_name))) {

       rt_kprintf("Can't find %sn", cfg->i2c_name);

       goto _on_failed;

   }

   strncpy(&dev->i2c_info.i2c_name[0], cfg->i2c_name, sizeof(dev->i2c_info.i2c_name));

   memcpy(&dev->sensor_func, &sensor_functions, sizeof(k_sensor_function));

   //设置时钟

   sensor_set_mclk(&sensor_mode->mclk_setting[0]);

   /** NEW SENSOR MODIFY START */

   snprintf(dev->sensor_name, sizeof(dev->sensor_name), "imx219_csi%d", cfg->csi_num);

   //设置power上电

   _sensor_power_state_set(dev, 1, 1);

   /* probe different slave address */

   dev->i2c_info.reg_addr_size = SENSOR_REG_VALUE_16BIT;

   dev->i2c_info.reg_val_size = SENSOR_REG_VALUE_8BIT;

   dev->i2c_info.slave_addr = 0x10;

   //读取chip ID

   if((0x00 != _sensor_read_chip_id_r(dev, &chip_id))) {

       _sensor_power_state_set(dev, 1, 1);

       goto _on_failed;

   }

   /** NEW SENSOR MODIFY END */

   return 0;

_on_failed:

   memset(dev, 0, sizeof(*dev));

   return -1;

}
传感器功能函数映射#

实现 Sensor 的电源控制、初始化、参数配置(增益、曝光、帧率等)函数映射,下面标注的必须实现的函数需要根据摄像头datasheet文档完成参数配置。

static const k_sensor_function sensor_functions = {
//sensor 上电初始化(必须实现)
   .sensor_power = sensor_power_impl,
//初始化配置函数,用来对sensor reset,gpio控制等(必须实现)
   .sensor_init = sensor_init_impl, 
//读取sensor chip id(必须实现)
   .sensor_get_chip_id = sensor_get_chip_id_impl,
//获取当前模式,可以参考其他sensor实现(必须实现)
   .sensor_get_mode = sensor_get_mode_impl,
//设置当前模式,进行模式切换,可以参考其他sensor实现(必须实现)
   .sensor_set_mode = sensor_set_mode_impl,
//列举当前支持的模式,可以参考其他sensor实现(必须实现)
   .sensor_enum_mode = sensor_enum_mode_impl,
//获取当前sensor的能力,包括位宽、分辨率和RAW格式(必须实现)
   .sensor_get_caps = sensor_get_caps_impl,
//获取当前设备的连接状态
   .sensor_conn_check = sensor_conn_check_impl,
//使能或者关闭码流(必须实现)
   .sensor_set_stream = sensor_set_stream_impl,
//获取当前的again(必须实现)
   .sensor_get_again = sensor_get_again_impl,
//设置当前的again(必须实现)
   .sensor_set_again = sensor_set_again_impl,
//获取当前的Dgain
   .sensor_get_dgain = sensor_get_dgain_impl,
//设置当前的Dgain
   .sensor_set_dgain = sensor_set_dgain_impl,
//获取当前的曝光时间(必须实现)
   .sensor_get_intg_time = sensor_get_intg_time_impl,
//设置当前的曝光时间(必须实现)
   .sensor_set_intg_time = sensor_set_intg_time_impl,
//获取当前曝光参数
   .sensor_get_exp_parm = sensor_get_exp_parm_impl,
//设置当前曝光参数
   .sensor_set_exp_parm = sensor_set_exp_parm_impl,
//获取当前的帧率
   .sensor_get_fps = sensor_get_fps_impl,
//设置当前帧率
   .sensor_set_fps = sensor_set_fps_impl,
//获取当前ISP状态
   .sensor_get_isp_status = sensor_get_isp_status_impl,
//设置blc
   .sensor_set_blc = sensor_set_blc_impl,
//设置wb
   .sensor_set_wb = sensor_set_wb_impl,
//获取tpg配置
   .sensor_get_tpg = sensor_get_tpg_impl,
//设置tpg
   .sensor_set_tpg = sensor_set_tpg_impl,
//读取expand_curve数据
   .sensor_get_expand_curve = sensor_get_expand_curve_impl,
//读取sensor otp数据
   .sensor_get_otp_data = sensor_get_otp_data_impl,
//设置sensor mirror
   .sensor_mirror_set = sensor_mirror_set_impl,
//自动对焦相关函数,设置对焦距离
   .sensor_set_focus_pos = sensor_autofocus_dev_set_position,
//自动对焦相关函数,获取对焦距离
   .sensor_get_focus_pos = sensor_autofocus_dev_get_position,
//自动对焦相关函数,获取自动对焦能力
   .sensor_get_foucs_cap = sensor_autofocus_dev_get_capability,
//自动对焦相关函数,设置自动对焦上电
   .sensor_set_focus_power = sensor_autofocus_dev_power,

};

应用层适配#

Sensor 类型映射#

~/src/rtsmart/mpp/userapps/src/sensor/mpi_sensor_type_to_mirror.c中,添加 IMX219 的模式与镜像配置映射(根据开发板型号适配)。

#elif defined(CONFIG_BOARD_K230_CANMV_01STUDIO)

static struct sensor_type_mirror_t type_mirror_tbl[] = {

...

#if defined (CONFIG_MPP_ENABLE_SENSOR_IMX219)

   {.type = IMX219_MIPI_CSI0_2LANE_1920x1080_30FPS_10BIT_LINEAR, .mirror = 0},

   {.type = IMX219_MIPI_CSI0_2LANE_1080x1920_30FPS_10BIT_LINEAR, .mirror = 0},

   {.type = IMX219_MIPI_CSI1_2LANE_1920x1080_30FPS_10BIT_LINEAR, .mirror = 0},

   {.type = IMX219_MIPI_CSI1_2LANE_1080x1920_30FPS_10BIT_LINEAR, .mirror = 0},

   {.type = IMX219_MIPI_CSI2_2LANE_1920x1080_30FPS_10BIT_LINEAR, .mirror = 0},

   {.type = IMX219_MIPI_CSI2_2LANE_1080x1920_30FPS_10BIT_LINEAR, .mirror = 0},

#endif // CONFIG_MPP_ENABLE_SENSOR_IMX219

};

默认配置添加#

~/src/rtsmart/mpp/userapps/src/sensor/mpi_sensor.c中,添加 IMX219 的默认参数配置,包括 CSI 接口、分辨率、帧率、数据格式等。

static const k_vicap_sensor_info sensor_info_list[] = {

...

#if defined (CONFIG_MPP_ENABLE_SENSOR_IMX219)

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_0)

   {

       "imx219_csi0",

       "imx219-1920x1080",

       1920,

       1080,

       VICAP_CSI0,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI0,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       30,

       IMX219_MIPI_CSI0_2LANE_1920x1080_30FPS_10BIT_LINEAR,

   },

   {

       "imx219_csi0",

       "imx219-1080x1920",

       1080,

       1920,

       VICAP_CSI0,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI0,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       60,

       IMX219_MIPI_CSI0_2LANE_1080x1920_30FPS_10BIT_LINEAR,

   },

#endif // CONFIG_MPP_ENABLE_CSI_DEV_0

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_1)

   {

       "imx219_csi1",

       "imx219-1920x1080",

       1920,

       1080,

       VICAP_CSI1,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI1,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       30,

       IMX219_MIPI_CSI1_2LANE_1920x1080_30FPS_10BIT_LINEAR,

   },

   {

       "imx219_csi1",

       "imx219-1080x1920",

       1080,

       1920,

       VICAP_CSI1,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI1,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       60,

       IMX219_MIPI_CSI1_2LANE_1080x1920_30FPS_10BIT_LINEAR,

   },

#endif // CONFIG_MPP_ENABLE_CSI_DEV_1

#if defined (CONFIG_MPP_ENABLE_CSI_DEV_2)

   {

       "imx219_csi2",

       "imx219-1920x1080",

       1920,

       1080,

       VICAP_CSI2,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI2,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       30,

       IMX219_MIPI_CSI2_2LANE_1920x1080_30FPS_10BIT_LINEAR,

   },

   {

       "imx219_csi2",

       "imx219-1080x1920",

       1080,

       1920,

       VICAP_CSI2,

       VICAP_MIPI_2LANE,

       VICAP_SOURCE_CSI2,

       K_FALSE,

       VICAP_MIPI_PHY_1200M,

       VICAP_CSI_DATA_TYPE_RAW10,

       VICAP_LINERA_MODE,

       VICAP_FLASH_DISABLE,

       VICAP_VI_FIRST_FRAME_FS_TR0,

       0,

       30,

       IMX219_MIPI_CSI2_2LANE_1080x1920_30FPS_10BIT_LINEAR,

   },

#endif // CONFIG_MPP_ENABLE_CSI_DEV_2

#endif // CONFIG_MPP_ENABLE_SENSOR_IMX219

...

};

ISP 配置文件添加#

~/src/rtsmart/mpp/userapps/src/sensor/config目录下,添加 IMX219 对应分辨率的 ISP 配置文件(xml/json 格式)。

zhangchenli@DESKTOP-OSN5BJK:~/canmv_k230_mmp/src/rtsmart/mpp/userapps/src/sensor/config$ ls imx219*

imx219-1920x1080.xml  imx219-1920x1080_auto.json  imx219_1920x1080_manual.json

编译拷贝配置#

~/src/rtsmart/Makefile中添加配置,确保编译时自动拷贝 IMX219 的应用层文件到镜像目录。

ifeq ($(CONFIG_MPP_ENABLE_SENSOR_IMX219),y)

   @rsync -a --delete $(SDK_RTSMART_SRC_DIR)/rtsmart/userapps/root/bin/imx219-* ${SDK_BUILD_IMAGES_DIR}/bin/

endif

编译运行#

  • 执行make menuconfig,在MPP配置中启用IMX219 Sensor 支持

  • 回到 RTOS 根目录,执行make编译生成镜像

  • 使用烧录工具(如 rufus)将镜像写入 TF 卡

  • 将 TF 卡插入开发板,上电启动,验证 IMX219 是否正常工作

问题调试#

黑屏问题排查#

若对接后显示黑屏,按以下步骤排查:

步骤 1:查看 ISP 状态#

通过命令查看 ISP 是否有数据输入:

msh /sdcard>cat /proc/umap/vicap

----------------------------------ISP STATUS INFO----------------------------------

ISP-DEV         ISP-Interrups   MI-Interrups    FE-Interrups

0               0               0               0

1               0               0               0

2               0               0               0

ISP-DEV         MCMW0-Interrups MCMW1-Interrups MCMW2-Interrups RDMA-Interrups

0               0               0               0               0

1               0               0               0               0

2               0               0               0               0

ISP-DEV         MP-Interrups    SP1-Interrups   SP2-Interrups   ISP-OUT-Interrups

0               0               0               0               0

1               0               0               0               0

2               0               0               0               0

ISP-DEV         MIS-Interrups   MIS1-Interrups  MIS2-Interrups  MIS3-Interrups

0               0               0               0               0

1               0               0               0               0

2               0               0               0               0

ISP-DEV         Input-Frames    Output0-Frames  Output1-Frames  Output2-Frames

0               0               0               0               0

1               0               0               0               0

2               0               0               0               0

ISP-DEV         INPUT           OUTPUT0                         OUTPUT1                         OUTPUT2                      

0               1920x1080       1920x1080@YUV_SEMIPLANAR_420    N/A                             N/A                         

ISP-DEV         AE      AWB     CCM     2DNR    3DNR    DEWARP

0               On      On      On      On      Off     Off
  • 若所有Input-Frames为 0,说明 Sensor 端无数据输出,需检查 Sensor 驱动或硬件连接。

步骤 2:验证 I2C 通信#

通过i2c_read命令读取 IMX219 寄存器,确认 I2C 通信是否正常:

msh />i2c_read -h

USAGE: i2c_read i2c_id salve_addr reg_addr

msh />i2c_read 0 0x10 0x3a0a

i2c_read 0 0x10 0x3a0a

0x3a0a=0x00
步骤 3:检查 CSI 寄存器状态#

读取 CSI 接口对应的寄存器值,确认 CSI 是否正常配置:

msh />devmem2 0x9000980c  # CSI0寄存器地址:0x9000980c;CSI1:0x9000a00c;CSI2:0x9000a80c

Value at address 0x9000980C (00000000c00d280c): 0x0
步骤 4:调整 MIPI PHY 频率#

MIPI CSI PHY 仅支持VICAP_MIPI_PHY_800MVICAP_MIPI_PHY_1200M,若频率不匹配会导致数据传输失败,需在应用层配置中切换尝试:

/**
* @brief Defines the MIPI CSI PHY freq
**/
typedef enum {

   VICAP_MIPI_PHY_800M  = 1,

   VICAP_MIPI_PHY_1200M = 2,

   VICAP_MIPI_PHY_1600M = 3, // 不支持,需排除

} k_vicap_mipi_phy_freq;
评论列表
条评论
登录