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) {