mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-08 20:46:52 +03:00
Rolling 20220924
This commit is contained in:
@@ -8,26 +8,56 @@ on:
|
||||
jobs:
|
||||
build-master:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
idf_target: ["esp32", "esp32s2", "esp32s3"]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@latest
|
||||
uses: espressif/esp-idf-ci-action@main
|
||||
with:
|
||||
target: ${{ matrix.idf_target }}
|
||||
path: 'examples'
|
||||
|
||||
build-release-v4_0:
|
||||
build-release-v5_0:
|
||||
name: Build for ${{ matrix.idf_target }} on ${{ matrix.idf_ver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["release-v5.0"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32s3"]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@release-v4.0
|
||||
uses: espressif/esp-idf-ci-action@main
|
||||
with:
|
||||
esp_idf_version: ${{ matrix.idf_ver }}
|
||||
target: ${{ matrix.idf_target }}
|
||||
path: 'examples'
|
||||
|
||||
build-release-v4_4:
|
||||
name: Build for ${{ matrix.idf_target }} on ${{ matrix.idf_ver }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
idf_ver: ["v4.4"]
|
||||
idf_target: ["esp32", "esp32s2", "esp32s3"]
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@main
|
||||
with:
|
||||
esp_idf_version: ${{ matrix.idf_ver }}
|
||||
target: ${{ matrix.idf_target }}
|
||||
path: 'examples'
|
||||
|
||||
build-release-v4_1:
|
||||
@@ -65,15 +95,3 @@ jobs:
|
||||
uses: espressif/esp-idf-ci-action@release-v4.3
|
||||
with:
|
||||
path: 'examples'
|
||||
|
||||
build-release-v3_3:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repo
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
submodules: 'recursive'
|
||||
- name: esp-idf build
|
||||
uses: espressif/esp-idf-ci-action@release-v3.3
|
||||
with:
|
||||
path: 'examples'
|
||||
|
||||
@@ -10,12 +10,10 @@ jobs:
|
||||
- uses: actions/checkout@master
|
||||
with:
|
||||
submodules: "recursive"
|
||||
|
||||
- name: Upload component to the component registry
|
||||
uses: espressif/github-actions/upload_components@master
|
||||
with:
|
||||
name: "esp32-camera"
|
||||
version: "git"
|
||||
namespace: "espressif"
|
||||
service_url: ${{ secrets.IDF_COMPONENT_API_URL }}
|
||||
version: ${{ github.ref_name }}
|
||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
||||
|
||||
@@ -1,5 +1,29 @@
|
||||
# get IDF version for comparison
|
||||
set(idf_version "${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}")
|
||||
|
||||
# set conversion sources
|
||||
set(COMPONENT_SRCS
|
||||
conversions/yuv.c
|
||||
conversions/to_jpg.cpp
|
||||
conversions/to_bmp.c
|
||||
conversions/jpge.cpp
|
||||
conversions/esp_jpg_decode.c
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS
|
||||
conversions/private_include
|
||||
)
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
driver/include
|
||||
conversions/include
|
||||
)
|
||||
|
||||
set(COMPONENT_REQUIRES driver)
|
||||
|
||||
# set driver sources only for supported platforms
|
||||
if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET STREQUAL "esp32s3")
|
||||
set(COMPONENT_SRCS
|
||||
list(APPEND COMPONENT_SRCS
|
||||
driver/esp_camera.c
|
||||
driver/cam_hal.c
|
||||
driver/sccb.c
|
||||
@@ -14,22 +38,14 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
|
||||
sensors/gc2145.c
|
||||
sensors/gc032a.c
|
||||
sensors/bf3005.c
|
||||
conversions/yuv.c
|
||||
conversions/to_jpg.cpp
|
||||
conversions/to_bmp.c
|
||||
conversions/jpge.cpp
|
||||
conversions/esp_jpg_decode.c
|
||||
sensors/bf20a6.c
|
||||
sensors/sc101iot.c
|
||||
sensors/sc030iot.c
|
||||
)
|
||||
|
||||
set(COMPONENT_ADD_INCLUDEDIRS
|
||||
driver/include
|
||||
conversions/include
|
||||
)
|
||||
|
||||
set(COMPONENT_PRIV_INCLUDEDIRS
|
||||
list(APPEND COMPONENT_PRIV_INCLUDEDIRS
|
||||
driver/private_include
|
||||
sensors/private_include
|
||||
conversions/private_include
|
||||
target/private_include
|
||||
)
|
||||
|
||||
@@ -58,8 +74,13 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
|
||||
)
|
||||
endif()
|
||||
|
||||
set(COMPONENT_REQUIRES driver)
|
||||
set(COMPONENT_PRIV_REQUIRES freertos nvs_flash)
|
||||
|
||||
register_component()
|
||||
set(min_version_for_esp_timer "4.2")
|
||||
if (idf_version VERSION_GREATER_EQUAL min_version_for_esp_timer)
|
||||
list(APPEND COMPONENT_PRIV_REQUIRES esp_timer)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
register_component()
|
||||
|
||||
@@ -69,6 +69,45 @@ menu "Camera configuration"
|
||||
help
|
||||
Enable this option if you want to use the BF3005.
|
||||
Disable this option to save memory.
|
||||
|
||||
config BF20A6_SUPPORT
|
||||
bool "Support BF20A6(BYD20A6) VGA"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the BF20A6.
|
||||
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
|
||||
bool "Support SC030IOT VGA"
|
||||
default y
|
||||
help
|
||||
Enable this option if you want to use the SC030IOT.
|
||||
Disable this option to save memory.
|
||||
|
||||
choice SCCB_HARDWARE_I2C_PORT
|
||||
bool "I2C peripheral to use for SCCB"
|
||||
@@ -103,6 +142,12 @@ menu "Camera configuration"
|
||||
bool "Subsample Mode"
|
||||
endchoice
|
||||
|
||||
config CAMERA_TASK_STACK_SIZE
|
||||
int "CAM task stack size"
|
||||
default 2048
|
||||
help
|
||||
Camera task stack size
|
||||
|
||||
choice CAMERA_TASK_PINNED_TO_CORE
|
||||
bool "Camera task pinned to core"
|
||||
default CAMERA_CORE0
|
||||
@@ -124,6 +169,37 @@ menu "Camera configuration"
|
||||
default 32768
|
||||
help
|
||||
Maximum value of DMA buffer
|
||||
Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent
|
||||
Larger values may fail to allocate due to insufficient contiguous memory blocks, and smaller value may cause DMA interrupt to be too frequent.
|
||||
|
||||
config CAMERA_CONVERTER_ENABLED
|
||||
bool "Enable camera RGB/YUV converter"
|
||||
depends on IDF_TARGET_ESP32S3
|
||||
default n
|
||||
help
|
||||
Enable this option if you want to use RGB565/YUV422/YUV420/YUV411 format conversion.
|
||||
|
||||
choice CAMERA_CONV_PROTOCOL
|
||||
bool "Camera converter protocol"
|
||||
depends on CAMERA_CONVERTER_ENABLED
|
||||
default LCD_CAM_CONV_BT601_ENABLED
|
||||
help
|
||||
Supports format conversion under both BT601 and BT709 standards.
|
||||
|
||||
config LCD_CAM_CONV_BT601_ENABLED
|
||||
bool "BT601"
|
||||
config LCD_CAM_CONV_BT709_ENABLED
|
||||
bool "BT709"
|
||||
endchoice
|
||||
|
||||
config LCD_CAM_CONV_FULL_RANGE_ENABLED
|
||||
bool "Camera converter full range mode"
|
||||
depends on CAMERA_CONVERTER_ENABLED
|
||||
default y
|
||||
help
|
||||
Supports format conversion under both full color range mode and limited color range mode.
|
||||
If full color range mode is selected, the color range of RGB or YUV is 0~255.
|
||||
If limited color range mode is selected, the color range of RGB is 16~240, and the color range of YUV is Y[16~240], UV[16~235].
|
||||
Full color range mode has a wider color range, so details in the image show more clearly.
|
||||
Please confirm the color range mode of the current camera sensor, incorrect color range mode may cause color difference in the final converted image.
|
||||
Full range mode is used by default. If this option is not selected, the format conversion function will be done using the limited range mode.
|
||||
endmenu
|
||||
|
||||
@@ -25,6 +25,9 @@ This repository hosts ESP32 series Soc compatible driver for image sensors. Addi
|
||||
| GC0308 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/6.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" |
|
||||
| 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" |
|
||||
|
||||
## Important to Remember
|
||||
|
||||
@@ -128,8 +131,8 @@ static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
.pin_reset = CAM_PIN_RESET,
|
||||
.pin_xclk = CAM_PIN_XCLK,
|
||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
||||
.pin_sccb_sda = CAM_PIN_SIOD,
|
||||
.pin_sccb_scl = CAM_PIN_SIOC,
|
||||
|
||||
.pin_d7 = CAM_PIN_D7,
|
||||
.pin_d6 = CAM_PIN_D6,
|
||||
|
||||
@@ -21,6 +21,10 @@
|
||||
#include "tjpgd.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/tjpgd.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32C3
|
||||
#include "esp32c3/rom/tjpgd.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
#include "esp32h2/rom/tjpgd.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
@@ -57,7 +61,7 @@ static const char * jd_errors[] = {
|
||||
"Not supported JPEG standard"
|
||||
};
|
||||
|
||||
static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
static unsigned int _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
{
|
||||
uint16_t x = rect->left;
|
||||
uint16_t y = rect->top;
|
||||
@@ -73,7 +77,7 @@ static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static uint32_t _jpg_read(JDEC *decoder, uint8_t *buf, uint32_t len)
|
||||
static unsigned int _jpg_read(JDEC *decoder, uint8_t *buf, unsigned int len)
|
||||
{
|
||||
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||
if (jpeg->len && len > (jpeg->len - jpeg->index)) {
|
||||
|
||||
@@ -29,7 +29,12 @@ namespace jpge {
|
||||
if(b){
|
||||
return b;
|
||||
}
|
||||
// check if SPIRAM is enabled and allocate on SPIRAM if allocatable
|
||||
#if (CONFIG_SPIRAM_SUPPORT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC))
|
||||
return heap_caps_malloc(nSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
static inline void jpge_free(void *p) { free(p); }
|
||||
|
||||
|
||||
@@ -21,19 +21,6 @@
|
||||
#include "esp_jpg_decode.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/spiram.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
@@ -72,7 +59,12 @@ typedef struct {
|
||||
|
||||
static void *_malloc(size_t size)
|
||||
{
|
||||
// check if SPIRAM is enabled and allocate on SPIRAM if allocatable
|
||||
#if (CONFIG_SPIRAM_SUPPORT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC))
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
#endif
|
||||
// try allocating in internal memory
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
//output buffer and image width
|
||||
@@ -168,7 +160,7 @@ static bool _rgb565_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16
|
||||
}
|
||||
|
||||
//input buffer
|
||||
static uint32_t _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
|
||||
static unsigned int _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
|
||||
{
|
||||
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||
if(buf) {
|
||||
@@ -310,7 +302,13 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
|
||||
*out_len = 0;
|
||||
|
||||
int pix_count = width*height;
|
||||
size_t out_size = (pix_count * 3) + BMP_HEADER_LEN;
|
||||
|
||||
// With BMP, 8-bit greyscale requires a palette.
|
||||
// For a 640x480 image though, that's a savings
|
||||
// over going RGB-24.
|
||||
int bpp = (format == PIXFORMAT_GRAYSCALE) ? 1 : 3;
|
||||
int palette_size = (format == PIXFORMAT_GRAYSCALE) ? 4 * 256 : 0;
|
||||
size_t out_size = (pix_count * bpp) + BMP_HEADER_LEN + palette_size;
|
||||
uint8_t * out_buf = (uint8_t *)_malloc(out_size);
|
||||
if(!out_buf) {
|
||||
ESP_LOGE(TAG, "_malloc failed! %u", out_size);
|
||||
@@ -322,45 +320,51 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
|
||||
bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
|
||||
bitmap->reserved = 0;
|
||||
bitmap->filesize = out_size;
|
||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN + palette_size;
|
||||
bitmap->dibheadersize = 40;
|
||||
bitmap->width = width;
|
||||
bitmap->height = -height;//set negative for top to bottom
|
||||
bitmap->planes = 1;
|
||||
bitmap->bitsperpixel = 24;
|
||||
bitmap->bitsperpixel = bpp * 8;
|
||||
bitmap->compression = 0;
|
||||
bitmap->imagesize = pix_count * 3;
|
||||
bitmap->imagesize = pix_count * bpp;
|
||||
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||
bitmap->numcolorspallette = 0;
|
||||
bitmap->mostimpcolor = 0;
|
||||
|
||||
uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN;
|
||||
uint8_t * palette_buf = out_buf + BMP_HEADER_LEN;
|
||||
uint8_t * pix_buf = palette_buf + palette_size;
|
||||
uint8_t * src_buf = src;
|
||||
|
||||
if (palette_size > 0) {
|
||||
// Grayscale palette
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
for (int j = 0; j < 3; ++j) {
|
||||
*palette_buf = i;
|
||||
palette_buf++;
|
||||
}
|
||||
// Reserved / alpha channel.
|
||||
*palette_buf = 0;
|
||||
palette_buf++;
|
||||
}
|
||||
}
|
||||
|
||||
//convert data to RGB888
|
||||
if(format == PIXFORMAT_RGB888) {
|
||||
memcpy(rgb_buf, src_buf, pix_count*3);
|
||||
memcpy(pix_buf, src_buf, pix_count*3);
|
||||
} else if(format == PIXFORMAT_RGB565) {
|
||||
int i;
|
||||
uint8_t hb, lb;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
hb = *src_buf++;
|
||||
lb = *src_buf++;
|
||||
*rgb_buf++ = (lb & 0x1F) << 3;
|
||||
*rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||
*rgb_buf++ = hb & 0xF8;
|
||||
*pix_buf++ = (lb & 0x1F) << 3;
|
||||
*pix_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||
*pix_buf++ = hb & 0xF8;
|
||||
}
|
||||
} else if(format == PIXFORMAT_GRAYSCALE) {
|
||||
int i;
|
||||
uint8_t b;
|
||||
for(i=0; i<pix_count; i++) {
|
||||
b = *src_buf++;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = b;
|
||||
}
|
||||
memcpy(pix_buf, src_buf, pix_count);
|
||||
} else if(format == PIXFORMAT_YUV422) {
|
||||
int i, maxi = pix_count / 2;
|
||||
uint8_t y0, y1, u, v;
|
||||
@@ -372,14 +376,14 @@ bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixf
|
||||
v = *src_buf++;
|
||||
|
||||
yuv2rgb(y0, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
*pix_buf++ = b;
|
||||
*pix_buf++ = g;
|
||||
*pix_buf++ = r;
|
||||
|
||||
yuv2rgb(y1, u, v, &r, &g, &b);
|
||||
*rgb_buf++ = b;
|
||||
*rgb_buf++ = g;
|
||||
*rgb_buf++ = r;
|
||||
*pix_buf++ = b;
|
||||
*pix_buf++ = g;
|
||||
*pix_buf++ = r;
|
||||
}
|
||||
}
|
||||
*out = out_buf;
|
||||
|
||||
@@ -21,21 +21,6 @@
|
||||
#include "jpge.h"
|
||||
#include "yuv.h"
|
||||
|
||||
#include "esp_system.h"
|
||||
#if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
|
||||
#if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
|
||||
#include "esp32/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/spiram.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/spiram.h"
|
||||
#else
|
||||
#error Target CONFIG_IDF_TARGET is not supported
|
||||
#endif
|
||||
#else // ESP32 Before IDF 4.0
|
||||
#include "esp_spiram.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
#define TAG ""
|
||||
@@ -50,7 +35,12 @@ static void *_malloc(size_t size)
|
||||
if(res) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// check if SPIRAM is enabled and is allocatable
|
||||
#if (CONFIG_SPIRAM_SUPPORT && (CONFIG_SPIRAM_USE_CAPS_ALLOC || CONFIG_SPIRAM_USE_MALLOC))
|
||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static IRAM_ATTR void convert_line_format(uint8_t * src, pixformat_t format, uint8_t * dst, size_t width, size_t in_channels, size_t line)
|
||||
|
||||
@@ -18,8 +18,27 @@
|
||||
#include "ll_cam.h"
|
||||
#include "cam_hal.h"
|
||||
|
||||
static const char *TAG = "cam_hal";
|
||||
#if (ESP_IDF_VERSION_MAJOR == 3) && (ESP_IDF_VERSION_MINOR == 3)
|
||||
#include "rom/ets_sys.h"
|
||||
#else
|
||||
#include "esp_timer.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/ets_sys.h"
|
||||
#endif
|
||||
#endif // ESP_IDF_VERSION_MAJOR
|
||||
#define ESP_CAMERA_ETS_PRINTF ets_printf
|
||||
|
||||
#if CONFIG_CAM_TASK_STACK_SIZE
|
||||
#define CAM_TASK_STACK CONFIG_CAM_TASK_STACK_SIZE
|
||||
#else
|
||||
#define CAM_TASK_STACK (2*1024)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "cam_hal";
|
||||
static cam_obj_t *cam_obj = NULL;
|
||||
|
||||
static const uint32_t JPEG_SOI_MARKER = 0xFFD8FF; // written in little-endian for esp32
|
||||
@@ -32,7 +51,7 @@ static int cam_verify_jpeg_soi(const uint8_t *inbuf, uint32_t length)
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF;
|
||||
if (sig == JPEG_SOI_MARKER) {
|
||||
ESP_LOGW(TAG, "SOI: %d", i);
|
||||
ESP_LOGW(TAG, "SOI: %d", (int) i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +112,7 @@ void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType
|
||||
if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) {
|
||||
ll_cam_stop(cam);
|
||||
cam->state = CAM_STATE_IDLE;
|
||||
ESP_EARLY_LOGE(TAG, "EV-%s-OVF", cam_event==CAM_IN_SUC_EOF_EVENT ? "EOF" : "VSYNC");
|
||||
ESP_CAMERA_ETS_PRINTF(DRAM_STR("cam_hal: EV-%s-OVF\r\n"), cam_event==CAM_IN_SUC_EOF_EVENT ? DRAM_STR("EOF") : DRAM_STR("VSYNC"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +123,7 @@ static void cam_task(void *arg)
|
||||
int frame_pos = 0;
|
||||
cam_obj->state = CAM_STATE_IDLE;
|
||||
cam_event_t cam_event = 0;
|
||||
|
||||
|
||||
xQueueReset(cam_obj->event_queue);
|
||||
|
||||
while (1) {
|
||||
@@ -127,7 +146,7 @@ static void cam_task(void *arg)
|
||||
case CAM_STATE_READ_BUF: {
|
||||
camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb;
|
||||
size_t pixels_per_dma = (cam_obj->dma_half_buffer_size * cam_obj->fb_bytes_per_pixel) / (cam_obj->dma_bytes_per_item * cam_obj->in_bytes_per_pixel);
|
||||
|
||||
|
||||
if (cam_event == CAM_IN_SUC_EOF_EVENT) {
|
||||
if(!cam_obj->psram_mode){
|
||||
if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
|
||||
@@ -137,8 +156,8 @@ static void cam_task(void *arg)
|
||||
continue;
|
||||
}
|
||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
cam_obj->dma_half_buffer_size);
|
||||
}
|
||||
//Check for JPEG SOI in the first buffer. stop if not found
|
||||
@@ -160,8 +179,8 @@ static void cam_task(void *arg)
|
||||
cnt--;
|
||||
} else {
|
||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
cam_obj->dma_half_buffer_size);
|
||||
}
|
||||
}
|
||||
@@ -179,7 +198,7 @@ static void cam_task(void *arg)
|
||||
} else if (!cam_obj->jpeg_mode) {
|
||||
if (frame_buffer_event->len != cam_obj->fb_size) {
|
||||
cam_obj->frames[frame_pos].en = 1;
|
||||
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, cam_obj->fb_size);
|
||||
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, (unsigned) cam_obj->fb_size);
|
||||
}
|
||||
}
|
||||
//send frame
|
||||
@@ -245,8 +264,9 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
cam_obj->dma_node_cnt = (cam_obj->dma_buffer_size) / cam_obj->dma_node_buffer_size; // Number of DMA nodes
|
||||
cam_obj->frame_copy_cnt = cam_obj->recv_size / cam_obj->dma_half_buffer_size; // Number of interrupted copies, ping-pong copy
|
||||
|
||||
ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
|
||||
cam_obj->dma_buffer_size, cam_obj->dma_half_buffer_size, cam_obj->dma_node_buffer_size, cam_obj->dma_node_cnt, cam_obj->frame_copy_cnt);
|
||||
ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
|
||||
(int) cam_obj->dma_buffer_size, (int) cam_obj->dma_half_buffer_size, (int) cam_obj->dma_node_buffer_size,
|
||||
(int) cam_obj->dma_node_cnt, (int) cam_obj->frame_copy_cnt);
|
||||
|
||||
cam_obj->dma_buffer = NULL;
|
||||
cam_obj->dma = NULL;
|
||||
@@ -276,13 +296,19 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
cam_obj->frames[x].fb_offset = 0;
|
||||
cam_obj->frames[x].en = 0;
|
||||
ESP_LOGI(TAG, "Allocating %d Byte frame buffer in %s", alloc_size, _caps & MALLOC_CAP_SPIRAM ? "PSRAM" : "OnBoard RAM");
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
|
||||
// In IDF v4.2 and earlier, memory returned by heap_caps_aligned_alloc must be freed using heap_caps_aligned_free.
|
||||
// And heap_caps_aligned_free is deprecated on v4.3.
|
||||
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_aligned_alloc(16, alloc_size, _caps);
|
||||
#else
|
||||
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(alloc_size, _caps);
|
||||
#endif
|
||||
CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
|
||||
if (cam_obj->psram_mode) {
|
||||
//align PSRAM buffer. TODO: save the offset so proper address can be freed later
|
||||
cam_obj->frames[x].fb_offset = dma_align - ((uint32_t)cam_obj->frames[x].fb.buf & (dma_align - 1));
|
||||
cam_obj->frames[x].fb.buf += cam_obj->frames[x].fb_offset;
|
||||
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (uint32_t)cam_obj->frames[x].fb.buf);
|
||||
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (unsigned) cam_obj->frames[x].fb.buf);
|
||||
cam_obj->frames[x].dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->frames[x].fb.buf);
|
||||
CAM_CHECK(cam_obj->frames[x].dma != NULL, "frame dma malloc failed", ESP_FAIL);
|
||||
}
|
||||
@@ -292,8 +318,8 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
if (!cam_obj->psram_mode) {
|
||||
cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
|
||||
if(NULL == cam_obj->dma_buffer) {
|
||||
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
|
||||
cam_obj->dma_buffer_size, heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
|
||||
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
|
||||
(int) cam_obj->dma_buffer_size, (int) heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -359,7 +385,7 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
|
||||
cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel;
|
||||
cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
|
||||
}
|
||||
|
||||
|
||||
ret = cam_dma_config(config);
|
||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);
|
||||
|
||||
@@ -376,13 +402,13 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
|
||||
ret = ll_cam_init_isr(cam_obj);
|
||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);
|
||||
|
||||
|
||||
|
||||
#if CONFIG_CAMERA_CORE0
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
|
||||
#elif CONFIG_CAMERA_CORE1
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
|
||||
#else
|
||||
xTaskCreate(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
|
||||
xTaskCreate(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "cam config ok");
|
||||
|
||||
@@ -57,6 +57,15 @@
|
||||
#if CONFIG_BF3005_SUPPORT
|
||||
#include "bf3005.h"
|
||||
#endif
|
||||
#if CONFIG_BF20A6_SUPPORT
|
||||
#include "bf20a6.h"
|
||||
#endif
|
||||
#if CONFIG_SC101IOT_SUPPORT
|
||||
#include "sc101iot.h"
|
||||
#endif
|
||||
#if CONFIG_SC030IOT_SUPPORT
|
||||
#include "sc030iot.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
@@ -119,10 +128,20 @@ static const sensor_func_t g_sensors[] = {
|
||||
#if CONFIG_BF3005_SUPPORT
|
||||
{bf3005_detect, bf3005_init},
|
||||
#endif
|
||||
#if CONFIG_BF20A6_SUPPORT
|
||||
{bf20a6_detect, bf20a6_init},
|
||||
#endif
|
||||
#if CONFIG_SC101IOT_SUPPORT
|
||||
{sc101iot_detect, sc101iot_init},
|
||||
#endif
|
||||
#if CONFIG_SC030IOT_SUPPORT
|
||||
{sc030iot_detect, sc030iot_init},
|
||||
#endif
|
||||
};
|
||||
|
||||
static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out_camera_model)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
*out_camera_model = CAMERA_NONE;
|
||||
if (s_state != NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
@@ -138,9 +157,17 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
CAMERA_ENABLE_OUT_CLOCK(config);
|
||||
}
|
||||
|
||||
if (config->pin_sscb_sda != -1) {
|
||||
ESP_LOGD(TAG, "Initializing SSCB");
|
||||
SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl);
|
||||
if (config->pin_sccb_sda != -1) {
|
||||
ESP_LOGD(TAG, "Initializing SCCB");
|
||||
ret = SCCB_Init(config->pin_sccb_sda, config->pin_sccb_scl);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Using existing I2C port");
|
||||
ret = SCCB_Use_Port(config->sccb_i2c_port);
|
||||
}
|
||||
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "sccb init err");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (config->pin_pwdn >= 0) {
|
||||
@@ -170,15 +197,14 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGD(TAG, "Searching for camera address");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
uint8_t slv_addr = SCCB_Probe();
|
||||
|
||||
if (slv_addr == 0) {
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Detected camera at address=0x%02x", slv_addr);
|
||||
@@ -203,9 +229,9 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
}
|
||||
|
||||
if (CAMERA_NONE == *out_camera_model) { //If no supported sensors are detected
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
ESP_LOGE(TAG, "Detected camera not supported.");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
ret = ESP_ERR_NOT_SUPPORTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
|
||||
@@ -213,11 +239,30 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
|
||||
ESP_LOGD(TAG, "Doing SW reset of sensor");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
s_state->sensor.reset(&s_state->sensor);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
return s_state->sensor.reset(&s_state->sensor);
|
||||
err :
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
static pixformat_t get_output_data_format(camera_conv_mode_t conv_mode)
|
||||
{
|
||||
pixformat_t format = PIXFORMAT_RGB565;
|
||||
switch (conv_mode) {
|
||||
case YUV422_TO_YUV420:
|
||||
format = PIXFORMAT_YUV420;
|
||||
break;
|
||||
case YUV422_TO_RGB565: // default format is RGB565
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "Convert to %d format enabled", format);
|
||||
return format;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
{
|
||||
esp_err_t err;
|
||||
@@ -256,6 +301,7 @@ esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
|
||||
s_state->sensor.status.framesize = frame_size;
|
||||
s_state->sensor.pixformat = pix_format;
|
||||
|
||||
ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height);
|
||||
if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
|
||||
ESP_LOGE(TAG, "Failed to set frame size");
|
||||
@@ -263,6 +309,11 @@ esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
goto fail;
|
||||
}
|
||||
s_state->sensor.set_pixformat(&s_state->sensor, pix_format);
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
if(config->conv_mode) {
|
||||
s_state->sensor.pixformat = get_output_data_format(config->conv_mode); // If conversion enabled, change the out data format by conversion mode
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_state->sensor.id.PID == OV2640_PID) {
|
||||
s_state->sensor.set_gainceiling(&s_state->sensor, GAINCEILING_2X);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
.pin_pwdn = PIN_PWDN,
|
||||
.pin_reset = PIN_RESET,
|
||||
.pin_xclk = PIN_XCLK,
|
||||
.pin_sscb_sda = PIN_SIOD,
|
||||
.pin_sscb_scl = PIN_SIOC,
|
||||
.pin_sccb_sda = PIN_SIOD,
|
||||
.pin_sccb_scl = PIN_SIOC,
|
||||
.pin_d7 = PIN_D7,
|
||||
.pin_d6 = PIN_D6,
|
||||
.pin_d5 = PIN_D5,
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "driver/ledc.h"
|
||||
#include "sensor.h"
|
||||
#include "sys/time.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -91,6 +92,19 @@ typedef enum {
|
||||
CAMERA_FB_IN_DRAM /*!< Frame buffer is placed in internal DRAM */
|
||||
} camera_fb_location_t;
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
/**
|
||||
* @brief Camera RGB\YUV conversion mode
|
||||
*/
|
||||
typedef enum {
|
||||
CONV_DISABLE,
|
||||
RGB565_TO_YUV422,
|
||||
|
||||
YUV422_TO_RGB565,
|
||||
YUV422_TO_YUV420
|
||||
} camera_conv_mode_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for camera initialization
|
||||
*/
|
||||
@@ -98,8 +112,14 @@ typedef struct {
|
||||
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
||||
int pin_reset; /*!< GPIO pin for camera reset line */
|
||||
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
||||
int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
|
||||
union {
|
||||
int pin_sccb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_sda __attribute__((deprecated("please use pin_sccb_sda instead"))); /*!< GPIO pin for camera SDA line (legacy name) */
|
||||
};
|
||||
union {
|
||||
int pin_sccb_scl; /*!< GPIO pin for camera SCL line */
|
||||
int pin_sscb_scl __attribute__((deprecated("please use pin_sccb_scl instead"))); /*!< GPIO pin for camera SCL line (legacy name) */
|
||||
};
|
||||
int pin_d7; /*!< GPIO pin for camera D7 line */
|
||||
int pin_d6; /*!< GPIO pin for camera D6 line */
|
||||
int pin_d5; /*!< GPIO pin for camera D5 line */
|
||||
@@ -124,6 +144,11 @@ typedef struct {
|
||||
size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
|
||||
camera_fb_location_t fb_location; /*!< The location where the frame buffer will be allocated */
|
||||
camera_grab_mode_t grab_mode; /*!< When buffers should be filled */
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
camera_conv_mode_t conv_mode; /*!< RGB<->YUV Conversion mode */
|
||||
#endif
|
||||
|
||||
int sccb_i2c_port; /*!< If pin_sccb_sda is -1, use the already configured I2C bus by number */
|
||||
} camera_config_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,9 @@ typedef enum {
|
||||
GC032A_PID = 0x232a,
|
||||
GC0308_PID = 0x9b,
|
||||
BF3005_PID = 0x30,
|
||||
BF20A6_PID = 0x20a6,
|
||||
SC101IOT_PID = 0xda4a,
|
||||
SC030IOT_PID = 0x9a46,
|
||||
} camera_pid_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -40,6 +43,9 @@ typedef enum {
|
||||
CAMERA_GC032A,
|
||||
CAMERA_GC0308,
|
||||
CAMERA_BF3005,
|
||||
CAMERA_BF20A6,
|
||||
CAMERA_SC101IOT,
|
||||
CAMERA_SC030IOT,
|
||||
CAMERA_MODEL_MAX,
|
||||
CAMERA_NONE,
|
||||
} camera_model_t;
|
||||
@@ -55,11 +61,15 @@ typedef enum {
|
||||
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
BF3005_SCCB_ADDR = 0x6E,
|
||||
BF20A6_SCCB_ADDR = 0x6E,
|
||||
SC101IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||
SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||
} camera_sccb_addr_t;
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
PIXFORMAT_YUV422, // 2BPP/YUV422
|
||||
PIXFORMAT_YUV420, // 1.5BPP/YUV420
|
||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||
@@ -199,7 +209,7 @@ typedef struct _sensor {
|
||||
|
||||
// Sensor function pointers
|
||||
int (*init_status) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor); // Reset the configuration of the sensor, and return ESP_OK if reset is successful
|
||||
int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
|
||||
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
||||
int (*set_contrast) (sensor_t *sensor, int level);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define __SCCB_H__
|
||||
#include <stdint.h>
|
||||
int SCCB_Init(int pin_sda, int pin_scl);
|
||||
int SCCB_Use_Port(int sccb_i2c_port);
|
||||
int SCCB_Deinit(void);
|
||||
uint8_t SCCB_Probe();
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||
|
||||
@@ -25,6 +25,11 @@ static const char* TAG = "sccb";
|
||||
|
||||
#include "driver/i2c.h"
|
||||
|
||||
// support IDF 5.x
|
||||
#ifndef portTICK_RATE_MS
|
||||
#define portTICK_RATE_MS portTICK_PERIOD_MS
|
||||
#endif
|
||||
|
||||
#define SCCB_FREQ CONFIG_SCCB_CLK_FREQ /*!< I2C master frequency*/
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
@@ -33,16 +38,26 @@ static const char* TAG = "sccb";
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
||||
const int SCCB_I2C_PORT = 1;
|
||||
const int SCCB_I2C_PORT_DEFAULT = 1;
|
||||
#else
|
||||
const int SCCB_I2C_PORT = 0;
|
||||
const int SCCB_I2C_PORT_DEFAULT = 0;
|
||||
#endif
|
||||
|
||||
static int sccb_i2c_port;
|
||||
static bool sccb_owns_i2c_port;
|
||||
|
||||
int SCCB_Init(int pin_sda, int pin_scl)
|
||||
{
|
||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d", pin_sda, pin_scl);
|
||||
i2c_config_t conf;
|
||||
esp_err_t ret;
|
||||
|
||||
memset(&conf, 0, sizeof(i2c_config_t));
|
||||
|
||||
sccb_i2c_port = SCCB_I2C_PORT_DEFAULT;
|
||||
sccb_owns_i2c_port = true;
|
||||
ESP_LOGI(TAG, "sccb_i2c_port=%d\n", sccb_i2c_port);
|
||||
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = pin_sda;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
@@ -50,30 +65,37 @@ int SCCB_Init(int pin_sda, int pin_scl)
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = SCCB_FREQ;
|
||||
|
||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
||||
return 0;
|
||||
if ((ret = i2c_param_config(sccb_i2c_port, &conf)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_driver_install(sccb_i2c_port, conf.mode, 0, 0, 0);
|
||||
}
|
||||
|
||||
int SCCB_Use_Port(int i2c_num) { // sccb use an already initialized I2C port
|
||||
if (sccb_owns_i2c_port) {
|
||||
SCCB_Deinit();
|
||||
}
|
||||
if (i2c_num < 0 || i2c_num > I2C_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
sccb_i2c_port = i2c_num;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int SCCB_Deinit(void)
|
||||
{
|
||||
return i2c_driver_delete(SCCB_I2C_PORT);
|
||||
if (!sccb_owns_i2c_port) {
|
||||
return ESP_OK;
|
||||
}
|
||||
sccb_owns_i2c_port = false;
|
||||
return i2c_driver_delete(sccb_i2c_port);
|
||||
}
|
||||
|
||||
uint8_t SCCB_Probe(void)
|
||||
{
|
||||
uint8_t slave_addr = 0x0;
|
||||
// for (size_t i = 1; i < 0x80; i++) {
|
||||
// i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
// i2c_master_start(cmd);
|
||||
// i2c_master_write_byte(cmd, ( i << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
// i2c_master_stop(cmd);
|
||||
// esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
// i2c_cmd_link_delete(cmd);
|
||||
// if( ret == ESP_OK) {
|
||||
// ESP_LOGW(TAG, "Found I2C Device at 0x%02X", i);
|
||||
// }
|
||||
// }
|
||||
|
||||
for (size_t i = 0; i < CAMERA_MODEL_MAX; i++) {
|
||||
if (slave_addr == camera_sensor[i].sccb_addr) {
|
||||
continue;
|
||||
@@ -83,7 +105,7 @@ uint8_t SCCB_Probe(void)
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
esp_err_t ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if( ret == ESP_OK) {
|
||||
return slave_addr;
|
||||
@@ -101,7 +123,7 @@ uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
@@ -109,7 +131,7 @@ uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
@@ -126,7 +148,7 @@ uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
@@ -146,7 +168,7 @@ uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
@@ -154,7 +176,7 @@ uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
||||
@@ -175,7 +197,7 @@ uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
|
||||
@@ -13,6 +13,9 @@ const camera_sensor_info_t camera_sensor[CAMERA_MODEL_MAX] = {
|
||||
{CAMERA_GC032A, "GC032A", GC032A_SCCB_ADDR, GC032A_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_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},
|
||||
};
|
||||
|
||||
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||
|
||||
@@ -38,6 +38,11 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
|
||||
// support IDF 5.x
|
||||
#ifndef portTICK_RATE_MS
|
||||
#define portTICK_RATE_MS portTICK_PERIOD_MS
|
||||
#endif
|
||||
|
||||
#include "esp_camera.h"
|
||||
|
||||
#define BOARD_WROVER_KIT 1
|
||||
@@ -94,8 +99,8 @@ static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
.pin_reset = CAM_PIN_RESET,
|
||||
.pin_xclk = CAM_PIN_XCLK,
|
||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
||||
.pin_sccb_sda = CAM_PIN_SIOD,
|
||||
.pin_sccb_scl = CAM_PIN_SIOC,
|
||||
|
||||
.pin_d7 = CAM_PIN_D7,
|
||||
.pin_d6 = CAM_PIN_D6,
|
||||
|
||||
@@ -1,5 +1,2 @@
|
||||
description: ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors.
|
||||
targets:
|
||||
- esp32
|
||||
- esp32s2
|
||||
- esp32s3
|
||||
url: https://github.com/espressif/esp32-camera
|
||||
|
||||
404
code/components/esp32-camera-master/sensors/bf20a6.c
Normal file
404
code/components/esp32-camera-master/sensors/bf20a6.c
Normal file
@@ -0,0 +1,404 @@
|
||||
// Copyright 2015-2021 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "sccb.h"
|
||||
#include "bf20a6.h"
|
||||
#include "bf20a6_regs.h"
|
||||
#include "bf20a6_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 = "bf20a6";
|
||||
#endif
|
||||
|
||||
#define H8(v) ((v)>>8)
|
||||
#define L8(v) ((v)&0xff)
|
||||
|
||||
//#define REG_DEBUG_ON
|
||||
|
||||
static int read_reg(uint8_t slv_addr, const uint16_t reg)
|
||||
{
|
||||
int ret = SCCB_Read(slv_addr, reg);
|
||||
// ESP_LOGI(TAG, "READ Register 0x%02x VALUE: 0x%02x", reg, ret);
|
||||
#ifdef REG_DEBUG_ON
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "READ REG 0x%04x FAILED: %d", reg, ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_reg(uint8_t slv_addr, const uint16_t reg, uint8_t value)
|
||||
{
|
||||
int ret = SCCB_Write(slv_addr, reg, value);
|
||||
#ifdef REG_DEBUG_ON
|
||||
if (ret < 0) {
|
||||
ESP_LOGE(TAG, "WRITE REG 0x%04x FAILED: %d", reg, ret);
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_PRINT_REG
|
||||
static int check_reg_mask(uint8_t slv_addr, uint16_t reg, uint8_t mask)
|
||||
{
|
||||
return (read_reg(slv_addr, reg) & mask) == mask;
|
||||
}
|
||||
|
||||
static void print_regs(uint8_t slv_addr)
|
||||
{
|
||||
vTaskDelay(pdMS_TO_TICKS(100));
|
||||
ESP_LOGI(TAG, "REG list look ======================");
|
||||
for (size_t i = 0xf0; i <= 0xfe; i++) {
|
||||
ESP_LOGI(TAG, "reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
|
||||
}
|
||||
ESP_LOGI(TAG, "\npage 0 ===");
|
||||
write_reg(slv_addr, 0xfe, 0x00); // page 0
|
||||
for (size_t i = 0x03; i <= 0x24; i++) {
|
||||
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
|
||||
}
|
||||
for (size_t i = 0x40; i <= 0x95; i++) {
|
||||
ESP_LOGI(TAG, "p0 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
|
||||
}
|
||||
ESP_LOGI(TAG, "\npage 3 ===");
|
||||
write_reg(slv_addr, 0xfe, 0x03); // page 3
|
||||
for (size_t i = 0x01; i <= 0x43; i++) {
|
||||
ESP_LOGI(TAG, "p3 reg[0x%02x] = 0x%02x", i, read_reg(slv_addr, i));
|
||||
}
|
||||
}
|
||||
|
||||
static int read_regs(uint8_t slv_addr, const uint16_t(*regs)[2])
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
while (regs[i][0] != REGLIST_TAIL) {
|
||||
if (regs[i][0] == REG_DLY) {
|
||||
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
ret = read_reg(slv_addr, regs[i][0]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
static int set_reg_bits(sensor_t *sensor, uint8_t reg, uint8_t offset, uint8_t length, uint8_t value)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
ret = SCCB_Read(sensor->slv_addr, reg);
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
uint8_t mask = ((1 << length) - 1) << offset;
|
||||
value = (ret & ~mask) | ((value << offset) & mask);
|
||||
ret = SCCB_Write(sensor->slv_addr, reg & 0xFF, value);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_regs(uint8_t slv_addr, const uint16_t(*regs)[2])
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
while (!ret && regs[i][0] != REGLIST_TAIL) {
|
||||
if (regs[i][0] == REG_DLY) {
|
||||
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
ret = write_reg(slv_addr, regs[i][0], regs[i][1]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int reset(sensor_t *sensor)
|
||||
{
|
||||
int ret;
|
||||
// Software Reset: clear all registers and reset them to their default values
|
||||
ret = write_reg(sensor->slv_addr, RESET_RELATED, 0x01);
|
||||
if (ret) {
|
||||
ESP_LOGE(TAG, "Software Reset FAILED!");
|
||||
return ret;
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
|
||||
ret = write_regs(sensor->slv_addr, bf20a6_default_init_regs);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Camera defaults loaded");
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
// int test_value = read_regs(sensor->slv_addr, bf20a6_default_init_regs);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_pixformat(sensor_t *sensor, pixformat_t pixformat)
|
||||
{
|
||||
int ret = 0;
|
||||
switch (pixformat) {
|
||||
case PIXFORMAT_YUV422:
|
||||
set_reg_bits(sensor, 0x12, 0, 1, 0);
|
||||
break;
|
||||
case PIXFORMAT_RAW:
|
||||
set_reg_bits(sensor, 0x12, 0, 1, 0x1);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGW(TAG, "set_pix unsupport format");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
if (ret == 0) {
|
||||
sensor->pixformat = pixformat;
|
||||
ESP_LOGD(TAG, "Set pixformat to: %u", pixformat);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_framesize(sensor_t *sensor, framesize_t framesize)
|
||||
{
|
||||
int ret = 0;
|
||||
if (framesize > FRAMESIZE_VGA) {
|
||||
return -1;
|
||||
}
|
||||
uint16_t w = resolution[framesize].width;
|
||||
uint16_t h = resolution[framesize].height;
|
||||
|
||||
sensor->status.framesize = framesize;
|
||||
|
||||
// Write MSBs
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x17, 0);
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x18, w >> 2);
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x19, 0);
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x1a, h >> 2);
|
||||
|
||||
// Write LSBs
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x1b, 0);
|
||||
|
||||
if ((w <= 320) && (h <= 240)) {
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x17, (80 - w / 4));
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x18, (80 + w / 4));
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x19, (60 - h / 4));
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x1a, (60 + h / 4));
|
||||
|
||||
} else if ((w <= 640) && (h <= 480)) {
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x17, (80 - w / 8));
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x18, (80 + w / 8));
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x19, (60 - h / 8));
|
||||
|
||||
ret |= SCCB_Write(sensor->slv_addr, 0x1a, (60 + h / 8));
|
||||
}
|
||||
|
||||
// Delay
|
||||
vTaskDelay(30 / portTICK_PERIOD_MS);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_hmirror(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->status.hmirror = enable;
|
||||
//ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
|
||||
ret |= set_reg_bits(sensor, 0x4a, 3, 0x01, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set h-mirror to: %d", enable);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_vflip(sensor_t *sensor, int enable)
|
||||
{
|
||||
int ret = 0;
|
||||
sensor->status.vflip = enable;
|
||||
//ret = write_reg(sensor->slv_addr, 0xfe, 0x00);
|
||||
ret |= set_reg_bits(sensor, 0x4a, 2, 0x01, enable);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set v-flip to: %d", enable);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_colorbar(sensor_t *sensor, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = write_reg(sensor->slv_addr, 0xb6, value);
|
||||
if (ret == 0) {
|
||||
sensor->status.colorbar = value;
|
||||
ESP_LOGD(TAG, "Set colorbar to: %d", value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_sharpness(sensor_t *sensor, int level)
|
||||
{
|
||||
int ret = 0;
|
||||
ret = SCCB_Write(sensor->slv_addr, 0x70, level);
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Set sharpness to: %d", level);
|
||||
sensor->status.sharpness = level;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int get_reg(sensor_t *sensor, int reg, int mask)
|
||||
{
|
||||
int ret = 0;
|
||||
if (mask > 0xFF) {
|
||||
ESP_LOGE(TAG, "mask should not more than 0xff");
|
||||
} else {
|
||||
ret = read_reg(sensor->slv_addr, reg);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret &= mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_reg(sensor_t *sensor, int reg, int mask, int value)
|
||||
{
|
||||
int ret = 0;
|
||||
if (mask > 0xFF) {
|
||||
ESP_LOGE(TAG, "mask should not more than 0xff");
|
||||
} else {
|
||||
ret = read_reg(sensor->slv_addr, reg);
|
||||
}
|
||||
if (ret < 0) {
|
||||
return ret;
|
||||
}
|
||||
value = (ret & ~mask) | (value & mask);
|
||||
|
||||
if (mask > 0xFF) {
|
||||
|
||||
} else {
|
||||
ret = write_reg(sensor->slv_addr, reg, value);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int init_status(sensor_t *sensor)
|
||||
{
|
||||
// write_reg(sensor->slv_addr, 0xfe, 0x00);
|
||||
sensor->status.brightness = SCCB_Read(sensor->slv_addr, 0x6f);
|
||||
sensor->status.contrast = SCCB_Read(sensor->slv_addr, 0xd6);
|
||||
sensor->status.saturation = 0;
|
||||
sensor->status.sharpness = SCCB_Read(sensor->slv_addr, 0x70);
|
||||
sensor->status.denoise = 0;
|
||||
sensor->status.ae_level = 0;
|
||||
sensor->status.gainceiling = SCCB_Read(sensor->slv_addr, 0x13);
|
||||
sensor->status.awb = 0;
|
||||
sensor->status.dcw = 0;
|
||||
sensor->status.agc = 0;
|
||||
sensor->status.aec = 0;
|
||||
sensor->status.hmirror = 0;// check_reg_mask(sensor->slv_addr, P0_CISCTL_MODE1, 0x01);
|
||||
sensor->status.vflip = 0;// check_reg_mask(sensor->slv_addr, P0_CISCTL_MODE1, 0x02);
|
||||
sensor->status.colorbar = 0;
|
||||
sensor->status.bpc = 0;
|
||||
sensor->status.wpc = 0;
|
||||
sensor->status.raw_gma = 0;
|
||||
sensor->status.lenc = 0;
|
||||
sensor->status.quality = 0;
|
||||
sensor->status.special_effect = 0;
|
||||
sensor->status.wb_mode = 0;
|
||||
sensor->status.awb_gain = 0;
|
||||
sensor->status.agc_gain = 0;
|
||||
sensor->status.aec_value = 0;
|
||||
sensor->status.aec2 = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int set_dummy(sensor_t *sensor, int val)
|
||||
{
|
||||
ESP_LOGW(TAG, "dummy Unsupported");
|
||||
return -1;
|
||||
}
|
||||
static int set_gainceiling_dummy(sensor_t *sensor, gainceiling_t val)
|
||||
{
|
||||
ESP_LOGW(TAG, "gainceiling Unsupported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
int bf20a6_detect(int slv_addr, sensor_id_t *id)
|
||||
{
|
||||
if (BF20A6_SCCB_ADDR == slv_addr) {
|
||||
uint8_t MIDL = SCCB_Read(slv_addr, SENSOR_ID_LOW);
|
||||
uint8_t MIDH = SCCB_Read(slv_addr, SENSOR_ID_HIGH);
|
||||
uint16_t PID = MIDH << 8 | MIDL;
|
||||
if (BF20A6_PID == PID) {
|
||||
id->PID = PID;
|
||||
return PID;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bf20a6_init(sensor_t *sensor)
|
||||
{
|
||||
sensor->init_status = init_status;
|
||||
sensor->reset = reset;
|
||||
sensor->set_pixformat = set_pixformat;
|
||||
sensor->set_framesize = set_framesize;
|
||||
sensor->set_contrast = set_dummy;
|
||||
sensor->set_brightness = set_dummy;
|
||||
sensor->set_saturation = set_dummy;
|
||||
sensor->set_sharpness = set_sharpness;
|
||||
sensor->set_denoise = set_dummy;
|
||||
sensor->set_gainceiling = set_gainceiling_dummy;
|
||||
sensor->set_quality = set_dummy;
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_whitebal = set_dummy;
|
||||
sensor->set_gain_ctrl = set_dummy;
|
||||
sensor->set_exposure_ctrl = set_dummy;
|
||||
sensor->set_hmirror = set_hmirror; // set_hmirror;
|
||||
sensor->set_vflip = set_vflip; // set_vflip;
|
||||
|
||||
sensor->set_aec2 = set_dummy;
|
||||
sensor->set_awb_gain = set_dummy;
|
||||
sensor->set_agc_gain = set_dummy;
|
||||
sensor->set_aec_value = set_dummy;
|
||||
|
||||
sensor->set_special_effect = set_dummy;
|
||||
sensor->set_wb_mode = set_dummy;
|
||||
sensor->set_ae_level = set_dummy;
|
||||
|
||||
sensor->set_dcw = set_dummy;
|
||||
sensor->set_bpc = set_dummy;
|
||||
sensor->set_wpc = set_dummy;
|
||||
|
||||
sensor->set_raw_gma = set_dummy;
|
||||
sensor->set_lenc = set_dummy;
|
||||
|
||||
sensor->get_reg = get_reg;
|
||||
sensor->set_reg = set_reg;
|
||||
sensor->set_res_raw = NULL;
|
||||
sensor->set_pll = NULL;
|
||||
sensor->set_xclk = NULL;
|
||||
|
||||
ESP_LOGD(TAG, "BF20A6 Attached");
|
||||
return 0;
|
||||
}
|
||||
@@ -88,10 +88,10 @@ static int set_reg_bits(uint8_t slv_addr, uint16_t reg, uint8_t offset, uint8_t
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int write_regs(uint8_t slv_addr, const uint16_t (*regs)[2])
|
||||
static int write_regs(uint8_t slv_addr, const uint8_t (*regs)[2], size_t regs_size)
|
||||
{
|
||||
int i = 0, ret = 0;
|
||||
while (!ret && regs[i][0] != REGLIST_TAIL) {
|
||||
while (!ret && (i < regs_size)) {
|
||||
if (regs[i][0] == REG_DLY) {
|
||||
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
|
||||
} else {
|
||||
@@ -132,11 +132,12 @@ static int reset(sensor_t *sensor)
|
||||
ESP_LOGE(TAG, "Software Reset FAILED!");
|
||||
return ret;
|
||||
}
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
ret = write_regs(sensor->slv_addr, gc0308_sensor_default_regs);
|
||||
|
||||
vTaskDelay(80 / portTICK_PERIOD_MS);
|
||||
ret = write_regs(sensor->slv_addr, gc0308_sensor_default_regs, sizeof(gc0308_sensor_default_regs)/(sizeof(uint8_t) * 2));
|
||||
if (ret == 0) {
|
||||
ESP_LOGD(TAG, "Camera defaults loaded");
|
||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
||||
vTaskDelay(80 / portTICK_PERIOD_MS);
|
||||
write_reg(sensor->slv_addr, 0xfe, 0x00);
|
||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||
set_reg_bits(sensor->slv_addr, 0x28, 4, 0x07, 1); //frequency division for esp32, ensure pclk <= 15MHz
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
|
||||
#ifndef __BF20A6_H__
|
||||
#define __BF20A6_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 bf20a6_detect(int slv_addr, sensor_id_t *id);
|
||||
|
||||
/**
|
||||
* @brief initialize sensor function pointers
|
||||
*
|
||||
* @param sensor pointer of sensor
|
||||
* @return
|
||||
* Always 0
|
||||
*/
|
||||
int bf20a6_init(sensor_t *sensor);
|
||||
|
||||
#endif // __BF20A6_H__
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* BF20A6 register definitions.
|
||||
*/
|
||||
#ifndef __BF20A6_REG_REGS_H__
|
||||
#define __BF20A6_REG_REGS_H__
|
||||
|
||||
#define SENSOR_ID_HIGH 0XFC
|
||||
#define SENSOR_ID_LOW 0XFD
|
||||
#define RESET_RELATED 0XF2
|
||||
|
||||
|
||||
#endif //__BF20A6_REG_REGS_H__
|
||||
@@ -0,0 +1,158 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define REG_DLY 0xffff
|
||||
#define REGLIST_TAIL 0xffff /* Array end token */
|
||||
|
||||
static const uint16_t bf20a6_default_init_regs[][2] = {
|
||||
{0xf2,0x01},
|
||||
{0x12,0x20},
|
||||
{0x3a,0x00},
|
||||
{0xe1,0x92},
|
||||
{0xe3,0x12},// PLL Control, important for framerate(choice: 0x02\0x12\0x22\0x32\0x82)
|
||||
{0xe0,0x00},
|
||||
{0x2a,0x98},
|
||||
{0xcd,0x17},
|
||||
{0xc0,0x10},
|
||||
{0xc6,0x1d},
|
||||
{0x10,0x35},
|
||||
{0xe2,0x09},
|
||||
{0xe4,0x72},
|
||||
{0xe5,0x22},
|
||||
{0xe6,0x24},
|
||||
{0xe7,0x64},
|
||||
{0xe8,0xa2}, // DVP:a2}, SPI:f2 VDDIO=1.8V,E8[2]=1},VDDIO=2.8V,E8[2]=0},
|
||||
{0x4a,0x00},
|
||||
{0x00,0x03},
|
||||
{0x1f,0x02},
|
||||
{0x22,0x02},
|
||||
{0x0c,0x31},
|
||||
|
||||
{0x00,0x00},
|
||||
{0x60,0x81},
|
||||
{0x61,0x81},
|
||||
|
||||
{0xa0,0x08},
|
||||
{0x01,0x1a},
|
||||
// {0x01,0x1a},
|
||||
// {0x01,0x1a},
|
||||
// {0x02,0x15},
|
||||
// {0x02,0x15},
|
||||
{0x02,0x15},
|
||||
{0x13,0x08},
|
||||
{0x8a,0x96},
|
||||
{0x8b,0x06},
|
||||
{0x87,0x18},
|
||||
|
||||
|
||||
{0x34,0x48}, // lens
|
||||
{0x35,0x40},
|
||||
{0x36,0x40},
|
||||
|
||||
{0x71,0x44},
|
||||
{0x72,0x48},
|
||||
{0x74,0xa2},
|
||||
{0x75,0xa9},
|
||||
{0x78,0x12},
|
||||
{0x79,0xa0},
|
||||
{0x7a,0x94},
|
||||
{0x7c,0x97},
|
||||
{0x40,0x30},
|
||||
{0x41,0x30},
|
||||
{0x42,0x28},
|
||||
{0x43,0x1f},
|
||||
{0x44,0x1c},
|
||||
{0x45,0x16},
|
||||
{0x46,0x13},
|
||||
{0x47,0x10},
|
||||
{0x48,0x0D},
|
||||
{0x49,0x0C},
|
||||
{0x4B,0x0A},
|
||||
{0x4C,0x0B},
|
||||
{0x4E,0x09},
|
||||
{0x4F,0x08},
|
||||
{0x50,0x08},
|
||||
|
||||
|
||||
{0x5f,0x29},
|
||||
{0x23,0x33},
|
||||
{0xa1,0x10}, // AWB
|
||||
{0xa2,0x0d},
|
||||
{0xa3,0x30},
|
||||
{0xa4,0x06},
|
||||
{0xa5,0x22},
|
||||
{0xa6,0x56},
|
||||
{0xa7,0x18},
|
||||
{0xa8,0x1a},
|
||||
{0xa9,0x12},
|
||||
{0xaa,0x12},
|
||||
{0xab,0x16},
|
||||
{0xac,0xb1},
|
||||
{0xba,0x12},
|
||||
{0xbb,0x12},
|
||||
{0xad,0x12},
|
||||
{0xae,0x56},
|
||||
{0xaf,0x0a},
|
||||
{0x3b,0x30},
|
||||
{0x3c,0x12},
|
||||
{0x3d,0x22},
|
||||
{0x3e,0x3f},
|
||||
{0x3f,0x28},
|
||||
{0xb8,0xc3},
|
||||
{0xb9,0xa3},
|
||||
{0x39,0x47}, // pure color threshold
|
||||
{0x26,0x13},
|
||||
{0x27,0x16},
|
||||
{0x28,0x14},
|
||||
{0x29,0x18},
|
||||
{0xee,0x0d},
|
||||
|
||||
|
||||
{0x13,0x05},
|
||||
{0x24,0x3C},
|
||||
{0x81,0x20},
|
||||
{0x82,0x40},
|
||||
{0x83,0x30},
|
||||
{0x84,0x58},
|
||||
{0x85,0x30},
|
||||
{0x92,0x08},
|
||||
{0x86,0x80},
|
||||
{0x8a,0x96},
|
||||
{0x91,0xff},
|
||||
{0x94,0x62},
|
||||
{0x9a,0x18}, // outdoor threshold
|
||||
{0xf0,0x45}, // integral time control, important for framerate(choice: 0x46\0x45\0x44..)
|
||||
{0x51,0x17}, // color normal
|
||||
{0x52,0x03},
|
||||
{0x53,0x5F},
|
||||
{0x54,0x47},
|
||||
{0x55,0x66},
|
||||
{0x56,0x0F},
|
||||
{0x7e,0x14},
|
||||
{0x57,0x36}, // color
|
||||
{0x58,0x2A},
|
||||
{0x59,0xAA},
|
||||
{0x5a,0xA8},
|
||||
{0x5b,0x43},
|
||||
{0x5c,0x10},
|
||||
{0x5d,0x00},
|
||||
{0x7d,0x36},
|
||||
{0x5e,0x10},
|
||||
|
||||
{0xd6,0x88}, // contrast
|
||||
{0xd5,0x20}, // bright
|
||||
{0xb0,0x84}, // low light ctrl in gray section
|
||||
{0xb5,0x08}, // the threshold of GLB_GAIN
|
||||
{0xb1,0xc8}, // saturation
|
||||
{0xb2,0xc0},
|
||||
{0xb3,0xd0},
|
||||
{0xb4,0xB0},
|
||||
|
||||
{0x32,0x10},
|
||||
// {0x8a,0x00},
|
||||
// {0x8b,0x10},
|
||||
{0xa0,0x09},
|
||||
{0x00,0x03},
|
||||
{0x0b,0x02},
|
||||
{REGLIST_TAIL, 0x00},
|
||||
};
|
||||
@@ -3,10 +3,9 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define REG_DLY 0xffff
|
||||
#define REGLIST_TAIL 0x0000 /* Array end token */
|
||||
#define REG_DLY 0xff
|
||||
|
||||
static const uint16_t gc0308_sensor_default_regs[][2] = {
|
||||
static const uint8_t gc0308_sensor_default_regs[][2] = {
|
||||
{0xfe, 0x00},
|
||||
{0xec, 0x20},
|
||||
{0x05, 0x00},
|
||||
@@ -239,7 +238,21 @@ static const uint16_t gc0308_sensor_default_regs[][2] = {
|
||||
{0x65, 0xd3},
|
||||
{0x66, 0x60},
|
||||
{0xfe, 0x00},
|
||||
{REGLIST_TAIL, 0x00},
|
||||
|
||||
{0x01, 0x32}, //frame setting
|
||||
{0x02, 0x0c},
|
||||
{0x0f, 0x01},
|
||||
{0xe2, 0x00},
|
||||
{0xe3, 0x78},
|
||||
{0xe4, 0x00},
|
||||
{0xe5, 0xfe},
|
||||
{0xe6, 0x01},
|
||||
{0xe7, 0xe0},
|
||||
{0xe8, 0x01},
|
||||
{0xe9, 0xe0},
|
||||
{0xea, 0x01},
|
||||
{0xeb, 0xe0},
|
||||
{0xfe, 0x00},
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -42,7 +42,8 @@ static const DRAM_ATTR uint16_t sensor_default_regs[][2] = {
|
||||
{ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
|
||||
|
||||
//sys reset
|
||||
{0x3000, 0x00},
|
||||
{0x3000, 0x20}, // reset MCU
|
||||
{REG_DLY, 10}, // delay 10ms
|
||||
{0x3002, 0x1c},
|
||||
|
||||
//clock enable
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
*
|
||||
* SC030IOT DVP driver.
|
||||
*
|
||||
*/
|
||||
#ifndef __SC030IOT_H__
|
||||
#define __SC030IOT_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 sc030iot_detect(int slv_addr, sensor_id_t *id);
|
||||
|
||||
/**
|
||||
* @brief initialize sensor function pointers
|
||||
*
|
||||
* @param sensor pointer of sensor
|
||||
* @return
|
||||
* Always 0
|
||||
*/
|
||||
int sc030iot_init(sensor_t *sensor);
|
||||
|
||||
#endif // __SC030IOT_H__
|
||||
@@ -0,0 +1,491 @@
|
||||
//version: V01P00_20220303
|
||||
//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:3.3V// 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=Dothinkey
|
||||
|
||||
[Vendor]
|
||||
VendorName=SmartSens
|
||||
|
||||
[Sensor]
|
||||
SensorName=SC031IOT
|
||||
width=640
|
||||
height=480
|
||||
port=1
|
||||
type=2
|
||||
pin=3
|
||||
SlaveID=0xd0
|
||||
mode=0
|
||||
FlagReg=0xf7
|
||||
FlagMask=0xff
|
||||
FlagData=0xfa
|
||||
FlagReg1=0xf8
|
||||
FlagMask1=0xff
|
||||
FlagData1=0x46
|
||||
outformat=0
|
||||
mclk=20
|
||||
avdd=2.80000
|
||||
dovdd=2.800000
|
||||
dvdd=1.5
|
||||
|
||||
Ext0=0
|
||||
Ext1=0
|
||||
Ext2=0
|
||||
AFVCC=0.0000
|
||||
VPP=0.000000
|
||||
*/
|
||||
#include <stdint.h>
|
||||
|
||||
static const uint8_t sc030iot_default_init_regs[][2] = {
|
||||
{0xf0, 0x30},
|
||||
{0x01, 0xff},
|
||||
{0x02, 0xff},
|
||||
{0x22, 0x07},
|
||||
{0x19, 0xff},
|
||||
{0x3f, 0x82},
|
||||
{0x30, 0x02},
|
||||
{0xf0, 0x01},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0x72, 0x20},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x75, 0x10},
|
||||
{0x76, 0x81},
|
||||
{0x77, 0x88},
|
||||
{0x78, 0xe1},
|
||||
{0x79, 0x01},
|
||||
{0xf5, 0x01},
|
||||
{0xf4, 0x0a},
|
||||
{0xf0, 0x36},
|
||||
{0x37, 0x79},
|
||||
{0x31, 0x82},
|
||||
{0x3e, 0x60},
|
||||
{0x30, 0xf0},
|
||||
{0x33, 0x33},
|
||||
{0xf0, 0x32},
|
||||
{0x48, 0x02},
|
||||
{0xf0, 0x33},
|
||||
{0x02, 0x12},
|
||||
{0x7c, 0x02},
|
||||
{0x7d, 0x0e},
|
||||
{0xa2, 0x04},
|
||||
{0x5e, 0x06},
|
||||
{0x5f, 0x0a},
|
||||
{0x0b, 0x58},
|
||||
{0x06, 0x38},
|
||||
{0xf0, 0x32},
|
||||
{0x48, 0x02},
|
||||
{0xf0, 0x39},
|
||||
{0x02, 0x70},
|
||||
{0xf0, 0x45},
|
||||
{0x09, 0x1c},
|
||||
{0xf0, 0x37},
|
||||
{0x22, 0x0d},
|
||||
{0xf0, 0x33},
|
||||
{0x33, 0x10},
|
||||
{0xb1, 0x80},
|
||||
{0x34, 0x40},
|
||||
{0x0b, 0x54},
|
||||
{0xb2, 0x78},
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x30},
|
||||
{0x38, 0x44},
|
||||
{0xf0, 0x33},
|
||||
{0xb3, 0x51},
|
||||
{0x01, 0x10},
|
||||
{0x0b, 0x6c},
|
||||
{0x06, 0x24},
|
||||
{0xf0, 0x36},
|
||||
{0x31, 0x82},
|
||||
{0x3e, 0x60},
|
||||
{0x30, 0xf0},
|
||||
{0x33, 0x33},
|
||||
{0xf0, 0x34},
|
||||
{0x9f, 0x02},
|
||||
{0xa6, 0x40},
|
||||
{0xa7, 0x47},
|
||||
{0xe8, 0x5f},
|
||||
{0xa8, 0x51},
|
||||
{0xa9, 0x44},
|
||||
{0xe9, 0x36},
|
||||
{0xf0, 0x33},
|
||||
{0xb3, 0x51},
|
||||
{0x64, 0x17},
|
||||
{0x90, 0x01},
|
||||
{0x91, 0x03},
|
||||
{0x92, 0x07},
|
||||
{0x01, 0x10},
|
||||
{0x93, 0x10},
|
||||
{0x94, 0x10},
|
||||
{0x95, 0x10},
|
||||
{0x96, 0x01},
|
||||
{0x97, 0x07},
|
||||
{0x98, 0x1f},
|
||||
{0x99, 0x10},
|
||||
{0x9a, 0x20},
|
||||
{0x9b, 0x28},
|
||||
{0x9c, 0x28},
|
||||
{0xf0, 0x36},
|
||||
{0x70, 0x54},
|
||||
{0xb6, 0x40},
|
||||
{0xb7, 0x41},
|
||||
{0xb8, 0x43},
|
||||
{0xb9, 0x47},
|
||||
{0xba, 0x4f},
|
||||
{0xb0, 0x8b},
|
||||
{0xb1, 0x8b},
|
||||
{0xb2, 0x8b},
|
||||
{0xb3, 0x9b},
|
||||
{0xb4, 0xb8},
|
||||
{0xb5, 0xf0},
|
||||
{0x7e, 0x41},
|
||||
{0x7f, 0x47},
|
||||
{0x77, 0x80},
|
||||
{0x78, 0x84},
|
||||
{0x79, 0x8a},
|
||||
{0xa0, 0x47},
|
||||
{0xa1, 0x5f},
|
||||
{0x96, 0x43},
|
||||
{0x97, 0x44},
|
||||
{0x98, 0x54},
|
||||
{0xf0, 0x00},
|
||||
{0xf0, 0x01},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0xf0, 0x36},
|
||||
{0x37, 0x74},
|
||||
{0xf0, 0x3f},
|
||||
{0x03, 0xa1},
|
||||
{0xf0, 0x36},//cvbs_off
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xc1},
|
||||
{0xf0, 0x37},
|
||||
{0x24, 0x21},
|
||||
{0xf0, 0x36},
|
||||
{0x41, 0x00},
|
||||
{0xea, 0x09},
|
||||
{0xeb, 0x03},
|
||||
{0xec, 0x19},
|
||||
{0xed, 0x38},
|
||||
{0xe9, 0x30},
|
||||
{0xf0, 0x33},
|
||||
{0x33, 0x00},
|
||||
{0x34, 0x00},
|
||||
{0xb1, 0x00},
|
||||
{0xf0, 0x00},
|
||||
{0xe0, 0x04},
|
||||
{0xf0, 0x01},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0xf0, 0x36},
|
||||
{0x32, 0x44},
|
||||
{0xf0, 0x36},
|
||||
{0x3e, 0xe0},
|
||||
{0x70, 0x56},
|
||||
{0x7c, 0x43},
|
||||
{0x7d, 0x47},
|
||||
{0x74, 0x00},
|
||||
{0x75, 0x00},
|
||||
{0x76, 0x00},
|
||||
{0xa0, 0x47},
|
||||
{0xa1, 0x5f},
|
||||
{0x96, 0x22},
|
||||
{0x97, 0x22},
|
||||
{0x98, 0x22},
|
||||
{0xf0, 0x00},
|
||||
{0x72, 0x38},
|
||||
{0x7a, 0x80},
|
||||
{0x85, 0x18},
|
||||
{0x9b, 0x35},
|
||||
{0x9e, 0x20},
|
||||
{0xd0, 0x66},
|
||||
{0xd1, 0x34},
|
||||
{0Xd3, 0x44},
|
||||
{0xd6, 0x44},
|
||||
{0xb0, 0x41},
|
||||
{0xb2, 0x48},
|
||||
{0xb3, 0xf4},
|
||||
{0xb4, 0x0b},
|
||||
{0xb5, 0x78},
|
||||
{0xba, 0xff},
|
||||
{0xbb, 0xc0},
|
||||
{0xbc, 0x90},
|
||||
{0xbd, 0x3a},
|
||||
{0xc1, 0x67},
|
||||
{0xf0, 0x01},
|
||||
{0x20, 0x11},
|
||||
{0x23, 0x90},
|
||||
{0x24, 0x15},
|
||||
{0x25, 0x87},
|
||||
{0xbc, 0x9f},
|
||||
{0xbd, 0x3a},
|
||||
{0x48, 0xe6},
|
||||
{0x49, 0xc0},
|
||||
{0x4a, 0xd0},
|
||||
{0x4b, 0x48},
|
||||
|
||||
// [cvbs_on]
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x00},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xf1},
|
||||
|
||||
// [cvbs_off]
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xc1},
|
||||
};
|
||||
|
||||
/*
|
||||
[Sensor]
|
||||
SensorName=SC031IOT
|
||||
width=640
|
||||
height=480
|
||||
port=1
|
||||
type=2
|
||||
pin=3
|
||||
SlaveID=0xd0
|
||||
mode=0
|
||||
FlagReg=0xf7
|
||||
FlagMask=0xff
|
||||
FlagData=0xfa
|
||||
FlagReg1=0xf8
|
||||
FlagMask1=0xff
|
||||
FlagData1=0x46
|
||||
outformat=0
|
||||
mclk=27
|
||||
avdd=2.80000
|
||||
dovdd=2.800000
|
||||
dvdd=1.5
|
||||
|
||||
Ext0=0
|
||||
Ext1=0
|
||||
Ext2=0
|
||||
AFVCC=0.0000
|
||||
VPP=0.000000
|
||||
*/
|
||||
/* 27M MCLK, 30fps
|
||||
static const uint8_t sc030iot_default_init_regs[][2] = {
|
||||
{0xf0, 0x30},
|
||||
{0x01, 0xff},
|
||||
{0x02, 0xff},
|
||||
{0x22, 0x07},
|
||||
{0x19, 0xff},
|
||||
{0x3f, 0x82},
|
||||
{0x30, 0x02},
|
||||
{0xf0, 0x01},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0x72, 0x20},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x75, 0x10},
|
||||
{0x76, 0x81},
|
||||
{0x77, 0x88},
|
||||
{0x78, 0xe1},
|
||||
{0x79, 0x01},
|
||||
{0xf5, 0x01},
|
||||
{0xf4, 0x0a},
|
||||
{0xf0, 0x36},
|
||||
{0x37, 0x79},
|
||||
{0x31, 0x82},
|
||||
{0x3e, 0x60},
|
||||
{0x30, 0xf0},
|
||||
{0x33, 0x33},
|
||||
{0xf0, 0x32},
|
||||
{0x48, 0x02},
|
||||
{0xf0, 0x33},
|
||||
{0x02, 0x12},
|
||||
{0x7c, 0x02},
|
||||
{0x7d, 0x0e},
|
||||
{0xa2, 0x04},
|
||||
{0x5e, 0x06},
|
||||
{0x5f, 0x0a},
|
||||
{0x0b, 0x58},
|
||||
{0x06, 0x38},
|
||||
{0xf0, 0x32},
|
||||
{0x48, 0x02},
|
||||
{0xf0, 0x39},
|
||||
{0x02, 0x70},
|
||||
{0xf0, 0x45},
|
||||
{0x09, 0x1c},
|
||||
{0xf0, 0x37},
|
||||
{0x22, 0x0d},
|
||||
{0xf0, 0x33},
|
||||
{0x33, 0x10},
|
||||
{0xb1, 0x80},
|
||||
{0x34, 0x40},
|
||||
{0x0b, 0x54},
|
||||
{0xb2, 0x78},
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x30},
|
||||
{0x38, 0x44},
|
||||
{0xf0, 0x33},
|
||||
{0xb3, 0x51},
|
||||
{0x01, 0x10},
|
||||
{0x0b, 0x6c},
|
||||
{0x06, 0x24},
|
||||
{0xf0, 0x36},
|
||||
{0x31, 0x82},
|
||||
{0x3e, 0x60},
|
||||
{0x30, 0xf0},
|
||||
{0x33, 0x33},
|
||||
{0xf0, 0x34},
|
||||
{0x9f, 0x02},
|
||||
{0xa6, 0x40},
|
||||
{0xa7, 0x47},
|
||||
{0xe8, 0x5f},
|
||||
{0xa8, 0x51},
|
||||
{0xa9, 0x44},
|
||||
{0xe9, 0x36},
|
||||
{0xf0, 0x33},
|
||||
{0xb3, 0x51},
|
||||
{0x64, 0x17},
|
||||
{0x90, 0x01},
|
||||
{0x91, 0x03},
|
||||
{0x92, 0x07},
|
||||
{0x01, 0x10},
|
||||
{0x93, 0x10},
|
||||
{0x94, 0x10},
|
||||
{0x95, 0x10},
|
||||
{0x96, 0x01},
|
||||
{0x97, 0x07},
|
||||
{0x98, 0x1f},
|
||||
{0x99, 0x10},
|
||||
{0x9a, 0x20},
|
||||
{0x9b, 0x28},
|
||||
{0x9c, 0x28},
|
||||
{0xf0, 0x36},
|
||||
{0x70, 0x54},
|
||||
{0xb6, 0x40},
|
||||
{0xb7, 0x41},
|
||||
{0xb8, 0x43},
|
||||
{0xb9, 0x47},
|
||||
{0xba, 0x4f},
|
||||
{0xb0, 0x8b},
|
||||
{0xb1, 0x8b},
|
||||
{0xb2, 0x8b},
|
||||
{0xb3, 0x9b},
|
||||
{0xb4, 0xb8},
|
||||
{0xb5, 0xf0},
|
||||
{0x7e, 0x41},
|
||||
{0x7f, 0x47},
|
||||
{0x77, 0x80},
|
||||
{0x78, 0x84},
|
||||
{0x79, 0x8a},
|
||||
{0xa0, 0x47},
|
||||
{0xa1, 0x5f},
|
||||
{0x96, 0x43},
|
||||
{0x97, 0x44},
|
||||
{0x98, 0x54},
|
||||
{0xf0, 0x00},
|
||||
{0xf0, 0x01},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0xf0, 0x36},
|
||||
{0x37, 0x74},
|
||||
{0xf0, 0x3f},
|
||||
{0x03, 0x93},
|
||||
{0xf0, 0x36},//cvbs_off
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xc1},
|
||||
{0xf0, 0x37},
|
||||
{0x24, 0x21},
|
||||
{0xf0, 0x36},
|
||||
{0x41, 0x00},
|
||||
{0xe9, 0x2c},
|
||||
{0xf0, 0x33},
|
||||
{0x33, 0x00},
|
||||
{0x34, 0x00},
|
||||
{0xb1, 0x00},
|
||||
{0xf0, 0x00},
|
||||
{0xe0, 0x04},
|
||||
{0xf0, 0x01},
|
||||
{0x73, 0x00},
|
||||
{0x74, 0xe0},
|
||||
{0x70, 0x00},
|
||||
{0x71, 0x80},
|
||||
{0xf0, 0x36},
|
||||
{0x32, 0x44},
|
||||
{0xf0, 0x36},
|
||||
{0x3e, 0xe0},
|
||||
{0x70, 0x56},
|
||||
{0x7c, 0x43},
|
||||
{0x7d, 0x47},
|
||||
{0x74, 0x00},
|
||||
{0x75, 0x00},
|
||||
{0x76, 0x00},
|
||||
{0xa0, 0x47},
|
||||
{0xa1, 0x5f},
|
||||
{0x96, 0x22},
|
||||
{0x97, 0x22},
|
||||
{0x98, 0x22},
|
||||
{0xf0, 0x00},
|
||||
{0x72, 0x38},
|
||||
{0x7a, 0x80},
|
||||
{0x85, 0x18},
|
||||
{0x9b, 0x35},
|
||||
{0x9e, 0x20},
|
||||
{0xd0, 0x66},
|
||||
{0xd1, 0x34},
|
||||
{0Xd3, 0x44},
|
||||
{0xd6, 0x44},
|
||||
{0xb0, 0x41},
|
||||
{0xb2, 0x48},
|
||||
{0xb3, 0xf4},
|
||||
{0xb4, 0x0b},
|
||||
{0xb5, 0x78},
|
||||
{0xba, 0xff},
|
||||
{0xbb, 0xc0},
|
||||
{0xbc, 0x90},
|
||||
{0xbd, 0x3a},
|
||||
{0xc1, 0x67},
|
||||
{0xf0, 0x01},
|
||||
{0x20, 0x11},
|
||||
{0x23, 0x90},
|
||||
{0x24, 0x15},
|
||||
{0x25, 0x87},
|
||||
{0xbc, 0x9f},
|
||||
{0xbd, 0x3a},
|
||||
{0x48, 0xe6},
|
||||
{0x49, 0xc0},
|
||||
{0x4a, 0xd0},
|
||||
{0x4b, 0x48},
|
||||
|
||||
// [cvbs_on]
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x00},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xf1},
|
||||
|
||||
// [cvbs_off]
|
||||
{0xf0, 0x36},
|
||||
{0x11, 0x80},
|
||||
{0xf0, 0x01},
|
||||
{0x79, 0xc1},
|
||||
};
|
||||
|
||||
*/
|
||||
@@ -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__
|
||||
@@ -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
|
||||
};
|
||||
335
code/components/esp32-camera-master/sensors/sc030iot.c
Normal file
335
code/components/esp32-camera-master/sensors/sc030iot.c
Normal file
@@ -0,0 +1,335 @@
|
||||
/*
|
||||
* SC030IOT 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 "sc030iot.h"
|
||||
#include "sc030iot_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 = "sc030";
|
||||
#endif
|
||||
|
||||
#define SC030_SENSOR_ID_HIGH_REG 0XF7
|
||||
#define SC030_SENSOR_ID_LOW_REG 0XF8
|
||||
#define SC030_MAX_FRAME_WIDTH (640)
|
||||
#define SC030_MAX_FRAME_HIGH (480)
|
||||
|
||||
// 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.
|
||||
static int get_reg(sensor_t *sensor, int reg, int reg_value_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 &= reg_value_mask;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// 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.
|
||||
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); // mirror on
|
||||
} else {
|
||||
SET_REG_BITS_OR_RETURN(0x3221, 1, 2, 0x0); // mirror off
|
||||
}
|
||||
|
||||
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 test pattern mode
|
||||
|
||||
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, sc030iot_default_init_regs, sizeof(sc030iot_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[1:0],0x0170},H_end={0x0172[5: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) & 0x03) | (((offset_x+w)>>4)&0x30));
|
||||
|
||||
//sc:V_start={0x0175[1:0],0x0173},H_end={0x0175[5: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) & 0x03) | (((offset_y+h)>>4)&0x30));
|
||||
|
||||
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>SC030_MAX_FRAME_WIDTH || h > SC030_MAX_FRAME_HIGH) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
uint16_t offset_x = (640-w) /2;
|
||||
uint16_t offset_y = (480-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, sc030/sc031 sensor only support YUV422.
|
||||
break;
|
||||
default:
|
||||
return -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 sc030iot_detect(int slv_addr, sensor_id_t *id)
|
||||
{
|
||||
if (SC030IOT_SCCB_ADDR == slv_addr) {
|
||||
uint8_t MIDL = SCCB_Read(slv_addr, SC030_SENSOR_ID_LOW_REG);
|
||||
uint8_t MIDH = SCCB_Read(slv_addr, SC030_SENSOR_ID_HIGH_REG);
|
||||
uint16_t PID = MIDH << 8 | MIDL;
|
||||
if (SC030IOT_PID == PID) {
|
||||
id->PID = PID;
|
||||
return PID;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "Mismatch PID=0x%x", PID);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sc030iot_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_saturation= set_saturation;
|
||||
sensor->set_colorbar = set_colorbar;
|
||||
sensor->set_hmirror = set_hmirror;
|
||||
sensor->set_vflip = set_vflip;
|
||||
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_contrast = set_contrast;
|
||||
//not supported
|
||||
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, "sc030iot Attached");
|
||||
|
||||
return 0;
|
||||
}
|
||||
342
code/components/esp32-camera-master/sensors/sc101iot.c
Normal file
342
code/components/esp32-camera-master/sensors/sc101iot.c
Normal file
@@ -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;
|
||||
}
|
||||
@@ -34,10 +34,14 @@ static inline int gpio_ll_get_level(gpio_dev_t *hw, int gpio_num)
|
||||
#include "xclk.h"
|
||||
#include "cam_hal.h"
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR >= 3)
|
||||
#include "esp_rom_gpio.h"
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
||||
#define GPIO_PIN_INTR_NEGEDGE GPIO_INTR_NEGEDGE
|
||||
#define gpio_matrix_in(a,b,c) gpio_iomux_in(a,b)
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "esp32 ll_cam";
|
||||
@@ -233,7 +237,7 @@ static void IRAM_ATTR ll_cam_dma_isr(void *arg)
|
||||
//DBG_PIN_SET(0);
|
||||
}
|
||||
|
||||
bool ll_cam_stop(cam_obj_t *cam)
|
||||
bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam)
|
||||
{
|
||||
I2S0.conf.rx_start = 0;
|
||||
I2S_ISR_DISABLE(in_suc_eof);
|
||||
@@ -308,7 +312,7 @@ esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
|
||||
I2S0.clkm_conf.clkm_div_a = 0;
|
||||
I2S0.clkm_conf.clkm_div_b = 0;
|
||||
I2S0.clkm_conf.clkm_div_num = 2;
|
||||
|
||||
|
||||
I2S0.fifo_conf.dscr_en = 1;
|
||||
I2S0.fifo_conf.rx_fifo_mod = sampling_mode;
|
||||
I2S0.fifo_conf.rx_fifo_mod_force_en = 1;
|
||||
@@ -442,9 +446,12 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
}
|
||||
// Calculate DMA size
|
||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
||||
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u, dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u, image_size: %u",
|
||||
node_size * cam->dma_bytes_per_item, nodes_per_line, lines_per_node, dma_half_buffer_min * cam->dma_bytes_per_item, dma_half_buffer * cam->dma_bytes_per_item, lines_per_half_buffer, dma_buffer_size * cam->dma_bytes_per_item, image_size);
|
||||
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u, dma_half_buffer_min: %5u, dma_half_buffer: %5u,"
|
||||
"lines_per_half_buffer: %2u, dma_buffer_size: %5u, image_size: %u",
|
||||
(unsigned) (node_size * cam->dma_bytes_per_item), (unsigned) nodes_per_line, (unsigned) lines_per_node,
|
||||
(unsigned) (dma_half_buffer_min * cam->dma_bytes_per_item), (unsigned) (dma_half_buffer * cam->dma_bytes_per_item),
|
||||
(unsigned) (lines_per_half_buffer), (unsigned) (dma_buffer_size * cam->dma_bytes_per_item), (unsigned) image_size);
|
||||
|
||||
cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||
cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item;
|
||||
|
||||
@@ -21,10 +21,15 @@
|
||||
#include "xclk.h"
|
||||
#include "cam_hal.h"
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR >= 3)
|
||||
#include "esp_rom_gpio.h"
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
||||
#define GPIO_PIN_INTR_NEGEDGE GPIO_INTR_NEGEDGE
|
||||
#define gpio_matrix_in(a,b,c) gpio_iomux_in(a,b)
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "s2 ll_cam";
|
||||
@@ -70,7 +75,7 @@ static void IRAM_ATTR ll_cam_dma_isr(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
bool ll_cam_stop(cam_obj_t *cam)
|
||||
bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam)
|
||||
{
|
||||
I2S0.conf.rx_start = 0;
|
||||
|
||||
@@ -119,7 +124,7 @@ bool ll_cam_start(cam_obj_t *cam, int frame_pos)
|
||||
} else {
|
||||
I2S0.in_link.addr = ((uint32_t)&cam->frames[frame_pos].dma[0]) & 0xfffff;
|
||||
}
|
||||
|
||||
|
||||
I2S0.in_link.start = 1;
|
||||
I2S0.conf.rx_start = 1;
|
||||
return true;
|
||||
@@ -299,8 +304,8 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u",
|
||||
node_size * cam->dma_bytes_per_item, nodes_per_line, lines_per_node);
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u",
|
||||
(unsigned) (node_size * cam->dma_bytes_per_item), nodes_per_line, lines_per_node);
|
||||
|
||||
cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item;
|
||||
|
||||
@@ -332,9 +337,10 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
size_t dma_buffer_max = 2 * dma_half_buffer_max;
|
||||
size_t dma_buffer_size = dma_buffer_max;
|
||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
||||
|
||||
ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u",
|
||||
dma_half_buffer_min * cam->dma_bytes_per_item, dma_half_buffer * cam->dma_bytes_per_item, lines_per_half_buffer, dma_buffer_size * cam->dma_bytes_per_item);
|
||||
|
||||
ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u",
|
||||
(unsigned) (dma_half_buffer_min * cam->dma_bytes_per_item), (unsigned) (dma_half_buffer * cam->dma_bytes_per_item),
|
||||
(unsigned) lines_per_half_buffer, (unsigned) (dma_buffer_size * cam->dma_bytes_per_item));
|
||||
|
||||
cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||
cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item;
|
||||
|
||||
@@ -22,10 +22,15 @@
|
||||
#include "soc/gdma_reg.h"
|
||||
#include "ll_cam.h"
|
||||
#include "cam_hal.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#define gpio_matrix_in(a,b,c) gpio_iomux_in(a,b)
|
||||
#define gpio_matrix_out(a,b,c,d) gpio_iomux_out(a,b,c)
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define gpio_matrix_out(a,b,c,d) esp_rom_gpio_connect_out_signal(a,b,c,d)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "s3 ll_cam";
|
||||
@@ -74,7 +79,7 @@ static void IRAM_ATTR ll_cam_dma_isr(void *arg)
|
||||
}
|
||||
}
|
||||
|
||||
bool ll_cam_stop(cam_obj_t *cam)
|
||||
bool IRAM_ATTR ll_cam_stop(cam_obj_t *cam)
|
||||
{
|
||||
if (cam->jpeg_mode || !cam->psram_mode) {
|
||||
GDMA.channel[cam->dma_num].in.int_ena.in_suc_eof = 0;
|
||||
@@ -170,6 +175,7 @@ static esp_err_t ll_cam_dma_init(cam_obj_t *cam)
|
||||
}
|
||||
|
||||
GDMA.channel[cam->dma_num].in.conf1.in_check_owner = 0;
|
||||
// GDMA.channel[cam->dma_num].in.conf1.in_ext_mem_bk_size = 2;
|
||||
|
||||
GDMA.channel[cam->dma_num].in.peri_sel.sel = 5;
|
||||
//GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15
|
||||
@@ -178,8 +184,57 @@ static esp_err_t ll_cam_dma_init(cam_obj_t *cam)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
static esp_err_t ll_cam_converter_config(cam_obj_t *cam, const camera_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
|
||||
switch (config->conv_mode) {
|
||||
case YUV422_TO_YUV420:
|
||||
if (config->pixel_format != PIXFORMAT_YUV422) {
|
||||
ret = ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "YUV422 to YUV420 mode");
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_yuv2yuv_mode = 1;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_yuv_mode = 0;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_trans_mode = 1;
|
||||
}
|
||||
break;
|
||||
case YUV422_TO_RGB565:
|
||||
if (config->pixel_format != PIXFORMAT_YUV422) {
|
||||
ret = ESP_FAIL;
|
||||
} else {
|
||||
ESP_LOGI(TAG, "YUV422 to RGB565 mode");
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_yuv2yuv_mode = 3;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_yuv_mode = 0;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_trans_mode = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#if CONFIG_LCD_CAM_CONV_BT709_ENABLED
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_protocol_mode = 1;
|
||||
#else
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_protocol_mode = 0;
|
||||
#endif
|
||||
#if CONFIG_LCD_CAM_CONV_FULL_RANGE_ENABLED
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_data_out_mode = 1;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_data_in_mode = 1;
|
||||
#else
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_data_out_mode = 0;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_data_in_mode = 0;
|
||||
#endif
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_mode_8bits_on = 1;
|
||||
LCD_CAM.cam_rgb_yuv.cam_conv_bypass = 1;
|
||||
cam->conv_mode = config->conv_mode;
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
if (REG_GET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN) == 0) {
|
||||
REG_CLR_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);
|
||||
REG_SET_BIT(SYSTEM_PERIP_CLK_EN1_REG, SYSTEM_LCD_CAM_CLK_EN);
|
||||
@@ -188,7 +243,7 @@ esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
|
||||
}
|
||||
|
||||
LCD_CAM.cam_ctrl.val = 0;
|
||||
|
||||
|
||||
LCD_CAM.cam_ctrl.cam_clkm_div_b = 0;
|
||||
LCD_CAM.cam_ctrl.cam_clkm_div_a = 0;
|
||||
LCD_CAM.cam_ctrl.cam_clkm_div_num = 160000000 / config->xclk_freq_hz;
|
||||
@@ -215,15 +270,21 @@ esp_err_t ll_cam_config(cam_obj_t *cam, const camera_config_t *config)
|
||||
|
||||
LCD_CAM.cam_rgb_yuv.val = 0;
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
if (config->conv_mode) {
|
||||
ret = ll_cam_converter_config(cam, config);
|
||||
if(ret != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
LCD_CAM.cam_ctrl.cam_update = 1;
|
||||
LCD_CAM.cam_ctrl1.cam_start = 1;
|
||||
|
||||
esp_err_t err = ll_cam_dma_init(cam);
|
||||
if(err != ESP_OK) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
ret = ll_cam_dma_init(cam);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ll_cam_vsync_intr_enable(cam_obj_t *cam, bool en)
|
||||
@@ -262,11 +323,12 @@ esp_err_t ll_cam_set_pin(cam_obj_t *cam, const camera_config_t *config)
|
||||
gpio_set_pull_mode(data_pins[i], GPIO_FLOATING);
|
||||
gpio_matrix_in(data_pins[i], CAM_DATA_IN0_IDX + i, false);
|
||||
}
|
||||
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_xclk], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(config->pin_xclk, GPIO_MODE_OUTPUT);
|
||||
gpio_set_pull_mode(config->pin_xclk, GPIO_FLOATING);
|
||||
gpio_matrix_out(config->pin_xclk, CAM_CLK_IDX, false, false);
|
||||
if (config->pin_xclk >= 0) {
|
||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_xclk], PIN_FUNC_GPIO);
|
||||
gpio_set_direction(config->pin_xclk, GPIO_MODE_OUTPUT);
|
||||
gpio_set_pull_mode(config->pin_xclk, GPIO_FLOATING);
|
||||
gpio_matrix_out(config->pin_xclk, CAM_CLK_IDX, false, false);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -338,8 +400,8 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u",
|
||||
node_size * cam->dma_bytes_per_item, nodes_per_line, lines_per_node);
|
||||
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u",
|
||||
(unsigned) (node_size * cam->dma_bytes_per_item), (unsigned) nodes_per_line, (unsigned) lines_per_node);
|
||||
|
||||
cam->dma_node_buffer_size = node_size * cam->dma_bytes_per_item;
|
||||
|
||||
@@ -371,9 +433,10 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
if (!cam->psram_mode) {
|
||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u",
|
||||
dma_half_buffer_min * cam->dma_bytes_per_item, dma_half_buffer * cam->dma_bytes_per_item, lines_per_half_buffer, dma_buffer_size * cam->dma_bytes_per_item);
|
||||
|
||||
ESP_LOGI(TAG, "dma_half_buffer_min: %5u, dma_half_buffer: %5u, lines_per_half_buffer: %2u, dma_buffer_size: %5u",
|
||||
(unsigned) (dma_half_buffer_min * cam->dma_bytes_per_item), (unsigned) (dma_half_buffer * cam->dma_bytes_per_item),
|
||||
(unsigned) lines_per_half_buffer, (unsigned) (dma_buffer_size * cam->dma_bytes_per_item));
|
||||
|
||||
cam->dma_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||
cam->dma_half_buffer_size = dma_half_buffer * cam->dma_bytes_per_item;
|
||||
@@ -382,7 +445,7 @@ static bool ll_cam_calc_rgb_dma(cam_obj_t *cam){
|
||||
}
|
||||
|
||||
bool ll_cam_dma_sizes(cam_obj_t *cam)
|
||||
{
|
||||
{
|
||||
cam->dma_bytes_per_item = 1;
|
||||
if (cam->jpeg_mode) {
|
||||
if (cam->psram_mode) {
|
||||
@@ -433,8 +496,22 @@ esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_
|
||||
}
|
||||
cam->fb_bytes_per_pixel = 1; // frame buffer stores Y8
|
||||
} else if (pix_format == PIXFORMAT_YUV422 || pix_format == PIXFORMAT_RGB565) {
|
||||
cam->in_bytes_per_pixel = 2; // camera sends YU/YV
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
switch (cam->conv_mode) {
|
||||
case YUV422_TO_YUV420:
|
||||
cam->in_bytes_per_pixel = 1.5; // for DMA receive
|
||||
cam->fb_bytes_per_pixel = 1.5; // frame buffer stores YUV420
|
||||
break;
|
||||
case YUV422_TO_RGB565:
|
||||
default:
|
||||
cam->in_bytes_per_pixel = 2; // for DMA receive
|
||||
cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
|
||||
break;
|
||||
}
|
||||
#else
|
||||
cam->in_bytes_per_pixel = 2; // for DMA receive
|
||||
cam->fb_bytes_per_pixel = 2; // frame buffer stores YU/YV/RGB565
|
||||
#endif
|
||||
} else if (pix_format == PIXFORMAT_JPEG) {
|
||||
cam->in_bytes_per_pixel = 1;
|
||||
cam->fb_bytes_per_pixel = 1;
|
||||
|
||||
@@ -101,7 +101,7 @@ typedef struct {
|
||||
QueueHandle_t frame_buffer_queue;
|
||||
TaskHandle_t task_handle;
|
||||
intr_handle_t cam_intr_handle;
|
||||
|
||||
|
||||
uint8_t dma_num;//ESP32-S3
|
||||
intr_handle_t dma_intr_handle;//ESP32-S3
|
||||
|
||||
@@ -116,8 +116,14 @@ typedef struct {
|
||||
//for RGB/YUV modes
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
float in_bytes_per_pixel;
|
||||
float fb_bytes_per_pixel;
|
||||
camera_conv_mode_t conv_mode;
|
||||
#else
|
||||
uint8_t in_bytes_per_pixel;
|
||||
uint8_t fb_bytes_per_pixel;
|
||||
#endif
|
||||
uint32_t fb_size;
|
||||
|
||||
cam_state_t state;
|
||||
@@ -134,7 +140,7 @@ esp_err_t ll_cam_init_isr(cam_obj_t *cam);
|
||||
void ll_cam_do_vsync(cam_obj_t *cam);
|
||||
uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
|
||||
bool ll_cam_dma_sizes(cam_obj_t *cam);
|
||||
size_t IRAM_ATTR ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
|
||||
size_t ll_cam_memcpy(cam_obj_t *cam, uint8_t *out, const uint8_t *in, size_t len);
|
||||
esp_err_t ll_cam_set_sample_mode(cam_obj_t *cam, pixformat_t pix_format, uint32_t xclk_freq_hz, uint16_t sensor_pid);
|
||||
|
||||
// implemented in cam_hal
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "unity.h"
|
||||
#include <mbedtls/base64.h>
|
||||
#include "esp_log.h"
|
||||
#include "driver/i2c.h"
|
||||
|
||||
#include "esp_camera.h"
|
||||
|
||||
@@ -105,11 +106,16 @@
|
||||
|
||||
#endif
|
||||
|
||||
#define I2C_MASTER_SCL_IO 4 /*!< GPIO number used for I2C master clock */
|
||||
#define I2C_MASTER_SDA_IO 5 /*!< GPIO number used for I2C master data */
|
||||
#define I2C_MASTER_NUM 0 /*!< I2C master i2c port number, the number of i2c peripheral interfaces available will depend on the chip */
|
||||
#define I2C_MASTER_FREQ_HZ 100000 /*!< I2C master clock frequency */
|
||||
|
||||
static const char *TAG = "test camera";
|
||||
|
||||
typedef void (*decode_func_t)(uint8_t *jpegbuffer, uint32_t size, uint8_t *outbuffer);
|
||||
|
||||
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count)
|
||||
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count, int sccb_sda_gpio_num, int sccb_port)
|
||||
{
|
||||
framesize_t size_bak = frame_size;
|
||||
if (PIXFORMAT_JPEG == pixel_format && FRAMESIZE_SVGA > frame_size) {
|
||||
@@ -119,8 +125,9 @@ static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, fr
|
||||
.pin_pwdn = PWDN_GPIO_NUM,
|
||||
.pin_reset = RESET_GPIO_NUM,
|
||||
.pin_xclk = XCLK_GPIO_NUM,
|
||||
.pin_sscb_sda = SIOD_GPIO_NUM,
|
||||
.pin_sscb_scl = SIOC_GPIO_NUM,
|
||||
.pin_sccb_sda = sccb_sda_gpio_num, // If pin_sccb_sda is -1, sccb will use the already initialized i2c port specified by `sccb_i2c_port`.
|
||||
.pin_sccb_scl = SIOC_GPIO_NUM,
|
||||
.sccb_i2c_port = sccb_port,
|
||||
|
||||
.pin_d7 = Y9_GPIO_NUM,
|
||||
.pin_d6 = Y8_GPIO_NUM,
|
||||
@@ -226,7 +233,7 @@ static void camera_performance_test(uint32_t xclk_freq, uint32_t pic_num)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
//detect sensor information
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2, SIOD_GPIO_NUM, -1));
|
||||
sensor_t *s = esp_camera_sensor_get();
|
||||
camera_sensor_info_t *info = esp_camera_sensor_get_info(&s->id);
|
||||
TEST_ASSERT_NOT_NULL(info);
|
||||
@@ -249,7 +256,7 @@ static void camera_performance_test(uint32_t xclk_freq, uint32_t pic_num)
|
||||
for (; format_s <= format_e; format_s++) {
|
||||
for (size_t i = 0; i <= max_size; i++) {
|
||||
ESP_LOGI(TAG, "\n\n===> Testing format:%s resolution: %d x %d <===", get_cam_format_name(*format_s), resolution[i].width, resolution[i].height);
|
||||
ret = init_camera(xclk_freq, *format_s, i, 2);
|
||||
ret = init_camera(xclk_freq, *format_s, i, 2, SIOD_GPIO_NUM, -1);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
if (ESP_OK != ret) {
|
||||
ESP_LOGW(TAG, "Testing init failed :-(, skip this item");
|
||||
@@ -276,7 +283,7 @@ static void camera_performance_test(uint32_t xclk_freq, uint32_t pic_num)
|
||||
TEST_CASE("Camera driver init, deinit test", "[camera]")
|
||||
{
|
||||
uint64_t t1 = esp_timer_get_time();
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2, SIOD_GPIO_NUM, -1));
|
||||
uint64_t t2 = esp_timer_get_time();
|
||||
ESP_LOGI(TAG, "Camera init time %llu ms", (t2 - t1) / 1000);
|
||||
|
||||
@@ -285,7 +292,7 @@ TEST_CASE("Camera driver init, deinit test", "[camera]")
|
||||
|
||||
TEST_CASE("Camera driver take RGB565 picture test", "[camera]")
|
||||
{
|
||||
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2));
|
||||
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2, SIOD_GPIO_NUM, -1));
|
||||
vTaskDelay(500 / portTICK_RATE_MS);
|
||||
ESP_LOGI(TAG, "Taking picture...");
|
||||
camera_fb_t *pic = esp_camera_fb_get();
|
||||
@@ -301,7 +308,7 @@ TEST_CASE("Camera driver take RGB565 picture test", "[camera]")
|
||||
|
||||
TEST_CASE("Camera driver take YUV422 picture test", "[camera]")
|
||||
{
|
||||
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_YUV422, FRAMESIZE_QVGA, 2));
|
||||
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_YUV422, FRAMESIZE_QVGA, 2, SIOD_GPIO_NUM, -1));
|
||||
vTaskDelay(500 / portTICK_RATE_MS);
|
||||
ESP_LOGI(TAG, "Taking picture...");
|
||||
camera_fb_t *pic = esp_camera_fb_get();
|
||||
@@ -317,7 +324,7 @@ TEST_CASE("Camera driver take YUV422 picture test", "[camera]")
|
||||
|
||||
TEST_CASE("Camera driver take JPEG picture test", "[camera]")
|
||||
{
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2));
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2, SIOD_GPIO_NUM, -1));
|
||||
vTaskDelay(500 / portTICK_RATE_MS);
|
||||
ESP_LOGI(TAG, "Taking picture...");
|
||||
camera_fb_t *pic = esp_camera_fb_get();
|
||||
@@ -484,6 +491,25 @@ static void img_jpeg_decode_test(uint16_t pic_index, uint16_t lib_index)
|
||||
jpg_decode_test(lib_index, DECODE_RGB565, imgs[pic_index].buf, imgs[pic_index].length, imgs[pic_index].w, imgs[pic_index].h, 16);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief i2c master initialization
|
||||
*/
|
||||
static esp_err_t i2c_master_init(int i2c_port)
|
||||
{
|
||||
i2c_config_t conf = {
|
||||
.mode = I2C_MODE_MASTER,
|
||||
.sda_io_num = I2C_MASTER_SDA_IO,
|
||||
.scl_io_num = I2C_MASTER_SCL_IO,
|
||||
.sda_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.scl_pullup_en = GPIO_PULLUP_ENABLE,
|
||||
.master.clk_speed = I2C_MASTER_FREQ_HZ,
|
||||
};
|
||||
|
||||
i2c_param_config(i2c_port, &conf);
|
||||
|
||||
return i2c_driver_install(i2c_port, conf.mode, 0, 0, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Conversions image 227x149 jpeg decode test", "[camera]")
|
||||
{
|
||||
img_jpeg_decode_test(0, 0);
|
||||
@@ -498,3 +524,12 @@ TEST_CASE("Conversions image 480x320 jpeg decode test", "[camera]")
|
||||
{
|
||||
img_jpeg_decode_test(2, 0);
|
||||
}
|
||||
|
||||
TEST_CASE("Camera driver uses an i2c port initialized by other devices test", "[camera]")
|
||||
{
|
||||
TEST_ESP_OK(i2c_master_init(I2C_MASTER_NUM));
|
||||
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2, -1, I2C_MASTER_NUM));
|
||||
vTaskDelay(500 / portTICK_RATE_MS);
|
||||
TEST_ESP_OK(esp_camera_deinit());
|
||||
TEST_ESP_OK(i2c_driver_delete(I2C_MASTER_NUM));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user