sensors/pag7936: Add missing control functions. (#2555)
Some checks are pending
🔎 Check Code Formatting / formatting-check (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_GIGA) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_33_BLE_SENSE) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NANO_RP2040_CONNECT) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_NICLA_VISION) (push) Waiting to run
🔥 Firmware Build / build-firmware (ARDUINO_PORTENTA_H7) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV2) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV3) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV4P) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMVPT) (push) Waiting to run
🔥 Firmware Build / build-firmware (OPENMV_RT1060) (push) Waiting to run
🔥 Firmware Build / code-size-report (push) Blocked by required conditions
🔥 Firmware Build / stable-release (push) Blocked by required conditions
🔥 Firmware Build / development-release (push) Blocked by required conditions

* sensors/pag7936: Add color bar output support.
* sensors/pag7936: Add auto exposure and auto gain support.
* sensors/pag7936: Add sleep support.
* sensors/pag7936: Fix HD image shifting.
* sensors/pag7936: Add cap on set_framerate per resolution.
This commit is contained in:
Kwabena W Agyeman 2024-12-30 05:20:49 -08:00 committed by GitHub
parent 9addcd90d8
commit 2a6c770b77
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -46,19 +46,57 @@
#define FRAME_TIME_20_16 (0x004E)
#define FRAME_TIME_15_8 (0x004D)
#define FRAME_TIME_7_0 (0x004C)
#define AGC_H (0x1424)
#define AGC_L (0x1423)
#define AE_START_DIV_4_X_7_0 (0x0482)
#define AE_START_DIV_4_X_8_7 (0x0483)
#define AE_START_DIV_4_Y (0x0484)
#define AE_SIZE_DIV_4_X_7_0 (0x0485)
#define AE_SIZE_DIV_4_X_8_7 (0x0486)
#define AE_SIZE_DIV_4_Y (0x0487)
#define AE_EXPO_MANUAL (0x1400)
#define AE_EXPO_MANUAL_AE_MANUAL_EN (0x10)
#define AE_EXPO_MANUAL_AE_ENH (0x1)
#define AE_FREQ_60 (0x1404)
#define AE_YTAR8BIT (0x1406)
#define AE_LOCKRANGE_IN (0x1407)
#define AE_LOCKRANGE_OUT_LB (0x1408)
#define AE_LOCKRANGE_OUT_UB (0x1409)
#define AE_STABLE_7_0 (0x145B)
#define AE_MINGAIN_7_0 (0x140A)
#define AE_MINGAIN_10_8 (0x140B)
#define AE_MAXGAIN_7_0 (0x140C)
#define AE_MAXGAIN_10_8 (0x140D)
#define AE_MINEXPO_7_0 (0x140E)
#define AE_MINEXPO_15_8 (0x140F)
#define AE_MINEXPO_17_16 (0x1410)
#define AE_MAXEXPO_7_0 (0x1412)
#define AE_MAXEXPO_15_8 (0x1413)
#define AE_MAXEXPO_17_16 (0x1414)
#define AE_GAIN_MANUAL_7_0 (0x1423)
#define AE_GAIN_MANUAL_10_8 (0x1424)
#define AE_EXP_LINE_NUM_7_0 (0x1450)
#define AE_EXP_LINE_NUM_15_8 (0x1451)
#define AE_EXP_LINE_NUM_17_16 (0x1452)
#define TOTAL_GAIN_7_0 (0x1453)
#define TOTAL_GAIN_10_8 (0x1454)
#define AE_EXPO_MANUAL_17_16 (0x1427)
#define AE_EXPO_MANUAL_15_8 (0x1426)
#define AE_EXPO_MANUAL_7_0 (0x1425)
#define SENSOR_UPDATE (0x00EB)
#define SENSOR_UPDATE_FLAG (0x80)
#define INTERFACE_POLARITY (0x0EAF)
#define SENSOR_OPMODE (0x0008)
#define SENSOR_OPMODE_RUN (0x83)
#define SENSOR_OPMODE_SUSPEND (0x85)
#define SENSOR_TRIGGER_FRAMENUM (0x002E)
#define SENSOR_TRIGGER_EN (0x002F)
#define SENSOR_TG_EN (0x0030)
#define SENSOR_TG_EN_FLAG (0x01)
#define SENSOR_TRIGGER_MODE (0x0031)
#define SENSOR_SOFTWARE_TRIGGER (0x00EA)
#define ISP_EN_H (0x0800)
#define ISP_EN_H_EN (0x01)
#define ISP_TEST_MODE (0x0801)
#define ISP_TEST_MODE_RAMP (0x04)
#define ISP_WOI_EN (0x0E10)
#define ISP_WOI_HSIZE_L (0x0E11)
#define ISP_WOI_HSIZE_H (0x0E12)
@ -105,11 +143,40 @@
#define PAG7936_MAX_INT ((FMAX_720P_120_LINEAR - 11)) // ExpLine max vlaue
#define PAG7936_MIN_AGAIN (1472) // AGain min value, unit is 1/1024x
#define PAG7936_MAX_AGAIN (16384) // AGain max value, unit is 1/1024x
#define PAG7936_MIN_AGAIN_REG ((PAG7936_MIN_AGAIN) / 64)
#define PAG7936_MAX_AGAIN_REG ((PAG7936_MAX_AGAIN) / 64)
#define PAG7936_GAIN_SCALE (16)
#define PAG7936_GAIN_SCALE_F ((PAG7936_GAIN_SCALE) * 1.0f)
#define PAG7936_EXP_OFFSET (80)
#define PAG7936_EXP_MIN (80)
#define PAG7936_EXP_DIV (8)
#define PAG7936_FRAME_TIME(h, m, l) ((((h) & 0x1f) << 16) | ((m) << 8) | (l))
#define PAG7936_FRAME_TIME_H(r, ft) (((r) & 0xe0) | (((ft) >> 16) & 0x1f))
#define PAG7936_FRAME_TIME_M(ft) (((ft) >> 8) & 0xff)
#define PAG7936_FRAME_TIME_L(ft) ((ft) & 0xff)
#define PAG7936_GAIN(h, l) ((((h) & 0x7) << 8) | (l))
#define PAG7936_GAIN_H(r, gain) (((r) & 0xf8) | (((gain) >> 8) & 0x7))
#define PAG7936_GAIN_L(gain) ((gain) & 0xff)
#define PAG7936_EXPOSURE(h, m, l) (((((h) & 0x3) << 16) | ((m) << 8) | (l)) * 8)
#define PAG7936_EXPOSURE_H(r, exp) (((r) & 0xfc) | (((exp) >> 16) & 0x3))
#define PAG7936_EXPOSURE_M(exp) (((exp) >> 8) & 0xff)
#define PAG7936_EXPOSURE_L(exp) ((exp) & 0xff)
#if OMV_PAG7936_MIPI_CSI2
#define PAG7936_WIDTH_ALIGN (8)
#define PAG7936_WIDTH_ALIGN (8)
#define PAG7936_QVGA_FPS_MAX (480)
#define PAG7936_VGA_FPS_MAX (240)
#define PAG7936_HD_FPS_MAX (120)
#else
#define PAG7936_WIDTH_ALIGN (4)
#define PAG7936_WIDTH_ALIGN (4)
#define PAG7936_QVGA_FPS_MAX (240)
#define PAG7936_VGA_FPS_MAX (120)
#define PAG7936_HD_FPS_MAX (60)
#endif
static const uint16_t default_regs[][2] = {
@ -320,26 +387,18 @@ static const uint16_t hd_regs[][2] = {
{ AVERAGE_MODE, 0x00 },
{ ROW_AVERAGE_MODE, 0x00 },
{ COL_AVERAGE_MODE, 0x00 },
{ ISP_WOI_EN, 0x01 },
{ ISP_WOI_HSIZE_L, 0x00 },
{ ISP_WOI_HSIZE_H, 0x05 },
{ ISP_WOI_VSIZE_L, 0x20 },
{ ISP_WOI_VSIZE_H, 0x03 },
{ ISP_WOI_HOFFSET_L, 0x10 },
{ ISP_WOI_HOFFSET_H, 0x00 },
{ ISP_WOI_VOFFSET_L, 0x10 },
{ ISP_WOI_VOFFSET_H, 0x00 },
{ ISP_WOI_EN, 0x00 },
{ HSIZE_L, 0x10 },
{ HSIZE_H, 0x05 },
{ VSIZE_L, 0x30 },
{ VSIZE_H, 0x03 },
{ WOI_HSIZE_L, 0x10 },
{ WOI_HSIZE_L, 0x00 },
{ WOI_HSIZE_H, 0x05 },
{ WOI_VSIZE_L, 0x30 },
{ WOI_VSIZE_L, 0x20 },
{ WOI_VSIZE_H, 0x03 },
{ WOI_HSTART_L, 0x00 },
{ WOI_HSTART_L, 0x08 },
{ WOI_HSTART_H, 0x00 },
{ WOI_VSTART_L, 0x00 },
{ WOI_VSTART_L, 0x08 },
{ WOI_VSTART_H, 0x00 },
{ SENSOR_UPDATE, 0x80 },
{ 0x0000, 0x00 },
@ -355,6 +414,9 @@ static int reset(omv_csi_t *csi) {
}
static int sleep(omv_csi_t *csi, int enable) {
int ret = omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_TG_EN, SENSOR_TG_EN_FLAG);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_OPMODE,
enable ? SENSOR_OPMODE_SUSPEND : SENSOR_OPMODE_RUN);
return 0;
}
@ -415,29 +477,187 @@ static int set_framesize(omv_csi_t *csi, omv_csi_framesize_t framesize) {
}
static int set_framerate(omv_csi_t *csi, int framerate) {
uint8_t reg, exposure_us_17_16, exposure_us_15_8, exposure_us_7_0;
int ret = 0;
int32_t frame_time = FT_CLK / framerate;
int32_t integ_time = IM_CLAMP((frame_time - 11), PAG7936_MIN_INT, PAG7936_MAX_INT);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_20_16, ((frame_time >> 16) & 0x1F));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_15_8, ((frame_time >> 8) & 0xFF));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_7_0, (frame_time & 0xFF));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, ((integ_time >> 16) & 0x03));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_15_8, ((integ_time >> 8) & 0xFF));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_7_0, (integ_time & 0xFF));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, 0x80);
switch (csi->framesize) {
case OMV_CSI_FRAMESIZE_HD:
framerate = IM_MIN(framerate, PAG7936_HD_FPS_MAX);
break;
case OMV_CSI_FRAMESIZE_VGA:
framerate = IM_MIN(framerate, PAG7936_VGA_FPS_MAX);
break;
case OMV_CSI_FRAMESIZE_QVGA:
framerate = IM_MIN(framerate, PAG7936_QVGA_FPS_MAX);
break;
default:
return -1;
}
int32_t frame_time = FT_CLK / framerate;
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_20_16, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_20_16, PAG7936_FRAME_TIME_H(reg, frame_time));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_15_8, PAG7936_FRAME_TIME_M(frame_time));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_7_0, PAG7936_FRAME_TIME_L(frame_time));
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &reg);
if (reg & AE_EXPO_MANUAL_AE_MANUAL_EN) {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, &exposure_us_17_16);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_15_8, &exposure_us_15_8);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_7_0, &exposure_us_7_0);
} else {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_17_16, &exposure_us_17_16);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_15_8, &exposure_us_15_8);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_7_0, &exposure_us_7_0);
}
int32_t exposure_us = PAG7936_EXPOSURE(exposure_us_17_16, exposure_us_15_8, exposure_us_7_0);
exposure_us = IM_CLAMP(exposure_us, PAG7936_EXP_MIN, (frame_time - PAG7936_EXP_OFFSET)) / PAG7936_EXP_DIV;
if (reg & AE_EXPO_MANUAL_AE_MANUAL_EN) {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, PAG7936_EXPOSURE_H(reg, exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_15_8, PAG7936_EXPOSURE_M(exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_7_0, PAG7936_EXPOSURE_L(exposure_us));
} else {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_17_16, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_17_16, PAG7936_EXPOSURE_H(reg, exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_15_8, PAG7936_EXPOSURE_M(exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_7_0, PAG7936_EXPOSURE_L(exposure_us));
}
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
static int set_gainceiling(omv_csi_t *csi, omv_csi_gainceiling_t gainceiling) {
uint8_t aec, reg;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &aec);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, aec | AE_EXPO_MANUAL_AE_MANUAL_EN);
int new_gainceiling = PAG7936_GAIN_SCALE << (gainceiling + 1);
if (new_gainceiling > PAG7936_MAX_AGAIN_REG) {
return -1;
}
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_10_8, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_10_8, PAG7936_GAIN_H(reg, new_gainceiling));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_7_0, PAG7936_GAIN_L(new_gainceiling));
// Force AEC/AGC to reload the new values.
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, aec);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
static int set_colorbar(omv_csi_t *csi, int enable) {
return 0;
uint8_t reg;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, ISP_EN_H, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, ISP_EN_H,
(reg & ~ISP_EN_H_EN) | (enable ? ISP_EN_H_EN : 0));
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, ISP_TEST_MODE, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, ISP_TEST_MODE,
(reg & ~ISP_TEST_MODE_RAMP) | (enable ? ISP_TEST_MODE_RAMP : 0));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
static int set_auto_gain(omv_csi_t *csi, int enable, float gain_db, float gain_db_ceiling) {
uint8_t reg;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, reg | AE_EXPO_MANUAL_AE_MANUAL_EN);
if ((enable == 0) && (!isnanf(gain_db)) && (!isinff(gain_db))) {
int gain = fast_roundf(expf((gain_db / 20.0f) * M_LN10) * PAG7936_GAIN_SCALE_F);
gain = IM_CLAMP(gain, PAG7936_MIN_AGAIN_REG, PAG7936_MAX_AGAIN_REG);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_GAIN_MANUAL_10_8, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_GAIN_MANUAL_10_8, PAG7936_GAIN_H(reg, gain));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_GAIN_MANUAL_7_0, PAG7936_GAIN_L(gain));
} else if ((enable != 0) && (!isnanf(gain_db_ceiling)) && (!isinff(gain_db_ceiling))) {
int gain_ceiling = fast_roundf(expf((gain_db_ceiling / 20.0f) * M_LN10) * PAG7936_GAIN_SCALE_F);
gain_ceiling = IM_CLAMP(gain_ceiling, PAG7936_MIN_AGAIN_REG, PAG7936_MAX_AGAIN_REG);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_10_8, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_10_8, PAG7936_GAIN_H(reg, gain_ceiling));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXGAIN_7_0, PAG7936_GAIN_L(gain_ceiling));
}
// Force AEC/AGC to reload the new values.
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL,
(reg & ~AE_EXPO_MANUAL_AE_MANUAL_EN) | (enable ? 0 : AE_EXPO_MANUAL_AE_MANUAL_EN));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
static int get_gain_db(omv_csi_t *csi, float *gain_db) {
uint8_t gainh, gainl;
int ret = 0;
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, TOTAL_GAIN_10_8, &gainh);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, TOTAL_GAIN_7_0, &gainl);
*gain_db = 20.0f * log10f(PAG7936_GAIN(gainh, gainl) / PAG7936_GAIN_SCALE_F);
return ret;
}
static int set_auto_exposure(omv_csi_t *csi, int enable, int exposure_us) {
uint8_t reg, frame_time_20_16, frame_time_15_8, frame_time_7_0;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, reg | AE_EXPO_MANUAL_AE_MANUAL_EN);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_20_16, &frame_time_20_16);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_15_8, &frame_time_15_8);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, FRAME_TIME_7_0, &frame_time_7_0);
int32_t frame_time_us = PAG7936_FRAME_TIME(frame_time_20_16, frame_time_15_8, frame_time_7_0);
exposure_us = IM_CLAMP(exposure_us, PAG7936_EXP_MIN, (frame_time_us - PAG7936_EXP_OFFSET)) / PAG7936_EXP_DIV;
if ((enable == 0) && (exposure_us >= 0)) {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_17_16, PAG7936_EXPOSURE_H(reg, exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_15_8, PAG7936_EXPOSURE_M(exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL_7_0, PAG7936_EXPOSURE_L(exposure_us));
} else if ((enable != 0) && (exposure_us >= 0)) {
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_17_16, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_17_16, PAG7936_EXPOSURE_H(reg, exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_15_8, PAG7936_EXPOSURE_M(exposure_us));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_MAXEXPO_7_0, PAG7936_EXPOSURE_L(exposure_us));
}
// Force AEC/AGC to reload the new values.
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, AE_EXPO_MANUAL,
(reg & ~AE_EXPO_MANUAL_AE_MANUAL_EN) | (enable ? 0 : AE_EXPO_MANUAL_AE_MANUAL_EN));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
static int get_exposure_us(omv_csi_t *csi, int *exposure_us) {
uint8_t exposure_us_17_16, exposure_us_15_8, exposure_us_7_0;
int ret = 0;
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXP_LINE_NUM_17_16, &exposure_us_17_16);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXP_LINE_NUM_15_8, &exposure_us_15_8);
ret |= omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, AE_EXP_LINE_NUM_7_0, &exposure_us_7_0);
*exposure_us = PAG7936_EXPOSURE(exposure_us_17_16, exposure_us_15_8, exposure_us_7_0);
return ret;
}
static int set_hmirror(omv_csi_t *csi, int enable) {
uint8_t reg;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, TG_FLIP, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, TG_FLIP, TG_FLIP_SET_HFLIP(reg, enable));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, 0x80);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
@ -445,7 +665,7 @@ static int set_vflip(omv_csi_t *csi, int enable) {
uint8_t reg;
int ret = omv_i2c_readb2(&csi->i2c_bus, csi->slv_addr, TG_FLIP, &reg);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, TG_FLIP, TG_FLIP_SET_VFLIP(reg, enable));
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, 0x80);
ret |= omv_i2c_writeb2(&csi->i2c_bus, csi->slv_addr, SENSOR_UPDATE, SENSOR_UPDATE_FLAG);
return ret;
}
@ -497,7 +717,12 @@ int pag7936_init(omv_csi_t *csi) {
csi->set_pixformat = set_pixformat;
csi->set_framesize = set_framesize;
csi->set_framerate = set_framerate;
csi->set_gainceiling = set_gainceiling;
csi->set_colorbar = set_colorbar;
csi->set_auto_gain = set_auto_gain;
csi->get_gain_db = get_gain_db;
csi->set_auto_exposure = set_auto_exposure;
csi->get_exposure_us = get_exposure_us;
csi->set_hmirror = set_hmirror;
csi->set_vflip = set_vflip;