Browse Source

Merge pull request #132 from espressif/ov5640

Add support for OV5640
pull/137/head
Me No Dev 5 years ago committed by GitHub
parent
commit
9f99b1b03c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CMakeLists.txt
  2. 13
      Kconfig
  3. 2
      conversions/esp_jpg_decode.c
  4. 2
      conversions/to_jpg.cpp
  5. 97
      driver/camera.c
  6. 1
      driver/include/esp_camera.h
  7. 67
      driver/include/sensor.h
  8. 2
      driver/private_include/camera_common.h
  9. 2
      driver/sccb.c
  10. 41
      driver/sensor.c
  11. 23
      driver/xclk.c
  12. 227
      sensors/ov2640.c
  13. 158
      sensors/ov3660.c
  14. 1105
      sensors/ov5640.c
  15. 4
      sensors/ov7725.c
  16. 55
      sensors/private_include/ov2640_settings.h
  17. 62
      sensors/private_include/ov3660_settings.h
  18. 9
      sensors/private_include/ov5640.h
  19. 213
      sensors/private_include/ov5640_regs.h
  20. 334
      sensors/private_include/ov5640_settings.h

1
CMakeLists.txt

@ -6,6 +6,7 @@ set(COMPONENT_SRCS
driver/xclk.c driver/xclk.c
sensors/ov2640.c sensors/ov2640.c
sensors/ov3660.c sensors/ov3660.c
sensors/ov5640.c
sensors/ov7725.c sensors/ov7725.c
conversions/yuv.c conversions/yuv.c
conversions/to_jpg.cpp conversions/to_jpg.cpp

13
Kconfig

@ -5,21 +5,28 @@ config OV2640_SUPPORT
default y default y
help help
Enable this option if you want to use the OV2640. Enable this option if you want to use the OV2640.
Disable this option to safe memory. Disable this option to save memory.
config OV7725_SUPPORT config OV7725_SUPPORT
bool "OV7725 Support" bool "OV7725 Support"
default n default n
help help
Enable this option if you want to use the OV7725. Enable this option if you want to use the OV7725.
Disable this option to safe memory. Disable this option to save memory.
config OV3660_SUPPORT config OV3660_SUPPORT
bool "OV3660 Support" bool "OV3660 Support"
default y default y
help help
Enable this option if you want to use the OV3360. Enable this option if you want to use the OV3360.
Disable this option to safe memory. Disable this option to save memory.
config OV5640_SUPPORT
bool "OV5640 Support"
default y
help
Enable this option if you want to use the OV5640.
Disable this option to save memory.
config SCCB_HARDWARE_I2C config SCCB_HARDWARE_I2C
bool "Use hardware I2C for SCCB" bool "Use hardware I2C for SCCB"

2
conversions/esp_jpg_decode.c

@ -14,7 +14,7 @@
#include "esp_jpg_decode.h" #include "esp_jpg_decode.h"
#include "esp_system.h" #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/tjpgd.h" #include "esp32/rom/tjpgd.h"
#else #else

2
conversions/to_jpg.cpp

@ -22,7 +22,7 @@
#include "yuv.h" #include "yuv.h"
#include "esp_system.h" #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/spiram.h" #include "esp32/spiram.h"
#else #else

97
driver/camera.c

@ -45,6 +45,9 @@
#if CONFIG_OV3660_SUPPORT #if CONFIG_OV3660_SUPPORT
#include "ov3660.h" #include "ov3660.h"
#endif #endif
#if CONFIG_OV5640_SUPPORT
#include "ov5640.h"
#endif
typedef enum { typedef enum {
CAMERA_NONE = 0, CAMERA_NONE = 0,
@ -52,6 +55,7 @@ typedef enum {
CAMERA_OV7725 = 7725, CAMERA_OV7725 = 7725,
CAMERA_OV2640 = 2640, CAMERA_OV2640 = 2640,
CAMERA_OV3660 = 3660, CAMERA_OV3660 = 3660,
CAMERA_OV5640 = 5640,
} camera_model_t; } camera_model_t;
#define REG_PID 0x0A #define REG_PID 0x0A
@ -80,6 +84,7 @@ typedef struct camera_fb_s {
size_t width; size_t width;
size_t height; size_t height;
pixformat_t format; pixformat_t format;
struct timeval timestamp;
size_t size; size_t size;
uint8_t ref; uint8_t ref;
uint8_t bad; uint8_t bad;
@ -546,6 +551,7 @@ static void IRAM_ATTR signal_dma_buf_received(bool* need_yield)
} }
//ESP_EARLY_LOGW(TAG, "qsf:%d", s_state->dma_received_count); //ESP_EARLY_LOGW(TAG, "qsf:%d", s_state->dma_received_count);
//ets_printf("qsf:%d\n", s_state->dma_received_count); //ets_printf("qsf:%d\n", s_state->dma_received_count);
//ets_printf("qovf\n");
} }
*need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE); *need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE);
} }
@ -577,6 +583,7 @@ static void IRAM_ATTR vsync_isr(void* arg)
if(s_state->dma_filtered_count > 1 || s_state->fb->bad || s_state->config.fb_count > 1) { if(s_state->dma_filtered_count > 1 || s_state->fb->bad || s_state->config.fb_count > 1) {
i2s_stop(&need_yield); i2s_stop(&need_yield);
} }
//ets_printf("vs\n");
} }
if(s_state->config.fb_count > 1 || s_state->dma_filtered_count < 2) { if(s_state->config.fb_count > 1 || s_state->dma_filtered_count < 2) {
I2S0.conf.rx_start = 0; I2S0.conf.rx_start = 0;
@ -669,6 +676,7 @@ static void IRAM_ATTR dma_finish_frame()
if(s_state->config.fb_count == 1) { if(s_state->config.fb_count == 1) {
i2s_start_bus(); i2s_start_bus();
} }
//ets_printf("bad\n");
} else { } else {
s_state->fb->len = s_state->dma_filtered_count * buf_len; s_state->fb->len = s_state->dma_filtered_count * buf_len;
if(s_state->fb->len) { if(s_state->fb->len) {
@ -695,6 +703,8 @@ static void IRAM_ATTR dma_finish_frame()
} else if(s_state->config.fb_count == 1){ } else if(s_state->config.fb_count == 1){
//frame was empty? //frame was empty?
i2s_start_bus(); i2s_start_bus();
} else {
//ets_printf("empty\n");
} }
} }
} else if(s_state->fb->len) { } else if(s_state->fb->len) {
@ -728,15 +738,19 @@ static void IRAM_ATTR dma_filter_buffer(size_t buf_idx)
if(s_state->sensor.pixformat == PIXFORMAT_JPEG) { if(s_state->sensor.pixformat == PIXFORMAT_JPEG) {
uint32_t sig = *((uint32_t *)s_state->fb->buf) & 0xFFFFFF; uint32_t sig = *((uint32_t *)s_state->fb->buf) & 0xFFFFFF;
if(sig != 0xffd8ff) { if(sig != 0xffd8ff) {
//ets_printf("bad header\n"); ets_printf("bh 0x%08x\n", sig);
s_state->fb->bad = 1; s_state->fb->bad = 1;
return; return;
} }
} }
//set the frame properties //set the frame properties
s_state->fb->width = resolution[s_state->sensor.status.framesize][0]; s_state->fb->width = resolution[s_state->sensor.status.framesize].width;
s_state->fb->height = resolution[s_state->sensor.status.framesize][1]; s_state->fb->height = resolution[s_state->sensor.status.framesize].height;
s_state->fb->format = s_state->sensor.pixformat; s_state->fb->format = s_state->sensor.pixformat;
uint64_t us = (uint64_t)esp_timer_get_time();
s_state->fb->timestamp.tv_sec = us / 1000000UL;
s_state->fb->timestamp.tv_usec = us % 1000000UL;
} }
s_state->dma_filtered_count++; s_state->dma_filtered_count++;
} }
@ -972,13 +986,6 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
gpio_set_level(config->pin_reset, 1); gpio_set_level(config->pin_reset, 1);
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
#if (CONFIG_OV2640_SUPPORT && !CONFIG_OV3660_SUPPORT)
} else {
//reset OV2640
SCCB_Write(0x30, 0xFF, 0x01);//bank sensor
SCCB_Write(0x30, 0x12, 0x80);//reset
vTaskDelay(10 / portTICK_PERIOD_MS);
#endif
} }
ESP_LOGD(TAG, "Searching for camera address"); ESP_LOGD(TAG, "Searching for camera address");
@ -989,15 +996,13 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
camera_disable_out_clock(); camera_disable_out_clock();
return ESP_ERR_CAMERA_NOT_DETECTED; return ESP_ERR_CAMERA_NOT_DETECTED;
} }
s_state->sensor.slv_addr = slv_addr;
s_state->sensor.xclk_freq_hz = config->xclk_freq_hz;
//s_state->sensor.slv_addr = 0x30; //slv_addr = 0x30;
ESP_LOGD(TAG, "Detected camera at address=0x%02x", s_state->sensor.slv_addr); ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr);
sensor_id_t* id = &s_state->sensor.id; sensor_id_t* id = &s_state->sensor.id;
#if (CONFIG_OV2640_SUPPORT) #if CONFIG_OV2640_SUPPORT
if (s_state->sensor.slv_addr == 0x30) { if (slv_addr == 0x30) {
ESP_LOGD(TAG, "Resetting OV2640"); ESP_LOGD(TAG, "Resetting OV2640");
//camera might be OV2640. try to reset it //camera might be OV2640. try to reset it
SCCB_Write(0x30, 0xFF, 0x01);//bank sensor SCCB_Write(0x30, 0xFF, 0x01);//bank sensor
@ -1007,7 +1012,10 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
} }
#endif #endif
#if CONFIG_OV3660_SUPPORT s_state->sensor.slv_addr = slv_addr;
s_state->sensor.xclk_freq_hz = config->xclk_freq_hz;
#if (CONFIG_OV3660_SUPPORT || CONFIG_OV5640_SUPPORT)
if(s_state->sensor.slv_addr == 0x3c){ if(s_state->sensor.slv_addr == 0x3c){
id->PID = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDH); id->PID = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDH);
id->VER = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDL); id->VER = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDL);
@ -1022,7 +1030,8 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
vTaskDelay(10 / portTICK_PERIOD_MS); vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x", ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
id->PID, id->VER, id->MIDH, id->MIDL); id->PID, id->VER, id->MIDH, id->MIDL);
#if CONFIG_OV3660_SUPPORT
#if (CONFIG_OV3660_SUPPORT || CONFIG_OV5640_SUPPORT)
} }
#endif #endif
@ -1045,6 +1054,12 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
*out_camera_model = CAMERA_OV3660; *out_camera_model = CAMERA_OV3660;
ov3660_init(&s_state->sensor); ov3660_init(&s_state->sensor);
break; break;
#endif
#if CONFIG_OV5640_SUPPORT
case OV5640_PID:
*out_camera_model = CAMERA_OV5640;
ov5640_init(&s_state->sensor);
break;
#endif #endif
default: default:
id->PID = 0; id->PID = 0;
@ -1072,12 +1087,46 @@ esp_err_t camera_init(const camera_config_t* config)
esp_err_t err = ESP_OK; esp_err_t err = ESP_OK;
framesize_t frame_size = (framesize_t) config->frame_size; framesize_t frame_size = (framesize_t) config->frame_size;
pixformat_t pix_format = (pixformat_t) config->pixel_format; pixformat_t pix_format = (pixformat_t) config->pixel_format;
s_state->width = resolution[frame_size][0];
s_state->height = resolution[frame_size][1]; switch (s_state->sensor.id.PID) {
#if CONFIG_OV2640_SUPPORT
case OV2640_PID:
if (frame_size > FRAMESIZE_UXGA) {
frame_size = FRAMESIZE_UXGA;
}
break;
#endif
#if CONFIG_OV7725_SUPPORT
case OV7725_PID:
if (frame_size > FRAMESIZE_VGA) {
frame_size = FRAMESIZE_VGA;
}
break;
#endif
#if CONFIG_OV3660_SUPPORT
case OV3660_PID:
if (frame_size > FRAMESIZE_QXGA) {
frame_size = FRAMESIZE_QXGA;
}
break;
#endif
#if CONFIG_OV5640_SUPPORT
case OV5640_PID:
if (frame_size > FRAMESIZE_QSXGA) {
frame_size = FRAMESIZE_QSXGA;
}
break;
#endif
default:
return ESP_ERR_CAMERA_NOT_SUPPORTED;
}
s_state->width = resolution[frame_size].width;
s_state->height = resolution[frame_size].height;
if (pix_format == PIXFORMAT_GRAYSCALE) { if (pix_format == PIXFORMAT_GRAYSCALE) {
s_state->fb_size = s_state->width * s_state->height; s_state->fb_size = s_state->width * s_state->height;
if (s_state->sensor.id.PID == OV3660_PID) { if (s_state->sensor.id.PID == OV3660_PID || s_state->sensor.id.PID == OV5640_PID) {
if (is_hs_mode()) { if (is_hs_mode()) {
s_state->sampling_mode = SM_0A00_0B00; s_state->sampling_mode = SM_0A00_0B00;
s_state->dma_filter = &dma_filter_yuyv_highspeed; s_state->dma_filter = &dma_filter_yuyv_highspeed;
@ -1120,8 +1169,8 @@ esp_err_t camera_init(const camera_config_t* config)
s_state->in_bytes_per_pixel = 2; // camera sends RGB565 s_state->in_bytes_per_pixel = 2; // camera sends RGB565
s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888 s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888
} else if (pix_format == PIXFORMAT_JPEG) { } else if (pix_format == PIXFORMAT_JPEG) {
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID) { if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID && s_state->sensor.id.PID != OV5640_PID) {
ESP_LOGE(TAG, "JPEG format is only supported for ov2640 and ov3660"); ESP_LOGE(TAG, "JPEG format is only supported for ov2640, ov3660 and ov5640");
err = ESP_ERR_NOT_SUPPORTED; err = ESP_ERR_NOT_SUPPORTED;
goto fail; goto fail;
} }
@ -1268,6 +1317,8 @@ esp_err_t esp_camera_init(const camera_config_t* config)
ESP_LOGD(TAG, "Detected OV2640 camera"); ESP_LOGD(TAG, "Detected OV2640 camera");
} else if (camera_model == CAMERA_OV3660) { } else if (camera_model == CAMERA_OV3660) {
ESP_LOGD(TAG, "Detected OV3660 camera"); ESP_LOGD(TAG, "Detected OV3660 camera");
} else if (camera_model == CAMERA_OV5640) {
ESP_LOGD(TAG, "Detected OV5640 camera");
} else { } else {
ESP_LOGE(TAG, "Camera not supported"); ESP_LOGE(TAG, "Camera not supported");
err = ESP_ERR_CAMERA_NOT_SUPPORTED; err = ESP_ERR_CAMERA_NOT_SUPPORTED;

1
driver/include/esp_camera.h

@ -115,6 +115,7 @@ typedef struct {
size_t width; /*!< Width of the buffer in pixels */ size_t width; /*!< Width of the buffer in pixels */
size_t height; /*!< Height of the buffer in pixels */ size_t height; /*!< Height of the buffer in pixels */
pixformat_t format; /*!< Format of the pixel data */ pixformat_t format; /*!< Format of the pixel data */
struct timeval timestamp; /*!< Timestamp since boot of the first DMA buffer of the frame */
} camera_fb_t; } camera_fb_t;
#define ESP_ERR_CAMERA_BASE 0x20000 #define ESP_ERR_CAMERA_BASE 0x20000

67
driver/include/sensor.h

@ -9,11 +9,13 @@
#ifndef __SENSOR_H__ #ifndef __SENSOR_H__
#define __SENSOR_H__ #define __SENSOR_H__
#include <stdint.h> #include <stdint.h>
#include <stdbool.h>
#define OV9650_PID (0x96) #define OV9650_PID (0x96)
#define OV2640_PID (0x26)
#define OV7725_PID (0x77) #define OV7725_PID (0x77)
#define OV2640_PID (0x26)
#define OV3660_PID (0x36) #define OV3660_PID (0x36)
#define OV5640_PID (0x56)
typedef enum { typedef enum {
PIXFORMAT_RGB565, // 2BPP/RGB565 PIXFORMAT_RGB565, // 2BPP/RGB565
@ -27,23 +29,45 @@ typedef enum {
} pixformat_t; } pixformat_t;
typedef enum { typedef enum {
FRAMESIZE_96x96, // 96x96 FRAMESIZE_96X96, // 96x96
FRAMESIZE_QQVGA, // 160x120 FRAMESIZE_QQVGA, // 160x120
FRAMESIZE_QQVGA2, // 128x160
FRAMESIZE_QCIF, // 176x144 FRAMESIZE_QCIF, // 176x144
FRAMESIZE_HQVGA, // 240x176 FRAMESIZE_HQVGA, // 240x176
FRAMESIZE_240x240, // 240x240 FRAMESIZE_240X240, // 240x240
FRAMESIZE_QVGA, // 320x240 FRAMESIZE_QVGA, // 320x240
FRAMESIZE_CIF, // 400x296 FRAMESIZE_CIF, // 400x296
FRAMESIZE_HVGA, // 480x320
FRAMESIZE_VGA, // 640x480 FRAMESIZE_VGA, // 640x480
FRAMESIZE_SVGA, // 800x600 FRAMESIZE_SVGA, // 800x600
FRAMESIZE_XGA, // 1024x768 FRAMESIZE_XGA, // 1024x768
FRAMESIZE_HD, // 1280x720
FRAMESIZE_SXGA, // 1280x1024 FRAMESIZE_SXGA, // 1280x1024
FRAMESIZE_UXGA, // 1600x1200 FRAMESIZE_UXGA, // 1600x1200
FRAMESIZE_QXGA, // 2048*1536 // 3MP Sensors
FRAMESIZE_FHD, // 1920x1080
FRAMESIZE_P_HD, // 720x1280
FRAMESIZE_P_3MP, // 864x1536
FRAMESIZE_QXGA, // 2048x1536
// 5MP Sensors
FRAMESIZE_QHD, // 2560x1440
FRAMESIZE_WQXGA, // 2560x1600
FRAMESIZE_P_FHD, // 1080x1920
FRAMESIZE_QSXGA, // 2560x1920
FRAMESIZE_INVALID FRAMESIZE_INVALID
} framesize_t; } framesize_t;
typedef enum {
ASPECT_RATIO_4X3,
ASPECT_RATIO_3X2,
ASPECT_RATIO_16X10,
ASPECT_RATIO_5X3,
ASPECT_RATIO_16X9,
ASPECT_RATIO_21X9,
ASPECT_RATIO_5X4,
ASPECT_RATIO_1X1,
ASPECT_RATIO_9X16
} aspect_ratio_t;
typedef enum { typedef enum {
GAINCEILING_2X, GAINCEILING_2X,
GAINCEILING_4X, GAINCEILING_4X,
@ -54,6 +78,28 @@ typedef enum {
GAINCEILING_128X, GAINCEILING_128X,
} gainceiling_t; } gainceiling_t;
typedef struct {
uint16_t max_width;
uint16_t max_height;
uint16_t start_x;
uint16_t start_y;
uint16_t end_x;
uint16_t end_y;
uint16_t offset_x;
uint16_t offset_y;
uint16_t total_x;
uint16_t total_y;
} ratio_settings_t;
typedef struct {
const uint16_t width;
const uint16_t height;
const aspect_ratio_t aspect_ratio;
} resolution_info_t;
// Resolution table (in sensor.c)
extern const resolution_info_t resolution[];
typedef struct { typedef struct {
uint8_t MIDH; uint8_t MIDH;
uint8_t MIDL; uint8_t MIDL;
@ -63,6 +109,8 @@ typedef struct {
typedef struct { typedef struct {
framesize_t framesize;//0 - 10 framesize_t framesize;//0 - 10
bool scale;
bool binning;
uint8_t quality;//0 - 63 uint8_t quality;//0 - 63
int8_t brightness;//-2 - 2 int8_t brightness;//-2 - 2
int8_t contrast;//-2 - 2 int8_t contrast;//-2 - 2
@ -132,9 +180,12 @@ typedef struct _sensor {
int (*set_raw_gma) (sensor_t *sensor, int enable); int (*set_raw_gma) (sensor_t *sensor, int enable);
int (*set_lenc) (sensor_t *sensor, int enable); int (*set_lenc) (sensor_t *sensor, int enable);
} sensor_t;
// Resolution table (in camera.c) int (*get_reg) (sensor_t *sensor, int reg, int mask);
extern const int resolution[][2]; int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
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);
int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
} sensor_t;
#endif /* __SENSOR_H__ */ #endif /* __SENSOR_H__ */

2
driver/private_include/camera_common.h

@ -12,7 +12,7 @@
#include "sensor.h" #include "sensor.h"
#include "esp_system.h" #include "esp_system.h"
#ifdef ESP_IDF_VERSION_MAJOR // IDF 4+ #if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4 #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
#include "esp32/rom/lldesc.h" #include "esp32/rom/lldesc.h"
#else #else

2
driver/sccb.c

@ -19,6 +19,8 @@
static const char* TAG = "sccb"; static const char* TAG = "sccb";
#endif #endif
//#undef CONFIG_SCCB_HARDWARE_I2C
#define LITTLETOBIG(x) ((x<<8)|(x>>8)) #define LITTLETOBIG(x) ((x<<8)|(x>>8))
#ifdef CONFIG_SCCB_HARDWARE_I2C #ifdef CONFIG_SCCB_HARDWARE_I2C

41
driver/sensor.c

@ -1,17 +1,28 @@
#include "sensor.h"
const int resolution[][2] = { const resolution_info_t resolution[FRAMESIZE_INVALID] = {
{ 96, 96 }, /* 96x96 */ { 96, 96, ASPECT_RATIO_1X1 }, /* 96x96 */
{ 160, 120 }, /* QQVGA */ { 160, 120, ASPECT_RATIO_4X3 }, /* QQVGA */
{ 128, 160 }, /* QQVGA2*/ { 176, 144, ASPECT_RATIO_5X4 }, /* QCIF */
{ 176, 144 }, /* QCIF */ { 240, 176, ASPECT_RATIO_4X3 }, /* HQVGA */
{ 240, 176 }, /* HQVGA */ { 240, 240, ASPECT_RATIO_1X1 }, /* 240x240 */
{ 240, 240 }, /* 240x240 */ { 320, 240, ASPECT_RATIO_4X3 }, /* QVGA */
{ 320, 240 }, /* QVGA */ { 400, 296, ASPECT_RATIO_4X3 }, /* CIF */
{ 400, 296 }, /* CIF */ { 480, 320, ASPECT_RATIO_3X2 }, /* HVGA */
{ 640, 480 }, /* VGA */ { 640, 480, ASPECT_RATIO_4X3 }, /* VGA */
{ 800, 600 }, /* SVGA */ { 800, 600, ASPECT_RATIO_4X3 }, /* SVGA */
{ 1024, 768 }, /* XGA */ { 1024, 768, ASPECT_RATIO_4X3 }, /* XGA */
{ 1280, 1024 }, /* SXGA */ { 1280, 720, ASPECT_RATIO_16X9 }, /* HD */
{ 1600, 1200 }, /* UXGA */ { 1280, 1024, ASPECT_RATIO_5X4 }, /* SXGA */
{ 2048, 1536 }, /* QXGA */ { 1600, 1200, ASPECT_RATIO_4X3 }, /* UXGA */
// 3MP Sensors
{ 1920, 1080, ASPECT_RATIO_16X9 }, /* FHD */
{ 720, 1280, ASPECT_RATIO_9X16 }, /* Portrait HD */
{ 864, 1536, ASPECT_RATIO_9X16 }, /* Portrait 3MP */
{ 2048, 1536, ASPECT_RATIO_4X3 }, /* QXGA */
// 5MP Sensors
{ 2560, 1440, ASPECT_RATIO_16X9 }, /* QHD */
{ 2560, 1600, ASPECT_RATIO_16X10 }, /* WQXGA */
{ 1088, 1920, ASPECT_RATIO_9X16 }, /* Portrait FHD */
{ 2560, 1920, ASPECT_RATIO_4X3 }, /* QSXGA */
}; };

23
driver/xclk.c

@ -12,19 +12,28 @@
static const char* TAG = "camera_xclk"; static const char* TAG = "camera_xclk";
#endif #endif
esp_err_t camera_enable_out_clock(camera_config_t* config) esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
{ {
periph_module_enable(PERIPH_LEDC_MODULE); ledc_timer_config_t timer_conf;
ledc_timer_config_t timer_conf = {};
timer_conf.duty_resolution = 2; timer_conf.duty_resolution = 2;
timer_conf.freq_hz = config->xclk_freq_hz; timer_conf.freq_hz = xclk_freq_hz;
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
timer_conf.timer_num = config->ledc_timer; #if ESP_IDF_VERSION_MAJOR >= 4
#ifdef ESP_IDF_VERSION_MAJOR
timer_conf.clk_cfg = LEDC_AUTO_CLK; timer_conf.clk_cfg = LEDC_AUTO_CLK;
#endif #endif
timer_conf.timer_num = (ledc_timer_t)ledc_timer;
esp_err_t err = ledc_timer_config(&timer_conf); esp_err_t err = ledc_timer_config(&timer_conf);
if (err != ESP_OK) {
ESP_LOGE(TAG, "ledc_timer_config failed for freq %d, rc=%x", xclk_freq_hz, err);
}
return err;
}
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) { if (err != ESP_OK) {
ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err);
return err; return err;

227
sensors/ov2640.c

@ -133,133 +133,100 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
return ret; return ret;
} }
//Functions are not needed currently static int set_window(sensor_t *sensor, ov2640_sensor_mode_t mode, int offset_x, int offset_y, int max_x, int max_y, int w, int h){
#if 0
//Set the sensor output window
int set_output_window(sensor_t *sensor, uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
int ret = 0; int ret = 0;
uint16_t endx, endy; const uint8_t (*regs)[2];
uint8_t com1, reg32; ov2640_clk_t c;
c.reserved = 0;
endy = y + height / 2;
com1 = read_reg(sensor, BANK_SENSOR, COM1); max_x /= 4;
WRITE_REG_OR_RETURN(BANK_SENSOR, COM1, (com1 & 0XF0) | (((endy & 0X03) << 2) | (y & 0X03))); max_y /= 4;
WRITE_REG_OR_RETURN(BANK_SENSOR, VSTART, y >> 2); w /= 4;
WRITE_REG_OR_RETURN(BANK_SENSOR, VSTOP, endy >> 2); h /= 4;
uint8_t win_regs[][2] = {
endx = x + width / 2; {BANK_SEL, BANK_DSP},
reg32 = read_reg(sensor, BANK_SENSOR, REG32); {HSIZE, max_x & 0xFF},
WRITE_REG_OR_RETURN(BANK_SENSOR, REG32, (reg32 & 0XC0) | (((endx & 0X07) << 3) | (x & 0X07))); {VSIZE, max_y & 0xFF},
WRITE_REG_OR_RETURN(BANK_SENSOR, HSTART, x >> 3); {XOFFL, offset_x & 0xFF},
WRITE_REG_OR_RETURN(BANK_SENSOR, HSTOP, endx >> 3); {YOFFL, offset_y & 0xFF},
{VHYX, ((max_y >> 1) & 0X80) | ((offset_y >> 4) & 0X70) | ((max_x >> 5) & 0X08) | ((offset_y >> 8) & 0X07)},
return ret; {TEST, (max_x >> 2) & 0X80},
} {ZMOW, (w)&0xFF},
{ZMOH, (h)&0xFF},
// Set the image output size (final output resolution) {ZMHH, ((h>>6)&0x04)|((w>>8)&0x03)},
int set_output_size(sensor_t *sensor, uint16_t width, uint16_t height) {0, 0}
{ };
int ret = 0;
uint16_t h, w; c.pclk_auto = 0;
c.pclk_div = 8;
if(width % 4) { c.clk_2x = 0;
return -1; c.clk_div = 0;
}
if(height % 4 ) { if(sensor->pixformat != PIXFORMAT_JPEG){
return -2; c.pclk_auto = 1;
} c.clk_div = 7;
}
w = width / 4;
h = height / 4; if (mode == OV2640_MODE_CIF) {
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP); regs = ov2640_settings_to_cif;
WRITE_REG_OR_RETURN(BANK_DSP, ZMOW, w & 0XFF); if(sensor->pixformat != PIXFORMAT_JPEG){
WRITE_REG_OR_RETURN(BANK_DSP, ZMOH, h & 0XFF); c.clk_div = 3;
WRITE_REG_OR_RETURN(BANK_DSP, ZMHH, ((w >> 8) & 0X03) | ((h >> 6) & 0X04));
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00);
return ret;
}
//Set the image window size >= output size
int set_window_size(sensor_t *sensor, uint16_t x, uint16_t y, uint16_t width, uint16_t height)
{
int ret = 0;
uint16_t w, h;
if(width % 4) {
return -1;
} }
if(height % 4) { } else if (mode == OV2640_MODE_SVGA) {
return -2; regs = ov2640_settings_to_svga;
} else {
regs = ov2640_settings_to_uxga;
c.pclk_div = 12;
} }
w = width / 4; WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS);
h = height / 4; WRITE_REGS_OR_RETURN(regs);
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP); WRITE_REGS_OR_RETURN(win_regs);
WRITE_REG_OR_RETURN(BANK_DSP, HSIZE, w & 0XFF); WRITE_REG_OR_RETURN(BANK_SENSOR, CLKRC, c.clk);
WRITE_REG_OR_RETURN(BANK_DSP, VSIZE, h & 0XFF); WRITE_REG_OR_RETURN(BANK_DSP, R_DVP_SP, c.pclk);
WRITE_REG_OR_RETURN(BANK_DSP, XOFFL, x & 0XFF); WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_EN);
WRITE_REG_OR_RETURN(BANK_DSP, YOFFL, y & 0XFF);
WRITE_REG_OR_RETURN(BANK_DSP, VHYX, ((h >> 1) & 0X80) | ((y >> 4) & 0X70) | ((w >> 5) & 0X08) | ((x >> 8) & 0X07));
WRITE_REG_OR_RETURN(BANK_DSP, TEST, (w >> 2) & 0X80);
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00);
return ret;
}
//Set the sensor resolution (UXGA, SVGA, CIF) vTaskDelay(10 / portTICK_PERIOD_MS);
int set_image_size(sensor_t *sensor, uint16_t width, uint16_t height) //required when changing resolution
{ set_pixformat(sensor, sensor->pixformat);
int ret = 0;
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP);
WRITE_REG_OR_RETURN(BANK_DSP, HSIZE8, (width >> 3) & 0XFF);
WRITE_REG_OR_RETURN(BANK_DSP, VSIZE8, (height >> 3) & 0XFF);
WRITE_REG_OR_RETURN(BANK_DSP, SIZEL, ((width & 0X07) << 3) | ((width >> 4) & 0X80) | (height & 0X07));
//WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00);
return ret; return ret;
} }
#endif
static int set_framesize(sensor_t *sensor, framesize_t framesize) static int set_framesize(sensor_t *sensor, framesize_t framesize)
{ {
int ret = 0; int ret = 0;
uint16_t w = resolution[framesize][0]; uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize][1]; uint16_t h = resolution[framesize].height;
const uint8_t (*regs)[2]; aspect_ratio_t ratio = resolution[framesize].aspect_ratio;
uint16_t max_x = ratio_table[ratio].max_x;
uint16_t max_y = ratio_table[ratio].max_y;
uint16_t offset_x = ratio_table[ratio].offset_x;
uint16_t offset_y = ratio_table[ratio].offset_y;
ov2640_sensor_mode_t mode = OV2640_MODE_UXGA;
sensor->status.framesize = framesize; sensor->status.framesize = framesize;
if (framesize <= FRAMESIZE_CIF) {
regs = ov2640_settings_to_cif;
} else if (framesize <= FRAMESIZE_SVGA) {
regs = ov2640_settings_to_svga;
} else {
regs = ov2640_settings_to_uxga;
}
WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS);
WRITE_REGS_OR_RETURN(regs);
if (sensor->pixformat == PIXFORMAT_JPEG && sensor->xclk_freq_hz == 10000000) {
if (framesize <= FRAMESIZE_CIF) { if (framesize <= FRAMESIZE_CIF) {
WRITE_REG_OR_RETURN(BANK_SENSOR, CLKRC, CLKRC_2X_CIF); mode = OV2640_MODE_CIF;
} else if (framesize <= FRAMESIZE_SVGA) { max_x /= 4;
WRITE_REG_OR_RETURN(BANK_SENSOR, CLKRC, CLKRC_2X_SVGA); max_y /= 4;
} else { offset_x /= 4;
WRITE_REG_OR_RETURN(BANK_SENSOR, CLKRC, CLKRC_2X_UXGA); offset_y /= 4;
if(max_y > 296){
max_y = 296;
} }
} else if (framesize <= FRAMESIZE_SVGA) {
mode = OV2640_MODE_SVGA;
max_x /= 2;
max_y /= 2;
offset_x /= 2;
offset_y /= 2;
} }
WRITE_REG_OR_RETURN(BANK_DSP, ZMOW, (w>>2)&0xFF); // OUTW[7:0] (real/4)
WRITE_REG_OR_RETURN(BANK_DSP, ZMOH, (h>>2)&0xFF); // OUTH[7:0] (real/4)
WRITE_REG_OR_RETURN(BANK_DSP, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); // OUTH[8]/OUTW[9:8]
WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0x00);
WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_EN);
vTaskDelay(10 / portTICK_PERIOD_MS);
//required when changing resolution
set_pixformat(sensor, sensor->pixformat);
ret = set_window(sensor, mode, offset_x, offset_y, max_x, max_y, w, h);
return ret; return ret;
} }
@ -482,6 +449,46 @@ static int set_denoise(sensor_t *sensor, int level)
return -1; return -1;
} }
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = read_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF);
if(ret > 0){
ret &= mask;
}
return ret;
}
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{
int ret = 0;
ret = read_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF);
if(ret < 0){
return ret;
}
value = (ret & ~mask) | (value & mask);
ret = write_reg(sensor, (reg >> 8) & 0x01, reg & 0xFF, value);
return ret;
}
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 set_window(sensor, (ov2640_sensor_mode_t)startX, offsetX, offsetY, totalX, totalY, outputX, outputY);
}
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;
sensor->xclk_freq_hz = xclk * 1000000U;
ret = xclk_timer_conf(timer, sensor->xclk_freq_hz);
return ret;
}
static int init_status(sensor_t *sensor){ static int init_status(sensor_t *sensor){
sensor->status.brightness = 0; sensor->status.brightness = 0;
sensor->status.contrast = 0; sensor->status.contrast = 0;
@ -562,6 +569,12 @@ int ov2640_init(sensor_t *sensor)
//not supported //not supported
sensor->set_sharpness = set_sharpness; sensor->set_sharpness = set_sharpness;
sensor->set_denoise = set_denoise; sensor->set_denoise = set_denoise;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_res_raw = set_res_raw;
sensor->set_pll = _set_pll;
sensor->set_xclk = set_xclk;
ESP_LOGD(TAG, "OV2640 Attached"); ESP_LOGD(TAG, "OV2640 Attached");
return 0; return 0;
} }

158
sensors/ov3660.c

@ -124,7 +124,7 @@ static int write_addr_reg(uint8_t slv_addr, const uint16_t reg, uint16_t x_value
#define write_reg_bits(slv_addr, reg, mask, enable) set_reg_bits(slv_addr, reg, 0, mask, enable?mask:0) #define write_reg_bits(slv_addr, reg, mask, enable) set_reg_bits(slv_addr, reg, 0, mask, enable?mask:0)
int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sys_div, int pll_pre_div, bool pll_root_2x, int pll_seld5, bool pclk_manual, int pclk_div) static int calc_sysclk(int xclk, bool pll_bypass, int pll_multiplier, int pll_sys_div, int pll_pre_div, bool pll_root_2x, int pll_seld5, bool pclk_manual, int pclk_div)
{ {
const int pll_pre_div2x_map[] = { 2, 3, 4, 6 };//values are multiplied by two to avoid floats const int pll_pre_div2x_map[] = { 2, 3, 4, 6 };//values are multiplied by two to avoid floats
const int pll_seld52x_map[] = { 2, 2, 4, 5 }; const int pll_seld52x_map[] = { 2, 2, 4, 5 };
@ -252,12 +252,12 @@ static int set_image_options(sensor_t *sensor)
} }
// binning // binning
if (sensor->status.framesize > FRAMESIZE_SVGA) { if (sensor->status.binning) {
reg20 |= 0x40;
} else {
reg20 |= 0x01; reg20 |= 0x01;
reg21 |= 0x01; reg21 |= 0x01;
reg4514_test |= 4; reg4514_test |= 4;
} else {
reg20 |= 0x40;
} }
// V-Flip // V-Flip
@ -292,8 +292,18 @@ static int set_image_options(sensor_t *sensor)
ret = -1; ret = -1;
} }
if (sensor->status.binning) {
ret = write_reg(sensor->slv_addr, 0x4520, 0x0b)
|| write_reg(sensor->slv_addr, X_INCREMENT, 0x31)//odd:3, even: 1
|| write_reg(sensor->slv_addr, Y_INCREMENT, 0x31);//odd:3, even: 1
} else {
ret = write_reg(sensor->slv_addr, 0x4520, 0xb0)
|| write_reg(sensor->slv_addr, X_INCREMENT, 0x11)//odd:1, even: 1
|| write_reg(sensor->slv_addr, Y_INCREMENT, 0x11);//odd:1, even: 1
}
ESP_LOGD(TAG, "Set Image Options: Compression: %u, Binning: %u, V-Flip: %u, H-Mirror: %u, Reg-4514: 0x%02x", ESP_LOGD(TAG, "Set Image Options: Compression: %u, Binning: %u, V-Flip: %u, H-Mirror: %u, Reg-4514: 0x%02x",
sensor->pixformat == PIXFORMAT_JPEG, sensor->status.framesize <= FRAMESIZE_SVGA, sensor->status.vflip, sensor->status.hmirror, reg4514); sensor->pixformat == PIXFORMAT_JPEG, sensor->status.binning, sensor->status.vflip, sensor->status.hmirror, reg4514);
return ret; return ret;
} }
@ -303,51 +313,37 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
framesize_t old_framesize = sensor->status.framesize; framesize_t old_framesize = sensor->status.framesize;
sensor->status.framesize = framesize; sensor->status.framesize = framesize;
if(framesize >= FRAMESIZE_INVALID){ if(framesize > FRAMESIZE_QXGA){
ESP_LOGE(TAG, "Invalid framesize: %u", framesize); ESP_LOGE(TAG, "Invalid framesize: %u", framesize);
return -1; return -1;
} }
uint16_t w = resolution[framesize][0]; uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize][1]; uint16_t h = resolution[framesize].height;
aspect_ratio_t ratio = resolution[sensor->status.framesize].aspect_ratio;
ratio_settings_t settings = ratio_table[ratio];
if (framesize > FRAMESIZE_SVGA) { sensor->status.binning = (w <= (settings.max_width / 2) && h <= (settings.max_height / 2));
ret = write_reg(sensor->slv_addr, 0x4520, 0xb0) sensor->status.scale = !((w == settings.max_width && h == settings.max_height)
|| write_reg(sensor->slv_addr, X_INCREMENT, 0x11)//odd:1, even: 1 || (w == (settings.max_width / 2) && h == (settings.max_height / 2)));
|| write_reg(sensor->slv_addr, Y_INCREMENT, 0x11);//odd:1, even: 1
} else {
ret = write_reg(sensor->slv_addr, 0x4520, 0x0b)
|| write_reg(sensor->slv_addr, X_INCREMENT, 0x31)//odd:3, even: 1
|| write_reg(sensor->slv_addr, Y_INCREMENT, 0x31);//odd:3, even: 1
}
if (ret) {
goto fail;
}
ret = write_addr_reg(sensor->slv_addr, X_ADDR_ST_H, 0, 0) ret = write_addr_reg(sensor->slv_addr, X_ADDR_ST_H, settings.start_x, settings.start_y)
|| write_addr_reg(sensor->slv_addr, X_ADDR_END_H, 2079, 1547) || write_addr_reg(sensor->slv_addr, X_ADDR_END_H, settings.end_x, settings.end_y)
|| write_addr_reg(sensor->slv_addr, X_OUTPUT_SIZE_H, w, h); || write_addr_reg(sensor->slv_addr, X_OUTPUT_SIZE_H, w, h);
if (ret) { if (ret) {
goto fail; goto fail;
} }
if (framesize > FRAMESIZE_SVGA) { if (sensor->status.binning) {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2300, 1564) ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, settings.total_x, (settings.total_y / 2) + 1)
|| write_addr_reg(sensor->slv_addr, X_OFFSET_H, 16, 6); || write_addr_reg(sensor->slv_addr, X_OFFSET_H, 8, 2);
} else {
if (framesize == FRAMESIZE_SVGA) {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2300, 788);
} else { } else {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2050, 788); ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, settings.total_x, settings.total_y)
} || write_addr_reg(sensor->slv_addr, X_OFFSET_H, 16, 6);
if (ret == 0) {
ret = write_addr_reg(sensor->slv_addr, X_OFFSET_H, 8, 2);
}
} }
if (ret == 0) { if (ret == 0) {
ret = write_reg_bits(sensor->slv_addr, ISP_CONTROL_01, 0x20, framesize != FRAMESIZE_QXGA); ret = write_reg_bits(sensor->slv_addr, ISP_CONTROL_01, 0x20, sensor->status.scale);
} }
if (ret == 0) { if (ret == 0) {
@ -880,6 +876,92 @@ static int set_denoise(sensor_t *sensor, int level)
return ret; return ret;
} }
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = 0, ret2 = 0;
if(mask > 0xFF){
ret = read_reg16(sensor->slv_addr, reg);
if(ret >= 0 && mask > 0xFFFF){
ret2 = read_reg(sensor->slv_addr, reg+2);
if(ret2 >= 0){
ret = (ret << 8) | ret2 ;
} else {
ret = ret2;
}
}
} 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, ret2 = 0;
if(mask > 0xFF){
ret = read_reg16(sensor->slv_addr, reg);
if(ret >= 0 && mask > 0xFFFF){
ret2 = read_reg(sensor->slv_addr, reg+2);
if(ret2 >= 0){
ret = (ret << 8) | ret2 ;
} else {
ret = ret2;
}
}
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if(ret < 0){
return ret;
}
value = (ret & ~mask) | (value & mask);
if(mask > 0xFFFF){
ret = write_reg16(sensor->slv_addr, reg, value >> 8);
if(ret >= 0){
ret = write_reg(sensor->slv_addr, reg+2, value & 0xFF);
}
} else if(mask > 0xFF){
ret = write_reg16(sensor->slv_addr, reg, value);
} else {
ret = write_reg(sensor->slv_addr, reg, value);
}
return ret;
}
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)
{
int ret = 0;
ret = write_addr_reg(sensor->slv_addr, X_ADDR_ST_H, startX, startY)
|| write_addr_reg(sensor->slv_addr, X_ADDR_END_H, endX, endY)
|| write_addr_reg(sensor->slv_addr, X_OFFSET_H, offsetX, offsetY)
|| write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, totalX, totalY)
|| write_addr_reg(sensor->slv_addr, X_OUTPUT_SIZE_H, outputX, outputY)
|| write_reg_bits(sensor->slv_addr, ISP_CONTROL_01, 0x20, scale);
if(!ret){
sensor->status.scale = scale;
sensor->status.binning = binning;
ret = set_image_options(sensor);
}
return ret;
}
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 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;
sensor->xclk_freq_hz = xclk * 1000000U;
ret = xclk_timer_conf(timer, sensor->xclk_freq_hz);
return ret;
}
static int init_status(sensor_t *sensor) static int init_status(sensor_t *sensor)
{ {
sensor->status.brightness = 0; sensor->status.brightness = 0;
@ -941,5 +1023,11 @@ int ov3660_init(sensor_t *sensor)
sensor->set_raw_gma = set_raw_gma_dsp; sensor->set_raw_gma = set_raw_gma_dsp;
sensor->set_lenc = set_lenc_dsp; sensor->set_lenc = set_lenc_dsp;
sensor->set_denoise = set_denoise; sensor->set_denoise = set_denoise;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_res_raw = set_res_raw;
sensor->set_pll = _set_pll;
sensor->set_xclk = set_xclk;
return 0; return 0;
} }

1105
sensors/ov5640.c

File diff suppressed because it is too large Load Diff

4
sensors/ov7725.c

@ -176,8 +176,8 @@ static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
static int set_framesize(sensor_t *sensor, framesize_t framesize) static int set_framesize(sensor_t *sensor, framesize_t framesize)
{ {
int ret=0; int ret=0;
uint16_t w = resolution[framesize][0]; uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize][1]; uint16_t h = resolution[framesize].height;
uint8_t reg = SCCB_Read(sensor->slv_addr, COM7); uint8_t reg = SCCB_Read(sensor->slv_addr, COM7);
sensor->status.framesize = framesize; sensor->status.framesize = framesize;

55
sensors/private_include/ov2640_settings.h

@ -19,6 +19,48 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "ov2640_regs.h" #include "ov2640_regs.h"
typedef enum {
OV2640_MODE_UXGA, OV2640_MODE_SVGA, OV2640_MODE_CIF, OV2640_MODE_MAX
} ov2640_sensor_mode_t;
typedef struct {
union {
struct {
uint8_t pclk_div:7;
uint8_t pclk_auto:1;
};
uint8_t pclk;
};
union {
struct {
uint8_t clk_div:6;
uint8_t reserved:1;
uint8_t clk_2x:1;
};
uint8_t clk;
};
} ov2640_clk_t;
typedef struct {
uint16_t offset_x;
uint16_t offset_y;
uint16_t max_x;
uint16_t max_y;
} ov2640_ratio_settings_t;
static const DRAM_ATTR ov2640_ratio_settings_t ratio_table[] = {
// ox, oy, mx, my
{ 0, 0, 1600, 1200 }, //4x3
{ 8, 72, 1584, 1056 }, //3x2
{ 0, 100, 1600, 1000 }, //16x10
{ 0, 120, 1600, 960 }, //5x3
{ 0, 150, 1600, 900 }, //16x9
{ 2, 258, 1596, 684 }, //21x9
{ 50, 0, 1500, 1200 }, //5x4
{ 200, 0, 1200, 1200 }, //1x1
{ 462, 0, 676, 1200 } //9x16
};
// 30fps@24MHz // 30fps@24MHz
const DRAM_ATTR uint8_t ov2640_settings_cif[][2] = { const DRAM_ATTR uint8_t ov2640_settings_cif[][2] = {
{BANK_SEL, BANK_DSP}, {BANK_SEL, BANK_DSP},
@ -193,7 +235,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_cif[][2] = {
{VSTART, 0x00}, {VSTART, 0x00},
{VSTOP, 0x25}, {VSTOP, 0x25},
{CLKRC, 0x01}, //{CLKRC, 0x00},
{BD50, 0xca}, {BD50, 0xca},
{BD60, 0xa8}, {BD60, 0xa8},
{0x5a, 0x23}, {0x5a, 0x23},
@ -228,7 +270,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_cif[][2] = {
{CTRL2, CTRL2_DCW_EN | 0x1D}, {CTRL2, CTRL2_DCW_EN | 0x1D},
{CTRLI, CTRLI_LP_DP | 0x00}, {CTRLI, CTRLI_LP_DP | 0x00},
{R_DVP_SP, 0x82}, //{R_DVP_SP, 0x08},
{0, 0} {0, 0}
}; };
@ -244,7 +286,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_svga[][2] = {
{VSTART, 0x00}, {VSTART, 0x00},
{VSTOP, 0x4b}, {VSTOP, 0x4b},
{CLKRC, 0x01}, //{CLKRC, 0x00},
{0x37, 0xc0}, {0x37, 0xc0},
{BD50, 0xca}, {BD50, 0xca},
{BD60, 0xa8}, {BD60, 0xa8},
@ -281,7 +323,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_svga[][2] = {
{CTRL2, CTRL2_DCW_EN | 0x1D}, {CTRL2, CTRL2_DCW_EN | 0x1D},
{CTRLI, CTRLI_LP_DP | 0x00}, {CTRLI, CTRLI_LP_DP | 0x00},
{R_DVP_SP, 0x80}, //{R_DVP_SP, 0x08},
{0, 0} {0, 0}
}; };
@ -297,7 +339,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_uxga[][2] = {
{VSTART, 0x01}, {VSTART, 0x01},
{VSTOP, 0x97}, {VSTOP, 0x97},
{CLKRC, 0x01}, //{CLKRC, 0x00},
{0x3d, 0x34}, {0x3d, 0x34},
{BD50, 0xbb}, {BD50, 0xbb},
{BD60, 0x9c}, {BD60, 0x9c},
@ -333,7 +375,7 @@ const DRAM_ATTR uint8_t ov2640_settings_to_uxga[][2] = {
{CTRL2, CTRL2_DCW_EN | 0x1d}, {CTRL2, CTRL2_DCW_EN | 0x1d},
{CTRLI, 0x00}, {CTRLI, 0x00},
{R_DVP_SP, 0x82}, //{R_DVP_SP, 0x06},
{0, 0} {0, 0}
}; };
@ -348,7 +390,6 @@ const DRAM_ATTR uint8_t ov2640_settings_jpeg3[][2] = {
{0xDF, 0x80}, {0xDF, 0x80},
{0x33, 0x80}, {0x33, 0x80},
{0x3C, 0x10}, {0x3C, 0x10},
{R_DVP_SP, 0x04},
{0xEB, 0x30}, {0xEB, 0x30},
{0xDD, 0x7F}, {0xDD, 0x7F},
{RESET, 0x00}, {RESET, 0x00},

62
sensors/private_include/ov3660_settings.h

@ -6,10 +6,23 @@
#include "esp_attr.h" #include "esp_attr.h"
#include "ov3660_regs.h" #include "ov3660_regs.h"
static const ratio_settings_t ratio_table[] = {
// mw, mh, sx, sy, ex, ey, ox, oy, tx, ty
{ 2048, 1536, 0, 0, 2079, 1547, 16, 6, 2300, 1564 }, //4x3
{ 1920, 1280, 64, 128, 2015, 1419, 16, 6, 2172, 1436 }, //3x2
{ 2048, 1280, 0, 128, 2079, 1419, 16, 6, 2300, 1436 }, //16x10
{ 1920, 1152, 64, 192, 2015, 1355, 16, 6, 2172, 1372 }, //5x3
{ 1920, 1080, 64, 242, 2015, 1333, 16, 6, 2172, 1322 }, //16x9
{ 2048, 880, 0, 328, 2079, 1219, 16, 6, 2300, 1236 }, //21x9
{ 1920, 1536, 64, 0, 2015, 1547, 16, 6, 2172, 1564 }, //5x4
{ 1536, 1536, 256, 0, 1823, 1547, 16, 6, 2044, 1564 }, //1x1
{ 864, 1536, 592, 0, 1487, 1547, 16, 6, 2044, 1564 } //9x16
};
#define REG_DLY 0xffff #define REG_DLY 0xffff
#define REGLIST_TAIL 0x0000 #define REGLIST_TAIL 0x0000
const DRAM_ATTR uint16_t sensor_default_regs[][2] = { static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{SYSTEM_CTROL0, 0x82}, // software reset {SYSTEM_CTROL0, 0x82}, // software reset
{REG_DLY, 10}, // delay 10ms {REG_DLY, 10}, // delay 10ms
@ -131,22 +144,23 @@ const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{0x538a, 0x01}, {0x538a, 0x01},
{0x538b, 0x98}, {0x538b, 0x98},
{0x5481, 0x05}, {0x5480, 0x01},
{0x5482, 0x09}, // {0x5481, 0x05},
{0x5483, 0x10}, // {0x5482, 0x09},
{0x5484, 0x3a}, // {0x5483, 0x10},
{0x5485, 0x4c}, // {0x5484, 0x3a},
{0x5486, 0x5a}, // {0x5485, 0x4c},
{0x5487, 0x68}, // {0x5486, 0x5a},
{0x5488, 0x74}, // {0x5487, 0x68},
{0x5489, 0x80}, // {0x5488, 0x74},
{0x548a, 0x8e}, // {0x5489, 0x80},
{0x548b, 0xa4}, // {0x548a, 0x8e},
{0x548c, 0xb4}, // {0x548b, 0xa4},
{0x548d, 0xc8}, // {0x548c, 0xb4},
{0x548e, 0xde}, // {0x548d, 0xc8},
{0x548f, 0xf0}, // {0x548e, 0xde},
{0x5490, 0x15}, // {0x548f, 0xf0},
// {0x5490, 0x15},
{0x5000, 0xa7}, {0x5000, 0xa7},
{0x5800, 0x0C}, {0x5800, 0x0C},
@ -247,7 +261,7 @@ const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{REGLIST_TAIL, 0x00}, // tail {REGLIST_TAIL, 0x00}, // tail
}; };
const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = { static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422 {FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x30}, // YUYV {FORMAT_CTRL00, 0x30}, // YUYV
{0x3002, 0x00},//0x1c to 0x00 !!! {0x3002, 0x00},//0x1c to 0x00 !!!
@ -256,30 +270,30 @@ const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
{REGLIST_TAIL, 0x00}, // tail {REGLIST_TAIL, 0x00}, // tail
}; };
const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = { static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
{FORMAT_CTRL00, 0x00}, // RAW {FORMAT_CTRL00, 0x00}, // RAW
{REGLIST_TAIL, 0x00} {REGLIST_TAIL, 0x00}
}; };
const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = { static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422 {FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x10}, // Y8 {FORMAT_CTRL00, 0x10}, // Y8
{REGLIST_TAIL, 0x00} {REGLIST_TAIL, 0x00}
}; };
const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = { static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422 {FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x30}, // YUYV {FORMAT_CTRL00, 0x30}, // YUYV
{REGLIST_TAIL, 0x00} {REGLIST_TAIL, 0x00}
}; };
const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = { static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
{FORMAT_CTRL, 0x01}, // RGB {FORMAT_CTRL, 0x01}, // RGB
{FORMAT_CTRL00, 0x61}, // RGB565 (BGR) {FORMAT_CTRL00, 0x61}, // RGB565 (BGR)
{REGLIST_TAIL, 0x00} {REGLIST_TAIL, 0x00}
}; };
const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = { static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
{0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4 {0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4
{0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3 {0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
{0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2 {0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
@ -291,7 +305,7 @@ const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
{0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4 {0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4
}; };
const DRAM_ATTR uint8_t sensor_special_effects[7][4] = { static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
{0x06, 0x40, 0x2c, 0x08},//Normal {0x06, 0x40, 0x2c, 0x08},//Normal
{0x46, 0x40, 0x28, 0x08},//Negative {0x46, 0x40, 0x28, 0x08},//Negative
{0x1e, 0x80, 0x80, 0x08},//Grayscale {0x1e, 0x80, 0x80, 0x08},//Grayscale

9
sensors/private_include/ov5640.h

@ -0,0 +1,9 @@
#ifndef __OV5640_H__
#define __OV5640_H__
#include "sensor.h"
int ov5640_init(sensor_t *sensor);
#endif // __OV5640_H__

213
sensors/private_include/ov5640_regs.h

@ -0,0 +1,213 @@
/*
* OV5640 register definitions.
*/
#ifndef __OV5640_REG_REGS_H__
#define __OV5640_REG_REGS_H__
/* system control registers */
#define SYSTEM_CTROL0 0x3008 // Bit[7]: Software reset
// Bit[6]: Software power down
// Bit[5]: Reserved
// Bit[4]: SRB clock SYNC enable
// Bit[3]: Isolation suspend select
// Bit[2:0]: Not used
#define DRIVE_CAPABILITY 0x302c // Bit[7:6]:
// 00: 1x
// 01: 2x
// 10: 3x
// 11: 4x
#define SC_PLLS_CTRL0 0x303a // Bit[7]: PLLS bypass
#define SC_PLLS_CTRL1 0x303b // Bit[4:0]: PLLS multiplier
#define SC_PLLS_CTRL2 0x303c // Bit[6:4]: PLLS charge pump control
// Bit[3:0]: PLLS system divider
#define SC_PLLS_CTRL3 0x303d // Bit[5:4]: PLLS pre-divider
// 00: 1
// 01: 1.5
// 10: 2
// 11: 3
// Bit[2]: PLLS root-divider - 1
// Bit[1:0]: PLLS seld5
// 00: 1
// 01: 1
// 10: 2
// 11: 2.5
/* AEC/AGC control functions */
#define AEC_PK_MANUAL 0x3503 // AEC Manual Mode Control
// Bit[7:6]: Reserved
// Bit[5]: Gain delay option
// Valid when 0x3503[4]=1’b0
// 0: Delay one frame latch
// 1: One frame latch
// Bit[4:2]: Reserved
// Bit[1]: AGC manual
// 0: Auto enable
// 1: Manual enable
// Bit[0]: AEC manual
// 0: Auto enable
// 1: Manual enable
//gain = {0x350A[1:0], 0x350B[7:0]} / 16
#define X_ADDR_ST_H 0x3800 //Bit[3:0]: X address start[11:8]
#define X_ADDR_ST_L 0x3801 //Bit[7:0]: X address start[7:0]
#define Y_ADDR_ST_H 0x3802 //Bit[2:0]: Y address start[10:8]
#define Y_ADDR_ST_L 0x3803 //Bit[7:0]: Y address start[7:0]
#define X_ADDR_END_H 0x3804 //Bit[3:0]: X address end[11:8]
#define X_ADDR_END_L 0x3805 //Bit[7:0]:
#define Y_ADDR_END_H 0x3806 //Bit[2:0]: Y address end[10:8]
#define Y_ADDR_END_L 0x3807 //Bit[7:0]:
// Size after scaling
#define X_OUTPUT_SIZE_H 0x3808 //Bit[3:0]: DVP output horizontal width[11:8]
#define X_OUTPUT_SIZE_L 0x3809 //Bit[7:0]:
#define Y_OUTPUT_SIZE_H 0x380a //Bit[2:0]: DVP output vertical height[10:8]
#define Y_OUTPUT_SIZE_L 0x380b //Bit[7:0]:
#define X_TOTAL_SIZE_H 0x380c //Bit[3:0]: Total horizontal size[11:8]
#define X_TOTAL_SIZE_L 0x380d //Bit[7:0]:
#define Y_TOTAL_SIZE_H 0x380e //Bit[7:0]: Total vertical size[15:8]
#define Y_TOTAL_SIZE_L 0x380f //Bit[7:0]:
#define X_OFFSET_H 0x3810 //Bit[3:0]: ISP horizontal offset[11:8]
#define X_OFFSET_L 0x3811 //Bit[7:0]:
#define Y_OFFSET_H 0x3812 //Bit[2:0]: ISP vertical offset[10:8]
#define Y_OFFSET_L 0x3813 //Bit[7:0]:
#define X_INCREMENT 0x3814 //Bit[7:4]: Horizontal odd subsample increment
//Bit[3:0]: Horizontal even subsample increment
#define Y_INCREMENT 0x3815 //Bit[7:4]: Vertical odd subsample increment
//Bit[3:0]: Vertical even subsample increment
// Size before scaling
//#define X_INPUT_SIZE (X_ADDR_END - X_ADDR_ST + 1 - (2 * X_OFFSET))
//#define Y_INPUT_SIZE (Y_ADDR_END - Y_ADDR_ST + 1 - (2 * Y_OFFSET))
/* mirror and flip registers */
#define TIMING_TC_REG20 0x3820 // Timing Control Register
// Bit[2:1]: Vertical flip enable
// 00: Normal
// 11: Vertical flip
// Bit[0]: Vertical binning enable
#define TIMING_TC_REG21 0x3821 // Timing Control Register
// Bit[5]: Compression Enable
// Bit[2:1]: Horizontal mirror enable
// 00: Normal
// 11: Horizontal mirror
// Bit[0]: Horizontal binning enable
#define PCLK_RATIO 0x3824 // Bit[4:0]: PCLK ratio manual
/* frame control registers */
#define FRAME_CTRL01 0x4201 // Control Passed Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
// Bit[7:4]: Not used
// Bit[3:0]: Frame ON number
#define FRAME_CTRL02 0x4202 // Control Masked Frame Number When both ON and OFF number set to 0x00,frame control is in bypass mode
// Bit[7:4]: Not used
// BIT[3:0]: Frame OFF number
/* format control registers */
#define FORMAT_CTRL00 0x4300
#define CLOCK_POL_CONTROL 0x4740// Bit[5]: PCLK polarity 0: active low
// 1: active high
// Bit[3]: Gate PCLK under VSYNC
// Bit[2]: Gate PCLK under HREF
// Bit[1]: HREF polarity
// 0: active low
// 1: active high
// Bit[0] VSYNC polarity
// 0: active low
// 1: active high
#define ISP_CONTROL_01 0x5001 // Bit[5]: Scale enable
// 0: Disable
// 1: Enable
/* output format control registers */
#define FORMAT_CTRL 0x501F // Format select
// Bit[2:0]:
// 000: YUV422
// 001: RGB
// 010: Dither
// 011: RAW after DPC
// 101: RAW after CIP
/* ISP top control registers */
#define PRE_ISP_TEST_SETTING_1 0x503D // Bit[7]: Test enable
// 0: Test disable
// 1: Color bar enable
// Bit[6]: Rolling
// Bit[5]: Transparent
// Bit[4]: Square black and white
// Bit[3:2]: Color bar style
// 00: Standard 8 color bar
// 01: Gradual change at vertical mode 1
// 10: Gradual change at horizontal
// 11: Gradual change at vertical mode 2
// Bit[1:0]: Test select
// 00: Color bar
// 01: Random data
// 10: Square data
// 11: Black image
//exposure = {0x3500[3:0], 0x3501[7:0], 0x3502[7:0]} / 16 × tROW
#define SCALE_CTRL_1 0x5601 // Bit[6:4]: HDIV RW
// DCW scale times
// 000: DCW 1 time
// 001: DCW 2 times
// 010: DCW 4 times
// 100: DCW 8 times
// 101: DCW 16 times
// Others: DCW 16 times
// Bit[2:0]: VDIV RW
// DCW scale times
// 000: DCW 1 time
// 001: DCW 2 times
// 010: DCW 4 times
// 100: DCW 8 times
// 101: DCW 16 times
// Others: DCW 16 times
#define SCALE_CTRL_2 0x5602 // X_SCALE High Bits
#define SCALE_CTRL_3 0x5603 // X_SCALE Low Bits
#define SCALE_CTRL_4 0x5604 // Y_SCALE High Bits
#define SCALE_CTRL_5 0x5605 // Y_SCALE Low Bits
#define SCALE_CTRL_6 0x5606 // Bit[3:0]: V Offset
#define VFIFO_CTRL0C 0x460C // Bit[1]: PCLK manual enable
// 0: Auto
// 1: Manual by PCLK_RATIO
#define VFIFO_X_SIZE_H 0x4602
#define VFIFO_X_SIZE_L 0x4603
#define VFIFO_Y_SIZE_H 0x4604
#define VFIFO_Y_SIZE_L 0x4605
#define COMPRESSION_CTRL00 0x4400 //
#define COMPRESSION_CTRL01 0x4401 //
#define COMPRESSION_CTRL02 0x4402 //
#define COMPRESSION_CTRL03 0x4403 //
#define COMPRESSION_CTRL04 0x4404 //
#define COMPRESSION_CTRL05 0x4405 //
#define COMPRESSION_CTRL06 0x4406 //
#define COMPRESSION_CTRL07 0x4407 // Bit[5:0]: QS
#define COMPRESSION_ISI_CTRL 0x4408 //
#define COMPRESSION_CTRL09 0x4409 //
#define COMPRESSION_CTRL0a 0x440a //
#define COMPRESSION_CTRL0b 0x440b //
#define COMPRESSION_CTRL0c 0x440c //
#define COMPRESSION_CTRL0d 0x440d //
#define COMPRESSION_CTRL0E 0x440e //
/**
* @brief register value
*/
#define TEST_COLOR_BAR 0xC0 /* Enable Color Bar roling Test */
#define AEC_PK_MANUAL_AGC_MANUALEN 0x02 /* Enable AGC Manual enable */
#define AEC_PK_MANUAL_AEC_MANUALEN 0x01 /* Enable AEC Manual enable */
#define TIMING_TC_REG20_VFLIP 0x06 /* Vertical flip enable */
#define TIMING_TC_REG21_HMIRROR 0x06 /* Horizontal mirror enable */
#endif // __OV3660_REG_REGS_H__

334
sensors/private_include/ov5640_settings.h

@ -0,0 +1,334 @@
#ifndef _OV5640_SETTINGS_H_
#define _OV5640_SETTINGS_H_
#include <stdint.h>
#include <stdbool.h>
#include "esp_attr.h"
#include "ov5640_regs.h"
static const ratio_settings_t ratio_table[] = {
// mw, mh, sx, sy, ex, ey, ox, oy, tx, ty
{ 2560, 1920, 0, 0, 2623, 1951, 32, 16, 2844, 1968 }, //4x3
{ 2560, 1704, 0, 110, 2623, 1843, 32, 16, 2844, 1752 }, //3x2
{ 2560, 1600, 0, 160, 2623, 1791, 32, 16, 2844, 1648 }, //16x10
{ 2560, 1536, 0, 192, 2623, 1759, 32, 16, 2844, 1584 }, //5x3
{ 2560, 1440, 0, 240, 2623, 1711, 32, 16, 2844, 1488 }, //16x9
{ 2560, 1080, 0, 420, 2623, 1531, 32, 16, 2844, 1128 }, //21x9
{ 2400, 1920, 80, 0, 2543, 1951, 32, 16, 2684, 1968 }, //5x4
{ 1920, 1920, 320, 0, 2543, 1951, 32, 16, 2684, 1968 }, //1x1
{ 1088, 1920, 736, 0, 1887, 1951, 32, 16, 1884, 1968 } //9x16
};
#define REG_DLY 0xffff
#define REGLIST_TAIL 0x0000
static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{SYSTEM_CTROL0, 0x82}, // software reset
{REG_DLY, 10}, // delay 10ms
{SYSTEM_CTROL0, 0x42}, // power down
//enable pll
{0x3103, 0x13},
//io direction
{0x3017, 0xff},
{0x3018, 0xff},
{DRIVE_CAPABILITY, 0xc3},
{CLOCK_POL_CONTROL, 0x21},
{0x4713, 0x02},//jpg mode select
{ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
//sys reset
{0x3000, 0x00},
{0x3002, 0x1c},
//clock enable
{0x3004, 0xff},
{0x3006, 0xc3},
//isp control
{0x5000, 0xa7},
{ISP_CONTROL_01, 0xa3},//+scaling?
{0x5003, 0x08},//special_effect
//unknown
{0x370c, 0x02},//!!IMPORTANT
{0x3634, 0x40},//!!IMPORTANT
//AEC/AGC
{0x3a02, 0x03},
{0x3a03, 0xd8},
{0x3a08, 0x01},
{0x3a09, 0x27},
{0x3a0a, 0x00},
{0x3a0b, 0xf6},
{0x3a0d, 0x04},
{0x3a0e, 0x03},
{0x3a0f, 0x30},//ae_level
{0x3a10, 0x28},//ae_level
{0x3a11, 0x60},//ae_level
{0x3a13, 0x43},
{0x3a14, 0x03},
{0x3a15, 0xd8},
{0x3a18, 0x00},//gainceiling
{0x3a19, 0xf8},//gainceiling
{0x3a1b, 0x30},//ae_level
{0x3a1e, 0x26},//ae_level
{0x3a1f, 0x14},//ae_level
//vcm debug
{0x3600, 0x08},
{0x3601, 0x33},
//50/60Hz
{0x3c01, 0xa4},
{0x3c04, 0x28},
{0x3c05, 0x98},
{0x3c06, 0x00},
{0x3c07, 0x08},
{0x3c08, 0x00},
{0x3c09, 0x1c},
{0x3c0a, 0x9c},
{0x3c0b, 0x40},
{0x460c, 0x22},//disable jpeg footer
//BLC
{0x4001, 0x02},
{0x4004, 0x02},
//AWB
{0x5180, 0xff},
{0x5181, 0xf2},
{0x5182, 0x00},
{0x5183, 0x14},
{0x5184, 0x25},
{0x5185, 0x24},
{0x5186, 0x09},
{0x5187, 0x09},
{0x5188, 0x09},
{0x5189, 0x75},
{0x518a, 0x54},
{0x518b, 0xe0},
{0x518c, 0xb2},
{0x518d, 0x42},
{0x518e, 0x3d},
{0x518f, 0x56},
{0x5190, 0x46},
{0x5191, 0xf8},
{0x5192, 0x04},
{0x5193, 0x70},
{0x5194, 0xf0},
{0x5195, 0xf0},
{0x5196, 0x03},
{0x5197, 0x01},
{0x5198, 0x04},
{0x5199, 0x12},
{0x519a, 0x04},
{0x519b, 0x00},
{0x519c, 0x06},
{0x519d, 0x82},
{0x519e, 0x38},
//color matrix (Saturation)
{0x5381, 0x1e},
{0x5382, 0x5b},
{0x5383, 0x08},
{0x5384, 0x0a},
{0x5385, 0x7e},
{0x5386, 0x88},
{0x5387, 0x7c},
{0x5388, 0x6c},
{0x5389, 0x10},
{0x538a, 0x01},
{0x538b, 0x98},
//CIP control (Sharpness)
{0x5300, 0x10},//sharpness
{0x5301, 0x10},//sharpness
{0x5302, 0x18},//sharpness
{0x5303, 0x19},//sharpness
{0x5304, 0x10},
{0x5305, 0x10},
{0x5306, 0x08},//denoise
{0x5307, 0x16},
{0x5308, 0x40},
{0x5309, 0x10},//sharpness
{0x530a, 0x10},//sharpness
{0x530b, 0x04},//sharpness
{0x530c, 0x06},//sharpness
//GAMMA
{0x5480, 0x01},
{0x5481, 0x00},
{0x5482, 0x1e},
{0x5483, 0x3b},
{0x5484, 0x58},
{0x5485, 0x66},
{0x5486, 0x71},
{0x5487, 0x7d},
{0x5488, 0x83},
{0x5489, 0x8f},
{0x548a, 0x98},
{0x548b, 0xa6},
{0x548c, 0xb8},
{0x548d, 0xca},
{0x548e, 0xd7},
{0x548f, 0xe3},
{0x5490, 0x1d},
//Special Digital Effects (SDE) (UV adjust)
{0x5580, 0x06},//enable brightness and contrast
{0x5583, 0x40},//special_effect
{0x5584, 0x10},//special_effect
{0x5586, 0x20},//contrast
{0x5587, 0x00},//brightness
{0x5588, 0x00},//brightness
{0x5589, 0x10},
{0x558a, 0x00},
{0x558b, 0xf8},
{0x501d, 0x40},// enable manual offset of contrast
//power on
{0x3008, 0x02},
//50Hz
{0x3c00, 0x04},
{REG_DLY, 300},
{REGLIST_TAIL, 0x00}, // tail
};
static const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x30}, // YUYV
{0x3002, 0x00},//0x1c to 0x00 !!!
{0x3006, 0xff},//0xc3 to 0xff !!!
{0x471c, 0x50},//0xd0 to 0x50 !!!
{REGLIST_TAIL, 0x00}, // tail
};
static const DRAM_ATTR uint16_t sensor_fmt_raw[][2] = {
{FORMAT_CTRL, 0x03}, // RAW (DPC)
{FORMAT_CTRL00, 0x00}, // RAW
{REGLIST_TAIL, 0x00}
};
static const DRAM_ATTR uint16_t sensor_fmt_grayscale[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x10}, // Y8
{REGLIST_TAIL, 0x00}
};
static const DRAM_ATTR uint16_t sensor_fmt_yuv422[][2] = {
{FORMAT_CTRL, 0x00}, // YUV422
{FORMAT_CTRL00, 0x30}, // YUYV
{REGLIST_TAIL, 0x00}
};
static const DRAM_ATTR uint16_t sensor_fmt_rgb565[][2] = {
{FORMAT_CTRL, 0x01}, // RGB
{FORMAT_CTRL00, 0x61}, // RGB565 (BGR)
{REGLIST_TAIL, 0x00}
};
static const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
{0x1d, 0x60, 0x03, 0x07, 0x48, 0x4f, 0x4b, 0x40, 0x0b, 0x01, 0x98},//-4
{0x1d, 0x60, 0x03, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
{0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
{0x1d, 0x60, 0x03, 0x0b, 0x6c, 0x77, 0x70, 0x60, 0x10, 0x01, 0x98},//-1
{0x1d, 0x60, 0x03, 0x0c, 0x78, 0x84, 0x7d, 0x6b, 0x12, 0x01, 0x98},//0
{0x1d, 0x60, 0x03, 0x0d, 0x84, 0x91, 0x8a, 0x76, 0x14, 0x01, 0x98},//+1
{0x1d, 0x60, 0x03, 0x0e, 0x90, 0x9e, 0x96, 0x80, 0x16, 0x01, 0x98},//+2
{0x1d, 0x60, 0x03, 0x10, 0x9c, 0xac, 0xa2, 0x8b, 0x17, 0x01, 0x98},//+3
{0x1d, 0x60, 0x03, 0x11, 0xa8, 0xb9, 0xaf, 0x96, 0x19, 0x01, 0x98},//+4
};
static const DRAM_ATTR uint8_t sensor_special_effects[7][4] = {
{0x06, 0x40, 0x2c, 0x08},//Normal
{0x46, 0x40, 0x28, 0x08},//Negative
{0x1e, 0x80, 0x80, 0x08},//Grayscale
{0x1e, 0x80, 0xc0, 0x08},//Red Tint
{0x1e, 0x60, 0x60, 0x08},//Green Tint
{0x1e, 0xa0, 0x40, 0x08},//Blue Tint
{0x1e, 0x40, 0xa0, 0x08},//Sepia
};
static const DRAM_ATTR uint16_t sensor_regs_gamma0[][2] = {
{0x5480, 0x01},
{0x5481, 0x08},
{0x5482, 0x14},
{0x5483, 0x28},
{0x5484, 0x51},
{0x5485, 0x65},
{0x5486, 0x71},
{0x5487, 0x7d},
{0x5488, 0x87},
{0x5489, 0x91},
{0x548a, 0x9a},
{0x548b, 0xaa},
{0x548c, 0xb8},
{0x548d, 0xcd},
{0x548e, 0xdd},
{0x548f, 0xea},
{0x5490, 0x1d}
};
static const DRAM_ATTR uint16_t sensor_regs_gamma1[][2] = {
{0x5480, 0x1},
{0x5481, 0x0},
{0x5482, 0x1e},
{0x5483, 0x3b},
{0x5484, 0x58},
{0x5485, 0x66},
{0x5486, 0x71},
{0x5487, 0x7d},
{0x5488, 0x83},
{0x5489, 0x8f},
{0x548a, 0x98},
{0x548b, 0xa6},
{0x548c, 0xb8},
{0x548d, 0xca},
{0x548e, 0xd7},
{0x548f, 0xe3},
{0x5490, 0x1d}
};
static const DRAM_ATTR uint16_t sensor_regs_awb0[][2] = {
{0x5180, 0xff},
{0x5181, 0xf2},
{0x5182, 0x00},
{0x5183, 0x14},
{0x5184, 0x25},
{0x5185, 0x24},
{0x5186, 0x09},
{0x5187, 0x09},
{0x5188, 0x09},
{0x5189, 0x75},
{0x518a, 0x54},
{0x518b, 0xe0},
{0x518c, 0xb2},
{0x518d, 0x42},
{0x518e, 0x3d},
{0x518f, 0x56},
{0x5190, 0x46},
{0x5191, 0xf8},
{0x5192, 0x04},
{0x5193, 0x70},
{0x5194, 0xf0},
{0x5195, 0xf0},
{0x5196, 0x03},
{0x5197, 0x01},
{0x5198, 0x04},
{0x5199, 0x12},
{0x519a, 0x04},
{0x519b, 0x00},
{0x519c, 0x06},
{0x519d, 0x82},
{0x519e, 0x38}
};
#endif
Loading…
Cancel
Save