From 625119a0b76517162f7dca2c964e337f7ce0d9b7 Mon Sep 17 00:00:00 2001 From: SPRESENSE <41312067+SPRESENSE@users.noreply.github.com> Date: Sun, 15 Jan 2023 20:01:50 +0900 Subject: [PATCH] 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. --- drivers/video/isx012.c | 120 +++++++++++++ drivers/video/isx012_range.h | 10 ++ drivers/video/isx012_reg.h | 1 + drivers/video/isx019.c | 250 +++++++++++++++++++++++++++ drivers/video/isx019_range.h | 4 + drivers/video/isx019_reg.h | 1 + drivers/video/video.c | 12 ++ include/nuttx/video/imgsensor.h | 1 + include/nuttx/video/video_controls.h | 4 + 9 files changed, 403 insertions(+) diff --git a/drivers/video/isx012.c b/drivers/video/isx012.c index 764d38a650562..67126c3ed7f32 100644 --- a/drivers/video/isx012.c +++ b/drivers/video/isx012.c @@ -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 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 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 do not comes here due to register specification. */ + + break; + } + + *w = isx012_getreg(priv, w_addr, 2); + *h = isx012_getreg(priv, h_addr, 2); +} + +static uint16_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; + uint16_t x; + uint16_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 ((x << 16) | y); +} + static int isx012_get_value(uint32_t id, uint32_t size, FAR imgsensor_value_t *value) @@ -2245,6 +2323,10 @@ static int isx012_get_value(uint32_t id, break; + case IMGSENSOR_ID_SPOT_POSITION: + value->value32 = get_spot_position(priv); + break; + case IMGSENSOR_ID_3A_PARAMETER: if (value->p_u16 == NULL) { @@ -2354,6 +2436,31 @@ static int set_clip(uint32_t size, uint32_t *val, isx012_rect_t *target) 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 & 0xffff0000) >> 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(uint32_t id, uint32_t size, FAR imgsensor_value_t value) @@ -2854,6 +2961,19 @@ static int isx012_set_value(uint32_t id, 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); diff --git a/drivers/video/isx012_range.h b/drivers/video/isx012_range.h index 698ba9d8d279d..144687370a255 100644 --- a/drivers/video/isx012_range.h +++ b/drivers/video/isx012_range.h @@ -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 diff --git a/drivers/video/isx012_reg.h b/drivers/video/isx012_reg.h index a30c9346077bc..2c4e41d093fc0 100644 --- a/drivers/video/isx012_reg.h +++ b/drivers/video/isx012_reg.h @@ -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) diff --git a/drivers/video/isx019.c b/drivers/video/isx019.c index 1de3372c6c324..41a43779ab1ef 100644 --- a/drivers/video/isx019.c +++ b/drivers/video/isx019.c @@ -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; @@ -1222,6 +1233,7 @@ static void store_default_value(void) def->iso = get_value32(IMGSENSOR_ID_ISO_SENSITIVITY); def->iso_auto = get_value32(IMGSENSOR_ID_ISO_SENSITIVITY_AUTO); def->meter = get_value32(IMGSENSOR_ID_EXPOSURE_METERING); + def->spot_pos = get_value32(IMGSENSOR_ID_SPOT_POSITION); def->threealock = get_value32(IMGSENSOR_ID_3A_LOCK); def->threeastatus = get_value32(IMGSENSOR_ID_3A_STATUS); def->jpgquality = get_value32(IMGSENSOR_ID_JPEG_QUALITY); @@ -1857,6 +1869,12 @@ static int isx019_get_supported_value(uint32_t id, 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, @@ -2325,6 +2343,154 @@ static int set_meter(imgsensor_value_t val) return OK; } +static void get_current_framesize(uint16_t *w, uint16_t *h) +{ + uint8_t frmsz; + + DEBUGASSERT(w && h); + + fpga_i2c_read(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(uint16_t *w, + uint16_t *h, + uint16_t *offset_x, + uint16_t *offset_y) +{ + uint8_t sz; + uint8_t top; + uint8_t left; + + fpga_i2c_read(FPGA_CLIP_SIZE, &sz, 1); + fpga_i2c_read(FPGA_CLIP_TOP, &top, 1); + fpga_i2c_read(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(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 & 0xffff0000) >> 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(&w, &h); + if ((x >= w) || (y >= h)) + { + return -EINVAL; + } + + get_current_clip_setting(&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(CAT_CATAE, SPOT_FRM_NUM, ®val, 1); +} + static int set_3alock(imgsensor_value_t val) { uint8_t regval; @@ -2733,6 +2899,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; @@ -2912,6 +3082,82 @@ static int get_meter(FAR imgsensor_value_t *val) return OK; } +static uint16_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 imgsensor_value_t *val) +{ + uint8_t regval; + uint8_t reg_x; + uint8_t reg_y; + uint16_t w; + uint16_t h; + uint16_t x; + uint16_t y; + uint16_t clip_w; + uint16_t clip_h; + uint16_t offset_x; + uint16_t offset_y; + int split; + + isx019_i2c_read(CAT_CATAE, SPOT_FRM_NUM, ®val, 1); + + reg_x = regval % ISX019_SPOT_POSITION_SPLIT_NUM_X; + reg_y = regval / ISX019_SPOT_POSITION_SPLIT_NUM_X; + + get_current_framesize(&w, &h); + get_current_clip_setting(&clip_w, &clip_h, &offset_x, &offset_y); + split = ISX019_SPOT_POSITION_SPLIT_NUM_X; + x = restore_spot_position(reg_x, ISX019_WIDTH, w, clip_w, offset_x, split); + split = ISX019_SPOT_POSITION_SPLIT_NUM_Y; + y = restore_spot_position(reg_y, ISX019_HEIGHT, h, clip_h, offset_y, split); + + val->value32 = (x << 16) | y; + return OK; +} + static int get_3alock(FAR imgsensor_value_t *val) { uint8_t regval; @@ -3137,6 +3383,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; diff --git a/drivers/video/isx019_range.h b/drivers/video/isx019_range.h index 4a3d6d143fec3..35365a148e771 100644 --- a/drivers/video/isx019_range.h +++ b/drivers/video/isx019_range.h @@ -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) diff --git a/drivers/video/isx019_reg.h b/drivers/video/isx019_reg.h index 71aead7cbd7e5..d6e9af658995f 100644 --- a/drivers/video/isx019_reg.h +++ b/drivers/video/isx019_reg.h @@ -236,6 +236,7 @@ /* For CAT_CATAE */ #define AEMODE (0x0000) +#define SPOT_FRM_NUM (0x0003) #define SHT_PRIMODE (0x0008) #define GAIN_PRIMODE (0x000c) diff --git a/drivers/video/video.c b/drivers/video/video.c index 8a05919e48771..5a952a1fa01d6 100644 --- a/drivers/video/video.c +++ b/drivers/video/video.c @@ -172,6 +172,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; @@ -393,6 +394,7 @@ static 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"}, @@ -907,6 +909,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); @@ -2324,6 +2327,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); @@ -2576,6 +2580,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; @@ -2883,6 +2891,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; diff --git a/include/nuttx/video/imgsensor.h b/include/nuttx/video/imgsensor.h index f31eb3b55f723..e7ba527d86c87 100644 --- a/include/nuttx/video/imgsensor.h +++ b/include/nuttx/video/imgsensor.h @@ -68,6 +68,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) diff --git a/include/nuttx/video/video_controls.h b/include/nuttx/video/video_controls.h index 3f286f158a510..5d74cada8b996 100644 --- a/include/nuttx/video/video_controls.h +++ b/include/nuttx/video/video_controls.h @@ -162,6 +162,10 @@ enum v4l2_exposure_metering V4L2_EXPOSURE_METERING_MATRIX = 3, /**< Matrix */ }; +/** Spot position in spot exposure metering */ + +#define V4L2_CID_EXPOSURE_METERING_SPOT_POSITION (22) + #define V4L2_CID_SCENE_MODE (16) /**< Scene selection */ /** enumeration for V4L2_CID_SCENE_MODE */