From ceb62ed60d8dbb74bf726225f0daf59e0ee9b900 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Sat, 26 Oct 2019 12:45:29 -0300 Subject: [PATCH 01/14] adding ov7670 support using esp-idf/components/esp32-camera. --- README.md | 6 +- components/camera/Kconfig | 28 - components/camera/camera.c | 808 ----------------------------- components/camera/camera_common.h | 72 --- components/camera/component.mk | 1 + components/camera/include/camera.h | 163 ------ components/camera/ov2640.c | 743 -------------------------- components/camera/ov2640.h | 13 - components/camera/ov2640_regs.h | 208 -------- components/camera/ov7725.c | 310 ----------- components/camera/ov7725.h | 14 - components/camera/ov7725_regs.h | 334 ------------ components/camera/sccb.c | 80 --- components/camera/sccb.h | 16 - components/camera/sensor.h | 179 ------- components/camera/twi.c | 263 ---------- components/camera/twi.h | 38 -- components/camera/wiring.c | 33 -- components/camera/wiring.h | 24 - components/camera/xclk.c | 44 -- components/camera/xclk.h | 7 - main/app_main.c | 259 ++++++--- sdkconfig.defaults | 11 - 23 files changed, 177 insertions(+), 3477 deletions(-) delete mode 100644 components/camera/Kconfig delete mode 100644 components/camera/camera.c delete mode 100644 components/camera/camera_common.h delete mode 100644 components/camera/include/camera.h delete mode 100644 components/camera/ov2640.c delete mode 100644 components/camera/ov2640.h delete mode 100644 components/camera/ov2640_regs.h delete mode 100644 components/camera/ov7725.c delete mode 100644 components/camera/ov7725.h delete mode 100644 components/camera/ov7725_regs.h delete mode 100644 components/camera/sccb.c delete mode 100644 components/camera/sccb.h delete mode 100644 components/camera/sensor.h delete mode 100644 components/camera/twi.c delete mode 100644 components/camera/twi.h delete mode 100644 components/camera/wiring.c delete mode 100644 components/camera/wiring.h delete mode 100644 components/camera/xclk.c delete mode 100644 components/camera/xclk.h delete mode 100644 sdkconfig.defaults diff --git a/README.md b/README.md index 5af4a6d..58dfede 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # ESP32 Camera Demo -Code provided in this repository gets the image from camera and prints it out as ASCII art to the serial port. +Code provided in this repository use the esp32-camera componet of idf for get the image using a webserver. ## Build Status @@ -43,7 +43,7 @@ If you are an owner of [ESP-WROVER V1 (aka DevKitJ)](http://dl.espressif.com/dl/ ### Camera -This example has been tested with OV7725 camera module. Use it, if this is your first exposure to interfacing a microcontroller with a camera. +This example has been tested with OV7670 camera module. Use it, if this is your first exposure to interfacing a microcontroller with a camera. Other OV7xxx series should work as well, with some changes to camera configuration code. OV5xxx can work too, but it is advisable to choose the ones which support RGB or YUV 8-bit wide output bus. The ones which only output 10-bit raw data may be a bit harder to work with. Also choose the camera which can output a scaled down (QVGA or VGA) image. Use of larger frame buffers will require external SPI RAM. @@ -211,7 +211,7 @@ D (1887) camera_demo: Done ### Software -The core of camera software is contained in `camera` folder and consists of the following files. +The core of camera software is contained in `esp32-camera` folder and consists of the following files. * [camera.c](components/camera/camera.c) and [include/camera.h](components/camera/include/camera.h) - main file responsible for configuration of ESP32's GPIO, clock, I2S and DMA to interface with camera module. Once interface is established, it perfroms camera configuration to then retrieve image and save it in ESP32 memory. Access to camera is executed using lower level routines in the following files. diff --git a/components/camera/Kconfig b/components/camera/Kconfig deleted file mode 100644 index aa779a9..0000000 --- a/components/camera/Kconfig +++ /dev/null @@ -1,28 +0,0 @@ -menu "Camera configuration" - -config ENABLE_TEST_PATTERN - bool "Enable test pattern on camera output" - default n - help - Configure the camera module to output test pattern instead of live image. - - Use this option to troubleshoot image issues like noise, - distortion, not legible and missing live image. - Instead, module will generate regular vertical bars - in shades from dark to white. - -config OV2640_SUPPORT - bool "OV2640 Support" - default y - help - Enable this option if you want to use the OV2640. - Disable this option to safe memory. - -config OV7725_SUPPORT - bool "OV7725 Support" - default y - help - Enable this option if you want to use the OV7725. - Disable this option to safe memory. - -endmenu diff --git a/components/camera/camera.c b/components/camera/camera.c deleted file mode 100644 index 6bbedef..0000000 --- a/components/camera/camera.c +++ /dev/null @@ -1,808 +0,0 @@ -// Copyright 2015-2016 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 -#include -#include -#include "time.h" -#include "sys/time.h" -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "freertos/semphr.h" -#include "rom/lldesc.h" -#include "soc/soc.h" -#include "soc/gpio_sig_map.h" -#include "soc/i2s_reg.h" -#include "soc/i2s_struct.h" -#include "soc/io_mux_reg.h" -#include "driver/gpio.h" -#include "driver/rtc_io.h" -#include "driver/periph_ctrl.h" -#include "esp_intr_alloc.h" -#include "esp_log.h" -#include "sensor.h" -#include "sccb.h" -#include "wiring.h" -#include "camera.h" -#include "camera_common.h" -#include "xclk.h" -#if CONFIG_OV2640_SUPPORT -#include "ov2640.h" -#endif -#if CONFIG_OV7725_SUPPORT -#include "ov7725.h" -#endif - -#define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN - -#define REG_PID 0x0A -#define REG_VER 0x0B -#define REG_MIDH 0x1C -#define REG_MIDL 0x1D - -static const char* TAG = "camera"; - -camera_state_t* s_state = NULL; - -const int resolution[][2] = { - { 40, 30 }, /* 40x30 */ - { 64, 32 }, /* 64x32 */ - { 64, 64 }, /* 64x64 */ - { 88, 72 }, /* QQCIF */ - { 160, 120 }, /* QQVGA */ - { 128, 160 }, /* QQVGA2*/ - { 176, 144 }, /* QCIF */ - { 240, 160 }, /* HQVGA */ - { 320, 240 }, /* QVGA */ - { 352, 288 }, /* CIF */ - { 640, 480 }, /* VGA */ - { 800, 600 }, /* SVGA */ - { 1280, 1024 }, /* SXGA */ - { 1600, 1200 }, /* UXGA */ -}; - -static void i2s_init(); -static void i2s_run(); -static void IRAM_ATTR gpio_isr(void* arg); -static void IRAM_ATTR i2s_isr(void* arg); -static esp_err_t dma_desc_init(); -static void dma_desc_deinit(); -static void dma_filter_task(void *pvParameters); -static void dma_filter_grayscale(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); -static void dma_filter_grayscale_highspeed(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); -static void dma_filter_jpeg(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); -static void dma_filter_rgb565(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); -static void i2s_stop(); - -static bool is_hs_mode() -{ - return s_state->config.xclk_freq_hz > 10000000; -} - -static size_t i2s_bytes_per_sample(i2s_sampling_mode_t mode) -{ - switch(mode) { - case SM_0A00_0B00: - return 4; - case SM_0A0B_0B0C: - return 4; - case SM_0A0B_0C0D: - return 2; - default: - assert(0 && "invalid sampling mode"); - return 0; - } -} - -static void vsync_intr_disable() -{ - gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_DISABLE); -} - -static void vsync_intr_enable() -{ - gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_NEGEDGE); -} - - -esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera_model) -{ - if (s_state != NULL) { - return ESP_ERR_INVALID_STATE; - } - - s_state = (camera_state_t*) calloc(sizeof(*s_state), 1); - if (!s_state) { - return ESP_ERR_NO_MEM; - } - - ESP_LOGD(TAG, "Enabling XCLK output"); - camera_enable_out_clock(config); - - ESP_LOGD(TAG, "Initializing SSCB"); - SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl); - - ESP_LOGD(TAG, "Resetting camera"); - gpio_config_t conf = { 0 }; - conf.pin_bit_mask = 1LL << config->pin_reset; - conf.mode = GPIO_MODE_OUTPUT; - gpio_config(&conf); - - gpio_set_level(config->pin_reset, 0); - delay(10); - gpio_set_level(config->pin_reset, 1); - delay(10); - - ESP_LOGD(TAG, "Searching for camera address"); - /* Probe the sensor */ - delay(10); - uint8_t slv_addr = SCCB_Probe(); - if (slv_addr == 0) { - *out_camera_model = CAMERA_NONE; - return ESP_ERR_CAMERA_NOT_DETECTED; - } - s_state->sensor.slv_addr = slv_addr; - ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr); - sensor_id_t* id = &s_state->sensor.id; - id->PID = SCCB_Read(slv_addr, REG_PID); - id->VER = SCCB_Read(slv_addr, REG_VER); - id->MIDL = SCCB_Read(slv_addr, REG_MIDL); - id->MIDH = SCCB_Read(slv_addr, REG_MIDH); - delay(10); - ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x", - id->PID, id->VER, id->MIDH, id->MIDL); - - switch (id->PID) { -#if CONFIG_OV2640_SUPPORT - case OV2640_PID: - *out_camera_model = CAMERA_OV2640; - ov2640_init(&s_state->sensor); - break; -#endif -#if CONFIG_OV7725_SUPPORT - case OV7725_PID: - *out_camera_model = CAMERA_OV7725; - ov7725_init(&s_state->sensor); - break; -#endif - default: - id->PID = 0; - *out_camera_model = CAMERA_UNKNOWN; - ESP_LOGD(TAG, "Detected camera not supported."); - return ESP_ERR_CAMERA_NOT_SUPPORTED; - } - - ESP_LOGD(TAG, "Doing SW reset of sensor"); - s_state->sensor.reset(&s_state->sensor); - - return ESP_OK; -} - -esp_err_t camera_init(const camera_config_t* config) -{ - if (!s_state) { - return ESP_ERR_INVALID_STATE; - } - if (s_state->sensor.id.PID == 0) { - return ESP_ERR_CAMERA_NOT_SUPPORTED; - } - memcpy(&s_state->config, config, sizeof(*config)); - esp_err_t err = ESP_OK; - framesize_t frame_size = (framesize_t) config->frame_size; - pixformat_t pix_format = (pixformat_t) config->pixel_format; - s_state->width = resolution[frame_size][0]; - s_state->height = resolution[frame_size][1]; - s_state->sensor.set_pixformat(&s_state->sensor, pix_format); - - ESP_LOGD(TAG, "Setting frame size to %dx%d", s_state->width, s_state->height); - if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) { - ESP_LOGE(TAG, "Failed to set frame size"); - err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE; - goto fail; - } - s_state->sensor.set_pixformat(&s_state->sensor, pix_format); - -#if ENABLE_TEST_PATTERN - /* Test pattern may get handy - if you are unable to get the live image right. - Once test pattern is enable, sensor will output - vertical shaded bars instead of live image. - */ - s_state->sensor.set_colorbar(&s_state->sensor, 1); - ESP_LOGD(TAG, "Test pattern enabled"); -#endif - - if (pix_format == PIXFORMAT_GRAYSCALE) { - if (s_state->sensor.id.PID != OV7725_PID) { - ESP_LOGE(TAG, "Grayscale format is only supported for ov7225"); - err = ESP_ERR_NOT_SUPPORTED; - goto fail; - } - s_state->fb_size = s_state->width * s_state->height; - if (is_hs_mode()) { - s_state->sampling_mode = SM_0A0B_0B0C; - s_state->dma_filter = &dma_filter_grayscale_highspeed; - } else { - s_state->sampling_mode = SM_0A0B_0C0D; - s_state->dma_filter = &dma_filter_grayscale; - } - s_state->in_bytes_per_pixel = 2; // camera sends YUYV - s_state->fb_bytes_per_pixel = 1; // frame buffer stores Y8 - } else if (pix_format == PIXFORMAT_RGB565) { - if (s_state->sensor.id.PID != OV7725_PID) { - ESP_LOGE(TAG, "RGB565 format is only supported for ov7225"); - err = ESP_ERR_NOT_SUPPORTED; - goto fail; - } - s_state->fb_size = s_state->width * s_state->height * 3; - if (is_hs_mode()) { - s_state->sampling_mode = SM_0A0B_0B0C; - } else { - s_state->sampling_mode = SM_0A00_0B00; - } - s_state->in_bytes_per_pixel = 2; // camera sends RGB565 (2 bytes) - s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888 - s_state->dma_filter = &dma_filter_rgb565; - - } else if (pix_format == PIXFORMAT_JPEG) { - if (s_state->sensor.id.PID != OV2640_PID) { - ESP_LOGE(TAG, "JPEG format is only supported for ov2640"); - err = ESP_ERR_NOT_SUPPORTED; - goto fail; - } - int qp = config->jpeg_quality; - int compression_ratio_bound; - if (qp >= 30) { - compression_ratio_bound = 5; - } else if (qp >= 10) { - compression_ratio_bound = 10; - } else { - compression_ratio_bound = 20; - } - (*s_state->sensor.set_quality)(&s_state->sensor, qp); - size_t equiv_line_count = s_state->height / compression_ratio_bound; - s_state->fb_size = s_state->width * equiv_line_count * 2 /* bpp */; - s_state->dma_filter = &dma_filter_jpeg; - if (is_hs_mode()) { - s_state->sampling_mode = SM_0A0B_0B0C; - } else { - s_state->sampling_mode = SM_0A00_0B00; - } - s_state->in_bytes_per_pixel = 2; - s_state->fb_bytes_per_pixel = 2; - } else { - ESP_LOGE(TAG, "Requested format is not supported"); - err = ESP_ERR_NOT_SUPPORTED; - goto fail; - } - - ESP_LOGD(TAG, "in_bpp: %d, fb_bpp: %d, fb_size: %d, mode: %d, width: %d height: %d", - s_state->in_bytes_per_pixel, s_state->fb_bytes_per_pixel, - s_state->fb_size, s_state->sampling_mode, - s_state->width, s_state->height); - - ESP_LOGD(TAG, "Allocating frame buffer (%d bytes)", s_state->fb_size); - s_state->fb = (uint8_t*) calloc(s_state->fb_size, 1); - if (s_state->fb == NULL) { - ESP_LOGE(TAG, "Failed to allocate frame buffer"); - err = ESP_ERR_NO_MEM; - goto fail; - } - - ESP_LOGD(TAG, "Initializing I2S and DMA"); - i2s_init(); - err = dma_desc_init(); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Failed to initialize I2S and DMA"); - goto fail; - } - - s_state->data_ready = xQueueCreate(16, sizeof(size_t)); - s_state->frame_ready = xSemaphoreCreateBinary(); - if (s_state->data_ready == NULL || s_state->frame_ready == NULL) { - ESP_LOGE(TAG, "Failed to create semaphores"); - err = ESP_ERR_NO_MEM; - goto fail; - } - if (!xTaskCreatePinnedToCore(&dma_filter_task, "dma_filter", 4096, NULL, 10, &s_state->dma_filter_task, 1)) { - ESP_LOGE(TAG, "Failed to create DMA filter task"); - err = ESP_ERR_NO_MEM; - goto fail; - } - - ESP_LOGD(TAG, "Initializing GPIO interrupts"); - vsync_intr_disable(); - err = gpio_isr_handler_add(s_state->config.pin_vsync, &gpio_isr, NULL); - if (err != ESP_OK) { - ESP_LOGE(TAG, "gpio_isr_handler_add failed (%x)", err); - goto fail; - } - - // skip at least one frame after changing camera settings - while (gpio_get_level(s_state->config.pin_vsync) == 0) { - ; - } - while (gpio_get_level(s_state->config.pin_vsync) != 0) { - ; - } - while (gpio_get_level(s_state->config.pin_vsync) == 0) { - ; - } - s_state->frame_count = 0; - ESP_LOGD(TAG, "Init done"); - return ESP_OK; - -fail: - camera_deinit(); - return err; -} - -esp_err_t camera_deinit() -{ - if (s_state == NULL) { - return ESP_ERR_INVALID_STATE; - } - if (s_state->dma_filter_task) { - vTaskDelete(s_state->dma_filter_task); - } - if (s_state->data_ready) { - vQueueDelete(s_state->data_ready); - } - if (s_state->frame_ready) { - vSemaphoreDelete(s_state->frame_ready); - } - gpio_isr_handler_remove(s_state->config.pin_vsync); - if (s_state->i2s_intr_handle) { - esp_intr_disable(s_state->i2s_intr_handle); - esp_intr_free(s_state->i2s_intr_handle); - } - dma_desc_deinit(); - free(s_state->fb); - free(s_state); - s_state = NULL; - camera_disable_out_clock(); - periph_module_disable(PERIPH_I2S0_MODULE); - return ESP_OK; -} - -uint8_t* camera_get_fb() -{ - if (s_state == NULL) { - return NULL; - } - return s_state->fb; -} - -int camera_get_fb_width() -{ - if (s_state == NULL) { - return 0; - } - return s_state->width; -} - -int camera_get_fb_height() -{ - if (s_state == NULL) { - return 0; - } - return s_state->height; -} - -size_t camera_get_data_size() -{ - if (s_state == NULL) { - return 0; - } - return s_state->data_size; -} - -esp_err_t camera_run() -{ - if (s_state == NULL) { - return ESP_ERR_INVALID_STATE; - } - struct timeval tv_start; - gettimeofday(&tv_start, NULL); -#ifndef _NDEBUG - memset(s_state->fb, 0, s_state->fb_size); -#endif // _NDEBUG - i2s_run(); - ESP_LOGD(TAG, "Waiting for frame"); - xSemaphoreTake(s_state->frame_ready, portMAX_DELAY); - struct timeval tv_end; - gettimeofday(&tv_end, NULL); - int time_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000; - ESP_LOGI(TAG, "Frame %d done in %d ms", s_state->frame_count, time_ms); - s_state->frame_count++; - return ESP_OK; -} - -static esp_err_t dma_desc_init() -{ - assert(s_state->width % 4 == 0); - size_t line_size = s_state->width * s_state->in_bytes_per_pixel * - i2s_bytes_per_sample(s_state->sampling_mode); - ESP_LOGD(TAG, "Line width (for DMA): %d bytes", line_size); - size_t dma_per_line = 1; - size_t buf_size = line_size; - while (buf_size >= 4096) { - buf_size /= 2; - dma_per_line *= 2; - } - size_t dma_desc_count = dma_per_line * 4; - s_state->dma_buf_width = line_size; - s_state->dma_per_line = dma_per_line; - s_state->dma_desc_count = dma_desc_count; - ESP_LOGD(TAG, "DMA buffer size: %d, DMA buffers per line: %d", buf_size, dma_per_line); - ESP_LOGD(TAG, "DMA buffer count: %d", dma_desc_count); - - s_state->dma_buf = (dma_elem_t**) malloc(sizeof(dma_elem_t*) * dma_desc_count); - if (s_state->dma_buf == NULL) { - return ESP_ERR_NO_MEM; - } - s_state->dma_desc = (lldesc_t*) malloc(sizeof(lldesc_t) * dma_desc_count); - if (s_state->dma_desc == NULL) { - return ESP_ERR_NO_MEM; - } - size_t dma_sample_count = 0; - for (int i = 0; i < dma_desc_count; ++i) { - ESP_LOGD(TAG, "Allocating DMA buffer #%d, size=%d", i, buf_size); - dma_elem_t* buf = (dma_elem_t*) malloc(buf_size); - if (buf == NULL) { - return ESP_ERR_NO_MEM; - } - s_state->dma_buf[i] = buf; - ESP_LOGV(TAG, "dma_buf[%d]=%p", i, buf); - - lldesc_t* pd = &s_state->dma_desc[i]; - pd->length = buf_size; - if (s_state->sampling_mode == SM_0A0B_0B0C && - (i + 1) % dma_per_line == 0) { - pd->length -= 4; - } - dma_sample_count += pd->length / 4; - pd->size = pd->length; - pd->owner = 1; - pd->sosf = 1; - pd->buf = (uint8_t*) buf; - pd->offset = 0; - pd->empty = 0; - pd->eof = 1; - pd->qe.stqe_next = &s_state->dma_desc[(i + 1) % dma_desc_count]; - } - s_state->dma_done = false; - s_state->dma_sample_count = dma_sample_count; - return ESP_OK; -} - -static void dma_desc_deinit() -{ - if (s_state->dma_buf) { - for (int i = 0; i < s_state->dma_desc_count; ++i) { - free(s_state->dma_buf[i]); - } - } - free(s_state->dma_buf); - free(s_state->dma_desc); -} - -static inline void i2s_conf_reset() -{ - const uint32_t lc_conf_reset_flags = I2S_IN_RST_M | I2S_AHBM_RST_M - | I2S_AHBM_FIFO_RST_M; - I2S0.lc_conf.val |= lc_conf_reset_flags; - I2S0.lc_conf.val &= ~lc_conf_reset_flags; - - const uint32_t conf_reset_flags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M - | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M; - I2S0.conf.val |= conf_reset_flags; - I2S0.conf.val &= ~conf_reset_flags; - while (I2S0.state.rx_fifo_reset_back) { - ; - } -} - -static void i2s_init() -{ - camera_config_t* config = &s_state->config; - - // Configure input GPIOs - gpio_num_t pins[] = { - config->pin_d7, - config->pin_d6, - config->pin_d5, - config->pin_d4, - config->pin_d3, - config->pin_d2, - config->pin_d1, - config->pin_d0, - config->pin_vsync, - config->pin_href, - config->pin_pclk - }; - gpio_config_t conf = { - .mode = GPIO_MODE_INPUT, - .pull_up_en = GPIO_PULLUP_ENABLE, - .pull_down_en = GPIO_PULLDOWN_DISABLE, - .intr_type = GPIO_INTR_DISABLE - }; - for (int i = 0; i < sizeof(pins) / sizeof(gpio_num_t); ++i) { - if (rtc_gpio_is_valid_gpio(pins[i])) { - rtc_gpio_deinit(pins[i]); - } - conf.pin_bit_mask = 1LL << pins[i]; - gpio_config(&conf); - } - - // Route input GPIOs to I2S peripheral using GPIO matrix - gpio_matrix_in(config->pin_d0, I2S0I_DATA_IN0_IDX, false); - gpio_matrix_in(config->pin_d1, I2S0I_DATA_IN1_IDX, false); - gpio_matrix_in(config->pin_d2, I2S0I_DATA_IN2_IDX, false); - gpio_matrix_in(config->pin_d3, I2S0I_DATA_IN3_IDX, false); - gpio_matrix_in(config->pin_d4, I2S0I_DATA_IN4_IDX, false); - gpio_matrix_in(config->pin_d5, I2S0I_DATA_IN5_IDX, false); - gpio_matrix_in(config->pin_d6, I2S0I_DATA_IN6_IDX, false); - gpio_matrix_in(config->pin_d7, I2S0I_DATA_IN7_IDX, false); - gpio_matrix_in(config->pin_vsync, I2S0I_V_SYNC_IDX, false); - gpio_matrix_in(0x38, I2S0I_H_SYNC_IDX, false); - gpio_matrix_in(config->pin_href, I2S0I_H_ENABLE_IDX, false); - gpio_matrix_in(config->pin_pclk, I2S0I_WS_IN_IDX, false); - - // Enable and configure I2S peripheral - periph_module_enable(PERIPH_I2S0_MODULE); - // Toggle some reset bits in LC_CONF register - // Toggle some reset bits in CONF register - i2s_conf_reset(); - // Enable slave mode (sampling clock is external) - I2S0.conf.rx_slave_mod = 1; - // Enable parallel mode - I2S0.conf2.lcd_en = 1; - // Use HSYNC/VSYNC/HREF to control sampling - I2S0.conf2.camera_en = 1; - // Configure clock divider - I2S0.clkm_conf.clkm_div_a = 1; - I2S0.clkm_conf.clkm_div_b = 0; - I2S0.clkm_conf.clkm_div_num = 2; - // FIFO will sink data to DMA - I2S0.fifo_conf.dscr_en = 1; - // FIFO configuration - I2S0.fifo_conf.rx_fifo_mod = s_state->sampling_mode; - I2S0.fifo_conf.rx_fifo_mod_force_en = 1; - I2S0.conf_chan.rx_chan_mod = 1; - // Clear flags which are used in I2S serial mode - I2S0.sample_rate_conf.rx_bits_mod = 0; - I2S0.conf.rx_right_first = 0; - I2S0.conf.rx_msb_right = 0; - I2S0.conf.rx_msb_shift = 0; - I2S0.conf.rx_mono = 0; - I2S0.conf.rx_short_sync = 0; - I2S0.timing.val = 0; - - // Allocate I2S interrupt, keep it disabled - esp_intr_alloc(ETS_I2S0_INTR_SOURCE, - ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, - &i2s_isr, NULL, &s_state->i2s_intr_handle); -} - - -static void i2s_stop() -{ - esp_intr_disable(s_state->i2s_intr_handle); - vsync_intr_disable(); - i2s_conf_reset(); - I2S0.conf.rx_start = 0; - size_t val = SIZE_MAX; - BaseType_t higher_priority_task_woken; - xQueueSendFromISR(s_state->data_ready, &val, &higher_priority_task_woken); -} - -static void i2s_run() -{ -#ifndef _NDEBUG - for (int i = 0; i < s_state->dma_desc_count; ++i) { - lldesc_t* d = &s_state->dma_desc[i]; - ESP_LOGV(TAG, "DMA desc %2d: %u %u %u %u %u %u %p %p", - i, d->length, d->size, d->offset, d->eof, d->sosf, d->owner, d->buf, d->qe.stqe_next); - memset(s_state->dma_buf[i], 0, d->length); - } -#endif - - // wait for vsync - ESP_LOGD(TAG, "Waiting for positive edge on VSYNC"); - while (gpio_get_level(s_state->config.pin_vsync) == 0) { - ; - } - while (gpio_get_level(s_state->config.pin_vsync) != 0) { - ; - } - ESP_LOGD(TAG, "Got VSYNC"); - - s_state->dma_done = false; - s_state->dma_desc_cur = 0; - s_state->dma_received_count = 0; - s_state->dma_filtered_count = 0; - esp_intr_disable(s_state->i2s_intr_handle); - i2s_conf_reset(); - - I2S0.rx_eof_num = s_state->dma_sample_count; - I2S0.in_link.addr = (uint32_t) &s_state->dma_desc[0]; - I2S0.in_link.start = 1; - I2S0.int_clr.val = I2S0.int_raw.val; - I2S0.int_ena.val = 0; - I2S0.int_ena.in_done = 1; - esp_intr_enable(s_state->i2s_intr_handle); - if (s_state->config.pixel_format == CAMERA_PF_JPEG) { - vsync_intr_enable(); - } - I2S0.conf.rx_start = 1; - -} - -static void IRAM_ATTR signal_dma_buf_received(bool* need_yield) -{ - size_t dma_desc_filled = s_state->dma_desc_cur; - s_state->dma_desc_cur = (dma_desc_filled + 1) % s_state->dma_desc_count; - s_state->dma_received_count++; - BaseType_t higher_priority_task_woken; - BaseType_t ret = xQueueSendFromISR(s_state->data_ready, &dma_desc_filled, &higher_priority_task_woken); - if (ret != pdTRUE) { - ESP_EARLY_LOGW(TAG, "queue send failed (%d), dma_received_count=%d", ret, s_state->dma_received_count); - } - *need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE); -} - -static void IRAM_ATTR i2s_isr(void* arg) -{ - I2S0.int_clr.val = I2S0.int_raw.val; - bool need_yield; - signal_dma_buf_received(&need_yield); - ESP_EARLY_LOGV(TAG, "isr, cnt=%d", s_state->dma_received_count); - if (s_state->dma_received_count == s_state->height * s_state->dma_per_line) { - i2s_stop(); - } - if (need_yield) { - portYIELD_FROM_ISR(); - } -} - -static void IRAM_ATTR gpio_isr(void* arg) -{ - bool need_yield = false; - ESP_EARLY_LOGV(TAG, "gpio isr, cnt=%d", s_state->dma_received_count); - if (gpio_get_level(s_state->config.pin_vsync) == 0 && - s_state->dma_received_count > 0 && - !s_state->dma_done) { - signal_dma_buf_received(&need_yield); - i2s_stop(); - } - if (need_yield) { - portYIELD_FROM_ISR(); - } -} - -static size_t get_fb_pos() -{ - return s_state->dma_filtered_count * s_state->width * - s_state->fb_bytes_per_pixel / s_state->dma_per_line; -} - -static void IRAM_ATTR dma_filter_task(void *pvParameters) -{ - while (true) { - size_t buf_idx; - xQueueReceive(s_state->data_ready, &buf_idx, portMAX_DELAY); - if (buf_idx == SIZE_MAX) { - s_state->data_size = get_fb_pos(); - xSemaphoreGive(s_state->frame_ready); - continue; - } - - size_t fb_pos = get_fb_pos(); - assert(fb_pos <= s_state->fb_size + s_state->width * - s_state->fb_bytes_per_pixel / s_state->dma_per_line); - - uint8_t* pfb = s_state->fb + fb_pos; - const dma_elem_t* buf = s_state->dma_buf[buf_idx]; - lldesc_t* desc = &s_state->dma_desc[buf_idx]; - (*s_state->dma_filter)(buf, desc, pfb); - s_state->dma_filtered_count++; - ESP_LOGV(TAG, "dma_flt: flt_count=%d ", s_state->dma_filtered_count); - } -} - -static void IRAM_ATTR dma_filter_grayscale(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) -{ - assert(s_state->sampling_mode == SM_0A0B_0C0D); - size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; - for (size_t i = 0; i < end; ++i) { - // manually unrolling 4 iterations of the loop here - dst[0] = src[0].sample1; - dst[1] = src[1].sample1; - dst[2] = src[2].sample1; - dst[3] = src[3].sample1; - src += 4; - dst += 4; - } -} - -static void IRAM_ATTR dma_filter_grayscale_highspeed(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) -{ - assert(s_state->sampling_mode == SM_0A0B_0B0C); - size_t end = dma_desc->length / sizeof(dma_elem_t) / 8; - for (size_t i = 0; i < end; ++i) { - // manually unrolling 4 iterations of the loop here - dst[0] = src[0].sample1; - dst[1] = src[2].sample1; - dst[2] = src[4].sample1; - dst[3] = src[6].sample1; - src += 8; - dst += 4; - } - // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling - if ((dma_desc->length & 0x7) != 0) { - dst[0] = src[0].sample1; - dst[1] = src[2].sample1; - } -} - -static void IRAM_ATTR dma_filter_jpeg(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) -{ - assert(s_state->sampling_mode == SM_0A0B_0B0C || - s_state->sampling_mode == SM_0A00_0B00 ); - size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; - // manually unrolling 4 iterations of the loop here - for (size_t i = 0; i < end; ++i) { - dst[0] = src[0].sample1; - dst[1] = src[1].sample1; - dst[2] = src[2].sample1; - dst[3] = src[3].sample1; - src += 4; - dst += 4; - } - // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling - if ((dma_desc->length & 0x7) != 0) { - dst[0] = src[0].sample1; - dst[1] = src[1].sample1; - dst[2] = src[2].sample1; - dst[3] = src[2].sample2; - } -} - -static inline void rgb565_to_888(uint8_t in1, uint8_t in2, uint8_t* dst) -{ - dst[0] = (in2 & 0b00011111) << 3; // blue - dst[1] = ((in1 & 0b111) << 5) | ((in2 & 0b11100000 >> 5)); // green - dst[2] = in1 & 0b11111000; // red -} - -static void IRAM_ATTR dma_filter_rgb565(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) -{ - assert(s_state->sampling_mode == SM_0A0B_0B0C || - s_state->sampling_mode == SM_0A00_0B00); - - const int unroll = 2; // manually unrolling 2 iterations of the loop - const int samples_per_pixel = 2; - const int bytes_per_pixel = 3; - size_t end = dma_desc->length / sizeof(dma_elem_t) / unroll / samples_per_pixel; - for (size_t i = 0; i < end; ++i) { - rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); - rgb565_to_888(src[2].sample1, src[3].sample1, &dst[3]); - dst += bytes_per_pixel * unroll; - src += samples_per_pixel * unroll; - } - if ((dma_desc->length & 0x7) != 0) { - rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); - rgb565_to_888(src[2].sample1, src[2].sample2, &dst[3]); - } -} diff --git a/components/camera/camera_common.h b/components/camera/camera_common.h deleted file mode 100644 index 9973dd5..0000000 --- a/components/camera/camera_common.h +++ /dev/null @@ -1,72 +0,0 @@ -#pragma once - -#include -#include -#include -#include "rom/lldesc.h" -#include "esp_err.h" -#include "esp_intr_alloc.h" -#include "freertos/FreeRTOS.h" -#include "freertos/semphr.h" -#include "freertos/task.h" -#include "camera.h" -#include "sensor.h" - -typedef union { - struct { - uint8_t sample2; - uint8_t unused2; - uint8_t sample1; - uint8_t unused1; - }; - uint32_t val; -} dma_elem_t; - -typedef enum { - /* camera sends byte sequence: s1, s2, s3, s4, ... - * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ... - */ - SM_0A0B_0B0C = 0, - /* camera sends byte sequence: s1, s2, s3, s4, ... - * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ... - */ - SM_0A0B_0C0D = 1, - /* camera sends byte sequence: s1, s2, s3, s4, ... - * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ... - */ - SM_0A00_0B00 = 3, -} i2s_sampling_mode_t; - -typedef void (*dma_filter_t)(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); - -typedef struct { - camera_config_t config; - sensor_t sensor; - uint8_t *fb; - size_t fb_size; - size_t data_size; - size_t width; - size_t height; - size_t in_bytes_per_pixel; - size_t fb_bytes_per_pixel; - size_t stride; - size_t frame_count; - - lldesc_t *dma_desc; - dma_elem_t **dma_buf; - bool dma_done; - size_t dma_desc_count; - size_t dma_desc_cur; - size_t dma_received_count; - size_t dma_filtered_count; - size_t dma_per_line; - size_t dma_buf_width; - size_t dma_sample_count; - i2s_sampling_mode_t sampling_mode; - dma_filter_t dma_filter; - intr_handle_t i2s_intr_handle; - QueueHandle_t data_ready; - SemaphoreHandle_t frame_ready; - TaskHandle_t dma_filter_task; -} camera_state_t; - diff --git a/components/camera/component.mk b/components/camera/component.mk index e69de29..cd11e2a 100644 --- a/components/camera/component.mk +++ b/components/camera/component.mk @@ -0,0 +1 @@ +COMPONENT_ADD_INCLUDEDIRS := . include diff --git a/components/camera/include/camera.h b/components/camera/include/camera.h deleted file mode 100644 index 4b10be8..0000000 --- a/components/camera/include/camera.h +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2015-2016 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. - -#pragma once - -#include "esp_err.h" -#include "driver/ledc.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - CAMERA_PF_RGB565 = 0, //!< RGB, 2 bytes per pixel (not implemented) - CAMERA_PF_YUV422 = 1, //!< YUYV, 2 bytes per pixel (not implemented) - CAMERA_PF_GRAYSCALE = 2, //!< 1 byte per pixel - CAMERA_PF_JPEG = 3, //!< JPEG compressed -} camera_pixelformat_t; - -typedef enum { - CAMERA_FS_QQVGA = 4, //!< 160x120 - CAMERA_FS_QVGA = 8, //!< 320x240 - CAMERA_FS_VGA = 10, //!< 640x480 - CAMERA_FS_SVGA = 11, //!< 800x600 -} camera_framesize_t; - -typedef enum { - CAMERA_NONE = 0, - CAMERA_UNKNOWN = 1, - CAMERA_OV7725 = 7725, - CAMERA_OV2640 = 2640, -} camera_model_t; - -typedef struct { - 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 */ - 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 */ - int pin_d4; /*!< GPIO pin for camera D4 line */ - int pin_d3; /*!< GPIO pin for camera D3 line */ - int pin_d2; /*!< GPIO pin for camera D2 line */ - int pin_d1; /*!< GPIO pin for camera D1 line */ - int pin_d0; /*!< GPIO pin for camera D0 line */ - int pin_vsync; /*!< GPIO pin for camera VSYNC line */ - int pin_href; /*!< GPIO pin for camera HREF line */ - int pin_pclk; /*!< GPIO pin for camera PCLK line */ - - int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz */ - - ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */ - ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */ - - camera_pixelformat_t pixel_format; - camera_framesize_t frame_size; - - int jpeg_quality; -} camera_config_t; - -#define ESP_ERR_CAMERA_BASE 0x20000 -#define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1) -#define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2) -#define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 3) - -/** - * @brief Probe the camera - * This function enables LEDC peripheral to generate XCLK signal, - * detects the camera I2C address and detects camera model. - * - * @param config camera configuration parameters - * @param[out] out_camera_model output, detected camera model - * @return ESP_OK if camera was detected - */ -esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera_model); - -/** - * @brief Initialize the camera driver - * - * @note call camera_probe before calling this function - * - * This function configures camera over I2C interface, - * allocates framebuffer and DMA buffers, - * initializes parallel I2S input, and sets up DMA descriptors. - * - * Currently this function can only be called once and there is - * no way to de-initialize this module. - * - * @param config Camera configuration parameters - * @return ESP_OK on success - */ -esp_err_t camera_init(const camera_config_t* config); - -/** - * Deinitialize the camera driver - * - * @return - * - ESP_OK on success - * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet - */ -esp_err_t camera_deinit(); - -/** - * @brief Obtain the pointer to framebuffer allocated by camera_init function. - * - * @return pointer to framebuffer - */ -uint8_t* camera_get_fb(); - -/** - * @brief Return the size of valid data in the framebuffer - * - * For grayscale mode, this function returns width * height of the framebuffer. - * For JPEG mode, this function returns the actual size of encoded JPEG image. - * @return size of valid data in framebuffer, in bytes - */ -size_t camera_get_data_size(); - -/** - * @brief Get the width of framebuffer, in pixels. - * @return width of framebuffer, in pixels - */ -int camera_get_fb_width(); - -/** - * @brief Get the height of framebuffer, in pixels. - * @return height of framebuffer, in pixels - */ -int camera_get_fb_height(); - -/** - * @brief Acquire one frame and store it into framebuffer - * - * This function waits for the next VSYNC, starts DMA to get data from camera, - * and blocks until all lines of the image are stored into the framebuffer. - * Once all lines are stored, the function returns. - * - * @return ESP_OK on success - */ -esp_err_t camera_run(); - -/** - * @brief Print contents of framebuffer on terminal - * - */ -void camera_print_fb(); - - -#ifdef __cplusplus -} -#endif diff --git a/components/camera/ov2640.c b/components/camera/ov2640.c deleted file mode 100644 index 9e80385..0000000 --- a/components/camera/ov2640.c +++ /dev/null @@ -1,743 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV2640 driver. - * - */ -#include -#include -#include -#include "sccb.h" -#include "ov2640.h" -#include "ov2640_regs.h" - -#define SVGA_HSIZE (800) -#define SVGA_VSIZE (600) - -#define UXGA_HSIZE (1600) -#define UXGA_VSIZE (1200) - -static const uint8_t default_regs[][2] = { - { BANK_SEL, BANK_SEL_DSP }, - { 0x2c, 0xff }, - { 0x2e, 0xdf }, - { BANK_SEL, BANK_SEL_SENSOR }, - { 0x3c, 0x32 }, - { CLKRC, 0x80 }, /* Set PCLK divider */ - { COM2, COM2_OUT_DRIVE_3x }, /* Output drive x2 */ -#ifdef OPENMV2 - { REG04, 0xF8}, /* Mirror/VFLIP/AEC[1:0] */ -#else - { REG04_SET(REG04_HREF_EN)}, -#endif - { COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) }, - { COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, - {COM10, 0}, //Invert VSYNC - { 0x2c, 0x0c }, - { 0x33, 0x78 }, - { 0x3a, 0x33 }, - { 0x3b, 0xfb }, - { 0x3e, 0x00 }, - { 0x43, 0x11 }, - { 0x16, 0x10 }, - { 0x39, 0x02 }, - { 0x35, 0x88 }, - { 0x22, 0x0a }, - { 0x37, 0x40 }, - { 0x23, 0x00 }, - { ARCOM2, 0xa0 }, - { 0x06, 0x02 }, - { 0x06, 0x88 }, - { 0x07, 0xc0 }, - { 0x0d, 0xb7 }, - { 0x0e, 0x01 }, - { 0x4c, 0x00 }, - { 0x4a, 0x81 }, - { 0x21, 0x99 }, - { AEW, 0x40 }, - { AEB, 0x38 }, - /* AGC/AEC fast mode operating region */ - { VV, VV_AGC_TH_SET(0x08, 0x02) }, - { COM19, 0x00 }, /* Zoom control 2 MSBs */ - { ZOOMS, 0x00 }, /* Zoom control 8 MSBs */ - { 0x5c, 0x00 }, - { 0x63, 0x00 }, - { FLL, 0x00 }, - { FLH, 0x00 }, - - /* Set banding filter */ - { COM3, COM3_BAND_SET(COM3_BAND_AUTO) }, - { REG5D, 0x55 }, - { REG5E, 0x7d }, - { REG5F, 0x7d }, - { REG60, 0x55 }, - { HISTO_LOW, 0x70 }, - { HISTO_HIGH, 0x80 }, - { 0x7c, 0x05 }, - { 0x20, 0x80 }, - { 0x28, 0x30 }, - { 0x6c, 0x00 }, - { 0x6d, 0x80 }, - { 0x6e, 0x00 }, - { 0x70, 0x02 }, - { 0x71, 0x94 }, - { 0x73, 0xc1 }, - { 0x3d, 0x34 }, - //{ COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, - { 0x5a, 0x57 }, - { BD50, 0xbb }, - { BD60, 0x9c }, - - { BANK_SEL, BANK_SEL_DSP }, - { 0xe5, 0x7f }, - { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, - { 0x41, 0x24 }, - { RESET, RESET_JPEG | RESET_DVP }, - { 0x76, 0xff }, - { 0x33, 0xa0 }, - { 0x42, 0x20 }, - { 0x43, 0x18 }, - { 0x4c, 0x00 }, - { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, - { 0x88, 0x3f }, - { 0xd7, 0x03 }, - { 0xd9, 0x10 }, - { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, - { 0xc8, 0x08 }, - { 0xc9, 0x80 }, - { BPADDR, 0x00 }, - { BPDATA, 0x00 }, - { BPADDR, 0x03 }, - { BPDATA, 0x48 }, - { BPDATA, 0x48 }, - { BPADDR, 0x08 }, - { BPDATA, 0x20 }, - { BPDATA, 0x10 }, - { BPDATA, 0x0e }, - { 0x90, 0x00 }, - { 0x91, 0x0e }, - { 0x91, 0x1a }, - { 0x91, 0x31 }, - { 0x91, 0x5a }, - { 0x91, 0x69 }, - { 0x91, 0x75 }, - { 0x91, 0x7e }, - { 0x91, 0x88 }, - { 0x91, 0x8f }, - { 0x91, 0x96 }, - { 0x91, 0xa3 }, - { 0x91, 0xaf }, - { 0x91, 0xc4 }, - { 0x91, 0xd7 }, - { 0x91, 0xe8 }, - { 0x91, 0x20 }, - { 0x92, 0x00 }, - { 0x93, 0x06 }, - { 0x93, 0xe3 }, - { 0x93, 0x03 }, - { 0x93, 0x03 }, - { 0x93, 0x00 }, - { 0x93, 0x02 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x93, 0x00 }, - { 0x96, 0x00 }, - { 0x97, 0x08 }, - { 0x97, 0x19 }, - { 0x97, 0x02 }, - { 0x97, 0x0c }, - { 0x97, 0x24 }, - { 0x97, 0x30 }, - { 0x97, 0x28 }, - { 0x97, 0x26 }, - { 0x97, 0x02 }, - { 0x97, 0x98 }, - { 0x97, 0x80 }, - { 0x97, 0x00 }, - { 0x97, 0x00 }, - { 0xa4, 0x00 }, - { 0xa8, 0x00 }, - { 0xc5, 0x11 }, - { 0xc6, 0x51 }, - { 0xbf, 0x80 }, - { 0xc7, 0x10 }, - { 0xb6, 0x66 }, - { 0xb8, 0xA5 }, - { 0xb7, 0x64 }, - { 0xb9, 0x7C }, - { 0xb3, 0xaf }, - { 0xb4, 0x97 }, - { 0xb5, 0xFF }, - { 0xb0, 0xC5 }, - { 0xb1, 0x94 }, - { 0xb2, 0x0f }, - { 0xc4, 0x5c }, - { 0xa6, 0x00 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x1b }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x19 }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0xa7, 0x20 }, - { 0xa7, 0xd8 }, - { 0xa7, 0x19 }, - { 0xa7, 0x31 }, - { 0xa7, 0x00 }, - { 0xa7, 0x18 }, - { 0x7f, 0x00 }, - { 0xe5, 0x1f }, - { 0xe1, 0x77 }, - { 0xdd, 0x7f }, - { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, - { 0x00, 0x00 } -}; - -static const uint8_t cif_regs[][2] = { -}; - -static const uint8_t svga_regs[][2] = { - { BANK_SEL, BANK_SEL_SENSOR }, - /* DSP input image resoultion and window size control */ - { COM7, COM7_RES_SVGA}, - { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ - { REG32, 0x09 }, /* UXGA=0x36, SVGA/CIF=0x09 */ - - { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ - { HSTOP, 0x43 }, /* UXGA=0x75, SVGA/CIF=0x43 */ - - { VSTART, 0x00 }, /* UXGA=0x01, SVGA/CIF=0x00 */ - { VSTOP, 0x4b }, /* UXGA=0x97, SVGA/CIF=0x4b */ - { 0x3d, 0x38 }, /* UXGA=0x34, SVGA/CIF=0x38 */ - - { 0x35, 0xda }, - { 0x22, 0x1a }, - { 0x37, 0xc3 }, - { 0x34, 0xc0 }, - { 0x06, 0x88 }, - { 0x0d, 0x87 }, - { 0x0e, 0x41 }, - { 0x42, 0x03 }, - - /* Set DSP input image size and offset. - The sensor output image can be scaled with OUTW/OUTH */ - { BANK_SEL, BANK_SEL_DSP }, - { R_BYPASS, R_BYPASS_DSP_BYPAS }, - - { RESET, RESET_DVP }, - { HSIZE8, (SVGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ - { VSIZE8, (SVGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ - - /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ - { SIZEL, ((SVGA_HSIZE>>6)&0x40) | ((SVGA_HSIZE&0x7)<<3) | (SVGA_VSIZE&0x7)}, - - { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ - { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ - { HSIZE, ((SVGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0]= HSIZE/4 */ - { VSIZE, ((SVGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0]= VSIZE/4 */ - - /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ - { VHYX, ((SVGA_VSIZE>>3)&0x80) | ((SVGA_HSIZE>>7)&0x08) }, - { TEST, (SVGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ - - { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | - CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, - - /* H_DIVIDER/V_DIVIDER */ - { CTRLI, CTRLI_LP_DP | 0x00}, - /* DVP prescalar */ - { R_DVP_SP, R_DVP_SP_AUTO_MODE}, - - { R_BYPASS, R_BYPASS_DSP_EN }, - { RESET, 0x00 }, - {0, 0}, -}; - -static const uint8_t uxga_regs[][2] = { - { BANK_SEL, BANK_SEL_SENSOR }, - /* DSP input image resoultion and window size control */ - { COM7, COM7_RES_UXGA}, - { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ - { REG32, 0x36 }, /* UXGA=0x36, SVGA/CIF=0x09 */ - - { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ - { HSTOP, 0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */ - - { VSTART, 0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */ - { VSTOP, 0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */ - { 0x3d, 0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */ - - { 0x35, 0x88 }, - { 0x22, 0x0a }, - { 0x37, 0x40 }, - { 0x34, 0xa0 }, - { 0x06, 0x02 }, - { 0x0d, 0xb7 }, - { 0x0e, 0x01 }, - { 0x42, 0x83 }, - - /* Set DSP input image size and offset. - The sensor output image can be scaled with OUTW/OUTH */ - { BANK_SEL, BANK_SEL_DSP }, - { R_BYPASS, R_BYPASS_DSP_BYPAS }, - - { RESET, RESET_DVP }, - { HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ - { VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ - - /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ - { SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)}, - - { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ - { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ - { HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */ - { VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */ - - /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ - { VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) }, - { TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ - - { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | - CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, - - /* H_DIVIDER/V_DIVIDER */ - { CTRLI, CTRLI_LP_DP | 0x00}, - /* DVP prescalar */ - { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04}, - - { R_BYPASS, R_BYPASS_DSP_EN }, - { RESET, 0x00 }, - {0, 0}, -}; - -static const uint8_t yuv422_regs[][2] = { - { BANK_SEL, BANK_SEL_DSP }, - { RESET, RESET_DVP}, - { IMAGE_MODE, IMAGE_MODE_YUV422 }, - { 0xD7, 0x01 }, - { 0xE1, 0x67 }, - { RESET, 0x00 }, - {0, 0}, -}; - -static const uint8_t rgb565_regs[][2] = { - { BANK_SEL, BANK_SEL_DSP }, - { RESET, RESET_DVP}, - { IMAGE_MODE, IMAGE_MODE_RGB565 }, - { 0xD7, 0x03 }, - { 0xE1, 0x77 }, - { RESET, 0x00 }, - {0, 0}, -}; - -static const uint8_t jpeg_regs[][2] = { - { BANK_SEL, BANK_SEL_DSP }, - { RESET, RESET_DVP}, - { IMAGE_MODE, IMAGE_MODE_JPEG_EN|IMAGE_MODE_RGB565 }, - { 0xD7, 0x03 }, - { 0xE1, 0x77 }, - { QS, 0x0C }, - { RESET, 0x00 }, - {0, 0}, -}; - -//|IMAGE_MODE_HREF_VSYNC - -#define NUM_BRIGHTNESS_LEVELS (5) -static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { - { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, - { 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ - { 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ - { 0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ - { 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ - { 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ -}; - -#define NUM_CONTRAST_LEVELS (5) -static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { - { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA }, - { 0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ - { 0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ - { 0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ - { 0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ - { 0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ -}; - -#define NUM_SATURATION_LEVELS (5) -static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { - { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, - { 0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */ - { 0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */ - { 0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */ - { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */ - { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +2 */ -}; - -static int reset(sensor_t *sensor) -{ - int i=0; - const uint8_t (*regs)[2]; - - /* Reset all registers */ - SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - SCCB_Write(sensor->slv_addr, COM7, COM7_SRST); - - /* delay n ms */ - delay(10); - - i = 0; - regs = default_regs; - /* Write initial regsiters */ - while (regs[i][0]) { - SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); - i++; - } - - i = 0; - regs = svga_regs; - /* Write DSP input regsiters */ - while (regs[i][0]) { - SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); - i++; - } - - return 0; -} - -static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) -{ - int i=0; - const uint8_t (*regs)[2]=NULL; - - /* read pixel format reg */ - switch (pixformat) { - case PIXFORMAT_RGB565: - regs = rgb565_regs; - break; - case PIXFORMAT_YUV422: - case PIXFORMAT_GRAYSCALE: - regs = yuv422_regs; - break; - case PIXFORMAT_JPEG: - regs = jpeg_regs; - break; - default: - return -1; - } - - /* Write initial regsiters */ - while (regs[i][0]) { - SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); - i++; - } - - /* delay n ms */ - delay(30); - - return 0; -} - -static int set_framesize(sensor_t *sensor, framesize_t framesize) -{ - int ret=0; - uint8_t clkrc; - uint16_t w = resolution[framesize][0]; - uint16_t h = resolution[framesize][1]; - - int i=0; - const uint8_t (*regs)[2]; - - if (framesize <= FRAMESIZE_SVGA) { - clkrc =0x83; - regs = svga_regs; - } else { - clkrc =0x87; - regs = uxga_regs; - } - - /* Disable DSP */ - - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_BYPAS); - - /* Write output width */ - ret |= SCCB_Write(sensor->slv_addr, ZMOW, (w>>2)&0xFF); // OUTW[7:0] (real/4) - ret |= SCCB_Write(sensor->slv_addr, ZMOH, (h>>2)&0xFF); // OUTH[7:0] (real/4) - ret |= SCCB_Write(sensor->slv_addr, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); // OUTH[8]/OUTW[9:8] - - /* Set CLKRC */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - ret |= SCCB_Write(sensor->slv_addr, CLKRC, clkrc); - - /* Write DSP input regsiters */ - while (regs[i][0]) { - SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); - i++; - } - - /* Enable DSP */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_EN); - /* delay n ms */ - delay(30); - - return ret; -} - -static int set_framerate(sensor_t *sensor, framerate_t framerate) -{ - return 0; -} - -static int set_contrast(sensor_t *sensor, int level) -{ - int ret=0; - - level += (NUM_CONTRAST_LEVELS / 2 + 1); - if (level < 0 || level > NUM_CONTRAST_LEVELS) { - return -1; - } - - /* Switch to DSP register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - - /* Write contrast registers */ - for (int i=0; islv_addr, contrast_regs[0][i], contrast_regs[level][i]); - } - - return ret; -} - -static int set_brightness(sensor_t *sensor, int level) -{ - int ret=0; - - level += (NUM_BRIGHTNESS_LEVELS / 2 + 1); - if (level < 0 || level > NUM_BRIGHTNESS_LEVELS) { - return -1; - } - - /* Switch to DSP register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - - /* Write brightness registers */ - for (int i=0; islv_addr, brightness_regs[0][i], brightness_regs[level][i]); - } - - return ret; -} - -static int set_saturation(sensor_t *sensor, int level) -{ - int ret=0; - - level += (NUM_SATURATION_LEVELS / 2 + 1); - if (level < 0 || level > NUM_SATURATION_LEVELS) { - return -1; - } - - /* Switch to DSP register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - - /* Write contrast registers */ - for (int i=0; islv_addr, saturation_regs[0][i], saturation_regs[level][i]); - } - - return ret; -} - -static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) -{ - int ret =0; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Write gain ceiling register */ - ret |= SCCB_Write(sensor->slv_addr, COM9, COM9_AGC_SET(gainceiling)); - - return ret; -} - -static int set_quality(sensor_t *sensor, int qs) -{ - int ret=0; - - /* Switch to DSP register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - - /* Write QS register */ - ret |= SCCB_Write(sensor->slv_addr, QS, qs); - - return ret; -} - -static int set_colorbar(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Update COM7 */ - reg = SCCB_Read(sensor->slv_addr, COM7); - - if (enable) { - reg |= COM7_COLOR_BAR; - } else { - reg &= ~COM7_COLOR_BAR; - } - - ret |= SCCB_Write(sensor->slv_addr, COM7, reg); - return ret; -} - -static int set_whitebal(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); - - /* Update CTRL1 */ - reg = SCCB_Read(sensor->slv_addr, CTRL1); - - if (enable) { - reg |= CTRL1_AWB; - } else { - reg &= ~CTRL1_AWB; - } - - ret |= SCCB_Write(sensor->slv_addr, CTRL1, reg); - return ret; -} - -static int set_gain_ctrl(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Update COM8 */ - reg = SCCB_Read(sensor->slv_addr, COM8); - - if (enable) { - reg |= COM8_AGC_EN; - } else { - reg &= ~COM8_AGC_EN; - } - - ret |= SCCB_Write(sensor->slv_addr, COM8, reg); - return ret; -} - -static int set_exposure_ctrl(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Update COM8 */ - reg = SCCB_Read(sensor->slv_addr, COM8); - - if (enable) { - reg |= COM8_AEC_EN; - } else { - reg &= ~COM8_AEC_EN; - } - - ret |= SCCB_Write(sensor->slv_addr, COM8, reg); - return ret; -} - -static int set_hmirror(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Update REG04 */ - reg = SCCB_Read(sensor->slv_addr, REG04); - - if (enable) { - reg |= REG04_HFLIP_IMG; - } else { - reg &= ~REG04_HFLIP_IMG; - } - - ret |= SCCB_Write(sensor->slv_addr, REG04, reg); - return ret; -} - -static int set_vflip(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - /* Switch to SENSOR register bank */ - ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); - - /* Update REG04 */ - reg = SCCB_Read(sensor->slv_addr, REG04); - - if (enable) { - reg |= REG04_VFLIP_IMG; - } else { - reg &= ~REG04_VFLIP_IMG; - } - - ret |= SCCB_Write(sensor->slv_addr, REG04, reg); - return ret; -} - -int ov2640_init(sensor_t *sensor) -{ - /* set function pointers */ - sensor->reset = reset; - sensor->set_pixformat = set_pixformat; - sensor->set_framesize = set_framesize; - sensor->set_framerate = set_framerate; - sensor->set_contrast = set_contrast; - sensor->set_brightness= set_brightness; - sensor->set_saturation= set_saturation; - sensor->set_gainceiling = set_gainceiling; - sensor->set_quality = set_quality; - sensor->set_colorbar = set_colorbar; - sensor->set_gain_ctrl = set_gain_ctrl; - sensor->set_exposure_ctrl = set_exposure_ctrl; - sensor->set_whitebal = set_whitebal; - sensor->set_hmirror = set_hmirror; - sensor->set_vflip = set_vflip; - - // Set sensor flags - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); - - return 0; -} diff --git a/components/camera/ov2640.h b/components/camera/ov2640.h deleted file mode 100644 index a890499..0000000 --- a/components/camera/ov2640.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV2640 driver. - * - */ -#ifndef __OV2640_H__ -#define __OV2640_H__ -#include "sensor.h" -int ov2640_init(sensor_t *sensor); -#endif // __OV2640_H__ diff --git a/components/camera/ov2640_regs.h b/components/camera/ov2640_regs.h deleted file mode 100644 index 264340a..0000000 --- a/components/camera/ov2640_regs.h +++ /dev/null @@ -1,208 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV2640 register definitions. - */ -#ifndef __REG_REGS_H__ -#define __REG_REGS_H__ -/* DSP register bank FF=0x00*/ -#define QS 0x44 -#define HSIZE 0x51 -#define VSIZE 0x52 -#define XOFFL 0x53 -#define YOFFL 0x54 -#define VHYX 0x55 -#define DPRP 0x56 -#define TEST 0x57 -#define ZMOW 0x5A -#define ZMOH 0x5B -#define ZMHH 0x5C -#define BPADDR 0x7C -#define BPDATA 0x7D -#define SIZEL 0x8C -#define HSIZE8 0xC0 -#define VSIZE8 0xC1 -#define CTRL1 0xC3 -#define MS_SP 0xF0 -#define SS_ID 0xF7 -#define SS_CTRL 0xF7 -#define MC_AL 0xFA -#define MC_AH 0xFB -#define MC_D 0xFC -#define P_CMD 0xFD -#define P_STATUS 0xFE - -#define CTRLI 0x50 -#define CTRLI_LP_DP 0x80 -#define CTRLI_ROUND 0x40 - -#define CTRL0 0xC2 -#define CTRL0_AEC_EN 0x80 -#define CTRL0_AEC_SEL 0x40 -#define CTRL0_STAT_SEL 0x20 -#define CTRL0_VFIRST 0x10 -#define CTRL0_YUV422 0x08 -#define CTRL0_YUV_EN 0x04 -#define CTRL0_RGB_EN 0x02 -#define CTRL0_RAW_EN 0x01 - -#define CTRL2 0x86 -#define CTRL2_DCW_EN 0x20 -#define CTRL2_SDE_EN 0x10 -#define CTRL2_UV_ADJ_EN 0x08 -#define CTRL2_UV_AVG_EN 0x04 -#define CTRL2_CMX_EN 0x01 - -#define CTRL3 0x87 -#define CTRL3_BPC_EN 0x80 -#define CTRL3_WPC_EN 0x40 -#define R_DVP_SP 0xD3 -#define R_DVP_SP_AUTO_MODE 0x80 - -#define R_BYPASS 0x05 -#define R_BYPASS_DSP_EN 0x00 -#define R_BYPASS_DSP_BYPAS 0x01 - -#define IMAGE_MODE 0xDA -#define IMAGE_MODE_Y8_DVP_EN 0x40 -#define IMAGE_MODE_JPEG_EN 0x10 -#define IMAGE_MODE_YUV422 0x00 -#define IMAGE_MODE_RAW10 0x04 -#define IMAGE_MODE_RGB565 0x08 -#define IMAGE_MODE_HREF_VSYNC 0x02 -#define IMAGE_MODE_LBYTE_FIRST 0x01 - -#define RESET 0xE0 -#define RESET_MICROC 0x40 -#define RESET_SCCB 0x20 -#define RESET_JPEG 0x10 -#define RESET_DVP 0x04 -#define RESET_IPU 0x02 -#define RESET_CIF 0x01 - -#define MC_BIST 0xF9 -#define MC_BIST_RESET 0x80 -#define MC_BIST_BOOT_ROM_SEL 0x40 -#define MC_BIST_12KB_SEL 0x20 -#define MC_BIST_12KB_MASK 0x30 -#define MC_BIST_512KB_SEL 0x08 -#define MC_BIST_512KB_MASK 0x0C -#define MC_BIST_BUSY_BIT_R 0x02 -#define MC_BIST_MC_RES_ONE_SH_W 0x02 -#define MC_BIST_LAUNCH 0x01 - -#define BANK_SEL 0xFF -#define BANK_SEL_DSP 0x00 -#define BANK_SEL_SENSOR 0x01 - -/* Sensor register bank FF=0x01*/ -#define GAIN 0x00 -#define COM1 0x03 -#define REG_PID 0x0A -#define REG_VER 0x0B -#define COM4 0x0D -#define AEC 0x10 -#define CLKRC 0x11 -#define COM10 0x15 -#define HSTART 0x17 -#define HSTOP 0x18 -#define VSTART 0x19 -#define VSTOP 0x1A -#define MIDH 0x1C -#define MIDL 0x1D -#define AEW 0x24 -#define AEB 0x25 -#define REG2A 0x2A -#define FRARL 0x2B -#define ADDVSL 0x2D -#define ADDVSH 0x2E -#define YAVG 0x2F -#define HSDY 0x30 -#define HEDY 0x31 -#define ARCOM2 0x34 -#define REG45 0x45 -#define FLL 0x46 -#define FLH 0x47 -#define COM19 0x48 -#define ZOOMS 0x49 -#define COM22 0x4B -#define COM25 0x4E -#define BD50 0x4F -#define BD60 0x50 -#define REG5D 0x5D -#define REG5E 0x5E -#define REG5F 0x5F -#define REG60 0x60 -#define HISTO_LOW 0x61 -#define HISTO_HIGH 0x62 - -#define REG04 0x04 -#define REG04_DEFAULT 0x28 -#define REG04_HFLIP_IMG 0x80 -#define REG04_VFLIP_IMG 0x40 -#define REG04_VREF_EN 0x10 -#define REG04_HREF_EN 0x08 -#define REG04_SET(x) (REG04_DEFAULT|x) - -#define REG08 0x08 -#define COM2 0x09 -#define COM2_STDBY 0x10 -#define COM2_OUT_DRIVE_1x 0x00 -#define COM2_OUT_DRIVE_2x 0x01 -#define COM2_OUT_DRIVE_3x 0x02 -#define COM2_OUT_DRIVE_4x 0x03 - -#define COM3 0x0C -#define COM3_DEFAULT 0x38 -#define COM3_BAND_50Hz 0x04 -#define COM3_BAND_60Hz 0x00 -#define COM3_BAND_AUTO 0x02 -#define COM3_BAND_SET(x) (COM3_DEFAULT|x) - -#define COM7 0x12 -#define COM7_SRST 0x80 -#define COM7_RES_UXGA 0x00 /* UXGA */ -#define COM7_RES_SVGA 0x40 /* SVGA */ -#define COM7_RES_CIF 0x20 /* CIF */ -#define COM7_ZOOM_EN 0x04 /* Enable Zoom */ -#define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ - -#define COM8 0x13 -#define COM8_DEFAULT 0xC0 -#define COM8_BNDF_EN 0x20 /* Enable Banding filter */ -#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ -#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ -#define COM8_SET(x) (COM8_DEFAULT|x) - -#define COM9 0x14 /* AGC gain ceiling */ -#define COM9_DEFAULT 0x08 -#define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ -#define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ -#define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ -#define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ -#define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ -#define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ -#define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ -#define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) - -#define COM10 0x15 -#define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */ -#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ -#define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */ -#define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */ -#define COM10_HREF_NEG 0x08 /* HREF negative */ -#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ -#define COM10_HSYNC_NEG 0x01 /* HSYNC negative */ - -#define CTRL1_AWB 0x08 /* Enable AWB */ - -#define VV 0x26 -#define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) - -#define REG32 0x32 -#define REG32_UXGA 0x36 -#define REG32_SVGA 0x09 -#define REG32_CIF 0x00 -#endif //__REG_REGS_H__ diff --git a/components/camera/ov7725.c b/components/camera/ov7725.c deleted file mode 100644 index ed5284d..0000000 --- a/components/camera/ov7725.c +++ /dev/null @@ -1,310 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV7725 driver. - * - */ -#include -#include -#include -#include "sccb.h" -#include "ov7725.h" -#include "ov7725_regs.h" -#include - -static const uint8_t default_regs[][2] = { - {COM3, COM3_SWAP_YUV}, - {COM7, COM7_RES_QVGA | COM7_FMT_YUV}, - - {COM4, 0x01}, /* bypass PLL */ - {CLKRC, 0xC0}, /* Res/Bypass pre-scalar */ - - // QVGA Window Size - {HSTART, 0x3F}, - {HSIZE, 0x50}, - {VSTART, 0x03}, - {VSIZE, 0x78}, - {HREF, 0x00}, - - // Scale down to QVGA Resolution - {HOUTSIZE, 0x50}, - {VOUTSIZE, 0x78}, - - {COM12, 0x03}, - {EXHCH, 0x00}, - {TGT_B, 0x7F}, - {FIXGAIN, 0x09}, - {AWB_CTRL0, 0xE0}, - {DSP_CTRL1, 0xFF}, - - {DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN}, - - {DSP_CTRL3, 0x00}, - {DSP_CTRL4, 0x00}, - {DSPAUTO, 0xFF}, - - {COM8, 0xF0}, - {COM6, 0xC5}, - {COM9, 0x11}, - {COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK - {BDBASE, 0x7F}, - {DBSTEP, 0x03}, - {AEW, 0x96}, - {AEB, 0x64}, - {VPT, 0xA1}, - {EXHCL, 0x00}, - {AWB_CTRL3, 0xAA}, - {COM8, 0xFF}, - - //Gamma - {GAM1, 0x0C}, - {GAM2, 0x16}, - {GAM3, 0x2A}, - {GAM4, 0x4E}, - {GAM5, 0x61}, - {GAM6, 0x6F}, - {GAM7, 0x7B}, - {GAM8, 0x86}, - {GAM9, 0x8E}, - {GAM10, 0x97}, - {GAM11, 0xA4}, - {GAM12, 0xAF}, - {GAM13, 0xC5}, - {GAM14, 0xD7}, - {GAM15, 0xE8}, - - {SLOP, 0x20}, - {EDGE1, 0x05}, - {EDGE2, 0x03}, - {EDGE3, 0x00}, - {DNSOFF, 0x01}, - - {MTX1, 0xB0}, - {MTX2, 0x9D}, - {MTX3, 0x13}, - {MTX4, 0x16}, - {MTX5, 0x7B}, - {MTX6, 0x91}, - {MTX_CTRL, 0x1E}, - - {BRIGHTNESS, 0x08}, - {CONTRAST, 0x30}, - {UVADJ0, 0x81}, - {SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)}, - - // For 30 fps/60Hz - {DM_LNL, 0x00}, - {DM_LNH, 0x00}, - {BDBASE, 0x7F}, - {DBSTEP, 0x03}, - - // Lens Correction, should be tuned with real camera module - {LC_RADI, 0x10}, - {LC_COEF, 0x10}, - {LC_COEFB, 0x14}, - {LC_COEFR, 0x17}, - {LC_CTR, 0x05}, - {COM5, 0xF5}, //0x65 - - {0x00, 0x00}, -}; - - -static int reset(sensor_t *sensor) -{ - int i=0; - const uint8_t (*regs)[2]; - - // Reset all registers - SCCB_Write(sensor->slv_addr, COM7, COM7_RESET); - - // Delay 10 ms - systick_sleep(10); - - // Write default regsiters - for (i=0, regs = default_regs; regs[i][0]; i++) { - SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); - } - - // Delay - systick_sleep(30); - - return 0; -} - - -static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) -{ - int ret=0; - // Read register COM7 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM7); - - switch (pixformat) { - case PIXFORMAT_RGB565: - reg = COM7_SET_FMT(reg, COM7_FMT_RGB) | COM7_FMT_RGB565; - break; - case PIXFORMAT_YUV422: - case PIXFORMAT_GRAYSCALE: - reg = COM7_SET_FMT(reg, COM7_FMT_YUV); - break; - default: - return -1; - } - - // Write back register COM7 - ret = SCCB_Write(sensor->slv_addr, COM7, reg); - - // Delay - systick_sleep(30); - - return ret; -} - -static int set_framesize(sensor_t *sensor, framesize_t framesize) -{ - int ret=0; - uint16_t w = resolution[framesize][0]; - uint16_t h = resolution[framesize][1]; - - // Write MSBs - ret |= SCCB_Write(sensor->slv_addr, HOUTSIZE, w>>2); - ret |= SCCB_Write(sensor->slv_addr, VOUTSIZE, h>>1); - - // Write LSBs - ret |= SCCB_Write(sensor->slv_addr, EXHCH, ((w&0x3) | ((h&0x1) << 2))); - - if (framesize < FRAMESIZE_VGA) { - // Enable auto-scaling/zooming factors - ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xFF); - } else { - // Disable auto-scaling/zooming factors - ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xF3); - - // Clear auto-scaling/zooming factors - ret |= SCCB_Write(sensor->slv_addr, SCAL0, 0x00); - ret |= SCCB_Write(sensor->slv_addr, SCAL1, 0x00); - ret |= SCCB_Write(sensor->slv_addr, SCAL2, 0x00); - } - - // Delay - systick_sleep(30); - - if (ret == 0) { - sensor->framesize = framesize; - } - - return ret; -} - -static int set_colorbar(sensor_t *sensor, int enable) -{ - int ret=0; - uint8_t reg; - - // Read reg COM3 - reg = SCCB_Read(sensor->slv_addr, COM3); - // Enable colorbar test pattern output - reg = COM3_SET_CBAR(reg, enable); - // Write back COM3 - ret |= SCCB_Write(sensor->slv_addr, COM3, reg); - - // Read reg DSP_CTRL3 - reg = SCCB_Read(sensor->slv_addr, DSP_CTRL3); - // Enable DSP colorbar output - reg = DSP_CTRL3_SET_CBAR(reg, enable); - // Write back DSP_CTRL3 - ret |= SCCB_Write(sensor->slv_addr, DSP_CTRL3, reg); - - return ret; -} - -static int set_whitebal(sensor_t *sensor, int enable) -{ - // Read register COM8 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); - - // Set white bal on/off - reg = COM8_SET_AWB(reg, enable); - - // Write back register COM8 - return SCCB_Write(sensor->slv_addr, COM8, reg); -} - -static int set_gain_ctrl(sensor_t *sensor, int enable) -{ - // Read register COM8 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); - - // Set white bal on/off - reg = COM8_SET_AGC(reg, enable); - - // Write back register COM8 - return SCCB_Write(sensor->slv_addr, COM8, reg); -} - -static int set_exposure_ctrl(sensor_t *sensor, int enable) -{ - // Read register COM8 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); - - // Set white bal on/off - reg = COM8_SET_AEC(reg, enable); - - // Write back register COM8 - return SCCB_Write(sensor->slv_addr, COM8, reg); -} - -static int set_hmirror(sensor_t *sensor, int enable) -{ - // Read register COM3 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); - - // Set mirror on/off - reg = COM3_SET_MIRROR(reg, enable); - - // Write back register COM3 - return SCCB_Write(sensor->slv_addr, COM3, reg); -} - -static int set_vflip(sensor_t *sensor, int enable) -{ - // Read register COM3 - uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); - - // Set mirror on/off - reg = COM3_SET_FLIP(reg, enable); - - // Write back register COM3 - return SCCB_Write(sensor->slv_addr, COM3, reg); -} - -int ov7725_init(sensor_t *sensor) -{ - // Set function pointers - sensor->reset = reset; - sensor->set_pixformat = set_pixformat; - sensor->set_framesize = set_framesize; - sensor->set_colorbar = set_colorbar; - sensor->set_whitebal = set_whitebal; - sensor->set_gain_ctrl = set_gain_ctrl; - sensor->set_exposure_ctrl = set_exposure_ctrl; - sensor->set_hmirror = set_hmirror; - sensor->set_vflip = set_vflip; - - // Retrieve sensor's signature - sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH); - sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL); - sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID); - sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER); - - // Set sensor flags - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); - SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); - - return 0; -} diff --git a/components/camera/ov7725.h b/components/camera/ov7725.h deleted file mode 100644 index f8c3516..0000000 --- a/components/camera/ov7725.h +++ /dev/null @@ -1,14 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV7725 driver. - * - */ -#ifndef __OV7725_H__ -#define __OV7725_H__ -#include "sensor.h" - -int ov7725_init(sensor_t *sensor); -#endif // __OV7725_H__ diff --git a/components/camera/ov7725_regs.h b/components/camera/ov7725_regs.h deleted file mode 100644 index 484f0c2..0000000 --- a/components/camera/ov7725_regs.h +++ /dev/null @@ -1,334 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * OV2640 register definitions. - */ -#ifndef __REG_REGS_H__ -#define __REG_REGS_H__ -#define GAIN 0x00 /* AGC – Gain control gain setting */ -#define BLUE 0x01 /* AWB – Blue channel gain setting */ -#define RED 0x02 /* AWB – Red channel gain setting */ -#define GREEN 0x03 /* AWB – Green channel gain setting */ -#define BAVG 0x05 /* U/B Average Level */ -#define GAVG 0x06 /* Y/Gb Average Level */ -#define RAVG 0x07 /* V/R Average Level */ -#define AECH 0x08 /* Exposure Value – AEC MSBs */ - -#define COM2 0x09 /* Common Control 2 */ -#define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */ -#define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */ -#define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */ -#define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */ -#define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */ - -#define REG_PID 0x0A /* Product ID Number MSB */ -#define REG_VER 0x0B /* Product ID Number LSB */ - -#define COM3 0x0C /* Common Control 3 */ -#define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */ -#define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */ -#define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */ -#define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */ -#define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */ -#define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */ -#define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */ -#define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */ -#define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0)) -#define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6)) -#define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7)) - -#define COM4 0x0D /* Common Control 4 */ -#define COM4_PLL_BYPASS 0x00 /* Bypass PLL */ -#define COM4_PLL_4x 0x40 /* PLL frequency 4x */ -#define COM4_PLL_6x 0x80 /* PLL frequency 6x */ -#define COM4_PLL_8x 0xc0 /* PLL frequency 8x */ -#define COM4_AEC_FULL 0x00 /* AEC evaluate full window */ -#define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */ -#define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */ -#define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */ - -#define COM5 0x0E /* Common Control 5 */ -#define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */ -#define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */ -#define COM5_AFR_0 0x00 /* No reduction of frame rate */ -#define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */ -#define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */ -#define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */ -#define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */ -#define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */ -#define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */ -#define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */ - -#define COM6 0x0F /* Common Control 6 */ -#define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */ - -#define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */ -#define CLKRC 0x11 /* Internal Clock */ - -#define COM7 0x12 /* Common Control 7 */ -#define COM7_RESET 0x80 /* SCCB Register Reset */ -#define COM7_RES_VGA 0x00 /* Resolution VGA */ -#define COM7_RES_QVGA 0x40 /* Resolution QVGA */ -#define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */ -#define COM7_SENSOR_RAW 0x10 /* Sensor RAW */ -#define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */ -#define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */ -#define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */ -#define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */ -#define COM7_FMT_YUV 0x00 /* Output format YUV */ -#define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */ -#define COM7_FMT_RGB 0x02 /* Output format RGB */ -#define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */ -#define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0)) - -#define COM8 0x13 /* Common Control 8 */ -#define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */ -#define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */ -#define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */ -#define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */ -#define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */ -#define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */ -#define COM8_AGC_EN 0x04 /* AGC Enable */ -#define COM8_AWB_EN 0x02 /* AWB Enable */ -#define COM8_AEC_EN 0x01 /* AEC Enable */ -#define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2)) -#define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1)) -#define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0)) - -#define COM9 0x14 /* Common Control 9 */ -#define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */ -#define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */ -#define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */ -#define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */ -#define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */ -#define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */ -#define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ -#define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ -#define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4)) - -#define COM10 0x15 /* Common Control 10 */ -#define COM10_NEGATIVE 0x80 /* Output negative data */ -#define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ -#define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */ -#define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */ -#define COM10_PCLK_REV 0x10 /* PCLK reverse */ -#define COM10_HREF_REV 0x08 /* HREF reverse */ -#define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */ -#define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */ -#define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ -#define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */ -#define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */ - -#define REG16 0x16 /* Register 16 */ -#define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */ -#define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */ -#define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */ -#define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */ -#define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */ -#define PSHFT 0x1B /* Data Format - Pixel Delay Select */ -#define REG_MIDH 0x1C /* Manufacturer ID Byte – High */ -#define REG_MIDL 0x1D /* Manufacturer ID Byte – Low */ -#define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */ - -#define COM11 0x20 /* Common Control 11 */ -#define COM11_SNGL_FRAME_EN 0x02 /* Single frame ON/OFF selection */ -#define COM11_SNGL_XFR_TRIG 0x01 /* Single frame transfer trigger */ - -#define BDBASE 0x22 /* Banding Filter Minimum AEC Value */ -#define DBSTEP 0x23 /* Banding Filter Maximum Step */ -#define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */ -#define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */ -#define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */ -#define REG28 0x28 /* Selection on the number of dummy rows, N */ -#define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */ -#define EXHCH 0x2A /* Dummy Pixel Insert MSB */ -#define EXHCL 0x2B /* Dummy Pixel Insert LSB */ -#define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */ -#define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */ -#define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */ -#define YAVE 0x2F /* Y/G Channel Average Value */ -#define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */ -#define LUMLTH 0x31 /* Histogram AEC/AGC Luminance Low Level Threshold */ -#define HREF 0x32 /* Image Start and Size Control */ -#define DM_LNL 0x33 /* Dummy Row Low 8 Bits */ -#define DM_LNH 0x34 /* Dummy Row High 8 Bits */ -#define ADOFF_B 0x35 /* AD Offset Compensation Value for B Channel */ -#define ADOFF_R 0x36 /* AD Offset Compensation Value for R Channel */ -#define ADOFF_GB 0x37 /* AD Offset Compensation Value for GB Channel */ -#define ADOFF_GR 0x38 /* AD Offset Compensation Value for GR Channel */ -#define OFF_B 0x39 /* AD Offset Compensation Value for B Channel */ -#define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */ -#define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */ -#define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */ -#define COM12 0x3D /* DC offset compensation for analog process */ - -#define COM13 0x3E /* Common Control 13 */ -#define COM13_BLC_EN 0x80 /* BLC enable */ -#define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */ -#define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */ -#define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */ - -#define COM14 0x3F /* Common Control 14 */ -#define COM15 0x40 /* Common Control 15 */ -#define COM16 0x41 /* Common Control 16 */ -#define TGT_B 0x42 /* BLC Blue Channel Target Value */ -#define TGT_R 0x43 /* BLC Red Channel Target Value */ -#define TGT_GB 0x44 /* BLC Gb Channel Target Value */ -#define TGT_GR 0x45 /* BLC Gr Channel Target Value */ - -#define LC_CTR 0x46 /* Lens Correction Control */ -#define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */ -#define LC_CTR_RGB_COMP_3 0x04 /* R, G, and B channel compensation coefficient is set by registers - LC_COEFB (0x4B), LC_COEF (0x49), and LC_COEFR (0x4C), respectively */ -#define LC_CTR_EN 0x01 /* Lens correction enable */ -#define LC_XC 0x47 /* X Coordinate of Lens Correction Center Relative to Array Center */ -#define LC_YC 0x48 /* Y Coordinate of Lens Correction Center Relative to Array Center */ -#define LC_COEF 0x49 /* Lens Correction Coefficient */ -#define LC_RADI 0x4A /* Lens Correction Radius */ -#define LC_COEFB 0x4B /* Lens Correction B Channel Compensation Coefficient */ -#define LC_COEFR 0x4C /* Lens Correction R Channel Compensation Coefficient */ - -#define FIXGAIN 0x4D /* Analog Fix Gain Amplifier */ -#define AREF0 0x4E /* Sensor Reference Control */ -#define AREF1 0x4F /* Sensor Reference Current Control */ -#define AREF2 0x50 /* Analog Reference Control */ -#define AREF3 0x51 /* ADC Reference Control */ -#define AREF4 0x52 /* ADC Reference Control */ -#define AREF5 0x53 /* ADC Reference Control */ -#define AREF6 0x54 /* Analog Reference Control */ -#define AREF7 0x55 /* Analog Reference Control */ -#define UFIX 0x60 /* U Channel Fixed Value Output */ -#define VFIX 0x61 /* V Channel Fixed Value Output */ -#define AWBB_BLK 0x62 /* AWB Option for Advanced AWB */ - -#define AWB_CTRL0 0x63 /* AWB Control Byte 0 */ -#define AWB_CTRL0_GAIN_EN 0x80 /* AWB gain enable */ -#define AWB_CTRL0_CALC_EN 0x40 /* AWB calculate enable */ -#define AWB_CTRL0_WBC_MASK 0x0F /* WBC threshold 2 */ - -#define DSP_CTRL1 0x64 /* DSP Control Byte 1 */ -#define DSP_CTRL1_FIFO_EN 0x80 /* FIFO enable/disable selection */ -#define DSP_CTRL1_UV_EN 0x40 /* UV adjust function ON/OFF selection */ -#define DSP_CTRL1_SDE_EN 0x20 /* SDE enable */ -#define DSP_CTRL1_MTRX_EN 0x10 /* Color matrix ON/OFF selection */ -#define DSP_CTRL1_INTRP_EN 0x08 /* Interpolation ON/OFF selection */ -#define DSP_CTRL1_GAMMA_EN 0x04 /* Gamma function ON/OFF selection */ -#define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */ -#define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */ - -#define DSP_CTRL2 0x65 /* DSP Control Byte 2 */ -#define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */ -#define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */ -#define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */ -#define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */ - -#define DSP_CTRL3 0x66 /* DSP Control Byte 3 */ -#define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */ -#define DSP_CTRL3_CBAR_EN 0x20 /* DSP color bar ON/OFF selection */ -#define DSP_CTRL3_FIFO_EN 0x08 /* FIFO power down ON/OFF selection */ -#define DSP_CTRL3_SCAL1_PWDN 0x04 /* Scaling module power down control 1 */ -#define DSP_CTRL3_SCAL2_PWDN 0x02 /* Scaling module power down control 2 */ -#define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */ -#define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5)) - - -#define DSP_CTRL4 0x67 /* DSP Control Byte 4 */ -#define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */ -#define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */ -#define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */ - - -#define AWB_BIAS 0x68 /* AWB BLC Level Clip */ -#define AWB_CTRL1 0x69 /* AWB Control 1 */ -#define AWB_CTRL2 0x6A /* AWB Control 2 */ - -#define AWB_CTRL3 0x6B /* AWB Control 3 */ -#define AWB_CTRL3_ADVANCED 0x80 /* AWB mode select - Advanced AWB */ -#define AWB_CTRL3_SIMPLE 0x00 /* AWB mode select - Simple AWB */ - -#define AWB_CTRL4 0x6C /* AWB Control 4 */ -#define AWB_CTRL5 0x6D /* AWB Control 5 */ -#define AWB_CTRL6 0x6E /* AWB Control 6 */ -#define AWB_CTRL7 0x6F /* AWB Control 7 */ -#define AWB_CTRL8 0x70 /* AWB Control 8 */ -#define AWB_CTRL9 0x71 /* AWB Control 9 */ -#define AWB_CTRL10 0x72 /* AWB Control 10 */ -#define AWB_CTRL11 0x73 /* AWB Control 11 */ -#define AWB_CTRL12 0x74 /* AWB Control 12 */ -#define AWB_CTRL13 0x75 /* AWB Control 13 */ -#define AWB_CTRL14 0x76 /* AWB Control 14 */ -#define AWB_CTRL15 0x77 /* AWB Control 15 */ -#define AWB_CTRL16 0x78 /* AWB Control 16 */ -#define AWB_CTRL17 0x79 /* AWB Control 17 */ -#define AWB_CTRL18 0x7A /* AWB Control 18 */ -#define AWB_CTRL19 0x7B /* AWB Control 19 */ -#define AWB_CTRL20 0x7C /* AWB Control 20 */ -#define AWB_CTRL21 0x7D /* AWB Control 21 */ -#define GAM1 0x7E /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */ -#define GAM2 0x7F /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */ -#define GAM3 0x80 /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */ -#define GAM4 0x81 /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */ -#define GAM5 0x82 /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */ -#define GAM6 0x83 /* Gamma Curve 6th Segment Input End Point 0x30 Output Value */ -#define GAM7 0x84 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */ -#define GAM8 0x85 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */ -#define GAM9 0x86 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */ -#define GAM10 0x87 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */ -#define GAM11 0x88 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */ -#define GAM12 0x89 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */ -#define GAM13 0x8A /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */ -#define GAM14 0x8B /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */ -#define GAM15 0x8C /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */ -#define SLOP 0x8D /* Gamma Curve Highest Segment Slope */ -#define DNSTH 0x8E /* De-noise Threshold */ -#define EDGE0 0x8F /* Edge Enhancement Strength Control */ -#define EDGE1 0x90 /* Edge Enhancement Threshold Control */ -#define DNSOFF 0x91 /* Auto De-noise Threshold Control */ -#define EDGE2 0x92 /* Edge Enhancement Strength Upper Limit */ -#define EDGE3 0x93 /* Edge Enhancement Strength Upper Limit */ -#define MTX1 0x94 /* Matrix Coefficient 1 */ -#define MTX2 0x95 /* Matrix Coefficient 2 */ -#define MTX3 0x96 /* Matrix Coefficient 3 */ -#define MTX4 0x97 /* Matrix Coefficient 4 */ -#define MTX5 0x98 /* Matrix Coefficient 5 */ -#define MTX6 0x99 /* Matrix Coefficient 6 */ - -#define MTX_CTRL 0x9A /* Matrix Control */ -#define MTX_CTRL_DBL_EN 0x80 /* Matrix double ON/OFF selection */ - -#define BRIGHTNESS 0x9B /* Brightness Control */ -#define CONTRAST 0x9C /* Contrast Gain */ -#define UVADJ0 0x9E /* Auto UV Adjust Control 0 */ -#define UVADJ1 0x9F /* Auto UV Adjust Control 1 */ -#define SCAL0 0xA0 /* DCW Ratio Control */ -#define SCAL1 0xA1 /* Horizontal Zoom Out Control */ -#define SCAL2 0xA2 /* Vertical Zoom Out Control */ -#define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */ -#define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */ - -#define SDE 0xA6 /* Special Digital Effect Control */ -#define SDE_NEGATIVE_EN 0x40 /* Negative image enable */ -#define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */ -#define SDE_V_FIXED_EN 0x10 /* V fixed value enable */ -#define SDE_U_FIXED_EN 0x08 /* U fixed value enable */ -#define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */ -#define SDE_SATURATION_EN 0x02 /* Saturation enable */ -#define SDE_HUE_EN 0x01 /* Hue enable */ - -#define USAT 0xA7 /* U Component Saturation Gain */ -#define VSAT 0xA8 /* V Component Saturation Gain */ -#define HUECOS 0xA9 /* Cosine value × 0x80 */ -#define HUESIN 0xAA /* Sine value × 0x80 */ -#define SIGN_BIT 0xAB /* Sign Bit for Hue and Brightness */ - -#define DSPAUTO 0xAC /* DSP Auto Function ON/OFF Control */ -#define DSPAUTO_AWB_EN 0x80 /* AWB auto threshold control */ -#define DSPAUTO_DENOISE_EN 0x40 /* De-noise auto threshold control */ -#define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */ -#define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */ -#define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */ -#define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2))*/ -#define SET_REG(reg, x) (##reg_DEFAULT|x) -#endif //__REG_REGS_H__ diff --git a/components/camera/sccb.c b/components/camera/sccb.c deleted file mode 100644 index a606e46..0000000 --- a/components/camera/sccb.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * SCCB (I2C like) driver. - * - */ -#include -#include "wiring.h" -#include "sccb.h" -#include "twi.h" -#include - -#define SCCB_FREQ (100000) // We don't need fast I2C. 100KHz is fine here. -#define TIMEOUT (1000) /* Can't be sure when I2C routines return. Interrupts -while polling hardware may result in unknown delays. */ - - -int SCCB_Init(int pin_sda, int pin_scl) -{ - twi_init(pin_sda, pin_scl); - return 0; -} - -uint8_t SCCB_Probe() -{ - uint8_t reg = 0x00; - uint8_t slv_addr = 0x00; - - for (uint8_t i=0; i<127; i++) { - if (twi_writeTo(i, ®, 1, true) == 0) { - slv_addr = i; - break; - } - - if (i!=126) { - systick_sleep(1); // Necessary for OV7725 camera (not for OV2640). - } - } - return slv_addr; -} - -uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg) -{ - uint8_t data=0; - - __disable_irq(); - int rc = twi_writeTo(slv_addr, ®, 1, true); - if (rc != 0) { - data = 0xff; - } - else { - rc = twi_readFrom(slv_addr, &data, 1, true); - if (rc != 0) { - data=0xFF; - } - } - __enable_irq(); - if (rc != 0) { - printf("SCCB_Read [%02x] failed rc=%d\n", reg, rc); - } - return data; -} - -uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data) -{ - uint8_t ret=0; - uint8_t buf[] = {reg, data}; - - __disable_irq(); - if(twi_writeTo(slv_addr, buf, 2, true) != 0) { - ret=0xFF; - } - __enable_irq(); - if (ret != 0) { - printf("SCCB_Write [%02x]=%02x failed\n", reg, data); - } - return ret; -} diff --git a/components/camera/sccb.h b/components/camera/sccb.h deleted file mode 100644 index 567e753..0000000 --- a/components/camera/sccb.h +++ /dev/null @@ -1,16 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * SCCB (I2C like) driver. - * - */ -#ifndef __SCCB_H__ -#define __SCCB_H__ -#include -int SCCB_Init(int pin_sda, int pin_scl); -uint8_t SCCB_Probe(); -uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg); -uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data); -#endif // __SCCB_H__ diff --git a/components/camera/sensor.h b/components/camera/sensor.h deleted file mode 100644 index 31af66d..0000000 --- a/components/camera/sensor.h +++ /dev/null @@ -1,179 +0,0 @@ -/* - * This file is part of the OpenMV project. - * Copyright (c) 2013/2014 Ibrahim Abdelkader - * This work is licensed under the MIT license, see the file LICENSE for details. - * - * Sensor abstraction layer. - * - */ -#ifndef __SENSOR_H__ -#define __SENSOR_H__ -#include -#include "wiring.h" - -#define OV9650_PID (0x96) -#define OV2640_PID (0x26) -#define OV7725_PID (0x77) - - -typedef struct { - uint8_t MIDH; - uint8_t MIDL; - uint8_t PID; - uint8_t VER; -} sensor_id_t; - -typedef enum { - PIXFORMAT_RGB565, // 2BPP/RGB565 - PIXFORMAT_YUV422, // 2BPP/YUV422 - PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE - PIXFORMAT_JPEG, // JPEG/COMPRESSED -} pixformat_t; - -typedef enum { - FRAMESIZE_40x30, // 40x30 - FRAMESIZE_64x32, // 64x32 - FRAMESIZE_64x64, // 64x64 - FRAMESIZE_QQCIF, // 88x72 - FRAMESIZE_QQVGA, // 160x120 - FRAMESIZE_QQVGA2, // 128x160 - FRAMESIZE_QCIF, // 176x144 - FRAMESIZE_HQVGA, // 220x160 - FRAMESIZE_QVGA, // 320x240 - FRAMESIZE_CIF, // 352x288 - FRAMESIZE_VGA, // 640x480 - FRAMESIZE_SVGA, // 800x600 - FRAMESIZE_SXGA, // 1280x1024 - FRAMESIZE_UXGA, // 1600x1200 -} framesize_t; - -typedef enum { - FRAMERATE_2FPS =0x9F, - FRAMERATE_8FPS =0x87, - FRAMERATE_15FPS=0x83, - FRAMERATE_30FPS=0x81, - FRAMERATE_60FPS=0x80, -} framerate_t; - -typedef enum { - GAINCEILING_2X, - GAINCEILING_4X, - GAINCEILING_8X, - GAINCEILING_16X, - GAINCEILING_32X, - GAINCEILING_64X, - GAINCEILING_128X, -} gainceiling_t; - -typedef enum { - SDE_NORMAL, - SDE_NEGATIVE, -} sde_t; - -typedef enum { - ATTR_CONTRAST=0, - ATTR_BRIGHTNESS, - ATTR_SATURATION, - ATTR_GAINCEILING, -} sensor_attr_t; - -typedef enum { - ACTIVE_LOW, - ACTIVE_HIGH -} reset_polarity_t; - -typedef void (*line_filter_t) (uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, void *args); - -#define SENSOR_HW_FLAGS_VSYNC (0) // vertical sync polarity. -#define SENSOR_HW_FLAGS_HSYNC (1) // horizontal sync polarity. -#define SENSOR_HW_FLAGS_PIXCK (2) // pixel clock edge. -#define SENSOR_HW_FLAGS_FSYNC (3) // hardware frame sync. -#define SENSOR_HW_FLAGS_JPEGE (4) // hardware JPEG encoder. -#define SENSOR_HW_FLAGS_GET(s, x) ((s)->hw_flags & (1<hw_flags |= (v<hw_flags &= ~(1< -#include -#include "twi.h" -#include "soc/gpio_reg.h" -#include "wiring.h" -#include - -unsigned char twi_dcount = 18; -static unsigned char twi_sda, twi_scl; - - -static inline void SDA_LOW() { - //Enable SDA (becomes output and since GPO is 0 for the pin, - // it will pull the line low) - if (twi_sda < 32) { - REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_sda)); - } - else { - REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_sda - 32)); - } -} - -static inline void SDA_HIGH() { - //Disable SDA (becomes input and since it has pullup it will go high) - if (twi_sda < 32) { - REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_sda)); - } - else { - REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_sda - 32)); - } -} - -static inline uint32_t SDA_READ() { - if (twi_sda < 32) { - return (REG_READ(GPIO_IN_REG) & BIT(twi_sda)) != 0; - } - else { - return (REG_READ(GPIO_IN1_REG) & BIT(twi_sda - 32)) != 0; - } -} - -static void SCL_LOW() { - if (twi_scl < 32) { - REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_scl)); - } - else { - REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_scl - 32)); - } -} - -static void SCL_HIGH() { - if (twi_scl < 32) { - REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_scl)); - } - else { - REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_scl - 32)); - } -} - -static uint32_t SCL_READ() { - if (twi_scl < 32) { - return (REG_READ(GPIO_IN_REG) & BIT(twi_scl)) != 0; - } - else { - return (REG_READ(GPIO_IN1_REG) & BIT(twi_scl - 32)) != 0; - } -} - - -#ifndef FCPU80 -#define FCPU80 80000000L -#endif - -#if F_CPU == FCPU80 -#define TWI_CLOCK_STRETCH 800 -#else -#define TWI_CLOCK_STRETCH 1600 -#endif - -void twi_setClock(unsigned int freq){ -#if F_CPU == FCPU80 - if(freq <= 100000) twi_dcount = 19;//about 100KHz - else if(freq <= 200000) twi_dcount = 8;//about 200KHz - else if(freq <= 300000) twi_dcount = 3;//about 300KHz - else if(freq <= 400000) twi_dcount = 1;//about 400KHz - else twi_dcount = 1;//about 400KHz -#else - if(freq <= 100000) twi_dcount = 32;//about 100KHz - else if(freq <= 200000) twi_dcount = 14;//about 200KHz - else if(freq <= 300000) twi_dcount = 8;//about 300KHz - else if(freq <= 400000) twi_dcount = 5;//about 400KHz - else if(freq <= 500000) twi_dcount = 3;//about 500KHz - else if(freq <= 600000) twi_dcount = 2;//about 600KHz - else twi_dcount = 1;//about 700KHz -#endif -} - -void twi_init(unsigned char sda, unsigned char scl){ - twi_sda = sda; - twi_scl = scl; - pinMode(twi_sda, OUTPUT); - pinMode(twi_scl, OUTPUT); - - digitalWrite(twi_sda, 0); - digitalWrite(twi_scl, 0); - - pinMode(twi_sda, INPUT_PULLUP); - pinMode(twi_scl, INPUT_PULLUP); - twi_setClock(100000); -} - -void twi_stop(void){ - pinMode(twi_sda, INPUT); - pinMode(twi_scl, INPUT); -} - -static void twi_delay(unsigned char v){ - unsigned int i; -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" - unsigned int reg; - for(i=0;i -#include - - -// Some functions from Arduino/Wiring -void pinMode(int pin, int mode); -void digitalWrite(int pin, int value); -void delay(int millis); - -#define OUTPUT 0 -#define INPUT 1 -#define INPUT_PULLUP 2 - -// Some functions to make OpenMV happy -#define systick_sleep(t) delay(t) -#define __disable_irq() -#define __enable_irq() - - - -#endif //__OMV_PORT_H__ diff --git a/components/camera/xclk.c b/components/camera/xclk.c deleted file mode 100644 index 4ad050f..0000000 --- a/components/camera/xclk.c +++ /dev/null @@ -1,44 +0,0 @@ -#include "driver/gpio.h" -#include "driver/ledc.h" -#include "esp_err.h" -#include "esp_log.h" -#include "xclk.h" - -static const char* TAG = "camera_xclk"; - -esp_err_t camera_enable_out_clock(camera_config_t* config) -{ - periph_module_enable(PERIPH_LEDC_MODULE); - - ledc_timer_config_t timer_conf = { - .duty_resolution = 1, - .freq_hz = config->xclk_freq_hz, - .speed_mode = LEDC_HIGH_SPEED_MODE, - .timer_num = config->ledc_timer - }; - esp_err_t err = ledc_timer_config(&timer_conf); - if (err != ESP_OK) { - ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); - return err; - } - - ledc_channel_config_t ch_conf = { - .channel = config->ledc_channel, - .timer_sel = config->ledc_timer, - .intr_type = LEDC_INTR_DISABLE, - .duty = 1, - .speed_mode = LEDC_HIGH_SPEED_MODE, - .gpio_num = config->pin_xclk - }; - err = ledc_channel_config(&ch_conf); - if (err != ESP_OK) { - ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err); - return err; - } - return ESP_OK; -} - -void camera_disable_out_clock() -{ - periph_module_disable(PERIPH_LEDC_MODULE); -} diff --git a/components/camera/xclk.h b/components/camera/xclk.h deleted file mode 100644 index 15ed736..0000000 --- a/components/camera/xclk.h +++ /dev/null @@ -1,7 +0,0 @@ -#pragma once - -#include "camera_common.h" - -esp_err_t camera_enable_out_clock(); - -void camera_disable_out_clock(); diff --git a/main/app_main.c b/main/app_main.c index 0da4a72..8fb5f0f 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -30,9 +30,9 @@ #include "nvs_flash.h" #include "driver/gpio.h" -#include "camera.h" +#include "esp_camera.h" #include "bitmap.h" -#include "http_server.h" +#include "../components/http_server/http_server.h" static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx); static void handle_rgb_bmp(http_context_t http_ctx, void* ctx); @@ -52,11 +52,6 @@ static const char* STREAM_BOUNDARY = "--123456789000000000000987654321"; static EventGroupHandle_t s_wifi_event_group; const int CONNECTED_BIT = BIT0; static ip4_addr_t s_ip_addr; -static camera_pixelformat_t s_pixel_format; - -#define CAMERA_PIXEL_FORMAT CAMERA_PF_GRAYSCALE -#define CAMERA_FRAME_SIZE CAMERA_FS_QVGA - void app_main() { @@ -71,52 +66,38 @@ void app_main() ESP_ERROR_CHECK(gpio_install_isr_service(0)); - camera_config_t camera_config = { - .ledc_channel = LEDC_CHANNEL_0, - .ledc_timer = LEDC_TIMER_0, - .pin_d0 = CONFIG_D0, - .pin_d1 = CONFIG_D1, - .pin_d2 = CONFIG_D2, - .pin_d3 = CONFIG_D3, - .pin_d4 = CONFIG_D4, - .pin_d5 = CONFIG_D5, - .pin_d6 = CONFIG_D6, - .pin_d7 = CONFIG_D7, + static camera_config_t camera_config = { + .pin_pwdn = -1, // power down is not used + .pin_reset = CONFIG_RESET, // software reset will be performed .pin_xclk = CONFIG_XCLK, - .pin_pclk = CONFIG_PCLK, - .pin_vsync = CONFIG_VSYNC, - .pin_href = CONFIG_HREF, .pin_sscb_sda = CONFIG_SDA, .pin_sscb_scl = CONFIG_SCL, - .pin_reset = CONFIG_RESET, + + .pin_d7 = CONFIG_D7, + .pin_d6 = CONFIG_D6, + .pin_d5 = CONFIG_D5, + .pin_d4 = CONFIG_D4, + .pin_d3 = CONFIG_D3, + .pin_d2 = CONFIG_D2, + .pin_d1 = CONFIG_D1, + .pin_d0 = CONFIG_D0, + .pin_vsync = CONFIG_VSYNC, + .pin_href = CONFIG_HREF, + .pin_pclk = CONFIG_PCLK, + + //XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) .xclk_freq_hz = CONFIG_XCLK_FREQ, - }; + .ledc_timer = LEDC_TIMER_0, + .ledc_channel = LEDC_CHANNEL_0, - camera_model_t camera_model; - err = camera_probe(&camera_config, &camera_model); - if (err != ESP_OK) { - ESP_LOGE(TAG, "Camera probe failed with error 0x%x", err); - return; - } + .pixel_format = /*PIXFORMAT_GRAYSCALE,*/ PIXFORMAT_RGB565, + .frame_size = /*FRAMESIZE_QVGA,*/ FRAMESIZE_QQVGA, //QQVGA-QXGA Do not use sizes above QVGA when not JPEG - if (camera_model == CAMERA_OV7725) { - s_pixel_format = CAMERA_PIXEL_FORMAT; - camera_config.frame_size = CAMERA_FRAME_SIZE; - ESP_LOGI(TAG, "Detected OV7725 camera, using %s bitmap format", - CAMERA_PIXEL_FORMAT == CAMERA_PF_GRAYSCALE ? - "grayscale" : "RGB565"); - } else if (camera_model == CAMERA_OV2640) { - ESP_LOGI(TAG, "Detected OV2640 camera, using JPEG format"); - s_pixel_format = CAMERA_PF_JPEG; - camera_config.frame_size = CAMERA_FRAME_SIZE; - camera_config.jpeg_quality = 15; - } else { - ESP_LOGE(TAG, "Camera not supported"); - return; - } + .jpeg_quality = 12, //0-63 lower number means higher quality + .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG + }; - camera_config.pixel_format = s_pixel_format; - err = camera_init(&camera_config); + err = esp_camera_init(&camera_config); if (err != ESP_OK) { ESP_LOGE(TAG, "Camera init failed with error 0x%x", err); return; @@ -128,17 +109,21 @@ void app_main() http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT(); ESP_ERROR_CHECK( http_server_start(&http_options, &server) ); - if (s_pixel_format == CAMERA_PF_GRAYSCALE) { + if (camera_config.pixel_format == PIXFORMAT_GRAYSCALE) { + ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); + ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) ); + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); ESP_ERROR_CHECK( http_register_handler(server, "/pgm", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_grayscale_pgm, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); } - if (s_pixel_format == CAMERA_PF_RGB565) { + if (camera_config.pixel_format == PIXFORMAT_RGB565) { ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); } - if (s_pixel_format == CAMERA_PF_JPEG) { + if (camera_config.pixel_format == PIXFORMAT_JPEG) { ESP_ERROR_CHECK( http_register_handler(server, "/jpg", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); ESP_ERROR_CHECK( http_register_handler(server, "/jpg_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) ); @@ -149,55 +134,123 @@ void app_main() } -static esp_err_t write_frame(http_context_t http_ctx) +static esp_err_t write_frame(http_context_t http_ctx, camera_fb_t * fb) { + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); + return ESP_FAIL; + } + http_buffer_t fb_data = { - .data = camera_get_fb(), - .size = camera_get_data_size(), + .data = fb->buf, + .size = fb->len, .data_is_persistent = true }; + return http_response_write(http_ctx, &fb_data); } +#define BUFFER_LEN 512 + +static esp_err_t write_gray_frame(http_context_t http_ctx, camera_fb_t * fb) +{ +uint8_t* buf; +int x = 0; +int size; +esp_err_t err = ESP_OK; + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); + return ESP_FAIL; + } + + buf = malloc( BUFFER_LEN * 3 ); + + if (!buf ){ + ESP_LOGE(TAG, "Dinamic memory failed"); + return ESP_FAIL; + } + + http_buffer_t fb_data = { + .data = buf, + .size = 0, + .data_is_persistent = false + }; + + while( (xlen) && (err == ESP_OK) ) { + size = (fb->len >= BUFFER_LEN) ? BUFFER_LEN : fb->len; + + for(int i=0; ibuf[i + x]; + buf[(i * 3) + 1 ] = fb->buf[i + x]; + buf[(i * 3) + 2 ] = fb->buf[i + x]; + } + + fb_data.size = size * 3; + + err = http_response_write(http_ctx, &fb_data); + + x += size; + } + + free( buf ); + + return err; +} + static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx) { - esp_err_t err = camera_run(); - if (err != ESP_OK) { - ESP_LOGD(TAG, "Camera capture failed with error = %d", err); + //acquire a frame + camera_fb_t * fb = esp_camera_fb_get(); + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); return; } + char* pgm_header_str; - asprintf(&pgm_header_str, "P5 %d %d %d\n", - camera_get_fb_width(), camera_get_fb_height(), 255); + asprintf(&pgm_header_str, "P5 %d %d %d\n", fb->width, fb->height, 255); if (pgm_header_str == NULL) { return; } - size_t response_size = strlen(pgm_header_str) + camera_get_data_size(); + size_t response_size = strlen(pgm_header_str) + fb->len; http_response_begin(http_ctx, 200, "image/x-portable-graymap", response_size); http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.pgm"); http_buffer_t pgm_header = { .data = pgm_header_str }; http_response_write(http_ctx, &pgm_header); free(pgm_header_str); - write_frame(http_ctx); + write_frame(http_ctx, fb); http_response_end(http_ctx); + + esp_camera_fb_return(fb); } static void handle_rgb_bmp(http_context_t http_ctx, void* ctx) { - esp_err_t err = camera_run(); - if (err != ESP_OK) { - ESP_LOGD(TAG, "Camera capture failed with error = %d", err); + //acquire a frame + camera_fb_t * fb = esp_camera_fb_get(); + + sensor_t * sensor = esp_camera_sensor_get(); + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); return; } - bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height()); + bitmap_header_t* header = bmp_create_header(fb->width, fb->height); if (header == NULL) { return; } - http_response_begin(http_ctx, 200, "image/bmp", sizeof(*header) + camera_get_data_size()); + int len = fb->len; + + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + len *= 3; + } + + http_response_begin(http_ctx, 200, "image/bmp", sizeof(*header) + len); http_buffer_t bmp_header = { .data = header, .size = sizeof(*header) @@ -206,59 +259,91 @@ static void handle_rgb_bmp(http_context_t http_ctx, void* ctx) http_response_write(http_ctx, &bmp_header); free(header); - write_frame(http_ctx); + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + write_gray_frame(http_ctx, fb); + }else{ + write_frame(http_ctx, fb); + } + http_response_end(http_ctx); + + esp_camera_fb_return(fb); } static void handle_jpg(http_context_t http_ctx, void* ctx) { - esp_err_t err = camera_run(); - if (err != ESP_OK) { - ESP_LOGD(TAG, "Camera capture failed with error = %d", err); + //acquire a frame + camera_fb_t * fb = esp_camera_fb_get(); + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); return; } - http_response_begin(http_ctx, 200, "image/jpeg", camera_get_data_size()); + http_response_begin(http_ctx, 200, "image/jpeg", fb->len); http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.jpg"); - write_frame(http_ctx); + write_frame(http_ctx, fb); http_response_end(http_ctx); -} + esp_camera_fb_return(fb); +} static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx) { + camera_fb_t * fb = esp_camera_fb_get(); + sensor_t * sensor = esp_camera_sensor_get(); + http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); - bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height()); + bitmap_header_t* header = bmp_create_header(fb->width, fb->height); if (header == NULL) { return; } + http_buffer_t bmp_header = { .data = header, .size = sizeof(*header) }; + esp_camera_fb_return(fb); while (true) { - esp_err_t err = camera_run(); - if (err != ESP_OK) { - ESP_LOGD(TAG, "Camera capture failed with error = %d", err); - return; + esp_camera_fb_get(); + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); + break; } - err = http_response_begin_multipart(http_ctx, "image/bitmap", - camera_get_data_size() + sizeof(*header)); + int len = fb->len; + + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + len *= 3; + } + + esp_err_t err = http_response_begin_multipart(http_ctx, "image/bitmap", len + sizeof(*header)); if (err != ESP_OK) { break; } + err = http_response_write(http_ctx, &bmp_header); if (err != ESP_OK) { break; } - err = write_frame(http_ctx); + + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + err = write_gray_frame(http_ctx, fb); + }else{ + err = write_frame(http_ctx, fb); + } + if (err != ESP_OK) { break; } + err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY); + + esp_camera_fb_return(fb); + if (err != ESP_OK) { break; } @@ -273,17 +358,20 @@ static void handle_jpg_stream(http_context_t http_ctx, void* ctx) http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); while (true) { - esp_err_t err = camera_run(); - if (err != ESP_OK) { - ESP_LOGD(TAG, "Camera capture failed with error = %d", err); + //acquire a frame + camera_fb_t * fb = esp_camera_fb_get(); + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); return; } - err = http_response_begin_multipart(http_ctx, "image/jpg", - camera_get_data_size()); + + esp_err_t err = http_response_begin_multipart(http_ctx, "image/jpg", fb->len ); + if (err != ESP_OK) { break; } - err = write_frame(http_ctx); + err = write_frame(http_ctx, fb); if (err != ESP_OK) { break; } @@ -295,7 +383,6 @@ static void handle_jpg_stream(http_context_t http_ctx, void* ctx) http_response_end(http_ctx); } - static esp_err_t event_handler(void *ctx, system_event_t *event) { switch (event->event_id) { diff --git a/sdkconfig.defaults b/sdkconfig.defaults deleted file mode 100644 index 8bc49d0..0000000 --- a/sdkconfig.defaults +++ /dev/null @@ -1,11 +0,0 @@ -CONFIG_ENABLE_TEST_PATTERN=n -CONFIG_OV2640_SUPPORT=y -CONFIG_OV7725_SUPPORT=y -CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y -CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 -CONFIG_MEMMAP_SMP=y -CONFIG_TASK_WDT=n -CONFIG_FREERTOS_UNICORE=n -CONFIG_FREERTOS_HZ=100 -CONFIG_LOG_DEFAULT_LEVEL_INFO=y -CONFIG_LOG_DEFAULT_LEVEL=3 From 56e53942deb3c0a42a13c24fbb10fd5dc591eef3 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Sat, 26 Oct 2019 18:14:58 -0300 Subject: [PATCH 02/14] adding grayscaleconvertion to bmp. --- main/app_main.c | 1 + 1 file changed, 1 insertion(+) diff --git a/main/app_main.c b/main/app_main.c index 8fb5f0f..1b71dcf 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -109,6 +109,7 @@ void app_main() http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT(); ESP_ERROR_CHECK( http_server_start(&http_options, &server) ); + // Convert the pcm grayscale to bmp. if (camera_config.pixel_format == PIXFORMAT_GRAYSCALE) { ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); From de65932d8a99a58045da7038e32c7c768e45e8e7 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Sat, 26 Oct 2019 18:36:58 -0300 Subject: [PATCH 03/14] delete travis.yml. --- .travis.yml | 42 ------------------------------------------ 1 file changed, 42 deletions(-) delete mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c91077f..0000000 --- a/.travis.yml +++ /dev/null @@ -1,42 +0,0 @@ -sudo: false -language: bash -os: - - linux - -addons: - apt: - packages: - - gperf - - python - - python-serial - -before_install: - # Save path to the git respository - - PROJECT_PATH=$(pwd) - -install: - # Install ESP32 toochain following steps as desribed - # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html - # - # Get required packages - already done above, see addons: apt: packages: - # - sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial - # Prepare directory for the toolchain - - mkdir -p ~/esp - - cd ~/esp - # Download binary toolchain for the ESP32 - - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz - - tar -xzf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz - # Make xtensa-esp32-elf available for all terminal sessions - - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin - # Get ESP-IDF from github - - git clone --recursive https://github.com/espressif/esp-idf.git - # Set the path to ESP-IDF directory - - export IDF_PATH=~/esp/esp-idf - -script: - # Go back to the git repository - - cd $PROJECT_PATH - # Update configuration so that kconfig doesn't start interactive mode - - make defconfig - # Build project from the git repository - - make From 1134865afbee109c0943cf7149b3866731294d71 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Sat, 26 Oct 2019 18:41:34 -0300 Subject: [PATCH 04/14] adding grayscaleconvertion to bmp_stream. --- main/app_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main/app_main.c b/main/app_main.c index 1b71dcf..4a58b65 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -109,7 +109,7 @@ void app_main() http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT(); ESP_ERROR_CHECK( http_server_start(&http_options, &server) ); - // Convert the pcm grayscale to bmp. + // Convert the pcm grayscale to bmp and bmp_stream. if (camera_config.pixel_format == PIXFORMAT_GRAYSCALE) { ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); From 65a1b25ae665a0a38dbf96f533863000e1df0d3d Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Wed, 6 Nov 2019 17:02:24 -0300 Subject: [PATCH 05/14] porting to idf 4.1 dev --- Makefile | 2 + components/http_server | 1 - main/Kconfig.projbuild | 16 +- main/app_main.c | 476 ++++++++++++++++++++++++----------------- 4 files changed, 278 insertions(+), 217 deletions(-) delete mode 160000 components/http_server diff --git a/Makefile b/Makefile index c8b983b..37a71e2 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,6 @@ PROJECT_NAME := esp32-cam-demo +EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common + include $(IDF_PATH)/make/project.mk diff --git a/components/http_server b/components/http_server deleted file mode 160000 index fc44658..0000000 --- a/components/http_server +++ /dev/null @@ -1 +0,0 @@ -Subproject commit fc44658b4c015fb809c5750c4d92e06eb3c6d287 diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 6005ee0..4b85b96 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -1,17 +1,5 @@ menu "ESP32 Camera Demo Configuration" - -config WIFI_SSID - string "WiFi SSID" - default "" - help - SSID (network name) for the demo to connect to. - -config WIFI_PASSWORD - string "WiFi Password" - default "" - help - Password for your network. - + config XCLK_FREQ int "XCLK Frequency" default "20000000" @@ -66,4 +54,4 @@ menu "Pin Configuration" default "2" endmenu -endmenu \ No newline at end of file +endmenu diff --git a/main/app_main.c b/main/app_main.c index 4a58b65..275ec81 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -24,7 +24,8 @@ #include "esp_system.h" #include "esp_wifi.h" -#include "esp_event_loop.h" +#include "esp_eth.h" +#include "esp_event.h" #include "esp_log.h" #include "esp_err.h" #include "nvs_flash.h" @@ -32,29 +33,27 @@ #include "driver/gpio.h" #include "esp_camera.h" #include "bitmap.h" -#include "../components/http_server/http_server.h" +#include "protocol_examples_common.h" +#include -static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx); -static void handle_rgb_bmp(http_context_t http_ctx, void* ctx); -static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx); -static void handle_jpg(http_context_t http_ctx, void* ctx); -static void handle_jpg_stream(http_context_t http_ctx, void* ctx); -static esp_err_t event_handler(void *ctx, system_event_t *event); -static void initialise_wifi(void); +static httpd_handle_t start_webserver(void); +static void connect_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data); +static void disconnect_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data); static const char* TAG = "camera_demo"; -static const char* STREAM_CONTENT_TYPE = - "multipart/x-mixed-replace; boundary=123456789000000000000987654321"; - -static const char* STREAM_BOUNDARY = "--123456789000000000000987654321"; - -static EventGroupHandle_t s_wifi_event_group; -const int CONNECTED_BIT = BIT0; -static ip4_addr_t s_ip_addr; +#define PART_BOUNDARY "123456789000000000000987654321" +static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +static const char* _STREAM_BMP_PART = "Content-Type: image/bitmap\r\nContent-Length: %u\r\n\r\n"; +static const char* _STREAM_JPG_PART = "Content-Type: image/jpg\r\nContent-Length: %u\r\n\r\n"; void app_main() { + static httpd_handle_t server = NULL; + esp_log_level_set("wifi", ESP_LOG_WARN); esp_log_level_set("gpio", ESP_LOG_WARN); @@ -91,7 +90,7 @@ void app_main() .ledc_channel = LEDC_CHANNEL_0, .pixel_format = /*PIXFORMAT_GRAYSCALE,*/ PIXFORMAT_RGB565, - .frame_size = /*FRAMESIZE_QVGA,*/ FRAMESIZE_QQVGA, //QQVGA-QXGA Do not use sizes above QVGA when not JPEG + .frame_size = FRAMESIZE_QQVGA, /*FRAMESIZE_QVGA,*/ //QQVGA-QXGA Do not use sizes above QVGA when not JPEG .jpeg_quality = 12, //0-63 lower number means higher quality .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG @@ -103,59 +102,40 @@ void app_main() return; } - initialise_wifi(); - - http_server_t server; - http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT(); - ESP_ERROR_CHECK( http_server_start(&http_options, &server) ); + tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_event_loop_create_default()); + + /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. + * Read "Establishing Wi-Fi or Ethernet Connection" section in + * examples/protocols/README.md for more information about this function. + */ + ESP_ERROR_CHECK(example_connect()); + + /* Register event handlers to stop the server when Wi-Fi or Ethernet is disconnected, + * and re-start it upon connection. + */ +#ifdef CONFIG_EXAMPLE_CONNECT_WIFI + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &connect_handler, &server)); + ESP_ERROR_CHECK(esp_event_handler_register(WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED, &disconnect_handler, &server)); +#endif // CONFIG_EXAMPLE_CONNECT_WIFI +#ifdef CONFIG_EXAMPLE_CONNECT_ETHERNET + ESP_ERROR_CHECK(esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP, &connect_handler, &server)); + ESP_ERROR_CHECK(esp_event_handler_register(ETH_EVENT, ETHERNET_EVENT_DISCONNECTED, &disconnect_handler, &server)); +#endif // CONFIG_EXAMPLE_CONNECT_ETHERNET + + /* Start the server for the first time */ + server = start_webserver(); - // Convert the pcm grayscale to bmp and bmp_stream. - if (camera_config.pixel_format == PIXFORMAT_GRAYSCALE) { - ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); - ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); - ESP_ERROR_CHECK( http_register_handler(server, "/pgm", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_grayscale_pgm, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); - } - if (camera_config.pixel_format == PIXFORMAT_RGB565) { - ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); - ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); - } - if (camera_config.pixel_format == PIXFORMAT_JPEG) { - ESP_ERROR_CHECK( http_register_handler(server, "/jpg", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); - ESP_ERROR_CHECK( http_register_handler(server, "/jpg_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) ); - ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); - } ESP_LOGI(TAG, "Free heap: %u", xPortGetFreeHeapSize()); ESP_LOGI(TAG, "Camera demo ready"); - -} - -static esp_err_t write_frame(http_context_t http_ctx, camera_fb_t * fb) -{ - if (!fb) { - ESP_LOGE(TAG, "Camera Capture Failed"); - return ESP_FAIL; - } - - http_buffer_t fb_data = { - .data = fb->buf, - .size = fb->len, - .data_is_persistent = true - }; - - return http_response_write(http_ctx, &fb_data); } #define BUFFER_LEN 512 -static esp_err_t write_gray_frame(http_context_t http_ctx, camera_fb_t * fb) +/* Convert the pgm gray in a rgb bitmap */ +static esp_err_t write_gray_frame(httpd_req_t *req, camera_fb_t * fb) { -uint8_t* buf; +char* buf; int x = 0; int size; esp_err_t err = ESP_OK; @@ -165,32 +145,25 @@ esp_err_t err = ESP_OK; return ESP_FAIL; } + /* To save RAM send the converted image in chunks of 512 bytes. */ buf = malloc( BUFFER_LEN * 3 ); - if (!buf ){ + if (!buf ) { ESP_LOGE(TAG, "Dinamic memory failed"); return ESP_FAIL; } - http_buffer_t fb_data = { - .data = buf, - .size = 0, - .data_is_persistent = false - }; - - while( (xlen) && (err == ESP_OK) ) { + while ( (xlen) && (err == ESP_OK) ) { size = (fb->len >= BUFFER_LEN) ? BUFFER_LEN : fb->len; - for(int i=0; ibuf[i + x]; buf[(i * 3) + 1 ] = fb->buf[i + x]; buf[(i * 3) + 2 ] = fb->buf[i + x]; } - - fb_data.size = size * 3; - - err = http_response_write(http_ctx, &fb_data); - + + err = httpd_resp_send_chunk(req, buf, size * 3); x += size; } @@ -199,231 +172,330 @@ esp_err_t err = ESP_OK; return err; } -static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx) +/* HTTP pgm handler to take one picture and file download */ +static esp_err_t handle_grayscale_pgm(httpd_req_t *req) { - //acquire a frame + esp_err_t err = ESP_OK; + + char pgm_header_str[64]; + + // acquire a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - return; + return ESP_FAIL; } - char* pgm_header_str; - asprintf(&pgm_header_str, "P5 %d %d %d\n", fb->width, fb->height, 255); - if (pgm_header_str == NULL) { - return; + err = httpd_resp_set_type(req, "image/x-portable-graymap"); + + if (err == ESP_OK){ + err = httpd_resp_set_hdr(req, "Content-disposition", "inline; filename=capture.pgm"); } - size_t response_size = strlen(pgm_header_str) + fb->len; - http_response_begin(http_ctx, 200, "image/x-portable-graymap", response_size); - http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.pgm"); - http_buffer_t pgm_header = { .data = pgm_header_str }; - http_response_write(http_ctx, &pgm_header); - free(pgm_header_str); + if (err == ESP_OK){ + size_t hlen = snprintf((char *)pgm_header_str, 64, "P5 %d %d %d\n", fb->width, fb->height, 255); - write_frame(http_ctx, fb); - http_response_end(http_ctx); + err = httpd_resp_send_chunk(req, (const char *)pgm_header_str, hlen); + } + + if (err == ESP_OK){ + err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + } + + /* buf_len as 0 to mark that all chunks have been sent. */ + if (err == ESP_OK){ + err = httpd_resp_send_chunk(req, 0, 0); + } esp_camera_fb_return(fb); + + return err; } -static void handle_rgb_bmp(http_context_t http_ctx, void* ctx) +/* HTTP bmp handler to take one picture*/ +static esp_err_t handle_rgb_bmp(httpd_req_t *req) { - //acquire a frame + esp_err_t err = ESP_OK; + + // acquire a frame camera_fb_t * fb = esp_camera_fb_get(); sensor_t * sensor = esp_camera_sensor_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - return; + return ESP_FAIL; } bitmap_header_t* header = bmp_create_header(fb->width, fb->height); if (header == NULL) { - return; + return ESP_FAIL; } - int len = fb->len; - - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - len *= 3; - } + err = httpd_resp_set_type(req, "image/bmp"); - http_response_begin(http_ctx, 200, "image/bmp", sizeof(*header) + len); - http_buffer_t bmp_header = { - .data = header, - .size = sizeof(*header) - }; - http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.bmp"); - http_response_write(http_ctx, &bmp_header); + if (err == ESP_OK){ + err = httpd_resp_set_hdr(req, "Content-disposition", "inline; filename=capture.bmp"); + } + + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, (const char*)header, sizeof(*header)); + } + free(header); - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - write_gray_frame(http_ctx, fb); - }else{ - write_frame(http_ctx, fb); + if (err == ESP_OK) { + /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + err = write_gray_frame(req, fb); + }else{ + err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + } } - http_response_end(http_ctx); + /* buf_len as 0 to mark that all chunks have been sent. */ + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, 0, 0); + } esp_camera_fb_return(fb); + + return err; } -static void handle_jpg(http_context_t http_ctx, void* ctx) +/* HTTP jpg handler to take one picture */ +static esp_err_t handle_jpg(httpd_req_t *req) { + esp_err_t err = ESP_OK; + //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - return; + return ESP_FAIL; + } + + err = httpd_resp_set_type(req, "image/jpeg"); + + if (err == ESP_OK) { + err = httpd_resp_set_hdr(req, "Content-disposition", "inline; filename=capture.jpg"); } - http_response_begin(http_ctx, 200, "image/jpeg", fb->len); - http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.jpg"); - write_frame(http_ctx, fb); - http_response_end(http_ctx); + if (err == ESP_OK) { + err = httpd_resp_send(req, (const char*)fb->buf, fb->len); + } esp_camera_fb_return(fb); + + return err; } -static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx) +/* HTTP bmp stream handler */ +static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) { + char * part_buf[64]; + esp_err_t err = ESP_OK; + camera_fb_t * fb = esp_camera_fb_get(); sensor_t * sensor = esp_camera_sensor_get(); - http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); bitmap_header_t* header = bmp_create_header(fb->width, fb->height); if (header == NULL) { - return; + return ESP_FAIL; } - http_buffer_t bmp_header = { - .data = header, - .size = sizeof(*header) - }; + err = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); esp_camera_fb_return(fb); - while (true) { - esp_camera_fb_get(); + while (err == ESP_OK) { + fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - break; + err = ESP_FAIL; } - int len = fb->len; + if (err == ESP_OK) { + int len = fb->len; - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - len *= 3; - } + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + len *= 3; + } + + size_t hlen = snprintf((char *)part_buf, 64, _STREAM_BMP_PART, len + sizeof(*header)); - esp_err_t err = http_response_begin_multipart(http_ctx, "image/bitmap", len + sizeof(*header)); - if (err != ESP_OK) { - break; + err = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); } - err = http_response_write(http_ctx, &bmp_header); - if (err != ESP_OK) { - break; + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, (const char*)header, sizeof(*header)); } - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - err = write_gray_frame(http_ctx, fb); - }else{ - err = write_frame(http_ctx, fb); + if (err == ESP_OK) { + /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ + if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + err = write_gray_frame(req, fb); + }else{ + err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + } } - if (err != ESP_OK) { - break; + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); } - err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY); - esp_camera_fb_return(fb); - - if (err != ESP_OK) { - break; - } } free(header); - http_response_end(http_ctx); + + return err; } -static void handle_jpg_stream(http_context_t http_ctx, void* ctx) +/* HTTP jpg stream handler */ +static esp_err_t handle_jpg_stream(httpd_req_t *req) { - http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); + esp_err_t err = ESP_OK; + char * part_buf[64]; - while (true) { + err = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); + + while (err == ESP_OK) { //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - return; + err = ESP_FAIL; } - esp_err_t err = http_response_begin_multipart(http_ctx, "image/jpg", fb->len ); + if (err == ESP_OK) { + size_t hlen = snprintf((char *)part_buf, 64, _STREAM_JPG_PART, fb->len); - if (err != ESP_OK) { - break; + err = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); } - err = write_frame(http_ctx, fb); - if (err != ESP_OK) { - break; + + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); } - err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY); - if (err != ESP_OK) { - break; + + if (err == ESP_OK) { + err = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); } + + esp_camera_fb_return(fb); } - http_response_end(http_ctx); + + return err; +} + +static const httpd_uri_t bmp = { + .uri = "/bmp", + .method = HTTP_GET, + .handler = handle_rgb_bmp, +}; + +static const httpd_uri_t bmp_stream = { + .uri = "/bmp_stream", + .method = HTTP_GET, + .handler = handle_rgb_bmp_stream, +}; + +static const httpd_uri_t pgm = { + .uri = "/pgm", + .method = HTTP_GET, + .handler = handle_grayscale_pgm, +}; + +static const httpd_uri_t jpg = { + .uri = "/jpg", + .method = HTTP_GET, + .handler = handle_jpg, +}; + +static const httpd_uri_t jpg_stream = { + .uri = "/jpg_stream", + .method = HTTP_GET, + .handler = handle_jpg_stream, +}; + +static ip4_addr_t get_ip_addr(void) +{ + tcpip_adapter_ip_info_t ip_info; + + // IP address. + tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info); + + return ip_info.ip; } -static esp_err_t event_handler(void *ctx, system_event_t *event) +static httpd_handle_t start_webserver(void) { - switch (event->event_id) { - case SYSTEM_EVENT_STA_START: - esp_wifi_connect(); - break; - case SYSTEM_EVENT_STA_GOT_IP: - xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT); - s_ip_addr = event->event_info.got_ip.ip_info.ip; - break; - case SYSTEM_EVENT_STA_DISCONNECTED: - esp_wifi_connect(); - xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); - break; - default: - break; + httpd_handle_t server = NULL; + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + + // Start the httpd server + ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port); + if (httpd_start(&server, &config) == ESP_OK) { + // Set URI handlers + ESP_LOGI(TAG, "Registering URI handlers"); + + sensor_t * sensor = esp_camera_sensor_get(); + + ip4_addr_t s_ip_addr = get_ip_addr(); + + if (sensor->pixformat == PIXFORMAT_GRAYSCALE) { + httpd_register_uri_handler(server, &bmp); + httpd_register_uri_handler(server, &bmp_stream); + httpd_register_uri_handler(server, &pgm); + + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); + } else if (sensor->pixformat == PIXFORMAT_RGB565) { + httpd_register_uri_handler(server, &bmp); + httpd_register_uri_handler(server, &bmp_stream); + + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); + } else if (sensor->pixformat == PIXFORMAT_JPEG) { + httpd_register_uri_handler(server, &jpg); + httpd_register_uri_handler(server, &jpg_stream); + + ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); + } + + return server; } - return ESP_OK; + + ESP_LOGI(TAG, "Error starting server!"); + return NULL; } -static void initialise_wifi(void) +static void disconnect_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) { - tcpip_adapter_init(); - s_wifi_event_group = xEventGroupCreate(); - ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); - wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); - ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); - ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); - wifi_config_t wifi_config = { - .sta = { - .ssid = CONFIG_WIFI_SSID, - .password = CONFIG_WIFI_PASSWORD, - }, - }; - ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); - ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); - ESP_ERROR_CHECK( esp_wifi_start() ); - ESP_ERROR_CHECK( esp_wifi_set_ps(WIFI_PS_NONE) ); - ESP_LOGI(TAG, "Connecting to \"%s\"", wifi_config.sta.ssid); - xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); - ESP_LOGI(TAG, "Connected"); + httpd_handle_t* server = (httpd_handle_t*) arg; + if (*server) { + ESP_LOGI(TAG, "Stopping webserver"); + httpd_stop(*server); + *server = NULL; + } } +static void connect_handler(void* arg, esp_event_base_t event_base, + int32_t event_id, void* event_data) +{ + httpd_handle_t* server = (httpd_handle_t*) arg; + + if (*server == NULL) { + ESP_LOGI(TAG, "Starting webserver"); + *server = start_webserver(); + } +} + + From 78c8ba1875ba3d402b6b91a81b6e72cdab0a9e3f Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Wed, 29 Jan 2020 10:22:47 -0300 Subject: [PATCH 06/14] support RGB565, move ENABLE_TEST_PATTERN --- README.md | 1 + main/Kconfig.projbuild | 11 +++++++ main/app_main.c | 73 +++++++++++++++++++++++++++++++++++++++--- 3 files changed, 81 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 58dfede..d848121 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # ESP32 Camera Demo Code provided in this repository use the esp32-camera componet of idf for get the image using a webserver. +The demonstration was carried out with the OV7670 sensor and the IDF 4.1 version. Use RGB565 mode (two bytes) to reduce the RAM used in the ISR. ## Build Status diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index 4b85b96..ff5aeb8 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -54,4 +54,15 @@ menu "Pin Configuration" default "2" endmenu +config ENABLE_TEST_PATTERN + bool "Enable test pattern on camera output" + default n + help + Configure the camera module to output test pattern instead of live image. + + Use this option to troubleshoot image issues like noise, + distortion, not legible and missing live image. + Instead, module will generate regular vertical bars + in shades from dark to white. + endmenu diff --git a/main/app_main.c b/main/app_main.c index 275ec81..1021eb9 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -36,6 +36,9 @@ #include "protocol_examples_common.h" #include + +#define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN + static httpd_handle_t start_webserver(void); static void connect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); @@ -63,8 +66,6 @@ void app_main() ESP_ERROR_CHECK( nvs_flash_init() ); } - ESP_ERROR_CHECK(gpio_install_isr_service(0)); - static camera_config_t camera_config = { .pin_pwdn = -1, // power down is not used .pin_reset = CONFIG_RESET, // software reset will be performed @@ -89,7 +90,7 @@ void app_main() .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, - .pixel_format = /*PIXFORMAT_GRAYSCALE,*/ PIXFORMAT_RGB565, + .pixel_format = /*PIXFORMAT_GRAYSCALE,*/ PIXFORMAT_RGB565, /* PIXFORMAT_RGB888,*/ .frame_size = FRAMESIZE_QQVGA, /*FRAMESIZE_QVGA,*/ //QQVGA-QXGA Do not use sizes above QVGA when not JPEG .jpeg_quality = 12, //0-63 lower number means higher quality @@ -102,6 +103,17 @@ void app_main() return; } +#if ENABLE_TEST_PATTERN + /* Test pattern may get handy + if you are unable to get the live image right. + Once test pattern is enable, sensor will output + vertical shaded bars instead of live image. + */ + sensor_t * sensor = esp_camera_sensor_get(); + sensor->set_colorbar(sensor, 1); + ESP_LOGD(TAG, "Test pattern enabled"); +#endif + tcpip_adapter_init(); ESP_ERROR_CHECK(esp_event_loop_create_default()); @@ -172,6 +184,53 @@ esp_err_t err = ESP_OK; return err; } +/* Convert the rgb565 format in a rgb bitmap */ +static esp_err_t write_rgb565_frame(httpd_req_t *req, camera_fb_t * fb) +{ +char* buf; +int x = 0; +int size; +esp_err_t err = ESP_OK; +int rgb_index = 0; +uint8_t hb; +uint8_t lb; + + if (!fb) { + ESP_LOGE(TAG, "Camera Capture Failed"); + return ESP_FAIL; + } + + /* To save RAM send the converted image in chunks of 512 bytes. */ + buf = malloc( BUFFER_LEN * 3 ); + + if (!buf ) { + ESP_LOGE(TAG, "Dinamic memory failed"); + return ESP_FAIL; + } + + while ( (xlen) && (err == ESP_OK) ) { + size = (fb->len >= (BUFFER_LEN * 2)) ? (BUFFER_LEN * 2) : fb->len; + + rgb_index = 0; + + /* Take two rgb565 bytes to build the rgb. */ + for (int i=0; ibuf[i + x]; + lb = fb->buf[i + x + 1]; + buf[ rgb_index++ ] = (lb & 0x1F) << 3; // red + buf[ rgb_index++ ] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3; // green + buf[ rgb_index++ ] = hb & 0xF8; // blue + } + + err = httpd_resp_send_chunk(req, buf, rgb_index); + x += size; + } + + free( buf ); + + return err; +} + /* HTTP pgm handler to take one picture and file download */ static esp_err_t handle_grayscale_pgm(httpd_req_t *req) { @@ -249,6 +308,9 @@ static esp_err_t handle_rgb_bmp(httpd_req_t *req) /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ err = write_gray_frame(req, fb); + /* To save RAM and CPU in camera ISR use the rgb565 and convert to RGB in the APP */ + }else if(sensor->pixformat == PIXFORMAT_RGB565){ + err = write_rgb565_frame(req, fb); }else{ err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); } @@ -338,6 +400,9 @@ static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ err = write_gray_frame(req, fb); + /* To save RAM and CPU in camera ISR use the rgb565 and convert to RGB in the APP */ + }else if(sensor->pixformat == PIXFORMAT_RGB565){ + err = write_rgb565_frame(req, fb); }else{ err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); } @@ -455,7 +520,7 @@ static httpd_handle_t start_webserver(void) ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); - } else if (sensor->pixformat == PIXFORMAT_RGB565) { + } else if ((sensor->pixformat == PIXFORMAT_RGB565) || (sensor->pixformat == PIXFORMAT_RGB888)) { httpd_register_uri_handler(server, &bmp); httpd_register_uri_handler(server, &bmp_stream); From 20b532b53d82eb3b6de04c86aaef607435942e26 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Thu, 6 Feb 2020 10:04:43 -0300 Subject: [PATCH 07/14] update readme with camera lib --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index d848121..0855cf6 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,8 @@ Other OV7xxx series should work as well, with some changes to camera configurati Configure your PC according to [ESP32 Documentation](http://esp-idf.readthedocs.io/en/latest/?badge=latest). [Windows](http://esp-idf.readthedocs.io/en/latest/windows-setup.html), [Linux](http://esp-idf.readthedocs.io/en/latest/linux-setup.html) and [Mac OS](http://esp-idf.readthedocs.io/en/latest/macos-setup.html) are supported. If this is you first exposure to ESP32 and [esp-idf](https://github.com/espressif/esp-idf), then get familiar with [01_hello_world](https://github.com/espressif/esp-idf/tree/master/examples/01_hello_world) and [02_blink](https://github.com/espressif/esp-idf/tree/master/examples/02_blink) examples. Make them work and understand before proceeding further. +Don't forget to copy the lib [esp32-camera] (https://github.com/jjsch-dev/esp32-camera) to the IDF components folder. + ## Quick Start If you have your components ready, follow this section to [connect](#connect) the camera to ESP32 module, [flash](#flash) application to the ESP32 and finally [shoot](#shoot) and display the image. From 6169e5cba40477726691ee601a8006105662d3d4 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Thu, 6 Feb 2020 10:07:22 -0300 Subject: [PATCH 08/14] update readme with camera lib --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0855cf6..0ab43bc 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ Other OV7xxx series should work as well, with some changes to camera configurati Configure your PC according to [ESP32 Documentation](http://esp-idf.readthedocs.io/en/latest/?badge=latest). [Windows](http://esp-idf.readthedocs.io/en/latest/windows-setup.html), [Linux](http://esp-idf.readthedocs.io/en/latest/linux-setup.html) and [Mac OS](http://esp-idf.readthedocs.io/en/latest/macos-setup.html) are supported. If this is you first exposure to ESP32 and [esp-idf](https://github.com/espressif/esp-idf), then get familiar with [01_hello_world](https://github.com/espressif/esp-idf/tree/master/examples/01_hello_world) and [02_blink](https://github.com/espressif/esp-idf/tree/master/examples/02_blink) examples. Make them work and understand before proceeding further. -Don't forget to copy the lib [esp32-camera] (https://github.com/jjsch-dev/esp32-camera) to the IDF components folder. +Don't forget to copy the lib [esp32-camera](https://github.com/jjsch-dev/esp32-camera) to the IDF components folder. ## Quick Start From 217cb7a867344a42c55212509b74f6514de1b7e2 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Thu, 6 Feb 2020 11:46:43 -0300 Subject: [PATCH 09/14] update readme with camera lib info --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0ab43bc..558b8e6 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,7 @@ To make this code work, you need the following components: * [ESP32](https://espressif.com/en/products/hardware/esp32/overview) module * Camera module * PC with [esp-idf](https://github.com/espressif/esp-idf) +* Camera lib [esp32-camera](https://github.com/jjsch-dev/esp32-camera) See the following sections for more details. From 610e083ca0c251c794d145e74c182d415a1ce5c3 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Mon, 17 Feb 2020 13:42:09 -0300 Subject: [PATCH 10/14] update to idf v4.2-dev-318-g605da33c3-dirty --- main/app_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main/app_main.c b/main/app_main.c index 1021eb9..8b31893 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -33,6 +33,7 @@ #include "driver/gpio.h" #include "esp_camera.h" #include "bitmap.h" +#include "esp_netif.h" #include "protocol_examples_common.h" #include @@ -114,7 +115,7 @@ void app_main() ESP_LOGD(TAG, "Test pattern enabled"); #endif - tcpip_adapter_init(); + ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); /* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig. From 7fb534d349b370be70e01e6805ab026e620fc2fa Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Thu, 5 Mar 2020 14:53:08 -0300 Subject: [PATCH 11/14] pixel format and size selected by menuconfig --- main/Kconfig.projbuild | 128 +++++++++++++++++++++++++++++++++++++++++ main/app_main.c | 69 ++++++++++++++++++++-- 2 files changed, 191 insertions(+), 6 deletions(-) diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index ff5aeb8..05d6f8b 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -54,6 +54,123 @@ menu "Pin Configuration" default "2" endmenu +choice PIXEL_FORMAT + prompt "Select the pixel format" + default PIXFORMAT_RGB565 + help + Select the sensor output pixel format. + + config PIXFORMAT_RGB565 + bool "RGB565" + help + The RGB565 color format is the same as the RGB555 color format, + except that 6 bits are used for the green value instead of 5. + Therefore, all 16 bits are in use. + + config PIXFORMAT_YUV422 + bool "YUV422" + help + 4 bytes per 2 pixels. + + config PIXFORMAT_GRAYSCALE + bool "GRAYSCALE" + help + The value of each pixel is a single sample representing only an amount of light, + that is, it carries only intensity information. + + config PIXFORMAT_JPEG + bool "JPEG" + help + JPEG compression. + + config PIXFORMAT_RGB888 + bool "RGB888" + help + uncompressed, 3 bytes for pixel. + + config PIXFORMAT_RAW + bool "RAW" + help + raw. + + config PIXFORMAT_RGB444 + bool "RGB444" + help + 2 bytes por pixel. + + config PIXFORMAT_RGB555 + bool "RGB555" + help + 2 bytes por pixel. +endchoice + +choice FRAME_SIZE + prompt "Select the frame size" + default FRAMESIZE_QQVGA + help + Select the sensor output frame size. + + config FRAMESIZE_96X96 + bool "96x96" + help + 96 x 96 pixeles. + + config FRAMESIZE_QQVGA + bool "QQVGA" + help + 160 x 120 pixeles. + + config FRAMESIZE_QCIF + bool "QCIF" + help + 176 x 144 pixeles. + + config FRAMESIZE_HQVGA + bool "HQVGA" + help + 240 x 176. + + config FRAMESIZE_240X240 + bool "240x240" + help + 240 x 240 pixeles. + + config FRAMESIZE_QVGA + bool "QVGA" + help + 320 x 240 pixeles. + + config FRAMESIZE_CIF + bool "CIF" + help + 400 x 296 pixeles. + + config FRAMESIZE_HVGA + bool "HVGA" + help + 480 x 320 pixeles. + + config FRAMESIZE_VGA + bool "VGA" + help + 640 x 480 pixeles. + + config FRAMESIZE_SVGA + bool "SVGA" + help + 800 x 600 pixeles. + + config FRAMESIZE_XGA + bool "XGA" + help + 1024 x 768 pixeles. + + config FRAMESIZE_HD + bool "HD" + help + 1280 x 720 pixeles. +endchoice + config ENABLE_TEST_PATTERN bool "Enable test pattern on camera output" default n @@ -65,4 +182,15 @@ config ENABLE_TEST_PATTERN Instead, module will generate regular vertical bars in shades from dark to white. +config ENABLE_VERTICAL_FLIP + bool "Enable vertical flip on camera output" + default n + help + Flip the frame of the the camera module. + +config ENABLE_HORIZONTAL_MIRROR + bool "Enable horizontal mirror on camera output" + default n + help + Mirror the frame of the the camera module. endmenu diff --git a/main/app_main.c b/main/app_main.c index 8b31893..616facc 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -37,8 +37,9 @@ #include "protocol_examples_common.h" #include - -#define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN +#define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN +#define ENABLE_VERTICAL_FLIP CONFIG_ENABLE_VERTICAL_FLIP +#define ENABLE_HORIZONTAL_MIRROR CONFIG_ENABLE_HORIZONTAL_MIRROR static httpd_handle_t start_webserver(void); static void connect_handler(void* arg, esp_event_base_t event_base, @@ -91,8 +92,50 @@ void app_main() .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, - .pixel_format = /*PIXFORMAT_GRAYSCALE,*/ PIXFORMAT_RGB565, /* PIXFORMAT_RGB888,*/ - .frame_size = FRAMESIZE_QQVGA, /*FRAMESIZE_QVGA,*/ //QQVGA-QXGA Do not use sizes above QVGA when not JPEG + #if CONFIG_PIXFORMAT_RGB565 + .pixel_format = PIXFORMAT_RGB565, + #elif CONFIG_PIXFORMAT_YUV422 + .pixel_format = PIXFORMAT_YUV422, + #elif CONFIG_PIXFORMAT_GRAYSCALE + .pixel_format = PIXFORMAT_GRAYSCALE, + #elif CONFIG_PIXFORMAT_JPEG + .pixel_format = PIXFORMAT_JPEG, + #elif CONFIG_PIXFORMAT_RGB888 + .pixel_format = PIXFORMAT_RGB888, + #elif CONFIG_PIXFORMAT_RAW + .pixel_format = PIXFORMAT_RAW, + #elif CONFIG_PIXFORMAT_RGB444 + .pixel_format = PIXFORMAT_RGB444, + #elif CONFIG_PIXFORMAT_RGB555 + .pixel_format = PIXFORMAT_RGB55, + #endif + + //QQVGA-QXGA Do not use sizes above QVGA when not JPEG + #if CONFIG_FRAMESIZE_96X96 + .frame_size = FRAMESIZE_96X96, + #elif CONFIG_FRAMESIZE_QQVGA + .frame_size = FRAMESIZE_QQVGA, + #elif CONFIG_FRAMESIZE_QCIF + .frame_size = FRAMESIZE_QCIF, + #elif CONFIG_FRAMESIZE_HQVGA + .frame_size = FRAMESIZE_HQVGA, + #elif CONFIG_FRAMESIZE_240X240 + .frame_size = FRAMESIZE_240X240, + #elif CONFIG_FRAMESIZE_QVGA + .frame_size = FRAMESIZE_QVGA, + #elif CONFIG_FRAMESIZE_CIF + .frame_size = FRAMESIZE_CIF, + #elif CONFIG_FRAMESIZE_HVGA + .frame_size = FRAMESIZE_HVGA, + #elif CONFIG_FRAMESIZE_VGA + .frame_size = FRAMESIZE_VGA, + #elif CONFIG_FRAMESIZE_SVGA + .frame_size = FRAMESIZE_SVGA, + #elif CONFIG_FRAMESIZE_XGA + .frame_size = FRAMESIZE_XGA, + #elif CONFIG_FRAMESIZE_HD + .frame_size = FRAMESIZE_HD, + #endif .jpeg_quality = 12, //0-63 lower number means higher quality .fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG @@ -104,17 +147,31 @@ void app_main() return; } +#if ENABLE_TEST_PATTERN || ENABLE_VERTICAL_FLIP || ENABLE_HORIZONTAL_MIRROR + sensor_t * sensor = esp_camera_sensor_get(); +#endif + #if ENABLE_TEST_PATTERN /* Test pattern may get handy if you are unable to get the live image right. Once test pattern is enable, sensor will output vertical shaded bars instead of live image. */ - sensor_t * sensor = esp_camera_sensor_get(); sensor->set_colorbar(sensor, 1); - ESP_LOGD(TAG, "Test pattern enabled"); + ESP_LOGI(TAG, "Test pattern enabled"); #endif +#if ENABLE_VERTICAL_FLIP + sensor->set_vflip(sensor, 1); + ESP_LOGI(TAG, "Vertical flip enabled"); +#endif + +#if ENABLE_HORIZONTAL_MIRROR + sensor->set_hmirror(sensor, 1); + ESP_LOGI(TAG, "Horizontal mirror enabled"); +#endif + + ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); From 109b8200e0e3c0fa0181f7825c9ae38333feb8c9 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Sat, 14 Mar 2020 17:47:58 -0300 Subject: [PATCH 12/14] add CMakeLists.txt --- CMakeLists.txt | 12 ++++++++++++ components/camera/CMakeLists.txt | 7 +++++++ components/camera/bitmap.c | 3 ++- main/CMakeLists.txt | 11 +++++++++++ main/app_main.c | 25 +++++++++++++++++++++++++ 5 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 CMakeLists.txt create mode 100644 components/camera/CMakeLists.txt create mode 100644 main/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..4ce8bb9 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,12 @@ +# The following lines of boilerplate have to be in your project's +# CMakeLists in this exact order for cmake to work correctly +cmake_minimum_required(VERSION 3.5) + +set(EXTRA_COMPONENT_DIRS ../../../components) + +# (Not part of the boilerplate) +# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection. +set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common) + +include($ENV{IDF_PATH}/tools/cmake/project.cmake) +project(esp32-cam-demo) diff --git a/components/camera/CMakeLists.txt b/components/camera/CMakeLists.txt new file mode 100644 index 0000000..2a50fcd --- /dev/null +++ b/components/camera/CMakeLists.txt @@ -0,0 +1,7 @@ +set(COMPONENT_SRCS + bitmap.c + ) + +set(COMPONENT_ADD_INCLUDEDIRS include) + +register_component() diff --git a/components/camera/bitmap.c b/components/camera/bitmap.c index e13a638..f21e9d1 100644 --- a/components/camera/bitmap.c +++ b/components/camera/bitmap.c @@ -9,7 +9,8 @@ bitmap_header_t *bmp_create_header(int w, int h) bitmap_header_t *pbitmap = (bitmap_header_t*)calloc(1, sizeof(bitmap_header_t)); int _pixelbytesize = w * h * _bitsperpixel/8; int _filesize = _pixelbytesize+sizeof(bitmap_header_t); - strcpy((char*)pbitmap->fileheader.signature, "BM"); + pbitmap->fileheader.signature[0] = 'B'; + pbitmap->fileheader.signature[1] = 'M'; pbitmap->fileheader.filesize = _filesize; pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap_header_t); pbitmap->bitmapinfoheader.dibheadersize = sizeof(bitmapinfoheader); diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt new file mode 100644 index 0000000..ef0068e --- /dev/null +++ b/main/CMakeLists.txt @@ -0,0 +1,11 @@ +set(COMPONENT_SRCS "app_main.c") + +set(COMPONENT_REQUIRES + esp32-camera + nvs_flash + esp_http_server + camera + protocol_examples_common + ) + +register_component() diff --git a/main/app_main.c b/main/app_main.c index 616facc..025a2ef 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -389,9 +389,13 @@ static esp_err_t handle_jpg(httpd_req_t *req) { esp_err_t err = ESP_OK; + uint64_t us_start = (uint64_t) esp_timer_get_time(); + //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); + uint64_t us_capture = (uint64_t) esp_timer_get_time(); + if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); return ESP_FAIL; @@ -409,6 +413,13 @@ static esp_err_t handle_jpg(httpd_req_t *req) esp_camera_fb_return(fb); + uint64_t us_end = (uint64_t) esp_timer_get_time(); + + ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", + (int) (us_capture - us_start), + (int) (us_end - us_capture), + (int) (us_end - us_start)); + return err; } @@ -487,9 +498,16 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) err = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); while (err == ESP_OK) { + uint64_t us_start = (uint64_t) esp_timer_get_time(); + //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); + uint64_t us_capture = (uint64_t) esp_timer_get_time(); + + //acquire a frame + //camera_fb_t * fb = esp_camera_fb_get(); + if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); err = ESP_FAIL; @@ -510,6 +528,13 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) } esp_camera_fb_return(fb); + + uint64_t us_end = (uint64_t) esp_timer_get_time(); + + ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", + (int) (us_capture - us_start), + (int) (us_end - us_capture), + (int) (us_end - us_start)); } return err; From 3a169d5127cf41318bf5388a591d2ae236f22065 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Tue, 22 Dec 2020 19:02:44 -0300 Subject: [PATCH 13/14] use fmt2rgb888 use the fmt2rgb888 function of the to_bmp module to convert the formats to RGB. --- main/app_main.c | 192 ++++++++++++++++++++---------------------------- 1 file changed, 81 insertions(+), 111 deletions(-) diff --git a/main/app_main.c b/main/app_main.c index 025a2ef..2dc8b08 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -25,7 +25,7 @@ #include "esp_system.h" #include "esp_wifi.h" #include "esp_eth.h" -#include "esp_event.h" +#include "esp_event.h" #include "esp_log.h" #include "esp_err.h" #include "nvs_flash.h" @@ -42,9 +42,9 @@ #define ENABLE_HORIZONTAL_MIRROR CONFIG_ENABLE_HORIZONTAL_MIRROR static httpd_handle_t start_webserver(void); -static void connect_handler(void* arg, esp_event_base_t event_base, +static void connect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); -static void disconnect_handler(void* arg, esp_event_base_t event_base, +static void disconnect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data); static const char* TAG = "camera_demo"; @@ -58,7 +58,7 @@ static const char* _STREAM_JPG_PART = "Content-Type: image/jpg\r\nContent-Length void app_main() { static httpd_handle_t server = NULL; - + esp_log_level_set("wifi", ESP_LOG_WARN); esp_log_level_set("gpio", ESP_LOG_WARN); @@ -93,7 +93,7 @@ void app_main() .ledc_channel = LEDC_CHANNEL_0, #if CONFIG_PIXFORMAT_RGB565 - .pixel_format = PIXFORMAT_RGB565, + .pixel_format = PIXFORMAT_RGB565, #elif CONFIG_PIXFORMAT_YUV422 .pixel_format = PIXFORMAT_YUV422, #elif CONFIG_PIXFORMAT_GRAYSCALE @@ -112,7 +112,7 @@ void app_main() //QQVGA-QXGA Do not use sizes above QVGA when not JPEG #if CONFIG_FRAMESIZE_96X96 - .frame_size = FRAMESIZE_96X96, + .frame_size = FRAMESIZE_96X96, #elif CONFIG_FRAMESIZE_QQVGA .frame_size = FRAMESIZE_QQVGA, #elif CONFIG_FRAMESIZE_QCIF @@ -128,7 +128,7 @@ void app_main() #elif CONFIG_FRAMESIZE_HVGA .frame_size = FRAMESIZE_HVGA, #elif CONFIG_FRAMESIZE_VGA - .frame_size = FRAMESIZE_VGA, + .frame_size = FRAMESIZE_QCIF, #elif CONFIG_FRAMESIZE_SVGA .frame_size = FRAMESIZE_SVGA, #elif CONFIG_FRAMESIZE_XGA @@ -202,86 +202,56 @@ void app_main() #define BUFFER_LEN 512 -/* Convert the pgm gray in a rgb bitmap */ -static esp_err_t write_gray_frame(httpd_req_t *req, camera_fb_t * fb) +/* Convert the frame to a rgb bitmap */ +static esp_err_t write_frame(httpd_req_t *req, camera_fb_t * fb, pixformat_t pixformat) { char* buf; -int x = 0; -int size; +int index = 0; +int source_len; +int rgb_len; esp_err_t err = ESP_OK; - + if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); return ESP_FAIL; } - /* To save RAM send the converted image in chunks of 512 bytes. */ - buf = malloc( BUFFER_LEN * 3 ); - - if (!buf ) { - ESP_LOGE(TAG, "Dinamic memory failed"); - return ESP_FAIL; - } - - while ( (xlen) && (err == ESP_OK) ) { - size = (fb->len >= BUFFER_LEN) ? BUFFER_LEN : fb->len; - - /* To convert, match the RGB bytes to the value of the PGM byte. */ - for (int i=0; ibuf[i + x]; - buf[(i * 3) + 1 ] = fb->buf[i + x]; - buf[(i * 3) + 2 ] = fb->buf[i + x]; - } - - err = httpd_resp_send_chunk(req, buf, size * 3); - x += size; + /* Calculate the number of bytes to process for the RGB buffer. */ + if (pixformat == PIXFORMAT_GRAYSCALE) { + source_len = BUFFER_LEN; + rgb_len = (BUFFER_LEN * 3); + }else if(pixformat == PIXFORMAT_RGB565) { + source_len = BUFFER_LEN * 2; + rgb_len = (BUFFER_LEN * 3); + }else if (pixformat == PIXFORMAT_YUV422) { + source_len = BUFFER_LEN * 2; + rgb_len = (BUFFER_LEN * 3); + }else{ + ESP_LOGE(TAG, "invalid pixel format: %d", pixformat); + return ESP_FAIL; } - free( buf ); - - return err; -} + ESP_LOGI(TAG, "source len: %d RGB buffer len: %d", source_len, rgb_len); -/* Convert the rgb565 format in a rgb bitmap */ -static esp_err_t write_rgb565_frame(httpd_req_t *req, camera_fb_t * fb) -{ -char* buf; -int x = 0; -int size; -esp_err_t err = ESP_OK; -int rgb_index = 0; -uint8_t hb; -uint8_t lb; - - if (!fb) { - ESP_LOGE(TAG, "Camera Capture Failed"); - return ESP_FAIL; - } + buf = malloc( rgb_len ); - /* To save RAM send the converted image in chunks of 512 bytes. */ - buf = malloc( BUFFER_LEN * 3 ); - if (!buf ) { ESP_LOGE(TAG, "Dinamic memory failed"); - return ESP_FAIL; + return ESP_FAIL; } - while ( (xlen) && (err == ESP_OK) ) { - size = (fb->len >= (BUFFER_LEN * 2)) ? (BUFFER_LEN * 2) : fb->len; + while ( (fb->len > index) && (err == ESP_OK) ) { - rgb_index = 0; - - /* Take two rgb565 bytes to build the rgb. */ - for (int i=0; ibuf[i + x]; - lb = fb->buf[i + x + 1]; - buf[ rgb_index++ ] = (lb & 0x1F) << 3; // red - buf[ rgb_index++ ] = (hb & 0x07) << 5 | (lb & 0xE0) >> 3; // green - buf[ rgb_index++ ] = hb & 0xF8; // blue + if ((fb->len - index) < source_len) { + source_len = fb->len - index; } - err = httpd_resp_send_chunk(req, buf, rgb_index); - x += size; + if (fmt2rgb888((const uint8_t *) &fb->buf[index], source_len, pixformat, (uint8_t*)buf)) { + err = httpd_resp_send_chunk(req, buf, rgb_len); + index += source_len; + } else { + err = ESP_FAIL; + } } free( buf ); @@ -293,9 +263,9 @@ uint8_t lb; static esp_err_t handle_grayscale_pgm(httpd_req_t *req) { esp_err_t err = ESP_OK; - + char pgm_header_str[64]; - + // acquire a frame camera_fb_t * fb = esp_camera_fb_get(); @@ -335,23 +305,25 @@ static esp_err_t handle_rgb_bmp(httpd_req_t *req) { esp_err_t err = ESP_OK; + ESP_LOGI(TAG, "Image captured begin"); + // acquire a frame camera_fb_t * fb = esp_camera_fb_get(); - sensor_t * sensor = esp_camera_sensor_get(); - if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); return ESP_FAIL; } + ESP_LOGI(TAG, "Image captured width: %d, heigth:%d, len: %d", fb->width, fb->height, fb->len); + bitmap_header_t* header = bmp_create_header(fb->width, fb->height); if (header == NULL) { return ESP_FAIL; } err = httpd_resp_set_type(req, "image/bmp"); - + if (err == ESP_OK){ err = httpd_resp_set_hdr(req, "Content-disposition", "inline; filename=capture.bmp"); } @@ -362,15 +334,13 @@ static esp_err_t handle_rgb_bmp(httpd_req_t *req) free(header); + sensor_t * sensor = esp_camera_sensor_get(); + if (err == ESP_OK) { - /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - err = write_gray_frame(req, fb); - /* To save RAM and CPU in camera ISR use the rgb565 and convert to RGB in the APP */ - }else if(sensor->pixformat == PIXFORMAT_RGB565){ - err = write_rgb565_frame(req, fb); - }else{ + if (sensor->pixformat == PIXFORMAT_RGB888) { err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + } else { + err = write_frame(req, fb, sensor->pixformat); } } @@ -388,7 +358,7 @@ static esp_err_t handle_rgb_bmp(httpd_req_t *req) static esp_err_t handle_jpg(httpd_req_t *req) { esp_err_t err = ESP_OK; - + uint64_t us_start = (uint64_t) esp_timer_get_time(); //acquire a frame @@ -415,7 +385,7 @@ static esp_err_t handle_jpg(httpd_req_t *req) uint64_t us_end = (uint64_t) esp_timer_get_time(); - ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", + ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", (int) (us_capture - us_start), (int) (us_end - us_capture), (int) (us_end - us_start)); @@ -446,16 +416,21 @@ static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); - err = ESP_FAIL; + err = ESP_FAIL; } if (err == ESP_OK) { int len = fb->len; - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ + ESP_LOGI(TAG, "Image captured width: %d, heigth:%d, len: %d", fb->width, fb->height, fb->len); + + if (sensor->pixformat == PIXFORMAT_GRAYSCALE) { len *= 3; - } - + } + else if (sensor->pixformat == PIXFORMAT_YUV422) { + len *= 2; + } + size_t hlen = snprintf((char *)part_buf, 64, _STREAM_BMP_PART, len + sizeof(*header)); err = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); @@ -466,17 +441,13 @@ static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) } if (err == ESP_OK) { - /* convert an image with a gray format of 8 bits to a 24 bit bmp. */ - if(sensor->pixformat == PIXFORMAT_GRAYSCALE){ - err = write_gray_frame(req, fb); - /* To save RAM and CPU in camera ISR use the rgb565 and convert to RGB in the APP */ - }else if(sensor->pixformat == PIXFORMAT_RGB565){ - err = write_rgb565_frame(req, fb); - }else{ + if (sensor->pixformat == PIXFORMAT_RGB888) { err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + } else { + err = write_frame(req, fb, sensor->pixformat); } } - + if (err == ESP_OK) { err = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); } @@ -485,7 +456,7 @@ static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) } free(header); - + return err; } @@ -504,7 +475,7 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) camera_fb_t * fb = esp_camera_fb_get(); uint64_t us_capture = (uint64_t) esp_timer_get_time(); - + //acquire a frame //camera_fb_t * fb = esp_camera_fb_get(); @@ -522,7 +493,7 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) if (err == ESP_OK) { err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); } - + if (err == ESP_OK) { err = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY)); } @@ -531,12 +502,12 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) uint64_t us_end = (uint64_t) esp_timer_get_time(); - ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", + ESP_LOGI(TAG, "JPG Capture time %d uS, send time %d uS, total %d uS", (int) (us_capture - us_start), (int) (us_end - us_capture), (int) (us_end - us_start)); } - + return err; } @@ -572,8 +543,8 @@ static const httpd_uri_t jpg_stream = { static ip4_addr_t get_ip_addr(void) { - tcpip_adapter_ip_info_t ip_info; - + tcpip_adapter_ip_info_t ip_info; + // IP address. tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info); @@ -594,7 +565,7 @@ static httpd_handle_t start_webserver(void) sensor_t * sensor = esp_camera_sensor_get(); ip4_addr_t s_ip_addr = get_ip_addr(); - + if (sensor->pixformat == PIXFORMAT_GRAYSCALE) { httpd_register_uri_handler(server, &bmp); httpd_register_uri_handler(server, &bmp_stream); @@ -603,16 +574,17 @@ static httpd_handle_t start_webserver(void) ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); - } else if ((sensor->pixformat == PIXFORMAT_RGB565) || (sensor->pixformat == PIXFORMAT_RGB888)) { + } else if ((sensor->pixformat == PIXFORMAT_RGB565) || (sensor->pixformat == PIXFORMAT_RGB888) || + (sensor->pixformat == PIXFORMAT_YUV422)) { httpd_register_uri_handler(server, &bmp); httpd_register_uri_handler(server, &bmp_stream); - + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); } else if (sensor->pixformat == PIXFORMAT_JPEG) { - httpd_register_uri_handler(server, &jpg); - httpd_register_uri_handler(server, &jpg_stream); - + httpd_register_uri_handler(server, &jpg); + httpd_register_uri_handler(server, &jpg_stream); + ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); } @@ -624,7 +596,7 @@ static httpd_handle_t start_webserver(void) return NULL; } -static void disconnect_handler(void* arg, esp_event_base_t event_base, +static void disconnect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { httpd_handle_t* server = (httpd_handle_t*) arg; @@ -635,7 +607,7 @@ static void disconnect_handler(void* arg, esp_event_base_t event_base, } } -static void connect_handler(void* arg, esp_event_base_t event_base, +static void connect_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { httpd_handle_t* server = (httpd_handle_t*) arg; @@ -645,5 +617,3 @@ static void connect_handler(void* arg, esp_event_base_t event_base, *server = start_webserver(); } } - - From 151da7b05ae963dfb90b6d0ed3dda085aeb60922 Mon Sep 17 00:00:00 2001 From: jjsch-dev Date: Tue, 22 Dec 2020 21:37:43 -0300 Subject: [PATCH 14/14] jpg format convertion the camera to_jpg module is used to convert RGB to JPG formats. --- main/app_main.c | 78 ++++++++++++++++++++++++++++++++++--------------- 1 file changed, 54 insertions(+), 24 deletions(-) diff --git a/main/app_main.c b/main/app_main.c index 2dc8b08..92bf4b4 100644 --- a/main/app_main.c +++ b/main/app_main.c @@ -128,7 +128,7 @@ void app_main() #elif CONFIG_FRAMESIZE_HVGA .frame_size = FRAMESIZE_HVGA, #elif CONFIG_FRAMESIZE_VGA - .frame_size = FRAMESIZE_QCIF, + .frame_size = FRAMESIZE_VGA, #elif CONFIG_FRAMESIZE_SVGA .frame_size = FRAMESIZE_SVGA, #elif CONFIG_FRAMESIZE_XGA @@ -354,6 +354,23 @@ static esp_err_t handle_rgb_bmp(httpd_req_t *req) return err; } +typedef struct { + httpd_req_t *req; + size_t len; +} jpg_chunking_t; + +static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ + jpg_chunking_t *j = (jpg_chunking_t *)arg; + if(!index){ + j->len = 0; + } + if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){ + return 0; + } + j->len += len; + return len; +} + /* HTTP jpg handler to take one picture */ static esp_err_t handle_jpg(httpd_req_t *req) { @@ -361,6 +378,8 @@ static esp_err_t handle_jpg(httpd_req_t *req) uint64_t us_start = (uint64_t) esp_timer_get_time(); + size_t fb_len = 0; + //acquire a frame camera_fb_t * fb = esp_camera_fb_get(); @@ -378,7 +397,15 @@ static esp_err_t handle_jpg(httpd_req_t *req) } if (err == ESP_OK) { - err = httpd_resp_send(req, (const char*)fb->buf, fb->len); + if(fb->format == PIXFORMAT_JPEG){ + fb_len = fb->len; + err = httpd_resp_send(req, (const char *)fb->buf, fb->len); + } else { + jpg_chunking_t jchunk = {req, 0}; + err = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL; + httpd_resp_send_chunk(req, NULL, 0); + fb_len = jchunk.len; + } } esp_camera_fb_return(fb); @@ -463,6 +490,8 @@ static esp_err_t handle_rgb_bmp_stream(httpd_req_t *req) /* HTTP jpg stream handler */ static esp_err_t handle_jpg_stream(httpd_req_t *req) { + size_t _jpg_buf_len; + uint8_t * _jpg_buf; esp_err_t err = ESP_OK; char * part_buf[64]; @@ -476,14 +505,23 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) uint64_t us_capture = (uint64_t) esp_timer_get_time(); - //acquire a frame - //camera_fb_t * fb = esp_camera_fb_get(); - if (!fb) { ESP_LOGE(TAG, "Camera Capture Failed"); err = ESP_FAIL; } + if(fb->format != PIXFORMAT_JPEG){ + bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); + if(!jpeg_converted){ + ESP_LOGE(TAG, "JPEG compression failed"); + esp_camera_fb_return(fb); + err = ESP_FAIL; + } + } else { + _jpg_buf_len = fb->len; + _jpg_buf = fb->buf; + } + if (err == ESP_OK) { size_t hlen = snprintf((char *)part_buf, 64, _STREAM_JPG_PART, fb->len); @@ -491,7 +529,7 @@ static esp_err_t handle_jpg_stream(httpd_req_t *req) } if (err == ESP_OK) { - err = httpd_resp_send_chunk(req, (const char*)fb->buf, fb->len); + err = httpd_resp_send_chunk(req, (const char*)_jpg_buf, _jpg_buf_len); } if (err == ESP_OK) { @@ -566,27 +604,19 @@ static httpd_handle_t start_webserver(void) ip4_addr_t s_ip_addr = get_ip_addr(); + httpd_register_uri_handler(server, &bmp); + httpd_register_uri_handler(server, &bmp_stream); + httpd_register_uri_handler(server, &jpg); + httpd_register_uri_handler(server, &jpg_stream); + + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); + ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); + if (sensor->pixformat == PIXFORMAT_GRAYSCALE) { - httpd_register_uri_handler(server, &bmp); - httpd_register_uri_handler(server, &bmp_stream); httpd_register_uri_handler(server, &pgm); - - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for a single image/bmp gray image", IP2STR(&s_ip_addr)); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of gray bitmaps", IP2STR(&s_ip_addr)); ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); - } else if ((sensor->pixformat == PIXFORMAT_RGB565) || (sensor->pixformat == PIXFORMAT_RGB888) || - (sensor->pixformat == PIXFORMAT_YUV422)) { - httpd_register_uri_handler(server, &bmp); - httpd_register_uri_handler(server, &bmp_stream); - - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); - ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); - } else if (sensor->pixformat == PIXFORMAT_JPEG) { - httpd_register_uri_handler(server, &jpg); - httpd_register_uri_handler(server, &jpg_stream); - - ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); - ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); } return server;