From abd977c60f9d34d8ce4bf8c8073abb7b604eaa72 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sat, 8 Feb 2020 21:25:59 +0200 Subject: [PATCH] Add HIMAX HM01B0 driver. --- src/Makefile | 2 + src/omv/Makefile | 1 + src/omv/hm01b0.c | 229 ++++++++++++++++++++++++++++++++++++++++++ src/omv/hm01b0.h | 15 +++ src/omv/hm01b0_regs.h | 116 +++++++++++++++++++++ src/omv/sensor.c | 13 +++ src/omv/sensor.h | 4 + 7 files changed, 380 insertions(+) create mode 100644 src/omv/hm01b0.c create mode 100644 src/omv/hm01b0.h create mode 100644 src/omv/hm01b0_regs.h diff --git a/src/Makefile b/src/Makefile index 8eb230008..9a505950b 100755 --- a/src/Makefile +++ b/src/Makefile @@ -187,6 +187,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \ ov5640.o \ mt9v034.o \ lepton.o \ + hm01b0.o \ sensor.o \ stm32fxxx_hal_msp.o \ soft_i2c.o \ @@ -504,6 +505,7 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/, \ ov5640.o \ mt9v034.o \ lepton.o \ + hm01b0.o \ sensor.o \ stm32fxxx_hal_msp.o \ soft_i2c.o \ diff --git a/src/omv/Makefile b/src/omv/Makefile index 2825bf356..5a300bb74 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -25,6 +25,7 @@ SRCS += $(addprefix , \ ov5640.c \ mt9v034.c \ lepton.c \ + hm01b0.c \ sensor.c \ stm32fxxx_hal_msp.c \ soft_i2c.c \ diff --git a/src/omv/hm01b0.c b/src/omv/hm01b0.c new file mode 100644 index 000000000..893af9993 --- /dev/null +++ b/src/omv/hm01b0.c @@ -0,0 +1,229 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2019 Ibrahim Abdelkader + * Copyright (c) 2013-2019 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * HM01B0 driver. + */ +#include +#include +#include +#include STM32_HAL_H +#include "cambus.h" +#include "hm01b0.h" +#include "hm01b0_regs.h" +#include "systick.h" +#include "omv_boardconfig.h" +#define HIMAX_BOOT_RETRY (10) + +#if (OMV_SENSOR_HM01B0 == 1) +static const uint16_t default_regs[][2] = { + {BLC_TGT, 0x08}, // BLC target :8 at 8 bit mode + {BLC2_TGT, 0x08}, // BLI target :8 at 8 bit mode + {0x3044, 0x0A}, // Increase CDS time for settling + {0x3045, 0x00}, // Make symetric for cds_tg and rst_tg + {0x3047, 0x0A}, // Increase CDS time for settling + {0x3050, 0xC0}, // Make negative offset up to 4x + {0x3051, 0x42}, + {0x3052, 0x50}, + {0x3053, 0x00}, + {0x3054, 0x03}, // tuning sf sig clamping as lowest + {0x3055, 0xF7}, // tuning dsun + {0x3056, 0xF8}, // increase adc nonoverlap clk + {0x3057, 0x29}, // increase adc pwr for missing code + {0x3058, 0x1F}, // turn on dsun + {0x3059, 0x1E}, + {0x3064, 0x00}, + {0x3065, 0x04}, // pad pull 0 + + {BLC_CFG, 0x43}, // BLC_on, IIR + + {0x1001, 0x43}, // BLC dithering en + {0x1002, 0x43}, // blc_darkpixel_thd + {0x0350, 0x00}, // Dgain Control + {BLI_EN, 0x01}, // BLI enable + {0x1003, 0x00}, // BLI Target [Def: 0x20] + + {DPC_CTRL, 0x01}, // DPC option 0: DPC off 1 : mono 3 : bayer1 5 : bayer2 + {0x1009, 0xA0}, // cluster hot pixel th + {0x100A, 0x60}, // cluster cold pixel th + {SINGLE_THR_HOT, 0x90}, // single hot pixel th + {SINGLE_THR_COLD, 0x40}, // single cold pixel th + {0x1012, 0x00}, // Sync. shift disable + {0x2000, 0x07}, + {0x2003, 0x00}, + {0x2004, 0x1C}, + {0x2007, 0x00}, + {0x2008, 0x58}, + {0x200B, 0x00}, + {0x200C, 0x7A}, + {0x200F, 0x00}, + {0x2010, 0xB8}, + {0x2013, 0x00}, + {0x2014, 0x58}, + {0x2017, 0x00}, + {0x2018, 0x9B}, + + {AE_CTRL, 0x01}, //Automatic Exposure + {AE_TARGET_MEAN, 0x3C}, //AE target mean [Def: 0x3C] + {AE_MIN_MEAN, 0x0A}, //AE min target mean [Def: 0x0A] + + {INTEGRATION_H, 0x00}, //Integration H [Def: 0x01] + {INTEGRATION_L, 0x60}, //Integration L [Def: 0x08] + {ANALOG_GAIN, 0x00}, //Analog Global Gain [Def: 0x00] + {DAMPING_FACTOR, 0x20}, //Damping Factor [Def: 0x20] + {DIGITAL_GAIN_H, 0x01}, //Digital Gain High [Def: 0x01] + {DIGITAL_GAIN_L, 0x00}, //Digital Gain Low [Def: 0x00] + + {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_AGAIN_FULL, 0x03}, //Maximum Analog gain in full frame mode [Def: 0x03] + {MAX_AGAIN_BIN2, 0x04}, //Maximum Analog gain in bin2 mode [Def: 0x04] + + {0x210B, 0xC0}, + {0x210E, 0x00}, //Flicker Control + {0x210F, 0x00}, + {0x2110, 0x3C}, + {0x2111, 0x00}, + {0x2112, 0x32}, + + {0x2150, 0x30}, + {0x0340, 0x02}, + {0x0341, 0x16}, + {0x0342, 0x01}, + {0x0343, 0x78}, + {0x3010, 0x01}, + {0x0383, 0x01}, + {0x0387, 0x01}, + {0x0390, 0x00}, + {0x3011, 0x70}, + {0x3059, 0x02}, + {0x3060, 0x01}, + {IMG_ORIENTATION, 0x01}, // change the orientation + {0x0104, 0x01}, + + //============= End of regs marker ================== + {0x0000, 0x00}, +}; + +static int reset(sensor_t *sensor) +{ + // Reset sensor. + uint8_t reg=0xff; + for (int retry=HIMAX_BOOT_RETRY; reg != HIMAX_MODE_STANDBY; retry--) { + if (retry == 0) { + return -1; + } + if (cambus_writeb2(sensor->slv_addr, SW_RESET, HIMAX_RESET) != 0) { + return -1; + } + // Delay for 1ms. + systick_sleep(1); + if (cambus_readb2(sensor->slv_addr, MODE_SELECT, ®) != 0) { + return -1; + } + } + + // Write default regsiters + int ret = 0; + for (int i=0; default_regs[i][0] && ret == 0; i++) { + ret |= cambus_writeb2(sensor->slv_addr, default_regs[i][0], default_regs[i][1]); + } + + // Set PCLK polarity. + ret |= cambus_writeb2(sensor->slv_addr, PCLK_POLARITY, (0x20 | PCLK_FALLING_EDGE)); + + // TODO: Set mode to streaming ? + ret |= cambus_writeb2(sensor->slv_addr, MODE_SELECT, HIMAX_MODE_STREAMING); + + // Delay 300 ms TODO is this required ? + systick_sleep(300); + + return ret; +} + +static int read_reg(sensor_t *sensor, uint16_t reg_addr) +{ + uint8_t reg_data; + if (cambus_readb2(sensor->slv_addr, reg_addr, ®_data) != 0) { + return -1; + } + return reg_data; +} + +static int write_reg(sensor_t *sensor, uint16_t reg_addr, uint16_t reg_data) +{ + return cambus_writeb2(sensor->slv_addr, reg_addr, reg_data); +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + int ret = 0; + switch (pixformat) { + case PIXFORMAT_GRAYSCALE: + // assuming the sensor is in GS mode by default. + break; + // Won't support any other format for now. + default: + return -1; + } + + return ret; +} + +static int set_framesize(sensor_t *sensor, framesize_t framesize) +{ + int ret=0; + uint16_t w = resolution[framesize][0]; + uint16_t h = resolution[framesize][1]; + + if ((w != 320) || (h != 240)) { + ret = -1; + } + + return ret; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb2(sensor->slv_addr, IMG_ORIENTATION, ®); + ret |= cambus_writeb2(sensor->slv_addr, IMG_ORIENTATION, HIMAX_SET_HMIRROR(reg, enable)) ; + return ret; +} + +static int set_vflip(sensor_t *sensor, int enable) +{ + uint8_t reg; + int ret = cambus_readb2(sensor->slv_addr, IMG_ORIENTATION, ®); + ret |= cambus_writeb2(sensor->slv_addr, IMG_ORIENTATION, HIMAX_SET_VMIRROR(reg, enable)) ; + return ret; +} + +int hm01b0_init(sensor_t *sensor) +{ + // Initialize sensor structure. + sensor->gs_bpp = 1; + sensor->reset = reset; + sensor->read_reg = read_reg; + sensor->write_reg = write_reg; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + + // Set sensor flags + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + return 0; +} +#endif //(OMV_SENSOR_HM01B0 == 1) diff --git a/src/omv/hm01b0.h b/src/omv/hm01b0.h new file mode 100644 index 000000000..84832f931 --- /dev/null +++ b/src/omv/hm01b0.h @@ -0,0 +1,15 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2019 Ibrahim Abdelkader + * Copyright (c) 2013-2019 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * HM01B0 driver. + */ +#ifndef __HM01B0_H__ +#define __HM01B0_H__ +#include "sensor.h" +int hm01b0_init(sensor_t *sensor); +#endif // __HM01B0_H__ diff --git a/src/omv/hm01b0_regs.h b/src/omv/hm01b0_regs.h new file mode 100644 index 000000000..01035d53e --- /dev/null +++ b/src/omv/hm01b0_regs.h @@ -0,0 +1,116 @@ +/* + * This file is part of the OpenMV project. + * + * Copyright (c) 2013-2019 Ibrahim Abdelkader + * Copyright (c) 2013-2019 Kwabena W. Agyeman + * + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * HM01B0 register definitions. + */ +#ifndef __REG_REGS_H__ +#define __REG_REGS_H__ + +// Read only registers +#define MODEL_ID_H 0x0000 +#define MODEL_ID_L 0x0001 +#define FRAME_COUNT 0x0005 +#define PIXEL_ORDER 0x0006 +// Sensor mode control +#define MODE_SELECT 0x0100 +#define IMG_ORIENTATION 0x0101 +#define SW_RESET 0x0103 +#define GRP_PARAM_HOLD 0x0104 +// Sensor exposure gain control +#define INTEGRATION_H 0x0202 +#define INTEGRATION_L 0x0203 +#define ANALOG_GAIN 0x0205 +#define DIGITAL_GAIN_H 0x020E +#define DIGITAL_GAIN_L 0x020F +// Frame timing control +#define FRAME_LEN_LINES_H 0x0340 +#define FRAME_LEN_LINES_L 0x0341 +#define LINE_LEN_PCK_H 0x0342 +#define LINE_LEN_PCK_L 0x0343 +// Binning mode control +#define READOUT_X 0x0383 +#define READOUT_Y 0x0387 +#define BINNING_MODE 0x0390 +// Test pattern control +#define TEST_PATTERN_MODE 0x0601 +// Black level control +#define BLC_CFG 0x1000 +#define BLC_TGT 0x1003 +#define BLI_EN 0x1006 +#define BLC2_TGT 0x1007 +// Sensor reserved +#define DPC_CTRL 0x1008 +#define SINGLE_THR_HOT 0x100B +#define SINGLE_THR_COLD 0x100C +// VSYNC,HSYNC and pixel shift register +#define VSYNC_HSYNC_PIXEL_SHIFT_EN 0x1012 +// Automatic exposure gain control +#define AE_CTRL 0x2100 +#define AE_TARGET_MEAN 0x2101 +#define AE_MIN_MEAN 0x2102 +#define CONVERGE_IN_TH 0x2103 +#define CONVERGE_OUT_TH 0x2104 +#define MAX_INTG_H 0x2105 +#define MAX_INTG_L 0x2106 +#define MIN_INTG 0x2107 +#define MAX_AGAIN_FULL 0x2108 +#define MAX_AGAIN_BIN2 0x2109 +#define MIN_AGAIN 0x210A +#define MAX_DGAIN 0x210B +#define MIN_DGAIN 0x210C +#define DAMPING_FACTOR 0x210D +#define FS_CTRL 0x210E +#define FS_60HZ_H 0x210F +#define FS_60HZ_L 0x2110 +#define FS_50HZ_H 0x2111 +#define FS_50HZ_L 0x2112 +#define FS_HYST_TH 0x2113 +// Motion detection control +#define MD_CTRL 0x2150 +#define I2C_CLEAR 0x2153 +#define WMEAN_DIFF_TH_H 0x2155 +#define WMEAN_DIFF_TH_M 0x2156 +#define WMEAN_DIFF_TH_L 0x2157 +#define MD_THH 0x2158 +#define MD_THM1 0x2159 +#define MD_THM2 0x215A +#define MD_THL 0x215B +// Sensor timing control +#define QVGA_WIN_EN 0x3010 +#define SIX_BIT_MODE_EN 0x3011 +#define PMU_AUTOSLEEP_FRAMECNT 0x3020 +#define ADVANCE_VSYNC 0x3022 +#define ADVANCE_HSYNC 0x3023 +#define EARLY_GAIN 0x3035 +// IO and clock control +#define BIT_CONTROL 0x3059 +#define OSC_CLK_DIV 0x3060 +#define ANA_Register_11 0x3061 +#define IO_DRIVE_STR 0x3062 +#define IO_DRIVE_STR2 0x3063 +#define ANA_Register_14 0x3064 +#define OUTPUT_PIN_STATUS_CONTROL 0x3065 +#define ANA_Register_17 0x3067 +#define PCLK_POLARITY 0x3068 +/* + * Useful value of Himax registers + */ +#define HIMAX_RESET 0x01 +#define HIMAX_MODE_STANDBY 0x00 +#define HIMAX_MODE_STREAMING 0x01 // I2C triggered streaming enable +#define HIMAX_MODE_STREAMING_NFRAMES 0x03 // Output N frames +#define HIMAX_MODE_STREAMING_TRIG 0x05 // Hardware Trigger +#define HIMAX_SET_HMIRROR(r, x) ((r&0xFE)|((x&1)<<0)) +#define HIMAX_SET_VMIRROR(r, x) ((r&0xFD)|((x&1)<<1)) + +#define PCLK_RISING_EDGE 0x00 +#define PCLK_FALLING_EDGE 0x01 +#define AE_CTRL_ENABLE 0x00 +#define AE_CTRL_DISABLE 0x01 + +#endif //__REG_REGS_H__ diff --git a/src/omv/sensor.c b/src/omv/sensor.c index 5619cc38c..83d120e1e 100644 --- a/src/omv/sensor.c +++ b/src/omv/sensor.c @@ -19,6 +19,7 @@ #include "ov5640.h" #include "mt9v034.h" #include "lepton.h" +#include "hm01b0.h" #include "sensor.h" #include "systick.h" #include "framebuffer.h" @@ -329,6 +330,13 @@ int sensor_init() case OV5640_SLV_ADDR: cambus_readb2(sensor.slv_addr, OV5640_CHIP_ID, &sensor.chip_id); break; + #if (OMV_SENSOR_HM01B0 == 1) + case HM01B0_SLV_ADDR: + cambus_readb2(sensor.slv_addr, HIMAX_CHIP_ID, &sensor.chip_id); + // TODO fix when manf. ID is known. + sensor.chip_id = HM01B0_ID; + break; + #endif //(OMV_SENSOR_HM01B0 == 1) default: return -3; break; @@ -363,6 +371,11 @@ int sensor_init() case OV9650_ID: init_ret = ov9650_init(&sensor); break; + #if (OMV_SENSOR_HM01B0 == 1) + case HM01B0_ID: + init_ret = hm01b0_init(&sensor); + break; + #endif //(OMV_SENSOR_HM01B0 == 1) default: return -3; break; diff --git a/src/omv/sensor.h b/src/omv/sensor.h index c92c3436d..b150f05fc 100644 --- a/src/omv/sensor.h +++ b/src/omv/sensor.h @@ -19,10 +19,13 @@ #define MT9V034_SLV_ADDR (0xB8) #define LEPTON_SLV_ADDR (0x54) #define OV5640_SLV_ADDR (0x78) +#define HM01B0_SLV_ADDR (0x48) +// Chip ID registers. #define OV_CHIP_ID (0x0A) #define OV5640_CHIP_ID (0x300A) #define ON_CHIP_ID (0x00) +#define HIMAX_CHIP_ID (0x0001) #define OV9650_ID (0x96) #define OV2640_ID (0x26) @@ -30,6 +33,7 @@ #define OV5640_ID (0x56) #define MT9V034_ID (0x13) #define LEPTON_ID (0x54) +#define HM01B0_ID (0xAA) // TODO fix this with valid manf. ID. typedef enum { PIXFORMAT_INVALID = 0,