---
title: 完成初始化序列配置
description: "配置初始化序列，建议参考版本发布包里面的Sensor驱动，以便于快速开发。为了方便调试，此时要排除AE配置及帧率配置的干扰，建议暂时空实现驱动中cmos_get_sns_regs_info函数。"
url: https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/latest/others/ispdevug/ispdevug_0015.html
sourcePath: /source/zh/CANNCommunityEdition/920beta1/others/ispdevug/ispdevug_0015.html
indexId: 9a1663fecdd0c3a88fd0c2ef1339b4c6c2c5696560bfc5d250116bc4dd20927e75
---
# 完成初始化序列配置

配置初始化序列，建议参考版本发布包里面的Sensor驱动，以便于快速开发。为了方便调试，此时要排除AE配置及帧率配置的干扰，建议暂时空实现驱动中cmos_get_sns_regs_info函数。

1. 准备Sensor驱动

  - 依据sensor datasheet或基于一款规格相近Sensor（master/slave, i2c/spi, wdr/linear）驱动修改，尝试编译出Sensor库。具体可参看xxx_cmos.c（主要实现ISP需要的回调函数，包括ISP、AE、AWB等）、xxx_cmos.h和xxx_sensor_ctl.c（主要实现Sensor的读写初始化）文件进行修改。
  - 声明并初始化对应的Sensor实例

```
hi_isp_sns_obj g_sns_xxx_obj = {
.pfn_register_callback     = sensor_register_callback,
.pfn_un_register_callback  = sensor_unregister_callback,
.pfn_standby               = xxx_standby,
.pfn_restart               = xxx_restart,
.pfn_write_reg             = xxx_write_register,
.pfn_read_reg              = xxx_read_register,
.pfn_set_bus_info          = xxx_set_bus_info,
.pfn_set_init              = sensor_set_init
};
```


    其中hi_isp_sns_obj结构体可以由用户增加或减少对应的函数及功能，目前的实现为：

```
typedef struct {
hi_s32  (*pfn_register_callback)(hi_vi_pipe vi_pipe, hi_isp_3a_alg_lib *ae_lib, hi_isp_3a_alg_lib *awb_lib);
hi_s32  (*pfn_un_register_callback)(hi_vi_pipe vi_pipe, hi_isp_3a_alg_lib *ae_lib, hi_isp_3a_alg_lib *awb_lib);
hi_s32  (*pfn_set_bus_info)(hi_vi_pipe vi_pipe, hi_isp_sns_commbus sns_bus_info);
hi_void (*pfn_standby)(hi_vi_pipe vi_pipe);
hi_void (*pfn_restart)(hi_vi_pipe vi_pipe);
hi_void (*pfn_mirror_flip)(hi_vi_pipe vi_pipe, hi_isp_sns_mirrorflip_type sns_mirror_flip);
hi_s32  (*pfn_write_reg)(hi_vi_pipe vi_pipe, hi_u32 addr, hi_u32 data);
hi_s32  (*pfn_read_reg)(hi_vi_pipe vi_pipe, hi_u32 addr);
hi_s32  (*pfn_set_init)(hi_vi_pipe vi_pipe, hi_isp_init_attr *init_attr);
} hi_isp_sns_obj;
```


  - 实现ISP回调函数指针注册，并依据需要实现部分函数或者设置为NULL，具体函数功能及说明请参见《DVPP媒体加速库(https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/920beta1/acce/dvpp/dvpp_03_0000.html)》，本节主要实现Sensor初始化。

```
static hi_s32 cmos_init_ae_exp_function(hi_isp_ae_sensor_exp_func *pstExpFuncs)
{
memset_s(pstExpFuncs, sizeof(hi_isp_ae_sensor_exp_func), 0, sizeof(hi_isp_ae_sensor_exp_func));
pstExpFuncs->pfn_cmos_get_ae_default    = cmos_get_ae_default;
pstExpFuncs->pfn_cmos_fps_set           = cmos_fps_set;
pstExpFuncs->pfn_cmos_slow_framerate_set = cmos_slow_framerate_set;
pstExpFuncs->pfn_cmos_inttime_update    = cmos_inttime_update;
pstExpFuncs->pfn_cmos_gains_update      = cmos_gains_update;
pstExpFuncs->pfn_cmos_again_calc_table  = cmos_again_calc_table;
pstExpFuncs->pfn_cmos_dgain_calc_table  = cmos_dgain_calc_table;
pstExpFuncs->pfn_cmos_get_inttime_max   = cmos_get_inttime_max;
pstExpFuncs->pfn_cmos_ae_fswdr_attr_set = cmos_ae_fswdr_attr_set;
pstExpFuncs->pfn_cmos_ae_quick_start_status_set = cmos_ae_quick_start_status_set;
pstExpFuncs->pfn_cmos_exp_param_convert = cmos_exp_param_convert;
return HI_SUCCESS;
}
static hi_s32 cmos_init_awb_exp_function(hi_isp_awb_sensor_exp_func *pstExpFuncs)
{
memset_s(pstExpFuncs, sizeof(hi_isp_awb_sensor_exp_func), 0, sizeof(hi_isp_awb_sensor_exp_func));
pstExpFuncs->pfn_cmos_get_awb_default = cmos_get_awb_default;
pstExpFuncs->pfn_cmos_get_awb_spec_default = cmos_get_awb_spec_default;
return HI_SUCCESS;
}
static hi_s32 cmos_init_sensor_exp_function(hi_isp_sensor_exp_func *pstSensorExpFunc)
{
memset_s(pstSensorExpFunc, sizeof(hi_isp_sensor_exp_func), 0, sizeof(hi_isp_sensor_exp_func));
pstSensorExpFunc->pfn_cmos_sensor_init                  = xxx_init;
pstSensorExpFunc->pfn_cmos_sensor_exit                  = xxx_exit;
pstSensorExpFunc->pfn_cmos_sensor_global_init           = sensor_global_init;
pstSensorExpFunc->pfn_cmos_set_image_mode               = cmos_set_image_mode;
pstSensorExpFunc->pfn_cmos_set_wdr_mode                 = cmos_set_wdr_mode;
pstSensorExpFunc->pfn_cmos_get_isp_default              = cmos_get_isp_default;
pstSensorExpFunc->pfn_cmos_get_isp_black_level          = cmos_get_isp_black_level;
pstSensorExpFunc->pfn_cmos_set_pixel_detect             = cmos_set_pixel_detect;
pstSensorExpFunc->pfn_cmos_get_sns_reg_info             = cmos_get_sns_regs_info;
return HI_SUCCESS;
}
static hi_u32 sensor_register_callback(hi_vi_pipe viPipe, hi_isp_3a_alg_lib *pstAeLib,
hi_isp_3a_alg_lib *pstAwbLib, hi_isp_3a_alg_lib *pstAfLib)
{
hi_isp_sensor_register stIspRegister;
hi_isp_ae_sensor_register  stAeRegister;
hi_isp_awb_sensor_register stAwbRegister;
hi_isp_sns_attr_info   stSnsAttrInfo;
sensor_ctx_init(viPipe);
stSnsAttrInfo.sensor_id = xxx_ID;
cmos_init_sensor_exp_function(&stIspRegister.sns_exp);
hi_mpi_isp_sensor_reg_callback(viPipe, &stSnsAttrInfo, &stIspRegister);
cmos_init_ae_exp_function(&stAeRegister.sns_exp);
hi_mpi_ae_sensor_reg_callback(viPipe, pstAeLib, &stSnsAttrInfo, &stAeRegister);
cmos_init_awb_exp_function(&stAwbRegister.sns_exp);
hi_mpi_awb_sensor_reg_callback(viPipe, pstAwbLib, &stSnsAttrInfo, &stAwbRegister);
return HI_SUCCESS;
}
```


2. 实现Sensor对寄存器操作

  a. 查阅Sensor手册了解Sensor寄存器配置方式并确认Sensor与芯片的硬件连接通信总线号。如I2C类Sensor需确认Sensor与芯片连接的I2C总线号，Sensor的I2C从地址等；如SPI类Sensor需确认Sensor与芯片连接的SPI总线号、片选号以及Sensor的传输芯片ID号等信息。
  b. 实现I2C或SPI接口的初始化，以及寄存器写函数

    - 在xxx_sensor_ctl.c中实现Sensor的i2c接口初始化函数，指定对应的i2c总线号及i2c设备从地址并初始化对应的i2c接口。如：

```
static hi_s32 g_fd[ISP_MAX_PIPE_NUM] = {[0 ... (ISP_MAX_PIPE_NUM -1)] = -1};
int xxx_i2c_init(VI_PIPE vi_pipe)
{
char acDevFile[I2C_DEV_FILE_NUM] = {0};
hi_u8 u8DevNum;// i2c 总线号
hi_u8 xxx_I2C_ADDR; // sensor 7位 i2c 从地址
snprintf_s(acDevFile, sizeof(acDevFile), sizeof(acDevFile) - 1, "/dev/i2c-%u", u8DevNum);
g_fd[vi_pipe] = open(acDevFile, O_RDWR, S_IRUSR | S_IWUSR);
ioctl(g_fd[vi_pipe], I2C_SLAVE_FORCE, (xxx_I2C_ADDR >> 1));
return HI_SUCCESS;
}
```


    - 在xxx_sensor_ctl.c中实现通过I2C实现对Sensor寄存器写操作。如：

```
#define xxx_ADDR_BYTE 2 // i2c 发送寄存器长度
#define xxx_DATA_BYTE 1 // i2c 发送数据长度
int xxx_write_register(VI_PIPE vi_pipe, HI_U32 addr, HI_U32 data)
{
HI_U32 idx = 0;
HI_U8 buf[I2C_BUF_NUM];
if (xxx_ADDR_BYTE == 2) {  /* 2 byte */
buf[idx] = (addr >> 8) & 0xff;  /* shift 8 */
idx++;
}
buf[idx] = addr & 0xff;
idx++;
buf[idx] = data & 0xff;
idx++;
write(g_fd[vi_pipe], buf, xxx_ADDR_BYTE + xxx_DATA_BYTE);
return HI_SUCCESS;
}
```


  c. 对于spi类型的Sensor

    - 在xxx_sensor_ctl.c中实现Sensor的spi接口初始化函数，指定对应的spi总线并初始化对应的spi接口。如：

```
static hi_s32 g_fd[ISP_MAX_PIPE_NUM] = {[0 ... (ISP_MAX_PIPE_NUM -1)] = -1};
int xxx_spi_init(VI_PIPE vi_pipe)
{
HI_U8 u8DevNum;  // Sensor 对应的spi总线号
hi_u8 u8CS;      // Sensor 对应的spi片选号
char spi_device
[
DEV_FILE_NUM] = {0};
// 打开SPI设备
snprintf_s(spi_device, sizeof(spi_device), sizeof(spi_device) - 1, "/dev/spidev%u.%u", u8DevNum, u8CS);
g_fd[vi_pipe] = open(spi_device, O_RDWR, S_IRUSR | S_IWUSR);
// 配置SPI工作模式
static char mode;
mode |= SPI_CPOL;
mode |= SPI_CPHA;
mode |= SPI_LSB_FIRST;
static char bpw = 8;
static char speed = 200000;
ioctl(g_fd[vi_pipe], SPI_IOC_WR_MODE, &mode);
ioctl(g_fd[vi_pipe], SPI_IOC_WR_BITS_PER_WORD, &bpw);
ioctl(g_fd[vi_pipe], SPI_IOC_WR_MAX_SPEED_HZ, &speed);
return HI_SUCCESS;
}
```


    - 在xxx_sensor_ctl.c中实现通过spi实现对Sensor寄存器写操作。如：

```
int xxx_write_register(VI_PIPE vi_pipe, HI_U32 addr, HI_U32 data)
{
char tx[4] = {0};
tx[0] = 0xXX; // SPI Chip ID
tx[1] = (char)((addr & 0xff00) >> 8) ; // Register Address
tx[2] = (char)(addr & 0xff); // Register Address
tx[3] = (char)data; // Register Data
static char bpw = 8;
static char speed = 200000;
struct spi_ioc_transfer trans[1];
memset_s(&trans[0], sizeof(trans[0]), 0, sizeof(trans[0]));
trans[0].tx_buf = (unsigned long)tx,
trans[0].len = 4,
trans[0].speed_hz = speed,
trans[0].bits_per_word = bpw,
ioctl(g_fd[vi_pipe], SPI_IOC_MESSAGE(1), trans);
return HI_SUCCESS;
}
```


3. 在xxx_sensor_ctl.c中实现Sensor初始化序列

  - 实现void pfn_cmos_sensor_init函数。参考Sensor手册或者Sensor厂家提供的Sensor序列实现这个函数。对于从模式Sensor，在pfn_cmos_sensor_init函数中需要调用hi_mpi_isp_set_sns_slave_attr /hi_mpi_isp_get_sns_slave_attr接口来实现从模式参数的适配，相关接口及结构体说明见《DVPP媒体加速库(https://www.hiascend.com/document/detail/zh/CANNCommunityEdition/920beta1/acce/dvpp/dvpp_03_0000.html)》。如：

```
void xxx_init(VI_PIPE vi_pipe)
{
// 调用i2c或者spi初始化函数
xxx_i2c_init(vi_pipe);/xxx_spi_init(vi_pipe);
// 如果是工作在从模式的Sensor， 需要配置对应的行场同步信号
hi_u8 SlaveDev;
hi_isp_slave_sns_sync sns_sync;
hi_mpi_isp_get_sns_slave_attr(SlaveDev, sns_sync);
// 配置需要的sns_sync属性
hi_mpi_isp_set_sns_slave_attr(SlaveDev, sns_sync);
// 根据需要的Sensor工作状态配置初始化寄存器
xxx_write_register(vi_pipe, address, value);
return;
}
```
