5.17.5. Sony Sensor Bring-Up

  • 本文以 imx586 为例,说明在 X5 平台上适配 Sony 系列 Camera Sensor 的完整流程

  • 流程包括驱动实现、App 配置与程序验证。通用概念与 dts 配置请先阅读 Camera 调试指南

源码位置

  • 驱动接口实现hbre/camsys/libcam/src/sensor/imx586/imx586_setting.c

  • 增益表与 Setting 配置hbre/camsys/libcam/src/sensor/imx586/inc/imx586_setting.hgain_lut、init/stream_on/stream_off 寄存器数组)


5.17.5.1. dts配置


5.17.5.2. 驱动

sensor_module_t 与文件命名

  • 文件名:imx586_utility.c;结构体/模块名:imx586;库名:libimx586.so.1.0.0,部署到板端 /usr/hobot/lib/sensor/

  • 需实现的接口:init、deinit、start、stop、power_on、power_off、aexp_gain_control、aexp_line_control、userspace_control。

#ifdef CAMERA_FRAMEWORK_HBN
SENSOR_MODULE_F(imx586, CAM_MODULE_FLAG_A16D8);
sensor_module_t imx586 = {
        .module = SENSOR_MNAME(imx586),
#else
sensor_module_t imx586 = {
        .module = "imx586",
#endif
        .init = sensor_init,
        .start = sensor_start,
        .stop = sensor_stop,
        .deinit = sensor_deinit,
        .power_on = sensor_poweron,
        .power_off = sensor_poweroff,
        .aexp_gain_control = sensor_aexp_gain_control,
        .aexp_line_control = sensor_aexp_line_control,
        .userspace_control = sensor_userspace_control,
};

power_on

  1. power_on 通过 X5 GPIO 控制 sensor 上电,需结合 spec 上电时序。

  2. sensor_poweron 一般在 sensor_init 中调用,只需要控制 XCLR 即可,以下为 imx586 power_on的代码实现:

../../_images/screenshot-20260210-154827.png

static int sensor_poweron(sensor_info_t *sensor_info)
{
        int gpio, ret = RET_OK;
        vin_dbg("%s gpio_num = %d \n", sensor_info->sensor_name, sensor_info->gpio_num);
        if(sensor_info->gpio_num > 0) {
                for(gpio = 0; gpio < sensor_info->gpio_num; gpio++) {
                        vin_dbg("%s gpio_pin[%d] = %d \n", sensor_info->sensor_name, gpio, sensor_info->gpio_pin[gpio]);
                        if(sensor_info->gpio_pin[gpio] != -1) {
                                ret = vin_power_ctrl(sensor_info->gpio_pin[gpio],
                                                sensor_info->gpio_level[gpio]);
                                usleep(100 * 1000);  // 100ms
                                ret |= vin_power_ctrl(sensor_info->gpio_pin[gpio],
                                                1 - sensor_info->gpio_level[gpio]);
                                if(ret < 0) {
                                        vin_err("vin_power_ctrl fail\n");
                                        return -HB_CAM_SENSOR_POWERON_FAIL;
                                }
                                usleep(100 * 1000);  // 100ms
                        }
                }
        }
        return ret;
}

power_off

  1. power_off 通过 X5 GPIO 控制 sensor 下电,需结合 spec 上电时序。

  2. sensor_poweroff 一般在 sensor_deinit 中调用,只需要控制 XCLR 即可,以下为 imx586 power_off 的代码实现:

../../_images/screenshot-20260210-154309.png

static int sensor_poweroff(sensor_info_t *sensor_info)
{
        int gpio, ret = RET_OK;
        if(sensor_info->gpio_num > 0) {
                for(gpio = 0; gpio < sensor_info->gpio_num; gpio++) {
                        if(sensor_info->gpio_pin[gpio] != -1) {
                                ret = vin_power_ctrl(sensor_info->gpio_pin[gpio],
                                        sensor_info->gpio_level[gpio]);
                                if(ret < 0) {
                                        vin_err("vin_power_ctrl fail\n");
                                        return -HB_CAM_SENSOR_POWEROFF_FAIL;
                                }
                        }
                }
        }
        return ret;
}

init

  1. 将 sensor 初始化寄存器列表通过i2c写函数写入 sensor;不同分辨率使用不同 setting 数组

  2. imx586_linear_data_init 用于填充turning_data信息。

  3. sensor_init 调用时机为 hbn_camera_attach_to_vin

static int sensor_init(sensor_info_t *sensor_info)
{
        int ret = RET_OK;
        int setting_size = 0;

        ret = sensor_poweron(sensor_info);
        if (ret < 0) {
                vin_err("%d : sensor reset %s fail\n", __LINE__, sensor_info->sensor_name);
                return ret;
        }
        switch(sensor_info->sensor_mode) {
        case NORMAL_M:
                vin_info("imx586 in normal/linear mode\n");
                vin_info("bus_num = %d, sensor_addr = 0x%0x, fps = %d\n",
                        sensor_info->bus_num, sensor_info->sensor_addr, sensor_info->fps);
                setting_size = sizeof(imx586_init_3840x2160_4lane_linear_setting) / sizeof(uint32_t) / 2;
                ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, REG_WIDTH,
                        setting_size, imx586_init_3840x2160_4lane_linear_setting);
                if (ret < 0) {
                        vin_err("%d : init %s fail\n", __LINE__, sensor_info->sensor_name);
                        return -HB_CAM_I2C_WRITE_FAIL;
                }
                ret = imx586_linear_data_init(sensor_info);
                if (ret < 0) {
                        vin_err("%d : linear data init %s fail\n", __LINE__, sensor_info->sensor_name);
                        return -HB_CAM_INIT_FAIL;
                }
                break;
        default:
                vin_err("%d not support mode %d\n", __LINE__, sensor_info->sensor_mode);
                ret = -HB_CAM_INIT_FAIL;
                break;
        }
        vin_info("imx586 config success under %d mode\n", sensor_info->sensor_mode);
        return ret;
}

deinit

  1. deinit 一般调用于 sensor的反初始化,直接调用 power_off 下电即可。

  2. sensor_deinit 调用时机为 hbn_camera_destroy 或者 hbn_camera_detach_from_vin。

static int sensor_deinit(sensor_info_t *sensor_info)
{
        int ret = RET_OK;
        ret = sensor_poweroff(sensor_info);
        if (ret < 0) {
                vin_err("%d : deinit %s fail\n", __LINE__, sensor_info->sensor_name);
                return ret;
        }
        return ret;
}

start

  1. start 实现下发开流寄存器0x0100 为0x01,使 sensor 出流。

  2. sensor_start 调用时机为 上层调用 hbn_vflow_start。

../../_images/screenshot-20260210-204256.png

static int sensor_start(sensor_info_t *sensor_info)
{
        int ret = RET_OK;
        int setting_size = 0;

        setting_size = sizeof(imx586_stream_on_setting)/sizeof(uint32_t)/2;
        vin_info("%s start normal/linear mode\n", sensor_info->sensor_name);
        ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, REG_WIDTH,
                setting_size, imx586_stream_on_setting);
        if(ret < 0) {
                vin_err("start %s fail\n", sensor_info->sensor_name);
                return -HB_CAM_I2C_WRITE_FAIL;
        }
        return ret;
}

stop

  1. stop 实现下发关流寄存器 0x0100 为0x00,使 sensor 关流。

  2. sensor_stop 调用时机为 上层调用 hbn_vflow_stop

static int sensor_stop(sensor_info_t *sensor_info)
{
        int ret = RET_OK;
        int setting_size = 0;

        setting_size = sizeof(imx586_stream_off_setting) / sizeof(uint32_t) / 2;
        vin_info("%s sensor stop\n", sensor_info->sensor_name);
        ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, REG_WIDTH,
                setting_size, imx586_stream_off_setting);
        if (ret < 0) {
                vin_err("start %s fail\n", sensor_info->sensor_name);
                return -HB_CAM_I2C_WRITE_FAIL;
        }
        return ret;
}

ISP 配置与 linear_data_init

../../_images/screenshot-20260210-150959.png

../../_images/screenshot-20260210-202708.png

../../_images/screenshot-20260210-222914.png

imx586_linear_data_init 中填充 tuning 参数:

  • 从 sensor 读 VTS(寄存器 0x0340/0x0341),计算 lines_per_second;

  • exposure_time_max/min、analog_gain_max、digital_gain_max;

  • 填充 bayer(sensor_data_bayer_fill、sensor_data_bits_fill);

  • 设置 stream_ctrl;将 again_lutimx586_setting.h 中的 imx586_gain_lut 拷贝到 turning_data.normal.again_lut,再通过 ioctl 下发。

关键参数配置:

  • lines_per_second = vts * sensor_info->fps

  • exposure_time_max = vts - 48 文档中为FRM_LENGTH_LINES - 48 即 VTS-48

  • analog_gain_max = 160 与 gain_lut 最大索引一致,32x 对应 160,参照 gain 索引值和 增益倍率 对照表

  • digital_gain_max = 0 dgain 未用配置0即可,如果使用参照analog_gain_max

  • exposure_time_min = 1

  • sensor_data_bayer_fill(..., 10, BAYER_START_R, BAYER_PATTERN_RGGB)sensor_data_bits_fill(..., 12),0,0位置BAYER_START是 BAYER_START_R,BAYER_PATTERN是RGGB,raw10格式,sensor_data_bits_fill pwl mode 才会用到,这里配置12即可

aexp_gain_control

对于 Sony 的sensor gain控制一般以线性公式进行控制,以 imx586 为例,需要根据增益倍数推导寄存器值计算公式,具体方式如下:

参考文档和gain_table.xlsx:

../../_images/screenshot-20260116-110906.png

../../_images/screenshot-20260116-103726.png

公式解析:

"0x" & DEC2HEX(1024 - 1024/B4, 0)

IMX586 的模拟增益公式为: Analog Gain = 1024 / (1024 - X)

其中: Analog Gain 是增益倍数(如 2.0x、4.0x 等) X 是要写入寄存器的值(范围 112-1008)

推导过程:

Analog Gain = 1024 / (1024 - X)
=> 1024 - X = 1024 / Analog Gain
=> X = 1024 - 1024 / Analog Gain
static int sensor_aexp_gain_control(hal_control_info_t *info, uint32_t mode, uint32_t *again, uint32_t *dgain, uint32_t gain_num)
{
        const uint16_t AGAIN_H = 0x0204;
        const uint16_t AGAIN_L = 0x0205;
        char again_reg_value_h = 0, again_reg_value_l = 0;
        int gain_index = 0;

        if (mode == NORMAL_M) {
                if (again[0] >= sizeof(imx586_gain_lut)/sizeof(uint32_t))
                        gain_index = sizeof(imx586_gain_lut)/sizeof(uint32_t) - 1;
                else
                        gain_index = again[0];

                again_reg_value_h = (imx586_gain_lut[gain_index] >> 8) & 0xFF;
                again_reg_value_l = (imx586_gain_lut[gain_index]) & 0xFF;

                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, AGAIN_H, again_reg_value_h);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, AGAIN_L, again_reg_value_l);
        } else {
                vin_err(" unsupport mode %d\n", mode);
        }
        return 0;
}

aexp_line_control

aexp_line_control这个函数是主要实现了曝光的控制,主要负责:

  1. 接收ISP 3A算法计算的下发的曝光的行数

  2. 将曝光的行数转换为sensor寄存器值

  3. 配置通过i2c下发给sensor 曝光寄存器

  4. 这里曝光寄存器为 0x0202、0x0203。

../../_images/screenshot-20260210-202303.png

static int sensor_aexp_line_control(hal_control_info_t *info, uint32_t mode, uint32_t *line, uint32_t line_num)
{
        const uint16_t EXP_LINE0 = 0x0202;
        const uint16_t EXP_LINE1 = 0x0203;
        char temp0 = 0, temp1 = 0;

        if (mode == NORMAL_M) {
                uint32_t sline = line[0];
                if (sline > 3063) sline = 3063;
                if (sline < 8) sline = 8;

                temp0 = (sline >> 8) & 0xFF;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, EXP_LINE0, temp0);
                temp1 = (sline) & 0xFF;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, EXP_LINE1, temp1);
        } else {
                vin_err(" unsupport mode %d\n", mode);
        }
        return 0;
}

userspace_control

  • 这里 sensor_userspace_control 用于 Gain Control 与 Exposure Control开关。

  • 用于 hbplayer 调试时排查 flicker 或画面异常,可开关 HAL_GAIN_CONTROL / HAL_LINE_CONTROL确认问题。

static int sensor_userspace_control(uint32_t port, uint32_t *enable)
{
        vin_info("enable userspace gain control and line control\n");
        *enable = HAL_GAIN_CONTROL | HAL_LINE_CONTROL | HAL_AF_CONTROL;
        return 0;
}

驱动部署

  1. ./bd.sh hbre camsys/libcam 编译。

  2. out/deploy/hbre/lib/sensor/libimx586.so.1.0.0 拷贝到板端 /usr/hobot/lib/sensor/


5.17.5.3. App 配置

  • 在路径 app/samples/platform_samples/vp_sensors/imx586/ 中为 imx586 添加配置,

  • 需配置 mipi(lane、datatype、mipiclk、linelenth、framelenth、settle)、camera(name、addr、sensor_mode、gpio、fps、width、height、format)、vin_node_attr(mipi_rx、cim_isp_flyby 等)、vin_ichn_attr、vin_ochn_attr(wstride 等)、isp_attr、isp_ichn_attr、isp_ochn_attr。

  • HTS/VTS 可从寄存器 0x342/0x343、0x340/0x341 读取或咨询 Sensor FAE 提供或者使用示波器测量,测量方法参考 mipi-参数确定

  • mipiclk 一般询问 Sensor FAE即可,计算方法参考 MIPI CLK

  • 其他的都为通用配置,参考文档 数据结构。 进行配置即可

vp_sensor 配置文件:linear_3840x2160_raw10_30fps_4lane.c

  • 配置文件路径:imx586/linear_3840x2160_raw10_30fps_4lane.c

  • 配置结构体名:linear_3840x2160_raw10_30fps_4lane(需在 vp_sensor_config_list 中注册)。

  • 当前示例为 RAW10 输出;datatype/format 配置为 0x2B主要参数如下:

配置项 参数名 / 位置 取值说明
顶层 config_file "linear_3840x2160_raw10_30fps_4lane.c"
sensor_name "imx586-30fps-4lane"
chip_id_reg / chip_id 0x0016 / 0x0586
sensor_i2c_addr_list {0x1A}
support_sensor_mode {NORMAL_M}
MIPI lane 4
datatype RAW10 (0x2B)
fps 30
mipiclk 4500(Mbps)
width / height 3840 / 2160(4K UHD)
linelenth / framelenth 8976 / 3064(与 sensor HTS/VTS)
settle 30
channel_num 1
stop_check_instart 1
Camera name / addr "imx586" / 0x1A
sensor_mode 1 (NORMAL_M)
format RAW10
gpio_enable_bit / gpio_level_bit 0x01 / 0x00
calib_lname "disable"
VIN mipi_rx 0
cim_isp_flyby 0(offline)
hdr_mode NOT_HDR
mclk_freq (vin_attr_ex) 24000000
VIN 输出 wstride SENSOR_WIDTH * 2(RAW10 为 ×2)
ISP 输入 input_mode DDR_MODE
sensor_mode ISP_NORMAL_M
crop x=0, y=0, w=3840, h=2160
input_fmt FRM_FMT_RAW
input_bit_width 10
ISP 输出 output_fmt FRM_FMT_NV12
output_bit_width 8
ddr_en 1

5.17.5.4. 程序验证

  1. get_vin_data:确认 raw 图无严重偏色、帧率符合配置。

  2. get_isp_data:准备 imx586_tuning.json(可拷贝同分辨率 json 并改 sensor_name),确认 YUV 正常。

  3. hbplayer:连接板端预览,见 hbplayer 和 tuning_tool 工具使用指南

  4. tuning_tool:使用tuning_tool连接hbplayer后,输入命令 e,配置 Manual AE,设置 aGain、integrationTime,看驱动打印核对 0x0204/0x0205、0x0202/0x0203 与 spec 一致,ISP 增益限制可在 imx586_tuning.json 中配置以便自测。

常见问题见 Camera Sensor FAQ