mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-09 21:17:06 +03:00
v10.2.0
This commit is contained in:
465
code/components/esp32-camera-master/sensors/gc0308.c
Normal file
465
code/components/esp32-camera-master/sensors/gc0308.c
Normal 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;
|
||||
}
|
||||
391
code/components/esp32-camera-master/sensors/gc032a.c
Normal file
391
code/components/esp32-camera-master/sensors/gc032a.c
Normal 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;
|
||||
}
|
||||
475
code/components/esp32-camera-master/sensors/gc2145.c
Normal file
475
code/components/esp32-camera-master/sensors/gc2145.c
Normal 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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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__
|
||||
@@ -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
|
||||
@@ -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__
|
||||
@@ -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
|
||||
// 5’h00 Cb Y Cr Y
|
||||
// 5’h01 Cr Y Cb Y
|
||||
// 5’h02 Y Cb Y Cr
|
||||
// 5’h03 Y Cr Y Cb
|
||||
// 5’h04 LSC bypass, C/Y
|
||||
// 5’h05 LSC bypass, Y/C
|
||||
// 5’h06 RGB 565
|
||||
// 5’h0f bypass 10bits
|
||||
// 5’h17 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__
|
||||
@@ -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倍关系,增大1,0xef的值减小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},
|
||||
};
|
||||
@@ -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__
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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__
|
||||
|
||||
Reference in New Issue
Block a user