From 7e45f89bc774b23cf2d35f7868761fc29282b835 Mon Sep 17 00:00:00 2001 From: Frank Zhao Date: Wed, 13 Jan 2021 09:43:13 -0800 Subject: [PATCH] Fix OV5640 PCLK calculation to use current register values (#1120) --- src/omv/sensors/ov5640.c | 61 ++++++++++++++++++++++++++--------- src/omv/sensors/ov5640_regs.h | 2 ++ 2 files changed, 47 insertions(+), 16 deletions(-) diff --git a/src/omv/sensors/ov5640.c b/src/omv/sensors/ov5640.c index 0be19c4a0..ce0f03c07 100644 --- a/src/omv/sensors/ov5640.c +++ b/src/omv/sensors/ov5640.c @@ -1086,14 +1086,47 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) return ret; } +static int calc_pclk_freq(uint8_t sc_pll_ctrl_0, uint8_t sc_pll_ctrl_1, uint8_t sc_pll_ctrl_2, uint8_t sc_pll_ctrl_3, uint8_t sys_root_div) +{ + uint32_t pclk_freq = OV5640_XCLK_FREQ; + pclk_freq /= ((sc_pll_ctrl_3 & 0x10) != 0x00) ? 2 : 1; + pclk_freq /= ((sc_pll_ctrl_0 & 0x0F) == 0x0A) ? 10 : 8; + switch (sc_pll_ctrl_3 & 0x0F) + { + case 0: pclk_freq /= 1; break; + case 1: pclk_freq /= 2; break; + case 2: pclk_freq /= 3; break; + case 3: pclk_freq /= 4; break; + case 4: pclk_freq /= 6; break; + case 5: pclk_freq /= 8; break; + default: pclk_freq /= 3; break; + } + pclk_freq *= sc_pll_ctrl_2; + sc_pll_ctrl_1 >>= 4; + pclk_freq /= sc_pll_ctrl_1; + switch (sys_root_div & 0x30) + { + case 0x00: pclk_freq /= 1; break; + case 0x10: pclk_freq /= 2; break; + case 0x20: pclk_freq /= 4; break; + case 0x30: pclk_freq /= 8; break; + default: pclk_freq /= 1; break; + } + return (int)pclk_freq; +} + static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) { - uint8_t reg, pll, hts_h, hts_l, vts_h, vts_l; + uint8_t reg, spc0, spc1, spc2, spc3, sysrootdiv, hts_h, hts_l, vts_h, vts_l; int ret = cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_MANUAL, ®); ret |= cambus_writeb2(&sensor->bus, sensor->slv_addr, AEC_PK_MANUAL, (reg & 0xFE) | ((enable == 0) << 0)); if ((enable == 0) && (exposure_us >= 0)) { - ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL2, &pll); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL0, &spc0); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL1, &spc1); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL2, &spc2); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL3, &spc3); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SYSTEM_ROOT_DIVIDER, &sysrootdiv); ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, TIMING_HTS_H, &hts_h); ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, TIMING_HTS_L, &hts_l); @@ -1104,12 +1137,7 @@ static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) uint16_t hts = (hts_h << 8) | hts_l; uint16_t vts = (vts_h << 8) | vts_l; - // "/ 3" -> SC_PLL_CONTRL3[3:0] (pll pre-divider) - // "/ 1" -> SC_PLL_CONTRL1[7:4] (system clock divider) - // "/ 2" -> SC_PLL_CONTRL3[4] (pll root divider) - // "/ 10" -> SYSTEM_CTROL0[3:0] (bit mode) - // "/ 1" -> SYSTEM_ROOT_DIVIDER[5:4] (pclk root divider) - int pclk_freq = ((((((OV5640_XCLK_FREQ / 3) * pll) / 1) / 2) / 10) / 1) * 2; + int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv); int clocks_per_us = pclk_freq / 1000000; int exposure = IM_MAX(IM_MIN((exposure_us * clocks_per_us) / hts, 0xFFFF), 0x0000); @@ -1128,8 +1156,14 @@ static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) static int get_exposure_us(sensor_t *sensor, int *exposure_us) { - uint8_t pll, aec_0, aec_1, aec_2, hts_h, hts_l; - int ret = cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL2, &pll); + uint8_t spc0, spc1, spc2, spc3, sysrootdiv, aec_0, aec_1, aec_2, hts_h, hts_l; + int ret = 0; + + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL0, &spc0); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL1, &spc1); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL2, &spc2); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SC_PLL_CONTRL3, &spc3); + ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, SYSTEM_ROOT_DIVIDER, &sysrootdiv); ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_EXPOSURE_0, &aec_0); ret |= cambus_readb2(&sensor->bus, sensor->slv_addr, AEC_PK_EXPOSURE_1, &aec_1); @@ -1141,12 +1175,7 @@ static int get_exposure_us(sensor_t *sensor, int *exposure_us) uint32_t aec = ((aec_0 << 16) | (aec_1 << 8) | aec_2) >> 4; uint16_t hts = (hts_h << 8) | hts_l; - // "/ 3" -> SC_PLL_CONTRL3[3:0] (pll pre-divider) - // "/ 1" -> SC_PLL_CONTRL1[7:4] (system clock divider) - // "/ 2" -> SC_PLL_CONTRL3[4] (pll root divider) - // "/ 10" -> SYSTEM_CTROL0[3:0] (bit mode) - // "/ 1" -> SYSTEM_ROOT_DIVIDER[5:4] (pclk root divider) - int pclk_freq = ((((((OV5640_XCLK_FREQ / 3) * pll) / 1) / 2) / 10) / 1) * 2; + int pclk_freq = calc_pclk_freq(spc0, spc1, spc2, spc3, sysrootdiv); int clocks_per_us = pclk_freq / 1000000; *exposure_us = (aec * hts) / clocks_per_us; diff --git a/src/omv/sensors/ov5640_regs.h b/src/omv/sensors/ov5640_regs.h index 4198afbad..97c58bdbf 100644 --- a/src/omv/sensors/ov5640_regs.h +++ b/src/omv/sensors/ov5640_regs.h @@ -23,11 +23,13 @@ #define AF_CMD_ACK 0x3023 #define AF_FW_STATUS 0x3029 +#define SC_PLL_CONTRL0 0x3034 #define SC_PLL_CONTRL1 0x3035 #define SC_PLL_CONTRL2 0x3036 #define SC_PLL_CONTRL3 0x3037 #define SCCB_SYSTEM_CTRL_1 0x3103 +#define SYSTEM_ROOT_DIVIDER 0x3108 #define AWB_R_GAIN_H 0x3400 #define AWB_R_GAIN_L 0x3401