drivers/video: Support spot position setting

Add new control id V4L2_CID_EXPOSURE_METERING_SPOT_POSITION
to support spot position setting in spot exposure metering.
This commit is contained in:
SPRESENSE 2023-01-15 20:01:50 +09:00 committed by Xiang Xiao
parent 3ba792cb52
commit e542ef9175
9 changed files with 408 additions and 0 deletions

View File

@ -152,6 +152,11 @@
#define CLIP_SIZE_UNIT (8)
#define RESCALE_FOR_CLIP(v, a, b) (((v) * (a)) / (b))
/* The number of whole image splits for spot position decision. */
#define ISX012_SPOT_POSITION_SPLIT_NUM_X (9)
#define ISX012_SPOT_POSITION_SPLIT_NUM_Y (7)
/****************************************************************************
* Private Types
****************************************************************************/
@ -1902,6 +1907,15 @@ static int isx012_get_supported_value(FAR struct imgsensor_s *sensor,
break;
case IMGSENSOR_ID_SPOT_POSITION:
value->type = IMGSENSOR_CTRL_TYPE_INTEGER;
range->minimum = ISX012_MIN_SPOTPOS;
range->maximum = ISX012_MAX_SPOTPOS;
range->step = ISX012_STEP_SPOTPOS;
range->default_value = ISX012_DEF_SPOTPOS;
break;
case IMGSENSOR_ID_AUTO_N_PRESET_WB:
value->type = IMGSENSOR_CTRL_TYPE_INTEGER_MENU;
discrete->nr_values = ARRAY_NENTRIES(g_isx012_presetwb_actual);
@ -1981,6 +1995,70 @@ static int isx012_get_supported_value(FAR struct imgsensor_s *sensor,
return ret;
}
static void get_current_framesize(FAR struct isx012_dev_s *priv,
FAR uint16_t *w,
FAR uint16_t *h)
{
uint16_t w_addr = HSIZE_MONI;
uint16_t h_addr = VSIZE_MONI;
switch (priv->mode)
{
case REGVAL_MODESEL_MON:
w_addr = HSIZE_MONI;
h_addr = VSIZE_MONI;
break;
case REGVAL_MODESEL_MOV:
w_addr = HSIZE_MOVIE;
h_addr = VSIZE_MOVIE;
break;
case REGVAL_MODESEL_CAP:
w_addr = HSIZE_CAP;
h_addr = VSIZE_CAP;
break;
default:
/* It does not come here due to register specification. */
break;
}
*w = isx012_getreg(priv, w_addr, 2);
*h = isx012_getreg(priv, h_addr, 2);
}
static uint32_t restore_spot_position(uint8_t regval,
uint16_t w,
uint16_t split)
{
return ((regval * w) / split + (w / split) / 2);
}
static int32_t get_spot_position(FAR struct isx012_dev_s *priv)
{
uint16_t regval;
uint16_t reg_x;
uint16_t reg_y;
uint32_t x;
uint32_t y;
uint16_t w;
uint16_t h;
regval = isx012_getreg(priv, SPOT_FRM_NUM, 1);
reg_x = regval % ISX012_SPOT_POSITION_SPLIT_NUM_X;
reg_y = regval / ISX012_SPOT_POSITION_SPLIT_NUM_X;
get_current_framesize(priv, &w, &h);
x = restore_spot_position(reg_x, w, ISX012_SPOT_POSITION_SPLIT_NUM_X);
y = restore_spot_position(reg_y, h, ISX012_SPOT_POSITION_SPLIT_NUM_Y);
return (int32_t)((x << 16) | y);
}
static int isx012_get_value(FAR struct imgsensor_s *sensor,
uint32_t id, uint32_t size,
FAR imgsensor_value_t *value)
@ -2245,6 +2323,10 @@ static int isx012_get_value(FAR struct imgsensor_s *sensor,
break;
case IMGSENSOR_ID_SPOT_POSITION:
value->value32 = get_spot_position(priv);
break;
case IMGSENSOR_ID_3A_PARAMETER:
if (value->p_u16 == NULL)
{
@ -2356,6 +2438,31 @@ static int set_clip(uint32_t size,
return OK;
}
static int set_spot_position(FAR struct isx012_dev_s *priv, int32_t val)
{
uint16_t w;
uint16_t h;
uint16_t x = (uint16_t)(val >> 16);
uint16_t y = (uint16_t)(val & 0xffff);
uint8_t reg_x;
uint8_t reg_y;
uint8_t reg;
get_current_framesize(priv, &w, &h);
if ((x >= w) || (y >= h))
{
return -EINVAL;
}
reg_x = (x * ISX012_SPOT_POSITION_SPLIT_NUM_X) / w;
reg_y = (y * ISX012_SPOT_POSITION_SPLIT_NUM_Y) / h;
reg = reg_y * ISX012_SPOT_POSITION_SPLIT_NUM_X + reg_x;
return isx012_putreg(priv, SPOT_FRM_NUM, reg, 1);
}
static int isx012_set_value(FAR struct imgsensor_s *sensor,
uint32_t id, uint32_t size,
imgsensor_value_t value)
@ -2854,6 +2961,19 @@ static int isx012_set_value(FAR struct imgsensor_s *sensor,
break;
case IMGSENSOR_ID_SPOT_POSITION:
ret = VALIDATE_VALUE(value.value32,
ISX012_MIN_SPOTPOS,
ISX012_MAX_SPOTPOS,
ISX012_STEP_SPOTPOS);
if (ret != OK)
{
break;
}
ret = set_spot_position(priv, value.value32);
break;
case IMGSENSOR_ID_AUTO_N_PRESET_WB:
for (cnt = 0;
cnt < ARRAY_NENTRIES(g_isx012_presetwb_actual);

View File

@ -222,6 +222,16 @@
#define ISX012_REG_PHOTOMETRY AE_SUB_SN1
#define ISX012_SIZE_PHOTOMETRY (1)
/* Definition for control spot position */
#define ISX012_TYPE_SPOTPOS V4L2_CTRL_TYPE_INTEGER
#define ISX012_DEF_SPOTPOS (0x051003cc)
#define ISX012_MIN_SPOTPOS (0)
#define ISX012_MAX_SPOTPOS (0x0a200798)
#define ISX012_STEP_SPOTPOS (1)
#define ISX012_REG_SPOTPOS SPOT_FRM_NUM
#define ISX012_SIZE_SPOTPOS (1)
/* Definition for control zoom */
#define ISX012_TYPE_ZOOM V4L2_CTRL_TYPE_U16FIXEDPOINT_Q8

View File

@ -667,6 +667,7 @@
#define AE_INIT_MASK_CNT (AE_BASE+0x002B)
#define AESPEED_INIT (AE_BASE+0x0031)
#define AESPEED_FAST (AE_BASE+0x0032)
#define SPOT_FRM_NUM (AE_BASE+0x0033)
#define FASTMOVE_TIMEOUT (AE_BASE+0x003D)
#define AE_START_LEVEL (AE_BASE+0x0040)

View File

@ -154,6 +154,16 @@
#define VTIME_PER_FRAME (30518)
#define INTERVAL_PER_FRAME (33333)
/* ISX019 image sensor output frame size. */
#define ISX019_WIDTH (1280)
#define ISX019_HEIGHT (960)
/* The number of whole image splits for spot position decision. */
#define ISX019_SPOT_POSITION_SPLIT_NUM_X (9)
#define ISX019_SPOT_POSITION_SPLIT_NUM_Y (7)
/****************************************************************************
* Private Types
****************************************************************************/
@ -179,6 +189,7 @@ struct isx019_default_value_s
int32_t iso;
int32_t iso_auto;
int32_t meter;
int32_t spot_pos;
int32_t threealock;
int32_t threeastatus;
int32_t jpgquality;
@ -1238,6 +1249,7 @@ static void store_default_value(FAR isx019_dev_t *priv)
def->iso = get_value32(priv, IMGSENSOR_ID_ISO_SENSITIVITY);
def->iso_auto = get_value32(priv, IMGSENSOR_ID_ISO_SENSITIVITY_AUTO);
def->meter = get_value32(priv, IMGSENSOR_ID_EXPOSURE_METERING);
def->spot_pos = get_value32(priv, IMGSENSOR_ID_SPOT_POSITION);
def->threealock = get_value32(priv, IMGSENSOR_ID_3A_LOCK);
def->threeastatus = get_value32(priv, IMGSENSOR_ID_3A_STATUS);
def->jpgquality = get_value32(priv, IMGSENSOR_ID_JPEG_QUALITY);
@ -1888,6 +1900,12 @@ static int isx019_get_supported_value(FAR struct imgsensor_s *sensor,
STEP_METER, def->meter);
break;
case IMGSENSOR_ID_SPOT_POSITION:
val->type = IMGSENSOR_CTRL_TYPE_INTEGER;
SET_RANGE(val->u.range, MIN_SPOTPOS, MAX_SPOTPOS,
STEP_SPOTPOS, def->spot_pos);
break;
case IMGSENSOR_ID_3A_LOCK:
val->type = IMGSENSOR_CTRL_TYPE_BITMASK;
SET_RANGE(val->u.range, MIN_3ALOCK, MAX_3ALOCK,
@ -2364,6 +2382,158 @@ static int set_meter(FAR isx019_dev_t *priv,
return OK;
}
static void get_current_framesize(FAR isx019_dev_t *priv,
FAR uint16_t *w, FAR uint16_t *h)
{
uint8_t frmsz;
DEBUGASSERT(w && h);
fpga_i2c_read(priv, FPGA_FORMAT_AND_SCALE, &frmsz, 1);
switch (frmsz & 0xf0)
{
case FPGA_SCALE_1280_960:
*w = 1280;
*h = 960;
break;
case FPGA_SCALE_640_480:
*w = 640;
*h = 480;
break;
case FPGA_SCALE_320_240:
*w = 320;
*h = 240;
break;
case FPGA_SCALE_160_120:
*w = 160;
*h = 120;
break;
default:
/* It may not come here due to register specification */
break;
}
}
static void get_current_clip_setting(FAR isx019_dev_t *priv,
FAR uint16_t *w,
FAR uint16_t *h,
FAR uint16_t *offset_x,
FAR uint16_t *offset_y)
{
uint8_t sz;
uint8_t top;
uint8_t left;
fpga_i2c_read(priv, FPGA_CLIP_SIZE, &sz, 1);
fpga_i2c_read(priv, FPGA_CLIP_TOP, &top, 1);
fpga_i2c_read(priv, FPGA_CLIP_LEFT, &left, 1);
*offset_x = left * FPGA_CLIP_UNIT;
*offset_y = top * FPGA_CLIP_UNIT;
switch (sz)
{
case FPGA_CLIP_NON:
*w = 0;
*h = 0;
*offset_x = 0;
*offset_y = 0;
break;
case FPGA_CLIP_1280_720:
*w = 1280;
*h = 720;
break;
case FPGA_CLIP_640_360:
*w = 640;
*h = 360;
break;
default:
/* It may not come here due to register specification */
break;
}
}
static int calc_spot_position_regval(uint16_t val,
uint16_t basis,
uint16_t sz,
uint16_t offset,
int split)
{
int ret;
int ratio;
/* Change basis from `sz` to `basis` about `val` and `offset`. */
ratio = basis / sz;
ret = val * ratio;
ret += (offset * FPGA_CLIP_UNIT * ratio);
return (ret * split) / basis;
}
static int set_spot_position(FAR isx019_dev_t *priv,
imgsensor_value_t val)
{
uint8_t regval;
uint8_t reg_x;
uint8_t reg_y;
uint16_t w;
uint16_t h;
uint16_t clip_w;
uint16_t clip_h;
uint16_t offset_x;
uint16_t offset_y;
uint16_t x = (uint16_t)(val.value32 >> 16);
uint16_t y = (uint16_t)(val.value32 & 0xffff);
int split;
/* Spot position of ISX019 is divided into 9x7 sections.
* - Horizontal direction is devided into 9 sections.
* - Vertical direction is divided into 7 sections.
* The register value 0 means left top.
* The register value 62 means right bottom.
* Then, the following ISX019 board flow.
* - image sensor output the 1280x960 image
* - FPGA scale
* - FPGA clipping
*/
get_current_framesize(priv, &w, &h);
if ((x >= w) || (y >= h))
{
return -EINVAL;
}
get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y);
if ((clip_w != 0) && (clip_h != 0))
{
if ((x >= clip_w) || (y >= clip_h))
{
return -EINVAL;
}
}
split = ISX019_SPOT_POSITION_SPLIT_NUM_X;
reg_x = calc_spot_position_regval(x, 1280, w, offset_x, split);
split = ISX019_SPOT_POSITION_SPLIT_NUM_Y;
reg_y = calc_spot_position_regval(y, 960, h, offset_y, split);
regval = reg_y * ISX019_SPOT_POSITION_SPLIT_NUM_X + reg_x;
return isx019_i2c_write(priv, CAT_CATAE, SPOT_FRM_NUM, &regval, 1);
}
static int set_3alock(FAR isx019_dev_t *priv,
imgsensor_value_t val)
{
@ -2783,6 +2953,10 @@ static setvalue_t set_value_func(uint32_t id)
func = set_meter;
break;
case IMGSENSOR_ID_SPOT_POSITION:
func = set_spot_position;
break;
case IMGSENSOR_ID_3A_LOCK:
func = set_3alock;
break;
@ -2972,6 +3146,83 @@ static int get_meter(FAR isx019_dev_t *priv,
return OK;
}
static uint32_t restore_spot_position(uint16_t regval,
uint16_t basis,
uint16_t sz,
uint16_t clip_sz,
uint16_t offset,
uint16_t split)
{
uint16_t ret;
uint16_t unit;
uint16_t border;
/* First, convert register value to coordinate value. */
unit = basis / split;
ret = (regval * unit) + (unit / 2);
/* Second, consider the ratio between basis size and frame size. */
ret = ret * sz / basis;
/* Third, consider offset value of clip setting. */
if (ret > offset)
{
ret = ret - offset;
}
else
{
ret = 0;
}
/* If the coordinate protrudes from the frame,
* regard it as the boader of the frame.
*/
border = (clip_sz != 0) ? (clip_sz - 1) : (sz - 1);
if (ret > border)
{
ret = border;
}
return ret;
}
static int get_spot_position(FAR isx019_dev_t *priv,
FAR imgsensor_value_t *val)
{
uint8_t regval;
uint8_t regx;
uint8_t regy;
uint16_t w;
uint16_t h;
uint32_t x;
uint32_t y;
uint16_t clip_w;
uint16_t clip_h;
uint16_t offset_x;
uint16_t offset_y;
int split;
isx019_i2c_read(priv, CAT_CATAE, SPOT_FRM_NUM, &regval, 1);
regx = regval % ISX019_SPOT_POSITION_SPLIT_NUM_X;
regy = regval / ISX019_SPOT_POSITION_SPLIT_NUM_X;
get_current_framesize(priv, &w, &h);
get_current_clip_setting(priv, &clip_w, &clip_h, &offset_x, &offset_y);
split = ISX019_SPOT_POSITION_SPLIT_NUM_X;
x = restore_spot_position(regx, ISX019_WIDTH, w, clip_w, offset_x, split);
split = ISX019_SPOT_POSITION_SPLIT_NUM_Y;
y = restore_spot_position(regy, ISX019_HEIGHT, h, clip_h, offset_y, split);
val->value32 = (int32_t)((x << 16) | y);
return OK;
}
static int get_3alock(FAR isx019_dev_t *priv,
FAR imgsensor_value_t *val)
{
@ -3204,6 +3455,10 @@ static getvalue_t get_value_func(uint32_t id)
func = get_meter;
break;
case IMGSENSOR_ID_SPOT_POSITION:
func = get_spot_position;
break;
case IMGSENSOR_ID_3A_LOCK:
func = get_3alock;
break;

View File

@ -92,6 +92,10 @@
#define MAX_METER (3)
#define STEP_METER (1)
#define MIN_SPOTPOS (0x00000000)
#define MAX_SPOTPOS (0x050003c0)
#define STEP_SPOTPOS (1)
#define MIN_PAN (-32)
#define MAX_PAN (32)
#define STEP_PAN (1)

View File

@ -236,6 +236,7 @@
/* For CAT_CATAE */
#define AEMODE (0x0000)
#define SPOT_FRM_NUM (0x0003)
#define SHT_PRIMODE (0x0008)
#define GAIN_PRIMODE (0x000c)

View File

@ -171,6 +171,7 @@ struct video_scene_params_s
enum v4l2_iso_sensitivity_auto_type iso_auto;
int32_t iso;
enum v4l2_exposure_metering meter;
int32_t spot_pos;
int32_t threea_lock;
enum v4l2_flash_led_mode led;
int32_t jpeg_quality;
@ -409,6 +410,7 @@ static const video_parameter_name_t g_video_parameter_name[] =
{IMGSENSOR_ID_ISO_SENSITIVITY, "ISO sensitivity"},
{IMGSENSOR_ID_ISO_SENSITIVITY_AUTO, "Automatic ISO sensitivity"},
{IMGSENSOR_ID_EXPOSURE_METERING, "Photometry"},
{IMGSENSOR_ID_SPOT_POSITION, "Spot position"},
{IMGSENSOR_ID_3A_LOCK, "Lock AWB/AE"},
{IMGSENSOR_ID_AUTO_FOCUS_START, "Start single Auto Focus"},
{IMGSENSOR_ID_AUTO_FOCUS_STOP, "Stop single Auto Focus"},
@ -906,6 +908,7 @@ static void initialize_scene_parameter(video_scene_params_t *sp)
sp->iso_auto = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY_AUTO);
sp->iso = get_default_value(IMGSENSOR_ID_ISO_SENSITIVITY);
sp->meter = get_default_value(IMGSENSOR_ID_EXPOSURE_METERING);
sp->spot_pos = get_default_value(IMGSENSOR_ID_SPOT_POSITION);
sp->threea_lock = get_default_value(IMGSENSOR_ID_3A_LOCK);
sp->led = get_default_value(IMGSENSOR_ID_FLASH_LED_MODE);
sp->jpeg_quality = get_default_value(IMGSENSOR_ID_JPEG_QUALITY);
@ -2381,6 +2384,7 @@ static int reflect_scene_parameter(enum v4l2_scene_mode mode)
}
set_intvalue(IMGSENSOR_ID_EXPOSURE_METERING, sp->meter);
set_intvalue(IMGSENSOR_ID_SPOT_POSITION, sp->spot_pos);
set_intvalue(IMGSENSOR_ID_3A_LOCK, sp->threea_lock);
set_intvalue(IMGSENSOR_ID_FLASH_LED_MODE, sp->led);
set_intvalue(IMGSENSOR_ID_JPEG_QUALITY, sp->jpeg_quality);
@ -2621,6 +2625,10 @@ static int read_scene_param(enum v4l2_scene_mode mode,
control->value = sp->meter;
break;
case IMGSENSOR_ID_SPOT_POSITION:
control->value = sp->spot_pos;
break;
case IMGSENSOR_ID_3A_LOCK:
control->value = sp->threea_lock;
break;
@ -2932,6 +2940,10 @@ static int save_scene_param(enum v4l2_scene_mode mode,
sp->meter = control->value;
break;
case IMGSENSOR_ID_SPOT_POSITION:
sp->spot_pos = control->value;
break;
case IMGSENSOR_ID_3A_LOCK:
sp->threea_lock = control->value;
break;

View File

@ -69,6 +69,7 @@
#define IMGSENSOR_ID_ISO_SENSITIVITY (0x0001000d)
#define IMGSENSOR_ID_ISO_SENSITIVITY_AUTO (0x0001000e)
#define IMGSENSOR_ID_EXPOSURE_METERING (0x0001000f)
#define IMGSENSOR_ID_SPOT_POSITION (0x00010016)
#define IMGSENSOR_ID_3A_LOCK (0x00010011)
#define IMGSENSOR_ID_AUTO_FOCUS_START (0x00010012)
#define IMGSENSOR_ID_AUTO_FOCUS_STOP (0x00010013)

View File

@ -202,6 +202,10 @@ enum v4l2_scene_mode
#define V4L2_3A_STATUS_AWB_OPERATING (1 << 1) /**< AWB is operating */
#define V4L2_3A_STATUS_AF_OPERATING (1 << 2) /**< AF is operating */
/** Spot position in spot exposure metering */
#define V4L2_CID_EXPOSURE_METERING_SPOT_POSITION (22)
/** Flash and privacy (indicator) light controls */
#define V4L2_CID_FLASH_LED_MODE (0)