diff --git a/src/Makefile b/src/Makefile index 3d4fb5bf1..18eb2c70b 100755 --- a/src/Makefile +++ b/src/Makefile @@ -57,6 +57,7 @@ WINC1500_DIR=drivers/winc1500 MLX90621_DIR=drivers/mlx90621 MLX90640_DIR=drivers/mlx90640 MLX90641_DIR=drivers/mlx90641 +PIXART_DIR=drivers/pixart LIBPDM_DIR=lib/libpdm TENSORFLOW_DIR=lib/libtf OMV_BOARD_CONFIG_DIR=$(TOP_DIR)/$(OMV_DIR)/boards/$(TARGET)/ diff --git a/src/drivers/pixart/Makefile b/src/drivers/pixart/Makefile new file mode 100644 index 000000000..cda814cb4 --- /dev/null +++ b/src/drivers/pixart/Makefile @@ -0,0 +1,41 @@ +### +# MIT License +# +# Copyright (c) 2021 Pixart Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +# of the Software, and to permit persons to whom the Software is furnished to do +# so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. +### + +SRCS = $(wildcard src/*.c) +OBJS = $(addprefix $(BUILD)/, $(SRCS:.c=.o)) +OBJ_DIRS = $(sort $(dir $(OBJS))) + +all: | $(OBJ_DIRS) $(OBJS) +$(OBJ_DIRS): + $(MKDIR) -p $@ + +$(BUILD)/%.o : %.c + $(ECHO) "CC $<" + $(CC) $(CFLAGS) -c -o $@ $< + +$(BUILD)/%.o : %.s + $(ECHO) "AS $<" + $(AS) $(AFLAGS) $< -o $@ + +-include $(OBJS:%.o=%.d) diff --git a/src/drivers/pixart/include/pixspi.h b/src/drivers/pixart/include/pixspi.h new file mode 100644 index 000000000..dbb081c06 --- /dev/null +++ b/src/drivers/pixart/include/pixspi.h @@ -0,0 +1,9 @@ +#ifndef __PIXSPI__ +#define __PIXSPI__ +#include +#include +bool pixspi_init(); +void pixspi_release(); +int pixspi_regs_read(uint8_t addr, uint8_t * data, uint16_t length); +int pixspi_regs_write(uint8_t addr, const uint8_t * data, uint16_t length); +#endif \ No newline at end of file diff --git a/src/drivers/pixart/src/pixspi.c b/src/drivers/pixart/src/pixspi.c new file mode 100644 index 000000000..11d09dde4 --- /dev/null +++ b/src/drivers/pixart/src/pixspi.c @@ -0,0 +1,145 @@ +#include "pixspi.h" +#include +#include STM32_HAL_H +#include +#include + +#include "common.h" +#include "omv_boardconfig.h" +#include + +#ifdef ISC_SPI +#define SPI_TIMEOUT (5000) /* in ms */ + +#define CS_PORT ISC_SPI_SSEL_PORT +#define CS_PIN ISC_SPI_SSEL_PIN +#define W_CS_LOW() HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_RESET) +#define W_CS_HIGH() HAL_GPIO_WritePin(CS_PORT, CS_PIN, GPIO_PIN_SET) + +extern SPI_HandleTypeDef ISC_SPIHandle; + +static bool spi_send(uint8_t *data, uint16_t len) +{ + HAL_StatusTypeDef status = HAL_OK; + W_CS_LOW(); + //mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + status = HAL_SPI_Transmit( + &ISC_SPIHandle, data, len, SPI_TIMEOUT); + //MICROPY_END_ATOMIC_SECTION(atomic_state); + W_CS_HIGH(); + + return (status == HAL_OK); +} + +static bool spi_send_recv(uint8_t *txData, uint8_t *rxData, uint16_t len) +{ + W_CS_LOW(); + //mp_uint_t atomic_state = MICROPY_BEGIN_ATOMIC_SECTION(); + bool res = (HAL_SPI_Transmit(&ISC_SPIHandle, txData, 1, SPI_TIMEOUT) == HAL_OK); + res = (HAL_SPI_Receive(&ISC_SPIHandle, rxData, len, SPI_TIMEOUT) == HAL_OK); + //MICROPY_END_ATOMIC_SECTION(atomic_state); + W_CS_HIGH(); + return res; +} + +bool pixspi_init() +{ + // Init SPI + memset(&ISC_SPIHandle, 0, sizeof(ISC_SPIHandle)); + ISC_SPIHandle.Instance = ISC_SPI; + ISC_SPIHandle.Init.Mode = SPI_MODE_MASTER; + ISC_SPIHandle.Init.Direction = SPI_DIRECTION_2LINES; + ISC_SPIHandle.Init.DataSize = SPI_DATASIZE_8BIT; + ISC_SPIHandle.Init.CLKPolarity = SPI_POLARITY_HIGH; + ISC_SPIHandle.Init.CLKPhase = SPI_PHASE_2EDGE; + ISC_SPIHandle.Init.NSS = SPI_NSS_SOFT; + ISC_SPIHandle.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32 ; + ISC_SPIHandle.Init.FirstBit = SPI_FIRSTBIT_MSB; + ISC_SPIHandle.Init.TIMode = SPI_TIMODE_DISABLED; + ISC_SPIHandle.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLED; + ISC_SPIHandle.Init.CRCPolynomial = 0; + + if (HAL_SPI_Init(&ISC_SPIHandle) != HAL_OK) + { + /* Initialization Error */ + return false; + } + + GPIO_InitTypeDef GPIO_InitStructure; + // Re-Init GPIO for SPI SS(CS) pin, software control. + GPIO_InitStructure.Pin = ISC_SPI_SSEL_PIN; + GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_PP; + GPIO_InitStructure.Pull = GPIO_PULLUP; + GPIO_InitStructure.Alternate = ISC_SPI_SSEL_AF; + GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_LOW; + HAL_GPIO_Init(ISC_SPI_SSEL_PORT, &GPIO_InitStructure); + + // Default high. + W_CS_HIGH(); + return true; +} + +void pixspi_release() +{ + W_CS_LOW(); + HAL_SPI_DeInit(&ISC_SPIHandle); +} + +int pixspi_regs_read(uint8_t addr, uint8_t * data, uint16_t length) +{ + if ((addr & 0x80)) + { +#ifdef DEBUG + printf("pixspi_regs_read() address (0x%x) overflow.\n", addr); +#endif + return -1; + } + addr |= 0x80; + if (!spi_send_recv(&addr, data, length)) + { +#ifdef DEBUG + printf("spi_send_recv() failed.\n"); +#endif + return -1; + } + return 0; +} + +int pixspi_regs_write(uint8_t addr, const uint8_t * data, uint16_t length) +{ + uint8_t buff[64] = {}; + if ((addr & 0x80) == 0x80) + { +#ifdef DEBUG + printf("pixspi_regs_read() address (0x%x) overflow.\n", addr); +#endif + return -1; + } + int32_t remaining = length; + + const static uint16_t MAX_LENGTH = 255; + do + { + uint16_t len = remaining>MAX_LENGTH?MAX_LENGTH:remaining; + buff[0] = addr; + memcpy(buff+1, data, len); + bool res = spi_send(buff, len + 1); + if (!res) + { +#ifdef DEBUG + printf("spi_send() failed.\n"); +#endif + return -1; + } + remaining = remaining - MAX_LENGTH; + } + while (remaining > 0); + + return 0; +} +#else +bool pixspi_init() { return false; } +void pixspi_release() {} +int pixspi_regs_read(uint8_t addr, uint8_t * data, uint16_t length) { return -1; } +int pixspi_regs_write(uint8_t addr, const uint8_t * data, uint16_t length) { return -1; } +#endif \ No newline at end of file diff --git a/src/omv/Makefile b/src/omv/Makefile index 9831bdfea..c1d2e9a33 100644 --- a/src/omv/Makefile +++ b/src/omv/Makefile @@ -37,6 +37,7 @@ SRCS += $(addprefix sensors/, \ lepton.c \ hm01b0.c \ gc2145.c \ + paj6100.c \ ) SRCS += $(addprefix modules/, \ diff --git a/src/omv/boards/NANO33/omv_boardconfig.h b/src/omv/boards/NANO33/omv_boardconfig.h index 34845f43d..d90cd9cac 100644 --- a/src/omv/boards/NANO33/omv_boardconfig.h +++ b/src/omv/boards/NANO33/omv_boardconfig.h @@ -46,6 +46,7 @@ #define OMV_ENABLE_MT9V034 (0) #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (0) // Set which OV767x sensor is used #define OMV_OV7670_VERSION (75) diff --git a/src/omv/boards/OPENMV2/omv_boardconfig.h b/src/omv/boards/OPENMV2/omv_boardconfig.h index 1f9754a57..365a66423 100644 --- a/src/omv/boards/OPENMV2/omv_boardconfig.h +++ b/src/omv/boards/OPENMV2/omv_boardconfig.h @@ -56,6 +56,7 @@ #define OMV_ENABLE_MT9V034 (0) #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMV3/omv_boardconfig.h b/src/omv/boards/OPENMV3/omv_boardconfig.h index 17a5256b1..0266f9185 100644 --- a/src/omv/boards/OPENMV3/omv_boardconfig.h +++ b/src/omv/boards/OPENMV3/omv_boardconfig.h @@ -56,6 +56,7 @@ #define OMV_ENABLE_MT9V034 (0) #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMV4/omv_boardconfig.h b/src/omv/boards/OPENMV4/omv_boardconfig.h index 2462f531e..65d5b335c 100644 --- a/src/omv/boards/OPENMV4/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4/omv_boardconfig.h @@ -62,6 +62,7 @@ #define OMV_ENABLE_MT9V034 (1) #define OMV_ENABLE_LEPTON (1) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (1) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMV4P/omv_boardconfig.h b/src/omv/boards/OPENMV4P/omv_boardconfig.h index 84dfd2739..82630cad8 100644 --- a/src/omv/boards/OPENMV4P/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4P/omv_boardconfig.h @@ -66,6 +66,7 @@ #define OMV_ENABLE_MT9V034 (1) #define OMV_ENABLE_LEPTON (1) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (1) // Enable sensor features #define OMV_ENABLE_OV5640_AF (0) diff --git a/src/omv/boards/OPENMVPT/omv_boardconfig.h b/src/omv/boards/OPENMVPT/omv_boardconfig.h index 1908adf04..ef34b0f6b 100644 --- a/src/omv/boards/OPENMVPT/omv_boardconfig.h +++ b/src/omv/boards/OPENMVPT/omv_boardconfig.h @@ -63,6 +63,7 @@ #define OMV_ENABLE_MT9V034 (0) #define OMV_ENABLE_LEPTON (0) #define OMV_ENABLE_HM01B0 (0) +#define OMV_ENABLE_PAJ6100 (0) // Enable sensor features #define OMV_ENABLE_OV5640_AF (1) diff --git a/src/omv/common/sensor.h b/src/omv/common/sensor.h index e889e59ed..9fea7f047 100644 --- a/src/omv/common/sensor.h +++ b/src/omv/common/sensor.h @@ -42,6 +42,8 @@ #define LEPTON_ID (0x54) #define HM01B0_ID (0xB0) #define GC2145_ID (0x21) +// Wide ID +#define PAJ6100_ID (0x6100) typedef enum { FRAMESIZE_INVALID = 0, diff --git a/src/omv/ports/stm32/omv_portconfig.mk b/src/omv/ports/stm32/omv_portconfig.mk index 49a3be337..7609fdd68 100644 --- a/src/omv/ports/stm32/omv_portconfig.mk +++ b/src/omv/ports/stm32/omv_portconfig.mk @@ -44,6 +44,7 @@ OMV_CFLAGS += -I$(TOP_DIR)/$(WINC1500_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90621_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90640_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(MLX90641_DIR)/include/ +OMV_CFLAGS += -I$(TOP_DIR)/$(PIXART_DIR)/include/ OMV_CFLAGS += -I$(TOP_DIR)/$(TENSORFLOW_DIR)/$(CPU)/ OMV_CFLAGS += -I$(TOP_DIR)/$(LIBPDM_DIR)/ @@ -113,6 +114,7 @@ endif FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o) FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o) FIRM_OBJ += $(wildcard $(BUILD)/$(MLX90641_DIR)/src/*.o) +FIRM_OBJ += $(wildcard $(BUILD)/$(PIXART_DIR)/src/*.o) #------------- OpenMV Objects ----------------# FIRM_OBJ += $(addprefix $(BUILD)/$(CMSIS_DIR)/src/, \ @@ -150,6 +152,7 @@ FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \ lepton.o \ hm01b0.o \ gc2145.o \ + paj6100.o \ ) FIRM_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/modules/, \ @@ -514,6 +517,7 @@ UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/sensors/, \ lepton.o \ hm01b0.o \ gc2145.o \ + paj6100.o \ ) UVC_OBJ += $(addprefix $(BUILD)/$(OMV_DIR)/imlib/,\ @@ -541,6 +545,7 @@ endif UVC_OBJ += $(wildcard $(BUILD)/$(MLX90621_DIR)/src/*.o) UVC_OBJ += $(wildcard $(BUILD)/$(MLX90640_DIR)/src/*.o) UVC_OBJ += $(wildcard $(BUILD)/$(MLX90641_DIR)/src/*.o) +UVC_OBJ += $(wildcard $(BUILD)/$(PIXART_DIR)/src/*.o) endif ifeq ($(OMV_ENABLE_CM4), 1) @@ -600,6 +605,7 @@ endif $(MAKE) -C $(MLX90621_DIR) BUILD=$(BUILD)/$(MLX90621_DIR) CFLAGS="$(CFLAGS) -MMD" $(MAKE) -C $(MLX90640_DIR) BUILD=$(BUILD)/$(MLX90640_DIR) CFLAGS="$(CFLAGS) -MMD" $(MAKE) -C $(MLX90641_DIR) BUILD=$(BUILD)/$(MLX90641_DIR) CFLAGS="$(CFLAGS) -MMD" + $(MAKE) -C $(PIXART_DIR) BUILD=$(BUILD)/$(PIXART_DIR) CFLAGS="$(CFLAGS) -MMD" $(MAKE) -C $(OMV_DIR) BUILD=$(BUILD)/$(OMV_DIR) CFLAGS="$(CFLAGS) -MMD" ifeq ($(CUBEAI), 1) $(MAKE) -C $(CUBEAI_DIR) BUILD=$(BUILD)/$(CUBEAI_DIR) CFLAGS="$(CFLAGS) -fno-strict-aliasing -MMD" diff --git a/src/omv/ports/stm32/sensor.c b/src/omv/ports/stm32/sensor.c index cdfd8f8c0..8a0c0e053 100644 --- a/src/omv/ports/stm32/sensor.c +++ b/src/omv/ports/stm32/sensor.c @@ -25,6 +25,7 @@ #include "mt9m114.h" #include "lepton.h" #include "hm01b0.h" +#include "paj6100.h" #include "gc2145.h" #include "systick.h" #include "framebuffer.h" @@ -42,6 +43,10 @@ #define OMV_ENABLE_SENSOR_MDMA_TOTAL_OFFLOAD 1 #endif +#if (OMV_ENABLE_PAJ6100 == 1) +#define OMV_ENABLE_NONI2CIS +#endif + sensor_t sensor = {}; static TIM_HandleTypeDef TIMHandle = {.Instance = DCMI_TIM}; static DMA_HandleTypeDef DMAHandle = {.Instance = DMA2_Stream1}; @@ -386,20 +391,35 @@ int sensor_init() systick_sleep(10); sensor.slv_addr = cambus_scan(&sensor.bus); + #ifndef OMV_ENABLE_NONI2CIS if (sensor.slv_addr == 0) { return -2; } + #endif } } } // Clear sensor chip ID. - sensor.chip_id = 0; + sensor.chip_id_w = 0; // Set default snapshot function. sensor.snapshot = sensor_snapshot; switch (sensor.slv_addr) { + #if (OMV_ENABLE_PAJ6100 == 1) + case 0: + if (paj6100_detect(&sensor)) { + // Found PixArt PAJ6100 + sensor.chip_id_w = PAJ6100_ID; + sensor.pwdn_pol = ACTIVE_LOW; + sensor.reset_pol = ACTIVE_LOW; + break; + } + // Okay, there is not any sensor be detected. + return -2; + #endif + #if (OMV_ENABLE_OV2640 == 1) case OV2640_SLV_ADDR: // Or OV9650. cambus_readb(&sensor.bus, sensor.slv_addr, OV_CHIP_ID, &sensor.chip_id); @@ -452,8 +472,7 @@ int sensor_init() return -3; break; } - - switch (sensor.chip_id) { + switch (sensor.chip_id_w) { #if (OMV_ENABLE_OV2640 == 1) case OV2640_ID: if (extclk_config(OV2640_XCLK_FREQ) != 0) { @@ -544,6 +563,15 @@ int sensor_init() break; #endif //(OMV_ENABLE_GC2145 == 1) + #if (OMV_ENABLE_PAJ6100 == 1) + case PAJ6100_ID: + if (extclk_config(PAJ6100_XCLK_FREQ) != 0) { + return -3; + } + init_ret = paj6100_init(&sensor); + break; + #endif // (OMV_ENABLE_PAJ6100 == 1) + default: return -3; break; @@ -639,7 +667,7 @@ int sensor_reset() int sensor_get_id() { - return sensor.chip_id; + return sensor.chip_id_w; } bool sensor_is_detected() diff --git a/src/omv/sensors/paj6100.c b/src/omv/sensors/paj6100.c new file mode 100644 index 000000000..48d08fcee --- /dev/null +++ b/src/omv/sensors/paj6100.c @@ -0,0 +1,788 @@ +/* + * File: paj6100.c + * Created Date: Tuesday, May 25th 2021, 10:45:35 am + * Author: Lake Fu + * ----- + * Last Modified: Tuesday June 15th 2021 2:54:43 pm + * Modified By: Lake Fu at + * ----- + * MIT License + * + * Copyright (c) 2021 Pixart Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * ----- + * HISTORY: + * Date By Comments + * ---------- --- ---------------------------------------------------------- + */ +#include "omv_boardconfig.h" +#if (OMV_ENABLE_PAJ6100 == 1) +#include +#include + +#include "systick.h" +#include "sensor.h" +#include "framebuffer.h" + +#include "paj6100.h" +#include "paj6100_reg.h" +#include "pixspi.h" + +#define CACHE_BANK + +#ifdef DEBUG +// For dump initial result before connect to IDE, +// we use a global variable to store it. +static int8_t init_res; +#endif + +static int16_t bank_cache = -1; + +// Exposure time related paramaters + +#define QVGA_MAX_EXPO_PA 85161 +#define QQVGA_MAX_EXPO_PA 25497 + +#define R_AE_MinGain 1 +#define R_AE_MaxGain 8 + +static float R_FrameTime = 6000000/30; +static long R_AE_MaxExpoTime; +static long R_AE_MinExpoTime = 120/6 + 0.5f; + +#define CAL_MAX_EXPO_TIME(PA) (fast_roundf(((float)(R_FrameTime-PA))/6)) + +#define L_TARGET 127 +#define AE_LOCK_RANGE_IN 8 +#define AE_LOCK_RANGE_OUT 16 + +static uint32_t l_total = 0; +static uint32_t l_target_total = 0; +static uint32_t lt_lockrange_in_ubound, lt_lockrange_in_lbound; +static uint32_t lt_lockrange_out_ubound, lt_lockrange_out_lbound; +static bool ae_converged_flag = false; + +static uint8_t skip_frame = 0; + +static bool is_ae_enabled = true; +static int exp_us_cache = -1; +// Exposure time related paramaters - + +static int set_auto_gain(sensor_t *sensor, int enable, + float gain_db, float gain_db_ceiling); +static int get_gain_db(sensor_t *sensor, float *gain_db); + +static int bank_switch(uint8_t bank) +{ +#ifdef CACHE_BANK + if (bank_cache == bank) + return 0; +#endif + + if (pixspi_regs_write(REG_BANK_SWITCH, &bank, 1)) + { + printf("Bank switch failed.\n"); + return -1; + } + bank_cache = bank; + return 0; +} + +static int read_regs_w_bank(uint8_t bank, uint8_t addr, uint8_t * buff, uint16_t len) +{ + if (bank_switch(bank)) return -1; + return pixspi_regs_read(addr, buff, len); +} + +static int write_regs_w_bank(uint8_t bank, uint8_t addr, uint8_t * buff, uint16_t len) +{ + if (bank_switch(bank)) return -1; + return pixspi_regs_write(addr, buff, len); +} + +static int init_sensor(sensor_t * sensor) +{ + #define ta_seq low_active_R_ABC_Avg_UBx50_T_BLACINV_EnHx1_T_SIG_REFx1 + + int arr_size = sizeof(ta_seq)/sizeof(ta_seq[0]); + for (int i=0; i= EXPOSURE_BASE) + { + int param; + if (sensor->framesize == FRAMESIZE_QVGA) + param = 88803; + else if (sensor->framesize == FRAMESIZE_QQVGA) + param = 29139; // QQVGA + else + param = 88803; + + int max_cmd_expo = R_FrameTime - param; + cmd_expo = (exp_us - EXPOSURE_BASE) * ((float)PAJ6100_XCLK_FREQ/1000000) + 0.5f; + if (protected) + { + if (cmd_expo > max_cmd_expo) + { + cmd_expo = max_cmd_expo; + exp_us = (cmd_expo + 3642) / ((float)PAJ6100_XCLK_FREQ/1000000) + 0.5f; + printf("Exposure time overflow, reset to %dus.\n", exp_us); + } + } + exp_offset = 0; + } + else + { + cmd_expo = 0; + exp_offset = (EXPOSURE_BASE - exp_us) * ((float)PAJ6100_XCLK_FREQ/1000000) + 0.5; + } +#ifdef DEBUG_AE + printf("target - cmd_exp: %ld, exp_offset: %d\n", cmd_expo, exp_offset); +#endif + uint8_t buff[3] = { + (uint8_t)(cmd_expo & 0xff), + (uint8_t)((cmd_expo >> 8) & 0xff), + (uint8_t)((cmd_expo >> 16) & 0xff), + }; + ret = write_regs_w_bank(BANK_0, REG_CMD_EXPO_L, buff, 3); + + buff[0] = (uint8_t)(exp_offset & 0xff); + buff[1] = (uint8_t)((exp_offset >> 8) & 0xff); + ret |= write_regs_w_bank(BANK_0, REG_EXP_OFFSET_L, buff, 2); + buff[0] = 1; + ret |= write_regs_w_bank(BANK_1, REG_ISP_UPDATE, buff, 1); + + if (ret) + { + printf("Failed to write cmd_expo or exp_offset.\n"); + return -1; + } + exp_us_cache = exp_us; + return ret; +} + +static int get_exposure(sensor_t *sensor) +{ + int ret; + uint8_t buff[3] = {}; + uint32_t cmd_expo /* 24-bit available */; + uint16_t exp_offset; + + if (exp_us_cache >= 0) + return exp_us_cache; + + ret = read_regs_w_bank(BANK_0, REG_CMD_EXPO_L, buff, 3); + if (ret) + { + printf("Read cmd_expo failed.\n"); + return -1; + } + cmd_expo = buff[0] + (((uint32_t)buff[1]) << 8) + (((uint32_t)buff[2]) << 16); + + ret = read_regs_w_bank(BANK_0, REG_EXP_OFFSET_L, buff, 2); + if (ret) + { + printf("Read exp_offset failed.\n"); + return -1; + } + exp_offset = buff[0] + (((uint16_t)buff[1]) << 8); + +#ifdef DEBUG_AE + printf("cmd_exp: %ld, exp_offset: %d\n", cmd_expo, exp_offset); +#endif + + if (exp_offset == 0) + { + exp_us_cache = (cmd_expo + 3642) / (PAJ6100_XCLK_FREQ/1000000); + } + else + { + exp_us_cache = (3642 - exp_offset) / (PAJ6100_XCLK_FREQ/1000000); + } + + return exp_us_cache; +} + +static void blc_freeze(bool enable) +{ + uint8_t tmp; + tmp = enable?2:0; + write_regs_w_bank(0, 0x0E, &tmp, 1); + tmp = 1; + write_regs_w_bank(1, 0x00, &tmp, 1); // Update flag +} + +static void auto_exposure(sensor_t *sensor) +{ + if (!is_ae_enabled) + return; + + if (skip_frame) + { + --skip_frame; + return; + } + + if ((lt_lockrange_in_lbound <= l_total) && (l_total <= lt_lockrange_in_ubound)) + { + ae_converged_flag = true; + } + else if ((l_total > lt_lockrange_out_ubound) || (l_total < lt_lockrange_out_lbound)) + { + ae_converged_flag = false; + } + blc_freeze(ae_converged_flag); + + if (ae_converged_flag == false) + { + float gain_db = 0; + if (get_gain_db(sensor, &gain_db)) + { + printf("Get Gain DB failed.\n"); + return; + } + uint32_t gain; + if (gain_db < 6) { + // 1x gain + gain = 1; + } else if (gain_db < 12) { + // 2x gain + gain = 2; + } else if (gain_db < 18) { + // 4x gain + gain = 4; + } else { + // 8x gain + gain = 8; + } + + int expo = get_exposure(sensor); + if (expo < 0) + { + printf("Get exposure failed.\n"); + return; + } +#ifdef DEBUG_AE + printf("Current Gain: %ldx, Expo: %d\n", gain, expo); +#endif + + uint32_t GEP = gain * expo; + float l_ratio = ((float)l_target_total) / l_total; + float GEP_target = GEP * l_ratio; + uint32_t expo_target = IM_MIN(IM_MAX(fast_roundf(GEP_target / R_AE_MinGain), R_AE_MinExpoTime), R_AE_MaxExpoTime); + +#ifdef DEBUG_AE + printf("GEP: %ld ", GEP); + printf("GEP_target: %d (x1000), L_Ratio: %d (x1000)\n", + (int)(GEP_target*1000), (int)(l_ratio*1000)); + printf("1st Expo Target: %ld (max: %ld) ", expo_target, R_AE_MaxExpoTime); +#endif + uint32_t gain_target; + float tmp_gain = GEP_target/expo_target; + if (tmp_gain <= 1) gain_target = 1; + else if (tmp_gain <= 2) gain_target = 2; + else if (tmp_gain <= 4) gain_target = 4; + else gain_target = 8; + //gain_target = IM_MIN(IM_MAX(fast_ceilf(GEP_target/expo_target), R_AE_MinGain), R_AE_MaxGain); + gain_db = 20 * (fast_log((float)gain_target)/fast_log(10.0)); + expo_target = IM_MIN(IM_MAX(fast_roundf(GEP_target / gain_target), R_AE_MinExpoTime), R_AE_MaxExpoTime); +#ifdef DEBUG_AE + printf("Gain Target: %ld (%d DB (x1000))\n", gain_target, (int)(gain_db*1000)); + printf("Final Expo Target: %ld (max: %ld) \n", expo_target, R_AE_MaxExpoTime); +#endif + set_exposure(sensor, expo_target, false); + set_auto_gain(sensor, false, gain_db, 0); + skip_frame = 0; + } +} +//----------------------------------------------------------------- +static int sleep(sensor_t *sensor, int enable) +{ + int ret; + uint8_t val; + + if (enable) { + ret = read_regs_w_bank(BANK_1, REG_CMD_SENSOR_MODE, &val, 1); + if (ret) { + printf("Failed to read REG_CMD_SENSOR_MODE.\n"); + return -1; + } + val |= (1 << 7); + ret = write_regs_w_bank(BANK_1, REG_CMD_SENSOR_MODE, &val, 1); + if (ret) { + printf("Failed to write REG_CMD_SENSOR_MODE.\n"); + return -1; + } + // Sleep 30ms + systick_sleep(30); + ret = read_regs_w_bank(BANK_1, REG_CMD_LPM_ENH, &val, 1); + if (ret) { + printf("Failed to read REG_CMD_SENSOR_MODE.\n"); + return -1; + } + val |= (1 << 6); + ret = write_regs_w_bank(BANK_1, REG_CMD_LPM_ENH, &val, 1); + if (ret) { + printf("Failed to write REG_CMD_LPM_ENH.\n"); + return -1; + } + } else { + ret = read_regs_w_bank(BANK_1, REG_CMD_SENSOR_MODE, &val, 1); + if (ret) { + #ifdef DEBUG + printf("Failed to read REG_CMD_SENSOR_MODE.\n"); + #endif + return -1; + } + val &= ~(1 << 7); + val &= ~(1 << 6); + ret = write_regs_w_bank(BANK_1, REG_CMD_SENSOR_MODE, &val, 1); + if (ret) { + #ifdef DEBUG + printf("Failed to write REG_CMD_SENSOR_MODE.\n"); + #endif + return -1; + } + } + return 0; +} + +static int read_reg(sensor_t *sensor, uint16_t reg_addr) +{ + uint8_t data; + + if (pixspi_regs_read((uint8_t)reg_addr, &data, 1)) + return -1; + return data; +} + +static int write_reg(sensor_t *sensor, uint16_t reg_addr, uint16_t reg_data) +{ + uint8_t data = reg_data; + + // Clear bank cache. + bank_cache = -1; + + return pixspi_regs_write((uint8_t)reg_addr, &data, 1); +} + +static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) +{ + if (pixformat != PIXFORMAT_GRAYSCALE) + return -1; + return 0; +} + +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]; + + uint8_t aavg_VnH, abc_start_line, voffset, abc_sample_size; + ret |= read_regs_w_bank(BANK_0, REG_CMD_AAVG_V /* REG_CMD_AAVG_H */, &aavg_VnH, 1); + ret |= read_regs_w_bank(BANK_0, REG_ABC_START_LINE, &abc_start_line, 1); + ret |= read_regs_w_bank(BANK_1, REG_ABC_SAMPLE_SIZE, &abc_sample_size, 1); + + if (ret) + { + printf("Failed to read Average mode registers.\n"); + return -1; + } + + switch (framesize) + { + case FRAMESIZE_QVGA: + aavg_VnH &= ~((1 << 3) | (1 << 2)); + abc_start_line = (abc_start_line & ~(0x07 << 1)) | (2 << 1); + voffset = 2; + abc_sample_size = (abc_sample_size & ~(0x07)) | 6; + + R_AE_MaxExpoTime = CAL_MAX_EXPO_TIME(QVGA_MAX_EXPO_PA); + break; + case FRAMESIZE_QQVGA: + aavg_VnH |= (1 << 3) | (1 << 2); + abc_start_line = (abc_start_line & ~(0x07 << 1)) | (1 << 1); + voffset = 1; + abc_sample_size = (abc_sample_size & ~(0x07)) | 5; + + R_AE_MaxExpoTime = CAL_MAX_EXPO_TIME(QQVGA_MAX_EXPO_PA); + break; + default: + printf("PAJ6100 only support QVGA & QQVGA now.\n"); + return -1; + } + + ret |= write_regs_w_bank(BANK_0, REG_CMD_AAVG_V /* REG_CMD_AAVG_H */, &aavg_VnH, 1); + ret |= write_regs_w_bank(BANK_0, REG_ABC_START_LINE, &abc_start_line, 1); + ret |= write_regs_w_bank(BANK_1, REG_CP_WOI_VOFFSET, &voffset, 1); + ret |= write_regs_w_bank(BANK_1, REG_ABC_SAMPLE_SIZE, &abc_sample_size, 1); + + if (ret) + { + printf("Failed to write Average mode registers.\n"); + return -1; + } + + l_target_total = L_TARGET * w * h; + lt_lockrange_in_ubound = (L_TARGET + AE_LOCK_RANGE_IN) * w * h; + lt_lockrange_in_lbound = (L_TARGET - AE_LOCK_RANGE_IN) * w * h; + lt_lockrange_out_ubound = (L_TARGET + AE_LOCK_RANGE_OUT) * w * h; + lt_lockrange_out_lbound = (L_TARGET - AE_LOCK_RANGE_OUT) * w * h; + + return 0; +} + +static int set_contrast(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_brightness(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_saturation(sensor_t *sensor, int level) +{ + return 0; +} + +static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) +{ + return 0; +} + +static int set_special_effect(sensor_t *sensor, sde_t sde) +{ + return 0; +} + +static int set_auto_gain(sensor_t *sensor, int enable, + float gain_db, float gain_db_ceiling) +{ + if (enable) + return 0; + int ret = 0; + uint8_t val, fgh, ggh; + + if (gain_db < 6) { + // 1x gain + fgh = 0; + ggh = 0; + } else if (gain_db < 12) { + // 2x gain + fgh = 0; + ggh = 1; + } else if (gain_db < 18) { + // 4x gain + fgh = 2; + ggh = 1; + } else { + // 8x gain + fgh = 3; + ggh = 1; + } + + ret = read_regs_w_bank(BANK_0, REG_FGH, &val, 1); + fgh = (val & ~(3 << 4)) | (fgh << 4); // fgh[5:4] = 0 + ret |= read_regs_w_bank(BANK_0, REG_GGH, &val, 1); + ggh = (val & ~(1 << 7)) | (ggh << 7); // ggh[7] = 1 + if (ret) { + printf("Failed to read FGH or GGH.\n"); + } else { + write_regs_w_bank(BANK_0, REG_FGH, &fgh, 1); + write_regs_w_bank(BANK_0, REG_GGH, &ggh, 1); + val = 1; + write_regs_w_bank(BANK_1, REG_ISP_UPDATE, &val, 1); + } + + return 0; +} + +static int get_gain_db(sensor_t *sensor, float *gain_db) +{ + int ret = 0; + uint8_t val; + uint8_t fgh, ggh; + + ret |= read_regs_w_bank(BANK_0, REG_FGH, &val, 1); + fgh = (val >> 4) & 0x03 ; + ret |= read_regs_w_bank(BANK_0, REG_GGH, &val, 1); + ggh = (val >> 7) & 0x01 ; + + if (ret) { + printf("Failed to read FGH or GGH.\n"); + return -1; + } + + if (ggh == 0 && fgh == 0) { + *gain_db = 0; + } else if (ggh == 1) { + switch (fgh) + { + case 0: + *gain_db = 6; + break; + case 2: + *gain_db = 12; + break; + case 3: + *gain_db = 18; + break; + default: + { + printf("Read a undefined FGH value (%d).\n", fgh); + return -1; + } + } + } + + return 0; +} + +static int set_auto_exposure(sensor_t *sensor, int enable, int exposure_us) +{ + if (enable) { + is_ae_enabled = true; + return 0; + } else { + is_ae_enabled = false; + return set_exposure(sensor, exposure_us, false); + } +} + +static int get_exposure_us(sensor_t *sensor, int *exposure_us) { + int ret = get_exposure(sensor); + if (ret >= 0) + { + *exposure_us = ret; + return 0; + } + return ret; +} + +static int set_auto_whitebal(sensor_t *sensor, int enable, float r_gain_db, float g_gain_db, float b_gain_db) +{ + return 0; +} + +static int get_rgb_gain_db(sensor_t *sensor, float *r_gain_db, float *g_gain_db, float *b_gain_db) +{ + return 0; +} + +static int set_hmirror(sensor_t *sensor, int enable) +{ + int ret; + uint8_t val; + ret = read_regs_w_bank(BANK_0, REG_CMD_HSYNC_INV, &val, 1); + if (ret) { + printf("Failed to read REG_CMD_HSYNC_INV.\n"); + return -1; + } + + val = enable==1?val|(0x01):val&~(0x01); + + ret = write_regs_w_bank(BANK_0, REG_CMD_HSYNC_INV, &val, 1); + ret = write_regs_w_bank(BANK_1, REG_ISP_UPDATE, &val, 1); + if (ret) { + printf("Failed to write REG_CMD_HSYNC_INV.\n"); + } + return ret; +} +static int set_vflip(sensor_t *sensor, int enable) +{ + int ret; + uint8_t val; + ret = read_regs_w_bank(BANK_0, REG_CMD_VSYNC_INV, &val, 1); + if (ret) { + printf("Failed to read REG_CMD_VSYNC_INV.\n"); + return -1; + } + + val = enable==1?val|(0x01<<1):val&~(0x01<<1); + + ret = write_regs_w_bank(BANK_0, REG_CMD_VSYNC_INV, &val, 1); + ret = write_regs_w_bank(BANK_1, REG_ISP_UPDATE, &val, 1); + if (ret) { + printf("Failed to write REG_CMD_VSYNC_INV.\n"); + } + return ret; +} +static int set_lens_correction(sensor_t *sensor, int enable, int radi, int coef) +{ + return 0; +} +static int reset(sensor_t *sensor) +{ + int ret; + bank_cache = -1; + exp_us_cache = -1; + +#ifdef DEBUG + uint8_t part_id_l = 0, part_id_h = 0; + read_regs_w_bank(0, 0x00, &part_id_l, 1); + read_regs_w_bank(0, 0x01, &part_id_h, 1); + printf("Part ID 0x%x 0x%x\n", part_id_l, part_id_h); + printf("init_res: %d\n", init_res); +#endif + + // Re-init sensor every time. + init_sensor(sensor); + + // Fetch default R_Frame_Time + uint8_t buff[3] = {}; + ret = read_regs_w_bank(BANK_0, REG_FRAME_TIME_L, buff, 3); + if (ret) { + printf("Read cmd_expo failed.\n"); + } else { + R_FrameTime = buff[0] + (((uint32_t)buff[1]) << 8) + (((uint32_t)buff[2]) << 16); + } + + // Default Gain 2x + uint8_t val, fgh, ggh; + ret = read_regs_w_bank(BANK_0, REG_FGH, &val, 1); + fgh = (val & ~(3 << 4)); // fgh[5:4] = 0 + ret |= read_regs_w_bank(BANK_0, REG_GGH, &val, 1); + ggh = (val & ~(1 << 7)) | (0x01 << 7); // ggh[7] = 1 + if (ret) { + printf("Failed to read FGH or GGH.\n"); + } else { + write_regs_w_bank(BANK_0, REG_FGH, &fgh, 1); + write_regs_w_bank(BANK_0, REG_GGH, &ggh, 1); + val = 1; + write_regs_w_bank(BANK_1, REG_ISP_UPDATE, &val, 1); + } + return 0; +} + +static int paj6100_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) +{ + int res = sensor_snapshot(sensor, image, flags); + if (res == 0) + { + l_total = 0; + int iml = image->h * image->w; + for (int i=0; idata[i]; + // PAJ6100 doesn't support HW auto-exposure, + // we provide a software implementation. + auto_exposure(sensor); + } + + return res; +} + +int paj6100_init(sensor_t *sensor) +{ + // Initialize sensor structure. + sensor->gs_bpp = 1; + sensor->reset = reset; + sensor->sleep = sleep; + sensor->read_reg = read_reg; + sensor->write_reg = write_reg; + sensor->set_pixformat = set_pixformat; + sensor->set_framesize = set_framesize; + sensor->set_contrast = set_contrast; + sensor->set_brightness = set_brightness; + sensor->set_saturation = set_saturation; + sensor->set_gainceiling = set_gainceiling; + sensor->set_auto_gain = set_auto_gain; + sensor->get_gain_db = get_gain_db; + sensor->set_auto_exposure = set_auto_exposure; + sensor->get_exposure_us = get_exposure_us; + sensor->set_auto_whitebal = set_auto_whitebal; + + sensor->get_rgb_gain_db = get_rgb_gain_db; + sensor->set_hmirror = set_hmirror; + sensor->set_vflip = set_vflip; + sensor->set_special_effect = set_special_effect; + sensor->set_lens_correction = set_lens_correction; + + sensor->snapshot = paj6100_snapshot; + + // 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, 1); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 0); + SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); + + init_sensor(sensor); + + return 0; +} + +bool paj6100_detect(sensor_t *sensor) +{ + int ret = 0; + uint8_t part_id_l, part_id_h; + + DCMI_RESET_HIGH(); + systick_sleep(10); + + if (!pixspi_init()) + { + printf("Initial pixspi failed.\n"); + return false; + } + + ret |= pixspi_regs_read(0x00, &part_id_l, 1); + ret |= pixspi_regs_read(0x01, &part_id_h, 1); +#ifdef DEBUG + printf("Part ID 0x%x 0x%x\n", part_id_l, part_id_h); +#endif + if (ret == 0 && + (part_id_l == 0x00 && part_id_h == 0x61)) + return true; // Got you. + + pixspi_release(); + return false; +} +#endif //(OMV_ENABLE_PAJ6100 == 1) diff --git a/src/omv/sensors/paj6100.h b/src/omv/sensors/paj6100.h new file mode 100644 index 000000000..d8d19529f --- /dev/null +++ b/src/omv/sensors/paj6100.h @@ -0,0 +1,16 @@ +/* + * This file is part of the OpenMV project. + * Copyright (c) 2019 Lake Fu + * This work is licensed under the MIT license, see the file LICENSE for details. + * + * PAJ6100 driver. + * + */ +#ifndef __PAJ6100_H__ +#define __PAJ6100_H__ + +#define PAJ6100_XCLK_FREQ 6000000 + +bool paj6100_detect(sensor_t *sensor); +int paj6100_init(sensor_t *sensor); +#endif diff --git a/src/omv/sensors/paj6100_reg.h b/src/omv/sensors/paj6100_reg.h new file mode 100644 index 000000000..71eaebd4e --- /dev/null +++ b/src/omv/sensors/paj6100_reg.h @@ -0,0 +1,146 @@ +/* + * File: paj6100u6_reg.h + * Created Date: Tuesday, May 25th 2021, 10:45:35 am + * Author: Lake Fu + * ----- + * Last Modified: Sunday May 30th 2021 2:39:45 pm + * Modified By: Lake Fu at + * ----- + * MIT License + * + * Copyright (c) 2021 Pixart Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies + * of the Software, and to permit persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * ----- + * HISTORY: + * Date By Comments + * ---------- --- ---------------------------------------------------------- + */ + +#include + +#define REG_BANK_SWITCH 0x7F + +// ======================================= +#define BANK_0 0x00 +// --------------------------------------- +#define REG_CMD_HSYNC_INV 0X07 // bit7 +#define REG_CMD_VSYNC_INV 0X07 // bit6 + +#define REG_CMD_AAVG_V 0X07 // bit3 +#define REG_CMD_AAVG_H 0X07 // bit2 + +#define REG_ABC_START_LINE 0x0D // bit3:1 + + +#define REG_FGH 0x11 // bit5:4 +#define REG_GGH 0x12 // bit7 + +#define REG_EXP_OFFSET_L 0x18 +#define REG_EXP_OFFSET_H 0x19 +#define REG_CMD_EXPO_L 0x48 +#define REG_CMD_EXPO_H 0x49 +#define REG_CMD_EXPO_2H 0x4A + +#define REG_FRAME_TIME_L 0x7A +#define REG_FRAME_TIME_H 0x7B +#define REG_FRAME_TIME_2H 0x7C +// ======================================= +#define BANK_1 0x01 +// --------------------------------------- +#define REG_ISP_UPDATE 0x00 + +#define REG_CMD_SENSOR_MODE 0X23 // bit7 +#define REG_CMD_LPM_ENH 0x23 // bit6 + +#define REG_CP_WOI_VOFFSET 0x45 +#define REG_ABC_SAMPLE_SIZE 0x46 // bit2:0 + + +// 20180504 +static const uint8_t low_active_R_ABC_Avg_UBx50_T_BLACINV_EnHx1_T_SIG_REFx1[] = { +//address, value + 0x7F, 0x00, + 0x0C, 0x1D, // software reset + 0x7F, 0x00, + 0x07, 0x00, // low active + 0x08, 0x03, + 0x0B, 0x0E, + 0x0D, 0xC5, + 0x0F, 0x32, //R_ABC_Avg_UB=50 + 0x11, 0x41, //R_global=1 + 0x13, 0xD2, + 0x14, 0xFE, + 0x15, 0x00, // R_fg_fast=0 + 0x17, 0x02, //03 + 0x1A, 0x07, + 0x1B, 0x08, + 0x20, 0x00, //R_fast_powerdn_WakeupTime=0 + 0x25, 0x78, + 0x29, 0x28, + 0x2B, 0x06, + 0x2F, 0x0E, + 0x30, 0x0E, + 0x34, 0x0F, + 0x35, 0x0F, + 0x3A, 0x28, + 0x45, 0x17, + 0x46, 0x17, + 0x48, 0x10, //EXP + 0x49, 0x27, //EXP + 0x4A, 0x00, //EXP + 0x4D, 0x0D, + 0x4E, 0x20, + 0x62, 0x12, + 0x64, 0x02, + 0x67, 0x0A, + 0x69, 0x0A, + 0x6C, 0x0B, + 0x6E, 0x0B, + 0x71, 0x0A, + 0x73, 0x1D, + 0x75, 0x1E, + 0x77, 0x0B, + 0x7F, 0x01, + 0x01, 0x14, + 0x02, 0x02, // + 0x04, 0x96, + 0x05, 0x03, + 0x06, 0x46, + 0x0D, 0x9F, //T_BLACINV_EnH=1 + 0x0E, 0x11, //T_SIG_REF=1 + 0x0F, 0x48, + 0x10, 0x10, //T_vcom_lvl=0 + 0x11, 0x00, + 0x12, 0x05, + 0x15, 0x00, + 0x16, 0x01, //schmitt trigger + 0x17, 0x67, + 0x18, 0xD0, //T_vrt_lvl=T_vrb_lvl=2 + 0x21, 0x14, + 0x22, 0x80, // + 0x2F, 0x30, + 0x35, 0x64, + 0x39, 0x03, + 0x3A, 0x03, + 0x46, 0x06, + 0x4A, 0x00, //FX2 + 0x4B, 0x00, //FX2 + 0x00, 0x01, //updated flag +}; \ No newline at end of file