add OV5640 driver

This commit is contained in:
jjsch-dev
2020-03-07 19:10:02 -03:00
parent 5957101010
commit df03701ff7
17 changed files with 330 additions and 118 deletions

View File

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

15
Kconfig
View File

@ -5,28 +5,35 @@ config OV2640_SUPPORT
default y
help
Enable this option if you want to use the OV2640.
Disable this option to safe memory.
Disable this option to save memory.
config OV7670_SUPPORT
bool "OV7670 Support"
default y
help
Enable this option if you want to use the OV7670.
Disable this option to safe memory.
Disable this option to save memory.
config OV7725_SUPPORT
bool "OV7725 Support"
default n
help
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
bool "OV3660 Support"
default y
help
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
bool "Use hardware I2C1 for SCCB"

View File

@ -2,7 +2,7 @@
## General Information
This repository hosts ESP32 compatible driver for OV2640, OV3660 and OV7670 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 compatible driver for OV2640, OV3660, OV5640 and OV7670 image sensors. Additionally it provides a few tools, which allow converting the captured frame data to the more common BMP and JPEG formats.
## Important to Remember

View File

@ -14,7 +14,7 @@
#include "esp_jpg_decode.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
#include "esp32/rom/tjpgd.h"
#else

View File

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

View File

@ -22,7 +22,7 @@
#include "yuv.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
#include "esp32/spiram.h"
#else

View File

@ -45,6 +45,9 @@
#if CONFIG_OV3660_SUPPORT
#include "ov3660.h"
#endif
#if CONFIG_OV5640_SUPPORT
#include "ov5640.h"
#endif
#if CONFIG_OV7670_SUPPORT
#include "ov7670.h"
#endif
@ -55,6 +58,7 @@ typedef enum {
CAMERA_OV7725 = 7725,
CAMERA_OV2640 = 2640,
CAMERA_OV3660 = 3660,
CAMERA_OV5640 = 5640,
CAMERA_OV7670 = 7670,
} camera_model_t;
@ -84,6 +88,7 @@ typedef struct camera_fb_s {
size_t width;
size_t height;
pixformat_t format;
struct timeval timestamp;
size_t size;
uint8_t ref;
uint8_t bad;
@ -550,6 +555,7 @@ static void IRAM_ATTR signal_dma_buf_received(bool* need_yield)
}
//ESP_EARLY_LOGW(TAG, "qsf:%d", 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);
}
@ -581,6 +587,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) {
i2s_stop(&need_yield);
}
//ets_printf("vs\n");
}
if(s_state->config.fb_count > 1 || s_state->dma_filtered_count < 2) {
I2S0.conf.rx_start = 0;
@ -673,6 +680,7 @@ static void IRAM_ATTR dma_finish_frame()
if(s_state->config.fb_count == 1) {
i2s_start_bus();
}
//ets_printf("bad\n");
} else {
s_state->fb->len = s_state->dma_filtered_count * buf_len;
if(s_state->fb->len) {
@ -699,6 +707,8 @@ static void IRAM_ATTR dma_finish_frame()
} else if(s_state->config.fb_count == 1){
//frame was empty?
i2s_start_bus();
} else {
//ets_printf("empty\n");
}
}
} else if(s_state->fb->len) {
@ -732,15 +742,19 @@ static void IRAM_ATTR dma_filter_buffer(size_t buf_idx)
if(s_state->sensor.pixformat == PIXFORMAT_JPEG) {
uint32_t sig = *((uint32_t *)s_state->fb->buf) & 0xFFFFFF;
if(sig != 0xffd8ff) {
//ets_printf("bad header\n");
ets_printf("bh 0x%08x\n", sig);
s_state->fb->bad = 1;
return;
}
}
//set the frame properties
s_state->fb->width = resolution[s_state->sensor.status.framesize][0];
s_state->fb->height = resolution[s_state->sensor.status.framesize][1];
s_state->fb->width = resolution[s_state->sensor.status.framesize].width;
s_state->fb->height = resolution[s_state->sensor.status.framesize].height;
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++;
}
@ -976,13 +990,6 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
vTaskDelay(10 / portTICK_PERIOD_MS);
gpio_set_level(config->pin_reset, 1);
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");
@ -993,14 +1000,12 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
camera_disable_out_clock();
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;
ESP_LOGD(TAG, "Detected camera at address=0x%02x", s_state->sensor.slv_addr);
//slv_addr = 0x30;
ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr);
sensor_id_t* id = &s_state->sensor.id;
#if (CONFIG_OV2640_SUPPORT && CONFIG_OV3660_SUPPORT)
#if CONFIG_OV2640_SUPPORT
if (slv_addr == 0x30) {
ESP_LOGD(TAG, "Resetting OV2640");
//camera might be OV2640. try to reset it
@ -1011,7 +1016,10 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
}
#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){
id->PID = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDH);
id->VER = SCCB_Read16(s_state->sensor.slv_addr, REG16_CHIDL);
@ -1026,7 +1034,8 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
vTaskDelay(10 / portTICK_PERIOD_MS);
ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
id->PID, id->VER, id->MIDH, id->MIDL);
#if CONFIG_OV3660_SUPPORT
#if (CONFIG_OV3660_SUPPORT || CONFIG_OV5640_SUPPORT)
}
#endif
@ -1050,6 +1059,12 @@ esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera
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;
@ -1082,12 +1097,53 @@ esp_err_t camera_init(const camera_config_t* config)
esp_err_t err = ESP_OK;
framesize_t frame_size = (framesize_t) config->frame_size;
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
#if CONFIG_OV7670_SUPPORT
case OV7725_PID:
if (frame_size > FRAMESIZE_VGA) {
frame_size = FRAMESIZE_VGA;
}
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) {
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()) {
s_state->sampling_mode = SM_0A00_0B00;
s_state->dma_filter = &dma_filter_yuyv_highspeed;
@ -1138,8 +1194,8 @@ esp_err_t camera_init(const camera_config_t* config)
s_state->in_bytes_per_pixel = 2; // camera sends RGB565
s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888
} else if (pix_format == PIXFORMAT_JPEG) {
if (s_state->sensor.id.PID != OV2640_PID && s_state->sensor.id.PID != OV3660_PID) {
ESP_LOGE(TAG, "JPEG format is only supported for ov2640 and ov3660");
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, ov3660 and ov5640");
err = ESP_ERR_NOT_SUPPORTED;
goto fail;
}
@ -1286,6 +1342,8 @@ esp_err_t esp_camera_init(const camera_config_t* config)
ESP_LOGD(TAG, "Detected OV2640 camera");
} else if (camera_model == CAMERA_OV3660) {
ESP_LOGD(TAG, "Detected OV3660 camera");
} else if (camera_model == CAMERA_OV5640) {
ESP_LOGD(TAG, "Detected OV5640 camera");
} else if (camera_model == CAMERA_OV7670) {
ESP_LOGD(TAG, "Detected OV7670 camera");
if(config->pixel_format == PIXFORMAT_JPEG) {

View File

@ -115,6 +115,7 @@ typedef struct {
size_t width; /*!< Width of the buffer in pixels */
size_t height; /*!< Height of the buffer in pixels */
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;
#define ESP_ERR_CAMERA_BASE 0x20000

View File

@ -9,11 +9,14 @@
#ifndef __SENSOR_H__
#define __SENSOR_H__
#include <stdint.h>
#include <stdbool.h>
#define OV9650_PID (0x96)
#define OV2640_PID (0x26)
#define OV7725_PID (0x77)
#define OV2640_PID (0x26)
#define OV3660_PID (0x36)
#define OV5640_PID (0x56)
#define OV7670_PID (0x76)
typedef enum {
@ -28,23 +31,39 @@ typedef enum {
} pixformat_t;
typedef enum {
FRAMESIZE_96x96, // 96x96
FRAMESIZE_96X96, // 96x96
FRAMESIZE_QQVGA, // 160x120
FRAMESIZE_QQVGA2, // 128x160
FRAMESIZE_QCIF, // 176x144
FRAMESIZE_HQVGA, // 240x176
FRAMESIZE_240x240, // 240x240
FRAMESIZE_240X240, // 240x240
FRAMESIZE_QVGA, // 320x240
FRAMESIZE_CIF, // 400x296
FRAMESIZE_HVGA, // 480x320
FRAMESIZE_VGA, // 640x480
FRAMESIZE_SVGA, // 800x600
FRAMESIZE_XGA, // 1024x768
FRAMESIZE_HD, // 1280x720
FRAMESIZE_SXGA, // 1280x1024
FRAMESIZE_UXGA, // 1600x1200
FRAMESIZE_QXGA, // 2048*1536
FRAMESIZE_FHD, // 1920x1080
FRAMESIZE_QXGA, // 2048x1536
FRAMESIZE_QHD, // 2560x1440
FRAMESIZE_WQXGA, // 2560x1600
FRAMESIZE_QSXGA, // 2560x1920
FRAMESIZE_INVALID
} 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_t;
typedef enum {
GAINCEILING_2X,
GAINCEILING_4X,
@ -55,6 +74,28 @@ typedef enum {
GAINCEILING_128X,
} 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 {
uint8_t MIDH;
uint8_t MIDL;
@ -133,9 +174,12 @@ typedef struct _sensor {
int (*set_raw_gma) (sensor_t *sensor, int enable);
int (*set_lenc) (sensor_t *sensor, int enable);
int (*get_reg) (sensor_t *sensor, int reg, int mask);
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
int (*set_res_raw) (sensor_t *sensor, int reg4520, int incrementX, int incrementY, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, int reg20, int reg21, int reg4514);
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;
// Resolution table (in camera.c)
extern const int resolution[][2];
#endif /* __SENSOR_H__ */

View File

@ -12,7 +12,7 @@
#include "sensor.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
#include "esp32/rom/lldesc.h"
#else

View File

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

View File

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

View File

@ -12,19 +12,28 @@
static const char* TAG = "camera_xclk";
#endif
esp_err_t xclk_timer_conf(int ledc_timer, int xclk_freq_hz)
{
ledc_timer_config_t timer_conf;
timer_conf.duty_resolution = 2;
timer_conf.freq_hz = xclk_freq_hz;
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
#if ESP_IDF_VERSION_MAJOR >= 4
timer_conf.clk_cfg = LEDC_AUTO_CLK;
#endif
timer_conf.timer_num = (ledc_timer_t)ledc_timer;
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);
ledc_timer_config_t timer_conf = {};
timer_conf.duty_resolution = 2;
timer_conf.freq_hz = config->xclk_freq_hz;
timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE;
timer_conf.timer_num = config->ledc_timer;
#ifdef ESP_IDF_VERSION_MAJOR
timer_conf.clk_cfg = LEDC_AUTO_CLK;
#endif
esp_err_t err = ledc_timer_config(&timer_conf);
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;

View File

@ -225,8 +225,8 @@ int set_image_size(sensor_t *sensor, uint16_t width, uint16_t height)
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
int ret = 0;
uint16_t w = resolution[framesize][0];
uint16_t h = resolution[framesize][1];
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
const uint8_t (*regs)[2];
sensor->status.framesize = framesize;

View File

@ -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)
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_seld52x_map[] = { 2, 2, 4, 5 };
@ -246,18 +246,24 @@ static int set_image_options(sensor_t *sensor)
uint8_t reg4514 = 0;
uint8_t reg4514_test = 0;
uint16_t w = resolution[sensor->status.framesize].width;
uint16_t h = resolution[sensor->status.framesize].height;
aspect_ratio_t ratio = resolution[sensor->status.framesize].aspect_ratio;
ratio_settings_t settings = ratio_table[ratio];
bool bining = (w <= (settings.max_width / 2) && h <= (settings.max_height / 2));
// compression
if (sensor->pixformat == PIXFORMAT_JPEG) {
reg21 |= 0x20;
}
// binning
if (sensor->status.framesize > FRAMESIZE_SVGA) {
reg20 |= 0x40;
} else {
if (bining) {
reg20 |= 0x01;
reg21 |= 0x01;
reg4514_test |= 4;
} else {
reg20 |= 0x40;
}
// V-Flip
@ -293,7 +299,7 @@ static int set_image_options(sensor_t *sensor)
}
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, bining, sensor->status.vflip, sensor->status.hmirror, reg4514);
return ret;
}
@ -303,51 +309,48 @@ static int set_framesize(sensor_t *sensor, framesize_t framesize)
framesize_t old_framesize = sensor->status.framesize;
sensor->status.framesize = framesize;
if(framesize >= FRAMESIZE_INVALID){
if(framesize > FRAMESIZE_QXGA){
ESP_LOGE(TAG, "Invalid framesize: %u", framesize);
return -1;
}
uint16_t w = resolution[framesize][0];
uint16_t h = resolution[framesize][1];
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
aspect_ratio_t ratio = resolution[sensor->status.framesize].aspect_ratio;
ratio_settings_t settings = ratio_table[ratio];
bool bining = (w <= (settings.max_width / 2) && h <= (settings.max_height / 2));
if (framesize > FRAMESIZE_SVGA) {
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
} else {
if (bining) {
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
}
if (ret) {
goto fail;
}
ret = write_addr_reg(sensor->slv_addr, X_ADDR_ST_H, 0, 0)
|| write_addr_reg(sensor->slv_addr, X_ADDR_END_H, 2079, 1547)
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, settings.end_x, settings.end_y)
|| write_addr_reg(sensor->slv_addr, X_OUTPUT_SIZE_H, w, h);
if (ret) {
goto fail;
}
if (framesize > FRAMESIZE_SVGA) {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2300, 1564)
|| write_addr_reg(sensor->slv_addr, X_OFFSET_H, 16, 6);
if (bining) {
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, 8, 2);
} else {
if (framesize == FRAMESIZE_SVGA) {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2300, 788);
} else {
ret = write_addr_reg(sensor->slv_addr, X_TOTAL_SIZE_H, 2050, 788);
}
if (ret == 0) {
ret = write_addr_reg(sensor->slv_addr, X_OFFSET_H, 8, 2);
}
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_reg_bits(sensor->slv_addr, ISP_CONTROL_01, 0x20, framesize != FRAMESIZE_QXGA);
ret = write_reg_bits(sensor->slv_addr, ISP_CONTROL_01, 0x20, !(w == settings.max_width && h == settings.max_height));
}
if (ret == 0) {
@ -880,6 +883,65 @@ static int set_denoise(sensor_t *sensor, int level)
return ret;
}
static int get_reg(sensor_t *sensor, int reg, int mask){
int ret = 0;
if(mask > 0xFF){
ret = read_reg16(sensor->slv_addr, reg);
} else {
ret = read_reg(sensor->slv_addr, reg);
}
if(ret > 0){
ret &= mask;
}
return ret;
}
static int sensor_set_reg(sensor_t *sensor, int reg, int mask, int value){
return set_reg_bits(sensor->slv_addr, reg & 0xffff, 0, mask & 0xff, value & 0xff);
}
static int set_res_raw(sensor_t *sensor, int reg4520, int incrementX, int incrementY, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, int reg20, int reg21, int reg4514)
{
int ret = 0;
if(outputX > 800 || outputY > 600){
reg4520 = 0xb0;
incrementX = 0x11;
incrementY = 0x11;
} else {
reg4520 = 0x0b;
incrementX = 0x31;
incrementY = 0x31;
}
ret = write_reg(sensor->slv_addr, 0x4520, reg4520)
|| write_reg(sensor->slv_addr, X_INCREMENT, incrementX)//odd:1, even: 1
|| write_reg(sensor->slv_addr, Y_INCREMENT, incrementY)//odd:1, even: 1
|| 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);
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)
{
int ret = 0;
ret = set_pll(sensor, bypass > 0, multiplier, sys_div, pre_div, root_2x > 0, seld5, pclk_manual > 0, pclk_div);
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;
sensor->xclk_freq_hz = xclk * 1000000U;
ret = xclk_timer_conf(timer, sensor->xclk_freq_hz);
return ret;
}
static int init_status(sensor_t *sensor)
{
sensor->status.brightness = 0;
@ -941,5 +1003,11 @@ int ov3660_init(sensor_t *sensor)
sensor->set_raw_gma = set_raw_gma_dsp;
sensor->set_lenc = set_lenc_dsp;
sensor->set_denoise = set_denoise;
sensor->get_reg = get_reg;
sensor->set_reg = sensor_set_reg;
sensor->set_res_raw = set_res_raw;
sensor->set_pll = _set_pll;
sensor->set_xclk = set_xclk;
return 0;
}

View File

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

View File

@ -6,10 +6,22 @@
#include "esp_attr.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
};
#define REG_DLY 0xffff
#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
{REG_DLY, 10}, // delay 10ms
@ -131,22 +143,23 @@ const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{0x538a, 0x01},
{0x538b, 0x98},
{0x5481, 0x05},
{0x5482, 0x09},
{0x5483, 0x10},
{0x5484, 0x3a},
{0x5485, 0x4c},
{0x5486, 0x5a},
{0x5487, 0x68},
{0x5488, 0x74},
{0x5489, 0x80},
{0x548a, 0x8e},
{0x548b, 0xa4},
{0x548c, 0xb4},
{0x548d, 0xc8},
{0x548e, 0xde},
{0x548f, 0xf0},
{0x5490, 0x15},
{0x5480, 0x01},
// {0x5481, 0x05},
// {0x5482, 0x09},
// {0x5483, 0x10},
// {0x5484, 0x3a},
// {0x5485, 0x4c},
// {0x5486, 0x5a},
// {0x5487, 0x68},
// {0x5488, 0x74},
// {0x5489, 0x80},
// {0x548a, 0x8e},
// {0x548b, 0xa4},
// {0x548c, 0xb4},
// {0x548d, 0xc8},
// {0x548e, 0xde},
// {0x548f, 0xf0},
// {0x5490, 0x15},
{0x5000, 0xa7},
{0x5800, 0x0C},
@ -247,7 +260,7 @@ const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
{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_CTRL00, 0x30}, // YUYV
{0x3002, 0x00},//0x1c to 0x00 !!!
@ -256,30 +269,30 @@ const DRAM_ATTR uint16_t sensor_fmt_jpeg[][2] = {
{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
{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_CTRL00, 0x10}, // Y8
{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_CTRL00, 0x30}, // YUYV
{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_CTRL00, 0x61}, // RGB565 (BGR)
{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, 0x08, 0x54, 0x5c, 0x58, 0x4b, 0x0d, 0x01, 0x98},//-3
{0x1d, 0x60, 0x03, 0x0a, 0x60, 0x6a, 0x64, 0x56, 0x0e, 0x01, 0x98},//-2
@ -291,7 +304,7 @@ const DRAM_ATTR uint8_t sensor_saturation_levels[9][11] = {
{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
{0x46, 0x40, 0x28, 0x08},//Negative
{0x1e, 0x80, 0x80, 0x08},//Grayscale