diff --git a/CMakeLists.txt b/CMakeLists.txt
index 536f6ba..5ceec97 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -10,6 +10,9 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
sensors/ov7725.c
sensors/ov7670.c
sensors/nt99141.c
+ sensors/gc0308.c
+ sensors/gc2145.c
+ sensors/gc032a.c
conversions/yuv.c
conversions/to_jpg.cpp
conversions/to_bmp.c
diff --git a/Kconfig b/Kconfig
index 49813f6..6fb5aad 100755
--- a/Kconfig
+++ b/Kconfig
@@ -8,8 +8,8 @@ menu "Camera configuration"
Disable this option to save memory.
config OV7725_SUPPORT
- bool "Support OV7725 SVGA"
- default n
+ bool "Support OV7725 VGA"
+ default y
help
Enable this option if you want to use the OV7725.
Disable this option to save memory.
@@ -42,6 +42,27 @@ menu "Camera configuration"
Enable this option if you want to use the OV5640.
Disable this option to save memory.
+ config GC2145_SUPPORT
+ bool "Support GC2145 2MP"
+ default y
+ help
+ Enable this option if you want to use the GC2145.
+ Disable this option to save memory.
+
+ config GC032A_SUPPORT
+ bool "Support GC032A VGA"
+ default y
+ help
+ Enable this option if you want to use the GC032A.
+ Disable this option to save memory.
+
+ config GC0308_SUPPORT
+ bool "Support GC0308 VGA"
+ default y
+ help
+ Enable this option if you want to use the GC0308.
+ Disable this option to save memory.
+
choice SCCB_HARDWARE_I2C_PORT
bool "I2C peripheral to use for SCCB"
default SCCB_HARDWARE_I2C_PORT1
@@ -53,6 +74,20 @@ menu "Camera configuration"
endchoice
+ choice GC_SENSOR_WINDOW_MODE
+ bool "GalaxyCore Sensor Window Mode"
+ depends on (GC2145_SUPPORT || GC032A_SUPPORT || GC0308_SUPPORT)
+ default GC_SENSOR_SUBSAMPLE_MODE
+ help
+ This option determines how to reduce the output size when the resolution you set is less than the maximum resolution.
+ SUBSAMPLE_MODE has a bigger perspective and WINDOWING_MODE has a higher frame rate.
+
+ config GC_SENSOR_WINDOWING_MODE
+ bool "Windowing Mode"
+ config GC_SENSOR_SUBSAMPLE_MODE
+ bool "Subsample Mode"
+ endchoice
+
choice CAMERA_TASK_PINNED_TO_CORE
bool "Camera task pinned to core"
default CAMERA_CORE0
@@ -68,4 +103,12 @@ menu "Camera configuration"
endchoice
+ config CAMERA_DMA_BUFFER_SIZE_MAX
+ int "DMA buffer size"
+ range 8192 32768
+ default 32768
+ help
+ Maximum value of DMA buffer
+ Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent
+
endmenu
diff --git a/README.md b/README.md
index 96872e6..56c00b2 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,27 @@
## General Information
-This repository hosts ESP32, ESP32-S2 and ESP32-S3 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
+This repository hosts ESP32 series Soc compatible driver for image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
+
+### Supported Soc
+
+- ESP32
+- ESP32-S2
+- ESP32-S3
+
+### Supported Sensor
+
+| model | max resolution | color type | output format | Len Size |
+| ------- | -------------- | ---------- | ------------------------------------------------------------ | -------- |
+| OV2640 | 1600 x 1200 | color | YUV(422/420)/YCbCr422
RGB565/555
8-bit compressed data
8/10-bit Raw RGB data | 1/4" |
+| OV3660 | 2048 x 1536 | color | raw RGB data
RGB565/555/444
CCIR656
YCbCr422
compression | 1/5" |
+| OV5640 | 2592 x 1944 | color | RAW RGB
RGB565/555/444
CCIR656
YUV422/420
YCbCr422
compression | 1/4" |
+| OV7670 | 640 x 480 | color | Raw Bayer RGB
Processed Bayer RGB
YUV/YCbCr422
GRB422
RGB565/555 | 1/6" |
+| OV7725 | 640 x 480 | color | Raw RGB
GRB 422
RGB565/555/444
YCbCr 422 | 1/4" |
+| NT99141 | 1280 x 720 | color | YCbCr 422
RGB565/555/444
Raw
CCIR656
JPEG compression | 1/4" |
+| GC032A | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/10" |
+| GC0308 | 640 x 480 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/6.5" |
+| GC2145 | 1600 x 1200 | color | YUV/YCbCr422
RAW Bayer
RGB565 | 1/5" |
## Important to Remember
@@ -75,17 +95,6 @@ However with a bit of patience and experimenting you'll figure the Kconfig out.
If you miss-skip-ignore this critical step the camera module will compile but camera logic inside the library will be 'empty' because the Kconfig sets the proper #ifdef statements during the build process to initialize the selected cameras. It's very not optional!
-### Kconfig options
-
-| config | description | default |
-| --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------ |
-| CONFIG_OV2640_SUPPORT | Support for OV2640 camera | enabled |
-| CONFIG_OV7725_SUPPORT | Support for OV7725 camera | disabled |
-| CONFIG_OV3660_SUPPORT | Support for OV3660 camera | enabled |
-| CONFIG_OV5640_SUPPORT | Support for OV5640 camera | enabled |
-| CONFIG_SCCB_HARDWARE_I2C | Enable this option if you want to use hardware I2C to control the camera. Disable this option to use software I2C. | enabled |
-| CONFIG_SCCB_HARDWARE_I2C_PORT | I2C peripheral to use for SCCB. Can be I2C0 and I2C1. | CONFIG_SCCB_HARDWARE_I2C_PORT1 |
-| CONFIG_CAMERA_TASK_PINNED_TO_CORE | Pin the camera handle task to a certain core(0/1). It can also be done automatically choosing NO_AFFINITY. Can be CAMERA_CORE0, CAMERA_CORE1 or NO_AFFINITY. | CONFIG_CAMERA_CORE0 |
## Examples
diff --git a/driver/cam_hal.c b/driver/cam_hal.c
index fce59bc..724c140 100644
--- a/driver/cam_hal.c
+++ b/driver/cam_hal.c
@@ -93,7 +93,7 @@ void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType
if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) {
ll_cam_stop(cam);
cam->state = CAM_STATE_IDLE;
- ESP_EARLY_LOGE(TAG, "EV-OVF");
+ ESP_EARLY_LOGE(TAG, "EV-%s-OVF", cam_event==CAM_IN_SUC_EOF_EVENT ? "EOF" : "VSYNC");
}
}
@@ -266,6 +266,7 @@ static esp_err_t cam_dma_config()
cam_obj->frames[x].dma = NULL;
cam_obj->frames[x].fb_offset = 0;
cam_obj->frames[x].en = 0;
+ ESP_LOGI(TAG, "Allocating %d Byte frame buffer in PSRAM", fb_size * sizeof(uint8_t) + dma_align);
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(fb_size * sizeof(uint8_t) + dma_align, MALLOC_CAP_SPIRAM);
CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
if (cam_obj->psram_mode) {
@@ -281,7 +282,11 @@ static esp_err_t cam_dma_config()
if (!cam_obj->psram_mode) {
cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
- CAM_CHECK(cam_obj->dma_buffer != NULL, "dma_buffer malloc failed", ESP_FAIL);
+ if(NULL == cam_obj->dma_buffer) {
+ ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
+ cam_obj->dma_buffer_size, heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
+ return ESP_FAIL;
+ }
cam_obj->dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->dma_buffer);
CAM_CHECK(cam_obj->dma != NULL, "dma malloc failed", ESP_FAIL);
@@ -453,7 +458,7 @@ camera_fb_t *cam_take(TickType_t timeout)
}
return dma_buffer;
} else {
- ESP_LOGI(TAG, "Failed to get the frame on time!");
+ ESP_LOGW(TAG, "Failed to get the frame on time!");
}
return NULL;
}
diff --git a/driver/esp_camera.c b/driver/esp_camera.c
index 30fb8d9..9ae1b56 100644
--- a/driver/esp_camera.c
+++ b/driver/esp_camera.c
@@ -26,7 +26,6 @@
#include "sccb.h"
#include "cam_hal.h"
#include "esp_camera.h"
-// #include "camera_common.h"
#include "xclk.h"
#if CONFIG_OV2640_SUPPORT
#include "ov2640.h"
@@ -46,6 +45,15 @@
#if CONFIG_OV7670_SUPPORT
#include "ov7670.h"
#endif
+#if CONFIG_GC2145_SUPPORT
+#include "gc2145.h"
+#endif
+#if CONFIG_GC032A_SUPPORT
+#include "gc032a.h"
+#endif
+#if CONFIG_GC0308_SUPPORT
+#include "gc0308.h"
+#endif
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
@@ -61,8 +69,8 @@ typedef struct {
camera_fb_t fb;
} camera_state_t;
-static const char* CAMERA_SENSOR_NVS_KEY = "sensor";
-static const char* CAMERA_PIXFORMAT_NVS_KEY = "pixformat";
+static const char *CAMERA_SENSOR_NVS_KEY = "sensor";
+static const char *CAMERA_PIXFORMAT_NVS_KEY = "pixformat";
static camera_state_t *s_state = NULL;
#if CONFIG_IDF_TARGET_ESP32S3 // LCD_CAM module of ESP32-S3 will generate xclk
@@ -73,6 +81,41 @@ static camera_state_t *s_state = NULL;
#define CAMERA_DISABLE_OUT_CLOCK() camera_disable_out_clock()
#endif
+typedef struct {
+ int (*detect)(int slv_addr, sensor_id_t *id);
+ int (*init)(sensor_t *sensor);
+} sensor_func_t;
+
+static const sensor_func_t g_sensors[] = {
+#if CONFIG_OV7725_SUPPORT
+ {ov7725_detect, ov7725_init},
+#endif
+#if CONFIG_OV7670_SUPPORT
+ {ov7670_detect, ov7670_init},
+#endif
+#if CONFIG_OV2640_SUPPORT
+ {ov2640_detect, ov2640_init},
+#endif
+#if CONFIG_OV3660_SUPPORT
+ {ov3660_detect, ov3660_init},
+#endif
+#if CONFIG_OV5640_SUPPORT
+ {ov5640_detect, ov5640_init},
+#endif
+#if CONFIG_NT99141_SUPPORT
+ {nt99141_detect, nt99141_init},
+#endif
+#if CONFIG_GC2145_SUPPORT
+ {gc2145_detect, gc2145_init},
+#endif
+#if CONFIG_GC032A_SUPPORT
+ {gc032a_detect, gc032a_init},
+#endif
+#if CONFIG_GC0308_SUPPORT
+ {gc0308_detect, gc0308_init},
+#endif
+};
+
static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out_camera_model)
{
*out_camera_model = CAMERA_NONE;
@@ -138,86 +181,38 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
s_state->sensor.xclk_freq_hz = config->xclk_freq_hz;
/**
- * Read sensor ID
+ * Read sensor ID and then initialize sensor
+ * Attention: Some sensors have the same SCCB address. Therefore, several attempts may be made in the detection process
*/
sensor_id_t *id = &s_state->sensor.id;
-
- if (slv_addr == OV2640_SCCB_ADDR || slv_addr == OV7725_SCCB_ADDR) {
- SCCB_Write(slv_addr, 0xFF, 0x01);//bank sensor
- id->PID = SCCB_Read(slv_addr, REG_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);
- } else if (slv_addr == OV5640_SCCB_ADDR || slv_addr == OV3660_SCCB_ADDR) {
- id->PID = SCCB_Read16(slv_addr, REG16_CHIDH);
- id->VER = SCCB_Read16(slv_addr, REG16_CHIDL);
- } else if (slv_addr == NT99141_SCCB_ADDR) {
- SCCB_Write16(slv_addr, 0x3008, 0x01);//bank sensor
- id->PID = SCCB_Read16(slv_addr, 0x3000);
- id->VER = SCCB_Read16(slv_addr, 0x3001);
- if (config->xclk_freq_hz > 10000000) {
- ESP_LOGE(TAG, "NT99141: only XCLK under 10MHz is supported, and XCLK is now set to 10M");
- s_state->sensor.xclk_freq_hz = 10000000;
+ for (size_t i = 0; i < sizeof(g_sensors) / sizeof(sensor_func_t); i++) {
+ if (g_sensors[i].detect(slv_addr, id)) {
+ camera_sensor_info_t *info = esp_camera_sensor_get_info(id);
+ if (NULL != info) {
+ *out_camera_model = info->model;
+ ESP_LOGI(TAG, "Detected %s camera", info->name);
+ g_sensors[i].init(&s_state->sensor);
+ break;
+ }
}
}
- vTaskDelay(10 / portTICK_PERIOD_MS);
- ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
- id->PID, id->VER, id->MIDH, id->MIDL);
- /**
- * Initialize sensor according to sensor ID
- */
- switch (id->PID) {
-#if CONFIG_OV2640_SUPPORT
- case OV2640_PID:
- *out_camera_model = CAMERA_OV2640;
- ov2640_init(&s_state->sensor);
- break;
-#endif
-#if CONFIG_OV7725_SUPPORT
- case OV7725_PID:
- *out_camera_model = CAMERA_OV7725;
- ov7725_init(&s_state->sensor);
- break;
-#endif
-#if CONFIG_OV3660_SUPPORT
- case OV3660_PID:
- *out_camera_model = CAMERA_OV3660;
- ov3660_init(&s_state->sensor);
- break;
-#endif
-#if CONFIG_OV5640_SUPPORT
- case OV5640_PID:
- *out_camera_model = CAMERA_OV5640;
- ov5640_init(&s_state->sensor);
- break;
-#endif
-#if CONFIG_OV7670_SUPPORT
- case OV7670_PID:
- *out_camera_model = CAMERA_OV7670;
- ov7670_init(&s_state->sensor);
- break;
-#endif
-#if CONFIG_NT99141_SUPPORT
- case NT99141_PID:
- *out_camera_model = CAMERA_NT99141;
- NT99141_init(&s_state->sensor);
- break;
-#endif
- default:
- id->PID = 0;
+ if (CAMERA_NONE == *out_camera_model) { //If no supported sensors are detected
CAMERA_DISABLE_OUT_CLOCK();
ESP_LOGE(TAG, "Detected camera not supported.");
return ESP_ERR_NOT_SUPPORTED;
}
+ ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
+ id->PID, id->VER, id->MIDH, id->MIDL);
+
ESP_LOGD(TAG, "Doing SW reset of sensor");
+ vTaskDelay(10 / portTICK_PERIOD_MS);
s_state->sensor.reset(&s_state->sensor);
return ESP_OK;
}
-
esp_err_t esp_camera_init(const camera_config_t *config)
{
esp_err_t err;
@@ -233,28 +228,18 @@ esp_err_t esp_camera_init(const camera_config_t *config)
ESP_LOGE(TAG, "Camera probe failed with error 0x%x(%s)", err, esp_err_to_name(err));
goto fail;
}
- if (camera_model == CAMERA_OV7725) {
- ESP_LOGI(TAG, "Detected OV7725 camera");
- } else if (camera_model == CAMERA_OV2640) {
- ESP_LOGI(TAG, "Detected OV2640 camera");
- } else if (camera_model == CAMERA_OV3660) {
- ESP_LOGI(TAG, "Detected OV3660 camera");
- } else if (camera_model == CAMERA_OV5640) {
- ESP_LOGI(TAG, "Detected OV5640 camera");
- } else if (camera_model == CAMERA_OV7670) {
- ESP_LOGI(TAG, "Detected OV7670 camera");
- } else if (camera_model == CAMERA_NT99141) {
- ESP_LOGI(TAG, "Detected NT99141 camera");
- } else {
- ESP_LOGI(TAG, "Camera not supported");
- err = ESP_ERR_CAMERA_NOT_SUPPORTED;
- goto fail;
- }
framesize_t frame_size = (framesize_t) config->frame_size;
pixformat_t pix_format = (pixformat_t) config->pixel_format;
+ if (PIXFORMAT_JPEG == pix_format && (!camera_sensor[camera_model].support_jpeg)) {
+ ESP_LOGE(TAG, "JPEG format is not supported on this sensor");
+ err = ESP_ERR_NOT_SUPPORTED;
+ goto fail;
+ }
+
if (frame_size > camera_sensor[camera_model].max_size) {
+ ESP_LOGW(TAG, "The frame size exceeds the maximum for this sensor, it will be forced to the maximum possible value");
frame_size = camera_sensor[camera_model].max_size;
}
@@ -266,7 +251,7 @@ esp_err_t esp_camera_init(const camera_config_t *config)
s_state->sensor.status.framesize = frame_size;
s_state->sensor.pixformat = pix_format;
- // ESP_LOGD(TAG, "Setting frame size to %dx%d", s_state->width, s_state->height);
+ ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height);
if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
ESP_LOGE(TAG, "Failed to set frame size");
err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE;
@@ -282,7 +267,7 @@ esp_err_t esp_camera_init(const camera_config_t *config)
}
if (pix_format == PIXFORMAT_JPEG) {
- (*s_state->sensor.set_quality)(&s_state->sensor, config->jpeg_quality);
+ s_state->sensor.set_quality(&s_state->sensor, config->jpeg_quality);
}
s_state->sensor.init_status(&s_state->sensor);
@@ -291,7 +276,6 @@ esp_err_t esp_camera_init(const camera_config_t *config)
return ESP_OK;
fail:
- CAMERA_DISABLE_OUT_CLOCK();
esp_camera_deinit();
return err;
}
@@ -299,13 +283,14 @@ fail:
esp_err_t esp_camera_deinit()
{
esp_err_t ret = cam_deinit();
+ CAMERA_DISABLE_OUT_CLOCK();
if (s_state) {
SCCB_Deinit();
free(s_state);
s_state = NULL;
}
-
+
return ret;
}
@@ -342,26 +327,26 @@ sensor_t *esp_camera_sensor_get()
return &s_state->sensor;
}
-esp_err_t esp_camera_save_to_nvs(const char *key)
+esp_err_t esp_camera_save_to_nvs(const char *key)
{
#if ESP_IDF_VERSION_MAJOR > 3
nvs_handle_t handle;
#else
nvs_handle handle;
#endif
- esp_err_t ret = nvs_open(key,NVS_READWRITE,&handle);
-
+ esp_err_t ret = nvs_open(key, NVS_READWRITE, &handle);
+
if (ret == ESP_OK) {
sensor_t *s = esp_camera_sensor_get();
if (s != NULL) {
- ret = nvs_set_blob(handle,CAMERA_SENSOR_NVS_KEY,&s->status,sizeof(camera_status_t));
+ ret = nvs_set_blob(handle, CAMERA_SENSOR_NVS_KEY, &s->status, sizeof(camera_status_t));
if (ret == ESP_OK) {
uint8_t pf = s->pixformat;
- ret = nvs_set_u8(handle,CAMERA_PIXFORMAT_NVS_KEY,pf);
+ ret = nvs_set_u8(handle, CAMERA_PIXFORMAT_NVS_KEY, pf);
}
return ret;
} else {
- return ESP_ERR_CAMERA_NOT_DETECTED;
+ return ESP_ERR_CAMERA_NOT_DETECTED;
}
nvs_close(handle);
return ret;
@@ -370,62 +355,62 @@ esp_err_t esp_camera_save_to_nvs(const char *key)
}
}
-esp_err_t esp_camera_load_from_nvs(const char *key)
+esp_err_t esp_camera_load_from_nvs(const char *key)
{
#if ESP_IDF_VERSION_MAJOR > 3
nvs_handle_t handle;
#else
nvs_handle handle;
#endif
- uint8_t pf;
-
- esp_err_t ret = nvs_open(key,NVS_READWRITE,&handle);
-
- if (ret == ESP_OK) {
- sensor_t *s = esp_camera_sensor_get();
- camera_status_t st;
- if (s != NULL) {
- size_t size = sizeof(camera_status_t);
- ret = nvs_get_blob(handle,CAMERA_SENSOR_NVS_KEY,&st,&size);
- if (ret == ESP_OK) {
- s->set_ae_level(s,st.ae_level);
- s->set_aec2(s,st.aec2);
- s->set_aec_value(s,st.aec_value);
- s->set_agc_gain(s,st.agc_gain);
- s->set_awb_gain(s,st.awb_gain);
- s->set_bpc(s,st.bpc);
- s->set_brightness(s,st.brightness);
- s->set_colorbar(s,st.colorbar);
- s->set_contrast(s,st.contrast);
- s->set_dcw(s,st.dcw);
- s->set_denoise(s,st.denoise);
- s->set_exposure_ctrl(s,st.aec);
- s->set_framesize(s,st.framesize);
- s->set_gain_ctrl(s,st.agc);
- s->set_gainceiling(s,st.gainceiling);
- s->set_hmirror(s,st.hmirror);
- s->set_lenc(s,st.lenc);
- s->set_quality(s,st.quality);
- s->set_raw_gma(s,st.raw_gma);
- s->set_saturation(s,st.saturation);
- s->set_sharpness(s,st.sharpness);
- s->set_special_effect(s,st.special_effect);
- s->set_vflip(s,st.vflip);
- s->set_wb_mode(s,st.wb_mode);
- s->set_whitebal(s,st.awb);
- s->set_wpc(s,st.wpc);
- }
- ret = nvs_get_u8(handle,CAMERA_PIXFORMAT_NVS_KEY,&pf);
- if (ret == ESP_OK) {
- s->set_pixformat(s,pf);
+ uint8_t pf;
+
+ esp_err_t ret = nvs_open(key, NVS_READWRITE, &handle);
+
+ if (ret == ESP_OK) {
+ sensor_t *s = esp_camera_sensor_get();
+ camera_status_t st;
+ if (s != NULL) {
+ size_t size = sizeof(camera_status_t);
+ ret = nvs_get_blob(handle, CAMERA_SENSOR_NVS_KEY, &st, &size);
+ if (ret == ESP_OK) {
+ s->set_ae_level(s, st.ae_level);
+ s->set_aec2(s, st.aec2);
+ s->set_aec_value(s, st.aec_value);
+ s->set_agc_gain(s, st.agc_gain);
+ s->set_awb_gain(s, st.awb_gain);
+ s->set_bpc(s, st.bpc);
+ s->set_brightness(s, st.brightness);
+ s->set_colorbar(s, st.colorbar);
+ s->set_contrast(s, st.contrast);
+ s->set_dcw(s, st.dcw);
+ s->set_denoise(s, st.denoise);
+ s->set_exposure_ctrl(s, st.aec);
+ s->set_framesize(s, st.framesize);
+ s->set_gain_ctrl(s, st.agc);
+ s->set_gainceiling(s, st.gainceiling);
+ s->set_hmirror(s, st.hmirror);
+ s->set_lenc(s, st.lenc);
+ s->set_quality(s, st.quality);
+ s->set_raw_gma(s, st.raw_gma);
+ s->set_saturation(s, st.saturation);
+ s->set_sharpness(s, st.sharpness);
+ s->set_special_effect(s, st.special_effect);
+ s->set_vflip(s, st.vflip);
+ s->set_wb_mode(s, st.wb_mode);
+ s->set_whitebal(s, st.awb);
+ s->set_wpc(s, st.wpc);
+ }
+ ret = nvs_get_u8(handle, CAMERA_PIXFORMAT_NVS_KEY, &pf);
+ if (ret == ESP_OK) {
+ s->set_pixformat(s, pf);
+ }
+ } else {
+ return ESP_ERR_CAMERA_NOT_DETECTED;
}
- } else {
- return ESP_ERR_CAMERA_NOT_DETECTED;
- }
- nvs_close(handle);
- return ret;
- } else {
- ESP_LOGW(TAG,"Error (%d) opening nvs key \"%s\"",ret,key);
- return ret;
- }
+ nvs_close(handle);
+ return ret;
+ } else {
+ ESP_LOGW(TAG, "Error (%d) opening nvs key \"%s\"", ret, key);
+ return ret;
+ }
}
diff --git a/driver/include/sensor.h b/driver/include/sensor.h
index c8931de..1f99c15 100755
--- a/driver/include/sensor.h
+++ b/driver/include/sensor.h
@@ -11,23 +11,21 @@
#include
#include
-// Chip ID Registers
-#define REG_PID 0x0A
-#define REG_VER 0x0B
-#define REG_MIDH 0x1C
-#define REG_MIDL 0x1D
-
-#define REG16_CHIDH 0x300A
-#define REG16_CHIDL 0x300B
+#ifdef __cplusplus
+extern "C" {
+#endif
typedef enum {
OV9650_PID = 0x96,
OV7725_PID = 0x77,
OV2640_PID = 0x26,
- OV3660_PID = 0x36,
- OV5640_PID = 0x56,
+ OV3660_PID = 0x3660,
+ OV5640_PID = 0x5640,
OV7670_PID = 0x76,
- NT99141_PID = 0x14
+ NT99141_PID = 0x1410,
+ GC2145_PID = 0x2145,
+ GC032A_PID = 0x232a,
+ GC0308_PID = 0x9b,
} camera_pid_t;
typedef enum {
@@ -37,18 +35,23 @@ typedef enum {
CAMERA_OV5640,
CAMERA_OV7670,
CAMERA_NT99141,
+ CAMERA_GC2145,
+ CAMERA_GC032A,
+ CAMERA_GC0308,
CAMERA_MODEL_MAX,
CAMERA_NONE,
- CAMERA_UNKNOWN
} camera_model_t;
typedef enum {
- OV2640_SCCB_ADDR = 0x30,
- OV5640_SCCB_ADDR = 0x3C,
- OV3660_SCCB_ADDR = 0x3C,
- OV7725_SCCB_ADDR = 0x21,
- OV7670_SCCB_ADDR = 0x21,
- NT99141_SCCB_ADDR = 0x2A,
+ OV2640_SCCB_ADDR = 0x30,// 0x60 >> 1
+ OV5640_SCCB_ADDR = 0x3C,// 0x78 >> 1
+ OV3660_SCCB_ADDR = 0x3C,// 0x78 >> 1
+ OV7725_SCCB_ADDR = 0x21,// 0x42 >> 1
+ OV7670_SCCB_ADDR = 0x21,// 0x42 >> 1
+ NT99141_SCCB_ADDR = 0x2A,// 0x54 >> 1
+ GC2145_SCCB_ADDR = 0x3C,// 0x78 >> 1
+ GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
+ GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
} camera_sccb_addr_t;
typedef enum {
@@ -92,6 +95,7 @@ typedef enum {
typedef struct {
const camera_model_t model;
+ const char *name;
const camera_sccb_addr_t sccb_addr;
const camera_pid_t pid;
const framesize_t max_size;
@@ -147,7 +151,7 @@ extern const camera_sensor_info_t camera_sensor[];
typedef struct {
uint8_t MIDH;
uint8_t MIDL;
- uint8_t PID;
+ uint16_t PID;
uint8_t VER;
} sensor_id_t;
@@ -232,4 +236,10 @@ typedef struct _sensor {
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
} sensor_t;
+camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif /* __SENSOR_H__ */
diff --git a/driver/private_include/camera_common.h b/driver/private_include/camera_common.h
deleted file mode 100755
index bdc24d2..0000000
--- a/driver/private_include/camera_common.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include "esp_err.h"
-#include "esp_intr_alloc.h"
-#include "freertos/FreeRTOS.h"
-#include "freertos/semphr.h"
-#include "freertos/task.h"
-#include "esp_camera.h"
-#include "sensor.h"
-
-#include "esp_system.h"
-#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
-#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
-#include "esp32/rom/lldesc.h"
-#elif CONFIG_IDF_TARGET_ESP32S2 // ESP32-S2
-#include "esp32s2/rom/lldesc.h"
-#elif CONFIG_IDF_TARGET_ESP32S3 // ESP32-S3
-#include "esp32s3/rom/lldesc.h"
-#else
-#error Target CONFIG_IDF_TARGET is not supported
-#endif
-#else // ESP32 Before IDF 4.0
-#include "rom/lldesc.h"
-#endif
-
diff --git a/driver/private_include/xclk.h b/driver/private_include/xclk.h
index 15ed736..3d721a6 100755
--- a/driver/private_include/xclk.h
+++ b/driver/private_include/xclk.h
@@ -1,6 +1,8 @@
#pragma once
-#include "camera_common.h"
+#include "esp_system.h"
+
+esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz);
esp_err_t camera_enable_out_clock();
diff --git a/driver/sensor.c b/driver/sensor.c
index d9e3b10..7ebd7af 100644
--- a/driver/sensor.c
+++ b/driver/sensor.c
@@ -1,13 +1,17 @@
+#include
#include "sensor.h"
const camera_sensor_info_t camera_sensor[CAMERA_MODEL_MAX] = {
// The sequence must be consistent with camera_model_t
- {CAMERA_OV7725, OV7725_SCCB_ADDR, OV7725_PID, FRAMESIZE_VGA, false},
- {CAMERA_OV2640, OV2640_SCCB_ADDR, OV2640_PID, FRAMESIZE_UXGA, true},
- {CAMERA_OV3660, OV3660_SCCB_ADDR, OV3660_PID, FRAMESIZE_QXGA, true},
- {CAMERA_OV5640, OV5640_SCCB_ADDR, OV5640_PID, FRAMESIZE_QSXGA, true},
- {CAMERA_OV7670, OV7670_SCCB_ADDR, OV7670_PID, FRAMESIZE_VGA, false},
- {CAMERA_NT99141, NT99141_SCCB_ADDR, NT99141_PID, FRAMESIZE_HD, true},
+ {CAMERA_OV7725, "OV7725", OV7725_SCCB_ADDR, OV7725_PID, FRAMESIZE_VGA, false},
+ {CAMERA_OV2640, "OV2640", OV2640_SCCB_ADDR, OV2640_PID, FRAMESIZE_UXGA, true},
+ {CAMERA_OV3660, "OV3660", OV3660_SCCB_ADDR, OV3660_PID, FRAMESIZE_QXGA, true},
+ {CAMERA_OV5640, "OV5640", OV5640_SCCB_ADDR, OV5640_PID, FRAMESIZE_QSXGA, true},
+ {CAMERA_OV7670, "OV7670", OV7670_SCCB_ADDR, OV7670_PID, FRAMESIZE_VGA, false},
+ {CAMERA_NT99141, "NT99141", NT99141_SCCB_ADDR, NT99141_PID, FRAMESIZE_HD, true},
+ {CAMERA_GC2145, "GC2145", GC2145_SCCB_ADDR, GC2145_PID, FRAMESIZE_UXGA, false},
+ {CAMERA_GC032A, "GC032A", GC032A_SCCB_ADDR, GC032A_PID, FRAMESIZE_VGA, false},
+ {CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false},
};
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
@@ -36,3 +40,13 @@ const resolution_info_t resolution[FRAMESIZE_INVALID] = {
{ 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */
{ 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */
};
+
+camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id)
+{
+ for (int i = 0; i < CAMERA_MODEL_MAX; i++) {
+ if (id->PID == camera_sensor[i].pid) {
+ return (camera_sensor_info_t *)&camera_sensor[i];
+ }
+ }
+ return NULL;
+}
diff --git a/examples/take_picture.c b/examples/take_picture.c
index 96b224f..fc4ae7a 100644
--- a/examples/take_picture.c
+++ b/examples/take_picture.c
@@ -117,7 +117,8 @@ static camera_config_t camera_config = {
.frame_size = FRAMESIZE_VGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 12, //0-63 lower number means higher quality
- .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
+ .fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
+ .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
};
static esp_err_t init_camera()
@@ -144,6 +145,7 @@ void app_main()
// use pic->buf to access the image
ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
+ esp_camera_fb_return(pic);
vTaskDelay(5000 / portTICK_RATE_MS);
}
diff --git a/sensors/gc0308.c b/sensors/gc0308.c
new file mode 100644
index 0000000..19064d3
--- /dev/null
+++ b/sensors/gc0308.c
@@ -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
+#include
+#include
+#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;
+}
diff --git a/sensors/gc032a.c b/sensors/gc032a.c
new file mode 100644
index 0000000..612e17b
--- /dev/null
+++ b/sensors/gc032a.c
@@ -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
+#include
+#include
+#include
+#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;
+}
diff --git a/sensors/gc2145.c b/sensors/gc2145.c
new file mode 100644
index 0000000..3113082
--- /dev/null
+++ b/sensors/gc2145.c
@@ -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
+#include
+#include
+#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;
+}
diff --git a/sensors/nt99141.c b/sensors/nt99141.c
index 450780b..86a8b8a 100644
--- a/sensors/nt99141.c
+++ b/sensors/nt99141.c
@@ -10,6 +10,7 @@
#include
#include
#include "sccb.h"
+#include "xclk.h"
#include "nt99141.h"
#include "nt99141_regs.h"
#include "nt99141_settings.h"
@@ -920,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;
@@ -934,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;
@@ -964,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;
diff --git a/sensors/ov2640.c b/sensors/ov2640.c
index e96d4c2..6d5dfc6 100755
--- a/sensors/ov2640.c
+++ b/sensors/ov2640.c
@@ -10,6 +10,7 @@
#include
#include
#include "sccb.h"
+#include "xclk.h"
#include "ov2640.h"
#include "ov2640_regs.h"
#include "ov2640_settings.h"
@@ -494,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;
@@ -545,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;
diff --git a/sensors/ov3660.c b/sensors/ov3660.c
index 59393b7..b9ebdba 100755
--- a/sensors/ov3660.c
+++ b/sensors/ov3660.c
@@ -10,6 +10,7 @@
#include
#include
#include "sccb.h"
+#include "xclk.h"
#include "ov3660.h"
#include "ov3660_regs.h"
#include "ov3660_settings.h"
@@ -957,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;
@@ -996,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;
diff --git a/sensors/ov5640.c b/sensors/ov5640.c
index a9ab2a8..a32b374 100755
--- a/sensors/ov5640.c
+++ b/sensors/ov5640.c
@@ -10,6 +10,7 @@
#include
#include
#include "sccb.h"
+#include "xclk.h"
#include "ov5640.h"
#include "ov5640_regs.h"
#include "ov5640_settings.h"
@@ -1034,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;
@@ -1073,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;
diff --git a/sensors/ov7670.c b/sensors/ov7670.c
index 285fe13..b9dcf23 100644
--- a/sensors/ov7670.c
+++ b/sensors/ov7670.c
@@ -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
diff --git a/sensors/ov7725.c b/sensors/ov7725.c
index bb31573..ad5d895 100755
--- a/sensors/ov7725.c
+++ b/sensors/ov7725.c
@@ -11,6 +11,7 @@
#include
#include
#include "sccb.h"
+#include "xclk.h"
#include "ov7725.h"
#include "ov7725_regs.h"
#include "freertos/FreeRTOS.h"
@@ -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
diff --git a/sensors/private_include/gc0308.h b/sensors/private_include/gc0308.h
new file mode 100644
index 0000000..edffca1
--- /dev/null
+++ b/sensors/private_include/gc0308.h
@@ -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
diff --git a/sensors/private_include/gc0308_regs.h b/sensors/private_include/gc0308_regs.h
new file mode 100644
index 0000000..f1cb453
--- /dev/null
+++ b/sensors/private_include/gc0308_regs.h
@@ -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__
diff --git a/sensors/private_include/gc0308_settings.h b/sensors/private_include/gc0308_settings.h
new file mode 100644
index 0000000..32ef381
--- /dev/null
+++ b/sensors/private_include/gc0308_settings.h
@@ -0,0 +1,245 @@
+#ifndef _GC0308_SETTINGS_H_
+#define _GC0308_SETTINGS_H_
+
+#include
+
+#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
diff --git a/sensors/private_include/gc032a.h b/sensors/private_include/gc032a.h
new file mode 100644
index 0000000..7679f07
--- /dev/null
+++ b/sensors/private_include/gc032a.h
@@ -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__
diff --git a/sensors/private_include/gc032a_regs.h b/sensors/private_include/gc032a_regs.h
new file mode 100644
index 0000000..5de59d1
--- /dev/null
+++ b/sensors/private_include/gc032a_regs.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__
diff --git a/sensors/private_include/gc032a_settings.h b/sensors/private_include/gc032a_settings.h
new file mode 100644
index 0000000..a19ffc7
--- /dev/null
+++ b/sensors/private_include/gc032a_settings.h
@@ -0,0 +1,401 @@
+#ifndef _GC032A_SETTINGS_H_
+#define _GC032A_SETTINGS_H_
+
+#include
+#include
+#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
diff --git a/sensors/private_include/gc2145.h b/sensors/private_include/gc2145.h
new file mode 100644
index 0000000..6c5b60f
--- /dev/null
+++ b/sensors/private_include/gc2145.h
@@ -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__
diff --git a/sensors/private_include/gc2145_regs.h b/sensors/private_include/gc2145_regs.h
new file mode 100644
index 0000000..b034a16
--- /dev/null
+++ b/sensors/private_include/gc2145_regs.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__
diff --git a/sensors/private_include/gc2145_settings.h b/sensors/private_include/gc2145_settings.h
new file mode 100644
index 0000000..879fd53
--- /dev/null
+++ b/sensors/private_include/gc2145_settings.h
@@ -0,0 +1,719 @@
+
+#include
+
+#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},
+};
diff --git a/sensors/private_include/nt99141.h b/sensors/private_include/nt99141.h
index 287a742..8b0c562 100644
--- a/sensors/private_include/nt99141.h
+++ b/sensors/private_include/nt99141.h
@@ -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__
diff --git a/sensors/private_include/ov2640.h b/sensors/private_include/ov2640.h
index a890499..342ab21 100755
--- a/sensors/private_include/ov2640.h
+++ b/sensors/private_include/ov2640.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__
diff --git a/sensors/private_include/ov2640_regs.h b/sensors/private_include/ov2640_regs.h
index eb096b4..8f47333 100755
--- a/sensors/private_include/ov2640_regs.h
+++ b/sensors/private_include/ov2640_regs.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
diff --git a/sensors/private_include/ov3660.h b/sensors/private_include/ov3660.h
index 8e5ae3c..341d688 100755
--- a/sensors/private_include/ov3660.h
+++ b/sensors/private_include/ov3660.h
@@ -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__
diff --git a/sensors/private_include/ov5640.h b/sensors/private_include/ov5640.h
index 7b572ad..120ae72 100755
--- a/sensors/private_include/ov5640.h
+++ b/sensors/private_include/ov5640.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__
diff --git a/sensors/private_include/ov7670.h b/sensors/private_include/ov7670.h
index cdf845c..b3a645a 100644
--- a/sensors/private_include/ov7670.h
+++ b/sensors/private_include/ov7670.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__
diff --git a/sensors/private_include/ov7725.h b/sensors/private_include/ov7725.h
index f8c3516..291b266 100755
--- a/sensors/private_include/ov7725.h
+++ b/sensors/private_include/ov7725.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__
diff --git a/target/esp32/ll_cam.c b/target/esp32/ll_cam.c
index f7e9e85..33a0dad 100644
--- a/target/esp32/ll_cam.c
+++ b/target/esp32/ll_cam.c
@@ -196,7 +196,7 @@ static void IRAM_ATTR ll_cam_vsync_isr(void *arg)
cam_obj_t *cam = (cam_obj_t *)arg;
BaseType_t HPTaskAwoken = pdFALSE;
// filter
- esp_rom_delay_us(1);
+ ets_delay_us(1);
if (gpio_ll_get_level(&GPIO, cam->vsync_pin) == !cam->vsync_invert) {
ll_cam_send_event(cam, CAM_VSYNC_EVENT, &HPTaskAwoken);
if (HPTaskAwoken == pdTRUE) {
@@ -382,13 +382,13 @@ uint8_t ll_cam_get_dma_align(cam_obj_t *cam)
}
static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
- size_t dma_half_buffer_max = 16 * 1024 / cam->dma_bytes_per_item;
+ size_t dma_half_buffer_max = CONFIG_CAMERA_DMA_BUFFER_SIZE_MAX / 2 / cam->dma_bytes_per_item;
size_t dma_buffer_max = 2 * dma_half_buffer_max;
size_t node_max = LCD_CAM_DMA_NODE_BUFFER_MAX_SIZE / cam->dma_bytes_per_item;
size_t line_width = cam->width * cam->in_bytes_per_pixel;
size_t image_size = cam->height * line_width;
- if (image_size > (2 * 1024 * 1024) || (line_width > dma_half_buffer_max)) {
+ if (image_size > (4 * 1024 * 1024) || (line_width > dma_half_buffer_max)) {
ESP_LOGE(TAG, "Resolution too high");
return 0;
}
@@ -472,7 +472,7 @@ size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in,
return r;
}
-esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint8_t sensor_pid)
+esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid)
{
if (pix_format == PIXFORMAT_GRAYSCALE) {
if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID) {
@@ -510,10 +510,6 @@ esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_
cam->in_bytes_per_pixel = 2; // camera sends YU/YV
cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
} else if (pix_format == PIXFORMAT_JPEG) {
- if (sensor_pid != OV2640_PID && sensor_pid != OV3660_PID && sensor_pid != OV5640_PID && sensor_pid != NT99141_PID) {
- ESP_LOGE(TAG, "JPEG format is not supported on this sensor");
- return ESP_ERR_NOT_SUPPORTED;
- }
cam->in_bytes_per_pixel = 1;
cam->fb_bytes_per_pixel = 1;
dma_filter = ll_cam_dma_filter_jpeg;
diff --git a/target/esp32s2/ll_cam.c b/target/esp32s2/ll_cam.c
index 4ad2baa..d3cb535 100644
--- a/target/esp32s2/ll_cam.c
+++ b/target/esp32s2/ll_cam.c
@@ -303,7 +303,7 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
cam->dma_half_buffer_cnt = 2;
cam->dma_half_buffer_size = cam->dma_buffer_size / cam->dma_half_buffer_cnt;
} else {
- size_t dma_half_buffer_max = 16 * 1024 / cam->dma_bytes_per_item;
+ size_t dma_half_buffer_max = CONFIG_CAMERA_DMA_BUFFER_SIZE_MAX / 2 / cam->dma_bytes_per_item;
if (line_width > dma_half_buffer_max) {
ESP_LOGE(TAG, "Resolution too high");
return 0;
@@ -358,7 +358,7 @@ bool ll_cam_dma_sizes(cam_obj_t *cam)
return 1;
}
-size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len)
+size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len)
{
// YUV to Grayscale
if (cam->in_bytes_per_pixel == 2 && cam->fb_bytes_per_pixel == 1) {
@@ -379,7 +379,7 @@ size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len
return len;
}
-esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint8_t sensor_pid)
+esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid)
{
if (pix_format == PIXFORMAT_GRAYSCALE) {
if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID) {
@@ -392,10 +392,6 @@ esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_
cam->in_bytes_per_pixel = 2; // camera sends YU/YV
cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
} else if (pix_format == PIXFORMAT_JPEG) {
- if (sensor_pid != OV2640_PID && sensor_pid != OV3660_PID && sensor_pid != OV5640_PID && sensor_pid != NT99141_PID) {
- ESP_LOGE(TAG, "JPEG format is not supported on this sensor");
- return ESP_ERR_NOT_SUPPORTED;
- }
cam->in_bytes_per_pixel = 1;
cam->fb_bytes_per_pixel = 1;
} else {
diff --git a/target/esp32s3/ll_cam.c b/target/esp32s3/ll_cam.c
index 9d154a2..2190134 100644
--- a/target/esp32s3/ll_cam.c
+++ b/target/esp32s3/ll_cam.c
@@ -319,7 +319,7 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item;
- size_t dma_half_buffer_max = 16 * 1024 / cam->dma_bytes_per_item;
+ size_t dma_half_buffer_max = CONFIG_CAMERA_DMA_BUFFER_SIZE_MAX / 2 / cam->dma_bytes_per_item;
if (line_width > dma_half_buffer_max) {
ESP_LOGE(TAG, "Resolution too high");
return 0;
@@ -378,7 +378,7 @@ bool ll_cam_dma_sizes(cam_obj_t *cam)
return 1;
}
-size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len)
+size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len)
{
// YUV to Grayscale
if (cam->in_bytes_per_pixel == 2 && cam->fb_bytes_per_pixel == 1) {
@@ -399,7 +399,7 @@ size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len
return len;
}
-esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint8_t sensor_pid)
+esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid)
{
if (pix_format == PIXFORMAT_GRAYSCALE) {
if (sensor_pid == OV3660_PID || sensor_pid == OV5640_PID || sensor_pid == NT99141_PID) {
@@ -412,10 +412,6 @@ esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_
cam->in_bytes_per_pixel = 2; // camera sends YU/YV
cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
} else if (pix_format == PIXFORMAT_JPEG) {
- if (sensor_pid != OV2640_PID && sensor_pid != OV3660_PID && sensor_pid != OV5640_PID && sensor_pid != NT99141_PID) {
- ESP_LOGE(TAG, "JPEG format is not supported on this sensor");
- return ESP_ERR_NOT_SUPPORTED;
- }
cam->in_bytes_per_pixel = 1;
cam->fb_bytes_per_pixel = 1;
} else {
diff --git a/target/private_include/ll_cam.h b/target/private_include/ll_cam.h
index 60ed459..85798a7 100644
--- a/target/private_include/ll_cam.h
+++ b/target/private_include/ll_cam.h
@@ -29,7 +29,6 @@
#endif
#include "esp_log.h"
#include "esp_camera.h"
-#include "camera_common.h"
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "freertos/task.h"
@@ -130,8 +129,8 @@ esp_err_t ll_cam_init_isr(cam_obj_t *cam);
void ll_cam_do_vsync(cam_obj_t *cam);
uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
bool ll_cam_dma_sizes(cam_obj_t *cam);
-size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
-esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint8_t sensor_pid);
+size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
+esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid);
// implemented in cam_hal
void ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType_t * HPTaskAwoken);
diff --git a/target/xclk.c b/target/xclk.c
index 872067b..b5ea53e 100755
--- a/target/xclk.c
+++ b/target/xclk.c
@@ -4,6 +4,7 @@
#include "esp_log.h"
#include "esp_system.h"
#include "xclk.h"
+#include "esp_camera.h"
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
#include "esp32-hal-log.h"
@@ -12,16 +13,15 @@
static const char* TAG = "camera_xclk";
#endif
+static ledc_channel_t g_ledc_channel = 0;
+
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
{
ledc_timer_config_t timer_conf;
timer_conf.duty_resolution = LEDC_TIMER_1_BIT;
timer_conf.freq_hz = xclk_freq_hz;
-#if CONFIG_IDF_TARGET_ESP32
- timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
-#else
timer_conf.speed_mode = LEDC_LOW_SPEED_MODE;
-#endif
+
#if ESP_IDF_VERSION_MAJOR >= 4
timer_conf.clk_cfg = LEDC_AUTO_CLK;
#endif
@@ -35,21 +35,16 @@ esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
esp_err_t camera_enable_out_clock(camera_config_t* config)
{
- periph_module_enable(PERIPH_LEDC_MODULE);
-
esp_err_t err = xclk_timer_conf(config->ledc_timer, config->xclk_freq_hz);
if (err != ESP_OK) {
ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
return err;
}
+ g_ledc_channel = config->ledc_channel;
ledc_channel_config_t ch_conf;
ch_conf.gpio_num = config->pin_xclk;
-#if CONFIG_IDF_TARGET_ESP32
- ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
-#else
ch_conf.speed_mode = LEDC_LOW_SPEED_MODE;
-#endif
ch_conf.channel = config->ledc_channel;
ch_conf.intr_type = LEDC_INTR_DISABLE;
ch_conf.timer_sel = config->ledc_timer;
@@ -65,5 +60,5 @@ esp_err_t camera_enable_out_clock(camera_config_t* config)
void camera_disable_out_clock()
{
- periph_module_disable(PERIPH_LEDC_MODULE);
+ ledc_stop(LEDC_LOW_SPEED_MODE, g_ledc_channel, 0);
}
diff --git a/test/test_camera.c b/test/test_camera.c
index 36d9f25..89ad061 100644
--- a/test/test_camera.c
+++ b/test/test_camera.c
@@ -83,8 +83,8 @@
#elif BOARD_CAMERA_MODEL_ESP32_S3_EYE
-#define PWDN_GPIO_NUM -1
-#define RESET_GPIO_NUM -1
+#define PWDN_GPIO_NUM 43
+#define RESET_GPIO_NUM 44
#define VSYNC_GPIO_NUM 6
#define HREF_GPIO_NUM 7
@@ -197,16 +197,6 @@ static const char *get_cam_format_name(pixformat_t pixel_format)
return "UNKNOW";
}
-static camera_sensor_info_t *get_camera_info_from_pid(uint16_t pid)
-{
- for (size_t i = 0; i < CAMERA_MODEL_MAX; i++) {
- if (pid == camera_sensor[i].pid) {
- return (camera_sensor_info_t *)&camera_sensor[i];
- }
- }
- return NULL;
-}
-
static void printf_img_base64(const camera_fb_t *pic)
{
uint8_t *outbuffer = NULL;
@@ -238,7 +228,7 @@ static void camera_performance_test(uint32_t xclk_freq, uint32_t pic_num)
//detect sensor information
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
sensor_t *s = esp_camera_sensor_get();
- camera_sensor_info_t *info = get_camera_info_from_pid(s->id.PID);
+ camera_sensor_info_t *info = esp_camera_sensor_get_info(&s->id);
TEST_ASSERT_NOT_NULL(info);
TEST_ESP_OK(esp_camera_deinit());
vTaskDelay(500 / portTICK_RATE_MS);
@@ -272,7 +262,7 @@ static void camera_performance_test(uint32_t xclk_freq, uint32_t pic_num)
}
printf("FPS Result\n");
- printf("resolution , JPEG fps, JPEG size, RGB565 fps, RGB565 size, YUV422 fps, YUV422 size \n");
+ printf("resolution , JPEG fps, JPEG size, RGB565 fps, RGB565 size, YUV422 fps, YUV422 size \n");
for (size_t i = 0; i <= max_size; i++) {
printf("%4d x %4d , %5.2f, %6d, %5.2f, %7d, %5.2f, %7d \n",
resolution[i].width, resolution[i].height,
@@ -295,8 +285,24 @@ TEST_CASE("Camera driver init, deinit test", "[camera]")
TEST_CASE("Camera driver take RGB565 picture test", "[camera]")
{
- TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
+ TEST_ESP_OK(init_camera(10000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
+ vTaskDelay(500 / portTICK_RATE_MS);
+ ESP_LOGI(TAG, "Taking picture...");
+ camera_fb_t *pic = esp_camera_fb_get();
+ if (pic) {
+ ESP_LOGI(TAG, "picture: %d x %d, size: %u", pic->width, pic->height, pic->len);
+ printf_img_base64(pic);
+ esp_camera_fb_return(pic);
+ }
+
+ TEST_ESP_OK(esp_camera_deinit());
+ TEST_ASSERT_NOT_NULL(pic);
+}
+TEST_CASE("Camera driver take YUV422 picture test", "[camera]")
+{
+ TEST_ESP_OK(init_camera(10000000, PIXFORMAT_YUV422, FRAMESIZE_QVGA, 2));
+ vTaskDelay(500 / portTICK_RATE_MS);
ESP_LOGI(TAG, "Taking picture...");
camera_fb_t *pic = esp_camera_fb_get();
if (pic) {
@@ -312,7 +318,7 @@ TEST_CASE("Camera driver take RGB565 picture test", "[camera]")
TEST_CASE("Camera driver take JPEG picture test", "[camera]")
{
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2));
-
+ vTaskDelay(500 / portTICK_RATE_MS);
ESP_LOGI(TAG, "Taking picture...");
camera_fb_t *pic = esp_camera_fb_get();
if (pic) {