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:
@@ -69,6 +69,15 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
|
|||||||
|
|
||||||
------
|
------
|
||||||
|
|
||||||
|
##### Rolling (2022-09-24)
|
||||||
|
|
||||||
|
- Updated menue
|
||||||
|
- Update tflite, esp32-cam-master, esp-nn (as of today 20220924)
|
||||||
|
|
||||||
|
##### Rolling (2022-09-21)
|
||||||
|
|
||||||
|
- Spelling corrections (**[cristianmitran](https://github.com/cristianmitran)**)
|
||||||
|
|
||||||
##### Rolling (2022-09-21)
|
##### Rolling (2022-09-21)
|
||||||
|
|
||||||
- New update mechanism:
|
- New update mechanism:
|
||||||
|
|||||||
BIN
code/components/esp-nn_20220924.zip
Normal file
BIN
code/components/esp-nn_20220924.zip
Normal file
Binary file not shown.
@@ -8,26 +8,56 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build-master:
|
build-master:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
idf_target: ["esp32", "esp32s2", "esp32s3"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: esp-idf build
|
- name: esp-idf build
|
||||||
uses: espressif/esp-idf-ci-action@latest
|
uses: espressif/esp-idf-ci-action@main
|
||||||
with:
|
with:
|
||||||
|
target: ${{ matrix.idf_target }}
|
||||||
path: 'examples'
|
path: 'examples'
|
||||||
|
|
||||||
build-release-v4_0:
|
build-release-v5_0:
|
||||||
|
name: Build for ${{ matrix.idf_target }} on ${{ matrix.idf_ver }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
idf_ver: ["release-v5.0"]
|
||||||
|
idf_target: ["esp32", "esp32s2", "esp32s3"]
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repo
|
- name: Checkout repo
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
submodules: 'recursive'
|
submodules: 'recursive'
|
||||||
- name: esp-idf build
|
- name: esp-idf build
|
||||||
uses: espressif/esp-idf-ci-action@release-v4.0
|
uses: espressif/esp-idf-ci-action@main
|
||||||
with:
|
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'
|
path: 'examples'
|
||||||
|
|
||||||
build-release-v4_1:
|
build-release-v4_1:
|
||||||
@@ -65,15 +95,3 @@ jobs:
|
|||||||
uses: espressif/esp-idf-ci-action@release-v4.3
|
uses: espressif/esp-idf-ci-action@release-v4.3
|
||||||
with:
|
with:
|
||||||
path: 'examples'
|
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
|
- uses: actions/checkout@master
|
||||||
with:
|
with:
|
||||||
submodules: "recursive"
|
submodules: "recursive"
|
||||||
|
|
||||||
- name: Upload component to the component registry
|
- name: Upload component to the component registry
|
||||||
uses: espressif/github-actions/upload_components@master
|
uses: espressif/github-actions/upload_components@master
|
||||||
with:
|
with:
|
||||||
name: "esp32-camera"
|
name: "esp32-camera"
|
||||||
version: "git"
|
|
||||||
namespace: "espressif"
|
namespace: "espressif"
|
||||||
service_url: ${{ secrets.IDF_COMPONENT_API_URL }}
|
version: ${{ github.ref_name }}
|
||||||
api_token: ${{ secrets.IDF_COMPONENT_API_TOKEN }}
|
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")
|
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/esp_camera.c
|
||||||
driver/cam_hal.c
|
driver/cam_hal.c
|
||||||
driver/sccb.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/gc2145.c
|
||||||
sensors/gc032a.c
|
sensors/gc032a.c
|
||||||
sensors/bf3005.c
|
sensors/bf3005.c
|
||||||
conversions/yuv.c
|
sensors/bf20a6.c
|
||||||
conversions/to_jpg.cpp
|
sensors/sc101iot.c
|
||||||
conversions/to_bmp.c
|
sensors/sc030iot.c
|
||||||
conversions/jpge.cpp
|
|
||||||
conversions/esp_jpg_decode.c
|
|
||||||
)
|
)
|
||||||
|
|
||||||
set(COMPONENT_ADD_INCLUDEDIRS
|
list(APPEND COMPONENT_PRIV_INCLUDEDIRS
|
||||||
driver/include
|
|
||||||
conversions/include
|
|
||||||
)
|
|
||||||
|
|
||||||
set(COMPONENT_PRIV_INCLUDEDIRS
|
|
||||||
driver/private_include
|
driver/private_include
|
||||||
sensors/private_include
|
sensors/private_include
|
||||||
conversions/private_include
|
|
||||||
target/private_include
|
target/private_include
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -58,8 +74,13 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(COMPONENT_REQUIRES driver)
|
|
||||||
set(COMPONENT_PRIV_REQUIRES freertos nvs_flash)
|
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()
|
endif()
|
||||||
|
|
||||||
|
register_component()
|
||||||
|
|||||||
@@ -69,6 +69,45 @@ menu "Camera configuration"
|
|||||||
help
|
help
|
||||||
Enable this option if you want to use the BF3005.
|
Enable this option if you want to use the BF3005.
|
||||||
Disable this option to save memory.
|
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
|
choice SCCB_HARDWARE_I2C_PORT
|
||||||
bool "I2C peripheral to use for SCCB"
|
bool "I2C peripheral to use for SCCB"
|
||||||
@@ -103,6 +142,12 @@ menu "Camera configuration"
|
|||||||
bool "Subsample Mode"
|
bool "Subsample Mode"
|
||||||
endchoice
|
endchoice
|
||||||
|
|
||||||
|
config CAMERA_TASK_STACK_SIZE
|
||||||
|
int "CAM task stack size"
|
||||||
|
default 2048
|
||||||
|
help
|
||||||
|
Camera task stack size
|
||||||
|
|
||||||
choice CAMERA_TASK_PINNED_TO_CORE
|
choice CAMERA_TASK_PINNED_TO_CORE
|
||||||
bool "Camera task pinned to core"
|
bool "Camera task pinned to core"
|
||||||
default CAMERA_CORE0
|
default CAMERA_CORE0
|
||||||
@@ -124,6 +169,37 @@ menu "Camera configuration"
|
|||||||
default 32768
|
default 32768
|
||||||
help
|
help
|
||||||
Maximum value of DMA buffer
|
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
|
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" |
|
| 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" |
|
| GC2145 | 1600 x 1200 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/5" |
|
||||||
| BF3005 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/4" |
|
| BF3005 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer<br/>RGB565 | 1/4" |
|
||||||
|
| BF20A6 | 640 x 480 | color | YUV/YCbCr422<br/>RAW Bayer | 1/10" |
|
||||||
|
| 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
|
## Important to Remember
|
||||||
|
|
||||||
@@ -128,8 +131,8 @@ static camera_config_t camera_config = {
|
|||||||
.pin_pwdn = CAM_PIN_PWDN,
|
.pin_pwdn = CAM_PIN_PWDN,
|
||||||
.pin_reset = CAM_PIN_RESET,
|
.pin_reset = CAM_PIN_RESET,
|
||||||
.pin_xclk = CAM_PIN_XCLK,
|
.pin_xclk = CAM_PIN_XCLK,
|
||||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
.pin_sccb_sda = CAM_PIN_SIOD,
|
||||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
.pin_sccb_scl = CAM_PIN_SIOC,
|
||||||
|
|
||||||
.pin_d7 = CAM_PIN_D7,
|
.pin_d7 = CAM_PIN_D7,
|
||||||
.pin_d6 = CAM_PIN_D6,
|
.pin_d6 = CAM_PIN_D6,
|
||||||
|
|||||||
@@ -21,6 +21,10 @@
|
|||||||
#include "tjpgd.h"
|
#include "tjpgd.h"
|
||||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||||
#include "esp32s3/rom/tjpgd.h"
|
#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
|
#else
|
||||||
#error Target CONFIG_IDF_TARGET is not supported
|
#error Target CONFIG_IDF_TARGET is not supported
|
||||||
#endif
|
#endif
|
||||||
@@ -57,7 +61,7 @@ static const char * jd_errors[] = {
|
|||||||
"Not supported JPEG standard"
|
"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 x = rect->left;
|
||||||
uint16_t y = rect->top;
|
uint16_t y = rect->top;
|
||||||
@@ -73,7 +77,7 @@ static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
|||||||
return 0;
|
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;
|
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||||
if (jpeg->len && len > (jpeg->len - jpeg->index)) {
|
if (jpeg->len && len > (jpeg->len - jpeg->index)) {
|
||||||
|
|||||||
@@ -29,7 +29,12 @@ namespace jpge {
|
|||||||
if(b){
|
if(b){
|
||||||
return 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);
|
return heap_caps_malloc(nSize, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
|
#else
|
||||||
|
return NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
static inline void jpge_free(void *p) { free(p); }
|
static inline void jpge_free(void *p) { free(p); }
|
||||||
|
|
||||||
|
|||||||
@@ -21,19 +21,6 @@
|
|||||||
#include "esp_jpg_decode.h"
|
#include "esp_jpg_decode.h"
|
||||||
|
|
||||||
#include "esp_system.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)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||||
#include "esp32-hal-log.h"
|
#include "esp32-hal-log.h"
|
||||||
@@ -72,7 +59,12 @@ typedef struct {
|
|||||||
|
|
||||||
static void *_malloc(size_t size)
|
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);
|
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
|
//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
|
//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;
|
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||||
if(buf) {
|
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;
|
*out_len = 0;
|
||||||
|
|
||||||
int pix_count = width*height;
|
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);
|
uint8_t * out_buf = (uint8_t *)_malloc(out_size);
|
||||||
if(!out_buf) {
|
if(!out_buf) {
|
||||||
ESP_LOGE(TAG, "_malloc failed! %u", out_size);
|
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];
|
bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
|
||||||
bitmap->reserved = 0;
|
bitmap->reserved = 0;
|
||||||
bitmap->filesize = out_size;
|
bitmap->filesize = out_size;
|
||||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN + palette_size;
|
||||||
bitmap->dibheadersize = 40;
|
bitmap->dibheadersize = 40;
|
||||||
bitmap->width = width;
|
bitmap->width = width;
|
||||||
bitmap->height = -height;//set negative for top to bottom
|
bitmap->height = -height;//set negative for top to bottom
|
||||||
bitmap->planes = 1;
|
bitmap->planes = 1;
|
||||||
bitmap->bitsperpixel = 24;
|
bitmap->bitsperpixel = bpp * 8;
|
||||||
bitmap->compression = 0;
|
bitmap->compression = 0;
|
||||||
bitmap->imagesize = pix_count * 3;
|
bitmap->imagesize = pix_count * bpp;
|
||||||
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||||
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||||
bitmap->numcolorspallette = 0;
|
bitmap->numcolorspallette = 0;
|
||||||
bitmap->mostimpcolor = 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;
|
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
|
//convert data to RGB888
|
||||||
if(format == PIXFORMAT_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) {
|
} else if(format == PIXFORMAT_RGB565) {
|
||||||
int i;
|
int i;
|
||||||
uint8_t hb, lb;
|
uint8_t hb, lb;
|
||||||
for(i=0; i<pix_count; i++) {
|
for(i=0; i<pix_count; i++) {
|
||||||
hb = *src_buf++;
|
hb = *src_buf++;
|
||||||
lb = *src_buf++;
|
lb = *src_buf++;
|
||||||
*rgb_buf++ = (lb & 0x1F) << 3;
|
*pix_buf++ = (lb & 0x1F) << 3;
|
||||||
*rgb_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
*pix_buf++ = (hb & 0x07) << 5 | (lb & 0xE0) >> 3;
|
||||||
*rgb_buf++ = hb & 0xF8;
|
*pix_buf++ = hb & 0xF8;
|
||||||
}
|
}
|
||||||
} else if(format == PIXFORMAT_GRAYSCALE) {
|
} else if(format == PIXFORMAT_GRAYSCALE) {
|
||||||
int i;
|
memcpy(pix_buf, src_buf, pix_count);
|
||||||
uint8_t b;
|
|
||||||
for(i=0; i<pix_count; i++) {
|
|
||||||
b = *src_buf++;
|
|
||||||
*rgb_buf++ = b;
|
|
||||||
*rgb_buf++ = b;
|
|
||||||
*rgb_buf++ = b;
|
|
||||||
}
|
|
||||||
} else if(format == PIXFORMAT_YUV422) {
|
} else if(format == PIXFORMAT_YUV422) {
|
||||||
int i, maxi = pix_count / 2;
|
int i, maxi = pix_count / 2;
|
||||||
uint8_t y0, y1, u, v;
|
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++;
|
v = *src_buf++;
|
||||||
|
|
||||||
yuv2rgb(y0, u, v, &r, &g, &b);
|
yuv2rgb(y0, u, v, &r, &g, &b);
|
||||||
*rgb_buf++ = b;
|
*pix_buf++ = b;
|
||||||
*rgb_buf++ = g;
|
*pix_buf++ = g;
|
||||||
*rgb_buf++ = r;
|
*pix_buf++ = r;
|
||||||
|
|
||||||
yuv2rgb(y1, u, v, &r, &g, &b);
|
yuv2rgb(y1, u, v, &r, &g, &b);
|
||||||
*rgb_buf++ = b;
|
*pix_buf++ = b;
|
||||||
*rgb_buf++ = g;
|
*pix_buf++ = g;
|
||||||
*rgb_buf++ = r;
|
*pix_buf++ = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*out = out_buf;
|
*out = out_buf;
|
||||||
|
|||||||
@@ -21,21 +21,6 @@
|
|||||||
#include "jpge.h"
|
#include "jpge.h"
|
||||||
#include "yuv.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)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||||
#include "esp32-hal-log.h"
|
#include "esp32-hal-log.h"
|
||||||
#define TAG ""
|
#define TAG ""
|
||||||
@@ -50,7 +35,12 @@ static void *_malloc(size_t size)
|
|||||||
if(res) {
|
if(res) {
|
||||||
return 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);
|
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)
|
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 "ll_cam.h"
|
||||||
#include "cam_hal.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 cam_obj_t *cam_obj = NULL;
|
||||||
|
|
||||||
static const uint32_t JPEG_SOI_MARKER = 0xFFD8FF; // written in little-endian for esp32
|
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++) {
|
for (uint32_t i = 0; i < length; i++) {
|
||||||
sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF;
|
sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF;
|
||||||
if (sig == JPEG_SOI_MARKER) {
|
if (sig == JPEG_SOI_MARKER) {
|
||||||
ESP_LOGW(TAG, "SOI: %d", i);
|
ESP_LOGW(TAG, "SOI: %d", (int) i);
|
||||||
return 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) {
|
if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) {
|
||||||
ll_cam_stop(cam);
|
ll_cam_stop(cam);
|
||||||
cam->state = CAM_STATE_IDLE;
|
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;
|
int frame_pos = 0;
|
||||||
cam_obj->state = CAM_STATE_IDLE;
|
cam_obj->state = CAM_STATE_IDLE;
|
||||||
cam_event_t cam_event = 0;
|
cam_event_t cam_event = 0;
|
||||||
|
|
||||||
xQueueReset(cam_obj->event_queue);
|
xQueueReset(cam_obj->event_queue);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
@@ -127,7 +146,7 @@ static void cam_task(void *arg)
|
|||||||
case CAM_STATE_READ_BUF: {
|
case CAM_STATE_READ_BUF: {
|
||||||
camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb;
|
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);
|
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_event == CAM_IN_SUC_EOF_EVENT) {
|
||||||
if(!cam_obj->psram_mode){
|
if(!cam_obj->psram_mode){
|
||||||
if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
|
if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
|
||||||
@@ -137,8 +156,8 @@ static void cam_task(void *arg)
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
&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_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||||
cam_obj->dma_half_buffer_size);
|
cam_obj->dma_half_buffer_size);
|
||||||
}
|
}
|
||||||
//Check for JPEG SOI in the first buffer. stop if not found
|
//Check for JPEG SOI in the first buffer. stop if not found
|
||||||
@@ -160,8 +179,8 @@ static void cam_task(void *arg)
|
|||||||
cnt--;
|
cnt--;
|
||||||
} else {
|
} else {
|
||||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
&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_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||||
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) {
|
} else if (!cam_obj->jpeg_mode) {
|
||||||
if (frame_buffer_event->len != cam_obj->fb_size) {
|
if (frame_buffer_event->len != cam_obj->fb_size) {
|
||||||
cam_obj->frames[frame_pos].en = 1;
|
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
|
//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->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
|
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",
|
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);
|
(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_buffer = NULL;
|
||||||
cam_obj->dma = 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].fb_offset = 0;
|
||||||
cam_obj->frames[x].en = 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");
|
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);
|
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);
|
CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
|
||||||
if (cam_obj->psram_mode) {
|
if (cam_obj->psram_mode) {
|
||||||
//align PSRAM buffer. TODO: save the offset so proper address can be freed later
|
//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_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;
|
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_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);
|
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) {
|
if (!cam_obj->psram_mode) {
|
||||||
cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
|
cam_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) {
|
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__,
|
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));
|
(int) cam_obj->dma_buffer_size, (int) heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
|
||||||
return ESP_FAIL;
|
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->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;
|
cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cam_dma_config(config);
|
ret = cam_dma_config(config);
|
||||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);
|
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);
|
ret = ll_cam_init_isr(cam_obj);
|
||||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);
|
CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);
|
||||||
|
|
||||||
|
|
||||||
#if CONFIG_CAMERA_CORE0
|
#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
|
#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
|
#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
|
#endif
|
||||||
|
|
||||||
ESP_LOGI(TAG, "cam config ok");
|
ESP_LOGI(TAG, "cam config ok");
|
||||||
|
|||||||
@@ -57,6 +57,15 @@
|
|||||||
#if CONFIG_BF3005_SUPPORT
|
#if CONFIG_BF3005_SUPPORT
|
||||||
#include "bf3005.h"
|
#include "bf3005.h"
|
||||||
#endif
|
#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)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||||
#include "esp32-hal-log.h"
|
#include "esp32-hal-log.h"
|
||||||
@@ -119,10 +128,20 @@ static const sensor_func_t g_sensors[] = {
|
|||||||
#if CONFIG_BF3005_SUPPORT
|
#if CONFIG_BF3005_SUPPORT
|
||||||
{bf3005_detect, bf3005_init},
|
{bf3005_detect, bf3005_init},
|
||||||
#endif
|
#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)
|
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;
|
*out_camera_model = CAMERA_NONE;
|
||||||
if (s_state != NULL) {
|
if (s_state != NULL) {
|
||||||
return ESP_ERR_INVALID_STATE;
|
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);
|
CAMERA_ENABLE_OUT_CLOCK(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config->pin_sscb_sda != -1) {
|
if (config->pin_sccb_sda != -1) {
|
||||||
ESP_LOGD(TAG, "Initializing SSCB");
|
ESP_LOGD(TAG, "Initializing SCCB");
|
||||||
SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl);
|
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) {
|
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);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Searching for camera address");
|
ESP_LOGD(TAG, "Searching for camera address");
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
uint8_t slv_addr = SCCB_Probe();
|
uint8_t slv_addr = SCCB_Probe();
|
||||||
|
|
||||||
if (slv_addr == 0) {
|
if (slv_addr == 0) {
|
||||||
CAMERA_DISABLE_OUT_CLOCK();
|
ret = ESP_ERR_NOT_FOUND;
|
||||||
return ESP_ERR_NOT_FOUND;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Detected camera at address=0x%02x", slv_addr);
|
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
|
if (CAMERA_NONE == *out_camera_model) { //If no supported sensors are detected
|
||||||
CAMERA_DISABLE_OUT_CLOCK();
|
|
||||||
ESP_LOGE(TAG, "Detected camera not supported.");
|
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",
|
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");
|
ESP_LOGD(TAG, "Doing SW reset of sensor");
|
||||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||||
s_state->sensor.reset(&s_state->sensor);
|
|
||||||
|
return s_state->sensor.reset(&s_state->sensor);
|
||||||
return ESP_OK;
|
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 esp_camera_init(const camera_config_t *config)
|
||||||
{
|
{
|
||||||
esp_err_t err;
|
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.status.framesize = frame_size;
|
||||||
s_state->sensor.pixformat = pix_format;
|
s_state->sensor.pixformat = pix_format;
|
||||||
|
|
||||||
ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height);
|
ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height);
|
||||||
if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
|
if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
|
||||||
ESP_LOGE(TAG, "Failed to set frame size");
|
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;
|
goto fail;
|
||||||
}
|
}
|
||||||
s_state->sensor.set_pixformat(&s_state->sensor, pix_format);
|
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) {
|
if (s_state->sensor.id.PID == OV2640_PID) {
|
||||||
s_state->sensor.set_gainceiling(&s_state->sensor, GAINCEILING_2X);
|
s_state->sensor.set_gainceiling(&s_state->sensor, GAINCEILING_2X);
|
||||||
|
|||||||
@@ -18,8 +18,8 @@
|
|||||||
.pin_pwdn = PIN_PWDN,
|
.pin_pwdn = PIN_PWDN,
|
||||||
.pin_reset = PIN_RESET,
|
.pin_reset = PIN_RESET,
|
||||||
.pin_xclk = PIN_XCLK,
|
.pin_xclk = PIN_XCLK,
|
||||||
.pin_sscb_sda = PIN_SIOD,
|
.pin_sccb_sda = PIN_SIOD,
|
||||||
.pin_sscb_scl = PIN_SIOC,
|
.pin_sccb_scl = PIN_SIOC,
|
||||||
.pin_d7 = PIN_D7,
|
.pin_d7 = PIN_D7,
|
||||||
.pin_d6 = PIN_D6,
|
.pin_d6 = PIN_D6,
|
||||||
.pin_d5 = PIN_D5,
|
.pin_d5 = PIN_D5,
|
||||||
@@ -70,6 +70,7 @@
|
|||||||
#include "driver/ledc.h"
|
#include "driver/ledc.h"
|
||||||
#include "sensor.h"
|
#include "sensor.h"
|
||||||
#include "sys/time.h"
|
#include "sys/time.h"
|
||||||
|
#include "sdkconfig.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
@@ -91,6 +92,19 @@ typedef enum {
|
|||||||
CAMERA_FB_IN_DRAM /*!< Frame buffer is placed in internal DRAM */
|
CAMERA_FB_IN_DRAM /*!< Frame buffer is placed in internal DRAM */
|
||||||
} camera_fb_location_t;
|
} 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
|
* @brief Configuration structure for camera initialization
|
||||||
*/
|
*/
|
||||||
@@ -98,8 +112,14 @@ typedef struct {
|
|||||||
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
||||||
int pin_reset; /*!< GPIO pin for camera reset line */
|
int pin_reset; /*!< GPIO pin for camera reset line */
|
||||||
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
||||||
int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
|
union {
|
||||||
int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
|
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_d7; /*!< GPIO pin for camera D7 line */
|
||||||
int pin_d6; /*!< GPIO pin for camera D6 line */
|
int pin_d6; /*!< GPIO pin for camera D6 line */
|
||||||
int pin_d5; /*!< GPIO pin for camera D5 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) */
|
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_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 */
|
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;
|
} camera_config_t;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,6 +27,9 @@ typedef enum {
|
|||||||
GC032A_PID = 0x232a,
|
GC032A_PID = 0x232a,
|
||||||
GC0308_PID = 0x9b,
|
GC0308_PID = 0x9b,
|
||||||
BF3005_PID = 0x30,
|
BF3005_PID = 0x30,
|
||||||
|
BF20A6_PID = 0x20a6,
|
||||||
|
SC101IOT_PID = 0xda4a,
|
||||||
|
SC030IOT_PID = 0x9a46,
|
||||||
} camera_pid_t;
|
} camera_pid_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
@@ -40,6 +43,9 @@ typedef enum {
|
|||||||
CAMERA_GC032A,
|
CAMERA_GC032A,
|
||||||
CAMERA_GC0308,
|
CAMERA_GC0308,
|
||||||
CAMERA_BF3005,
|
CAMERA_BF3005,
|
||||||
|
CAMERA_BF20A6,
|
||||||
|
CAMERA_SC101IOT,
|
||||||
|
CAMERA_SC030IOT,
|
||||||
CAMERA_MODEL_MAX,
|
CAMERA_MODEL_MAX,
|
||||||
CAMERA_NONE,
|
CAMERA_NONE,
|
||||||
} camera_model_t;
|
} camera_model_t;
|
||||||
@@ -55,11 +61,15 @@ typedef enum {
|
|||||||
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
|
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||||
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
|
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||||
BF3005_SCCB_ADDR = 0x6E,
|
BF3005_SCCB_ADDR = 0x6E,
|
||||||
|
BF20A6_SCCB_ADDR = 0x6E,
|
||||||
|
SC101IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||||
|
SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||||
} camera_sccb_addr_t;
|
} camera_sccb_addr_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||||
PIXFORMAT_YUV422, // 2BPP/YUV422
|
PIXFORMAT_YUV422, // 2BPP/YUV422
|
||||||
|
PIXFORMAT_YUV420, // 1.5BPP/YUV420
|
||||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||||
@@ -199,7 +209,7 @@ typedef struct _sensor {
|
|||||||
|
|
||||||
// Sensor function pointers
|
// Sensor function pointers
|
||||||
int (*init_status) (sensor_t *sensor);
|
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_pixformat) (sensor_t *sensor, pixformat_t pixformat);
|
||||||
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
||||||
int (*set_contrast) (sensor_t *sensor, int level);
|
int (*set_contrast) (sensor_t *sensor, int level);
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
#define __SCCB_H__
|
#define __SCCB_H__
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
int SCCB_Init(int pin_sda, int pin_scl);
|
int SCCB_Init(int pin_sda, int pin_scl);
|
||||||
|
int SCCB_Use_Port(int sccb_i2c_port);
|
||||||
int SCCB_Deinit(void);
|
int SCCB_Deinit(void);
|
||||||
uint8_t SCCB_Probe();
|
uint8_t SCCB_Probe();
|
||||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||||
|
|||||||
@@ -25,6 +25,11 @@ static const char* TAG = "sccb";
|
|||||||
|
|
||||||
#include "driver/i2c.h"
|
#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 SCCB_FREQ CONFIG_SCCB_CLK_FREQ /*!< I2C master frequency*/
|
||||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
#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 ACK_VAL 0x0 /*!< I2C ack value */
|
||||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||||
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
||||||
const int SCCB_I2C_PORT = 1;
|
const int SCCB_I2C_PORT_DEFAULT = 1;
|
||||||
#else
|
#else
|
||||||
const int SCCB_I2C_PORT = 0;
|
const int SCCB_I2C_PORT_DEFAULT = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static int sccb_i2c_port;
|
||||||
|
static bool sccb_owns_i2c_port;
|
||||||
|
|
||||||
int SCCB_Init(int pin_sda, int pin_scl)
|
int SCCB_Init(int pin_sda, int pin_scl)
|
||||||
{
|
{
|
||||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d", pin_sda, pin_scl);
|
ESP_LOGI(TAG, "pin_sda %d pin_scl %d", pin_sda, pin_scl);
|
||||||
i2c_config_t conf;
|
i2c_config_t conf;
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
memset(&conf, 0, sizeof(i2c_config_t));
|
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.mode = I2C_MODE_MASTER;
|
||||||
conf.sda_io_num = pin_sda;
|
conf.sda_io_num = pin_sda;
|
||||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
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.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||||
conf.master.clk_speed = SCCB_FREQ;
|
conf.master.clk_speed = SCCB_FREQ;
|
||||||
|
|
||||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
if ((ret = i2c_param_config(sccb_i2c_port, &conf)) != ESP_OK) {
|
||||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
return ret;
|
||||||
return 0;
|
}
|
||||||
|
|
||||||
|
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)
|
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 SCCB_Probe(void)
|
||||||
{
|
{
|
||||||
uint8_t slave_addr = 0x0;
|
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++) {
|
for (size_t i = 0; i < CAMERA_MODEL_MAX; i++) {
|
||||||
if (slave_addr == camera_sensor[i].sccb_addr) {
|
if (slave_addr == camera_sensor[i].sccb_addr) {
|
||||||
continue;
|
continue;
|
||||||
@@ -83,7 +105,7 @@ uint8_t SCCB_Probe(void)
|
|||||||
i2c_master_start(cmd);
|
i2c_master_start(cmd);
|
||||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if( ret == ESP_OK) {
|
if( ret == ESP_OK) {
|
||||||
return slave_addr;
|
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, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) return -1;
|
if(ret != ESP_OK) return -1;
|
||||||
cmd = i2c_cmd_link_create();
|
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_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) {
|
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);
|
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, reg, ACK_CHECK_EN);
|
||||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) {
|
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);
|
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[0], ACK_CHECK_EN);
|
||||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) return -1;
|
if(ret != ESP_OK) return -1;
|
||||||
cmd = i2c_cmd_link_create();
|
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_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) {
|
if(ret != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
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, reg_u8[1], ACK_CHECK_EN);
|
||||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||||
i2c_master_stop(cmd);
|
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);
|
i2c_cmd_link_delete(cmd);
|
||||||
if(ret != ESP_OK) {
|
if(ret != ESP_OK) {
|
||||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
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_GC032A, "GC032A", GC032A_SCCB_ADDR, GC032A_PID, FRAMESIZE_VGA, false},
|
||||||
{CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false},
|
{CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false},
|
||||||
{CAMERA_BF3005, "BF3005", BF3005_SCCB_ADDR, BF3005_PID, FRAMESIZE_VGA, false},
|
{CAMERA_BF3005, "BF3005", BF3005_SCCB_ADDR, BF3005_PID, FRAMESIZE_VGA, false},
|
||||||
|
{CAMERA_BF20A6, "BF20A6", BF20A6_SCCB_ADDR, BF20A6_PID, FRAMESIZE_VGA, false},
|
||||||
|
{CAMERA_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] = {
|
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||||
|
|||||||
@@ -38,6 +38,11 @@
|
|||||||
#include "freertos/FreeRTOS.h"
|
#include "freertos/FreeRTOS.h"
|
||||||
#include "freertos/task.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"
|
#include "esp_camera.h"
|
||||||
|
|
||||||
#define BOARD_WROVER_KIT 1
|
#define BOARD_WROVER_KIT 1
|
||||||
@@ -94,8 +99,8 @@ static camera_config_t camera_config = {
|
|||||||
.pin_pwdn = CAM_PIN_PWDN,
|
.pin_pwdn = CAM_PIN_PWDN,
|
||||||
.pin_reset = CAM_PIN_RESET,
|
.pin_reset = CAM_PIN_RESET,
|
||||||
.pin_xclk = CAM_PIN_XCLK,
|
.pin_xclk = CAM_PIN_XCLK,
|
||||||
.pin_sscb_sda = CAM_PIN_SIOD,
|
.pin_sccb_sda = CAM_PIN_SIOD,
|
||||||
.pin_sscb_scl = CAM_PIN_SIOC,
|
.pin_sccb_scl = CAM_PIN_SIOC,
|
||||||
|
|
||||||
.pin_d7 = CAM_PIN_D7,
|
.pin_d7 = CAM_PIN_D7,
|
||||||
.pin_d6 = CAM_PIN_D6,
|
.pin_d6 = CAM_PIN_D6,
|
||||||
|
|||||||
@@ -1,5 +1,2 @@
|
|||||||
description: ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors.
|
description: ESP32 compatible driver for OV2640, OV3660, OV5640, OV7670 and OV7725 image sensors.
|
||||||
targets:
|
url: https://github.com/espressif/esp32-camera
|
||||||
- esp32
|
|
||||||
- esp32s2
|
|
||||||
- esp32s3
|
|
||||||
|
|||||||
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;
|
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;
|
int i = 0, ret = 0;
|
||||||
while (!ret && regs[i][0] != REGLIST_TAIL) {
|
while (!ret && (i < regs_size)) {
|
||||||
if (regs[i][0] == REG_DLY) {
|
if (regs[i][0] == REG_DLY) {
|
||||||
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
|
vTaskDelay(regs[i][1] / portTICK_PERIOD_MS);
|
||||||
} else {
|
} else {
|
||||||
@@ -132,11 +132,12 @@ static int reset(sensor_t *sensor)
|
|||||||
ESP_LOGE(TAG, "Software Reset FAILED!");
|
ESP_LOGE(TAG, "Software Reset FAILED!");
|
||||||
return ret;
|
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) {
|
if (ret == 0) {
|
||||||
ESP_LOGD(TAG, "Camera defaults loaded");
|
ESP_LOGD(TAG, "Camera defaults loaded");
|
||||||
vTaskDelay(100 / portTICK_PERIOD_MS);
|
vTaskDelay(80 / portTICK_PERIOD_MS);
|
||||||
write_reg(sensor->slv_addr, 0xfe, 0x00);
|
write_reg(sensor->slv_addr, 0xfe, 0x00);
|
||||||
#ifdef CONFIG_IDF_TARGET_ESP32
|
#ifdef CONFIG_IDF_TARGET_ESP32
|
||||||
set_reg_bits(sensor->slv_addr, 0x28, 4, 0x07, 1); //frequency division for esp32, ensure pclk <= 15MHz
|
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>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define REG_DLY 0xffff
|
#define REG_DLY 0xff
|
||||||
#define REGLIST_TAIL 0x0000 /* Array end token */
|
|
||||||
|
|
||||||
static const uint16_t gc0308_sensor_default_regs[][2] = {
|
static const uint8_t gc0308_sensor_default_regs[][2] = {
|
||||||
{0xfe, 0x00},
|
{0xfe, 0x00},
|
||||||
{0xec, 0x20},
|
{0xec, 0x20},
|
||||||
{0x05, 0x00},
|
{0x05, 0x00},
|
||||||
@@ -239,7 +238,21 @@ static const uint16_t gc0308_sensor_default_regs[][2] = {
|
|||||||
{0x65, 0xd3},
|
{0x65, 0xd3},
|
||||||
{0x66, 0x60},
|
{0x66, 0x60},
|
||||||
{0xfe, 0x00},
|
{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
|
#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
|
{ISP_CONTROL_01, 0x83}, // turn color matrix, awb and SDE
|
||||||
|
|
||||||
//sys reset
|
//sys reset
|
||||||
{0x3000, 0x00},
|
{0x3000, 0x20}, // reset MCU
|
||||||
|
{REG_DLY, 10}, // delay 10ms
|
||||||
{0x3002, 0x1c},
|
{0x3002, 0x1c},
|
||||||
|
|
||||||
//clock enable
|
//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 "xclk.h"
|
||||||
#include "cam_hal.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)
|
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||||
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
||||||
#define GPIO_PIN_INTR_NEGEDGE GPIO_INTR_NEGEDGE
|
#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
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "esp32 ll_cam";
|
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);
|
//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;
|
I2S0.conf.rx_start = 0;
|
||||||
I2S_ISR_DISABLE(in_suc_eof);
|
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_a = 0;
|
||||||
I2S0.clkm_conf.clkm_div_b = 0;
|
I2S0.clkm_conf.clkm_div_b = 0;
|
||||||
I2S0.clkm_conf.clkm_div_num = 2;
|
I2S0.clkm_conf.clkm_div_num = 2;
|
||||||
|
|
||||||
I2S0.fifo_conf.dscr_en = 1;
|
I2S0.fifo_conf.dscr_en = 1;
|
||||||
I2S0.fifo_conf.rx_fifo_mod = sampling_mode;
|
I2S0.fifo_conf.rx_fifo_mod = sampling_mode;
|
||||||
I2S0.fifo_conf.rx_fifo_mod_force_en = 1;
|
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
|
// Calculate DMA size
|
||||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
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",
|
ESP_LOGI(TAG, "node_size: %4u, nodes_per_line: %u, lines_per_node: %u, dma_half_buffer_min: %5u, dma_half_buffer: %5u,"
|
||||||
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);
|
"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_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||||
cam->dma_half_buffer_size = dma_half_buffer * 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 "xclk.h"
|
||||||
#include "cam_hal.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)
|
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||||
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
#define GPIO_PIN_INTR_POSEDGE GPIO_INTR_POSEDGE
|
||||||
#define GPIO_PIN_INTR_NEGEDGE GPIO_INTR_NEGEDGE
|
#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
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "s2 ll_cam";
|
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;
|
I2S0.conf.rx_start = 0;
|
||||||
|
|
||||||
@@ -119,7 +124,7 @@ bool ll_cam_start(cam_obj_t *cam, int frame_pos)
|
|||||||
} else {
|
} else {
|
||||||
I2S0.in_link.addr = ((uint32_t)&cam->frames[frame_pos].dma[0]) & 0xfffff;
|
I2S0.in_link.addr = ((uint32_t)&cam->frames[frame_pos].dma[0]) & 0xfffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
I2S0.in_link.start = 1;
|
I2S0.in_link.start = 1;
|
||||||
I2S0.conf.rx_start = 1;
|
I2S0.conf.rx_start = 1;
|
||||||
return true;
|
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",
|
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);
|
(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;
|
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_max = 2 * dma_half_buffer_max;
|
||||||
size_t dma_buffer_size = dma_buffer_max;
|
size_t dma_buffer_size = dma_buffer_max;
|
||||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
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",
|
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);
|
(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_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||||
cam->dma_half_buffer_size = dma_half_buffer * 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 "soc/gdma_reg.h"
|
||||||
#include "ll_cam.h"
|
#include "ll_cam.h"
|
||||||
#include "cam_hal.h"
|
#include "cam_hal.h"
|
||||||
|
#include "esp_rom_gpio.h"
|
||||||
|
|
||||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||||
#define gpio_matrix_in(a,b,c) gpio_iomux_in(a,b)
|
#include "soc/gpio_sig_map.h"
|
||||||
#define gpio_matrix_out(a,b,c,d) gpio_iomux_out(a,b,c)
|
#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
|
#endif
|
||||||
|
|
||||||
static const char *TAG = "s3 ll_cam";
|
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) {
|
if (cam->jpeg_mode || !cam->psram_mode) {
|
||||||
GDMA.channel[cam->dma_num].in.int_ena.in_suc_eof = 0;
|
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_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.peri_sel.sel = 5;
|
||||||
//GDMA.channel[cam->dma_num].in.pri.rx_pri = 1;//rx prio 0-15
|
//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;
|
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 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) {
|
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_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);
|
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.val = 0;
|
||||||
|
|
||||||
LCD_CAM.cam_ctrl.cam_clkm_div_b = 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_a = 0;
|
||||||
LCD_CAM.cam_ctrl.cam_clkm_div_num = 160000000 / config->xclk_freq_hz;
|
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;
|
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_ctrl.cam_update = 1;
|
||||||
LCD_CAM.cam_ctrl1.cam_start = 1;
|
LCD_CAM.cam_ctrl1.cam_start = 1;
|
||||||
|
|
||||||
esp_err_t err = ll_cam_dma_init(cam);
|
ret = ll_cam_dma_init(cam);
|
||||||
if(err != ESP_OK) {
|
|
||||||
return err;
|
return ret;
|
||||||
}
|
|
||||||
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ll_cam_vsync_intr_enable(cam_obj_t *cam, bool en)
|
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_set_pull_mode(data_pins[i], GPIO_FLOATING);
|
||||||
gpio_matrix_in(data_pins[i], CAM_DATA_IN0_IDX + i, false);
|
gpio_matrix_in(data_pins[i], CAM_DATA_IN0_IDX + i, false);
|
||||||
}
|
}
|
||||||
|
if (config->pin_xclk >= 0) {
|
||||||
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_xclk], PIN_FUNC_GPIO);
|
PIN_FUNC_SELECT(GPIO_PIN_MUX_REG[config->pin_xclk], PIN_FUNC_GPIO);
|
||||||
gpio_set_direction(config->pin_xclk, GPIO_MODE_OUTPUT);
|
gpio_set_direction(config->pin_xclk, GPIO_MODE_OUTPUT);
|
||||||
gpio_set_pull_mode(config->pin_xclk, GPIO_FLOATING);
|
gpio_set_pull_mode(config->pin_xclk, GPIO_FLOATING);
|
||||||
gpio_matrix_out(config->pin_xclk, CAM_CLK_IDX, false, false);
|
gpio_matrix_out(config->pin_xclk, CAM_CLK_IDX, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
return ESP_OK;
|
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",
|
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);
|
(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;
|
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) {
|
if (!cam->psram_mode) {
|
||||||
dma_buffer_size =(dma_buffer_max / dma_half_buffer) * dma_half_buffer;
|
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",
|
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);
|
(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_buffer_size = dma_buffer_size * cam->dma_bytes_per_item;
|
||||||
cam->dma_half_buffer_size = dma_half_buffer * 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)
|
bool ll_cam_dma_sizes(cam_obj_t *cam)
|
||||||
{
|
{
|
||||||
cam->dma_bytes_per_item = 1;
|
cam->dma_bytes_per_item = 1;
|
||||||
if (cam->jpeg_mode) {
|
if (cam->jpeg_mode) {
|
||||||
if (cam->psram_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
|
cam->fb_bytes_per_pixel = 1; // frame buffer stores Y8
|
||||||
} else if (pix_format == PIXFORMAT_YUV422 || pix_format == PIXFORMAT_RGB565) {
|
} 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
|
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) {
|
} else if (pix_format == PIXFORMAT_JPEG) {
|
||||||
cam->in_bytes_per_pixel = 1;
|
cam->in_bytes_per_pixel = 1;
|
||||||
cam->fb_bytes_per_pixel = 1;
|
cam->fb_bytes_per_pixel = 1;
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ typedef struct {
|
|||||||
QueueHandle_t frame_buffer_queue;
|
QueueHandle_t frame_buffer_queue;
|
||||||
TaskHandle_t task_handle;
|
TaskHandle_t task_handle;
|
||||||
intr_handle_t cam_intr_handle;
|
intr_handle_t cam_intr_handle;
|
||||||
|
|
||||||
uint8_t dma_num;//ESP32-S3
|
uint8_t dma_num;//ESP32-S3
|
||||||
intr_handle_t dma_intr_handle;//ESP32-S3
|
intr_handle_t dma_intr_handle;//ESP32-S3
|
||||||
|
|
||||||
@@ -116,8 +116,14 @@ typedef struct {
|
|||||||
//for RGB/YUV modes
|
//for RGB/YUV modes
|
||||||
uint16_t width;
|
uint16_t width;
|
||||||
uint16_t height;
|
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 in_bytes_per_pixel;
|
||||||
uint8_t fb_bytes_per_pixel;
|
uint8_t fb_bytes_per_pixel;
|
||||||
|
#endif
|
||||||
uint32_t fb_size;
|
uint32_t fb_size;
|
||||||
|
|
||||||
cam_state_t state;
|
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);
|
void ll_cam_do_vsync(cam_obj_t *cam);
|
||||||
uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
|
uint8_t ll_cam_get_dma_align(cam_obj_t *cam);
|
||||||
bool ll_cam_dma_sizes(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);
|
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
|
// implemented in cam_hal
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "unity.h"
|
#include "unity.h"
|
||||||
#include <mbedtls/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
#include "esp_log.h"
|
#include "esp_log.h"
|
||||||
|
#include "driver/i2c.h"
|
||||||
|
|
||||||
#include "esp_camera.h"
|
#include "esp_camera.h"
|
||||||
|
|
||||||
@@ -105,11 +106,16 @@
|
|||||||
|
|
||||||
#endif
|
#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";
|
static const char *TAG = "test camera";
|
||||||
|
|
||||||
typedef void (*decode_func_t)(uint8_t *jpegbuffer, uint32_t size, uint8_t *outbuffer);
|
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;
|
framesize_t size_bak = frame_size;
|
||||||
if (PIXFORMAT_JPEG == pixel_format && FRAMESIZE_SVGA > 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_pwdn = PWDN_GPIO_NUM,
|
||||||
.pin_reset = RESET_GPIO_NUM,
|
.pin_reset = RESET_GPIO_NUM,
|
||||||
.pin_xclk = XCLK_GPIO_NUM,
|
.pin_xclk = XCLK_GPIO_NUM,
|
||||||
.pin_sscb_sda = SIOD_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_sscb_scl = SIOC_GPIO_NUM,
|
.pin_sccb_scl = SIOC_GPIO_NUM,
|
||||||
|
.sccb_i2c_port = sccb_port,
|
||||||
|
|
||||||
.pin_d7 = Y9_GPIO_NUM,
|
.pin_d7 = Y9_GPIO_NUM,
|
||||||
.pin_d6 = Y8_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;
|
esp_err_t ret = ESP_OK;
|
||||||
//detect sensor information
|
//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();
|
sensor_t *s = esp_camera_sensor_get();
|
||||||
camera_sensor_info_t *info = esp_camera_sensor_get_info(&s->id);
|
camera_sensor_info_t *info = esp_camera_sensor_get_info(&s->id);
|
||||||
TEST_ASSERT_NOT_NULL(info);
|
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 (; format_s <= format_e; format_s++) {
|
||||||
for (size_t i = 0; i <= max_size; i++) {
|
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);
|
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);
|
vTaskDelay(100 / portTICK_RATE_MS);
|
||||||
if (ESP_OK != ret) {
|
if (ESP_OK != ret) {
|
||||||
ESP_LOGW(TAG, "Testing init failed :-(, skip this item");
|
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]")
|
TEST_CASE("Camera driver init, deinit test", "[camera]")
|
||||||
{
|
{
|
||||||
uint64_t t1 = esp_timer_get_time();
|
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();
|
uint64_t t2 = esp_timer_get_time();
|
||||||
ESP_LOGI(TAG, "Camera init time %llu ms", (t2 - t1) / 1000);
|
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_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);
|
vTaskDelay(500 / portTICK_RATE_MS);
|
||||||
ESP_LOGI(TAG, "Taking picture...");
|
ESP_LOGI(TAG, "Taking picture...");
|
||||||
camera_fb_t *pic = esp_camera_fb_get();
|
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_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);
|
vTaskDelay(500 / portTICK_RATE_MS);
|
||||||
ESP_LOGI(TAG, "Taking picture...");
|
ESP_LOGI(TAG, "Taking picture...");
|
||||||
camera_fb_t *pic = esp_camera_fb_get();
|
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_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);
|
vTaskDelay(500 / portTICK_RATE_MS);
|
||||||
ESP_LOGI(TAG, "Taking picture...");
|
ESP_LOGI(TAG, "Taking picture...");
|
||||||
camera_fb_t *pic = esp_camera_fb_get();
|
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);
|
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]")
|
TEST_CASE("Conversions image 227x149 jpeg decode test", "[camera]")
|
||||||
{
|
{
|
||||||
img_jpeg_decode_test(0, 0);
|
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);
|
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));
|
||||||
|
}
|
||||||
|
|||||||
BIN
code/components/esp32-camera-master_20220924.zip
Normal file
BIN
code/components/esp32-camera-master_20220924.zip
Normal file
Binary file not shown.
@@ -51,18 +51,28 @@ set(lib_srcs
|
|||||||
"${tflite_dir}/kernels/internal/quantization_util.cc"
|
"${tflite_dir}/kernels/internal/quantization_util.cc"
|
||||||
"${tflite_dir}/schema/schema_utils.cc")
|
"${tflite_dir}/schema/schema_utils.cc")
|
||||||
|
|
||||||
|
set(priv_req esp-nn)
|
||||||
|
|
||||||
|
# include component requirements which were introduced after IDF version 4.1
|
||||||
|
if("${IDF_VERSION_MAJOR}.${IDF_VERSION_MINOR}" VERSION_GREATER "4.1")
|
||||||
|
list(APPEND priv_req esp_timer driver)
|
||||||
|
endif()
|
||||||
|
|
||||||
idf_component_register(
|
idf_component_register(
|
||||||
SRCS "${lib_srcs}"
|
SRCS "${lib_srcs}"
|
||||||
INCLUDE_DIRS "." "third_party/gemmlowp"
|
INCLUDE_DIRS "." "third_party/gemmlowp"
|
||||||
"third_party/flatbuffers/include"
|
"third_party/flatbuffers/include"
|
||||||
"third_party/ruy"
|
"third_party/ruy"
|
||||||
"third_party/kissfft"
|
"third_party/kissfft"
|
||||||
REQUIRES "esp-nn")
|
REQUIRES ${pub_req}
|
||||||
|
PRIV_REQUIRES ${priv_req})
|
||||||
|
|
||||||
# Reduce the level of paranoia to be able to compile TF sources
|
# Reduce the level of paranoia to be able to compile TF sources
|
||||||
target_compile_options(${COMPONENT_LIB} PRIVATE
|
target_compile_options(${COMPONENT_LIB} PRIVATE
|
||||||
-Wno-maybe-uninitialized
|
-Wno-maybe-uninitialized
|
||||||
-Wno-missing-field-initializers
|
-Wno-missing-field-initializers
|
||||||
|
-Wno-error=sign-compare
|
||||||
|
-Wno-error=double-promotion
|
||||||
-DESP_NN # enables ESP-NN optimizations by Espressif
|
-DESP_NN # enables ESP-NN optimizations by Espressif
|
||||||
-Wno-type-limits)
|
-Wno-type-limits)
|
||||||
|
|
||||||
|
|||||||
@@ -185,6 +185,7 @@ typedef enum {
|
|||||||
kTfLiteBuiltinUnsortedSegmentSum = 155,
|
kTfLiteBuiltinUnsortedSegmentSum = 155,
|
||||||
kTfLiteBuiltinAtan2 = 156,
|
kTfLiteBuiltinAtan2 = 156,
|
||||||
kTfLiteBuiltinUnsortedSegmentMin = 157,
|
kTfLiteBuiltinUnsortedSegmentMin = 157,
|
||||||
|
kTfLiteBuiltinSign = 158,
|
||||||
} TfLiteBuiltinOperator;
|
} TfLiteBuiltinOperator;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -283,4 +283,25 @@ const char* TfLiteTypeGetName(TfLiteType type) {
|
|||||||
|
|
||||||
TfLiteDelegate TfLiteDelegateCreate() { return TfLiteDelegate{}; }
|
TfLiteDelegate TfLiteDelegateCreate() { return TfLiteDelegate{}; }
|
||||||
|
|
||||||
|
struct TfLiteOpaqueDelegateStruct* TfLiteOpaqueDelegateCreate(
|
||||||
|
const TfLiteOpaqueDelegateBuilder* opaque_delegate_builder) {
|
||||||
|
if (!opaque_delegate_builder) return nullptr;
|
||||||
|
|
||||||
|
TfLiteDelegate* result = new TfLiteDelegate{};
|
||||||
|
result->opaque_delegate_builder = new TfLiteOpaqueDelegateBuilder{};
|
||||||
|
*(result->opaque_delegate_builder) = *opaque_delegate_builder;
|
||||||
|
|
||||||
|
return reinterpret_cast<struct TfLiteOpaqueDelegateStruct*>(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TfLiteOpaqueDelegateDelete(
|
||||||
|
const struct TfLiteOpaqueDelegateStruct* opaque_delegate) {
|
||||||
|
if (!opaque_delegate) return;
|
||||||
|
|
||||||
|
const TfLiteDelegate* tflite_delegate =
|
||||||
|
reinterpret_cast<const TfLiteDelegate*>(opaque_delegate);
|
||||||
|
delete tflite_delegate->opaque_delegate_builder;
|
||||||
|
delete tflite_delegate;
|
||||||
|
}
|
||||||
|
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
|
|||||||
@@ -63,6 +63,8 @@ typedef enum TfLiteExternalContextType {
|
|||||||
struct TfLiteContext;
|
struct TfLiteContext;
|
||||||
struct TfLiteDelegate;
|
struct TfLiteDelegate;
|
||||||
struct TfLiteRegistration;
|
struct TfLiteRegistration;
|
||||||
|
struct TfLiteOpaqueDelegateStruct;
|
||||||
|
struct TfLiteOpaqueDelegateBuilder;
|
||||||
|
|
||||||
// An external context is a collection of information unrelated to the TF Lite
|
// An external context is a collection of information unrelated to the TF Lite
|
||||||
// framework, but useful to a subset of the ops. TF Lite knows very little
|
// framework, but useful to a subset of the ops. TF Lite knows very little
|
||||||
@@ -973,7 +975,7 @@ typedef enum TfLiteDelegateFlags {
|
|||||||
typedef struct TfLiteDelegate {
|
typedef struct TfLiteDelegate {
|
||||||
// Data that delegate needs to identify itself. This data is owned by the
|
// Data that delegate needs to identify itself. This data is owned by the
|
||||||
// delegate. The delegate is owned in the user code, so the delegate is
|
// delegate. The delegate is owned in the user code, so the delegate is
|
||||||
// responsible for doing this when it is destroyed.
|
// responsible for deallocating this when it is destroyed.
|
||||||
void* data_;
|
void* data_;
|
||||||
|
|
||||||
// Invoked by ModifyGraphWithDelegate. This prepare is called, giving the
|
// Invoked by ModifyGraphWithDelegate. This prepare is called, giving the
|
||||||
@@ -1010,12 +1012,83 @@ typedef struct TfLiteDelegate {
|
|||||||
|
|
||||||
// Bitmask flags. See the comments in `TfLiteDelegateFlags`.
|
// Bitmask flags. See the comments in `TfLiteDelegateFlags`.
|
||||||
int64_t flags;
|
int64_t flags;
|
||||||
|
|
||||||
|
// The opaque delegate builder associated with this object. If set then the
|
||||||
|
// TF Lite runtime will give precedence to this field. E.g. instead of
|
||||||
|
// invoking 'Prepare' via the function pointer inside the 'TfLiteDelegate'
|
||||||
|
// object, the runtime will first check if the corresponding function
|
||||||
|
// pointer inside 'opaque_delegate_builder' is set and if so invoke that.
|
||||||
|
//
|
||||||
|
// If this field is non-null, then the 'Prepare' field (of the
|
||||||
|
// 'TfLiteDelegate') should be null.
|
||||||
|
struct TfLiteOpaqueDelegateBuilder* opaque_delegate_builder;
|
||||||
} TfLiteDelegate;
|
} TfLiteDelegate;
|
||||||
|
|
||||||
// Build a 'null' delegate, with all the fields properly set to their default
|
// Build a 'null' delegate, with all the fields properly set to their default
|
||||||
// values.
|
// values.
|
||||||
TfLiteDelegate TfLiteDelegateCreate(void);
|
TfLiteDelegate TfLiteDelegateCreate(void);
|
||||||
|
|
||||||
|
// `TfLiteOpaqueDelegateBuilder` is used for constructing
|
||||||
|
// `TfLiteOpaqueDelegateStruct`, see `TfLiteOpaqueDelegateCreate` below. Note:
|
||||||
|
// This struct is not ABI stable.
|
||||||
|
//
|
||||||
|
// For forward source compatibility `TfLiteOpaqueDelegateBuilder` objects should
|
||||||
|
// be brace-initialized, so that all fields (including any that might be added
|
||||||
|
// in the future) get zero-initialized. The purpose of each field is exactly
|
||||||
|
// the same as with `TfLiteDelegate`.
|
||||||
|
//
|
||||||
|
// WARNING: This is an experimental interface that is subject to change.
|
||||||
|
typedef struct TfLiteOpaqueDelegateBuilder {
|
||||||
|
// Data that delegate needs to identify itself. This data is owned by the
|
||||||
|
// delegate. The delegate is owned in the user code, so the delegate is
|
||||||
|
// responsible for deallocating this when it is destroyed.
|
||||||
|
void* data;
|
||||||
|
// Invoked by ModifyGraphWithDelegate. This prepare is called, giving the
|
||||||
|
// delegate a view of the current graph through TfLiteContext*. It typically
|
||||||
|
// will look at the nodes and call ReplaceNodeSubsetsWithDelegateKernels()
|
||||||
|
// to ask the TensorFlow lite runtime to create macro-nodes to represent
|
||||||
|
// delegated subgraphs of the original graph.
|
||||||
|
TfLiteStatus (*Prepare)(TfLiteOpaqueContext* context, // NOLINT
|
||||||
|
struct TfLiteOpaqueDelegateStruct* delegate,
|
||||||
|
void* data);
|
||||||
|
// Copies the data from delegate buffer handle into raw memory of the given
|
||||||
|
// 'tensor'. Note that the delegate is allowed to allocate the raw bytes as
|
||||||
|
// long as it follows the rules for kTfLiteDynamic tensors, in which case this
|
||||||
|
// cannot be null.
|
||||||
|
TfLiteStatus (*CopyFromBufferHandle)( // NOLINT
|
||||||
|
TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate,
|
||||||
|
void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor);
|
||||||
|
// Copies the data from raw memory of the given 'tensor' to delegate buffer
|
||||||
|
// handle. This can be null if the delegate doesn't use its own buffer.
|
||||||
|
TfLiteStatus (*CopyToBufferHandle)( // NOLINT
|
||||||
|
TfLiteOpaqueContext* context, struct TfLiteOpaqueDelegateStruct* delegate,
|
||||||
|
void* data, TfLiteBufferHandle buffer_handle, TfLiteOpaqueTensor* tensor);
|
||||||
|
// Frees the Delegate Buffer Handle. Note: This only frees the handle, but
|
||||||
|
// this doesn't release the underlying resource (e.g. textures). The
|
||||||
|
// resources are either owned by application layer or the delegate.
|
||||||
|
// This can be null if the delegate doesn't use its own buffer.
|
||||||
|
void (*FreeBufferHandle)(TfLiteOpaqueContext* context, // NOLINT
|
||||||
|
struct TfLiteOpaqueDelegateStruct* delegate,
|
||||||
|
void* data, TfLiteBufferHandle* handle);
|
||||||
|
// Bitmask flags. See the comments in `TfLiteDelegateFlags`.
|
||||||
|
int64_t flags;
|
||||||
|
} TfLiteOpaqueDelegateBuilder;
|
||||||
|
|
||||||
|
// Creates an opaque delegate and returns its address. The opaque delegate will
|
||||||
|
// behave according to the provided 'opaque_delegate_builder'. The lifetime of
|
||||||
|
// the fields within the 'opaque_delegate_builder' must outlive any interaction
|
||||||
|
// between the runtime and the returned 'TfLiteOpaqueDelegateStruct'. The
|
||||||
|
// returned address should be passed to 'TfLiteOpaqueDelegateDelete' for
|
||||||
|
// deletion. If 'opaque_delegate_builder' is a null pointer, then a null
|
||||||
|
// pointer will be returned.
|
||||||
|
struct TfLiteOpaqueDelegateStruct* TfLiteOpaqueDelegateCreate(
|
||||||
|
const TfLiteOpaqueDelegateBuilder* opaque_delegate_builder);
|
||||||
|
|
||||||
|
// Deletes the provided opaque 'delegate'. This function has no effect if the
|
||||||
|
// 'delegate' is a null pointer.
|
||||||
|
void TfLiteOpaqueDelegateDelete(
|
||||||
|
const struct TfLiteOpaqueDelegateStruct* delegate);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} // extern "C"
|
} // extern "C"
|
||||||
#endif // __cplusplus
|
#endif // __cplusplus
|
||||||
|
|||||||
@@ -12,8 +12,9 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
// This provides a few C++ helpers that are useful for manipulating C structures
|
/// \file
|
||||||
// in C++.
|
/// This provides a few C++ helpers that are useful for manipulating C
|
||||||
|
/// structures in C++.
|
||||||
#ifndef TENSORFLOW_LITE_CONTEXT_UTIL_H_
|
#ifndef TENSORFLOW_LITE_CONTEXT_UTIL_H_
|
||||||
#define TENSORFLOW_LITE_CONTEXT_UTIL_H_
|
#define TENSORFLOW_LITE_CONTEXT_UTIL_H_
|
||||||
|
|
||||||
@@ -23,13 +24,14 @@ limitations under the License.
|
|||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
|
|
||||||
// Provide a range iterable wrapper for TfLiteIntArray* (C lists that TfLite
|
/// Provides a range iterable wrapper for TfLiteIntArray* (C lists) that TfLite
|
||||||
// C api uses. Can't use the google array_view, since we can't depend on even
|
/// C api uses.
|
||||||
|
// Can't use the google array_view, since we can't depend on even
|
||||||
// absl for embedded device reasons.
|
// absl for embedded device reasons.
|
||||||
class TfLiteIntArrayView {
|
class TfLiteIntArrayView {
|
||||||
public:
|
public:
|
||||||
// Construct a view of a TfLiteIntArray*. Note, `int_array` should be non-null
|
/// Construct a view of a TfLiteIntArray*. Note, `int_array` should be
|
||||||
// and this view does not take ownership of it.
|
/// non-null and this view does not take ownership of it.
|
||||||
explicit TfLiteIntArrayView(const TfLiteIntArray* int_array)
|
explicit TfLiteIntArrayView(const TfLiteIntArray* int_array)
|
||||||
: int_array_(int_array) {}
|
: int_array_(int_array) {}
|
||||||
|
|
||||||
|
|||||||
@@ -457,6 +457,10 @@ TfLiteStatus ParseOpDataTfLite(const Operator* op, BuiltinOperator op_type,
|
|||||||
return ParseRsqrt(op, error_reporter, allocator, builtin_data);
|
return ParseRsqrt(op, error_reporter, allocator, builtin_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case BuiltinOperator_SELECT_V2: {
|
||||||
|
return ParseSelectV2(op, error_reporter, allocator, builtin_data);
|
||||||
|
}
|
||||||
|
|
||||||
case BuiltinOperator_SHAPE: {
|
case BuiltinOperator_SHAPE: {
|
||||||
return ParseShape(op, error_reporter, allocator, builtin_data);
|
return ParseShape(op, error_reporter, allocator, builtin_data);
|
||||||
}
|
}
|
||||||
@@ -865,7 +869,6 @@ TfLiteStatus ParseOpDataTfLite(const Operator* op, BuiltinOperator op_type,
|
|||||||
case BuiltinOperator_RELU_0_TO_1:
|
case BuiltinOperator_RELU_0_TO_1:
|
||||||
case BuiltinOperator_SCATTER_ND:
|
case BuiltinOperator_SCATTER_ND:
|
||||||
case BuiltinOperator_SELECT:
|
case BuiltinOperator_SELECT:
|
||||||
case BuiltinOperator_SELECT_V2:
|
|
||||||
case BuiltinOperator_SLICE:
|
case BuiltinOperator_SLICE:
|
||||||
case BuiltinOperator_TILE:
|
case BuiltinOperator_TILE:
|
||||||
case BuiltinOperator_TOPK_V2:
|
case BuiltinOperator_TOPK_V2:
|
||||||
@@ -881,6 +884,7 @@ TfLiteStatus ParseOpDataTfLite(const Operator* op, BuiltinOperator op_type,
|
|||||||
case BuiltinOperator_UNSORTED_SEGMENT_PROD:
|
case BuiltinOperator_UNSORTED_SEGMENT_PROD:
|
||||||
case BuiltinOperator_UNSORTED_SEGMENT_SUM:
|
case BuiltinOperator_UNSORTED_SEGMENT_SUM:
|
||||||
case BuiltinOperator_ATAN2:
|
case BuiltinOperator_ATAN2:
|
||||||
|
case BuiltinOperator_SIGN:
|
||||||
case BuiltinOperator_WHERE:
|
case BuiltinOperator_WHERE:
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
case BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES:
|
case BuiltinOperator_PLACEHOLDER_FOR_GREATER_OP_CODES:
|
||||||
@@ -1982,6 +1986,14 @@ TfLiteStatus ParseRsqrt(const Operator*, ErrorReporter*, BuiltinDataAllocator*,
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We have this parse function instead of directly returning kTfLiteOk from the
|
||||||
|
// switch-case in ParseOpData because this function is used as part of the
|
||||||
|
// selective registration for the OpResolver implementation in micro.
|
||||||
|
TfLiteStatus ParseSelectV2(const Operator*, ErrorReporter*,
|
||||||
|
BuiltinDataAllocator*, void**) {
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
|
|
||||||
TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter,
|
TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter,
|
||||||
BuiltinDataAllocator* allocator, void** builtin_data) {
|
BuiltinDataAllocator* allocator, void** builtin_data) {
|
||||||
SafeBuiltinDataAllocator safe_allocator(allocator);
|
SafeBuiltinDataAllocator safe_allocator(allocator);
|
||||||
|
|||||||
@@ -319,6 +319,10 @@ TfLiteStatus ParseRound(const Operator* op, ErrorReporter* error_reporter,
|
|||||||
TfLiteStatus ParseRsqrt(const Operator* op, ErrorReporter* error_reporter,
|
TfLiteStatus ParseRsqrt(const Operator* op, ErrorReporter* error_reporter,
|
||||||
BuiltinDataAllocator* allocator, void** builtin_data);
|
BuiltinDataAllocator* allocator, void** builtin_data);
|
||||||
|
|
||||||
|
TfLiteStatus ParseSelectV2(const Operator* op, ErrorReporter* error_reporter,
|
||||||
|
BuiltinDataAllocator* allocator,
|
||||||
|
void** builtin_data);
|
||||||
|
|
||||||
TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter,
|
TfLiteStatus ParseShape(const Operator* op, ErrorReporter* error_reporter,
|
||||||
BuiltinDataAllocator* allocator, void** builtin_data);
|
BuiltinDataAllocator* allocator, void** builtin_data);
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h"
|
#include "tensorflow/lite/experimental/microfrontend/lib/kiss_fft_common.h"
|
||||||
|
|
||||||
#define FIXED_POINT 16
|
#define FIXED_POINT 16
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
||||||
==============================================================================*/
|
==============================================================================*/
|
||||||
#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ACTIVATIONS_H_
|
#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_
|
||||||
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_ACTIVATIONS_H_
|
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
@@ -165,4 +165,4 @@ inline void HardSwish(const HardSwishParams& params,
|
|||||||
} // namespace reference_ops
|
} // namespace reference_ops
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|
||||||
#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_CONV_H_
|
#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_HARD_SWISH_H_
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ limitations under the License.
|
|||||||
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MUL_H_
|
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_MUL_H_
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <complex>
|
||||||
|
|
||||||
#include "tensorflow/lite/kernels/internal/common.h"
|
#include "tensorflow/lite/kernels/internal/common.h"
|
||||||
|
|
||||||
@@ -61,6 +62,20 @@ inline void Mul(const ArithmeticParams& params,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void Mul(const ArithmeticParams& params,
|
||||||
|
const RuntimeShape& input1_shape,
|
||||||
|
const std::complex<float>* input1_data,
|
||||||
|
const RuntimeShape& input2_shape,
|
||||||
|
const std::complex<float>* input2_data,
|
||||||
|
const RuntimeShape& output_shape,
|
||||||
|
std::complex<float>* output_data) {
|
||||||
|
const int flat_size =
|
||||||
|
MatchingExtendedShapeFlatSize(input1_shape, input2_shape, output_shape);
|
||||||
|
for (int i = 0; i < flat_size; ++i) {
|
||||||
|
output_data[i] = input1_data[i] * input2_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void Mul(const ArithmeticParams& params,
|
inline void Mul(const ArithmeticParams& params,
|
||||||
const RuntimeShape& input1_shape, const uint8_t* input1_data,
|
const RuntimeShape& input1_shape, const uint8_t* input1_data,
|
||||||
const RuntimeShape& input2_shape, const uint8_t* input2_data,
|
const RuntimeShape& input2_shape, const uint8_t* input2_data,
|
||||||
@@ -162,6 +177,37 @@ void BroadcastMul4DSlow(const ArithmeticParams& params,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void BroadcastMul4DSlow(const ArithmeticParams& params,
|
||||||
|
const RuntimeShape& unextended_input1_shape,
|
||||||
|
const std::complex<float>* input1_data,
|
||||||
|
const RuntimeShape& unextended_input2_shape,
|
||||||
|
const std::complex<float>* input2_data,
|
||||||
|
const RuntimeShape& unextended_output_shape,
|
||||||
|
std::complex<float>* output_data) {
|
||||||
|
TFLITE_DCHECK_LE(unextended_input1_shape.DimensionsCount(), 4);
|
||||||
|
TFLITE_DCHECK_LE(unextended_input2_shape.DimensionsCount(), 4);
|
||||||
|
TFLITE_DCHECK_LE(unextended_output_shape.DimensionsCount(), 4);
|
||||||
|
const RuntimeShape output_shape =
|
||||||
|
RuntimeShape::ExtendedShape(4, unextended_output_shape);
|
||||||
|
|
||||||
|
NdArrayDesc<4> desc1;
|
||||||
|
NdArrayDesc<4> desc2;
|
||||||
|
NdArrayDescsForElementwiseBroadcast(unextended_input1_shape,
|
||||||
|
unextended_input2_shape, &desc1, &desc2);
|
||||||
|
|
||||||
|
for (int b = 0; b < output_shape.Dims(0); ++b) {
|
||||||
|
for (int y = 0; y < output_shape.Dims(1); ++y) {
|
||||||
|
for (int x = 0; x < output_shape.Dims(2); ++x) {
|
||||||
|
for (int c = 0; c < output_shape.Dims(3); ++c) {
|
||||||
|
output_data[Offset(output_shape, b, y, x, c)] =
|
||||||
|
input1_data[SubscriptToIndex(desc1, b, y, x, c)] *
|
||||||
|
input2_data[SubscriptToIndex(desc2, b, y, x, c)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace reference_ops
|
} // namespace reference_ops
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
|
||||||
|
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.
|
||||||
|
==============================================================================*/
|
||||||
|
#ifndef TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_
|
||||||
|
#define TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "ruy/profiler/instrumentation.h" // from @ruy
|
||||||
|
#include "tensorflow/lite/kernels/internal/common.h"
|
||||||
|
#include "tensorflow/lite/kernels/internal/types.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
namespace reference_ops {
|
||||||
|
|
||||||
|
template <typename D, typename T>
|
||||||
|
void Select(const RuntimeShape& input_condition_shape,
|
||||||
|
const D* input_condition_data, const RuntimeShape& input_x_shape,
|
||||||
|
const T* input_x_data, const RuntimeShape& input_y_shape,
|
||||||
|
const T* input_y_data, const RuntimeShape& output_shape,
|
||||||
|
T* output_data) {
|
||||||
|
ruy::profiler::ScopeLabel label("Select");
|
||||||
|
int64_t flatsize;
|
||||||
|
// Allow select operator executions on mixed scalar tensors and one element
|
||||||
|
// tensors.
|
||||||
|
if (input_condition_shape.FlatSize() == 1 && input_x_shape.FlatSize() == 1 &&
|
||||||
|
input_y_shape.FlatSize() == 1 && output_shape.FlatSize() == 1) {
|
||||||
|
flatsize = 1;
|
||||||
|
} else {
|
||||||
|
flatsize = MatchingFlatSize(input_condition_shape, input_x_shape,
|
||||||
|
input_y_shape, output_shape);
|
||||||
|
}
|
||||||
|
for (int64_t i = 0; i < flatsize; ++i) {
|
||||||
|
output_data[i] =
|
||||||
|
input_condition_data[i] ? input_x_data[i] : input_y_data[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename D, typename T>
|
||||||
|
void RankOneSelect(const RuntimeShape& input_condition_shape,
|
||||||
|
const D* input_condition_data,
|
||||||
|
const RuntimeShape& input_x_shape, const T* input_x_data,
|
||||||
|
const RuntimeShape& input_y_shape, const T* input_y_data,
|
||||||
|
const RuntimeShape& output_shape, T* output_data) {
|
||||||
|
ruy::profiler::ScopeLabel label("Select/RankOneSelect");
|
||||||
|
const int64_t outer_size = input_condition_shape.FlatSize();
|
||||||
|
int64_t inner_size;
|
||||||
|
if (input_condition_shape.DimensionsCount() == 0) {
|
||||||
|
inner_size = MatchingFlatSize(input_x_shape, input_y_shape, output_shape);
|
||||||
|
} else {
|
||||||
|
TFLITE_DCHECK_EQ(
|
||||||
|
MatchingDim(input_x_shape, 0, input_y_shape, 0, output_shape, 0),
|
||||||
|
outer_size);
|
||||||
|
inner_size =
|
||||||
|
MatchingFlatSizeSkipDim(input_x_shape, 0, input_y_shape, output_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t offset = 0;
|
||||||
|
for (int64_t i = 0; i < outer_size; i++) {
|
||||||
|
const T* input_data = input_condition_data[i] ? input_x_data : input_y_data;
|
||||||
|
memcpy(output_data + offset, input_data + offset, inner_size * sizeof(T));
|
||||||
|
offset += inner_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename D, typename T>
|
||||||
|
void BroadcastSelect5DSlow(const RuntimeShape& input_condition_shape,
|
||||||
|
const D* input_condition_data,
|
||||||
|
const RuntimeShape& input_x_shape,
|
||||||
|
const T* input_x_data,
|
||||||
|
const RuntimeShape& input_y_shape,
|
||||||
|
const T* input_y_data,
|
||||||
|
const RuntimeShape& output_shape, T* output_data) {
|
||||||
|
ruy::profiler::ScopeLabel label("Select/BroadcastSelectSlow");
|
||||||
|
TFLITE_DCHECK_LE(input_condition_shape.DimensionsCount(), 5);
|
||||||
|
TFLITE_DCHECK_LE(input_x_shape.DimensionsCount(), 5);
|
||||||
|
TFLITE_DCHECK_LE(input_y_shape.DimensionsCount(), 5);
|
||||||
|
TFLITE_DCHECK_LE(output_shape.DimensionsCount(), 5);
|
||||||
|
|
||||||
|
NdArrayDesc<5> desc_condition;
|
||||||
|
NdArrayDesc<5> desc_x;
|
||||||
|
NdArrayDesc<5> desc_y;
|
||||||
|
NdArrayDesc<5> desc_output;
|
||||||
|
const RuntimeShape extended_output_shape =
|
||||||
|
RuntimeShape::ExtendedShape(5, output_shape);
|
||||||
|
CopyDimsToDesc(extended_output_shape, &desc_output);
|
||||||
|
NdArrayDescsForElementwiseBroadcast(input_condition_shape, input_x_shape,
|
||||||
|
input_y_shape, &desc_condition, &desc_x,
|
||||||
|
&desc_y);
|
||||||
|
|
||||||
|
// In Tensorflow, the dimensions are canonically named (batch_number, row,
|
||||||
|
// col, channel), with extents (batches, height, width, depth), with the
|
||||||
|
// trailing dimension changing most rapidly (channels has the smallest
|
||||||
|
// stride, typically 1 element).
|
||||||
|
//
|
||||||
|
// In generated C code, we store arrays with the dimensions reversed. The
|
||||||
|
// first dimension has smallest stride.
|
||||||
|
//
|
||||||
|
// We name our variables by their Tensorflow convention, but generate C code
|
||||||
|
// nesting loops such that the innermost loop has the smallest stride for
|
||||||
|
// the best cache behavior.
|
||||||
|
for (int n = 0; n < desc_output.extents[0]; ++n) {
|
||||||
|
int out_idx_n = desc_output.extents[1] * n;
|
||||||
|
int cond_idx_n = desc_condition.strides[0] * n;
|
||||||
|
int in_idx1_n = desc_x.strides[0] * n;
|
||||||
|
int in_idx2_n = desc_y.strides[0] * n;
|
||||||
|
for (int b = 0; b < desc_output.extents[1]; ++b) {
|
||||||
|
int out_idx_b = (out_idx_n + b) * desc_output.extents[2];
|
||||||
|
int cond_idx_b = cond_idx_n + desc_condition.strides[1] * b;
|
||||||
|
int in_idx1_b = in_idx1_n + desc_x.strides[1] * b;
|
||||||
|
int in_idx2_b = in_idx2_n + desc_y.strides[1] * b;
|
||||||
|
for (int y = 0; y < desc_output.extents[2]; ++y) {
|
||||||
|
int out_idx_y = (out_idx_b + y) * desc_output.extents[3];
|
||||||
|
int cond_idx_y = cond_idx_b + desc_condition.strides[2] * y;
|
||||||
|
int in_idx1_y = in_idx1_b + desc_x.strides[2] * y;
|
||||||
|
int in_idx2_y = in_idx2_b + desc_y.strides[2] * y;
|
||||||
|
for (int x = 0; x < desc_output.extents[3]; ++x) {
|
||||||
|
int out_idx = (out_idx_y + x) * desc_output.extents[4];
|
||||||
|
int cond_idx = cond_idx_y + desc_condition.strides[3] * x;
|
||||||
|
int in_idx1 = in_idx1_y + desc_x.strides[3] * x;
|
||||||
|
int in_idx2 = in_idx2_y + desc_y.strides[3] * x;
|
||||||
|
for (int c = 0; c < desc_output.extents[4]; ++c) {
|
||||||
|
output_data[out_idx] = input_condition_data[cond_idx]
|
||||||
|
? input_x_data[in_idx1]
|
||||||
|
: input_y_data[in_idx2];
|
||||||
|
out_idx++;
|
||||||
|
cond_idx += desc_condition.strides[4];
|
||||||
|
in_idx1 += desc_x.strides[4];
|
||||||
|
in_idx2 += desc_y.strides[4];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace reference_ops
|
||||||
|
} // namespace tflite
|
||||||
|
|
||||||
|
#endif // TENSORFLOW_LITE_KERNELS_INTERNAL_REFERENCE_SELECT_H_
|
||||||
@@ -92,6 +92,7 @@ AllOpsResolver::AllOpsResolver() {
|
|||||||
AddResizeNearestNeighbor();
|
AddResizeNearestNeighbor();
|
||||||
AddRound();
|
AddRound();
|
||||||
AddRsqrt();
|
AddRsqrt();
|
||||||
|
AddSelectV2();
|
||||||
AddShape();
|
AddShape();
|
||||||
AddSin();
|
AddSin();
|
||||||
AddSlice();
|
AddSlice();
|
||||||
@@ -102,6 +103,7 @@ AllOpsResolver::AllOpsResolver() {
|
|||||||
AddSplitV();
|
AddSplitV();
|
||||||
AddSqrt();
|
AddSqrt();
|
||||||
AddSquare();
|
AddSquare();
|
||||||
|
AddSquaredDifference();
|
||||||
AddSqueeze();
|
AddSqueeze();
|
||||||
AddStridedSlice();
|
AddStridedSlice();
|
||||||
AddSub();
|
AddSub();
|
||||||
@@ -110,6 +112,7 @@ AllOpsResolver::AllOpsResolver() {
|
|||||||
AddTanh();
|
AddTanh();
|
||||||
AddTranspose();
|
AddTranspose();
|
||||||
AddTransposeConv();
|
AddTransposeConv();
|
||||||
|
AddUnidirectionalSequenceLSTM();
|
||||||
AddUnpack();
|
AddUnpack();
|
||||||
AddVarHandle();
|
AddVarHandle();
|
||||||
AddWhile();
|
AddWhile();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
|
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -59,6 +59,19 @@ TfLiteStatus CalculateOpDataAdd(TfLiteContext* context, TfLiteAddParams* params,
|
|||||||
|
|
||||||
TfLiteStatus AddPrepare(TfLiteContext* context, TfLiteNode* node);
|
TfLiteStatus AddPrepare(TfLiteContext* context, TfLiteNode* node);
|
||||||
|
|
||||||
|
// Generic must define registration function.
|
||||||
|
TfLiteRegistration Register_ADD();
|
||||||
|
|
||||||
|
#if defined(CMSIS_NN)
|
||||||
|
TfLiteRegistration Register_ADD_INT8();
|
||||||
|
|
||||||
|
TfLiteRegistration Register_ADD_INT16();
|
||||||
|
#else
|
||||||
|
// Fallback registration
|
||||||
|
inline TfLiteRegistration Register_ADD_INT8() { return Register_ADD(); }
|
||||||
|
|
||||||
|
inline TfLiteRegistration Register_ADD_INT16() { return Register_ADD(); }
|
||||||
|
#endif
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|
||||||
#endif // TENSORFLOW_LITE_MICRO_KERNELS_ADD_H_
|
#endif // TENSORFLOW_LITE_MICRO_KERNELS_ADD_H_
|
||||||
|
|||||||
@@ -121,8 +121,8 @@ TfLiteStatus CalculateOpData(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
context, kTfLiteActNone, output, &data->output_activation_min,
|
context, kTfLiteActNone, output, &data->output_activation_min,
|
||||||
&data->output_activation_max));
|
&data->output_activation_max));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "ADD_N only supports FLOAT32 and INT8, got %s.",
|
MicroPrintf("ADD_N only supports FLOAT32 and INT8, got %s.",
|
||||||
TfLiteTypeGetName(output->type));
|
TfLiteTypeGetName(output->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,8 +198,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
} else if (output->type == kTfLiteInt8) {
|
} else if (output->type == kTfLiteInt8) {
|
||||||
EvalAddNQuantized<int8_t>(context, node, output);
|
EvalAddNQuantized<int8_t>(context, node, output);
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "ADD_N only supports FLOAT32 and INT8, got %s.",
|
MicroPrintf("ADD_N only supports FLOAT32 and INT8, got %s.",
|
||||||
TfLiteTypeGetName(output->type));
|
TfLiteTypeGetName(output->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -70,21 +70,20 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node, bool is_arg_max) {
|
|||||||
TF_LITE_ARG_MIN_MAX(int8_t, int32_t, int32_t);
|
TF_LITE_ARG_MIN_MAX(int8_t, int32_t, int32_t);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf(
|
||||||
"Only float32, uint8_t and int8_t are "
|
"Only float32, uint8_t and int8_t are "
|
||||||
"supported currently, got %s.",
|
"supported currently, got %s.",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Only int32_t are supported currently, got %s.",
|
||||||
"Only int32_t are supported currently, got %s.",
|
TfLiteTypeGetName(output->type));
|
||||||
TfLiteTypeGetName(output->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Only int32_t are supported currently, got %s.",
|
MicroPrintf("Only int32_t are supported currently, got %s.",
|
||||||
TfLiteTypeGetName(axis->type));
|
TfLiteTypeGetName(axis->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorData<int8_t>(output));
|
tflite::micro::GetTensorData<int8_t>(output));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ TfLiteStatus CircularBufferEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
EvalInt8(tflite::micro::GetTensorData<int8_t>(input), num_slots, depth,
|
EvalInt8(tflite::micro::GetTensorData<int8_t>(input), num_slots, depth,
|
||||||
tflite::micro::GetTensorData<int8_t>(output));
|
tflite::micro::GetTensorData<int8_t>(output));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
TfLiteTypeGetName(input->type), input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ TfLiteStatus EqualEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -210,8 +210,8 @@ TfLiteStatus NotEqualEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -288,8 +288,8 @@ TfLiteStatus GreaterEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -366,8 +366,8 @@ TfLiteStatus GreaterEqualEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -444,8 +444,8 @@ TfLiteStatus LessEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -522,8 +522,8 @@ TfLiteStatus LessEqualEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output_data);
|
output_data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input1->type), input1->type);
|
TfLiteTypeGetName(input1->type), input1->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE(context,
|
TF_LITE_ENSURE(context,
|
||||||
input_type == kTfLiteFloat32 || input_type == kTfLiteInt8 ||
|
input_type == kTfLiteFloat32 || input_type == kTfLiteInt8 ||
|
||||||
input_type == kTfLiteInt16 || input_type == kTfLiteInt32 ||
|
input_type == kTfLiteInt16 || input_type == kTfLiteInt32 ||
|
||||||
input_type == kTfLiteInt64);
|
input_type == kTfLiteInt64 || input_type == kTfLiteBool);
|
||||||
|
|
||||||
// Output type must match input type
|
// Output type must match input type
|
||||||
TF_LITE_ENSURE_EQ(context, output_type, input_type);
|
TF_LITE_ENSURE_EQ(context, output_type, input_type);
|
||||||
@@ -149,8 +149,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
int num_dimensions = NumDimensions(input);
|
int num_dimensions = NumDimensions(input);
|
||||||
|
|
||||||
if (num_dimensions > RuntimeShape::kMaxSmallSize) {
|
if (num_dimensions > RuntimeShape::kMaxSmallSize) {
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf(
|
||||||
context,
|
|
||||||
"Op Concatenation does not currently support num dimensions > %d "
|
"Op Concatenation does not currently support num dimensions > %d "
|
||||||
"Tensor has %d dimensions.",
|
"Tensor has %d dimensions.",
|
||||||
RuntimeShape::kMaxSmallSize, num_dimensions);
|
RuntimeShape::kMaxSmallSize, num_dimensions);
|
||||||
@@ -168,6 +167,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE(context, output != nullptr);
|
TF_LITE_ENSURE(context, output != nullptr);
|
||||||
|
|
||||||
switch (output_type) { // Already know in/outtypes are same.
|
switch (output_type) { // Already know in/outtypes are same.
|
||||||
|
case kTfLiteBool:
|
||||||
case kTfLiteFloat32:
|
case kTfLiteFloat32:
|
||||||
case kTfLiteInt16:
|
case kTfLiteInt16:
|
||||||
case kTfLiteInt32:
|
case kTfLiteInt32:
|
||||||
@@ -205,9 +205,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Op Concatenation does not currently support Type '%s'.",
|
||||||
context, "Op Concatenation does not currently support Type '%s'.",
|
TfLiteTypeGetName(output_type));
|
||||||
TfLiteTypeGetName(output_type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,11 +237,13 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
case kTfLiteInt16:
|
case kTfLiteInt16:
|
||||||
EvalUnquantized<int16_t>(context, node);
|
EvalUnquantized<int16_t>(context, node);
|
||||||
break;
|
break;
|
||||||
|
case kTfLiteBool:
|
||||||
|
EvalUnquantized<bool>(context, node);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Op Concatenation does not currently support Type '%s'.",
|
||||||
context, "Op Concatenation does not currently support Type '%s'.",
|
TfLiteTypeGetName(output_type));
|
||||||
TfLiteTypeGetName(output_type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
if (axis < 0) axis += input_shape.DimensionsCount();
|
if (axis < 0) axis += input_shape.DimensionsCount();
|
||||||
|
|
||||||
if (axis < 0 || axis >= input_shape.DimensionsCount()) {
|
if (axis < 0 || axis >= input_shape.DimensionsCount()) {
|
||||||
TF_LITE_KERNEL_LOG(context, "CUMSUM Invalid axis: %d", axis);
|
MicroPrintf("CUMSUM Invalid axis: %d", axis);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,9 +156,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("CUMSUM only supports FLOAT32 and INT8, got %s.",
|
||||||
"CUMSUM only supports FLOAT32 and INT8, got %s.",
|
TfLiteTypeGetName(output->type));
|
||||||
TfLiteTypeGetName(output->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,9 +124,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorData<int8_t>(output));
|
tflite::micro::GetTensorData<int8_t>(output));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("DEPTH_TO_SPACE only supports FLOAT32 and INT8, got %s.",
|
||||||
context, "DEPTH_TO_SPACE only supports FLOAT32 and INT8, got %s.",
|
TfLiteTypeGetName(output->type));
|
||||||
TfLiteTypeGetName(output->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,8 +82,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -162,8 +162,7 @@ TfLiteStatus EvalQuantized(TfLiteContext* context, TfLiteNode* node,
|
|||||||
}
|
}
|
||||||
#undef TF_LITE_DIV
|
#undef TF_LITE_DIV
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Unsupported combination of input and output types in DIV.");
|
||||||
context, "Unsupported combination of input and output types in DIV.");
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,10 +188,10 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE_OK(context, EvalQuantized(context, node, params, data,
|
TF_LITE_ENSURE_OK(context, EvalQuantized(context, node, params, data,
|
||||||
input1, input2, output));
|
input1, input2, output));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf(
|
||||||
"DIV only supports FLOAT32, quantized INT8 "
|
"DIV only supports FLOAT32, quantized INT8 "
|
||||||
"now, got type %s (%d).",
|
"now, got type %s (%d).",
|
||||||
TfLiteTypeGetName(output->type), output->type);
|
TfLiteTypeGetName(output->type), output->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ TfLiteStatus GenericPrepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE(context, output != nullptr);
|
TF_LITE_ENSURE(context, output != nullptr);
|
||||||
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
||||||
if (!IsSupportedType(input->type)) {
|
if (!IsSupportedType(input->type)) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Input data type %s (%d) is not supported.",
|
MicroPrintf("Input data type %s (%d) is not supported.",
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
TfLiteTypeGetName(input->type), input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -112,8 +112,8 @@ TfLiteStatus PrepareAbsRsqrt(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE(context, output != nullptr);
|
TF_LITE_ENSURE(context, output != nullptr);
|
||||||
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
TF_LITE_ENSURE_TYPES_EQ(context, input->type, output->type);
|
||||||
if (!IsSupportedType(input->type)) {
|
if (!IsSupportedType(input->type)) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Input data type %s (%d) is not supported.",
|
MicroPrintf("Input data type %s (%d) is not supported.",
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
TfLiteTypeGetName(input->type), input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -317,8 +317,8 @@ TfLiteStatus AbsEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
type);
|
type);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Current data type %s is not supported.",
|
MicroPrintf("Current data type %s is not supported.",
|
||||||
TfLiteTypeGetName(type));
|
TfLiteTypeGetName(type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -355,8 +355,8 @@ TfLiteStatus RsqrtEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
elementwise::validate_input_func, type);
|
elementwise::validate_input_func, type);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Current data type %s is not supported.",
|
MicroPrintf("Current data type %s is not supported.",
|
||||||
TfLiteTypeGetName(type));
|
TfLiteTypeGetName(type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -426,4 +426,4 @@ TfLiteRegistration Register_LOGICAL_NOT() {
|
|||||||
|
|
||||||
} // namespace micro
|
} // namespace micro
|
||||||
} // namespace ops
|
} // namespace ops
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/internal/types.h"
|
#include "tensorflow/lite/kernels/internal/types.h"
|
||||||
#include "tensorflow/lite/kernels/kernel_util.h"
|
#include "tensorflow/lite/kernels/kernel_util.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -136,9 +135,8 @@ TfLiteStatus EluEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("ELU only supports float32 and int8 currently, got %s.",
|
||||||
context, "ELU only supports float32 and int8 currently, got %s.",
|
TfLiteTypeGetName(input->type));
|
||||||
TfLiteTypeGetName(input->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,6 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/padding.h"
|
#include "tensorflow/lite/kernels/padding.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
|
|
||||||
#if ESP_NN
|
#if ESP_NN
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/padding.h"
|
#include "tensorflow/lite/kernels/padding.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
|
|
||||||
#if ESP_NN
|
#if ESP_NN
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/op_macros.h"
|
#include "tensorflow/lite/kernels/op_macros.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
|
|
||||||
#include "freertos/FreeRTOS.h"
|
|
||||||
#include <esp_timer.h>
|
#include <esp_timer.h>
|
||||||
|
|
||||||
#if ESP_NN
|
#if ESP_NN
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
||||||
#include "tensorflow/lite/kernels/kernel_util.h"
|
#include "tensorflow/lite/kernels/kernel_util.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
|
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
namespace {
|
namespace {
|
||||||
@@ -63,8 +64,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
static_cast<size_t>(flat_size),
|
static_cast<size_t>(flat_size),
|
||||||
tflite::micro::GetTensorData<float>(output));
|
tflite::micro::GetTensorData<float>(output));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) currently not supported by Exp.",
|
MicroPrintf("Type %s (%d) currently not supported by Exp.",
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
TfLiteTypeGetName(input->type), input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -31,8 +31,7 @@ TfLiteStatus GetAxisValueFromTensor(TfLiteContext* context,
|
|||||||
int32_t* axis_value) {
|
int32_t* axis_value) {
|
||||||
const int axis_dims = (tflite::GetTensorShape(axis)).DimensionsCount();
|
const int axis_dims = (tflite::GetTensorShape(axis)).DimensionsCount();
|
||||||
if (axis_dims > 1) {
|
if (axis_dims > 1) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Axis has only one element for Expand_Dims.",
|
MicroPrintf("Axis has only one element for Expand_Dims.", axis_dims);
|
||||||
axis_dims);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,9 +40,8 @@ TfLiteStatus GetAxisValueFromTensor(TfLiteContext* context,
|
|||||||
*axis_value = axis_ptr[0];
|
*axis_value = axis_ptr[0];
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Axis type %s (%d) not supported by Expand_Dims.",
|
||||||
"Axis type %s (%d) not supported by Expand_Dims.",
|
TfLiteTypeGetName(axis->type), axis->type);
|
||||||
TfLiteTypeGetName(axis->type), axis->type);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -99,8 +97,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TF_LITE_ENSURE(context, output != nullptr);
|
TF_LITE_ENSURE(context, output != nullptr);
|
||||||
output->type = input->type;
|
output->type = input->type;
|
||||||
if (IsDynamicTensor(axis)) {
|
if (IsDynamicTensor(axis)) {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("DynamicTensor is not yet supported by Expand_Dims.");
|
||||||
"DynamicTensor is not yet supported by Expand_Dims.");
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
TF_LITE_ENSURE_OK(context, VerifyTensorDim(context, input, axis, output));
|
TF_LITE_ENSURE_OK(context, VerifyTensorDim(context, input, axis, output));
|
||||||
@@ -135,8 +132,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorData<int8_t>(input), flat_size);
|
tflite::micro::GetTensorData<int8_t>(input), flat_size);
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf(
|
||||||
context,
|
|
||||||
"Expand_Dims only currently supports int8 and float32, got %d.",
|
"Expand_Dims only currently supports int8 and float32, got %d.",
|
||||||
input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
|
|||||||
@@ -53,9 +53,8 @@ TfLiteStatus EnsureEq(TfLiteContext* context, const TfLiteIntArray* array,
|
|||||||
case kTfLiteInt64:
|
case kTfLiteInt64:
|
||||||
return EnsureEqImpl<int64_t>(context, array, tensor);
|
return EnsureEqImpl<int64_t>(context, array, tensor);
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("cannot compare int array to tensor of type %d.",
|
||||||
"cannot compare int array to tensor of type %d.",
|
tensor->type);
|
||||||
tensor->type);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -123,9 +122,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
FillImpl<int8_t>(value, output);
|
FillImpl<int8_t>(value, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Fill only currently supports float32 for input 1, got %d.",
|
||||||
context, "Fill only currently supports float32 for input 1, got %d.",
|
TfLiteTypeGetName(value->type));
|
||||||
TfLiteTypeGetName(value->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ TfLiteStatus EvalFloorDiv(TfLiteContext* context,
|
|||||||
// Validate the denominator.
|
// Validate the denominator.
|
||||||
for (int i = 0; i < tflite::ElementCount(*input2->dims); ++i) {
|
for (int i = 0; i < tflite::ElementCount(*input2->dims); ++i) {
|
||||||
if (std::equal_to<T>()(denominator_data[i], 0)) {
|
if (std::equal_to<T>()(denominator_data[i], 0)) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Division by 0");
|
MicroPrintf("Division by 0");
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -113,8 +113,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return EvalFloorDiv<float>(context, input1, input2, output);
|
return EvalFloorDiv<float>(context, input1, input2, output);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type '%s' is not supported by FLOOR_DIV.",
|
MicroPrintf("Type '%s' is not supported by FLOOR_DIV.",
|
||||||
TfLiteTypeGetName(input1->type));
|
TfLiteTypeGetName(input1->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -111,8 +111,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output);
|
output);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type '%s' is not supported by FLOOR_MOD.",
|
MicroPrintf("Type '%s' is not supported by FLOOR_MOD.",
|
||||||
TfLiteTypeGetName(input1->type));
|
TfLiteTypeGetName(input1->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,8 +141,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -118,9 +118,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
case kTfLiteInt32:
|
case kTfLiteInt32:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Positions of type '%s' are not supported by gather.",
|
||||||
"Positions of type '%s' are not supported by gather.",
|
TfLiteTypeGetName(coords->type));
|
||||||
TfLiteTypeGetName(coords->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -134,8 +133,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
case kTfLiteInt8:
|
case kTfLiteInt8:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type '%s' is not supported by gather.",
|
MicroPrintf("Type '%s' is not supported by gather.",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -207,8 +206,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return Gather<int8_t, int32_t>(params, input, coords, output);
|
return Gather<int8_t, int32_t>(params, input, coords, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type '%s' is not supported by gather.",
|
MicroPrintf("Type '%s' is not supported by gather.",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,9 +47,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
case kTfLiteInt8:
|
case kTfLiteInt8:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Params of type '%s' are not supported by gather_nd.",
|
||||||
"Params of type '%s' are not supported by gather_nd.",
|
TfLiteTypeGetName(params->type));
|
||||||
TfLiteTypeGetName(params->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -57,9 +56,8 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
case kTfLiteInt32:
|
case kTfLiteInt32:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Indices of type '%s' are not supported by gather_nd.",
|
||||||
"Indices of type '%s' are not supported by gather_nd.",
|
TfLiteTypeGetName(indices->type));
|
||||||
TfLiteTypeGetName(indices->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -67,22 +65,20 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
const int indices_rank = NumDimensions(indices);
|
const int indices_rank = NumDimensions(indices);
|
||||||
const int indices_nd = SizeOfDimension(indices, indices_rank - 1);
|
const int indices_nd = SizeOfDimension(indices, indices_rank - 1);
|
||||||
if (params_rank < 1) {
|
if (params_rank < 1) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Params must be at least a vector.");
|
MicroPrintf("Params must be at least a vector.");
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
if (indices_rank < 1) {
|
if (indices_rank < 1) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Indices must be at least a vector.");
|
MicroPrintf("Indices must be at least a vector.");
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
if (indices_nd > params_rank) {
|
if (indices_nd > params_rank) {
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Index innermost dimension length must be <= params rank.");
|
||||||
context, "Index innermost dimension length must be <= params rank.");
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
if (indices_nd > MAX_INDICES_ND) {
|
if (indices_nd > MAX_INDICES_ND) {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Index innermost dimension length must not exceed %d.",
|
||||||
"Index innermost dimension length must not exceed %d.",
|
MAX_INDICES_ND);
|
||||||
MAX_INDICES_ND);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,13 +167,12 @@ TfLiteStatus EvalGatherNd(TfLiteContext* context,
|
|||||||
status = GatherNd<int8_t, IndicesT>(params, indices, output);
|
status = GatherNd<int8_t, IndicesT>(params, indices, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Params type '%s' are not supported by gather_nd.",
|
||||||
"Params type '%s' are not supported by gather_nd.",
|
TfLiteTypeGetName(params->type));
|
||||||
TfLiteTypeGetName(params->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
if (status != kTfLiteOk) {
|
if (status != kTfLiteOk) {
|
||||||
TF_LITE_KERNEL_LOG(context, "gather_nd index out of bounds");
|
MicroPrintf("gather_nd index out of bounds");
|
||||||
}
|
}
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@@ -195,9 +190,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return EvalGatherNd<int32_t>(context, params, indices, output);
|
return EvalGatherNd<int32_t>(context, params, indices, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Indices of type '%s' are not supported by gather_nd.",
|
||||||
"Indices of type '%s' are not supported by gather_nd.",
|
TfLiteTypeGetName(indices->type));
|
||||||
TfLiteTypeGetName(indices->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -106,5 +106,17 @@ TfLiteStatus KernelRunner::Invoke() {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TfLiteStatus KernelRunner::Free() {
|
||||||
|
tflite::micro::ClearBufferApi(&context_);
|
||||||
|
context_.GetScratchBuffer = MicroContextGetScratchBuffer;
|
||||||
|
|
||||||
|
if (registration_.free == nullptr) {
|
||||||
|
MicroPrintf("TfLiteRegistration missing free function pointer!");
|
||||||
|
return kTfLiteError;
|
||||||
|
}
|
||||||
|
|
||||||
|
registration_.free(&context_, node_.user_data);
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
} // namespace micro
|
} // namespace micro
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
@@ -48,6 +48,11 @@ class KernelRunner {
|
|||||||
// passed into the constructor of this class.
|
// passed into the constructor of this class.
|
||||||
TfLiteStatus Invoke();
|
TfLiteStatus Invoke();
|
||||||
|
|
||||||
|
// Calls Free on a given TfLiteRegistration pointer(if it's implemented).
|
||||||
|
// After successful Free, kTfLiteOk status will be returned. If Free is not
|
||||||
|
// implemented for a given kernel kTfLiteError will be returned.
|
||||||
|
TfLiteStatus Free();
|
||||||
|
|
||||||
// Returns a pointer to the internal MockMicroGraph which KernelRunner uses
|
// Returns a pointer to the internal MockMicroGraph which KernelRunner uses
|
||||||
// to stub out MicroGraph methods and track invocations on each subgraph.
|
// to stub out MicroGraph methods and track invocations on each subgraph.
|
||||||
MockMicroGraph* GetMockGraph() { return &mock_micro_graph_; }
|
MockMicroGraph* GetMockGraph() { return &mock_micro_graph_; }
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ limitations under the License.
|
|||||||
|
|
||||||
#include "tensorflow/lite/c/common.h"
|
#include "tensorflow/lite/c/common.h"
|
||||||
#include "tensorflow/lite/micro/memory_helpers.h"
|
#include "tensorflow/lite/micro/memory_helpers.h"
|
||||||
|
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
namespace micro {
|
namespace micro {
|
||||||
@@ -39,9 +40,10 @@ int ValidateTensorIndexing(const TfLiteContext* context, int index,
|
|||||||
TfLiteRegistration RegisterOp(
|
TfLiteRegistration RegisterOp(
|
||||||
void* (*init)(TfLiteContext* context, const char* buffer, size_t length),
|
void* (*init)(TfLiteContext* context, const char* buffer, size_t length),
|
||||||
TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node),
|
TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node),
|
||||||
TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node)) {
|
TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node),
|
||||||
|
void (*free)(TfLiteContext* context, void* buffer)) {
|
||||||
return {/*init=*/init,
|
return {/*init=*/init,
|
||||||
/*free=*/nullptr,
|
/*free=*/free,
|
||||||
/*prepare=*/prepare,
|
/*prepare=*/prepare,
|
||||||
/*invoke=*/invoke,
|
/*invoke=*/invoke,
|
||||||
/*profiling_string=*/nullptr,
|
/*profiling_string=*/nullptr,
|
||||||
@@ -160,6 +162,46 @@ TfLiteStatus CopyOpInputsToOpOutputs(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Args:
|
||||||
|
// 1. int8_t tensor_data - int8_t buffer of unknown size who's data you'd
|
||||||
|
// like
|
||||||
|
// to print
|
||||||
|
// 2. int n_btyes - a small int representing number of bytes you want to
|
||||||
|
// print
|
||||||
|
// to debug output. It should always be <= tensor_data's size.
|
||||||
|
// 3. prefix - optional message you'd like to print before printing bytes
|
||||||
|
//
|
||||||
|
// Purpose:
|
||||||
|
// Function takes in paramaters above and prints n_bytes bytes from the
|
||||||
|
// tensor_data buffer. This can be use to debug the output of a model and it's
|
||||||
|
// op.
|
||||||
|
|
||||||
|
void PrintNBytes(const int8_t* tensor_data, int n_bytes, const char* prefix) {
|
||||||
|
if (prefix != nullptr) {
|
||||||
|
MicroPrintf("%s", prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < n_bytes; ++i) {
|
||||||
|
MicroPrintf(" %x", tensor_data[i]);
|
||||||
|
}
|
||||||
|
MicroPrintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as the PrintNBytes above but the buffer needs to be extracted out of the
|
||||||
|
// TfLiteEvalTensor*
|
||||||
|
void PrintNBytes(const TfLiteEvalTensor* tensor, int n_bytes,
|
||||||
|
const char* prefix) {
|
||||||
|
const int8_t* tensor_data = tflite::micro::GetTensorData<int8_t>(tensor);
|
||||||
|
PrintNBytes(tensor_data, n_bytes, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// same as the PrintNBytes above but the buffer needs to be extracted out of the
|
||||||
|
// TfLiteEvalTensor*
|
||||||
|
void PrintNBytes(const TfLiteTensor* tensor, int n_bytes, const char* prefix) {
|
||||||
|
const int8_t* tensor_data = tflite::GetTensorData<int8_t>(tensor);
|
||||||
|
PrintNBytes(tensor_data, n_bytes, prefix);
|
||||||
|
}
|
||||||
|
|
||||||
TfLiteStatus CopyOpInputsToSubgraphInputs(TfLiteContext* context,
|
TfLiteStatus CopyOpInputsToSubgraphInputs(TfLiteContext* context,
|
||||||
TfLiteNode* node,
|
TfLiteNode* node,
|
||||||
MicroGraph* graph_info,
|
MicroGraph* graph_info,
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/c/builtin_op_data.h"
|
#include "tensorflow/lite/c/builtin_op_data.h"
|
||||||
#include "tensorflow/lite/c/common.h"
|
#include "tensorflow/lite/c/common.h"
|
||||||
#include "tensorflow/lite/kernels/internal/compatibility.h"
|
#include "tensorflow/lite/kernels/internal/compatibility.h"
|
||||||
|
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
||||||
#include "tensorflow/lite/kernels/internal/types.h"
|
#include "tensorflow/lite/kernels/internal/types.h"
|
||||||
#include "tensorflow/lite/micro/micro_context.h"
|
#include "tensorflow/lite/micro/micro_context.h"
|
||||||
|
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
namespace micro {
|
namespace micro {
|
||||||
@@ -30,7 +32,20 @@ namespace micro {
|
|||||||
TfLiteRegistration RegisterOp(
|
TfLiteRegistration RegisterOp(
|
||||||
void* (*init)(TfLiteContext* context, const char* buffer, size_t length),
|
void* (*init)(TfLiteContext* context, const char* buffer, size_t length),
|
||||||
TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node),
|
TfLiteStatus (*prepare)(TfLiteContext* context, TfLiteNode* node),
|
||||||
TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node));
|
TfLiteStatus (*invoke)(TfLiteContext* context, TfLiteNode* node),
|
||||||
|
void (*free)(TfLiteContext* context, void* buffer) = nullptr);
|
||||||
|
|
||||||
|
// Prints out n bytes in a int8_t buffer as hex
|
||||||
|
void PrintNBytes(const int8_t* tensor_data, int n_bytes,
|
||||||
|
const char* prefix = nullptr);
|
||||||
|
|
||||||
|
// Prints out the the n bytes in a TfLiteEvalTensor as hex
|
||||||
|
void PrintNBytes(const TfLiteEvalTensor* tensor, int n_bytes,
|
||||||
|
const char* prefix = nullptr);
|
||||||
|
|
||||||
|
// Prints out the the n bytes in a TfLiteTensor as hex
|
||||||
|
void PrintNBytes(const TfLiteTensor* tensor, int n_bytes,
|
||||||
|
const char* prefix = nullptr);
|
||||||
|
|
||||||
// Returns a mutable tensor for a given input index. is_variable must be checked
|
// Returns a mutable tensor for a given input index. is_variable must be checked
|
||||||
// during prepare when the full TfLiteTensor is available.
|
// during prepare when the full TfLiteTensor is available.
|
||||||
|
|||||||
@@ -125,9 +125,8 @@ TfLiteStatus L2Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
L2EvalFloat(*params, *input, &op_params, output);
|
L2EvalFloat(*params, *input, &op_params, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("L2_POOL_2D only supports float32 currently, got %s.",
|
||||||
"L2_POOL_2D only supports float32 currently, got %s.",
|
TfLiteTypeGetName(input->type));
|
||||||
TfLiteTypeGetName(input->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -126,8 +126,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorData<int8_t>(input),
|
tflite::micro::GetTensorData<int8_t>(input),
|
||||||
tflite::micro::GetTensorData<int8_t>(output));
|
tflite::micro::GetTensorData<int8_t>(output));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Output type is %s, requires float.",
|
MicroPrintf("Output type is %s, requires float.",
|
||||||
TfLiteTypeGetName(output->type));
|
TfLiteTypeGetName(output->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -132,9 +132,8 @@ TfLiteStatus LogSoftmaxEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("LOG_SOFTMAX only supports float32, int8, got %s.",
|
||||||
"LOG_SOFTMAX only supports float32, int8, got %s.",
|
TfLiteTypeGetName(input->type));
|
||||||
TfLiteTypeGetName(input->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/c/builtin_op_data.h"
|
#include "tensorflow/lite/c/builtin_op_data.h"
|
||||||
#include "tensorflow/lite/c/common.h"
|
#include "tensorflow/lite/c/common.h"
|
||||||
#include "tensorflow/lite/kernels/internal/compatibility.h"
|
#include "tensorflow/lite/kernels/internal/compatibility.h"
|
||||||
|
#include "tensorflow/lite/kernels/internal/reference/integer_ops/logistic.h"
|
||||||
|
#include "tensorflow/lite/kernels/internal/reference/integer_ops/tanh.h"
|
||||||
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
||||||
#include "tensorflow/lite/kernels/op_macros.h"
|
#include "tensorflow/lite/kernels/op_macros.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
@@ -530,11 +532,20 @@ void CalculateLstmGateInteger8x8_16(
|
|||||||
// Apply activation
|
// Apply activation
|
||||||
switch (activation) {
|
switch (activation) {
|
||||||
case kTfLiteActSigmoid:
|
case kTfLiteActSigmoid:
|
||||||
micro_tensor_utils::ApplySigmoid(gate, n_batch, n_cell, gate);
|
|
||||||
break;
|
reference_integer_ops::Logistic(
|
||||||
case kTfLiteActTanh:
|
0 /*data->input_multiplier*/, 0 /*data->input_left_shift */,
|
||||||
micro_tensor_utils::ApplyTanh(3, gate, n_batch, n_cell, gate);
|
n_batch * n_cell /*NumElements(input->dims)*/,
|
||||||
|
gate /* tflite::micro::GetTensorData<int16_t>(input) */,
|
||||||
|
gate /*tflite::micro::GetTensorData<int16_t>(output) */);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case kTfLiteActTanh: {
|
||||||
|
int32_t dims_data = n_batch * n_cell;
|
||||||
|
RuntimeShape tanh_inp_shape = RuntimeShape(1, &dims_data);
|
||||||
|
reference_integer_ops::Tanh(0, 0, tanh_inp_shape, gate, tanh_inp_shape,
|
||||||
|
gate);
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
// Only Sigmoid or Tanh is used.
|
// Only Sigmoid or Tanh is used.
|
||||||
TFLITE_ASSERT_FALSE;
|
TFLITE_ASSERT_FALSE;
|
||||||
@@ -599,7 +610,7 @@ void UpdateLstmCellInteger(int n_batch, int n_cell, int16_t* cell_state,
|
|||||||
// - scratch1: scratch area of size n_batch*n_cell
|
// - scratch1: scratch area of size n_batch*n_cell
|
||||||
// - scratch2: scratch area used by MatrixBatchVectorMultiplyAccumulate
|
// - scratch2: scratch area used by MatrixBatchVectorMultiplyAccumulate
|
||||||
void CalculateLstmOutputInteger8x8_16(
|
void CalculateLstmOutputInteger8x8_16(
|
||||||
int n_batch, int n_cell, int n_output, const int16_t* cell_state,
|
int n_batch, int n_cell, int n_output, int16_t* cell_state,
|
||||||
int32_t cell_state_scale, const int16_t* output_gate,
|
int32_t cell_state_scale, const int16_t* output_gate,
|
||||||
int32_t hidden_scale_a, int32_t hidden_scale_b, int32_t hidden_zp,
|
int32_t hidden_scale_a, int32_t hidden_scale_b, int32_t hidden_zp,
|
||||||
const int8_t* projection_weights, int32_t proj_scale_a,
|
const int8_t* projection_weights, int32_t proj_scale_a,
|
||||||
@@ -607,8 +618,23 @@ void CalculateLstmOutputInteger8x8_16(
|
|||||||
int32_t output_state_zp, int8_t quantized_proj_clip, int8_t* output_state,
|
int32_t output_state_zp, int8_t quantized_proj_clip, int8_t* output_state,
|
||||||
int16_t* scratch0, int8_t* scratch1, int32_t* scratch2) {
|
int16_t* scratch0, int8_t* scratch1, int32_t* scratch2) {
|
||||||
// Note: unlike float/hybrid, the activation is always Tanh.
|
// Note: unlike float/hybrid, the activation is always Tanh.
|
||||||
micro_tensor_utils::ApplyTanh(15 + cell_state_scale, cell_state, n_batch,
|
|
||||||
n_cell, scratch0);
|
{
|
||||||
|
int32_t tanh_input_left_shift = (15 + cell_state_scale) - 3;
|
||||||
|
int32_t dims_data = n_batch * n_cell;
|
||||||
|
if (tanh_input_left_shift < 0) /* handling negative shift value */
|
||||||
|
{
|
||||||
|
int32_t i;
|
||||||
|
tanh_input_left_shift = -tanh_input_left_shift;
|
||||||
|
for (i = 0; i < dims_data; i++) {
|
||||||
|
cell_state[i] = cell_state[i] >> tanh_input_left_shift;
|
||||||
|
}
|
||||||
|
tanh_input_left_shift = 0;
|
||||||
|
}
|
||||||
|
RuntimeShape tanh_inp_shape = RuntimeShape(1, &dims_data);
|
||||||
|
reference_integer_ops::Tanh(0, tanh_input_left_shift, tanh_inp_shape,
|
||||||
|
cell_state, tanh_inp_shape, scratch0);
|
||||||
|
}
|
||||||
micro_tensor_utils::CwiseMul(output_gate, scratch0, hidden_scale_a,
|
micro_tensor_utils::CwiseMul(output_gate, scratch0, hidden_scale_a,
|
||||||
hidden_scale_b, n_batch, n_cell, hidden_zp,
|
hidden_scale_b, n_batch, n_cell, hidden_zp,
|
||||||
scratch1);
|
scratch1);
|
||||||
|
|||||||
@@ -98,15 +98,13 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TFLiteOperation<int64_t, OpType>(context, node, op_context);
|
TFLiteOperation<int64_t, OpType>(context, node, op_context);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Type %s (%d) is not supported by Maximum/Minimum.",
|
||||||
"Type %s (%d) is not supported by Maximum/Minimum.",
|
TfLiteTypeGetName(op_context.output->type),
|
||||||
TfLiteTypeGetName(op_context.output->type),
|
op_context.output->type);
|
||||||
op_context.output->type);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context,
|
MicroPrintf("Kernel type not supported by Maximum/Minimum.");
|
||||||
"Kernel type not supported by Maximum/Minimum.");
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -72,6 +72,7 @@ TfLiteRegistration Register_READ_VARIABLE();
|
|||||||
TfLiteRegistration Register_RELU();
|
TfLiteRegistration Register_RELU();
|
||||||
TfLiteRegistration Register_RELU6();
|
TfLiteRegistration Register_RELU6();
|
||||||
TfLiteRegistration Register_RESIZE_BILINEAR();
|
TfLiteRegistration Register_RESIZE_BILINEAR();
|
||||||
|
TfLiteRegistration Register_SELECT_V2();
|
||||||
TfLiteRegistration Register_SHAPE();
|
TfLiteRegistration Register_SHAPE();
|
||||||
TfLiteRegistration Register_SLICE();
|
TfLiteRegistration Register_SLICE();
|
||||||
TfLiteRegistration Register_SPACE_TO_BATCH_ND();
|
TfLiteRegistration Register_SPACE_TO_BATCH_ND();
|
||||||
@@ -79,6 +80,7 @@ TfLiteRegistration Register_SPACE_TO_DEPTH();
|
|||||||
TfLiteRegistration Register_SQUARED_DIFFERENCE();
|
TfLiteRegistration Register_SQUARED_DIFFERENCE();
|
||||||
TfLiteRegistration Register_SQUEEZE();
|
TfLiteRegistration Register_SQUEEZE();
|
||||||
TfLiteRegistration Register_SUB();
|
TfLiteRegistration Register_SUB();
|
||||||
|
TfLiteRegistration Register_SUM();
|
||||||
TfLiteRegistration Register_SVDF();
|
TfLiteRegistration Register_SVDF();
|
||||||
TfLiteRegistration Register_TRANSPOSE();
|
TfLiteRegistration Register_TRANSPOSE();
|
||||||
TfLiteRegistration Register_TRANSPOSE_CONV();
|
TfLiteRegistration Register_TRANSPOSE_CONV();
|
||||||
|
|||||||
@@ -663,7 +663,7 @@ void PortableCwiseMul(const int16_t* input_1, const int16_t* input_2,
|
|||||||
const int16_t b = input_2[index];
|
const int16_t b = input_2[index];
|
||||||
int32_t value = static_cast<int32_t>(a) * static_cast<int32_t>(b);
|
int32_t value = static_cast<int32_t>(a) * static_cast<int32_t>(b);
|
||||||
value = MultiplyByQuantizedMultiplier(value, multiplier, shift);
|
value = MultiplyByQuantizedMultiplier(value, multiplier, shift);
|
||||||
value -= output_zp;
|
value += output_zp;
|
||||||
value = std::min(std::max(static_cast<int32_t>(-128), value),
|
value = std::min(std::max(static_cast<int32_t>(-128), value),
|
||||||
static_cast<int32_t>(127));
|
static_cast<int32_t>(127));
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
|
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -60,6 +60,15 @@ void EvalMulFloatReference(TfLiteContext* context, TfLiteNode* node,
|
|||||||
const TfLiteEvalTensor* input2,
|
const TfLiteEvalTensor* input2,
|
||||||
TfLiteEvalTensor* output);
|
TfLiteEvalTensor* output);
|
||||||
|
|
||||||
|
// Generic must define registration function.
|
||||||
|
TfLiteRegistration Register_MUL();
|
||||||
|
|
||||||
|
#if defined(CMSIS_NN)
|
||||||
|
TfLiteRegistration Register_MUL_INT8();
|
||||||
|
#else
|
||||||
|
// Fallback registration
|
||||||
|
inline TfLiteRegistration Register_MUL_INT8() { return Register_MUL(); }
|
||||||
|
#endif
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|
||||||
#endif // TENSORFLOW_LITE_MICRO_KERNELS_MUL_H_
|
#endif // TENSORFLOW_LITE_MICRO_KERNELS_MUL_H_
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorData<float>(output));
|
tflite::micro::GetTensorData<float>(output));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -95,8 +95,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
data->axis);
|
data->axis);
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
TF_LITE_KERNEL_LOG(context, "Type '%s' is not supported by pack.",
|
MicroPrintf("Type '%s' is not supported by pack.",
|
||||||
TfLiteTypeGetName(output->type));
|
TfLiteTypeGetName(output->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -213,8 +213,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
|
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s not currently supported by Pad.",
|
MicroPrintf("Type %s not currently supported by Pad.",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -45,8 +45,8 @@ TfLiteStatus AverageEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
AveragePoolingEvalQuantized(context, node, params, data, input, output);
|
AveragePoolingEvalQuantized(context, node, params, data, input, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Input type %s is not currently supported",
|
MicroPrintf("Input type %s is not currently supported",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
@@ -73,8 +73,8 @@ TfLiteStatus MaxEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
MaxPoolingEvalQuantized(context, node, params, data, input, output);
|
MaxPoolingEvalQuantized(context, node, params, data, input, output);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s not currently supported.",
|
MicroPrintf("Type %s not currently supported.",
|
||||||
TfLiteTypeGetName(input->type));
|
TfLiteTypeGetName(input->type));
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
|
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ limitations under the License.
|
|||||||
|
|
||||||
#include "tensorflow/lite/c/builtin_op_data.h"
|
#include "tensorflow/lite/c/builtin_op_data.h"
|
||||||
#include "tensorflow/lite/c/common.h"
|
#include "tensorflow/lite/c/common.h"
|
||||||
|
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
|
|
||||||
@@ -66,6 +67,19 @@ void MaxPoolingEvalQuantized(TfLiteContext* context, TfLiteNode* node,
|
|||||||
const TfLiteEvalTensor* input,
|
const TfLiteEvalTensor* input,
|
||||||
TfLiteEvalTensor* output);
|
TfLiteEvalTensor* output);
|
||||||
|
|
||||||
|
#if defined(CMSIS_NN)
|
||||||
|
TfLiteRegistration Register_AVERAGE_POOL_2D_INT8();
|
||||||
|
|
||||||
|
TfLiteRegistration Register_MAX_POOL_2D_INT8();
|
||||||
|
#else
|
||||||
|
inline TfLiteRegistration Register_AVERAGE_POOL_2D_INT8() {
|
||||||
|
return tflite::Register_AVERAGE_POOL_2D();
|
||||||
|
}
|
||||||
|
|
||||||
|
inline TfLiteRegistration Register_MAX_POOL_2D_INT8() {
|
||||||
|
return tflite::Register_MAX_POOL_2D();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
} // namespace tflite
|
} // namespace tflite
|
||||||
|
|
||||||
#endif // TENSORFLOW_LITE_MICRO_KERNELS_POOLING_H_
|
#endif // TENSORFLOW_LITE_MICRO_KERNELS_POOLING_H_
|
||||||
|
|||||||
@@ -61,9 +61,8 @@ TfLiteStatus PreluEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
} break;
|
} break;
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("Only float32 and uint8_t are supported currently, got %d.",
|
||||||
context, "Only float32 and uint8_t are supported currently, got %d.",
|
TfLiteTypeGetName(input->type));
|
||||||
TfLiteTypeGetName(input->type));
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ limitations under the License.
|
|||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
|
|
||||||
const int kMaxNumberOfAxis = 4;
|
const int kMaxNumberOfAxis = 5;
|
||||||
const int kMaxNumberOfReducedAxis = 2;
|
const int kMaxNumberOfReducedAxis = 2;
|
||||||
|
|
||||||
TfLiteStatus PrepareSimple(TfLiteContext* context, TfLiteNode* node,
|
TfLiteStatus PrepareSimple(TfLiteContext* context, TfLiteNode* node,
|
||||||
|
|||||||
@@ -55,8 +55,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
auto* params =
|
auto* params =
|
||||||
reinterpret_cast<TfLiteResizeBilinearParams*>(node->builtin_data);
|
reinterpret_cast<TfLiteResizeBilinearParams*>(node->builtin_data);
|
||||||
if (params->half_pixel_centers && params->align_corners) {
|
if (params->half_pixel_centers && params->align_corners) {
|
||||||
TF_LITE_KERNEL_LOG(
|
MicroPrintf("If half_pixel_centers is True, align_corners must be False.");
|
||||||
context, "If half_pixel_centers is True, align_corners must be False.");
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -100,8 +99,7 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
tflite::micro::GetTensorShape(output),
|
tflite::micro::GetTensorShape(output),
|
||||||
tflite::micro::GetTensorData<int8_t>(output));
|
tflite::micro::GetTensorData<int8_t>(output));
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Output type is %d, requires float or int8.",
|
MicroPrintf("Output type is %d, requires float or int8.", output->type);
|
||||||
output->type);
|
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ limitations under the License.
|
|||||||
#include "tensorflow/lite/kernels/kernel_util.h"
|
#include "tensorflow/lite/kernels/kernel_util.h"
|
||||||
#include "tensorflow/lite/kernels/op_macros.h"
|
#include "tensorflow/lite/kernels/op_macros.h"
|
||||||
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
|
||||||
|
|
||||||
namespace tflite {
|
namespace tflite {
|
||||||
namespace ops {
|
namespace ops {
|
||||||
@@ -55,7 +54,7 @@ TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
output->type = input->type;
|
output->type = input->type;
|
||||||
|
|
||||||
if (!IsConstantTensor(size)) {
|
if (!IsConstantTensor(size)) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Dynamic tensors are unsupported in tfmicro.");
|
MicroPrintf("Dynamic tensors are unsupported in tfmicro.");
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,196 @@
|
|||||||
|
/* Copyright 2022 The TensorFlow Authors. All Rights Reserved.
|
||||||
|
|
||||||
|
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 "tensorflow/lite/kernels/internal/reference/select.h"
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "tensorflow/lite/c/common.h"
|
||||||
|
#include "tensorflow/lite/kernels/internal/tensor_ctypes.h"
|
||||||
|
#include "tensorflow/lite/kernels/kernel_util.h"
|
||||||
|
#include "tensorflow/lite/micro/kernels/kernel_util.h"
|
||||||
|
|
||||||
|
namespace tflite {
|
||||||
|
|
||||||
|
constexpr int kInputTensorCondition = 0;
|
||||||
|
constexpr int kInputTensorX = 1;
|
||||||
|
constexpr int kInputTensorY = 2;
|
||||||
|
constexpr int kOutputTensor = 0;
|
||||||
|
|
||||||
|
struct OpData {
|
||||||
|
bool requires_broadcast;
|
||||||
|
// True if input condition is scalar or input condition has rank one and
|
||||||
|
// matches the first dimension of other inputs.
|
||||||
|
bool has_low_rank_input_condition;
|
||||||
|
};
|
||||||
|
|
||||||
|
void* SelectInit(TfLiteContext* context, const char* buffer, size_t length) {
|
||||||
|
TFLITE_DCHECK(context->AllocatePersistentBuffer != nullptr);
|
||||||
|
auto* data = static_cast<OpData*>(
|
||||||
|
context->AllocatePersistentBuffer(context, sizeof(OpData)));
|
||||||
|
data->requires_broadcast = false;
|
||||||
|
data->has_low_rank_input_condition = false;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
TfLiteStatus CheckBroadcastShape(TfLiteContext* context,
|
||||||
|
const TfLiteTensor* input1,
|
||||||
|
const TfLiteTensor* input2,
|
||||||
|
const TfLiteTensor* input3,
|
||||||
|
const TfLiteIntArray* output_shape) {
|
||||||
|
const int dims1 = NumDimensions(input1);
|
||||||
|
const int dims2 = NumDimensions(input2);
|
||||||
|
const int dims3 = NumDimensions(input3);
|
||||||
|
const int out_dims = std::max(std::max(dims1, dims2), dims3);
|
||||||
|
TF_LITE_ENSURE_EQ(context, out_dims, output_shape->size);
|
||||||
|
|
||||||
|
for (int i = 0; i < out_dims; ++i) {
|
||||||
|
const int d1 = i >= dims1 ? 1 : SizeOfDimension(input1, dims1 - i - 1);
|
||||||
|
const int d2 = i >= dims2 ? 1 : SizeOfDimension(input2, dims2 - i - 1);
|
||||||
|
const int d3 = i >= dims3 ? 1 : SizeOfDimension(input3, dims3 - i - 1);
|
||||||
|
const int min_value = std::min(std::min(d1, d2), d3);
|
||||||
|
int max_value = std::max(std::max(d1, d2), d3);
|
||||||
|
// If one dimention is 0, others must be 0 or 1.
|
||||||
|
if (min_value == 0) max_value = 0;
|
||||||
|
if (!(d1 == 1 || d1 == max_value) || !(d2 == 1 || d2 == max_value) ||
|
||||||
|
!(d3 == 1 || d3 == max_value)) {
|
||||||
|
MicroPrintf("Given shapes are not broadcastable.");
|
||||||
|
return kTfLiteError;
|
||||||
|
}
|
||||||
|
TF_LITE_ENSURE_EQ(context, output_shape->data[out_dims - i - 1], max_value);
|
||||||
|
}
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
TfLiteStatus SelectPrepare(TfLiteContext* context, TfLiteNode* node) {
|
||||||
|
OpData* data = reinterpret_cast<OpData*>(node->user_data);
|
||||||
|
|
||||||
|
TF_LITE_ENSURE_EQ(context, NumInputs(node), 3);
|
||||||
|
TF_LITE_ENSURE_EQ(context, NumOutputs(node), 1);
|
||||||
|
|
||||||
|
MicroContext* micro_context = GetMicroContext(context);
|
||||||
|
TfLiteTensor* input_condition =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorCondition);
|
||||||
|
|
||||||
|
TfLiteTensor* input_x =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorX);
|
||||||
|
|
||||||
|
TfLiteTensor* input_y =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorY);
|
||||||
|
|
||||||
|
TfLiteTensor* output =
|
||||||
|
micro_context->AllocateTempOutputTensor(node, kOutputTensor);
|
||||||
|
|
||||||
|
// Input must be bool.
|
||||||
|
TF_LITE_ENSURE_TYPES_EQ(context, input_condition->type, kTfLiteBool);
|
||||||
|
TF_LITE_ENSURE_TYPES_EQ(context, input_x->type, input_y->type);
|
||||||
|
output->type = input_x->type;
|
||||||
|
|
||||||
|
// Respect the original output shape when there are mixed shapes to represent
|
||||||
|
// a scalar data.
|
||||||
|
if (GetTensorShape(input_condition).FlatSize() == 1 &&
|
||||||
|
GetTensorShape(input_x).FlatSize() == 1 &&
|
||||||
|
GetTensorShape(input_y).FlatSize() == 1 &&
|
||||||
|
GetTensorShape(output).FlatSize() == 1) {
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool same_shape = HaveSameShapes(input_condition, input_x) &&
|
||||||
|
HaveSameShapes(input_x, input_y);
|
||||||
|
if (!same_shape) {
|
||||||
|
TF_LITE_ENSURE_OK(
|
||||||
|
context, CheckBroadcastShape(context, input_condition, input_x, input_y,
|
||||||
|
output->dims));
|
||||||
|
data->requires_broadcast = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_condition);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_x);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_y);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(output);
|
||||||
|
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
TfLiteStatus SelectEval(TfLiteContext* context, TfLiteNode* node) {
|
||||||
|
OpData* data = static_cast<OpData*>(node->user_data);
|
||||||
|
MicroContext* micro_context = GetMicroContext(context);
|
||||||
|
|
||||||
|
TfLiteTensor* input_condition =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorCondition);
|
||||||
|
|
||||||
|
TfLiteTensor* input_x =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorX);
|
||||||
|
|
||||||
|
TfLiteTensor* input_y =
|
||||||
|
micro_context->AllocateTempInputTensor(node, kInputTensorY);
|
||||||
|
|
||||||
|
TfLiteTensor* output =
|
||||||
|
micro_context->AllocateTempOutputTensor(node, kOutputTensor);
|
||||||
|
|
||||||
|
#define TF_LITE_SELECT(type, op) \
|
||||||
|
reference_ops::op(GetTensorShape(input_condition), \
|
||||||
|
GetTensorData<bool>(input_condition), \
|
||||||
|
GetTensorShape(input_x), GetTensorData<type>(input_x), \
|
||||||
|
GetTensorShape(input_y), GetTensorData<type>(input_y), \
|
||||||
|
GetTensorShape(output), GetTensorData<type>(output));
|
||||||
|
|
||||||
|
#define TF_LITE_SWITCH(type, op) \
|
||||||
|
switch (type) { \
|
||||||
|
case kTfLiteFloat32: \
|
||||||
|
TF_LITE_SELECT(float, op); \
|
||||||
|
break; \
|
||||||
|
case kTfLiteInt8: \
|
||||||
|
TF_LITE_SELECT(int8_t, op); \
|
||||||
|
break; \
|
||||||
|
case kTfLiteInt16: \
|
||||||
|
TF_LITE_SELECT(int16_t, op); \
|
||||||
|
break; \
|
||||||
|
default: \
|
||||||
|
MicroPrintf("Does not support type other than %s, but got %s", \
|
||||||
|
"int8|int16|float32", TfLiteTypeGetName(type)); \
|
||||||
|
return kTfLiteError; \
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data->has_low_rank_input_condition) {
|
||||||
|
MicroPrintf("Not yet implemented.");
|
||||||
|
return kTfLiteError;
|
||||||
|
} else if (data->requires_broadcast) {
|
||||||
|
TF_LITE_SWITCH(input_x->type, BroadcastSelect5DSlow);
|
||||||
|
} else {
|
||||||
|
TF_LITE_SWITCH(input_x->type, Select);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef TF_LITE_SELECT
|
||||||
|
#undef TF_LITE_SWITCH
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_condition);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_x);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(input_y);
|
||||||
|
micro_context->DeallocateTempTfLiteTensor(output);
|
||||||
|
|
||||||
|
return kTfLiteOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SelectV2 op selects values of 'x' if the corresponding value of 'condition'
|
||||||
|
// is true or the value of 'y' if false. There are valid condition input sizes:
|
||||||
|
//
|
||||||
|
// 1. Either the same shape (in which case the select is elementwise), or
|
||||||
|
// 2. Broadcastable shapes between 'condition', 'x' and 'y'.
|
||||||
|
TfLiteRegistration Register_SELECT_V2() {
|
||||||
|
return tflite::micro::RegisterOp(tflite::SelectInit, tflite::SelectPrepare,
|
||||||
|
tflite::SelectEval);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace tflite
|
||||||
@@ -47,8 +47,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
TfLiteEvalTensor* output =
|
TfLiteEvalTensor* output =
|
||||||
tflite::micro::GetEvalOutput(context, node, kOutputTensor);
|
tflite::micro::GetEvalOutput(context, node, kOutputTensor);
|
||||||
if (output->type != kTfLiteInt32) {
|
if (output->type != kTfLiteInt32) {
|
||||||
TF_LITE_KERNEL_LOG(context, "Output type %s (%d) not supported.",
|
MicroPrintf("Output type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(output->type), output->type);
|
TfLiteTypeGetName(output->type), output->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
} else {
|
} else {
|
||||||
ExtractShape(input, tflite::micro::GetTensorData<int32_t>(output));
|
ExtractShape(input, tflite::micro::GetTensorData<int32_t>(output));
|
||||||
|
|||||||
@@ -106,8 +106,8 @@ TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
GetBeginAndSizeVectors<int64_t>(input->dims->size, begin, size,
|
GetBeginAndSizeVectors<int64_t>(input->dims->size, begin, size,
|
||||||
op_params.begin, op_params.size);
|
op_params.begin, op_params.size);
|
||||||
} else {
|
} else {
|
||||||
TF_LITE_KERNEL_LOG(context, "Begin tensor type %s (%d) not supported.",
|
MicroPrintf("Begin tensor type %s (%d) not supported.",
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
TfLiteTypeGetName(input->type), input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -75,8 +75,8 @@ TfLiteStatus SoftmaxEval(TfLiteContext* context, TfLiteNode* node) {
|
|||||||
return kTfLiteOk;
|
return kTfLiteOk;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
TF_LITE_KERNEL_LOG(context, "Type %s (%d) not supported.",
|
MicroPrintf("Type %s (%d) not supported.", TfLiteTypeGetName(input->type),
|
||||||
TfLiteTypeGetName(input->type), input->type);
|
input->type);
|
||||||
return kTfLiteError;
|
return kTfLiteError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user