Compare commits

..

5 Commits

Author SHA1 Message Date
dchvs c2113b443d Fix low framerate 2021-03-08 16:29:16 -06:00
dchvs ca8e71f447 Add script to control AE on sensor-id=0 2021-03-08 16:29:16 -06:00
dchvs 7f1843d73d Fix gain equation on Driver 2021-03-08 16:29:16 -06:00
dchvs fef47412d5 documentation: Update README with AE 2021-03-08 16:29:16 -06:00
dchvs cccd9ac76c Fix gain & exposure range on DTB 2021-03-08 16:29:16 -06:00
5 changed files with 143 additions and 215 deletions

View File

@ -5,16 +5,14 @@ The camera sensors should be conencted to a ConnectTech's Elroy board.
## Features
* V4L2 Kernel Driver Version 2.0 supported on L4T32.4.4
* V4L2 Kernel Driver Version 2.0 supported on L4T32.2.1
* V4l2 controls
* test pattern
* individual gains
* vertical/horizontal flip
* flash control
* LibArgus and nvarguscamerasrc
* Resolutions supported:
* 1280x720 @ 60fps
* 1280x960 @ 45fps
* Resolution supported: 1280x720 @ 60fps
* Gain, exposure, and framerate controls
* Camera synchronization
@ -102,13 +100,28 @@ The AE controls realays in the feedback provided by the Driver's camera sensor t
and the custom DTSIs with the sensor parameters definitions.
As the AE has interdependency with the digital gain. This gain it's and operation on the Driver, and follows this setup:
MT9M021 sensor datasheet:
```bash
/*
* Digital gain equation:
*
* RANGE: 1x, 7.97x
* GAIN: VAL / STEPS;
* STEPS: 1/32
*
* SCALE FACTOR = 100.000
*
* min_gain_val = 100.000
* max_gain_val = 797.000
* step_gain_val = 3125
*/
MT9M021 sensor datasheet:
* <a href="https://files.niemo.de/aptina_pdfs/MT9M021-M031_Developer_Guide.pdf">MT9M021 Developer Guide</a>
```
Where, the `min_gain_val, max_gain_val, step_gain_val` are part of the cameras' DTSI (tegra186-tx2-spiri-camera.dtsi) fixed parameters
as per the datasheet. The `gain` consists on the steps (1x + n * 1/32 for the register) scaled to a value that represents this fraction in an integer value for the gain register.
Where, the min_gain_val, max_gain_val, step_gain_val are part of the cameras' DTSI (tegra186-tx2-spiri-camera.dtsi) fixed parameters
as per the datasheet. The step_gain_val consists of the steps (1/32 for the register) scaled to a value that makes this fraction become an significant
in integer.
#### Kernel Changes

View File

@ -93,71 +93,31 @@ i2c8 = "/i2c@31e0000";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
min_gain_val = "100000";
max_gain_val = "796000";
step_gain_val = "1";
default_gain = "100000"; /* 1x */
default_gain = "100000";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "60000000";
max_framerate = "60000000";
step_framerate = "1";
default_framerate = "60000000"; // 60.0 fps
default_framerate = "60000000"; // 60.0 fps
min_exp_time = "100"; // us
max_exp_time = "16620"; // us
min_exp_time = "500"; // us
max_exp_time = "16000"; // us
step_exp_time = "1";
default_exp_time = "16620"; // us
default_exp_time = "12000"; // us
};
mode1 {
mclk_khz = "24000";
num_lanes = "1";
tegra_sinterface = "serial_b";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "26";
active_w = "1280";
active_h = "960";
dynamic_pixel_bit_depth = "12";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
step_gain_val = "1";
default_gain = "100000"; /* 1x */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "45000000";
step_framerate = "1";
default_framerate = "45000000"; // 45.0 fps
min_exp_time = "100"; // us
max_exp_time = "22220"; // us
step_exp_time = "1";
default_exp_time = "22220"; // us
};
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;
@ -220,18 +180,18 @@ i2c8 = "/i2c@31e0000";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
min_gain_val = "100000";
max_gain_val = "796000";
step_gain_val = "1";
default_gain = "100000"; /* 1x */
default_gain = "100000";
min_hdr_ratio = "1";
max_hdr_ratio = "1";
@ -240,50 +200,11 @@ i2c8 = "/i2c@31e0000";
step_framerate = "1";
default_framerate = "60000000"; // 60.0 fps
min_exp_time = "100"; // us
max_exp_time = "16620"; // us
min_exp_time = "500"; // us
max_exp_time = "16000"; // us
step_exp_time = "1";
default_exp_time = "16620"; // us
default_exp_time = "12000"; // us
};
mode1 {
mclk_khz = "24000";
num_lanes = "1";
tegra_sinterface = "serial_a";
discontinuous_clk = "no";
dpcm_enable = "false";
cil_settletime = "26";
active_w = "1280";
active_h = "960";
dynamic_pixel_bit_depth = "12";
csi_pixel_bit_depth = "12";
mode_type = "bayer";
pixel_phase = "rggb";
readout_orientation = "0";
line_length = "1650";
inherent_gain = "1";
pix_clk_hz = "74250000";
gain_factor = "3125";
framerate_factor = "1000000";
exposure_factor = "1000000";
min_gain_val = "100000"; /* 1x */
max_gain_val = "796875"; /* 7.97x */
step_gain_val = "1";
default_gain = "100000"; /* 1x */
min_hdr_ratio = "1";
max_hdr_ratio = "1";
min_framerate = "2000000";
max_framerate = "45000000";
step_framerate = "1";
default_framerate = "45000000"; // 45.0 fps
min_exp_time = "100"; // us
max_exp_time = "22220"; // us
step_exp_time = "1";
default_exp_time = "22220"; // us
};
ports {
#address-cells = <0x1>;
#size-cells = <0x0>;

View File

@ -135,8 +135,8 @@
#define MT9M021_ANALOG_GAIN_SHIFT 4
#define MT9M021_ANALOG_GAIN_MASK 0x0030
#define MT9M021_GLOBAL_GAIN_MIN 100
#define MT9M021_GLOBAL_GAIN_MAX 762
#define MT9M021_GLOBAL_GAIN_MIN 100000
#define MT9M021_GLOBAL_GAIN_MAX 796000
#define MT9M021_GLOBAL_GAIN_DEF 100
#define MT9M021_COARSE_INT_TIME_MIN 0x0001
@ -396,39 +396,67 @@ static int mt9m021_set_gain(struct tegracam_device *tc_dev, s64 val)
{
struct camera_common_data *s_data = tc_dev->s_data;
struct device *dev = tc_dev->dev;
int err = 0;
u64 gain = 0;
int err = 0;
u16 gain_mul;
u16 reg16 = 0;
u64 gain = 0;
dev_dbg(dev, "Setting Gain to: %lld", val);
/*
* Digital gain equation:
*
* RANGE: 1x, 7.97x
* STEPS: 1/32
*
* gain accepts mapping from range 32 - 255
*
* SCALE FACTOR = 3125
*
* min_gain_val = 100000
* max_gain_val = 796875
* gain_factor = 3125
*
*/
gain = val / 3125;
if (val >= MT9M021_GAIN_8X_FIXED) {
gain_mul = MT9M021_GAIN_8X;
} else if (val >= MT9M021_GAIN_4X_FIXED) {
gain_mul = MT9M021_GAIN_4X;
} else if (val >= MT9M021_GAIN_2X_FIXED) {
gain_mul = MT9M021_GAIN_2X;
} else {
gain_mul = MT9M021_GAIN_1X;
}
/*
* Digital gain equation:
*
* RANGE: 1x, 7.97x
* GAIN: VAL / STEPS;
* STEPS: 1/32
*
* SCALE FACTOR = 100.000
*
* min_gain_val = 100.000
* max_gain_val = 797.000
* gain_factor = 3125
*
* gain maps to range 32 - 255
*/
gain = val / 3125;
/* Update analog gain multiplier */
err = mt9m021_read_reg16(s_data, MT9M021_DIGITAL_TEST, &reg16);
if (err)
goto exit;
reg16 =
(reg16 & ~MT9M021_ANALOG_GAIN_MASK) |
((gain_mul << MT9M021_ANALOG_GAIN_SHIFT) &
MT9M021_ANALOG_GAIN_MASK);
err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16);
// msleep(10);
if (err)
goto exit;
/* Update global gain */
err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN, gain);
err =
mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN, gain);
// msleep(10);
if (err)
goto exit;
err = mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN_CB, gain);
err =
mt9m021_write_reg16(s_data, MT9M021_GLOBAL_GAIN_CB, gain);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Gain control error: %d", err);
return err;
@ -464,8 +492,8 @@ static int mt9m021_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
/* Calculate frame-length */
frame_length = mode->signal_properties.pixel_clock.val *
mode->control_properties.framerate_factor /
mode->image_properties.line_length / val;
mode->control_properties.framerate_factor /
mode->image_properties.line_length / val;
err = mt9m021_set_frame_length(priv, frame_length);
if (err)
@ -473,7 +501,7 @@ static int mt9m021_set_frame_rate(struct tegracam_device *tc_dev, s64 val)
return 0;
exit:
exit:
dev_err(dev, "Frame rate control error: %d", err);
return err;
}
@ -486,12 +514,13 @@ static int mt9m021_set_coarse_time(struct mt9m021 *priv, s64 val)
dev_dbg(dev, "Setting Coarse Time to: %lld", val);
err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME, val);
err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME, val);
if (err)
return err;
err = mt9m021_write_reg16(s_data, MT9M021_COARSE_INT_TIME_CB, val);
if (err)
return err;
// msleep(30);
return 0;
}
@ -502,24 +531,24 @@ static int mt9m021_set_exposure(struct tegracam_device *tc_dev, s64 val)
struct mt9m021 *priv = (struct mt9m021 *)tc_dev->priv;
struct device *dev = tc_dev->dev;
const struct sensor_mode_properties *mode =
&s_data->sensor_props.sensor_modes[s_data->mode];
&s_data->sensor_props.sensor_modes[s_data->mode];
u64 coarse_time;
int err = 0;
dev_dbg(dev, "Setting Exposure Time to : %lld", val);
dev_dbg(dev, "Setting Exposure Time to : %lld", val);
coarse_time =
val * mode->signal_properties.pixel_clock.val /
mode->image_properties.line_length /
mode->control_properties.exposure_factor;
coarse_time =
val * mode->signal_properties.pixel_clock.val /
mode->image_properties.line_length /
mode->control_properties.exposure_factor;
err = mt9m021_set_coarse_time(priv, coarse_time);
err = mt9m021_set_coarse_time(priv, coarse_time);
if (err)
goto exit;
return err;
exit:
exit:
dev_err(dev, "Exposure control error: %d", err);
return err;
}
@ -539,14 +568,16 @@ static int mt9m021_set_analog_gain(struct tegracam_device *tc_dev, s64 val)
goto exit;
reg16 =
(reg16 & ~MT9M021_ANALOG_GAIN_MASK) |
((val << MT9M021_ANALOG_GAIN_SHIFT) & MT9M021_ANALOG_GAIN_MASK);
((val << MT9M021_ANALOG_GAIN_SHIFT) &
MT9M021_ANALOG_GAIN_MASK);
err = mt9m021_write_reg16(s_data, MT9M021_DIGITAL_TEST, reg16);
// msleep(30);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Analog Gain control error: %d", err);
return err;
@ -596,10 +627,11 @@ static int mt9m021_set_digital_gain(struct tegracam_device *tc_dev, s64 val,
err = mt9m021_write_reg16(s_data, gain_cb_reg, val);
if (err)
goto exit;
// msleep(30);
return 0;
exit:
exit:
dev_err(dev, "Digital Gain control error: %d", err);
return err;
}
@ -616,13 +648,15 @@ static int mt9m021_set_test_pattern(struct tegracam_device *tc_dev, s32 val)
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN,
MT9M021_TEST_PATTERN_VAL);
else
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN, val);
err = mt9m021_write_reg16(s_data, MT9M021_TEST_PATTERN,
val);
// msleep(30);
if (err)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Test Pattern control error: %d", err);
return err;
@ -637,7 +671,7 @@ static int mt9m021_set_flash(struct tegracam_device *tc_dev, s32 val)
dev_dbg(dev, "Setting Flash to: %d", val);
switch (val) {
switch(val) {
case V4L2_FLASH_LED_MODE_NONE:
err = mt9m021_write_reg16(s_data, MT9M021_FLASH, 0x0000);
priv->flash_en = false;
@ -656,7 +690,7 @@ static int mt9m021_set_flash(struct tegracam_device *tc_dev, s32 val)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Flash control error: %d", err);
return err;
@ -670,7 +704,7 @@ static int mt9m021_set_flip(struct tegracam_device *tc_dev, s32 val, int id)
dev_dbg(dev, "Setting Flip to: %d", val);
switch (id) {
switch(id) {
case V4L2_CID_HFLIP:
err = mt9m021_update_bits(s_data, MT9M021_READ_MODE,
val << 14, MT9M021_HFLIP_MASK);
@ -689,7 +723,7 @@ static int mt9m021_set_flip(struct tegracam_device *tc_dev, s32 val, int id)
goto exit;
return 0;
exit:
exit:
dev_err(dev, "Flip control error: %d", err);
return err;
@ -760,7 +794,7 @@ static int mt9m021_power_off(struct camera_common_data *s_data)
usleep_range(2000, 2010);
}
power_off_done:
power_off_done:
pw->state = SWITCH_OFF;
return 0;
@ -882,7 +916,7 @@ static struct camera_common_pdata *mt9m021_parse_dt(struct tegracam_device
return board_priv_pdata;
error:
error:
devm_kfree(dev, board_priv_pdata);
return ret;
@ -929,10 +963,15 @@ static int mt9m021_col_correction(struct mt9m021 *priv)
if (ret < 0)
return ret;
// msleep(200);
// usleep(200);
/* Enable Streaming */
ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_START_STREAM]);
if (ret < 0)
return ret;
// msleep(200);
// usleep(200);
/* Disable Streaming */
ret = mt9m021_write_table(priv, mode_table[MT9M021_MODE_STOP_STREAM]);
@ -943,6 +982,8 @@ static int mt9m021_col_correction(struct mt9m021 *priv)
ret = mt9m021_write_reg16(s_data, MT9M021_COLUMN_CORRECTION, 0xE007);
if (ret < 0)
return ret;
// msleep(200);
// usleep(200);
return ret;
}
@ -972,7 +1013,7 @@ static int mt9m021_set_mode(struct tegracam_device *tc_dev)
dev_err(dev, "%s: Failed to set pll setup\n", __func__);
return ret;
}
msleep(100);
msleep(100);
ret = mt9m021_col_correction(priv);
if (ret < 0) {
@ -1057,7 +1098,7 @@ static int mt9m021_get_trigger_mode(struct mt9m021 *priv)
}
err =
of_property_read_string(node, "trigger_mode", &priv->trigger_mode);
of_property_read_string(node, "trigger_mode", &priv->trigger_mode);
if (err == -EINVAL) {
dev_warn(&client->dev, "trigger_mode not in device tree\n");
*(&priv->trigger_mode) = "master";
@ -1089,8 +1130,7 @@ static int mt9m021_verify_chip_id(struct mt9m021 *priv)
err = mt9m021_read_reg16(s_data, MT9M021_CHIP_ID_REG, &chip_id);
if (!err)
break;
dev_info(&client->dev,
"Failed to read Chip ID, trying again\n");
dev_info(&client->dev, "Failed to read Chip ID, trying again\n");
max_retries--;
msleep(30);
}
@ -1106,7 +1146,7 @@ static int mt9m021_verify_chip_id(struct mt9m021 *priv)
goto exit;
}
exit:
exit:
ret = mt9m021_power_off(s_data);
if (ret)
return ret;

View File

@ -31,12 +31,12 @@
#define mt9m021_reg struct reg_16
static const mt9m021_reg mt9m021_start[] = {
{0x301A, 0x00DC}, /* Enable Streaming */
{0x301A, 0x00DC}, /* Enable Streaming */
{MT9M021_TABLE_END, 0x00}
};
static const mt9m021_reg mt9m021_stop[] = {
{0x301A, 0x00D8}, /* Disable Streaming */
{0x301A, 0x00D8}, /* Disable Streaming */
{MT9M021_TABLE_END, 0x00}
};
@ -102,42 +102,8 @@ static const mt9m021_reg mt9m021_mode_1280x720_60fps[] = {
{MT9M021_TABLE_END, 0x00}
};
static const mt9m021_reg mt9m021_mode_1280x960_45fps[] = {
/* Rev2 Settings */
{0x307A, 0x0000},
{0x30EA, 0x0C00},
{0x3044, 0x0404},
{0x301E, 0x012C},
{0x3180, 0x8000},
{0x3014, 0x0000},
/* Analog Settings */
{0x3ED6, 0x00FD},
{0x3ED8, 0x0FFF},
{0x3EDA, 0x0003},
{0x3EDC, 0xF87A},
{0x3EDE, 0xE075},
{0x3EE0, 0x077C},
{0x3EE2, 0xA4EB},
{0x3EE4, 0xD208},
/* Size Settings */
{0x3064, 0x1802}, /* EMBEDDED_DATA_CTRL */
{0x3032, 0x0020}, /* DIGITAL_BINNING */
{0x3002, 0x0004}, /* Y ADDR START */
{0x3004, 0x0001}, /* X ADDR START */
{0x3006, 0x03C3}, /* Y ADDR END */
{0x3008, 0x0500}, /* X ADDR END */
{0x300A, 0x03DE}, /* FRAME_LENGTH_LINES */
{0x300C, 0x0672}, /* LINE_LENGTH_PCK */
{0x30A2, 0x0001}, /* X_ODD_INC */
{0x30A6, 0x0001}, /* Y_ODD_INC */
{MT9M021_TABLE_END, 0x00}
};
enum {
MT9M021_MODE_1280x720_60FPS,
MT9M021_MODE_1280x960_45FPS,
MT9M021_MODE_PLL_SETUP,
@ -146,16 +112,15 @@ enum {
};
static const mt9m021_reg *mode_table[] = {
[MT9M021_MODE_1280x720_60FPS] = mt9m021_mode_1280x720_60fps,
[MT9M021_MODE_1280x960_45FPS] = mt9m021_mode_1280x960_45fps,
[MT9M021_MODE_1280x720_60FPS] = mt9m021_mode_1280x720_60fps,
[MT9M021_MODE_PLL_SETUP] = mt9m021_pll_setup,
[MT9M021_MODE_PLL_SETUP] = mt9m021_pll_setup,
[MT9M021_MODE_START_STREAM] = mt9m021_start,
[MT9M021_MODE_STOP_STREAM] = mt9m021_stop,
[MT9M021_MODE_START_STREAM] = mt9m021_start,
[MT9M021_MODE_STOP_STREAM] = mt9m021_stop,
};
static const int mt9m021_framerates_1280x720[] = {
static const int mt9m021_framerates[] = {
10,
20,
30,
@ -164,19 +129,8 @@ static const int mt9m021_framerates_1280x720[] = {
60,
};
static const int mt9m021_framerates_1280x960[] = {
10,
20,
30,
40,
45,
};
static const struct camera_common_frmfmt mt9m021_frmfmt[] = {
{{1280, 720}, mt9m021_framerates_1280x720, 1, 0,
MT9M021_MODE_1280x720_60FPS},
{{1280, 960}, mt9m021_framerates_1280x960, 1, 0,
MT9M021_MODE_1280x960_45FPS},
{{1280, 720}, mt9m021_framerates, 1, 0, MT9M021_MODE_1280x720_60FPS},
};
#endif /* __MT9M021_I2C_TABLES__ */
#endif /* __MT9M021_I2C_TABLES__ */

View File

@ -5,7 +5,7 @@ initial_exposure_time=0
while true; do sleep 0.5;
# Read center camera controls
echo `v4l2-ctl -d /dev/video0 --get-ctrl=gain --get-ctrl=exposure` > controls
echo `v4l2-ctl -d /dev/video1 --get-ctrl=gain --get-ctrl=exposure` > controls
awk '{print $2}' controls > get_control
actual_gain=`cat get_control`
awk '{print $4}' controls > get_control
@ -18,10 +18,10 @@ while true; do sleep 0.5;
rm controls get_control
# Set R/L camera controls manually
if [ $actual_gain -ne $initial_gain ]; then
v4l2-ctl -d /dev/video1 --set-ctrl=gain=$actual_gain
v4l2-ctl -d /dev/video0 --set-ctrl=gain=$actual_gain
fi
if [ $actual_exposure_time -ne $initial_exposure_time ]; then
v4l2-ctl -d /dev/video1 --set-ctrl=exposure=$actual_exposure_time
v4l2-ctl -d /dev/video0 --set-ctrl=exposure=$actual_exposure_time
fi
# Define new initial value
initial_gain=$actual_gain