5.17.6. HDR Sensor Bring-Up

⚠️ Important Notice: When an HDR sensor is connected, the VIN-ISP connection must use online mode. Since online mode exclusively occupies the ISP resource, only 1 stream is supported.

  • This document uses Sony imx415 DOL2 as an example to describe the complete process of adapting an HDR mode Camera Sensor on the X5 platform.

  • The Sony sensor HDR implementation outputs image line data with alternating exposure times within one frame set period.

  • The process includes driver implementation, App configuration, and program verification. For general concepts and dts configuration, please read the Camera Bring-Up Guide first.

Source Code Location

  • Driver interface implementation: hbre/camsys/libcam/src/sensor/imx415/imx415_utility.c

  • Gain table and Setting configuration: hbre/camsys/libcam/src/sensor/imx415/inc/imx415_setting.h (gain_lut, init/stream_on/stream_off register arrays)


5.17.6.1. dts Configuration

  • For dts configuration, power-on, and sensor ID verification, refer to Modify Platform Device Tree

  • The dts configuration for DOL2 mode is the same as Linear mode, no additional modifications required.


5.17.6.2. Driver

sensor_module_t and File Naming

  • File name: imx415_utility.c; struct/module name: imx415; library name: libimx415.so.1.0.0, deployed to /usr/hobot/lib/sensor/ on the board.

  • Required interfaces: init, deinit, start, stop, power_on, power_off, aexp_gain_control, aexp_line_control, userspace_control.

  • HDR mode and Linear mode share the same sensor_module_t, differentiated by sensor_mode to take different branches.

#ifdef CAMERA_FRAMEWORK_HBN
SENSOR_MODULE_F(imx415, CAM_MODULE_FLAG_A16D8);
sensor_module_t imx415 = {
        .module = SENSOR_MNAME(imx415),
#else
sensor_module_t imx415 = {
        .module = "imx415",
#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 controls sensor power-up through X5 GPIO, following the spec power-on timing sequence.

  2. sensor_poweron is typically called in sensor_init, only XCLR needs to be controlled.

  3. The power-on sequence is identical for HDR mode and Linear mode. The following is the imx415 power_on implementation:

../../_images/screenshot-20260422-193603.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 controls sensor power-down through X5 GPIO, following the spec power-on timing sequence.

  2. sensor_poweroff is typically called in sensor_deinit, only XCLR needs to be controlled. The following is the imx415 power_off implementation:

../../_images/screenshot-20260422-193628.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. Write the sensor initialization register list to the sensor via the i2c write function; HDR mode uses the DOL2-specific setting array.

  2. imx415_dol2_data_init is used to populate turning_data information.

  3. sensor_init is called when hbn_camera_attach_to_vin is invoked.

  4. HDR mode uses sensor_mode == DOL2_M to take a separate branch.

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:
                // ... linear mode initialization (omitted) ...
                break;
        case DOL2_M:
                vin_info("imx415 in dol2/hdr mode\n");
                setting_size = sizeof(imx415_init_3840x2160_dol2_4lane_setting) / sizeof(uint32_t) / 2;
                ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, REG_WIDTH,
                                setting_size, imx415_init_3840x2160_dol2_4lane_setting);
                if (ret < 0) {
                        vin_err("%d : init %s fail\n", __LINE__, sensor_info->sensor_name);
                        return -HB_CAM_I2C_WRITE_FAIL;
                }
                ret = imx415_dol2_data_init(sensor_info);
                if (ret < 0) {
                        vin_err("%d : hdr 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;
        }
        return ret;
}

deinit

  1. deinit is typically called for sensor de-initialization, simply call power_off to power down.

  2. sensor_deinit is called when hbn_camera_destroy or hbn_camera_detach_from_vin is invoked.

  3. HDR mode and Linear mode are identical.

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 implements sending stream-on registers 0x3000 as 0x00, 0x3002 as 0x00, to enable sensor streaming.

  2. sensor_start is called when the upper layer calls hbn_vflow_start.

  3. HDR mode and Linear mode use the same stream_on registers.

../../_images/screenshot-20260422-214020.png

../../_images/screenshot-20260422-214035.png

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

        switch (sensor_info->sensor_mode) {
        case NORMAL_M:
        case DOL2_M:
                setting_size = sizeof(imx415_stream_on_setting) / sizeof(uint32_t) / 2;
                ret = vin_write_array(sensor_info->bus_num, sensor_info->sensor_addr, 2,
                                      setting_size, imx415_stream_on_setting);
                if (ret < 0) {
                        vin_err("start %s fail\n", sensor_info->sensor_name);
                        return ret;
                }
                break;
        }
        return ret;
}

stop

  1. stop implements sending stream-off registers 0x3000 as 0x01, 0x3002 as 0x01, to disable sensor streaming.

  2. sensor_stop is called when the upper layer calls hbn_vflow_stop.

  3. HDR mode and Linear mode use the same stream_off registers.

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

        setting_size = sizeof(imx415_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, imx415_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 Configuration and dol2_data_init

Below are some HDR terminology definitions for imx415:

../../_images/screenshot-20260422-165005.png

Below is the description of bayer_pattern and bayer_start:

../../_images/screenshot-20260422-221051.png

In DOL2 mode, IMX415 needs to alternately output LEF (Long Exposure Frame) and SEF1 (Short Exposure Frame) data within one frame set period. The time occupied is VMAX x 2. ../../_images/screenshot-20260422-163831.png

../../_images/screenshot-20260422-162608.png

In imx415_dol2_data_init, populate the tuning parameters:

  • Need to read VMAX (0x3024-0x3026) and RHS1 (0x3060-0x3062) from the sensor, calculate FSC = VMAX x 2;

  • exposure_time_long_max / exposure_time_max are calculated according to the DOL2 formula in the SPEC;

  • gain_lut uses turning_data.dol2.again_lut

  • Set turning_type = 6.

DOL2 exposure time formula from the figure above:

After consulting the sensor FAE, Toffset can be negligible, therefore:

LEF exposure lines:  t_LEF  = FSC  - SHR0,  FSC = VMAX x 2
SEF1 exposure lines: t_SEF1 = RHS1 - SHR1

Key parameter configuration:

  • lines_per_second = FSC * sensor_info->fps (FSC = VMAX x 2)

  • exposure_time_long_max = FSC - (RHS1 + 9) LEF maximum exposure lines

  • exposure_time_max = RHS1 - 9 SEF1 maximum exposure lines

  • exposure_time_min = 8

  • analog_gain_max = 255 consistent with the maximum gain_lut index

  • digital_gain_max = 0

  • sensor_data_bayer_fill(..., 10, BAYER_START_GB, BAYER_PATTERN_RGGB); sensor_data_bits_fill(..., 12)

static int imx415_dol2_data_init(sensor_info_t *sensor_info)
{
        int ret = RET_OK;
        sensor_turning_data_t turning_data;
        uint32_t *stream_on = turning_data.stream_ctrl.stream_on;
        uint32_t *stream_off = turning_data.stream_ctrl.stream_off;

        int val_l = 0, val_m = 0, val_h = 0;
        uint32_t Vmax = 0, rhs1 = 0, fsc = 0;

        val_l = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_VMAX);
        val_m = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_VMAX + 1);
        val_h = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_VMAX + 2);
        Vmax = ((val_h & 0x0F) << 16) | (val_m << 8) | val_l;

        val_l = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_RHS1);
        val_m = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_RHS1 + 1);
        val_h = hb_vin_i2c_read_reg16_data8(sensor_info->bus_num, sensor_info->sensor_addr, IMX415_RHS1 + 2);
        rhs1 = ((val_h & 0x0F) << 16) | (val_m << 8) | val_l;

        fsc = Vmax * 2;

        memset(&turning_data, 0, sizeof(sensor_turning_data_t));

        turning_data.bus_num = sensor_info->bus_num;
        turning_data.bus_type = sensor_info->bus_type;
        turning_data.port = sensor_info->port;
        turning_data.reg_width = sensor_info->reg_width;
        turning_data.mode = sensor_info->sensor_mode;
        turning_data.sensor_addr = sensor_info->sensor_addr;
        strncpy(turning_data.sensor_name, sensor_info->sensor_name,
                sizeof(turning_data.sensor_name));
        turning_data.sensor_data.turning_type = 6;
        turning_data.sensor_data.active_width = sensor_info->width;
        turning_data.sensor_data.active_height = sensor_info->height;

        turning_data.sensor_data.lines_per_second = fsc * sensor_info->fps;
        turning_data.sensor_data.exposure_time_long_max = fsc - (rhs1 + 9);
        turning_data.sensor_data.exposure_time_max = rhs1 - 9;
        turning_data.sensor_data.exposure_time_min = 8;
        turning_data.sensor_data.analog_gain_max = 255;
        turning_data.sensor_data.digital_gain_max = 0;

        sensor_data_bayer_fill(&turning_data.sensor_data, 10, (uint32_t)BAYER_START_GB, (uint32_t)BAYER_PATTERN_RGGB);
        sensor_data_bits_fill(&turning_data.sensor_data, 12);

        turning_data.stream_ctrl.data_length = 1;
        memcpy(stream_on, imx415_stream_on_setting, sizeof(imx415_stream_on_setting));
        memcpy(stream_off, imx415_stream_off_setting, sizeof(imx415_stream_off_setting));

        turning_data.dol2.again_lut = malloc(256 * sizeof(uint32_t));
        if (turning_data.dol2.again_lut != NULL) {
                memset(turning_data.dol2.again_lut, 0xff, 256 * sizeof(uint32_t));
                memcpy(turning_data.dol2.again_lut, imx415_gain_lut, sizeof(imx415_gain_lut));
        }

        ret = ioctl(sensor_info->sen_devfd, SENSOR_TURNING_PARAM, &turning_data);

        if (turning_data.dol2.again_lut) {
                free(turning_data.dol2.again_lut);
                turning_data.dol2.again_lut = NULL;
        }
        if (ret < 0) {
                vin_err("%s sync gain lut ioctl fail %d\n", sensor_info->sensor_name, ret);
                return -RET_ERROR;
        }
        return ret;
}

aexp_gain_control

In DOL2 mode, LEF and SEF1 gain need to be controlled separately:

  • again[0] -> LEF gain, written to GAIN_PGC0 (0x3090)

  • again[1] -> SEF1 gain, written to GAIN_PGC1 (0x3092)

    ../../_images/screenshot-20260422-163403.png

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 = GAIN_PGC0;
        const uint16_t S_AGAIN = GAIN_PGC1;
        char again_reg_value = 0, s_again_reg_value = 0;
        int again_index = 0, s_again_index = 0;

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

                again_reg_value = (imx415_gain_lut[again_index] >> 0) & 0xFF;
                set_gain_registers(info, AGAIN, again_reg_value);
        } else if (mode == DOL2_M) {
                if (again[0] >= sizeof(imx415_gain_lut)/sizeof(uint32_t))
                        again_index = sizeof(imx415_gain_lut)/sizeof(uint32_t) - 1;
                else
                        again_index = again[0];
                if (again[1] >= sizeof(imx415_gain_lut)/sizeof(uint32_t))
                        s_again_index = sizeof(imx415_gain_lut)/sizeof(uint32_t) - 1;
                else
                        s_again_index = again[1];

                again_reg_value = (imx415_gain_lut[again_index] >> 0) & 0xFF;
                s_again_reg_value = (imx415_gain_lut[s_again_index] >> 0) & 0xFF;

                set_gain_registers(info, AGAIN, again_reg_value);
                set_gain_registers(info, S_AGAIN, s_again_reg_value);
        } else {
                vin_err(" unsupport mode %d\n", mode);
        }
        return 0;
}

aexp_line_control

aexp_line_control in DOL2 mode needs to set both LEF and SEF1 exposure simultaneously, mainly responsible for:

  1. Receiving exposure line counts from the ISP 3A algorithm: line[0] (LEF), line[1] (SEF1)

  2. Converting exposure line counts to SHR0 and SHR1 register values

  3. Performing boundary checks and odd/even alignment

  4. Sending to sensor via i2c

../../_images/screenshot-20260422-162608.png

DOL2 Exposure Formula:

SHR0 = FSC  - line[0]     (LEF,  FSC = VMAX x 2)
SHR1 = RHS1 - line[1]     (SEF1)

Constraints: SHR0 is even (2n),    (RHS1 + 9) <= SHR0 <= (FSC - 8)
             SHR1 is odd (2n+1),   9 <= SHR1 <= (RHS1 - 8)

Linear Mode Exposure Formula:

SHR0 = VMAX - line[0]

Constraints: 8 <= SHR0 <= (VMAX - 4)
static int sensor_aexp_line_control(hal_control_info_t *info, uint32_t mode, uint32_t *line, uint32_t line_num)
{
        uint32_t tmp = 0;
        char temp0 = 0, temp1 = 0, temp2 = 0;
        int val_l = 0, val_m = 0, val_h = 0;
        uint32_t Vmax = 0;

        val_l = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_VMAX);
        val_m = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_VMAX + 1);
        val_h = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_VMAX + 2);
        Vmax = ((val_h & 0x0F) << 16) | (val_m << 8) | val_l;

        if ((mode == NORMAL_M) || (line_num == 1)) {
                int shr0 = Vmax - line[0];
                if (shr0 < 8)              shr0 = 8;
                if (shr0 > (int)(Vmax - 4)) shr0 = Vmax - 4;

                tmp = shr0;
                temp2 = (tmp >> 16) & 0x0F;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0 + 2, temp2);
                temp1 = (tmp >> 8) & 0xFF;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0 + 1, temp1);
                temp0 = (tmp & 0xFF);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0, temp0);
        } else if (mode == DOL2_M) {
                uint32_t rhs1 = 0, fsc = 0;
                int shr0 = 0, shr1 = 0;

                val_l = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_RHS1);
                val_m = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_RHS1 + 1);
                val_h = hb_vin_i2c_read_reg16_data8(info->bus_num, info->sensor_addr, IMX415_RHS1 + 2);
                rhs1 = ((val_h & 0x0F) << 16) | (val_m << 8) | val_l;

                fsc = Vmax * 2;
                shr0 = fsc - line[0];
                shr1 = rhs1 - line[1];

                if (shr1 < 9)              shr1 = 9;
                if (shr1 > (int)(rhs1 - 8)) shr1 = rhs1 - 8;
                if (shr0 < (int)(rhs1 + 9)) shr0 = rhs1 + 9;
                if (shr0 > (int)(fsc - 8))   shr0 = fsc - 8;

                shr1 |= 0x01;               // Force SHR1 to odd (2n+1)
                shr0 = (shr0 >> 1) << 1;    // Force SHR0 to even (2n)

                // Write SHR0 (3 bytes LSB first: 0x3050, 0x3051, 0x3052)
                tmp = shr0;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0 + 2, (tmp >> 16) & 0x0F);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0 + 1, (tmp >> 8) & 0xFF);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR0,     tmp & 0xFF);

                // Write SHR1 (3 bytes LSB first: 0x3054, 0x3055, 0x3056)
                tmp = shr1;
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR1 + 2, (tmp >> 16) & 0x0F);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR1 + 1, (tmp >> 8) & 0xFF);
                vin_i2c_write8(info->bus_num, 16, info->sensor_addr, IMX415_SHR1,     tmp & 0xFF);
        } else {
                vin_err(" unsupport mode %d\n", mode);
                return -1;
        }
        return 0;
}

userspace_control

  • sensor_userspace_control is used here for Gain Control and Exposure Control switches.

  • Used during hbplayer debugging to troubleshoot flicker or abnormal images; HAL_GAIN_CONTROL / HAL_LINE_CONTROL can be toggled to isolate the issue.

  • HDR mode and Linear mode are identical.

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;
        return 0;
}

Driver Deployment

  1. Build with ./bd.sh hbre camsys/libcam.

  2. Copy out/deploy/hbre/lib/sensor/libimx415.so.1.0.0 to /usr/hobot/lib/sensor/ on the board.


5.17.6.3. App Configuration

  • Add DOL2 configuration for imx415 in the path app/samples/platform_samples/vp_sensors/imx415/.

  • HTS/VTS can be read from registers 0x3028/0x3029, 0x3024~0x3026, or obtained by consulting the Sensor FAE, or measured with an oscilloscope. For measurement methods, refer to MIPI Parameter Determination

  • mipiclk can generally be obtained from the Sensor FAE. For calculation methods, refer to MIPI CLK

  • Other parameters are common configurations. Refer to Data Structures for configuration.

vp_sensor Configuration File: dol2_3840x2160_raw10_30fps_4lane.c

  • Configuration file path: imx415/dol2_3840x2160_raw10_30fps_4lane.c.

  • Configuration struct name: imx415_dol2_3480x2160_raw10_30fps_4lane (must be registered in vp_sensor_config_list).

  • The current example uses RAW10 output; datatype/format is configured as 0x2B.

DOL2 mode has several key differences from Linear mode, described module by module below:

MIPI Configuration

In DOL2 mode, the sensor transmits LEF (VC0) and SEF1 (VC1) over the same MIPI link using Virtual Channels. The SoC side needs to configure 2 channels to receive them separately:

static mipi_config_t imx415_mipi_config = {
        .rx_enable = 1,
        .rx_attr = {
                .phy = 0,
                .lane = 4,
                .datatype = RAW10,
                .fps = 30,
                .mclk = 1,
                .mipiclk = 7128,
                .width = 3840,
                .height = 2160,
                .linelenth = 6400,
                .framelenth = 4700,
                .settle = 10,
                .channel_num = 2,          // DOL2: 2 channels (Linear is 1)
                .channel_sel = {0, 1},     // VC0=LEF, VC1=SEF1
        },
        .rx_ex_mask = 0x40,
        .rx_attr_ex = {
                .stop_check_instart = 1,
        }
};

Differences from Linear mode:

  • channel_num = 2: DOL2 requires receiving data from two virtual channels VC0 and VC1, Linear is 1

  • channel_sel = {0, 1}: Specifies receiving VC0 and VC1

  • framelenth: DOL2 and Linear frame lengths differ, verify based on actual VMAX configuration

Camera Configuration

static camera_config_t imx415_camera_config = {
        .name = "imx415",
        .addr = 0x1a,
        .sensor_mode = DOL2_M,                    // DOL2 mode (Linear is NORMAL_M)
        .fps = 30,
        .format = RAW10,
        .width = 3840,
        .height = 2160,
        .gpio_enable_bit = 0x01,
        .gpio_level_bit = 0x00,
        .mipi_cfg = &imx415_mipi_config,
        .calib_lname = "imx415_hdr_tuning.json",  //HDR-specific tuning file
};

Differences from Linear mode:

  • sensor_mode = DOL2_M: Determines that driver init/start/gain/line take the DOL2 branch

  • calib_lname: Requires an HDR-specific tuning file

VIN Configuration

VIN configuration is the part with the most differences between DOL2 and Linear:

static vin_node_attr_t imx415_vin_node_attr = {
        .cim_attr = {
                .mipi_rx = 0,
                .vc_index = 0,             // Start from VC0
                .ipi_channel = 2,          // DOL2: 2 IPI channels (Linear is 1)
                .cim_isp_flyby = 1,        // DOL2 only supports online mode
                .func = {
                        .enable_frame_id = 1,
                        .set_init_frame_id = 0,
                        .hdr_mode = DOL_2,  //Notify ISP to do two-frame synthesis (Linear is NOT_HDR)
                        .time_stamp_en = 0,
                },
        },
};

Key parameter description (refer to VIN API Data Structures):

Parameter Linear Value DOL2 Value Description
ipi_channel 1 2 DOL2 requires 2 IPI channels to receive VC0 (LEF) and VC1 (SEF1) separately
cim_isp_flyby 0 1 DOL2 typically uses VIN online ISP (PASSTHROUGH_MODE)
hdr_mode NOT_HDR (0) DOL_2 (1) 0: no multi-frame synthesis; 1: SoC does two-frame synthesis; 2: three-frame synthesis (not supported by X5)

VIN output channel configuration:

static vin_ochn_attr_t imx415_vin_ochn_attr = {
        .ddr_en = 0,                   // 0 in online mode
        .ochn_attr_type = VIN_BASIC_ATTR,
        .vin_basic_attr = {
                .format = RAW10,
                .wstride = (SENSOR_WIDTH) * 2,
        },
};

ISP Configuration

ISP needs to be set to DOL2 synthesis mode, working with VIN online:

static isp_attr_t imx415_isp_attr = {
        .input_mode = PASSTHROUGH_MODE,  // online
        .sensor_mode = ISP_DOL2_M,       // DOL2 synthesis mode
        .tile_mode = 0,
        .crop = {
                .x = 0, .y = 0,
                .h = 2160, .w = 3840,
        },
};

Key parameter description (refer to HBN API Data Structures):

Parameter Linear Value DOL2 Value Description
input_mode DDR_MODE (2) PASSTHROUGH_MODE (0) Corresponds to cim_isp_flyby=1, VIN and ISP connect without going through DDR
sensor_mode ISP_NORMAL_M (0) ISP_DOL2_M (1) ISP performs DOL2 two-frame HDR synthesis internally

Note: When using VIN online ISP, the binding method for hbn_vflow_bind_vnode is src_out_channel=1, dst_input_channel=0, which differs from the src_out_channel=0 used in Linear offline mode.

Complete Parameter Summary

Configuration Item Parameter Name / Location Value Description
Top-level config_file "dol2_3840x2160_raw10_30fps_4lane.c"
sensor_name "imx415-30fps-4lane-dol2"
chip_id_reg / chip_id 0x3F12 / 0x0514
sensor_i2c_addr_list {0x1A}
support_sensor_mode {DOL2_M}
MIPI lane 4
datatype RAW10 (0x2B)
fps 30
mipiclk 7128 (Mbps)
width / height 3840 / 2160
linelenth / framelenth 6400 / 4700
settle 10
channel_num 2
channel_sel {0, 1}
stop_check_instart 1
Camera name / addr "imx415" / 0x1A
sensor_mode DOL2_M
format RAW10
gpio_enable_bit / gpio_level_bit 0x01 / 0x00
calib_lname "imx415_hdr_tuning.json"
VIN mipi_rx 0
vc_index 0
ipi_channel 2
cim_isp_flyby 1 (online)
hdr_mode DOL_2
mclk_freq (vin_attr_ex) 24000000
VIN Output ddr_en 0 (online mode)
wstride SENSOR_WIDTH x 2 (RAW10 is x2)
ISP Input input_mode PASSTHROUGH_MODE
sensor_mode ISP_DOL2_M
crop x=0, y=0, w=3840, h=2160
input_fmt FRM_FMT_RAW
input_bit_width 10
ISP Output output_fmt FRM_FMT_NV12
output_bit_width 8
ddr_en 1

5.17.6.4. Program Verification

  1. get_vin_data: Confirm that raw images have no severe color cast and frame rate matches the configuration. In DOL2 mode, there will be data from two channels.

  2. get_isp_data: Prepare imx415_hdr_tuning.json (can copy an HDR json of the same resolution and change sensor_name), confirm that the ISP-synthesized YUV image is normal, and that bright and dark areas have richer detail compared to Linear mode.

  3. hbplayer: Connect to the board to preview short frame, long frame, and YUV data. See hbplayer and tuning_tool Usage Guide.

  4. tuning_tool: Use tuning_tool to connect to hbplayer, enter command e, configure Manual AE, set aGain and integrationTime for LEF and SEF1 respectively, check driver prints to verify SHR0 (0x3050~0x3052), SHR1 (0x3054~0x3056), GAIN_PGC0 (0x3090), GAIN_PGC1 (0x3092) match the spec. ISP gain limits can be configured in imx415_hdr_tuning.json for self-testing.

For common issues, see Camera Sensor FAQ.