mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-10 13:36:54 +03:00
Rolling 20220924
This commit is contained in:
@@ -18,8 +18,27 @@
|
||||
#include "ll_cam.h"
|
||||
#include "cam_hal.h"
|
||||
|
||||
static const char *TAG = "cam_hal";
|
||||
#if (ESP_IDF_VERSION_MAJOR == 3) && (ESP_IDF_VERSION_MINOR == 3)
|
||||
#include "rom/ets_sys.h"
|
||||
#else
|
||||
#include "esp_timer.h"
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
|
||||
#elif CONFIG_IDF_TARGET_ESP32S2
|
||||
#include "esp32s2/rom/ets_sys.h"
|
||||
#elif CONFIG_IDF_TARGET_ESP32S3
|
||||
#include "esp32s3/rom/ets_sys.h"
|
||||
#endif
|
||||
#endif // ESP_IDF_VERSION_MAJOR
|
||||
#define ESP_CAMERA_ETS_PRINTF ets_printf
|
||||
|
||||
#if CONFIG_CAM_TASK_STACK_SIZE
|
||||
#define CAM_TASK_STACK CONFIG_CAM_TASK_STACK_SIZE
|
||||
#else
|
||||
#define CAM_TASK_STACK (2*1024)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "cam_hal";
|
||||
static cam_obj_t *cam_obj = NULL;
|
||||
|
||||
static const uint32_t JPEG_SOI_MARKER = 0xFFD8FF; // written in little-endian for esp32
|
||||
@@ -32,7 +51,7 @@ static int cam_verify_jpeg_soi(const uint8_t *inbuf, uint32_t length)
|
||||
for (uint32_t i = 0; i < length; i++) {
|
||||
sig = *((uint32_t *)(&inbuf[i])) & 0xFFFFFF;
|
||||
if (sig == JPEG_SOI_MARKER) {
|
||||
ESP_LOGW(TAG, "SOI: %d", i);
|
||||
ESP_LOGW(TAG, "SOI: %d", (int) i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
@@ -93,7 +112,7 @@ void IRAM_ATTR ll_cam_send_event(cam_obj_t *cam, cam_event_t cam_event, BaseType
|
||||
if (xQueueSendFromISR(cam->event_queue, (void *)&cam_event, HPTaskAwoken) != pdTRUE) {
|
||||
ll_cam_stop(cam);
|
||||
cam->state = CAM_STATE_IDLE;
|
||||
ESP_EARLY_LOGE(TAG, "EV-%s-OVF", cam_event==CAM_IN_SUC_EOF_EVENT ? "EOF" : "VSYNC");
|
||||
ESP_CAMERA_ETS_PRINTF(DRAM_STR("cam_hal: EV-%s-OVF\r\n"), cam_event==CAM_IN_SUC_EOF_EVENT ? DRAM_STR("EOF") : DRAM_STR("VSYNC"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,7 +123,7 @@ static void cam_task(void *arg)
|
||||
int frame_pos = 0;
|
||||
cam_obj->state = CAM_STATE_IDLE;
|
||||
cam_event_t cam_event = 0;
|
||||
|
||||
|
||||
xQueueReset(cam_obj->event_queue);
|
||||
|
||||
while (1) {
|
||||
@@ -127,7 +146,7 @@ static void cam_task(void *arg)
|
||||
case CAM_STATE_READ_BUF: {
|
||||
camera_fb_t * frame_buffer_event = &cam_obj->frames[frame_pos].fb;
|
||||
size_t pixels_per_dma = (cam_obj->dma_half_buffer_size * cam_obj->fb_bytes_per_pixel) / (cam_obj->dma_bytes_per_item * cam_obj->in_bytes_per_pixel);
|
||||
|
||||
|
||||
if (cam_event == CAM_IN_SUC_EOF_EVENT) {
|
||||
if(!cam_obj->psram_mode){
|
||||
if (cam_obj->fb_size < (frame_buffer_event->len + pixels_per_dma)) {
|
||||
@@ -137,8 +156,8 @@ static void cam_task(void *arg)
|
||||
continue;
|
||||
}
|
||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
cam_obj->dma_half_buffer_size);
|
||||
}
|
||||
//Check for JPEG SOI in the first buffer. stop if not found
|
||||
@@ -160,8 +179,8 @@ static void cam_task(void *arg)
|
||||
cnt--;
|
||||
} else {
|
||||
frame_buffer_event->len += ll_cam_memcpy(cam_obj,
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
&frame_buffer_event->buf[frame_buffer_event->len],
|
||||
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
||||
cam_obj->dma_half_buffer_size);
|
||||
}
|
||||
}
|
||||
@@ -179,7 +198,7 @@ static void cam_task(void *arg)
|
||||
} else if (!cam_obj->jpeg_mode) {
|
||||
if (frame_buffer_event->len != cam_obj->fb_size) {
|
||||
cam_obj->frames[frame_pos].en = 1;
|
||||
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, cam_obj->fb_size);
|
||||
ESP_LOGE(TAG, "FB-SIZE: %u != %u", frame_buffer_event->len, (unsigned) cam_obj->fb_size);
|
||||
}
|
||||
}
|
||||
//send frame
|
||||
@@ -245,8 +264,9 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
cam_obj->dma_node_cnt = (cam_obj->dma_buffer_size) / cam_obj->dma_node_buffer_size; // Number of DMA nodes
|
||||
cam_obj->frame_copy_cnt = cam_obj->recv_size / cam_obj->dma_half_buffer_size; // Number of interrupted copies, ping-pong copy
|
||||
|
||||
ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
|
||||
cam_obj->dma_buffer_size, cam_obj->dma_half_buffer_size, cam_obj->dma_node_buffer_size, cam_obj->dma_node_cnt, cam_obj->frame_copy_cnt);
|
||||
ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d",
|
||||
(int) cam_obj->dma_buffer_size, (int) cam_obj->dma_half_buffer_size, (int) cam_obj->dma_node_buffer_size,
|
||||
(int) cam_obj->dma_node_cnt, (int) cam_obj->frame_copy_cnt);
|
||||
|
||||
cam_obj->dma_buffer = NULL;
|
||||
cam_obj->dma = NULL;
|
||||
@@ -276,13 +296,19 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
cam_obj->frames[x].fb_offset = 0;
|
||||
cam_obj->frames[x].en = 0;
|
||||
ESP_LOGI(TAG, "Allocating %d Byte frame buffer in %s", alloc_size, _caps & MALLOC_CAP_SPIRAM ? "PSRAM" : "OnBoard RAM");
|
||||
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0)
|
||||
// In IDF v4.2 and earlier, memory returned by heap_caps_aligned_alloc must be freed using heap_caps_aligned_free.
|
||||
// And heap_caps_aligned_free is deprecated on v4.3.
|
||||
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_aligned_alloc(16, alloc_size, _caps);
|
||||
#else
|
||||
cam_obj->frames[x].fb.buf = (uint8_t *)heap_caps_malloc(alloc_size, _caps);
|
||||
#endif
|
||||
CAM_CHECK(cam_obj->frames[x].fb.buf != NULL, "frame buffer malloc failed", ESP_FAIL);
|
||||
if (cam_obj->psram_mode) {
|
||||
//align PSRAM buffer. TODO: save the offset so proper address can be freed later
|
||||
cam_obj->frames[x].fb_offset = dma_align - ((uint32_t)cam_obj->frames[x].fb.buf & (dma_align - 1));
|
||||
cam_obj->frames[x].fb.buf += cam_obj->frames[x].fb_offset;
|
||||
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (uint32_t)cam_obj->frames[x].fb.buf);
|
||||
ESP_LOGI(TAG, "Frame[%d]: Offset: %u, Addr: 0x%08X", x, cam_obj->frames[x].fb_offset, (unsigned) cam_obj->frames[x].fb.buf);
|
||||
cam_obj->frames[x].dma = allocate_dma_descriptors(cam_obj->dma_node_cnt, cam_obj->dma_node_buffer_size, cam_obj->frames[x].fb.buf);
|
||||
CAM_CHECK(cam_obj->frames[x].dma != NULL, "frame dma malloc failed", ESP_FAIL);
|
||||
}
|
||||
@@ -292,8 +318,8 @@ static esp_err_t cam_dma_config(const camera_config_t *config)
|
||||
if (!cam_obj->psram_mode) {
|
||||
cam_obj->dma_buffer = (uint8_t *)heap_caps_malloc(cam_obj->dma_buffer_size * sizeof(uint8_t), MALLOC_CAP_DMA);
|
||||
if(NULL == cam_obj->dma_buffer) {
|
||||
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
|
||||
cam_obj->dma_buffer_size, heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
|
||||
ESP_LOGE(TAG,"%s(%d): DMA buffer %d Byte malloc failed, the current largest free block:%d Byte", __FUNCTION__, __LINE__,
|
||||
(int) cam_obj->dma_buffer_size, (int) heap_caps_get_largest_free_block(MALLOC_CAP_DMA));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
@@ -359,7 +385,7 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
|
||||
cam_obj->recv_size = cam_obj->width * cam_obj->height * cam_obj->in_bytes_per_pixel;
|
||||
cam_obj->fb_size = cam_obj->width * cam_obj->height * cam_obj->fb_bytes_per_pixel;
|
||||
}
|
||||
|
||||
|
||||
ret = cam_dma_config(config);
|
||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam_dma_config failed", err);
|
||||
|
||||
@@ -376,13 +402,13 @@ esp_err_t cam_config(const camera_config_t *config, framesize_t frame_size, uint
|
||||
ret = ll_cam_init_isr(cam_obj);
|
||||
CAM_CHECK_GOTO(ret == ESP_OK, "cam intr alloc failed", err);
|
||||
|
||||
|
||||
|
||||
#if CONFIG_CAMERA_CORE0
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 0);
|
||||
#elif CONFIG_CAMERA_CORE1
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
|
||||
xTaskCreatePinnedToCore(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle, 1);
|
||||
#else
|
||||
xTaskCreate(cam_task, "cam_task", 2048, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
|
||||
xTaskCreate(cam_task, "cam_task", CAM_TASK_STACK, NULL, configMAX_PRIORITIES - 2, &cam_obj->task_handle);
|
||||
#endif
|
||||
|
||||
ESP_LOGI(TAG, "cam config ok");
|
||||
|
||||
@@ -57,6 +57,15 @@
|
||||
#if CONFIG_BF3005_SUPPORT
|
||||
#include "bf3005.h"
|
||||
#endif
|
||||
#if CONFIG_BF20A6_SUPPORT
|
||||
#include "bf20a6.h"
|
||||
#endif
|
||||
#if CONFIG_SC101IOT_SUPPORT
|
||||
#include "sc101iot.h"
|
||||
#endif
|
||||
#if CONFIG_SC030IOT_SUPPORT
|
||||
#include "sc030iot.h"
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||
#include "esp32-hal-log.h"
|
||||
@@ -119,10 +128,20 @@ static const sensor_func_t g_sensors[] = {
|
||||
#if CONFIG_BF3005_SUPPORT
|
||||
{bf3005_detect, bf3005_init},
|
||||
#endif
|
||||
#if CONFIG_BF20A6_SUPPORT
|
||||
{bf20a6_detect, bf20a6_init},
|
||||
#endif
|
||||
#if CONFIG_SC101IOT_SUPPORT
|
||||
{sc101iot_detect, sc101iot_init},
|
||||
#endif
|
||||
#if CONFIG_SC030IOT_SUPPORT
|
||||
{sc030iot_detect, sc030iot_init},
|
||||
#endif
|
||||
};
|
||||
|
||||
static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out_camera_model)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
*out_camera_model = CAMERA_NONE;
|
||||
if (s_state != NULL) {
|
||||
return ESP_ERR_INVALID_STATE;
|
||||
@@ -138,9 +157,17 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
CAMERA_ENABLE_OUT_CLOCK(config);
|
||||
}
|
||||
|
||||
if (config->pin_sscb_sda != -1) {
|
||||
ESP_LOGD(TAG, "Initializing SSCB");
|
||||
SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl);
|
||||
if (config->pin_sccb_sda != -1) {
|
||||
ESP_LOGD(TAG, "Initializing SCCB");
|
||||
ret = SCCB_Init(config->pin_sccb_sda, config->pin_sccb_scl);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "Using existing I2C port");
|
||||
ret = SCCB_Use_Port(config->sccb_i2c_port);
|
||||
}
|
||||
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "sccb init err");
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (config->pin_pwdn >= 0) {
|
||||
@@ -170,15 +197,14 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
|
||||
ESP_LOGD(TAG, "Searching for camera address");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
|
||||
uint8_t slv_addr = SCCB_Probe();
|
||||
|
||||
if (slv_addr == 0) {
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
ret = ESP_ERR_NOT_FOUND;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Detected camera at address=0x%02x", slv_addr);
|
||||
@@ -203,9 +229,9 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
}
|
||||
|
||||
if (CAMERA_NONE == *out_camera_model) { //If no supported sensors are detected
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
ESP_LOGE(TAG, "Detected camera not supported.");
|
||||
return ESP_ERR_NOT_SUPPORTED;
|
||||
ret = ESP_ERR_NOT_SUPPORTED;
|
||||
goto err;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x",
|
||||
@@ -213,11 +239,30 @@ static esp_err_t camera_probe(const camera_config_t *config, camera_model_t *out
|
||||
|
||||
ESP_LOGD(TAG, "Doing SW reset of sensor");
|
||||
vTaskDelay(10 / portTICK_PERIOD_MS);
|
||||
s_state->sensor.reset(&s_state->sensor);
|
||||
|
||||
return ESP_OK;
|
||||
|
||||
return s_state->sensor.reset(&s_state->sensor);
|
||||
err :
|
||||
CAMERA_DISABLE_OUT_CLOCK();
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
static pixformat_t get_output_data_format(camera_conv_mode_t conv_mode)
|
||||
{
|
||||
pixformat_t format = PIXFORMAT_RGB565;
|
||||
switch (conv_mode) {
|
||||
case YUV422_TO_YUV420:
|
||||
format = PIXFORMAT_YUV420;
|
||||
break;
|
||||
case YUV422_TO_RGB565: // default format is RGB565
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "Convert to %d format enabled", format);
|
||||
return format;
|
||||
}
|
||||
#endif
|
||||
|
||||
esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
{
|
||||
esp_err_t err;
|
||||
@@ -256,6 +301,7 @@ esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
|
||||
s_state->sensor.status.framesize = frame_size;
|
||||
s_state->sensor.pixformat = pix_format;
|
||||
|
||||
ESP_LOGD(TAG, "Setting frame size to %dx%d", resolution[frame_size].width, resolution[frame_size].height);
|
||||
if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) {
|
||||
ESP_LOGE(TAG, "Failed to set frame size");
|
||||
@@ -263,6 +309,11 @@ esp_err_t esp_camera_init(const camera_config_t *config)
|
||||
goto fail;
|
||||
}
|
||||
s_state->sensor.set_pixformat(&s_state->sensor, pix_format);
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
if(config->conv_mode) {
|
||||
s_state->sensor.pixformat = get_output_data_format(config->conv_mode); // If conversion enabled, change the out data format by conversion mode
|
||||
}
|
||||
#endif
|
||||
|
||||
if (s_state->sensor.id.PID == OV2640_PID) {
|
||||
s_state->sensor.set_gainceiling(&s_state->sensor, GAINCEILING_2X);
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
.pin_pwdn = PIN_PWDN,
|
||||
.pin_reset = PIN_RESET,
|
||||
.pin_xclk = PIN_XCLK,
|
||||
.pin_sscb_sda = PIN_SIOD,
|
||||
.pin_sscb_scl = PIN_SIOC,
|
||||
.pin_sccb_sda = PIN_SIOD,
|
||||
.pin_sccb_scl = PIN_SIOC,
|
||||
.pin_d7 = PIN_D7,
|
||||
.pin_d6 = PIN_D6,
|
||||
.pin_d5 = PIN_D5,
|
||||
@@ -70,6 +70,7 @@
|
||||
#include "driver/ledc.h"
|
||||
#include "sensor.h"
|
||||
#include "sys/time.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@@ -91,6 +92,19 @@ typedef enum {
|
||||
CAMERA_FB_IN_DRAM /*!< Frame buffer is placed in internal DRAM */
|
||||
} camera_fb_location_t;
|
||||
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
/**
|
||||
* @brief Camera RGB\YUV conversion mode
|
||||
*/
|
||||
typedef enum {
|
||||
CONV_DISABLE,
|
||||
RGB565_TO_YUV422,
|
||||
|
||||
YUV422_TO_RGB565,
|
||||
YUV422_TO_YUV420
|
||||
} camera_conv_mode_t;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Configuration structure for camera initialization
|
||||
*/
|
||||
@@ -98,8 +112,14 @@ typedef struct {
|
||||
int pin_pwdn; /*!< GPIO pin for camera power down line */
|
||||
int pin_reset; /*!< GPIO pin for camera reset line */
|
||||
int pin_xclk; /*!< GPIO pin for camera XCLK line */
|
||||
int pin_sscb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_scl; /*!< GPIO pin for camera SCL line */
|
||||
union {
|
||||
int pin_sccb_sda; /*!< GPIO pin for camera SDA line */
|
||||
int pin_sscb_sda __attribute__((deprecated("please use pin_sccb_sda instead"))); /*!< GPIO pin for camera SDA line (legacy name) */
|
||||
};
|
||||
union {
|
||||
int pin_sccb_scl; /*!< GPIO pin for camera SCL line */
|
||||
int pin_sscb_scl __attribute__((deprecated("please use pin_sccb_scl instead"))); /*!< GPIO pin for camera SCL line (legacy name) */
|
||||
};
|
||||
int pin_d7; /*!< GPIO pin for camera D7 line */
|
||||
int pin_d6; /*!< GPIO pin for camera D6 line */
|
||||
int pin_d5; /*!< GPIO pin for camera D5 line */
|
||||
@@ -124,6 +144,11 @@ typedef struct {
|
||||
size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */
|
||||
camera_fb_location_t fb_location; /*!< The location where the frame buffer will be allocated */
|
||||
camera_grab_mode_t grab_mode; /*!< When buffers should be filled */
|
||||
#if CONFIG_CAMERA_CONVERTER_ENABLED
|
||||
camera_conv_mode_t conv_mode; /*!< RGB<->YUV Conversion mode */
|
||||
#endif
|
||||
|
||||
int sccb_i2c_port; /*!< If pin_sccb_sda is -1, use the already configured I2C bus by number */
|
||||
} camera_config_t;
|
||||
|
||||
/**
|
||||
|
||||
@@ -27,6 +27,9 @@ typedef enum {
|
||||
GC032A_PID = 0x232a,
|
||||
GC0308_PID = 0x9b,
|
||||
BF3005_PID = 0x30,
|
||||
BF20A6_PID = 0x20a6,
|
||||
SC101IOT_PID = 0xda4a,
|
||||
SC030IOT_PID = 0x9a46,
|
||||
} camera_pid_t;
|
||||
|
||||
typedef enum {
|
||||
@@ -40,6 +43,9 @@ typedef enum {
|
||||
CAMERA_GC032A,
|
||||
CAMERA_GC0308,
|
||||
CAMERA_BF3005,
|
||||
CAMERA_BF20A6,
|
||||
CAMERA_SC101IOT,
|
||||
CAMERA_SC030IOT,
|
||||
CAMERA_MODEL_MAX,
|
||||
CAMERA_NONE,
|
||||
} camera_model_t;
|
||||
@@ -55,11 +61,15 @@ typedef enum {
|
||||
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
|
||||
BF3005_SCCB_ADDR = 0x6E,
|
||||
BF20A6_SCCB_ADDR = 0x6E,
|
||||
SC101IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||
SC030IOT_SCCB_ADDR = 0x68,// 0xd0 >> 1
|
||||
} camera_sccb_addr_t;
|
||||
|
||||
typedef enum {
|
||||
PIXFORMAT_RGB565, // 2BPP/RGB565
|
||||
PIXFORMAT_YUV422, // 2BPP/YUV422
|
||||
PIXFORMAT_YUV420, // 1.5BPP/YUV420
|
||||
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
|
||||
PIXFORMAT_JPEG, // JPEG/COMPRESSED
|
||||
PIXFORMAT_RGB888, // 3BPP/RGB888
|
||||
@@ -199,7 +209,7 @@ typedef struct _sensor {
|
||||
|
||||
// Sensor function pointers
|
||||
int (*init_status) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor);
|
||||
int (*reset) (sensor_t *sensor); // Reset the configuration of the sensor, and return ESP_OK if reset is successful
|
||||
int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
|
||||
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
|
||||
int (*set_contrast) (sensor_t *sensor, int level);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#define __SCCB_H__
|
||||
#include <stdint.h>
|
||||
int SCCB_Init(int pin_sda, int pin_scl);
|
||||
int SCCB_Use_Port(int sccb_i2c_port);
|
||||
int SCCB_Deinit(void);
|
||||
uint8_t SCCB_Probe();
|
||||
uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg);
|
||||
|
||||
@@ -25,6 +25,11 @@ static const char* TAG = "sccb";
|
||||
|
||||
#include "driver/i2c.h"
|
||||
|
||||
// support IDF 5.x
|
||||
#ifndef portTICK_RATE_MS
|
||||
#define portTICK_RATE_MS portTICK_PERIOD_MS
|
||||
#endif
|
||||
|
||||
#define SCCB_FREQ CONFIG_SCCB_CLK_FREQ /*!< I2C master frequency*/
|
||||
#define WRITE_BIT I2C_MASTER_WRITE /*!< I2C master write */
|
||||
#define READ_BIT I2C_MASTER_READ /*!< I2C master read */
|
||||
@@ -33,16 +38,26 @@ static const char* TAG = "sccb";
|
||||
#define ACK_VAL 0x0 /*!< I2C ack value */
|
||||
#define NACK_VAL 0x1 /*!< I2C nack value */
|
||||
#if CONFIG_SCCB_HARDWARE_I2C_PORT1
|
||||
const int SCCB_I2C_PORT = 1;
|
||||
const int SCCB_I2C_PORT_DEFAULT = 1;
|
||||
#else
|
||||
const int SCCB_I2C_PORT = 0;
|
||||
const int SCCB_I2C_PORT_DEFAULT = 0;
|
||||
#endif
|
||||
|
||||
static int sccb_i2c_port;
|
||||
static bool sccb_owns_i2c_port;
|
||||
|
||||
int SCCB_Init(int pin_sda, int pin_scl)
|
||||
{
|
||||
ESP_LOGI(TAG, "pin_sda %d pin_scl %d", pin_sda, pin_scl);
|
||||
i2c_config_t conf;
|
||||
esp_err_t ret;
|
||||
|
||||
memset(&conf, 0, sizeof(i2c_config_t));
|
||||
|
||||
sccb_i2c_port = SCCB_I2C_PORT_DEFAULT;
|
||||
sccb_owns_i2c_port = true;
|
||||
ESP_LOGI(TAG, "sccb_i2c_port=%d\n", sccb_i2c_port);
|
||||
|
||||
conf.mode = I2C_MODE_MASTER;
|
||||
conf.sda_io_num = pin_sda;
|
||||
conf.sda_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
@@ -50,30 +65,37 @@ int SCCB_Init(int pin_sda, int pin_scl)
|
||||
conf.scl_pullup_en = GPIO_PULLUP_ENABLE;
|
||||
conf.master.clk_speed = SCCB_FREQ;
|
||||
|
||||
i2c_param_config(SCCB_I2C_PORT, &conf);
|
||||
i2c_driver_install(SCCB_I2C_PORT, conf.mode, 0, 0, 0);
|
||||
return 0;
|
||||
if ((ret = i2c_param_config(sccb_i2c_port, &conf)) != ESP_OK) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
return i2c_driver_install(sccb_i2c_port, conf.mode, 0, 0, 0);
|
||||
}
|
||||
|
||||
int SCCB_Use_Port(int i2c_num) { // sccb use an already initialized I2C port
|
||||
if (sccb_owns_i2c_port) {
|
||||
SCCB_Deinit();
|
||||
}
|
||||
if (i2c_num < 0 || i2c_num > I2C_NUM_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
sccb_i2c_port = i2c_num;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
int SCCB_Deinit(void)
|
||||
{
|
||||
return i2c_driver_delete(SCCB_I2C_PORT);
|
||||
if (!sccb_owns_i2c_port) {
|
||||
return ESP_OK;
|
||||
}
|
||||
sccb_owns_i2c_port = false;
|
||||
return i2c_driver_delete(sccb_i2c_port);
|
||||
}
|
||||
|
||||
uint8_t SCCB_Probe(void)
|
||||
{
|
||||
uint8_t slave_addr = 0x0;
|
||||
// for (size_t i = 1; i < 0x80; i++) {
|
||||
// i2c_cmd_handle_t cmd = i2c_cmd_link_create();
|
||||
// i2c_master_start(cmd);
|
||||
// i2c_master_write_byte(cmd, ( i << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
// i2c_master_stop(cmd);
|
||||
// esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
// i2c_cmd_link_delete(cmd);
|
||||
// if( ret == ESP_OK) {
|
||||
// ESP_LOGW(TAG, "Found I2C Device at 0x%02X", i);
|
||||
// }
|
||||
// }
|
||||
|
||||
for (size_t i = 0; i < CAMERA_MODEL_MAX; i++) {
|
||||
if (slave_addr == camera_sensor[i].sccb_addr) {
|
||||
continue;
|
||||
@@ -83,7 +105,7 @@ uint8_t SCCB_Probe(void)
|
||||
i2c_master_start(cmd);
|
||||
i2c_master_write_byte(cmd, ( slave_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
esp_err_t ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
esp_err_t ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if( ret == ESP_OK) {
|
||||
return slave_addr;
|
||||
@@ -101,7 +123,7 @@ uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | WRITE_BIT, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
@@ -109,7 +131,7 @@ uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Read Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
@@ -126,7 +148,7 @@ uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data)
|
||||
i2c_master_write_byte(cmd, reg, ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "SCCB_Write Failed addr:0x%02x, reg:0x%02x, data:0x%02x, ret:%d", slv_addr, reg, data, ret);
|
||||
@@ -146,7 +168,7 @@ uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
i2c_master_write_byte(cmd, reg_u8[0], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) return -1;
|
||||
cmd = i2c_cmd_link_create();
|
||||
@@ -154,7 +176,7 @@ uint8_t SCCB_Read16(uint8_t slv_addr, uint16_t reg)
|
||||
i2c_master_write_byte(cmd, ( slv_addr << 1 ) | READ_BIT, ACK_CHECK_EN);
|
||||
i2c_master_read_byte(cmd, &data, NACK_VAL);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x fail\n", reg, data);
|
||||
@@ -175,7 +197,7 @@ uint8_t SCCB_Write16(uint8_t slv_addr, uint16_t reg, uint8_t data)
|
||||
i2c_master_write_byte(cmd, reg_u8[1], ACK_CHECK_EN);
|
||||
i2c_master_write_byte(cmd, data, ACK_CHECK_EN);
|
||||
i2c_master_stop(cmd);
|
||||
ret = i2c_master_cmd_begin(SCCB_I2C_PORT, cmd, 1000 / portTICK_RATE_MS);
|
||||
ret = i2c_master_cmd_begin(sccb_i2c_port, cmd, 1000 / portTICK_RATE_MS);
|
||||
i2c_cmd_link_delete(cmd);
|
||||
if(ret != ESP_OK) {
|
||||
ESP_LOGE(TAG, "W [%04x]=%02x %d fail\n", reg, data, i++);
|
||||
|
||||
@@ -13,6 +13,9 @@ const camera_sensor_info_t camera_sensor[CAMERA_MODEL_MAX] = {
|
||||
{CAMERA_GC032A, "GC032A", GC032A_SCCB_ADDR, GC032A_PID, FRAMESIZE_VGA, false},
|
||||
{CAMERA_GC0308, "GC0308", GC0308_SCCB_ADDR, GC0308_PID, FRAMESIZE_VGA, false},
|
||||
{CAMERA_BF3005, "BF3005", BF3005_SCCB_ADDR, BF3005_PID, FRAMESIZE_VGA, false},
|
||||
{CAMERA_BF20A6, "BF20A6", BF20A6_SCCB_ADDR, BF20A6_PID, FRAMESIZE_VGA, false},
|
||||
{CAMERA_SC101IOT, "SC101IOT", SC101IOT_SCCB_ADDR, SC101IOT_PID, FRAMESIZE_HD, false},
|
||||
{CAMERA_SC030IOT, "SC030IOT", SC030IOT_SCCB_ADDR, SC030IOT_PID, FRAMESIZE_VGA, false},
|
||||
};
|
||||
|
||||
const resolution_info_t resolution[FRAMESIZE_INVALID] = {
|
||||
|
||||
Reference in New Issue
Block a user