Browse Source

feat: add sc101iot camera sensor driver (#412)

pull/414/head
yuxinwww 3 years ago committed by GitHub
parent
commit
eee63849f4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      CMakeLists.txt
  2. 25
      Kconfig
  3. 1
      README.md
  4. 6
      driver/esp_camera.c
  5. 3
      driver/include/sensor.h
  6. 1
      driver/sensor.c
  7. 31
      sensors/private_include/sc101iot.h
  8. 257
      sensors/private_include/sc101iot_settings.h
  9. 4
      sensors/sc030iot.c
  10. 342
      sensors/sc101iot.c

1
CMakeLists.txt

@ -39,6 +39,7 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
sensors/gc032a.c sensors/gc032a.c
sensors/bf3005.c sensors/bf3005.c
sensors/bf20a6.c sensors/bf20a6.c
sensors/sc101iot.c
sensors/sc030iot.c sensors/sc030iot.c
) )

25
Kconfig

@ -77,6 +77,31 @@ menu "Camera configuration"
Enable this option if you want to use the BF20A6. Enable this option if you want to use the BF20A6.
Disable this option to save memory. Disable this option to save memory.
config SC101IOT_SUPPORT
bool "Support SC101IOT HD"
default n
help
Enable this option if you want to use the SC101IOT.
Disable this option to save memory.
choice SC101_REGS_SELECT
prompt "SC101iot default regs"
default SC101IOT_720P_15FPS_ENABLED
depends on SC101IOT_SUPPORT
help
Currently SC010iot has several register sets available.
Select the one that matches your needs.
config SC101IOT_720P_15FPS_ENABLED
bool "xclk20M_720p_15fps"
help
Select this option means that when xclk is 20M, the frame rate is 15fps at 720p resolution.
config SC101IOT_VGA_25FPS_ENABLED
bool "xclk20M_VGA_25fps"
help
Select this option means that when xclk is 20M, the frame rate is 25fps at VGA resolution.
endchoice
config SC030IOT_SUPPORT config SC030IOT_SUPPORT
bool "Support SC030IOT VGA" bool "Support SC030IOT VGA"
default y default y

1
README.md

@ -26,6 +26,7 @@ This repository hosts ESP32 series Soc compatible driver for image sensors. Addi
| GC2145 | 1600 x 1200 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/5" | | GC2145 | 1600 x 1200 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/5" |
| BF3005 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/4" | | BF3005 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/4" |
| BF20A6 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer | 1/10" | | BF20A6 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer | 1/10" |
| SC101IOT| 1280 x 720 | color | YUV/YCbCr422<br/>Raw RGB | 1/4.2" |
| SC030IOT| 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer | 1/6.5" | | SC030IOT| 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer | 1/6.5" |
## Important to Remember ## Important to Remember

6
driver/esp_camera.c

@ -60,6 +60,9 @@
#if CONFIG_BF20A6_SUPPORT #if CONFIG_BF20A6_SUPPORT
#include "bf20a6.h" #include "bf20a6.h"
#endif #endif
#if CONFIG_SC101IOT_SUPPORT
#include "sc101iot.h"
#endif
#if CONFIG_SC030IOT_SUPPORT #if CONFIG_SC030IOT_SUPPORT
#include "sc030iot.h" #include "sc030iot.h"
#endif #endif
@ -128,6 +131,9 @@ static const sensor_func_t g_sensors[] = {
#if CONFIG_BF20A6_SUPPORT #if CONFIG_BF20A6_SUPPORT
{bf20a6_detect, bf20a6_init}, {bf20a6_detect, bf20a6_init},
#endif #endif
#if CONFIG_SC101IOT_SUPPORT
{sc101iot_detect, sc101iot_init},
#endif
#if CONFIG_SC030IOT_SUPPORT #if CONFIG_SC030IOT_SUPPORT
{sc030iot_detect, sc030iot_init}, {sc030iot_detect, sc030iot_init},
#endif #endif

3
driver/include/sensor.h

@ -28,6 +28,7 @@ typedef enum {
GC0308_PID = 0x9b, GC0308_PID = 0x9b,
BF3005_PID = 0x30, BF3005_PID = 0x30,
BF20A6_PID = 0x20a6, BF20A6_PID = 0x20a6,
SC101IOT_PID = 0xda4a,
SC030IOT_PID = 0x9a46, SC030IOT_PID = 0x9a46,
} camera_pid_t; } camera_pid_t;
@ -43,6 +44,7 @@ typedef enum {
CAMERA_GC0308, CAMERA_GC0308,
CAMERA_BF3005, CAMERA_BF3005,
CAMERA_BF20A6, CAMERA_BF20A6,
CAMERA_SC101IOT,
CAMERA_SC030IOT, CAMERA_SC030IOT,
CAMERA_MODEL_MAX, CAMERA_MODEL_MAX,
CAMERA_NONE, CAMERA_NONE,
@ -60,6 +62,7 @@ typedef enum {
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1 GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
BF3005_SCCB_ADDR = 0x6E, BF3005_SCCB_ADDR = 0x6E,
BF20A6_SCCB_ADDR = 0x6E, BF20A6_SCCB_ADDR = 0x6E,
SC101IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1 SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
} camera_sccb_addr_t; } camera_sccb_addr_t;

1
driver/sensor.c

@ -14,6 +14,7 @@ const camera_sensor_info_t camera_sensor[CAMERA_MODEL_MAX] = {
{CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false}, {CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false},
{CAMERA_BF3005, "BF3005", BF3005_SCCB_ADDR, BF3005_PID, FRAMESIZE_VGA, false}, {CAMERA_BF3005, "BF3005", BF3005_SCCB_ADDR, BF3005_PID, FRAMESIZE_VGA, false},
{CAMERA_BF20A6, "BF20A6", BF20A6_SCCB_ADDR, BF20A6_PID, FRAMESIZE_VGA, false}, {CAMERA_BF20A6, "BF20A6", BF20A6_SCCB_ADDR, BF20A6_PID, FRAMESIZE_VGA, false},
{CAMERA_SC101IOT, "SC101IOT", SC101IOT_SCCB_ADDR, SC101IOT_PID, FRAMESIZE_HD, false},
{CAMERA_SC030IOT, "SC030IOT", SC030IOT_SCCB_ADDR, SC030IOT_PID, FRAMESIZE_VGA, false}, {CAMERA_SC030IOT, "SC030IOT", SC030IOT_SCCB_ADDR, SC030IOT_PID, FRAMESIZE_VGA, false},
}; };

31
sensors/private_include/sc101iot.h

@ -0,0 +1,31 @@
/*
*
* SC101IOT DVP driver.
*
*/
#ifndef __SC101IOT_H__
#define __SC101IOT_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 sc101iot_detect(int slv_addr, sensor_id_t *id);
/**
* @brief initialize sensor function pointers
*
* @param sensor pointer of sensor
* @return
* Always 0
*/
int sc101iot_init(sensor_t *sensor);
#endif // __SC101IOT_H__

257
sensors/private_include/sc101iot_settings.h

@ -0,0 +1,257 @@
//Preview Type:0:DVP Raw 10 bit// 1:Raw 8 bit// 2:YUV422// 3:RAW16
//Preview Type:4:RGB565// 5:Pixart SPI// 6:MIPI 10bit// 7:MIPI 12bit// 8: MTK SPI
//port 0:MIPI// 1:Parallel// 2:MTK// 3:SPI// 4:TEST// 5: HISPI// 6 : Z2P/Z4P
//I2C Mode :0:Normal 8Addr,8Data// 1:Samsung 8 Addr,8Data// 2:Micron 8 Addr,16Data
//I2C Mode :3:Stmicro 16Addr,8Data//4:Micron2 16 Addr,16Data
//Out Format :0:YCbYCr/RG_GB// 1:YCrYCb/GR_BG// 2:CbYCrY/GB_RG// 3:CrYCbY/BG_GR
//MCLK Speed :0:6M//1:8M//2:10M//3:11.4M//4:12M//5:12.5M//6:13.5M//7:15M//8:18M//9:24M
//pin :BIT0 pwdn// BIT1:reset
//avdd 0:2.8V// 1:2.5V// 2:1.8V
//dovdd 0:2.8V// 1:2.5V// 2:1.8V
//dvdd 0:1.8V// 1:1.5V// 2:1.2V
/*
[DataBase]
DBName=DemoSens
[Vendor]
VendorName=SmartSens
I2C_CRC=0
[Sensor]
SensorName=SC101AP_raw
width=1280
height=720
port=1
type=2
pin=3
SlaveID=0xd0
mode=0
FlagReg=0xf7
FlagMask=0xff
FlagData=0xda
FlagReg1=0xf8
FlagMask1=0xff
FlagData1=0x4a
outformat=0
mclk=20
avdd=2.800000
dovdd=2.800000
dvdd=1.200000
Ext0=0
Ext1=0
Ext2=0
AFVCC=0.00
VPP=0.000000
*/
#include <stdint.h>
static const uint8_t sc101iot_default_init_regs[][2] = {
#if CONFIG_SC101IOT_720P_15FPS_ENABLED // 720P+YUV422+15FPS sensor default regs
/* Here are some test results:
# size xclk fps pic pclk
# ------- ------- ------ --------- ------- --- --- --- --- ---
# 720p 4 3 err
# 720p 8 5 normal 15
# 720p 10 7.8 normal 19
# 720p 20 15 warning 37.5
# VGA 8 6 normal
# VGA 20 16 normal
*/
{0xf0, 0x30},
{0x01, 0xff},
{0x02, 0xe0},
{0x30, 0x10},
{0x3f, 0x81},
{0xf0, 0x00},
{0x70, 0x6b},
{0x72, 0x30},
{0x84, 0xb4},
{0x8b, 0x00},
{0x8c, 0x20},
{0x8d, 0x02},
{0x8e, 0xec},
{0x9e, 0x10},
{0xb0, 0xc1},
{0xc8, 0x10},
{0xc9, 0x10},
{0xc6, 0x00},
{0xe0, 0x0f},
{0xb5, 0xf0},
{0xde, 0x80},
{0xb5, 0xf0},
{0xde, 0x80},
{0xb2, 0x50},
{0xb3, 0xfc},
{0xb4, 0x40},
{0xb5, 0xc0},
{0xb6, 0x50},
{0xb7, 0xfc},
{0xb8, 0x40},
{0xb9, 0xc0},
{0xba, 0xff},
{0xbb, 0xcc},
{0xbc, 0xa9},
{0xbd, 0x7d},
{0xc1, 0x77},
{0xf0, 0x01},
{0x70, 0x02},
{0x71, 0x02},
{0x72, 0x50},
{0x73, 0x02},
{0x74, 0xd2},
{0x75, 0x20},
{0x76, 0x81},
{0x77, 0x8c},
{0x78, 0x81},
{0xf4, 0x01},
{0xf5, 0x00},
{0xf6, 0x00},
{0xf0, 0x36},
{0x40, 0x03},
{0x41, 0x01},
{0xf0, 0x39},
{0x02, 0x70},
{0xf0, 0x32},
{0x41, 0x00},
{0x43, 0x01},
{0x48, 0x02},
{0xf0, 0x45},
{0x09, 0x20},
{0xf0, 0x33},
{0x33, 0x10},
{0xf0, 0x30},
{0x38, 0x44},
{0xf0, 0x39},
{0x07, 0x00},
{0x08, 0x19},
{0x47, 0x00},
{0x48, 0x00},
{0xf0, 0x37},
{0x24, 0x31},
{0xf0, 0x34},
{0x9f, 0x02},
{0xa6, 0x51},
{0xa7, 0x57},
{0xe8, 0x5f},
{0xa8, 0x50},
{0xa9, 0x50},
{0xe9, 0x50},
{0xf0, 0x33},
{0xb3, 0x58},
{0xb2, 0x78},
{0xf0, 0x34},
{0x9f, 0x03},
{0xa6, 0x51},
{0xa7, 0x57},
{0xaa, 0x01},
{0xab, 0x28},
{0xac, 0x01},
{0xad, 0x38},
{0xf0, 0x33},
{0x0a, 0x01},
{0x0b, 0x28},
{0xf0, 0x33},
{0x64, 0x0f},
{0xec, 0x51},
{0xed, 0x57},
{0x06, 0x58},
{0xe9, 0x58},
{0xeb, 0x68},
{0xf0, 0x33},
{0x64, 0x0f},
{0xf0, 0x36},
{0x70, 0xdf},
{0xb6, 0x40},
{0xb7, 0x51},
{0xb8, 0x53},
{0xb9, 0x57},
{0xba, 0x5f},
{0xb0, 0x84},
{0xb1, 0x82},
{0xb2, 0x84},
{0xb3, 0x88},
{0xb4, 0x90},
{0xb5, 0x90},
{0xf0, 0x36},
{0x7e, 0x50},
{0x7f, 0x51},
{0x77, 0x81},
{0x78, 0x86},
{0x79, 0x89},
{0xf0, 0x36},
{0x70, 0xdf},
{0x9c, 0x51},
{0x9d, 0x57},
{0x90, 0x54},
{0x91, 0x54},
{0x92, 0x56},
{0xf0, 0x36},
{0xa0, 0x51},
{0xa1, 0x57},
{0x96, 0x33},
{0x97, 0x43},
{0x98, 0x43},
{0xf0, 0x36},
{0x70, 0xdf},
{0x7c, 0x40},
{0x7d, 0x53},
{0x74, 0xd0},
{0x75, 0xf0},
{0x76, 0xf0},
{0xf0, 0x37},
{0x0f, 0xd5},
{0x7a, 0x40},
{0x7b, 0x57},
{0x71, 0x09},
{0x72, 0x09},
{0x73, 0x05},
{0xf0, 0x33},
{0x01, 0x44},
{0xf0, 0x36},
{0x37, 0xfb},
{0xf0, 0x36},
{0x3c, 0x0d},
{0xf0, 0x33},
{0x14, 0x95},
{0xf0, 0x33},
{0x8f, 0x80},
{0xf0, 0x37},
{0x27, 0x14},
{0x28, 0x03},
{0xf0, 0x36},
{0x37, 0xf4},
{0xf0, 0x33},
{0x01, 0x44},
{0xf0, 0x36},
{0x79, 0x89},
{0xf0, 0x34},
{0xac, 0x01},
{0xad, 0x40},
{0xf0, 0x33},
{0xeb, 0x70},
{0xf0, 0x34},
{0xa8, 0x50},
{0xa9, 0x50},
{0xf0, 0x33},
{0xb3, 0x58},
{0xf0, 0x36},
{0x11, 0x80},
{0xf0, 0x36},
{0x41, 0x51},
{0xf0, 0x3f},
{0x03, 0x09},
{0xf0, 0x32},
{0x0c, 0x06},
{0x0d, 0x82},
{0x0e, 0x02},
{0x0f, 0xee},
{0xf0, 0x36},
{0xea, 0x09},
{0xeb, 0xf5},
{0xec, 0x11},
{0xed, 0x27},
{0xe9, 0x20},
#endif
};

4
sensors/sc030iot.c

@ -42,7 +42,7 @@ static const char* TAG = "sc030";
// sc030 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg. // sc030 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg.
// For more information please refer to the Technical Reference Manual. // For more information please refer to the Technical Reference Manual.
int get_reg(sensor_t *sensor, int reg, int reg_value_mask) static int get_reg(sensor_t *sensor, int reg, int reg_value_mask)
{ {
int ret = 0; int ret = 0;
uint8_t reg_high = (reg>>8) & 0xFF; uint8_t reg_high = (reg>>8) & 0xFF;
@ -61,7 +61,7 @@ int get_reg(sensor_t *sensor, int reg, int reg_value_mask)
// sc030 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg. // sc030 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg.
// For more information please refer to the Technical Reference Manual. // For more information please refer to the Technical Reference Manual.
int set_reg(sensor_t *sensor, int reg, int mask, int value) static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{ {
int ret = 0; int ret = 0;
uint8_t reg_high = (reg>>8) & 0xFF; uint8_t reg_high = (reg>>8) & 0xFF;

342
sensors/sc101iot.c

@ -0,0 +1,342 @@
/*
* SC101IOT driver.
*
* Copyright 2020-2022 Espressif Systems (Shanghai) PTE LTD
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sccb.h"
#include "xclk.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "sc101iot.h"
#include "sc101iot_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 = "sc101";
#endif
#define SC101_SENSOR_ID_HIGH_REG 0XF7
#define SC101_SENSOR_ID_LOW_REG 0XF8
#define SC101_MAX_FRAME_WIDTH (1280)
#define SC101_MAX_FRAME_HIGH (720)
// sc101 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg.
// For more information please refer to the Technical Reference Manual.
static int get_reg(sensor_t *sensor, int reg, int mask)
{
int ret = 0;
uint8_t reg_high = (reg>>8) & 0xFF;
uint8_t reg_low = reg & 0xFF;
if(SCCB_Write(sensor->slv_addr, 0xf0, reg_high)) {
return -1;
}
ret = SCCB_Read(sensor->slv_addr, reg_low);
if(ret > 0){
ret &= mask;
}
return ret;
}
// sc101 use "i2c paging mode", so the high byte of the register needs to be written to the 0xf0 reg.
// For more information please refer to the Technical Reference Manual.
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
{
int ret = 0;
uint8_t reg_high = (reg>>8) & 0xFF;
uint8_t reg_low = reg & 0xFF;
if(SCCB_Write(sensor->slv_addr, 0xf0, reg_high)) {
return -1;
}
ret = SCCB_Write(sensor->slv_addr, reg_low, value & 0xFF);
return ret;
}
static int set_regs(sensor_t *sensor, const uint8_t (*regs)[2], uint32_t regs_entry_len)
{
int i=0, res = 0;
while (i<regs_entry_len) {
res = SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]);
if (res) {
return res;
}
i++;
}
return res;
}
static int set_reg_bits(sensor_t *sensor, int reg, uint8_t offset, uint8_t length, uint8_t value)
{
int ret = 0;
ret = get_reg(sensor, reg, 0xff);
if(ret < 0){
return ret;
}
uint8_t mask = ((1 << length) - 1) << offset;
value = (ret & ~mask) | ((value << offset) & mask);
ret = set_reg(sensor, reg & 0xFFFF, 0xFFFF, value);
return ret;
}
#define WRITE_REGS_OR_RETURN(regs, regs_entry_len) ret = set_regs(sensor, regs, regs_entry_len); if(ret){return ret;}
#define WRITE_REG_OR_RETURN(reg, val) ret = set_reg(sensor, reg, 0xFF, val); if(ret){return ret;}
#define SET_REG_BITS_OR_RETURN(reg, offset, length, val) ret = set_reg_bits(sensor, reg, offset, length, val); if(ret){return ret;}
static int set_hmirror(sensor_t *sensor, int enable)
{
int ret = 0;
if(enable) {
SET_REG_BITS_OR_RETURN(0x3221, 1, 2, 0x3); // enable mirror
} else {
SET_REG_BITS_OR_RETURN(0x3221, 1, 2, 0x0); // disable mirror
}
return ret;
}
static int set_vflip(sensor_t *sensor, int enable)
{
int ret = 0;
if(enable) {
SET_REG_BITS_OR_RETURN(0x3221, 5, 2, 0x3); // flip on
} else {
SET_REG_BITS_OR_RETURN(0x3221, 5, 2, 0x0); // flip off
}
return ret;
}
static int set_colorbar(sensor_t *sensor, int enable)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x0100, 7, 1, enable & 0xff); // enable colorbar mode
return ret;
}
static int set_raw_gma(sensor_t *sensor, int enable)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x00f5, 1, 1, enable & 0xff); // enable gamma compensation
return ret;
}
static int set_sharpness(sensor_t *sensor, int level)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x00e0, 1, 1, 1); // enable edge enhancement
WRITE_REG_OR_RETURN(0x00d0, level & 0xFF); // base value
WRITE_REG_OR_RETURN(0x00d2, (level >> 8) & 0xFF); // limit
return ret;
}
static int set_agc_gain(sensor_t *sensor, int gain)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x0070, 1, 1, 1); // enable auto agc control
WRITE_REG_OR_RETURN(0x0068, gain & 0xFF); // Window weight setting1
WRITE_REG_OR_RETURN(0x0069, (gain >> 8) & 0xFF); // Window weight setting2
WRITE_REG_OR_RETURN(0x006a, (gain >> 16) & 0xFF); // Window weight setting3
WRITE_REG_OR_RETURN(0x006b, (gain >> 24) & 0xFF); // Window weight setting4
return ret;
}
static int set_aec_value(sensor_t *sensor, int value)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x0070, 0, 1, 1); // enable auto aec control
WRITE_REG_OR_RETURN(0x0072, value & 0xFF); // AE target
return ret;
}
static int set_awb_gain(sensor_t *sensor, int value)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x00b0, 0, 1, 1); // enable awb control
WRITE_REG_OR_RETURN(0x00c8, value & 0xFF); // blue gain
WRITE_REG_OR_RETURN(0x00c9, (value>>8) & 0XFF); // red gain
return ret;
}
static int set_saturation(sensor_t *sensor, int level)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x00f5, 5, 1, 0); // enable saturation control
WRITE_REG_OR_RETURN(0x0149, level & 0xFF); // blue saturation gain (/128)
WRITE_REG_OR_RETURN(0x014a, (level>>8) & 0XFF); // red saturation gain (/128)
return ret;
}
static int set_contrast(sensor_t *sensor, int level)
{
int ret = 0;
SET_REG_BITS_OR_RETURN(0x00f5, 6, 1, 0); // enable contrast control
WRITE_REG_OR_RETURN(0x014b, level); // contrast coefficient(/64)
return ret;
}
static int reset(sensor_t *sensor)
{
int ret = set_regs(sensor, sc101iot_default_init_regs, sizeof(sc101iot_default_init_regs)/(sizeof(uint8_t) * 2));
// Delay
vTaskDelay(50 / portTICK_PERIOD_MS);
// ESP_LOGI(TAG, "set_reg=%0x", set_reg(sensor, 0x0100, 0xffff, 0x00)); // write 0x80 to enter test mode if you want to test the sensor
// ESP_LOGI(TAG, "0x0100=%0x", get_reg(sensor, 0x0100, 0xffff));
if (ret) {
ESP_LOGE(TAG, "reset fail");
}
return ret;
}
static int set_window(sensor_t *sensor, int offset_x, int offset_y, int w, int h)
{
int ret = 0;
//sc:H_start={0x0172[3:0],0x0170},H_end={0x0172[7:4],0x0171},
WRITE_REG_OR_RETURN(0x0170, offset_x & 0xff);
WRITE_REG_OR_RETURN(0x0171, (offset_x+w) & 0xff);
WRITE_REG_OR_RETURN(0x0172, ((offset_x>>8) & 0x0f) | (((offset_x+w)>>4)&0xf0));
//sc:V_start={0x0175[3:0],0x0173},H_end={0x0175[7:4],0x0174},
WRITE_REG_OR_RETURN(0x0173, offset_y & 0xff);
WRITE_REG_OR_RETURN(0x0174, (offset_y+h) & 0xff);
WRITE_REG_OR_RETURN(0x0175, ((offset_y>>8) & 0x0f) | (((offset_y+h)>>4)&0xf0));
vTaskDelay(10 / portTICK_PERIOD_MS);
return ret;
}
static int set_framesize(sensor_t *sensor, framesize_t framesize)
{
uint16_t w = resolution[framesize].width;
uint16_t h = resolution[framesize].height;
if(w>SC101_MAX_FRAME_WIDTH || h > SC101_MAX_FRAME_HIGH) {
goto err;
}
uint16_t offset_x = (SC101_MAX_FRAME_WIDTH-w) /2;
uint16_t offset_y = (SC101_MAX_FRAME_HIGH-h) /2;
if(set_window(sensor, offset_x, offset_y, w, h)) {
goto err;
}
sensor->status.framesize = framesize;
return 0;
err:
ESP_LOGE(TAG, "frame size err");
return -1;
}
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
{
int ret=0;
sensor->pixformat = pixformat;
switch (pixformat) {
case PIXFORMAT_RGB565:
case PIXFORMAT_RAW:
case PIXFORMAT_GRAYSCALE:
ESP_LOGE(TAG, "Not support");
break;
case PIXFORMAT_YUV422: // For now, sc101 sensor only support YUV422.
break;
default:
ret = -1;
}
return ret;
}
static int init_status(sensor_t *sensor)
{
return 0;
}
static int set_dummy(sensor_t *sensor, int val){ return -1; }
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;
}
int sc101iot_detect(int slv_addr, sensor_id_t *id)
{
if (SC101IOT_SCCB_ADDR == slv_addr) {
uint8_t MIDL = SCCB_Read(slv_addr, SC101_SENSOR_ID_LOW_REG);
uint8_t MIDH = SCCB_Read(slv_addr, SC101_SENSOR_ID_HIGH_REG);
uint16_t PID = MIDH << 8 | MIDL;
if (SC101IOT_PID == PID) {
id->PID = PID;
return PID;
} else {
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
}
}
return 0;
}
int sc101iot_init(sensor_t *sensor)
{
// Set function pointers
sensor->reset = reset;
sensor->init_status = init_status;
sensor->set_pixformat = set_pixformat;
sensor->set_framesize = set_framesize;
sensor->set_hmirror = set_hmirror;
sensor->set_vflip = set_vflip;
sensor->set_colorbar = set_colorbar;
sensor->set_raw_gma = set_raw_gma;
sensor->set_sharpness = set_sharpness;
sensor->set_agc_gain = set_agc_gain;
sensor->set_aec_value = set_aec_value;
sensor->set_awb_gain = set_awb_gain;
sensor->set_saturation= set_saturation;
sensor->set_contrast = set_contrast;
sensor->set_denoise = set_dummy;
sensor->set_quality = set_dummy;
sensor->set_special_effect = set_dummy;
sensor->set_wb_mode = set_dummy;
sensor->set_ae_level = set_dummy;
sensor->get_reg = get_reg;
sensor->set_reg = set_reg;
sensor->set_xclk = set_xclk;
ESP_LOGD(TAG, "sc101iot Attached");
return 0;
}
Loading…
Cancel
Save