下载
中文
注册

完成初始化序列配置

配置初始化序列,建议参考版本发布包里面的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,具体函数功能及说明请参见CANN AscendCL应用软件开发指南(C&C++),本节主要实现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对寄存器操作
    1. 查阅Sensor手册了解Sensor寄存器配置方式并确认Sensor与芯片的硬件连接通信总线号。如I2C类Sensor需确认Sensor与芯片连接的I2C总线号,Sensor的I2C从地址等;如SPI类Sensor需确认Sensor与芯片连接的SPI总线号、片选号以及Sensor的传输芯片ID号等信息。
    2. 实现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;
        }
    3. 对于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工作模式
            staticchar mode;
            mode |= SPI_CPOL;
            mode |= SPI_CPHA;
            mode |= SPI_LSB_FIRST;
            staticchar bpw = 8;
            staticint 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
            staticchar bpw = 8;
            staticint 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接口来实现从模式参数的适配,相关接口及结构体说明见应用开发指南。如:
      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;
      }