From 6ae6056b83e18b0f77254fe7721f2971a03bb960 Mon Sep 17 00:00:00 2001 From: Ibrahim Abd Elkader Date: Mon, 18 Jan 2021 15:23:57 +0200 Subject: [PATCH] Update HM01B0 driver. (#1125) * Fix framerate for QVGA and QQVGA. * Fix set_exposure calculations. * Calculate vt_pix_clk from dividers in OSC register. * Implement frame rate for HM01b0. * Fix frame timing for QQVGA * Implement set_framerate. --- src/omv/sensors/hm01b0.c | 126 ++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 22 deletions(-) diff --git a/src/omv/sensors/hm01b0.c b/src/omv/sensors/hm01b0.c index bfc20fc8a..e4a50f018 100644 --- a/src/omv/sensors/hm01b0.c +++ b/src/omv/sensors/hm01b0.c @@ -20,9 +20,12 @@ #include "hm01b0_regs.h" #include "py/mphal.h" -#define HIMAX_BOOT_RETRY (10) -#define HIMAX_LINE_LEN_PCK 0x172 -#define HIMAX_FRAME_LENGTH 0x232 +#define HIMAX_BOOT_RETRY (10) +#define HIMAX_LINE_LEN_PCK_QVGA 0x178 +#define HIMAX_FRAME_LENGTH_QVGA 0x104 + +#define HIMAX_LINE_LEN_PCK_QQVGA 0x178 +#define HIMAX_FRAME_LENGTH_QQVGA 0x084 static const uint16_t default_regs[][2] = { {BLC_TGT, 0x08}, // BLC target :8 at 8 bit mode @@ -76,8 +79,8 @@ static const uint16_t default_regs[][2] = { {AE_MIN_MEAN, 0x0A}, //AE min target mean [Def: 0x0A] {CONVERGE_IN_TH, 0x03}, //Converge in threshold [Def: 0x03] {CONVERGE_OUT_TH, 0x05}, //Converge out threshold [Def: 0x05] - {MAX_INTG_H, 0x01}, //Maximum INTG High Byte [Def: 0x01] - {MAX_INTG_L, 0x54}, //Maximum INTG Low Byte [Def: 0x54] + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QVGA-2)>>8}, //Maximum INTG High Byte [Def: 0x01] + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QVGA-2)&0xFF}, //Maximum INTG Low Byte [Def: 0x54] {MAX_AGAIN_FULL, 0x03}, //Maximum Analog gain in full frame mode [Def: 0x03] {MAX_AGAIN_BIN2, 0x04}, //Maximum Analog gain in bin2 mode [Def: 0x04] {MAX_DGAIN, 0xC0}, @@ -97,17 +100,17 @@ static const uint16_t default_regs[][2] = { {FS_50HZ_L, 0x32}, {MD_CTRL, 0x30}, - {FRAME_LEN_LINES_H, HIMAX_FRAME_LENGTH>>8}, - {FRAME_LEN_LINES_L, HIMAX_FRAME_LENGTH&0xFF}, - {LINE_LEN_PCK_H, HIMAX_LINE_LEN_PCK>>8}, - {LINE_LEN_PCK_L, HIMAX_LINE_LEN_PCK&0xFF}, - {0x3010, 0x00}, // no full frame + {FRAME_LEN_LINES_H, HIMAX_FRAME_LENGTH_QVGA>>8}, + {FRAME_LEN_LINES_L, HIMAX_FRAME_LENGTH_QVGA&0xFF}, + {LINE_LEN_PCK_H, HIMAX_LINE_LEN_PCK_QVGA>>8}, + {LINE_LEN_PCK_L, HIMAX_LINE_LEN_PCK_QVGA&0xFF}, + {QVGA_WIN_EN, 0x01}, // Enable QVGA window readout {0x0383, 0x01}, {0x0387, 0x01}, {0x0390, 0x00}, {0x3011, 0x70}, {0x3059, 0x02}, - {0x3060, 0x0B}, + {OSC_CLK_DIV, 0x0B}, {IMG_ORIENTATION, 0x00}, // change the orientation {0x0104, 0x01}, @@ -177,19 +180,31 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) } static const uint16_t QVGA_regs[][2] = { - {0x0383, 0x01}, - {0x0387, 0x01}, - {0x0390, 0x00}, - //============= End of regs marker ================== + {0x0383, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QVGA-2)>>8}, + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QVGA-2)&0xFF}, + {FRAME_LEN_LINES_H, (HIMAX_FRAME_LENGTH_QVGA>>8)}, + {FRAME_LEN_LINES_L, (HIMAX_FRAME_LENGTH_QVGA&0xFF)}, + {LINE_LEN_PCK_H, (HIMAX_LINE_LEN_PCK_QVGA>>8)}, + {LINE_LEN_PCK_L, (HIMAX_LINE_LEN_PCK_QVGA&0xFF)}, + //============= End of regs marker ================== {0x0000, 0x00}, }; static const uint16_t QQVGA_regs[][2] = { - {0x0383, 0x03}, - {0x0387, 0x03}, - {0x0390, 0x03}, - //============= End of regs marker ================== + {0x0383, 0x03}, + {0x0387, 0x03}, + {0x0390, 0x03}, + {MAX_INTG_H, (HIMAX_FRAME_LENGTH_QQVGA-2)>>8}, + {MAX_INTG_L, (HIMAX_FRAME_LENGTH_QQVGA-2)&0xFF}, + {FRAME_LEN_LINES_H, (HIMAX_FRAME_LENGTH_QQVGA>>8)}, + {FRAME_LEN_LINES_L, (HIMAX_FRAME_LENGTH_QQVGA&0xFF)}, + {LINE_LEN_PCK_H, (HIMAX_LINE_LEN_PCK_QQVGA>>8)}, + {LINE_LEN_PCK_L, (HIMAX_LINE_LEN_PCK_QQVGA&0xFF)}, + //============= End of regs marker ================== {0x0000, 0x00}, }; @@ -220,6 +235,36 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize) return ret; } +static int set_framerate(sensor_t *sensor, int framerate) +{ + uint8_t osc_div = 0; + uint32_t framesize = sensor->framesize; + + if (framesize == FRAMESIZE_INVALID) { + // Use QVGA by default if the framesize is not set + framesize = FRAMESIZE_QVGA; + } + + switch (framerate) { + case 15: + osc_div = (framesize == FRAMESIZE_QVGA) ? 0x01 : 0x00; + break; + case 30: + osc_div = (framesize == FRAMESIZE_QVGA) ? 0x02 : 0x01; + break; + case 60: + osc_div = (framesize == FRAMESIZE_QVGA) ? 0x03 : 0x02; + break; + case 120: + // Set to max FPS. + osc_div = 0x03; + break; + default: + return -1; + } + return cambus_writeb2(&sensor->bus, sensor->slv_addr, OSC_CLK_DIV, osc_div); +} + static int set_contrast(sensor_t *sensor, int level) { return 0; @@ -265,6 +310,23 @@ static int get_gain_db(sensor_t *sensor, float *gain_db) return 0; } +static int get_vt_pix_clk(sensor_t *sensor, uint32_t *vt_pix_clk) +{ + uint8_t reg; + if (cambus_readb2(&sensor->bus, sensor->slv_addr, OSC_CLK_DIV, ®) != 0) { + return -1; + } + // 00 -> MCLK / 8 + // 01 -> MCLK / 4 + // 10 -> MCLK / 2 + // 11 -> MCLK / 1 + uint32_t vt_sys_div = 8 / (1 << (reg & 0x03)); + + // vt_pix_clk = MCLK / vt_sys_div + *vt_pix_clk = OMV_XCLK_FREQUENCY / vt_sys_div; + return 0; +} + static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) { int ret=0; @@ -272,9 +334,28 @@ static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) if (enable) { ret |= cambus_writeb2(&sensor->bus, sensor->slv_addr, AE_CTRL, 1); } else { - int coarse_int = exposure_us*(OMV_XCLK_FREQUENCY/1000000)/LINE_LEN_PCK_H; - if (coarse_int<2) coarse_int = 2; - if (coarse_int>HIMAX_FRAME_LENGTH-2) coarse_int = HIMAX_FRAME_LENGTH-2; + uint32_t line_len; + uint32_t frame_len; + uint32_t coarse_int; + uint32_t vt_pix_clk = 0; + + if (sensor->framesize == FRAMESIZE_QVGA) { + line_len = HIMAX_LINE_LEN_PCK_QVGA; + frame_len = HIMAX_FRAME_LENGTH_QVGA; + } else { + line_len = HIMAX_LINE_LEN_PCK_QQVGA; + frame_len = HIMAX_FRAME_LENGTH_QQVGA; + } + + ret |= get_vt_pix_clk(sensor, &vt_pix_clk); + coarse_int = exposure_us * (vt_pix_clk / 1000000) / line_len; + + if (coarse_int < 2) { + coarse_int = 2; + } else if (coarse_int > (frame_len-2)) { + coarse_int = frame_len-2; + } + ret |= cambus_writeb2(&sensor->bus, sensor->slv_addr, AE_CTRL, 0); ret |= cambus_writeb2(&sensor->bus, sensor->slv_addr, INTEGRATION_H, coarse_int>>8); ret |= cambus_writeb2(&sensor->bus, sensor->slv_addr, INTEGRATION_L, coarse_int&0xff); @@ -323,6 +404,7 @@ int hm01b0_init(sensor_t *sensor) sensor->write_reg = write_reg; sensor->set_pixformat = set_pixformat; sensor->set_framesize = set_framesize; + sensor->set_framerate = set_framerate; sensor->set_contrast = set_contrast; sensor->set_brightness = set_brightness; sensor->set_saturation = set_saturation;