Initialization Sequence Configuration

Configure the initialization sequence by referring to the sensor driver in the version release package. To facilitate debugging,eliminate the interference from the AE configuration and frame rate configuration. Therefore, you are advised to use a null implementation of cmos_get_sns_regs_info in the driver.

  1. Prepare the sensor driver.
    • Compile the sensor library based on the sensor data sheet or a sensor driver with similar specifications (master/slave, I2C/SPI, WDR/linear). For details, see xxx_cmos.c (implementing the callback functions required by the ISP, including the ISP, AE, and AWB), xxx_cmos.h, and xxx_sensor_ctl.c (implementing the read/write initialization of the sensor).
    • Declare and initialize the sensor instance.
      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
      };

      You can add or delete functions in the hi_isp_sns_obj structure. The current implementation is as follows:

      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;
    • Register the ISP callback function pointer, and implement some functions or set them to null as required. For details about the functions, see DVPP Media Acceleration Library. This part describes how to initialize the 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. Implement operations on the sensor register.
    1. Understand the sensor register configuration mode by referring to the sensor manual and confirm the ID of the communication bus between the sensor and chip. For an I2C sensor, confirm the ID of the I2C bus that connects the sensor to the chip and the I2C slave address of the sensor. For an SPI sensor, confirm the ID of the SPI bus that connects the sensor to the chip, chip select (CS) ID, and ID of the transmission chip of the sensor.
    2. Initialize the I2C or SPI interface and register write functions.
      • In xxx_sensor_ctl.c, implement the initialization function of the I2C interface of the sensor, specify the I2C bus number and I2C slave address, and initialize the corresponding I2C interface. Example:
        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 bus number
            hi_u8 xxx_I2C_ADDR; // 7-bit I2C slave address of the sensor
            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;
        }
      • Perform the write operation on the sensor register through the I2C in xxx_sensor_ctl.c. Example:
        #define xxx_ADDR_BYTE 2 // Register length sent by the I2C
        #define xxx_DATA_BYTE 1 // Data length sent by the 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 bytes */
                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;
        }
    3. For an SPI sensor, perform the following steps.
      • In xxx_sensor_ctl.c, implement the SPI interface initialization function of the sensor, specify the SPI bus, and initialize the corresponding SPI interface. Example:
        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;  // SPI bus number corresponding to the sensor
            hi_u8 u8CS;      //  SPI CS ID corresponding to the sensor
            char spi_device[DEV_FILE_NUM] = {0};
        
            // Start an SPI device.
            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);
        
            // Configure the SPI working mode.
            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;
        }
      • Perform the write operation on the sensor register through the SPI in xxx_sensor_ctl.c. Example:
        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. Implement the sensor initialization sequence in xxx_sensor_ctl.c.
    • Implement the void pfn_cmos_sensor_init function by referring to the sensor manual or sensor sequence provided by the sensor vendor. For the sensor in slave mode, call the hi_mpi_isp_set_sns_slave_attr and hi_mpi_isp_get_sns_slave_attr APIs in the pfn_cmos_sensor_init function to adapt the slave mode parameters. For details about the related interfaces and structures, see DVPP Media Acceleration Library. Example:
      void xxx_init(VI_PIPE vi_pipe)
      {
          // Call the I2C or SPI initialization function.
          xxx_i2c_init(vi_pipe);/xxx_spi_init(vi_pipe);
          
          // For the sensor in slave mode, configure the corresponding horizontal/vertical synchronization signal.
          hi_u8 SlaveDev; 
          hi_isp_slave_sns_sync sns_sync;
          hi_mpi_isp_get_sns_slave_attr(SlaveDev, sns_sync);
          // Configure the required sns_sync attribute.
          hi_mpi_isp_set_sns_slave_attr(SlaveDev, sns_sync);
      
          // Configure the initialization register based on the required sensor working modes.
          xxx_write_register(vi_pipe, address, value);
          ...
      
          return;
      }