This commit is contained in:
jomjol
2022-01-14 20:18:24 +01:00
parent 2daf6c8b3f
commit e79c86c7b6
86 changed files with 8008 additions and 1803 deletions

View File

@@ -0,0 +1,465 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sccb.h"
#include "gc0308.h"
#include "gc0308_regs.h"
#include "gc0308_settings.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#else
#include "esp_log.h"
static const char *TAG = "gc0308";
#endif
#define H8(v) ((v)>>8)
#define L8(v) ((v)&0xff)
//#define REG_DEBUG_ON
static int read_reg(uint8_t slv_addr, const uint16_t reg)
{
int ret = SCCB_Read(slv_addr, reg);
#ifdef REG_DEBUG_ON
if (ret < 0) {
ESP_LOGE(TAG, "READ REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value)
{
int ret = 0;
#ifndef REG_DEBUG_ON
ret = SCCB_Write(slv_addr, reg, value);
#else
int old_value = read_reg(slv_addr, reg);
if (old_value < 0) {
return old_value;
}
if ((uint8_t)old_value != value) {
ESP_LOGI(TAG, "NEW REG 0x%04x: 0x%02x to 0x%02x", reg, (uint8_t)old_value, value);
ret = SCCB_Write(slv_addr, reg, value);
} else {
ESP_LOGD(TAG, "OLD REG 0x%04x: 0x%02x", reg, (uint8_t)old_value);
ret = SCCB_Write(slv_addr, reg, value);//maybe not?
}
if (ret < 0) {
ESP_LOGE(TAG, "WRITE REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int check_reg_mask(uint8_t slv_addr, uint16_t reg, uint8_t mask)
{
return (read_reg(slv_addr, reg) & mask) == mask;
}
static int set_reg_bits(uint8_t slv_addr, uint16_t reg, uint8_t offset, uint8_t mask, uint8_t value)
{
int ret = 0;
uint8_t c_value, new_value;
ret = read_reg(slv_addr, reg);
if (ret < 0) {
return ret;
}
c_value = ret;
new_value = (c_value & ~(mask << offset)) | ((value & mask) << offset);
ret = write_reg(slv_addr, reg, new_value);
return ret;
}
static int write_regs(uint8_t slv_addr, const uint16_t (*regs)[2])
{
int i = 0, ret = 0;
while (!ret && regs[i][0] != REGLIST_TAIL) {
if (regs[i][0] == REG_DLY) {
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
} else {
ret = write_reg(slv_addr, regs[i][0], regs[i][1]);
}
i++;
}
return ret;
}
static void print_regs(uint8_t slv_addr)
{
#ifdef DEBUG_PRINT_REG
ESP_LOGI(TAG, "REG list look ======================");
for (size_t i = 0xf0; i <= 0xfe; i++) {
ESP_LOGI(TAG, "reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 0 ===");
write_reg(slv_addr, 0xfe, 0x00); // page 0
for (size_t i = 0x03; i <= 0xa2; i++) {
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 3 ===");
write_reg(slv_addr, 0xfe, 0x03); // page 3
for (size_t i = 0x01; i <= 0x43; i++) {
ESP_LOGI(TAG, "p3 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
#endif
}
static int reset(sensor_t *sensor)
{
int ret = 0;
// Software Reset: clear all registers and reset them to their default values
ret = write_reg(sensor->slv_addr, RESET_RELATED, 0xf0);
if (ret) {
ESP_LOGE(TAG, "Software Reset FAILED!");
return ret;
}
vTaskDelay(100 / portTICK_PERIOD_MS);
ret = write_regs(sensor->slv_addr, gc0308_sensor_default_regs);
if (ret == 0) {
ESP_LOGD(TAG, "Camera defaults loaded");
vTaskDelay(100 / portTICK_PERIOD_MS);
write_reg(sensor->slv_addr, 0xfe, 0x00);
#ifdef CONFIG_IDF_TARGET_ESP32
set_reg_bits(sensor->slv_addr, 0x28, 4, 0x07, 1); //frequency division for esp32, ensure pclk <= 15MHz
#endif
}
return ret;
}
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
{
int ret = 0;
switch (pixformat) {
case PIXFORMAT_RGB565:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, 0x24, 0, 0x0f, 6); //RGB565
break;
case PIXFORMAT_YUV422:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, 0x24, 0, 0x0f, 2); //yuv422 Y Cb Y Cr
break;
default:
ESP_LOGW(TAG, "unsupport format");
ret = -1;
break;
}
if (ret == 0) {
sensor->pixformat = pixformat;
ESP_LOGD(TAG, "Set pixformat to: %u", pixformat);
}
return ret;
}
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
int ret = 0;
if (framesize > FRAMESIZE_VGA) {
ESP_LOGW(TAG, "Invalid framesize: %u", framesize);
framesize = FRAMESIZE_VGA;
}
sensor->status.framesize = framesize;
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
uint16_t row_s = (resolution[FRAMESIZE_VGA].height - h) / 2;
uint16_t col_s = (resolution[FRAMESIZE_VGA].width - w) / 2;
#if CONFIG_GC_SENSOR_SUBSAMPLE_MODE
struct subsample_cfg {
uint16_t ratio_numerator;
uint16_t ratio_denominator;
uint8_t reg0x54;
uint8_t reg0x56;
uint8_t reg0x57;
uint8_t reg0x58;
uint8_t reg0x59;
};
const struct subsample_cfg subsample_cfgs[] = { // define some subsample ratio
{84, 420, 0x55, 0x00, 0x00, 0x00, 0x00}, //1/5
{105, 420, 0x44, 0x00, 0x00, 0x00, 0x00},//1/4
{140, 420, 0x33, 0x00, 0x00, 0x00, 0x00},//1/3
{210, 420, 0x22, 0x00, 0x00, 0x00, 0x00},//1/2
{240, 420, 0x77, 0x02, 0x46, 0x02, 0x46},//4/7
{252, 420, 0x55, 0x02, 0x04, 0x02, 0x04},//3/5
{280, 420, 0x33, 0x02, 0x00, 0x02, 0x00},//2/3
{420, 420, 0x11, 0x00, 0x00, 0x00, 0x00},//1/1
};
uint16_t win_w = 640;
uint16_t win_h = 480;
const struct subsample_cfg *cfg = NULL;
/**
* Strategy: try to keep the maximum perspective
*/
for (size_t i = 0; i < sizeof(subsample_cfgs) / sizeof(struct subsample_cfg); i++) {
cfg = &subsample_cfgs[i];
if ((win_w * cfg->ratio_numerator / cfg->ratio_denominator >= w) && (win_h * cfg->ratio_numerator / cfg->ratio_denominator >= h)) {
win_w = w * cfg->ratio_denominator / cfg->ratio_numerator;
win_h = h * cfg->ratio_denominator / cfg->ratio_numerator;
row_s = (resolution[FRAMESIZE_VGA].height - win_h) / 2;
col_s = (resolution[FRAMESIZE_VGA].width - win_w) / 2;
ESP_LOGI(TAG, "subsample win:%dx%d, ratio:%f", win_w, win_h, (float)cfg->ratio_numerator / (float)cfg->ratio_denominator);
break;
}
}
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, 0x05, H8(row_s));
write_reg(sensor->slv_addr, 0x06, L8(row_s));
write_reg(sensor->slv_addr, 0x07, H8(col_s));
write_reg(sensor->slv_addr, 0x08, L8(col_s));
write_reg(sensor->slv_addr, 0x09, H8(win_h + 8));
write_reg(sensor->slv_addr, 0x0a, L8(win_h + 8));
write_reg(sensor->slv_addr, 0x0b, H8(win_w + 8));
write_reg(sensor->slv_addr, 0x0c, L8(win_w + 8));
write_reg(sensor->slv_addr, 0xfe, 0x01);
set_reg_bits(sensor->slv_addr, 0x53, 7, 0x01, 1);
set_reg_bits(sensor->slv_addr, 0x55, 0, 0x01, 1);
write_reg(sensor->slv_addr, 0x54, cfg->reg0x54);
write_reg(sensor->slv_addr, 0x56, cfg->reg0x56);
write_reg(sensor->slv_addr, 0x57, cfg->reg0x57);
write_reg(sensor->slv_addr, 0x58, cfg->reg0x58);
write_reg(sensor->slv_addr, 0x59, cfg->reg0x59);
write_reg(sensor->slv_addr, 0xfe, 0x00);
#elif CONFIG_GC_SENSOR_WINDOWING_MODE
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, 0xf7, col_s / 4);
write_reg(sensor->slv_addr, 0xf8, row_s / 4);
write_reg(sensor->slv_addr, 0xf9, (col_s + h) / 4);
write_reg(sensor->slv_addr, 0xfa, (row_s + w) / 4);
write_reg(sensor->slv_addr, 0x05, H8(row_s));
write_reg(sensor->slv_addr, 0x06, L8(row_s));
write_reg(sensor->slv_addr, 0x07, H8(col_s));
write_reg(sensor->slv_addr, 0x08, L8(col_s));
write_reg(sensor->slv_addr, 0x09, H8(h + 8));
write_reg(sensor->slv_addr, 0x0a, L8(h + 8));
write_reg(sensor->slv_addr, 0x0b, H8(w + 8));
write_reg(sensor->slv_addr, 0x0c, L8(w + 8));
#endif
if (ret == 0) {
ESP_LOGD(TAG, "Set framesize to: %ux%u", w, h);
}
return 0;
}
static int set_contrast(sensor_t *sensor, int contrast)
{
if (contrast != 0) {
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, 0xb3, contrast);
}
return 0;
}
static int set_global_gain(sensor_t *sensor, int gain_level)
{
if (gain_level != 0) {
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, 0x50, gain_level);
}
return 0;
}
static int set_hmirror(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.hmirror = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, 0x14, 0, 0x01, enable != 0);
if (ret == 0) {
ESP_LOGD(TAG, "Set h-mirror to: %d", enable);
}
return ret;
}
static int set_vflip(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.vflip = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, 0x14, 1, 0x01, enable != 0);
if (ret == 0) {
ESP_LOGD(TAG, "Set v-flip to: %d", enable);
}
return ret;
}
static int set_colorbar(sensor_t *sensor, int enable)
{
int ret = 0;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, 0x2e, 0, 0x01, enable);
if (ret == 0) {
sensor->status.colorbar = enable;
ESP_LOGD(TAG, "Set colorbar to: %d", enable);
}
return ret;
}
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret > 0) {
ret &= mask;
}
return ret;
}
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret < 0) {
return ret;
}
value = (ret & ~mask) | (value & mask);
if (mask > 0xFF) {
} else {
ret = write_reg(sensor->slv_addr, reg, value);
}
return ret;
}
static int init_status(sensor_t *sensor)
{
write_reg(sensor->slv_addr, 0xfe, 0x00);
sensor->status.brightness = 0;
sensor->status.contrast = 0;
sensor->status.saturation = 0;
sensor->status.sharpness = 0;
sensor->status.denoise = 0;
sensor->status.ae_level = 0;
sensor->status.gainceiling = 0;
sensor->status.awb = 0;
sensor->status.dcw = 0;
sensor->status.agc = 0;
sensor->status.aec = 0;
sensor->status.hmirror = check_reg_mask(sensor->slv_addr, 0x14, 0x01);
sensor->status.vflip = check_reg_mask(sensor->slv_addr, 0x14, 0x02);
sensor->status.colorbar = 0;
sensor->status.bpc = 0;
sensor->status.wpc = 0;
sensor->status.raw_gma = 0;
sensor->status.lenc = 0;
sensor->status.quality = 0;
sensor->status.special_effect = 0;
sensor->status.wb_mode = 0;
sensor->status.awb_gain = 0;
sensor->status.agc_gain = 0;
sensor->status.aec_value = 0;
sensor->status.aec2 = 0;
print_regs(sensor->slv_addr);
return 0;
}
static int set_dummy(sensor_t *sensor, int val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
int gc0308_detect(int slv_addr, sensor_id_t *id)
{
if (GC0308_SCCB_ADDR == slv_addr) {
write_reg(slv_addr, 0xfe, 0x00);
uint8_t PID = SCCB_Read(slv_addr, 0x00);
if (GC0308_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int gc0308_init(sensor_t *sensor)
{
sensor->init_status = init_status;
sensor->reset = reset;
sensor->set_pixformat = set_pixformat;
sensor->set_framesize = set_framesize;
sensor->set_contrast = set_contrast;
sensor->set_brightness = set_dummy;
sensor->set_saturation = set_dummy;
sensor->set_sharpness = set_dummy;
sensor->set_denoise = set_dummy;
sensor->set_gainceiling = set_gainceiling_dummy;
sensor->set_quality = set_dummy;
sensor->set_colorbar = set_colorbar;
sensor->set_whitebal = set_dummy;
sensor->set_gain_ctrl = set_global_gain;
sensor->set_exposure_ctrl = set_dummy;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_aec2 = set_dummy;
sensor->set_awb_gain = set_dummy;
sensor->set_agc_gain = set_dummy;
sensor->set_aec_value = set_dummy;
sensor->set_special_effect = set_dummy;
sensor->set_wb_mode = set_dummy;
sensor->set_ae_level = set_dummy;
sensor->set_dcw = set_dummy;
sensor->set_bpc = set_dummy;
sensor->set_wpc = set_dummy;
sensor->set_raw_gma = set_dummy;
sensor->set_lenc = set_dummy;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_res_raw = NULL;
sensor->set_pll = NULL;
sensor->set_xclk = NULL;
ESP_LOGD(TAG, "GC0308 Attached");
return 0;
}

View File

@@ -0,0 +1,391 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sccb.h"
#include "gc032a.h"
#include "gc032a_regs.h"
#include "gc032a_settings.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#else
#include "esp_log.h"
static const char *TAG = "gc032a";
#endif
#define H8(v) ((v)>>8)
#define L8(v) ((v)&0xff)
//#define REG_DEBUG_ON
static int read_reg(uint8_t slv_addr, const uint16_t reg)
{
int ret = SCCB_Read(slv_addr, reg);
#ifdef REG_DEBUG_ON
if (ret < 0) {
ESP_LOGE(TAG, "READ REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value)
{
int ret = 0;
#ifndef REG_DEBUG_ON
ret = SCCB_Write(slv_addr, reg, value);
#else
int old_value = read_reg(slv_addr, reg);
if (old_value < 0) {
return old_value;
}
if ((uint8_t)old_value != value) {
ESP_LOGI(TAG, "NEW REG 0x%04x: 0x%02x to 0x%02x", reg, (uint8_t)old_value, value);
ret = SCCB_Write(slv_addr, reg, value);
} else {
ESP_LOGD(TAG, "OLD REG 0x%04x: 0x%02x", reg, (uint8_t)old_value);
ret = SCCB_Write(slv_addr, reg, value);//maybe not?
}
if (ret < 0) {
ESP_LOGE(TAG, "WRITE REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int check_reg_mask(uint8_t slv_addr, uint16_t reg, uint8_t mask)
{
return (read_reg(slv_addr, reg) & mask) == mask;
}
static void print_regs(uint8_t slv_addr)
{
#ifdef DEBUG_PRINT_REG
vTaskDelay(pdMS_TO_TICKS(100));
ESP_LOGI(TAG, "REG list look ======================");
for (size_t i = 0xf0; i <= 0xfe; i++) {
ESP_LOGI(TAG, "reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 0 ===");
write_reg(slv_addr, 0xfe, 0x00); // page 0
for (size_t i = 0x03; i <= 0x24; i++) {
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
for (size_t i = 0x40; i <= 0x95; i++) {
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 3 ===");
write_reg(slv_addr, 0xfe, 0x03); // page 3
for (size_t i = 0x01; i <= 0x43; i++) {
ESP_LOGI(TAG, "p3 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
#endif
}
static int set_reg_bits(uint8_t slv_addr, uint16_t reg, uint8_t offset, uint8_t mask, uint8_t value)
{
int ret = 0;
uint8_t c_value, new_value;
ret = read_reg(slv_addr, reg);
if (ret < 0) {
return ret;
}
c_value = ret;
new_value = (c_value & ~(mask << offset)) | ((value & mask) << offset);
ret = write_reg(slv_addr, reg, new_value);
return ret;
}
static int write_regs(uint8_t slv_addr, const uint16_t (*regs)[2])
{
int i = 0, ret = 0;
while (!ret && regs[i][0] != REGLIST_TAIL) {
if (regs[i][0] == REG_DLY) {
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
} else {
ret = write_reg(slv_addr, regs[i][0], regs[i][1]);
}
i++;
}
return ret;
}
static int reset(sensor_t *sensor)
{
int ret;
// Software Reset: clear all registers and reset them to their default values
ret = write_reg(sensor->slv_addr, RESET_RELATED, 0xf0);
if (ret) {
ESP_LOGE(TAG, "Software Reset FAILED!");
return ret;
}
vTaskDelay(100 / portTICK_PERIOD_MS);
ret = write_regs(sensor->slv_addr, gc032a_default_regs);
if (ret == 0) {
ESP_LOGD(TAG, "Camera defaults loaded");
vTaskDelay(100 / portTICK_PERIOD_MS);
write_reg(sensor->slv_addr, 0xfe, 0x00);
set_reg_bits(sensor->slv_addr, 0xf7, 1, 0x01, 1); // PLL_mode1:div2en
set_reg_bits(sensor->slv_addr, 0xf7, 7, 0x01, 1); // PLL_mode1:dvp mode
set_reg_bits(sensor->slv_addr, 0xf8, 0, 0x3f, 8); //PLL_mode2 :divx4
set_reg_bits(sensor->slv_addr, 0xfa, 4, 0x0f, 2); //vlk div mode :divide_by
}
return ret;
}
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
{
int ret = 0;
switch (pixformat) {
case PIXFORMAT_RGB565:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, 0x44, 0, 0x1f, 6); //RGB565
break;
case PIXFORMAT_YUV422:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, 0x44, 0, 0x1f, 3);
break;
default:
ESP_LOGW(TAG, "unsupport format");
ret = -1;
break;
}
if (ret == 0) {
sensor->pixformat = pixformat;
ESP_LOGD(TAG, "Set pixformat to: %u", pixformat);
}
return ret;
}
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
ESP_LOGI(TAG, "set_framesize");
int ret = 0;
if (framesize > FRAMESIZE_VGA) {
ESP_LOGW(TAG, "Invalid framesize: %u", framesize);
framesize = FRAMESIZE_VGA;
}
sensor->status.framesize = framesize;
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
uint16_t row_s = (resolution[FRAMESIZE_VGA].height - h) / 2;
uint16_t col_s = (resolution[FRAMESIZE_VGA].width - w) / 2;
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, P0_ROW_START_HIGH, H8(row_s)); // Row_start[8]
write_reg(sensor->slv_addr, P0_ROW_START_LOW, L8(row_s)); // Row_start[7:0]
write_reg(sensor->slv_addr, P0_COLUMN_START_HIGH, H8(col_s)); // Column_start[9:8]
write_reg(sensor->slv_addr, P0_COLUMN_START_LOW, L8(col_s)); // Column_start[7:0]
write_reg(sensor->slv_addr, P0_WINDOW_HEIGHT_HIGH, H8(h + 8)); //window_height [8]
write_reg(sensor->slv_addr, P0_WINDOW_HEIGHT_LOW, L8(h + 8)); //window_height [7:0]
write_reg(sensor->slv_addr, P0_WINDOW_WIDTH_HIGH, H8(w + 8)); //window_width [9:8]
write_reg(sensor->slv_addr, P0_WINDOW_WIDTH_LOW, L8(w + 8)); //window_width [7:0]
write_reg(sensor->slv_addr, P0_WIN_MODE, 0x01);
write_reg(sensor->slv_addr, P0_OUT_WIN_HEIGHT_HIGH, H8(h));
write_reg(sensor->slv_addr, P0_OUT_WIN_HEIGHT_LOW, L8(h));
write_reg(sensor->slv_addr, P0_OUT_WIN_WIDTH_HIGH, H8(w));
write_reg(sensor->slv_addr, P0_OUT_WIN_WIDTH_LOW, L8(w));
if (ret == 0) {
ESP_LOGD(TAG, "Set framesize to: %ux%u", w, h);
}
print_regs(sensor->slv_addr);
return ret;
}
static int set_hmirror(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.hmirror = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, P0_CISCTL_MODE1, 0, 0x01, enable);
if (ret == 0) {
ESP_LOGD(TAG, "Set h-mirror to: %d", enable);
}
return ret;
}
static int set_vflip(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.vflip = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, P0_CISCTL_MODE1, 1, 0x01, enable);
if (ret == 0) {
ESP_LOGD(TAG, "Set v-flip to: %d", enable);
}
return ret;
}
static int set_colorbar(sensor_t *sensor, int enable)
{
int ret = 0;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, P0_DEBUG_MODE2, 3, 0x01, enable);
if (ret == 0) {
sensor->status.colorbar = enable;
ESP_LOGD(TAG, "Set colorbar to: %d", enable);
}
return ret;
}
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret > 0) {
ret &= mask;
}
return ret;
}
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret < 0) {
return ret;
}
value = (ret & ~mask) | (value & mask);
if (mask > 0xFF) {
} else {
ret = write_reg(sensor->slv_addr, reg, value);
}
return ret;
}
static int init_status(sensor_t *sensor)
{
write_reg(sensor->slv_addr, 0xfe, 0x00);
sensor->status.brightness = 0;
sensor->status.contrast = 0;
sensor->status.saturation = 0;
sensor->status.sharpness = 0;
sensor->status.denoise = 0;
sensor->status.ae_level = 0;
sensor->status.gainceiling = 0;
sensor->status.awb = 0;
sensor->status.dcw = 0;
sensor->status.agc = 0;
sensor->status.aec = 0;
sensor->status.hmirror = check_reg_mask(sensor->slv_addr, P0_CISCTL_MODE1, 0x01);
sensor->status.vflip = check_reg_mask(sensor->slv_addr, P0_CISCTL_MODE1, 0x02);
sensor->status.colorbar = 0;
sensor->status.bpc = 0;
sensor->status.wpc = 0;
sensor->status.raw_gma = 0;
sensor->status.lenc = 0;
sensor->status.quality = 0;
sensor->status.special_effect = 0;
sensor->status.wb_mode = 0;
sensor->status.awb_gain = 0;
sensor->status.agc_gain = 0;
sensor->status.aec_value = 0;
sensor->status.aec2 = 0;
return 0;
}
static int set_dummy(sensor_t *sensor, int val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
int gc032a_detect(int slv_addr, sensor_id_t *id)
{
if (GC032A_SCCB_ADDR == slv_addr) {
uint8_t MIDL = SCCB_Read(slv_addr, SENSOR_ID_LOW);
uint8_t MIDH = SCCB_Read(slv_addr, SENSOR_ID_HIGH);
uint16_t PID = MIDH << 8 | MIDL;
if (GC032A_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int gc032a_init(sensor_t *sensor)
{
sensor->init_status = init_status;
sensor->reset = reset;
sensor->set_pixformat = set_pixformat;
sensor->set_framesize = set_framesize;
sensor->set_contrast = set_dummy;
sensor->set_brightness = set_dummy;
sensor->set_saturation = set_dummy;
sensor->set_sharpness = set_dummy;
sensor->set_denoise = set_dummy;
sensor->set_gainceiling = set_gainceiling_dummy;
sensor->set_quality = set_dummy;
sensor->set_colorbar = set_colorbar;
sensor->set_whitebal = set_dummy;
sensor->set_gain_ctrl = set_dummy;
sensor->set_exposure_ctrl = set_dummy;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_aec2 = set_dummy;
sensor->set_awb_gain = set_dummy;
sensor->set_agc_gain = set_dummy;
sensor->set_aec_value = set_dummy;
sensor->set_special_effect = set_dummy;
sensor->set_wb_mode = set_dummy;
sensor->set_ae_level = set_dummy;
sensor->set_dcw = set_dummy;
sensor->set_bpc = set_dummy;
sensor->set_wpc = set_dummy;
sensor->set_raw_gma = set_dummy;
sensor->set_lenc = set_dummy;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_res_raw = NULL;
sensor->set_pll = NULL;
sensor->set_xclk = NULL;
ESP_LOGD(TAG, "GC032A Attached");
return 0;
}

View File

@@ -0,0 +1,475 @@
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sccb.h"
#include "gc2145.h"
#include "gc2145_regs.h"
#include "gc2145_settings.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
#else
#include "esp_log.h"
static const char *TAG = "gc2145";
#endif
#define H8(v) ((v)>>8)
#define L8(v) ((v)&0xff)
//#define REG_DEBUG_ON
static int read_reg(uint8_t slv_addr, const uint16_t reg)
{
int ret = SCCB_Read(slv_addr, reg);
#ifdef REG_DEBUG_ON
if (ret < 0) {
ESP_LOGE(TAG, "READ REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value)
{
int ret = 0;
#ifndef REG_DEBUG_ON
ret = SCCB_Write(slv_addr, reg, value);
#else
int old_value = read_reg(slv_addr, reg);
if (old_value < 0) {
return old_value;
}
if ((uint8_t)old_value != value) {
ESP_LOGI(TAG, "NEW REG 0x%04x: 0x%02x to 0x%02x", reg, (uint8_t)old_value, value);
ret = SCCB_Write(slv_addr, reg, value);
} else {
ESP_LOGD(TAG, "OLD REG 0x%04x: 0x%02x", reg, (uint8_t)old_value);
ret = SCCB_Write(slv_addr, reg, value);//maybe not?
}
if (ret < 0) {
ESP_LOGE(TAG, "WRITE REG 0x%04x FAILED: %d", reg, ret);
}
#endif
return ret;
}
static int check_reg_mask(uint8_t slv_addr, uint16_t reg, uint8_t mask)
{
return (read_reg(slv_addr, reg) & mask) == mask;
}
static int set_reg_bits(uint8_t slv_addr, uint16_t reg, uint8_t offset, uint8_t mask, uint8_t value)
{
int ret = 0;
uint8_t c_value, new_value;
ret = read_reg(slv_addr, reg);
if (ret < 0) {
return ret;
}
c_value = ret;
new_value = (c_value & ~(mask << offset)) | ((value & mask) << offset);
ret = write_reg(slv_addr, reg, new_value);
return ret;
}
static int write_regs(uint8_t slv_addr, const uint16_t (*regs)[2])
{
int i = 0, ret = 0;
while (!ret && regs[i][0] != REGLIST_TAIL) {
if (regs[i][0] == REG_DLY) {
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
} else {
ret = write_reg(slv_addr, regs[i][0], regs[i][1]);
}
i++;
}
return ret;
}
static void print_regs(uint8_t slv_addr)
{
#ifdef DEBUG_PRINT_REG
vTaskDelay(pdMS_TO_TICKS(100));
ESP_LOGI(TAG, "REG list look ======================");
for (size_t i = 0xf0; i <= 0xfe; i++) {
ESP_LOGI(TAG, "reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 0 ===");
write_reg(slv_addr, 0xfe, 0x00); // page 0
for (size_t i = 0x03; i <= 0x24; i++) {
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
for (size_t i = 0x80; i <= 0xa2; i++) {
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
ESP_LOGI(TAG, "\npage 3 ===");
write_reg(slv_addr, 0xfe, 0x03); // page 3
for (size_t i = 0x01; i <= 0x43; i++) {
ESP_LOGI(TAG, "p3 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
}
#endif
}
static int reset(sensor_t *sensor)
{
int ret = 0;
// Software Reset: clear all registers and reset them to their default values
ret = write_reg(sensor->slv_addr, RESET_RELATED, 0xe0);
if (ret) {
ESP_LOGE(TAG, "Software Reset FAILED!");
return ret;
}
vTaskDelay(100 / portTICK_PERIOD_MS);
ret = write_regs(sensor->slv_addr, gc2145_default_init_regs);
if (ret == 0) {
ESP_LOGD(TAG, "Camera defaults loaded");
vTaskDelay(100 / portTICK_PERIOD_MS);
#ifdef CONFIG_IDF_TARGET_ESP32
write_reg(sensor->slv_addr, 0xfe, 0x00);
//ensure pclk <= 15MHz for esp32
set_reg_bits(sensor->slv_addr, 0xf8, 0, 0x3f, 2); // divx4
set_reg_bits(sensor->slv_addr, 0xfa, 4, 0x0f, 2); // divide_by
#endif
}
return ret;
}
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
{
int ret = 0;
switch (pixformat) {
case PIXFORMAT_RGB565:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, P0_OUTPUT_FORMAT, 0, 0x1f, 6); //RGB565
break;
case PIXFORMAT_YUV422:
write_reg(sensor->slv_addr, 0xfe, 0x00);
ret = set_reg_bits(sensor->slv_addr, P0_OUTPUT_FORMAT, 0, 0x1f, 2); //yuv422
break;
default:
ESP_LOGW(TAG, "unsupport format");
ret = -1;
break;
}
if (ret == 0) {
sensor->pixformat = pixformat;
ESP_LOGD(TAG, "Set pixformat to: %u", pixformat);
}
return ret;
}
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
int ret = 0;
if (framesize > FRAMESIZE_UXGA) {
ESP_LOGW(TAG, "Invalid framesize: %u", framesize);
framesize = FRAMESIZE_UXGA;
}
sensor->status.framesize = framesize;
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
uint16_t row_s = (resolution[FRAMESIZE_UXGA].height - h) / 2;
uint16_t col_s = (resolution[FRAMESIZE_UXGA].width - w) / 2;
#if CONFIG_GC_SENSOR_SUBSAMPLE_MODE
struct subsample_cfg {
uint16_t ratio_numerator;
uint16_t ratio_denominator;
uint8_t reg0x99;
uint8_t reg0x9b;
uint8_t reg0x9c;
uint8_t reg0x9d;
uint8_t reg0x9e;
uint8_t reg0x9f;
uint8_t reg0xa0;
uint8_t reg0xa1;
uint8_t reg0xa2;
};
const struct subsample_cfg subsample_cfgs[] = { // define some subsample ratio
// {60, 420, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //1/7 // A smaller ratio brings a larger view, but it reduces the frame rate
// {84, 420, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, //1/5
// {105, 420, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//1/4
{140, 420, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//1/3
{210, 420, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//1/2
{240, 420, 0x77, 0x02, 0x46, 0x02, 0x46, 0x02, 0x46, 0x02, 0x46},//4/7
{252, 420, 0x55, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04, 0x02, 0x04},//3/5
{280, 420, 0x33, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00},//2/3
{420, 420, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//1/1
};
uint16_t win_w = resolution[FRAMESIZE_UXGA].width;
uint16_t win_h = resolution[FRAMESIZE_UXGA].height;
const struct subsample_cfg *cfg = NULL;
/**
* Strategy: try to keep the maximum perspective
*/
uint8_t i = 0;
if (framesize >= FRAMESIZE_QVGA) {
i = 1;
}
for (; i < sizeof(subsample_cfgs) / sizeof(struct subsample_cfg); i++) {
cfg = &subsample_cfgs[i];
if ((win_w * cfg->ratio_numerator / cfg->ratio_denominator >= w) && (win_h * cfg->ratio_numerator / cfg->ratio_denominator >= h)) {
win_w = w * cfg->ratio_denominator / cfg->ratio_numerator;
win_h = h * cfg->ratio_denominator / cfg->ratio_numerator;
row_s = (resolution[FRAMESIZE_UXGA].height - win_h) / 2;
col_s = (resolution[FRAMESIZE_UXGA].width - win_w) / 2;
ESP_LOGI(TAG, "subsample win:%dx%d, ratio:%f", win_w, win_h, (float)cfg->ratio_numerator / (float)cfg->ratio_denominator);
break;
}
}
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, P0_CROP_ENABLE, 0x01);
write_reg(sensor->slv_addr, 0x09, H8(row_s));
write_reg(sensor->slv_addr, 0x0a, L8(row_s));
write_reg(sensor->slv_addr, 0x0b, H8(col_s));
write_reg(sensor->slv_addr, 0x0c, L8(col_s));
write_reg(sensor->slv_addr, 0x0d, H8(win_h + 8));
write_reg(sensor->slv_addr, 0x0e, L8(win_h + 8));
write_reg(sensor->slv_addr, 0x0f, H8(win_w + 16));
write_reg(sensor->slv_addr, 0x10, L8(win_w + 16));
write_reg(sensor->slv_addr, 0x99, cfg->reg0x99);
write_reg(sensor->slv_addr, 0x9b, cfg->reg0x9b);
write_reg(sensor->slv_addr, 0x9c, cfg->reg0x9c);
write_reg(sensor->slv_addr, 0x9d, cfg->reg0x9d);
write_reg(sensor->slv_addr, 0x9e, cfg->reg0x9e);
write_reg(sensor->slv_addr, 0x9f, cfg->reg0x9f);
write_reg(sensor->slv_addr, 0xa0, cfg->reg0xa0);
write_reg(sensor->slv_addr, 0xa1, cfg->reg0xa1);
write_reg(sensor->slv_addr, 0xa2, cfg->reg0xa2);
write_reg(sensor->slv_addr, 0x95, H8(h));
write_reg(sensor->slv_addr, 0x96, L8(h));
write_reg(sensor->slv_addr, 0x97, H8(w));
write_reg(sensor->slv_addr, 0x98, L8(w));
#elif CONFIG_GC_SENSOR_WINDOWING_MODE
write_reg(sensor->slv_addr, 0xfe, 0x00);
write_reg(sensor->slv_addr, P0_CROP_ENABLE, 0x01);
// write_reg(sensor->slv_addr, 0xec, col_s / 8); //measure window
// write_reg(sensor->slv_addr, 0xed, row_s / 8);
// write_reg(sensor->slv_addr, 0xee, (col_s + h) / 8);
// write_reg(sensor->slv_addr, 0xef, (row_s + w) / 8);
write_reg(sensor->slv_addr, 0x09, H8(row_s));
write_reg(sensor->slv_addr, 0x0a, L8(row_s));
write_reg(sensor->slv_addr, 0x0b, H8(col_s));
write_reg(sensor->slv_addr, 0x0c, L8(col_s));
write_reg(sensor->slv_addr, 0x0d, H8(h + 8));
write_reg(sensor->slv_addr, 0x0e, L8(h + 8));
write_reg(sensor->slv_addr, 0x0f, H8(w + 8));
write_reg(sensor->slv_addr, 0x10, L8(w + 8));
write_reg(sensor->slv_addr, 0x95, H8(h));
write_reg(sensor->slv_addr, 0x96, L8(h));
write_reg(sensor->slv_addr, 0x97, H8(w));
write_reg(sensor->slv_addr, 0x98, L8(w));
#endif
if (ret == 0) {
ESP_LOGD(TAG, "Set framesize to: %ux%u", w, h);
}
return ret;
}
static int set_hmirror(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.hmirror = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, P0_ANALOG_MODE1, 0, 0x01, enable != 0);
if (ret == 0) {
ESP_LOGD(TAG, "Set h-mirror to: %d", enable);
}
return ret;
}
static int set_vflip(sensor_t *sensor, int enable)
{
int ret = 0;
sensor->status.vflip = enable;
ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
ret |= set_reg_bits(sensor->slv_addr, P0_ANALOG_MODE1, 1, 0x01, enable != 0);
if (ret == 0) {
ESP_LOGD(TAG, "Set v-flip to: %d", enable);
}
return ret;
}
static int set_colorbar(sensor_t *sensor, int enable)
{
int ret = 0;
// ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
// ret |= set_reg_bits(sensor->slv_addr, P0_DEBUG_MODE3, 3, 0x01, enable);
if (ret == 0) {
sensor->status.colorbar = enable;
ESP_LOGD(TAG, "Set colorbar to: %d", enable);
}
return ret;
}
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret > 0) {
ret &= mask;
}
return ret;
}
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{
int ret = 0;
if (mask > 0xFF) {
ESP_LOGE(TAG, "mask should not more than 0xff");
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if (ret < 0) {
return ret;
}
value = (ret & ~mask) | (value & mask);
if (mask > 0xFF) {
} else {
ret = write_reg(sensor->slv_addr, reg, value);
}
return ret;
}
static int init_status(sensor_t *sensor)
{
write_reg(sensor->slv_addr, 0xfe, 0x00);
sensor->status.brightness = 0;
sensor->status.contrast = 0;
sensor->status.saturation = 0;
sensor->status.sharpness = 0;
sensor->status.denoise = 0;
sensor->status.ae_level = 0;
sensor->status.gainceiling = 0;
sensor->status.awb = 0;
sensor->status.dcw = 0;
sensor->status.agc = 0;
sensor->status.aec = 0;
sensor->status.hmirror = check_reg_mask(sensor->slv_addr, P0_ANALOG_MODE1, 0x01);
sensor->status.vflip = check_reg_mask(sensor->slv_addr, P0_ANALOG_MODE1, 0x02);
sensor->status.colorbar = 0;
sensor->status.bpc = 0;
sensor->status.wpc = 0;
sensor->status.raw_gma = 0;
sensor->status.lenc = 0;
sensor->status.quality = 0;
sensor->status.special_effect = 0;
sensor->status.wb_mode = 0;
sensor->status.awb_gain = 0;
sensor->status.agc_gain = 0;
sensor->status.aec_value = 0;
sensor->status.aec2 = 0;
print_regs(sensor->slv_addr);
return 0;
}
static int set_dummy(sensor_t *sensor, int val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val)
{
ESP_LOGW(TAG, "Unsupported");
return -1;
}
int gc2145_detect(int slv_addr, sensor_id_t *id)
{
if (GC2145_SCCB_ADDR == slv_addr) {
uint8_t MIDL = SCCB_Read(slv_addr, CHIP_ID_LOW);
uint8_t MIDH = SCCB_Read(slv_addr, CHIP_ID_HIGH);
uint16_t PID = MIDH << 8 | MIDL;
if (GC2145_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int gc2145_init(sensor_t *sensor)
{
sensor->init_status = init_status;
sensor->reset = reset;
sensor->set_pixformat = set_pixformat;
sensor->set_framesize = set_framesize;
sensor->set_contrast = set_dummy;
sensor->set_brightness = set_dummy;
sensor->set_saturation = set_dummy;
sensor->set_sharpness = set_dummy;
sensor->set_denoise = set_dummy;
sensor->set_gainceiling = set_gainceiling_dummy;
sensor->set_quality = set_dummy;
sensor->set_colorbar = set_colorbar;
sensor->set_whitebal = set_dummy;
sensor->set_gain_ctrl = set_dummy;
sensor->set_exposure_ctrl = set_dummy;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_aec2 = set_dummy;
sensor->set_awb_gain = set_dummy;
sensor->set_agc_gain = set_dummy;
sensor->set_aec_value = set_dummy;
sensor->set_special_effect = set_dummy;
sensor->set_wb_mode = set_dummy;
sensor->set_ae_level = set_dummy;
sensor->set_dcw = set_dummy;
sensor->set_bpc = set_dummy;
sensor->set_wpc = set_dummy;
sensor->set_raw_gma = set_dummy;
sensor->set_lenc = set_dummy;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_res_raw = NULL;
sensor->set_pll = NULL;
sensor->set_xclk = NULL;
ESP_LOGD(TAG, "GC2145 Attached");
return 0;
}

View File

@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include "sccb.h"
#include "xclk.h"
#include "nt99141.h"
#include "nt99141_regs.h"
#include "nt99141_settings.h"
@@ -144,28 +145,6 @@ static int write_addr_reg(uint8_t slv_addr, const uint16_t reg, uint16_t x_value
#define write_reg_bits(slv_addr, reg, mask, enable) set_reg_bits(slv_addr, reg, 0, mask, enable?mask:0)
static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sys_div, int pll_pre_div, bool pll_root_2x, int pll_seld5, bool pclk_manual, int pclk_div)
{
const int pll_pre_div2x_map[] = { 2, 3, 4, 6 };//values are multiplied by two to avoid floats
const int pll_seld52x_map[] = { 2, 2, 4, 5 };
if (!pll_sys_div) {
pll_sys_div = 1;
}
int pll_pre_div2x = pll_pre_div2x_map[pll_pre_div];
int pll_root_div = pll_root_2x ? 2 : 1;
int pll_seld52x = pll_seld52x_map[pll_seld5];
int VCO = (xclk / 1000) * pll_multiplier * pll_root_div * 2 / pll_pre_div2x;
int PLLCLK = pll_bypass ? (xclk) : (VCO * 1000 * 2 / pll_sys_div / pll_seld52x);
int PCLK = PLLCLK / 2 / ((pclk_manual && pclk_div) ? pclk_div : 1);
int SYSCLK = PLLCLK / 4;
ESP_LOGD(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO * 1000, PLLCLK, SYSCLK, PCLK);
return SYSCLK;
}
static int set_pll(sensor_t *sensor, bool bypass, uint8_t multiplier, uint8_t sys_div, uint8_t pre_div, bool root_2x, uint8_t seld5, bool pclk_manual, uint8_t pclk_div)
{
return -1;
@@ -309,7 +288,7 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
ret = write_regs(sensor->slv_addr, sensor_framesize_VGA);
}
return 0;
return ret;
}
static int set_hmirror(sensor_t *sensor, int enable)
@@ -682,7 +661,6 @@ static int set_brightness(sensor_t *sensor, int level)
{
int ret = 0;
uint8_t value = 0;
bool negative = false;
switch (level) {
case 3:
@@ -699,17 +677,14 @@ static int set_brightness(sensor_t *sensor, int level)
case -1:
value = 0x78;
negative = true;
break;
case -2:
value = 0x70;
negative = true;
break;
case -3:
value = 0x60;
negative = true;
break;
default: // 0
@@ -730,7 +705,6 @@ static int set_contrast(sensor_t *sensor, int level)
{
int ret = 0;
uint8_t value1 = 0, value2 = 0 ;
bool negative = false;
switch (level) {
case 3:
@@ -947,7 +921,6 @@ static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, i
return set_pll(sensor, bypass > 0, multiplier, sys_div, pre_div, root_2x > 0, seld5, pclk_manual > 0, pclk_div);
}
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
static int set_xclk(sensor_t *sensor, int timer, int xclk)
{
int ret = 0;
@@ -961,6 +934,23 @@ static int set_xclk(sensor_t *sensor, int timer, int xclk)
return ret;
}
int nt99141_detect(int slv_addr, sensor_id_t *id)
{
if (NT99141_SCCB_ADDR == slv_addr) {
SCCB_Write16(slv_addr, 0x3008, 0x01);//bank sensor
uint16_t h = SCCB_Read16(slv_addr, 0x3000);
uint16_t l = SCCB_Read16(slv_addr, 0x3001);
uint16_t PID = (h<<8) | l;
if (NT99141_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
static int init_status(sensor_t *sensor)
{
sensor->status.brightness = 0;
@@ -991,7 +981,7 @@ static int init_status(sensor_t *sensor)
return 0;
}
int NT99141_init(sensor_t *sensor)
int nt99141_init(sensor_t *sensor)
{
sensor->reset = reset;
sensor->set_pixformat = set_pixformat;

View File

@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include "sccb.h"
#include "xclk.h"
#include "ov2640.h"
#include "ov2640_regs.h"
#include "ov2640_settings.h"
@@ -149,7 +150,7 @@ static int set_window(sensor_t *sensor, ov2640_sensor_mode_t mode, int offset_x,
{VSIZE, max_y & 0xFF},
{XOFFL, offset_x & 0xFF},
{YOFFL, offset_y & 0xFF},
{VHYX, ((max_y >> 1) & 0X80) | ((offset_y >> 4) & 0X70) | ((max_x >> 5) & 0X08) | ((offset_y >> 8) & 0X07)},
{VHYX, ((max_y >> 1) & 0X80) | ((offset_y >> 4) & 0X70) | ((max_x >> 5) & 0X08) | ((offset_x >> 8) & 0X07)},
{TEST, (max_x >> 2) & 0X80},
{ZMOW, (w)&0xFF},
{ZMOH, (h)&0xFF},
@@ -157,26 +158,40 @@ static int set_window(sensor_t *sensor, ov2640_sensor_mode_t mode, int offset_x,
{0, 0}
};
c.pclk_auto = 0;
c.pclk_div = 8;
c.clk_2x = 0;
c.clk_div = 0;
if(sensor->pixformat != PIXFORMAT_JPEG){
c.pclk_auto = 1;
if (sensor->pixformat == PIXFORMAT_JPEG) {
c.clk_2x = 0;
c.clk_div = 0;
c.pclk_auto = 0;
c.pclk_div = 8;
if(mode == OV2640_MODE_UXGA) {
c.pclk_div = 12;
}
// if (sensor->xclk_freq_hz == 16000000) {
// c.pclk_div = c.pclk_div / 2;
// }
} else {
#if CONFIG_IDF_TARGET_ESP32
c.clk_2x = 0;
#else
c.clk_2x = 1;
#endif
c.clk_div = 7;
c.pclk_auto = 1;
c.pclk_div = 8;
if (mode == OV2640_MODE_CIF) {
c.clk_div = 3;
} else if(mode == OV2640_MODE_UXGA) {
c.pclk_div = 12;
}
}
ESP_LOGI(TAG, "Set PLL: clk_2x: %u, clk_div: %u, pclk_auto: %u, pclk_div: %u", c.clk_2x, c.clk_div, c.pclk_auto, c.pclk_div);
if (mode == OV2640_MODE_CIF) {
regs = ov2640_settings_to_cif;
if(sensor->pixformat != PIXFORMAT_JPEG){
c.clk_div = 3;
}
} else if (mode == OV2640_MODE_SVGA) {
regs = ov2640_settings_to_svga;
} else {
regs = ov2640_settings_to_uxga;
c.pclk_div = 12;
}
WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS);
@@ -480,7 +495,6 @@ static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, i
return -1;
}
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
static int set_xclk(sensor_t *sensor, int timer, int xclk)
{
int ret = 0;
@@ -531,6 +545,24 @@ static int init_status(sensor_t *sensor){
return 0;
}
int ov2640_detect(int slv_addr, sensor_id_t *id)
{
if (OV2640_SCCB_ADDR == slv_addr) {
SCCB_Write(slv_addr, 0xFF, 0x01);//bank sensor
uint16_t PID = SCCB_Read(slv_addr, 0x0A);
if (OV2640_PID == PID) {
id->PID = PID;
id->VER = SCCB_Read(slv_addr, REG_VER);
id->MIDL = SCCB_Read(slv_addr, REG_MIDL);
id->MIDH = SCCB_Read(slv_addr, REG_MIDH);
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int ov2640_init(sensor_t *sensor)
{
sensor->reset = reset;

View File

@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include "sccb.h"
#include "xclk.h"
#include "ov3660.h"
#include "ov3660_regs.h"
#include "ov3660_settings.h"
@@ -142,7 +143,7 @@ static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sy
int PCLK = PLLCLK / 2 / ((pclk_manual && pclk_div)?pclk_div:1);
int SYSCLK = PLLCLK / 4;
ESP_LOGD(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO*1000, PLLCLK, SYSCLK, PCLK);
ESP_LOGI(TAG, "Calculated VCO: %d Hz, PLLCLK: %d Hz, SYSCLK: %d Hz, PCLK: %d Hz", VCO*1000, PLLCLK, SYSCLK, PCLK);
return SYSCLK;
}
@@ -310,13 +311,13 @@ static int set_image_options(sensor_t *sensor)
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
int ret = 0;
framesize_t old_framesize = sensor->status.framesize;
sensor->status.framesize = framesize;
if(framesize > FRAMESIZE_QXGA){
ESP_LOGE(TAG, "Invalid framesize: %u", framesize);
return -1;
ESP_LOGW(TAG, "Invalid framesize: %u", framesize);
framesize = FRAMESIZE_QXGA;
}
framesize_t old_framesize = sensor->status.framesize;
sensor->status.framesize = framesize;
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
aspect_ratio_t ratio = resolution[sensor->status.framesize].aspect_ratio;
@@ -355,7 +356,7 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
}
if (sensor->pixformat == PIXFORMAT_JPEG) {
if (framesize == FRAMESIZE_QXGA) {
if (framesize == FRAMESIZE_QXGA || sensor->xclk_freq_hz == 16000000) {
//40MHz SYSCLK and 10MHz PCLK
ret = set_pll(sensor, false, 24, 1, 3, false, 0, true, 8);
} else {
@@ -363,12 +364,16 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
ret = set_pll(sensor, false, 30, 1, 3, false, 0, true, 10);
}
} else {
if (framesize > FRAMESIZE_CIF) {
//10MHz SYSCLK and 10MHz PCLK (6.19 FPS)
ret = set_pll(sensor, false, 2, 1, 0, false, 0, true, 2);
//tuned for 16MHz XCLK and 8MHz PCLK
if (framesize > FRAMESIZE_HVGA) {
//8MHz SYSCLK and 8MHz PCLK (4.44 FPS)
ret = set_pll(sensor, false, 4, 1, 0, false, 2, true, 2);
} else if (framesize >= FRAMESIZE_QVGA) {
//16MHz SYSCLK and 8MHz PCLK (10.25 FPS)
ret = set_pll(sensor, false, 8, 1, 0, false, 2, true, 4);
} else {
//25MHz SYSCLK and 10MHz PCLK (15.45 FPS)
ret = set_pll(sensor, false, 5, 1, 0, false, 0, true, 5);
//32MHz SYSCLK and 8MHz PCLK (17.77 FPS)
ret = set_pll(sensor, false, 8, 1, 0, false, 0, true, 8);
}
}
@@ -953,7 +958,6 @@ static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, i
return set_pll(sensor, bypass > 0, multiplier, sys_div, pre_div, root_2x > 0, seld5, pclk_manual > 0, pclk_div);
}
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
static int set_xclk(sensor_t *sensor, int timer, int xclk)
{
int ret = 0;
@@ -992,6 +996,22 @@ static int init_status(sensor_t *sensor)
return 0;
}
int ov3660_detect(int slv_addr, sensor_id_t *id)
{
if (OV3660_SCCB_ADDR == slv_addr) {
uint8_t h = SCCB_Read16(slv_addr, 0x300A);
uint8_t l = SCCB_Read16(slv_addr, 0x300B);
uint16_t PID = (h<<8) | l;
if (OV3660_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int ov3660_init(sensor_t *sensor)
{
sensor->reset = reset;

View File

@@ -10,6 +10,7 @@
#include <stdlib.h>
#include <string.h>
#include "sccb.h"
#include "xclk.h"
#include "ov5640.h"
#include "ov5640_regs.h"
#include "ov5640_settings.h"
@@ -196,7 +197,7 @@ static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sy
unsigned int SYSCLK = PLL_CLK / 4;
ESP_LOGD(TAG, "Calculated XVCLK: %d Hz, REFIN: %u Hz, VCO: %u Hz, PLL_CLK: %u Hz, SYSCLK: %u Hz, PCLK: %u Hz", xclk, REFIN, VCO, PLL_CLK, SYSCLK, PCLK);
ESP_LOGI(TAG, "Calculated XVCLK: %d Hz, REFIN: %u Hz, VCO: %u Hz, PLL_CLK: %u Hz, SYSCLK: %u Hz, PCLK: %u Hz", xclk, REFIN, VCO, PLL_CLK, SYSCLK, PCLK);
return SYSCLK;
}
@@ -209,6 +210,7 @@ static int set_pll(sensor_t *sensor, bool bypass, uint8_t multiplier, uint8_t sy
if(multiplier > 127){
multiplier &= 0xFE;//only even integers above 127
}
ESP_LOGI(TAG, "Set PLL: bypass: %u, multiplier: %u, sys_div: %u, pre_div: %u, root_2x: %u, pclk_root_div: %u, pclk_manual: %u, pclk_div: %u", bypass, multiplier, sys_div, pre_div, root_2x, pclk_root_div, pclk_manual, pclk_div);
calc_sysclk(sensor->xclk_freq_hz, bypass, multiplier, sys_div, pre_div, root_2x, pclk_root_div, pclk_manual, pclk_div);
@@ -432,14 +434,22 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
if (sensor->pixformat == PIXFORMAT_JPEG) {
//10MHz PCLK
uint8_t sys_mul = 200;
if(framesize < FRAMESIZE_QVGA){
if(framesize < FRAMESIZE_QVGA || sensor->xclk_freq_hz == 16000000){
sys_mul = 160;
} else if(framesize < FRAMESIZE_XGA){
sys_mul = 180;
}
ret = set_pll(sensor, false, sys_mul, 4, 2, false, 2, true, 4);
//Set PLL: bypass: 0, multiplier: sys_mul, sys_div: 4, pre_div: 2, root_2x: 0, pclk_root_div: 2, pclk_manual: 1, pclk_div: 4
} else {
ret = set_pll(sensor, false, 10, 1, 1, false, 1, true, 4);
//ret = set_pll(sensor, false, 8, 1, 1, false, 1, true, 4);
if (framesize > FRAMESIZE_HVGA) {
ret = set_pll(sensor, false, 10, 1, 2, false, 1, true, 2);
} else if (framesize >= FRAMESIZE_QVGA) {
ret = set_pll(sensor, false, 8, 1, 1, false, 1, true, 4);
} else {
ret = set_pll(sensor, false, 20, 1, 1, false, 1, true, 8);
}
}
if (ret == 0) {
@@ -1025,7 +1035,6 @@ static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, i
return ret;
}
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
static int set_xclk(sensor_t *sensor, int timer, int xclk)
{
int ret = 0;
@@ -1064,6 +1073,22 @@ static int init_status(sensor_t *sensor)
return 0;
}
int ov5640_detect(int slv_addr, sensor_id_t *id)
{
if (OV5640_SCCB_ADDR == slv_addr) {
uint8_t h = SCCB_Read16(slv_addr, 0x300A);
uint8_t l = SCCB_Read16(slv_addr, 0x300B);
uint16_t PID = (h<<8) | l;
if (OV5640_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int ov5640_init(sensor_t *sensor)
{
sensor->reset = reset;

View File

@@ -45,7 +45,7 @@ static struct regval_list ov7670_default_regs[] = {
{CLKRC, 0x00},
{DBLV, 0x4A},
{COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK},
{COM10, COM10_VSYNC_NEG | COM10_PCLK_FREE},
/* Improve white balance */
{COM4, 0x40},
@@ -393,6 +393,24 @@ static int init_status(sensor_t *sensor)
static int set_dummy(sensor_t *sensor, int val){ return -1; }
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val){ return -1; }
int ov7670_detect(int slv_addr, sensor_id_t *id)
{
if (OV7670_SCCB_ADDR == slv_addr) {
SCCB_Write(slv_addr, 0xFF, 0x01);//bank sensor
uint16_t PID = SCCB_Read(slv_addr, 0x0A);
if (OV7670_PID == PID) {
id->PID = PID;
id->VER = SCCB_Read(slv_addr, REG_VER);
id->MIDL = SCCB_Read(slv_addr, REG_MIDL);
id->MIDH = SCCB_Read(slv_addr, REG_MIDH);
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int ov7670_init(sensor_t *sensor)
{
// Set function pointers

View File

@@ -11,6 +11,7 @@
#include <string.h>
#include <stdio.h>
#include "sccb.h"
#include "xclk.h"
#include "ov7725.h"
#include "ov7725_regs.h"
#include "freertos/FreeRTOS.h"
@@ -58,10 +59,10 @@ static const uint8_t default_regs[][2] = {
{COM8, 0xF0},
{COM6, 0xC5},
{COM9, 0x11},
{COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK
{COM10, COM10_VSYNC_NEG | COM10_PCLK_FREE}, //Invert VSYNC and MASK PCLK
{BDBASE, 0x7F},
{DBSTEP, 0x03},
{AEW, 0x96},
{AEW, 0x75},
{AEB, 0x64},
{VPT, 0xA1},
{EXHCL, 0x00},
@@ -493,7 +494,6 @@ static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val){ return -1
static int set_res_raw(sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning){return -1;}
static int _set_pll(sensor_t *sensor, int bypass, int multiplier, int sys_div, int root_2x, int pre_div, int seld5, int pclk_manual, int pclk_div){return -1;}
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
static int set_xclk(sensor_t *sensor, int timer, int xclk)
{
int ret = 0;
@@ -502,6 +502,24 @@ static int set_xclk(sensor_t *sensor, int timer, int xclk)
return ret;
}
int ov7725_detect(int slv_addr, sensor_id_t *id)
{
if (OV7725_SCCB_ADDR == slv_addr) {
SCCB_Write(slv_addr, 0xFF, 0x01);//bank sensor
uint16_t PID = SCCB_Read(slv_addr, 0x0A);
if (OV7725_PID == PID) {
id->PID = PID;
id->VER = SCCB_Read(slv_addr, REG_VER);
id->MIDL = SCCB_Read(slv_addr, REG_MIDL);
id->MIDH = SCCB_Read(slv_addr, REG_MIDH);
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int ov7725_init(sensor_t *sensor)
{
// Set function pointers

View File

@@ -0,0 +1,31 @@
#pragma once
#include "sensor.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int gc0308_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int gc0308_init(sensor_t *sensor);
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,25 @@
/*
* GC0308 register definitions.
*/
#ifndef __GC0308_REG_REGS_H__
#define __GC0308_REG_REGS_H__
#define RESET_RELATED 0xfe // Bit[7]: Software reset
// Bit[6:5]: NA
// Bit[4]: CISCTL_restart_n
// Bit[3:1]: NA
// Bit[0]: page select
// 0:page0
// 1:page1
// page0:
/**
* @brief register value
*/
#endif // __GC0308_REG_REGS_H__

View File

@@ -0,0 +1,245 @@
#ifndef _GC0308_SETTINGS_H_
#define _GC0308_SETTINGS_H_
#include <stdint.h>
#define REG_DLY 0xffff
#define REGLIST_TAIL 0x0000 /* Array end token */
static const uint16_t gc0308_sensor_default_regs[][2] = {
{0xfe, 0x00},
{0xec, 0x20},
{0x05, 0x00},
{0x06, 0x00},
{0x07, 0x00},
{0x08, 0x00},
{0x09, 0x01},
{0x0a, 0xe8},
{0x0b, 0x02},
{0x0c, 0x88},
{0x0d, 0x02},
{0x0e, 0x02},
{0x10, 0x26},
{0x11, 0x0d},
{0x12, 0x2a},
{0x13, 0x00},
{0x14, 0x11},
{0x15, 0x0a},
{0x16, 0x05},
{0x17, 0x01},
{0x18, 0x44},
{0x19, 0x44},
{0x1a, 0x2a},
{0x1b, 0x00},
{0x1c, 0x49},
{0x1d, 0x9a},
{0x1e, 0x61},
{0x1f, 0x00}, //pad drv <=24MHz, use 0x00 is ok
{0x20, 0x7f},
{0x21, 0xfa},
{0x22, 0x57},
{0x24, 0xa2}, //YCbYCr
{0x25, 0x0f},
{0x26, 0x03}, // 0x01
{0x28, 0x00},
{0x2d, 0x0a},
{0x2f, 0x01},
{0x30, 0xf7},
{0x31, 0x50},
{0x32, 0x00},
{0x33, 0x28},
{0x34, 0x2a},
{0x35, 0x28},
{0x39, 0x04},
{0x3a, 0x20},
{0x3b, 0x20},
{0x3c, 0x00},
{0x3d, 0x00},
{0x3e, 0x00},
{0x3f, 0x00},
{0x50, 0x14}, // 0x14
{0x52, 0x41},
{0x53, 0x80},
{0x54, 0x80},
{0x55, 0x80},
{0x56, 0x80},
{0x8b, 0x20},
{0x8c, 0x20},
{0x8d, 0x20},
{0x8e, 0x14},
{0x8f, 0x10},
{0x90, 0x14},
{0x91, 0x3c},
{0x92, 0x50},
//{0x8b,0x10},
//{0x8c,0x10},
//{0x8d,0x10},
//{0x8e,0x10},
//{0x8f,0x10},
//{0x90,0x10},
//{0x91,0x3c},
//{0x92,0x50},
{0x5d, 0x12},
{0x5e, 0x1a},
{0x5f, 0x24},
{0x60, 0x07},
{0x61, 0x15},
{0x62, 0x08}, // 0x08
{0x64, 0x03}, // 0x03
{0x66, 0xe8},
{0x67, 0x86},
{0x68, 0x82},
{0x69, 0x18},
{0x6a, 0x0f},
{0x6b, 0x00},
{0x6c, 0x5f},
{0x6d, 0x8f},
{0x6e, 0x55},
{0x6f, 0x38},
{0x70, 0x15},
{0x71, 0x33},
{0x72, 0xdc},
{0x73, 0x00},
{0x74, 0x02},
{0x75, 0x3f},
{0x76, 0x02},
{0x77, 0x38}, // 0x47
{0x78, 0x88},
{0x79, 0x81},
{0x7a, 0x81},
{0x7b, 0x22},
{0x7c, 0xff},
{0x93, 0x48}, //color matrix default
{0x94, 0x02},
{0x95, 0x07},
{0x96, 0xe0},
{0x97, 0x40},
{0x98, 0xf0},
{0xb1, 0x40},
{0xb2, 0x40},
{0xb3, 0x40}, //0x40
{0xb6, 0xe0},
{0xbd, 0x38},
{0xbe, 0x36},
{0xd0, 0xCB},
{0xd1, 0x10},
{0xd2, 0x90},
{0xd3, 0x48},
{0xd5, 0xF2},
{0xd6, 0x16},
{0xdb, 0x92},
{0xdc, 0xA5},
{0xdf, 0x23},
{0xd9, 0x00},
{0xda, 0x00},
{0xe0, 0x09},
{0xed, 0x04},
{0xee, 0xa0},
{0xef, 0x40},
{0x80, 0x03},
{0x9F, 0x10},
{0xA0, 0x20},
{0xA1, 0x38},
{0xA2, 0x4e},
{0xA3, 0x63},
{0xA4, 0x76},
{0xA5, 0x87},
{0xA6, 0xa2},
{0xA7, 0xb8},
{0xA8, 0xca},
{0xA9, 0xd8},
{0xAA, 0xe3},
{0xAB, 0xeb},
{0xAC, 0xf0},
{0xAD, 0xF8},
{0xAE, 0xFd},
{0xAF, 0xFF},
{0xc0, 0x00},
{0xc1, 0x10},
{0xc2, 0x1c},
{0xc3, 0x30},
{0xc4, 0x43},
{0xc5, 0x54},
{0xc6, 0x65},
{0xc7, 0x75},
{0xc8, 0x93},
{0xc9, 0xB0},
{0xca, 0xCB},
{0xcb, 0xE6},
{0xcc, 0xFF},
{0xf0, 0x02},
{0xf1, 0x01},
{0xf2, 0x02},
{0xf3, 0x30},
{0xf7, 0x04},
{0xf8, 0x02},
{0xf9, 0x9f},
{0xfa, 0x78},
{0xfe, 0x01},
{0x00, 0xf5},
{0x02, 0x20},
{0x04, 0x10},
{0x05, 0x08},
{0x06, 0x20},
{0x08, 0x0a},
{0x0a, 0xa0},
{0x0b, 0x60},
{0x0c, 0x08},
{0x0e, 0x44},
{0x0f, 0x32},
{0x10, 0x41},
{0x11, 0x37},
{0x12, 0x22},
{0x13, 0x19},
{0x14, 0x44},
{0x15, 0x44},
{0x16, 0xc2},
{0x17, 0xA8},
{0x18, 0x18},
{0x19, 0x50},
{0x1a, 0xd8},
{0x1b, 0xf5},
{0x70, 0x40},
{0x71, 0x58},
{0x72, 0x30},
{0x73, 0x48},
{0x74, 0x20},
{0x75, 0x60},
{0x77, 0x20},
{0x78, 0x32},
{0x30, 0x03},
{0x31, 0x40},
{0x32, 0x10},
{0x33, 0xe0},
{0x34, 0xe0},
{0x35, 0x00},
{0x36, 0x80},
{0x37, 0x00},
{0x38, 0x04},
{0x39, 0x09},
{0x3a, 0x12},
{0x3b, 0x1C},
{0x3c, 0x28},
{0x3d, 0x31},
{0x3e, 0x44},
{0x3f, 0x57},
{0x40, 0x6C},
{0x41, 0x81},
{0x42, 0x94},
{0x43, 0xA7},
{0x44, 0xB8},
{0x45, 0xD6},
{0x46, 0xEE},
{0x47, 0x0d},
{0x62, 0xf7},
{0x63, 0x68},
{0x64, 0xd3},
{0x65, 0xd3},
{0x66, 0x60},
{0xfe, 0x00},
{REGLIST_TAIL, 0x00},
};
#endif

View File

@@ -0,0 +1,31 @@
/*
*
* GC032A driver.
*
*/
#ifndef __GC032A_H__
#define __GC032A_H__
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int gc032a_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int gc032a_init(sensor_t *sensor);
#endif // __GC032A_H__

View File

@@ -0,0 +1,82 @@
/*
* GC032A register definitions.
*/
#ifndef __GC032A_REG_REGS_H__
#define __GC032A_REG_REGS_H__
#define SENSOR_ID_HIGH 0XF0
#define SENSOR_ID_LOW 0XF1
#define PAD_VB_HIZ_MODE 0XF2
#define SYNC_OUTPUT 0XF3
#define I2C_CONFIG 0XF4
#define PLL_MODE1 0XF7
#define PLL_MODE2 0XF8
#define CM_MODE 0XF9
#define ISP_DIV_MODE 0XFA
#define I2C_DEVICE_ID 0XFB
#define ANALOG_PWC 0XFC
#define ISP_DIV_MODE2 0XFD
#define RESET_RELATED 0XFE // Bit[7]: Software reset
// Bit[6]: cm reset
// Bit[5]: spi reset
// Bit[4]: CISCTL_restart_n
// Bit[3]: PLL_rst
// Bit[2:0]: page select
// 000:page0
// 001:page1
// 010:page2
// 011:page3
//----page0-----------------------------
#define P0_EXPOSURE_HIGH 0X03
#define P0_EXPOSURE_LOW 0X04
#define P0_HB_HIGH 0X05
#define P0_HB_LOW 0X06
#define P0_VB_HIGH 0X07
#define P0_VB_LOW 0X08
#define P0_ROW_START_HIGH 0X09
#define P0_ROW_START_LOW 0X0A
#define P0_COLUMN_START_HIGH 0X0B
#define P0_COLUMN_START_LOW 0X0C
#define P0_WINDOW_HEIGHT_HIGH 0X0D
#define P0_WINDOW_HEIGHT_LOW 0X0E
#define P0_WINDOW_WIDTH_HIGH 0X0F
#define P0_WINDOW_WIDTH_LOW 0X10
#define P0_SH_DELAY 0X11
#define P0_VS_ST 0X12
#define P0_VS_ET 0X13
#define P0_CISCTL_MODE1 0X17
#define P0_BLOCK_ENABLE_1 0X40
#define P0_AAAA_ENABLE 0X42
#define P0_SPECIAL_EFFECT 0X43
#define P0_SYNC_MODE 0X46
#define P0_GAIN_CODE 0X48
#define P0_DEBUG_MODE2 0X4C
#define P0_WIN_MODE 0X50
#define P0_OUT_WIN_Y1_HIGH 0X51
#define P0_OUT_WIN_Y1_LOW 0X52
#define P0_OUT_WIN_X1_HIGH 0X53
#define P0_OUT_WIN_X1_LOW 0X54
#define P0_OUT_WIN_HEIGHT_HIGH 0X55
#define P0_OUT_WIN_HEIGHT_LOW 0X56
#define P0_OUT_WIN_WIDTH_HIGH 0X57
#define P0_OUT_WIN_WIDTH_LOW 0X58
#define P0_GLOBAL_SATURATION 0XD0
#define P0_SATURATION_CB 0XD1
#define P0_SATURATION_CR 0XD2
#define P0_LUMA_CONTRAST 0XD3
#define P0_CONTRAST_CENTER 0XD4
#define P0_LUMA_OFFSET 0XD5
#define P0_FIXED_CB 0XDA
#define P0_FIXED_CR 0XDB
//----page3-----------------------------
#define P3_IMAGE_WIDTH_LOW 0X5B
#define P3_IMAGE_WIDTH_HIGH 0X5C
#define P3_IMAGE_HEIGHT_LOW 0X5D
#define P3_IMAGE_HEIGHT_HIGH 0X5E
#endif //__GC032A_REG_REGS_H__

View File

@@ -0,0 +1,401 @@
#ifndef _GC032A_SETTINGS_H_
#define _GC032A_SETTINGS_H_
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "gc032a_regs.h"
#define REG_DLY 0xffff
#define REGLIST_TAIL 0x0000
/*
* The default register settings, as obtained from OmniVision. There
* is really no making sense of most of these - lots of "reserved" values
* and such.
*
*/
static const uint16_t gc032a_default_regs[][2] = {
/*System*/
{0xf3, 0xff},
{0xf5, 0x06},
{0xf7, 0x01},
{0xf8, 0x03},
{0xf9, 0xce},
{0xfa, 0x00},
{0xfc, 0x02},
{0xfe, 0x02},
{0x81, 0x03},
{0xfe, 0x00},
{0x77, 0x64},
{0x78, 0x40},
{0x79, 0x60},
/*ANALOG & CISCTL*/
{0xfe, 0x00},
{0x03, 0x01},
{0x04, 0xce},
{0x05, 0x01},
{0x06, 0xad},
{0x07, 0x00},
{0x08, 0x10},
{0x0a, 0x00},
{0x0c, 0x00},
{0x0d, 0x01},
{0x0e, 0xe8}, // height 488
{0x0f, 0x02},
{0x10, 0x88}, // width 648
{0x17, 0x54},
{0x19, 0x08},
{0x1a, 0x0a},
{0x1f, 0x40},
{0x20, 0x30},
{0x2e, 0x80},
{0x2f, 0x2b},
{0x30, 0x1a},
{0xfe, 0x02},
{0x03, 0x02},
{0x05, 0xd7},
{0x06, 0x60},
{0x08, 0x80},
{0x12, 0x89},
/*blk*/
{0xfe, 0x00},
{0x18, 0x02},
{0xfe, 0x02},
{0x40, 0x22},
{0x45, 0x00},
{0x46, 0x00},
{0x49, 0x20},
{0x4b, 0x3c},
{0x50, 0x20},
{0x42, 0x10},
/*isp*/
{0xfe, 0x01},
{0x0a, 0xc5},
{0x45, 0x00},
{0xfe, 0x00},
{0x40, 0xff},
{0x41, 0x25},
{0x42, 0xcf},
{0x43, 0x10},
{0x44, 0x83},
{0x46, 0x23},
{0x49, 0x03},
{0x52, 0x02},
{0x54, 0x00},
{0xfe, 0x02},
{0x22, 0xf6},
/*Shading*/
{0xfe, 0x01},
{0xc1, 0x38},
{0xc2, 0x4c},
{0xc3, 0x00},
{0xc4, 0x32},
{0xc5, 0x24},
{0xc6, 0x16},
{0xc7, 0x08},
{0xc8, 0x08},
{0xc9, 0x00},
{0xca, 0x20},
{0xdc, 0x8a},
{0xdd, 0xa0},
{0xde, 0xa6},
{0xdf, 0x75},
/*AWB*/
{0xfe, 0x01},
{0x7c, 0x09},
{0x65, 0x06},
{0x7c, 0x08},
{0x56, 0xf4},
{0x66, 0x0f},
{0x67, 0x84},
{0x6b, 0x80},
{0x6d, 0x12},
{0x6e, 0xb0},
{0x86, 0x00},
{0x87, 0x00},
{0x88, 0x00},
{0x89, 0x00},
{0x8a, 0x00},
{0x8b, 0x00},
{0x8c, 0x00},
{0x8d, 0x00},
{0x8e, 0x00},
{0x8f, 0x00},
{0x90, 0x00},
{0x91, 0x00},
{0x92, 0xf4},
{0x93, 0xd5},
{0x94, 0x50},
{0x95, 0x0f},
{0x96, 0xf4},
{0x97, 0x2d},
{0x98, 0x0f},
{0x99, 0xa6},
{0x9a, 0x2d},
{0x9b, 0x0f},
{0x9c, 0x59},
{0x9d, 0x2d},
{0x9e, 0xaa},
{0x9f, 0x67},
{0xa0, 0x59},
{0xa1, 0x00},
{0xa2, 0x00},
{0xa3, 0x0a},
{0xa4, 0x00},
{0xa5, 0x00},
{0xa6, 0xd4},
{0xa7, 0x9f},
{0xa8, 0x55},
{0xa9, 0xd4},
{0xaa, 0x9f},
{0xab, 0xac},
{0xac, 0x9f},
{0xad, 0x55},
{0xae, 0xd4},
{0xaf, 0xac},
{0xb0, 0xd4},
{0xb1, 0xa3},
{0xb2, 0x55},
{0xb3, 0xd4},
{0xb4, 0xac},
{0xb5, 0x00},
{0xb6, 0x00},
{0xb7, 0x05},
{0xb8, 0xd6},
{0xb9, 0x8c},
/*CC*/
{0xfe, 0x01},
{0xd0, 0x40},
{0xd1, 0xf8},
{0xd2, 0x00},
{0xd3, 0xfa},
{0xd4, 0x45},
{0xd5, 0x02},
{0xd6, 0x30},
{0xd7, 0xfa},
{0xd8, 0x08},
{0xd9, 0x08},
{0xda, 0x58},
{0xdb, 0x02},
{0xfe, 0x00},
/*Gamma*/
{0xfe, 0x00},
{0xba, 0x00},
{0xbb, 0x04},
{0xbc, 0x0a},
{0xbd, 0x0e},
{0xbe, 0x22},
{0xbf, 0x30},
{0xc0, 0x3d},
{0xc1, 0x4a},
{0xc2, 0x5d},
{0xc3, 0x6b},
{0xc4, 0x7a},
{0xc5, 0x85},
{0xc6, 0x90},
{0xc7, 0xa5},
{0xc8, 0xb5},
{0xc9, 0xc2},
{0xca, 0xcc},
{0xcb, 0xd5},
{0xcc, 0xde},
{0xcd, 0xea},
{0xce, 0xf5},
{0xcf, 0xff},
/*Auto Gamma*/
{0xfe, 0x00},
{0x5a, 0x08},
{0x5b, 0x0f},
{0x5c, 0x15},
{0x5d, 0x1c},
{0x5e, 0x28},
{0x5f, 0x36},
{0x60, 0x45},
{0x61, 0x51},
{0x62, 0x6a},
{0x63, 0x7d},
{0x64, 0x8d},
{0x65, 0x98},
{0x66, 0xa2},
{0x67, 0xb5},
{0x68, 0xc3},
{0x69, 0xcd},
{0x6a, 0xd4},
{0x6b, 0xdc},
{0x6c, 0xe3},
{0x6d, 0xf0},
{0x6e, 0xf9},
{0x6f, 0xff},
/*Gain*/
{0xfe, 0x00},
{0x70, 0x50},
/*AEC*/
{0xfe, 0x00},
{0x4f, 0x01},
{0xfe, 0x01},
{0x0d, 0x00},
{0x12, 0xa0},
{0x13, 0x3a},
{0x44, 0x04},
{0x1f, 0x30},
{0x20, 0x40},
{0x26, 0x9a},
{0x3e, 0x20},
{0x3f, 0x2d},
{0x40, 0x40},
{0x41, 0x5b},
{0x42, 0x82},
{0x43, 0xb7},
{0x04, 0x0a},
{0x02, 0x79},
{0x03, 0xc0},
/*measure window*/
{0xfe, 0x01},
{0xcc, 0x08},
{0xcd, 0x08},
{0xce, 0xa4},
{0xcf, 0xec},
/*DNDD*/
{0xfe, 0x00},
{0x81, 0xb8},
{0x82, 0x12},
{0x83, 0x0a},
{0x84, 0x01},
{0x86, 0x50},
{0x87, 0x18},
{0x88, 0x10},
{0x89, 0x70},
{0x8a, 0x20},
{0x8b, 0x10},
{0x8c, 0x08},
{0x8d, 0x0a},
/*Intpee*/
{0xfe, 0x00},
{0x8f, 0xaa},
{0x90, 0x9c},
{0x91, 0x52},
{0x92, 0x03},
{0x93, 0x03},
{0x94, 0x08},
{0x95, 0x44},
{0x97, 0x00},
{0x98, 0x00},
/*ASDE*/
{0xfe, 0x00},
{0xa1, 0x30},
{0xa2, 0x41},
{0xa4, 0x30},
{0xa5, 0x20},
{0xaa, 0x30},
{0xac, 0x32},
/*YCP*/
{0xfe, 0x00},
{0xd1, 0x3c},
{0xd2, 0x3c},
{0xd3, 0x38},
{0xd6, 0xf4},
{0xd7, 0x1d},
{0xdd, 0x73},
{0xde, 0x84},
/*Banding*/
{0xfe, 0x00},
{0x05, 0x01},
{0x06, 0xad},
{0x07, 0x00},
{0x08, 0x10},
{0xfe, 0x01},
{0x25, 0x00},
{0x26, 0x9a},
{0x27, 0x01},
{0x28, 0xce},
{0x29, 0x02},
{0x2a, 0x68},
{0x2b, 0x02},
{0x2c, 0x68},
{0x2d, 0x07},
{0x2e, 0xd2},
{0x2f, 0x0b},
{0x30, 0x6e},
{0x31, 0x0e},
{0x32, 0x70},
{0x33, 0x12},
{0x34, 0x0c},
{0x3c, 0x30},
/*Analog&Cisctl*/
{0xfe, 0x00},
{0x05, 0x01},
{0x06, 0xa0},
{0x07, 0x00},
{0x08, 0x20},
{0x0a, 0x78},
{0x0c, 0xa0},
{0x0d, 0x00}, //window_height [8]
{0x0e, 0xf8}, //window_height [7:0] 248
{0x0f, 0x01}, //window_width [9:8]
{0x10, 0x48}, //window_width [7:0] 328
{0x55, 0x00},
{0x56, 0xf0}, // 240
{0x57, 0x01},
{0x58, 0x40}, // 320
/*SPI*/
{0xfe, 0x03},
{0x5b, 0x40},
{0x5c, 0x01},
{0x5d, 0xf0},
{0x5e, 0x00},
/*AEC*/
{0xfe, 0x01},
{0x25, 0x00}, //step
{0x26, 0x63},
{0x27, 0x01},
{0x28, 0x29},
{0x29, 0x01},
{0x2a, 0x29},
{0x2b, 0x01},
{0x2c, 0x29},
{0x2d, 0x01},
{0x2e, 0x29},
{0x2f, 0x01},
{0x30, 0x29},
{0x31, 0x01},
{0x32, 0x29},
{0x33, 0x01},
{0x34, 0x29},
{0x3c, 0x00},
/*measure window*/
{0xfe, 0x01},
{0xcc, 0x04},
{0xcd, 0x04},
{0xce, 0x72},
{0xcf, 0x52},
{REGLIST_TAIL, 0x00},
};
#endif

View File

@@ -0,0 +1,27 @@
#ifndef __GC2145_H__
#define __GC2145_H__
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int gc2145_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int gc2145_init(sensor_t *sensor);
#endif // __GC2145_H__

View File

@@ -0,0 +1,85 @@
/*
* GC2145 register definitions.
*/
#ifndef __GC2145_REG_REGS_H__
#define __GC2145_REG_REGS_H__
#define CHIP_ID_HIGH 0XF0
#define CHIP_ID_LOW 0XF1
#define PLL_MODE1 0XF7
#define PLL_MODE2 0XF8
#define CM_MODE 0XF9
#define CLK_DIV_MODE 0XFA
#define RESET_RELATED 0xfe // Bit[7]: Software reset
// Bit[6]: cm reset
// Bit[5]: mipi reset
// Bit[4]: CISCTL_restart_n
// Bit[3]: NA
// Bit[2:0]: page select
// 000:page0
// 001:page1
// 010:page2
// 011:page3
//-page0----------------
#define P0_EXPOSURE_HIGH 0X03
#define P0_EXPOSURE_LOW 0X04
#define P0_HB_HIGH 0X05
#define P0_HB_LOW 0X06
#define P0_VB_HIGH 0X07
#define P0_VB_LOW 0X08
#define P0_ROW_START_HIGH 0X09
#define P0_ROW_START_LOW 0X0A
#define P0_COL_START_HIGH 0X0B
#define P0_COL_START_LOW 0X0C
#define P0_WIN_HEIGHT_HIGH 0X0D
#define P0_WIN_HEIGHT_LOW 0X0E
#define P0_WIN_WIDTH_HIGH 0X0F
#define P0_WIN_WIDTH_LOW 0X10
#define P0_ANALOG_MODE1 0X17
#define P0_ANALOG_MODE2 0X18
#define P0_SPECIAL_EFFECT 0X83
#define P0_OUTPUT_FORMAT 0x84 // Format select
// Bit[7]:YUV420 row switch
// Bit[6]:YUV420 col switch
// Bit[7]:YUV420_legacy
// Bit[4:0]:output data mode
// 5h00 Cb Y Cr Y
// 5h01 Cr Y Cb Y
// 5h02 Y Cb Y Cr
// 5h03 Y Cr Y Cb
// 5h04 LSC bypass, C/Y
// 5h05 LSC bypass, Y/C
// 5h06 RGB 565
// 5h0f bypass 10bits
// 5h17 switch odd/even column /row to controls output Bayer pattern
// 00 RGBG
// 01 RGGB
// 10 BGGR
// 11 GBRG
// 5'h18 DNDD out mode
// 5'h19 LSC out mode
// 5;h1b EEINTP out mode
#define P0_FRAME_START 0X85
#define P0_SYNC_MODE 0X86
#define P0_MODULE_GATING 0X88
#define P0_BYPASS_MODE 0X89
#define P0_DEBUG_MODE2 0X8C
#define P0_DEBUG_MODE3 0X8D
#define P0_CROP_ENABLE 0X90
#define P0_OUT_WIN_Y1_HIGH 0X91
#define P0_OUT_WIN_Y1_LOW 0X92
#define P0_OUT_WIN_X1_HIGH 0X93
#define P0_OUT_WIN_X1_LOW 0X94
#define P0_OUT_WIN_HEIGHT_HIGH 0X95
#define P0_OUT_WIN_HEIGHT_LOW 0X96
#define P0_OUT_WIN_WIDTH_HIGH 0X97
#define P0_OUT_WIN_WIDTH_LOW 0X98
#define P0_SUBSAMPLE 0X99
#define P0_SUBSAMPLE_MODE 0X9A
#endif // __GC2145_REG_REGS_H__

View File

@@ -0,0 +1,719 @@
#include <stdint.h>
#define REG_DLY 0xffff
#define REGLIST_TAIL 0x0000 /* Array end token */
static const uint16_t gc2145_default_init_regs[][2] = {
{0xfe, 0xf0},
{0xfe, 0xf0},
{0xfe, 0xf0},
{0xfc, 0x06},
{0xf6, 0x00},
{0xf7, 0x1d}, //37 //17 //37 //1d//05
{0xf8, 0x83}, //87 //83 //82
{0xfa, 0x00},
{0xf9, 0xfe}, //ff
{0xfd, 0x00},
{0xc2, 0x00},
{0xf2, 0x0f},
//////////////////////////////////////////////////////
//////////////////// Analog & Cisctl ////////////////
//////////////////////////////////////////////////////
{0xfe, 0x00},
{0x03, 0x04}, //exp time
{0x04, 0x62}, //exp time
{0x05, 0x01}, //00 //hb[11:8]
{0x06, 0x3b}, //0b //hb
{0x09, 0x00}, //row start
{0x0a, 0x00}, //
{0x0b, 0x00}, //col start
{0x0c, 0x00},
{0x0d, 0x04}, //height
{0x0e, 0xc0},
{0x0f, 0x06}, //width
{0x10, 0x52},
{0x12, 0x2e}, //sh_delay 太短 YUV出图异常
{0x17, 0x14}, //CISCTL Mode1 [1:0]mirror flip
{0x18, 0x22}, //sdark mode
{0x19, 0x0f}, // AD pipe number
{0x1a, 0x01}, //AD manual switch mode
{0x1b, 0x4b}, //48 restg Width,SH width
{0x1c, 0x07}, //06 帧率快后,横条纹 //12 //TX Width,Space Width
{0x1d, 0x10}, //double reset
{0x1e, 0x88}, //90//98 //fix 竖线//Analog Mode1,TX high,Coln_r
{0x1f, 0x78}, //78 //38 //18 //Analog Mode2,txlow
{0x20, 0x03}, //07 //Analog Mode3,comv,ad_clk mode
{0x21, 0x40}, //10//20//40 //fix 灯管横条纹
{0x22, 0xa0}, //d0//f0 //a2 //Vref vpix FPN严重
{0x24, 0x1e},
{0x25, 0x01}, //col sel
{0x26, 0x10}, //Analog PGA gain1
{0x2d, 0x60}, //40//40 //txl drv mode
{0x30, 0x01}, //Analog Mode4
{0x31, 0x90}, //b0//70 // Analog Mode7 [7:5]rsgh_r灯管横条纹[4:3]isp_g
{0x33, 0x06}, //03//02//01 //EQ_hstart_width
{0x34, 0x01},
//
///////////////////////////////////////////////////
//////////////////// ISP reg //////////////////////
//////////////////////////////////////////////////////
{0x80, 0xff}, //outdoor gamma_en, GAMMA_en, CC_en, EE_en, INTP_en, DN_en, DD_en,LSC_en
{0x81, 0x24}, //26//24 //BLK dither mode, ll_y_en ,skin_en, edge SA, new_skin_mode, autogray_en,ll_gamma_en,BFF test image
{0x82, 0xfa}, //FA //auto_SA, auto_EE, auto_DN, auto_DD, auto_LSC, ABS_en, AWB_en, NA
{0x83, 0x00}, //special_effect
{0x84, 0x02}, //output format
{0x86, 0x03}, //c2 //46 //c2 //sync mode
{0x88, 0x03}, //[1]ctl_auto_gating [0]out_auto_gating
{0x89, 0x03}, //bypass disable
{0x85, 0x30}, //60//frame start cut
{0x8a, 0x00}, //ISP_quiet_mode,close aaa pclk,BLK gate mode,exception,close first pipe clock,close dndd clock,close intp clock,DIV_gatedclk_en
{0x8b, 0x00}, //[7:6]BFF_gate_mode,[5]BLK switch gain,[4]protect exp,[3:2]pipe gate mode,[1]not split sram,[0]dark current update
{0xb0, 0x55}, //60 //global gain
{0xc3, 0x00}, //[7:4]auto_exp_gamma_th1[11:8],[3:0]auto_exp_gamma_th2[11:8]
{0xc4, 0x80}, //auto_exp_gamma_th1[7:0] into
{0xc5, 0x90}, //auto_exp_gamma_th2[7:0] out //outdoor gamma
{0xc6, 0x38}, //auto_gamma_th1
{0xc7, 0x40}, //auto_gamma_th2
{0xec, 0x06}, //measure window
{0xed, 0x04},
{0xee, 0x60}, //16 col
{0xef, 0x90}, //8 row
{0xb6, 0x01}, //[0]aec en
{0x90, 0x01}, //crop
{0x91, 0x00},
{0x92, 0x00},
{0x93, 0x00},
{0x94, 0x00}, //08
{0x95, 0x04},
{0x96, 0xb0},
{0x97, 0x06},
{0x98, 0x40},
///////////////////////////////////////////////
/////////// BLK ////////////////////////
///////////////////////////////////////////////
{0x18, 0x02},
{0x40, 0x42}, //2b //27
{0x41, 0x00}, //80 //dark row sel
{0x43, 0x54}, //[7:4]BLK start not smooth [3:0]output start frame
{0x5e, 0x00}, //00//10 //18
{0x5f, 0x00}, //00//10 //18
{0x60, 0x00}, //00//10 //18
{0x61, 0x00}, //00///10 //18
{0x62, 0x00}, //00//10 //18
{0x63, 0x00}, //00//10 //18
{0x64, 0x00}, //00/10 //18
{0x65, 0x00}, //00//10 //18
{0x66, 0x20}, //1e
{0x67, 0x20}, //1e
{0x68, 0x20}, //1e
{0x69, 0x20}, //1e
{0x76, 0x00}, //0f
{0x6a, 0x00}, //06
{0x6b, 0x00}, //06
{0x6c, 0x3e}, //06
{0x6d, 0x3e}, //06
{0x6e, 0x3f}, //06
{0x6f, 0x3f}, //06
{0x70, 0x00}, //06
{0x71, 0x00}, //06 //manual offset
{0x76, 0x00}, //1f//add offset
{0x72, 0xf0}, //[7:4]BLK DD th [3:0]BLK various th
{0x7e, 0x3c}, //ndark
{0x7f, 0x00},
{0xfe, 0x02},
{0x48, 0x15},
{0x49, 0x00}, //04//04 //ASDE OFFSET SLOPE
{0x4b, 0x0b}, //ASDE y OFFSET SLOPE
{0xfe, 0x00},
///////////////////////////////////////////////
/////////// AEC ////////////////////////
///////////////////////////////////////////////
{0xfe, 0x01},
{0x01, 0x04}, //AEC X1
{0x02, 0xc0}, //AEC X2
{0x03, 0x04}, //AEC Y1
{0x04, 0x90}, //AEC Y2
{0x05, 0x30}, //20 //AEC center X1
{0x06, 0x90}, //40 //AEC center X2
{0x07, 0x20}, //30 //AEC center Y1
{0x08, 0x70}, //60 //AEC center Y2
{0x09, 0x00}, //AEC show mode
{0x0a, 0xc2}, //[7]col gain enable
{0x0b, 0x11}, //AEC every N
{0x0c, 0x10}, //AEC_mode3 center weight
{0x13, 0x40}, //2a //AEC Y target
{0x17, 0x00}, //AEC ignore mode
{0x1c, 0x11}, //
{0x1e, 0x61}, //
{0x1f, 0x30}, //40//50 //max pre gain
{0x20, 0x40}, //60//40 //max post gain
{0x22, 0x80}, //AEC outdoor THD
{0x23, 0x20}, //target_Y_low_limit
{0xfe, 0x02},
{0x0f, 0x04}, //05
{0xfe, 0x01},
{0x12, 0x35}, //35 //[5:4]group_size [3]slope_disable [2]outdoor_enable [0]histogram_enable
{0x15, 0x50}, //target_Y_high_limit
{0x10, 0x31}, //num_thd_high
{0x3e, 0x28}, //num_thd_low
{0x3f, 0xe0}, //luma_thd
{0x40, 0x20}, //luma_slope
{0x41, 0x0f}, //color_diff
{0xfe, 0x02},
{0x0f, 0x05}, //max_col_level
///////////////////////////
////// INTPEE /////////////
///////////////////////////
{0xfe, 0x02}, //page2
{0x90, 0x6c}, //ac //eeintp mode1
{0x91, 0x03}, //02 ////eeintp mode2
{0x92, 0xc8}, //44 //low criteria for direction
{0x94, 0x66},
{0x95, 0xb5},
{0x97, 0x64}, //78 ////edge effect
{0xa2, 0x11}, //fix direction
{0xfe, 0x00},
/////////////////////////////
//////// DNDD///////////////
/////////////////////////////
{0xfe, 0x02},
{0x80, 0xc1}, //c1 //[7]share mode [6]skin mode [5]is 5x5 mode [1:0]noise value select 0:2 1:2.5 2:3 3:4
{0x81, 0x08}, //
{0x82, 0x08}, //signal a 0.6
{0x83, 0x08}, //04 //signal b 2.5
{0x84, 0x0a}, //10 //05 dark_DD_TH
{0x86, 0xf0}, //a0 Y_value_dd_th2
{0x87, 0x50}, //90 Y_value_dd_th3
{0x88, 0x15}, //60 Y_value_dd_th4
{0x89, 0x50}, //80 // asde th2
{0x8a, 0x30}, //60 // asde th3
{0x8b, 0x10}, //30 // asde th4
/////////////////////////////////////////////////
///////////// ASDE ////////////////////////
/////////////////////////////////////////////////
{0xfe, 0x01}, //page 1
{0x21, 0x14}, //luma_value_div_sel(分频与0xef呈2倍关系增大10xef的值减小1倍)
//ff ef luma_value read_only
{0xfe, 0x02}, //page2
{0xa3, 0x40}, //ASDE_low_luma_value_LSC_th_H
{0xa4, 0x20}, //ASDE_low_luma_value_LSC_th_L
{0xa5, 0x40}, //80 //ASDE_LSC_gain_dec_slope_H
{0xa6, 0x80}, // 80 //ASDE_LSC_gain_dec_slope_L
//ff a7 ASDE_LSC_gain_dec //read only
{0xab, 0x40}, //50 //ASDE_low_luma_value_OT_th
{0xae, 0x0c}, //[3]EE1_effect_inc_or_dec_high,[2]EE2_effect_inc_or_dec_high,
//[1]EE1_effect_inc_or_dec_low,[0]EE2_effect_inc_or_dec_low, 1:inc 0:dec
{0xb3, 0x34}, //44 //ASDE_EE1_effect_slope_low,ASDE_EE2_effect_slope_low
{0xb4, 0x44}, //12 //ASDE_EE1_effect_slope_high,ASDE_EE2_effect_slope_high
{0xb6, 0x38}, //40//40 //ASDE_auto_saturation_dec_slope
{0xb7, 0x02}, //04 //ASDE_sub_saturation_slope
{0xb9, 0x30}, //[7:0]ASDE_auto_saturation_low_limit
{0x3c, 0x08}, //[3:0]auto gray_dec_slope
{0x3d, 0x30}, //[7:0]auto gray_dec_th
{0x4b, 0x0d}, //y offset slope
{0x4c, 0x20}, //y offset limit
{0xfe, 0x00},
//
///////////////////gamma1////////////////////
////Gamma
{0xfe, 0x02},
{0x10, 0x10},
{0x11, 0x15},
{0x12, 0x1a},
{0x13, 0x1f},
{0x14, 0x2c},
{0x15, 0x39},
{0x16, 0x45},
{0x17, 0x54},
{0x18, 0x69},
{0x19, 0x7d},
{0x1a, 0x8f},
{0x1b, 0x9d},
{0x1c, 0xa9},
{0x1d, 0xbd},
{0x1e, 0xcd},
{0x1f, 0xd9},
{0x20, 0xe3},
{0x21, 0xea},
{0x22, 0xef},
{0x23, 0xf5},
{0x24, 0xf9},
{0x25, 0xff},
/////auto gamma/////
{0xfe, 0x02},
{0x26, 0x0f},
{0x27, 0x14},
{0x28, 0x19},
{0x29, 0x1e},
{0x2a, 0x27},
{0x2b, 0x33},
{0x2c, 0x3b},
{0x2d, 0x45},
{0x2e, 0x59},
{0x2f, 0x69},
{0x30, 0x7c},
{0x31, 0x89},
{0x32, 0x98},
{0x33, 0xae},
{0x34, 0xc0},
{0x35, 0xcf},
{0x36, 0xda},
{0x37, 0xe2},
{0x38, 0xe9},
{0x39, 0xf3},
{0x3a, 0xf9},
{0x3b, 0xff},
///////////////////////////////////////////////
/////////// YCP ///////////////////////
///////////////////////////////////////////////
{0xfe, 0x02},
{0xd1, 0x30}, //32 //
{0xd2, 0x30}, //32 //
{0xd3, 0x45},
{0xdd, 0x14}, //edge sa
{0xde, 0x86}, //asde auto gray
{0xed, 0x01}, //
{0xee, 0x28},
{0xef, 0x30},
{0xd8, 0xd8}, //autogray protecy
////////////////////////////
//////// LSC 0.8///////////////
////////////////////////////
{0xfe, 0x01},
{0xa1, 0x80}, // center_row
{0xa2, 0x80}, // center_col
{0xa4, 0x00}, // sign of b1
{0xa5, 0x00}, // sign of b1
{0xa6, 0x70}, // sign of b4
{0xa7, 0x00}, // sign of b4
{0xa8, 0x77}, // sign of b22
{0xa9, 0x77}, // sign of b22
{0xaa, 0x1f}, // Q1_b1 of R
{0xab, 0x0d}, // Q1_b1 of G
{0xac, 0x19}, // Q1_b1 of B
{0xad, 0x24}, // Q2_b1 of R
{0xae, 0x0e}, // Q2_b1 of G
{0xaf, 0x1d}, // Q2_b1 of B
{0xb0, 0x12}, // Q3_b1 of R
{0xb1, 0x0c}, // Q3_b1 of G
{0xb2, 0x06}, // Q3_b1 of B
{0xb3, 0x13}, // Q4_b1 of R
{0xb4, 0x10}, // Q4_b1 of G
{0xb5, 0x0c}, // Q4_b1 of B
{0xb6, 0x6a}, // right_b2 of R
{0xb7, 0x46}, // right_b2 of G
{0xb8, 0x40}, // right_b2 of B
{0xb9, 0x0b}, // right_b4 of R
{0xba, 0x04}, // right_b4 of G
{0xbb, 0x00}, // right_b4 of B
{0xbc, 0x53}, // left_b2 of R
{0xbd, 0x37}, // left_b2 of G
{0xbe, 0x2d}, // left_b2 of B
{0xbf, 0x0a}, // left_b4 of R
{0xc0, 0x0a}, // left_b4 of G
{0xc1, 0x14}, // left_b4 of B
{0xc2, 0x34}, // up_b2 of R
{0xc3, 0x22}, // up_b2 of G
{0xc4, 0x18}, // up_b2 of B
{0xc5, 0x23}, // up_b4 of R
{0xc6, 0x0f}, // up_b4 of G
{0xc7, 0x3c}, // up_b4 of B
{0xc8, 0x20}, // down_b2 of R
{0xc9, 0x1f}, // down_b2 of G
{0xca, 0x17}, // down_b2 of B
{0xcb, 0x2d}, // down_b4 of R
{0xcc, 0x12}, // down_b4 of G
{0xcd, 0x20}, // down_b4 of B
{0xd0, 0x61}, // right_up_b22 of R
{0xd1, 0x2f}, // right_up_b22 of G
{0xd2, 0x39}, // right_up_b22 of B
{0xd3, 0x45}, // right_down_b22 of R
{0xd4, 0x2c}, // right_down_b22 of G
{0xd5, 0x21}, // right_down_b22 of B
{0xd6, 0x64}, // left_up_b22 of R
{0xd7, 0x2d}, // left_up_b22 of G
{0xd8, 0x30}, // left_up_b22 of B
{0xd9, 0x42}, // left_down_b22 of R
{0xda, 0x27}, // left_down_b22 of G
{0xdb, 0x13}, // left_down_b22 of B
{0xfe, 0x00},
/////////////////////////////////////////////////
///////////// AWB ////////////////////////
/////////////////////////////////////////////////
{0xfe, 0x01},
{0x4f, 0x00},
{0x4f, 0x00},
{0x4b, 0x01},
{0x4f, 0x00},
{0x4c, 0x01},
{0x4d, 0x6f},
{0x4e, 0x02},
{0x4c, 0x01},
{0x4d, 0x70},
{0x4e, 0x02},
{0x4c, 0x01},
{0x4d, 0x8f},
{0x4e, 0x02},
{0x4c, 0x01},
{0x4d, 0x90},
{0x4e, 0x02}, //light
{0x4c, 0x01},
{0x4d, 0xed},
{0x4e, 0x33}, //light
{0x4c, 0x01},
{0x4d, 0xcd},
{0x4e, 0x33}, //light
{0x4c, 0x01},
{0x4d, 0xec},
{0x4e, 0x03}, //light
{0x4c, 0x01},
{0x4d, 0x6c},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0x6d},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0x6e},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0x8c},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0x8d},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0x8e},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xab},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xac},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xad},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xae},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xcb},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xcc},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xce},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xeb},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xec},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xee},
{0x4e, 0x03},
{0x4c, 0x02},
{0x4d, 0x0c},
{0x4e, 0x03},
{0x4c, 0x02},
{0x4d, 0x0d},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xea},
{0x4e, 0x03},
{0x4c, 0x01},
{0x4d, 0xaf},
{0x4e, 0x03}, //dark
{0x4c, 0x01},
{0x4d, 0xcf},
{0x4e, 0x03}, //dark
{0x4c, 0x01},
{0x4d, 0xca},
{0x4e, 0x04}, //light
{0x4c, 0x02},
{0x4d, 0x0b},
{0x4e, 0x05}, //light
{0x4c, 0x02},
{0x4d, 0xc8},
{0x4e, 0x06}, //light 100lux
{0x4c, 0x02},
{0x4d, 0xa8},
{0x4e, 0x06}, //light
{0x4c, 0x02},
{0x4d, 0xa9},
{0x4e, 0x06}, //light
{0x4c, 0x02},
{0x4d, 0x89},
{0x4e, 0x06}, //400lux
{0x4c, 0x02},
{0x4d, 0x69},
{0x4e, 0x06}, //f12
{0x4c, 0x02},
{0x4d, 0x6a},
{0x4e, 0x06}, //f12
{0x4c, 0x02},
{0x4d, 0xc7},
{0x4e, 0x07},
{0x4c, 0x02},
{0x4d, 0xe7},
{0x4e, 0x07}, //100lux
{0x4c, 0x03},
{0x4d, 0x07},
{0x4e, 0x07}, //light
{0x4c, 0x02},
{0x4d, 0xe8},
{0x4e, 0x07},
{0x4c, 0x02},
{0x4d, 0xe9},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x08},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x09},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x27},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x28},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x29},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x47},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x48},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x49},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x67},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x68},
{0x4e, 0x07},
{0x4c, 0x03},
{0x4d, 0x69},
{0x4e, 0x07},
{0x4f, 0x01},
{0xfe, 0x01},
{0x50, 0x80}, //AWB_PRE_mode
{0x51, 0xa8}, //AWB_pre_THD_min[7:0]
{0x52, 0x57}, //AWB_pre_THD_min[15:8] Dominiate luma 0.25=639c 0.22=57a8
{0x53, 0x38}, //AWB_pre_THD_min_MIX[7:0]
{0x54, 0xc7}, //AWB_pre_THD_min_MIX[15:8] Mix luma 0.5
{0x56, 0x0e}, //AWB_tone mode
{0x58, 0x08}, //AWB_C_num_sel,AWB_D_num_sel
{0x5b, 0x00}, //AWB_mix_mode
{0x5c, 0x74}, //green_num0[7:0]
{0x5d, 0x8b}, //green_num0[15:8] 0.35
{0x61, 0xd3}, //R2G_stand0
{0x62, 0xb5}, //B2G_stand0
{0x63, 0x00}, //88//a4 //AWB gray mode [7]enable
{0x65, 0x04}, //AWB margin
{0x67, 0xb2}, //R2G_stand3[7:0] FF/CWF
{0x68, 0xac}, //B2G_stand3[7:0]
{0x69, 0x00}, //R2G_stand4[9:8] B2G_stand4[9:8] R2G_stand3[9:8] B2G_stand3[9:8]
{0x6a, 0xb2}, //R2G_stand4[7:0] TL84/TL84&CWF
{0x6b, 0xac}, //B2G_stand4[7:0]
{0x6c, 0xb2}, //R2G_stand5[7:0] A
{0x6d, 0xac}, //B2G_stand5[7:0]
{0x6e, 0x40}, //AWB_skin_weight R2G_stand5[9:8] B2G_stand5[9:8]
{0x6f, 0x18}, //AWB_indoor_THD (0x21=17 caculate)
{0x73, 0x00}, //AWB_indoor_mode
{0x70, 0x10}, //AWB low luma TH
{0x71, 0xe8}, //AWB outdoor TH
{0x72, 0xc0}, //outdoor mode
{0x74, 0x01}, //[2:0]AWB skip mode 2x2,4x4,4x8,8x8
{0x75, 0x01}, //[1:0]AWB_every_N
{0x7f, 0x08}, //[3]gray world frame start
{0x76, 0x70}, //R limit
{0x77, 0x58}, //G limit
{0x78, 0xa0}, //d8 //B limit
{0xfe, 0x00},
//
//////////////////////////////////////////
/////////// CC ////////////////////////
//////////////////////////////////////////
{0xfe, 0x02},
{0xc0, 0x01}, //[5:4] CC mode [0]CCT enable
{0xC1, 0x50}, //D50/D65
{0xc2, 0xF9},
{0xc3, 0x00}, //0
{0xc4, 0xe8}, //e0
{0xc5, 0x48},
{0xc6, 0xf0},
{0xC7, 0x50},
{0xc8, 0xf2},
{0xc9, 0x00},
{0xcA, 0xE0},
{0xcB, 0x45},
{0xcC, 0xec},
{0xCd, 0x45},
{0xce, 0xf0},
{0xcf, 0x00},
{0xe3, 0xf0},
{0xe4, 0x45},
{0xe5, 0xe8},
{0xfe, 0x00},
{0xf2, 0x0f},
//////////////frame rate 50Hz
{0xfe, 0x00},
{0xf7, 0x1d},
{0xf8, 0x84},
{0xfa, 0x00},
{0x05, 0x01}, //hb
{0x06, 0x3b},
{0x07, 0x01}, //Vb
{0x08, 0x0b},
{0xfe, 0x01},
{0x25, 0x01},
{0x26, 0x32}, //step
{0x27, 0x03}, //8.15fps
{0x28, 0x96},
{0x29, 0x03}, //8.15fps
{0x2a, 0x96},
{0x2b, 0x03}, //8.15fps
{0x2c, 0x96},
{0x2d, 0x04}, //8.15fps
{0x2e, 0x62},
{0x3c, 0x00},
{0xfe, 0x00},
/////////dark sun//////
{0xfe, 0x00},
{0x18, 0x22},
{0xfe, 0x02},
{0x40, 0xbf},
{0x46, 0xcf},
{0xfe, 0x00},
{0xfe, 0x00},
{0xf7, 0x1d},
{0xf8, 0x84},
{0xfa, 0x10},
{0x05, 0x01}, //hb
{0x06, 0x18},
{0x07, 0x00}, //Vb
{0x08, 0x2e},
{0xfe, 0x01},
{0x25, 0x00},
{0x26, 0xa2}, //step
{0x27, 0x01},
{0x28, 0xe6},
{0x29, 0x01},
{0x2a, 0xe6},
{0x2b, 0x01},
{0x2c, 0xe6},
{0x2d, 0x04}, // AEC_exp_level4[12:8]
{0x2e, 0x62}, // AEC_exp_level4[7:0]
{0x3c, 0x00},
{0xfe, 0x00},
{0x09, 0x01}, //row start
{0x0a, 0xd0}, //
{0x0b, 0x02}, //col start
{0x0c, 0x70},
{0x0d, 0x01}, //height
{0x0e, 0x00},
{0x0f, 0x01}, //width
{0x10, 0x50},
{0x90, 0x01}, //crop
{0x91, 0x00},
{0x92, 0x00},
{0x93, 0x00},
{0x94, 0x00},
{0x95, 0x00},
{0x96, 0xf0},
{0x97, 0x01},
{0x98, 0x40},
{REGLIST_TAIL, 0x00},
};

View File

@@ -11,6 +11,24 @@
#include "sensor.h"
int NT99141_init(sensor_t *sensor);
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int nt99141_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int nt99141_init(sensor_t *sensor);
#endif // __NT99141_H__

View File

@@ -9,5 +9,24 @@
#ifndef __OV2640_H__
#define __OV2640_H__
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int ov2640_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int ov2640_init(sensor_t *sensor);
#endif // __OV2640_H__

View File

@@ -120,8 +120,8 @@ typedef enum {
#define HSTOP 0x18
#define VSTART 0x19
#define VSTOP 0x1A
#define MIDH 0x1C
#define MIDL 0x1D
#define REG_MIDH 0x1C
#define REG_MIDL 0x1D
#define AEW 0x24
#define AEB 0x25
#define VV 0x26

View File

@@ -11,6 +11,24 @@
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int ov3660_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int ov3660_init(sensor_t *sensor);
#endif // __OV3660_H__

View File

@@ -4,6 +4,24 @@
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int ov5640_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int ov5640_init(sensor_t *sensor);
#endif // __OV5640_H__

View File

@@ -10,5 +10,24 @@
#define __OV7670_H__
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int ov7670_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int ov7670_init(sensor_t *sensor);
#endif // __OV7670_H__

View File

@@ -10,5 +10,24 @@
#define __OV7725_H__
#include "sensor.h"
/**
* @brief Detect sensor pid
*
* @param slv_addr SCCB address
* @param id Detection result
* @return
* 0: Can't detect this sensor
* Nonzero: This sensor has been detected
*/
int ov7725_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int ov7725_init(sensor_t *sensor);
#endif // __OV7725_H__