├── .gitmodules ├── main ├── eye.raw ├── CMakeLists.txt ├── val2pwm.h ├── component.mk ├── display.h ├── Kconfig.projbuild ├── val2pwm.c ├── display.c └── main.c ├── components ├── ov2640 │ ├── camera │ │ ├── private_include │ │ │ ├── xclk.h │ │ │ ├── sccb.h │ │ │ ├── camera_common.h │ │ │ └── twi.h │ │ ├── sensor.c │ │ ├── xclk.c │ │ ├── sccb.c │ │ ├── include │ │ │ ├── sensor.h │ │ │ └── esp_camera.h │ │ └── twi.c │ ├── component.mk │ ├── sensors │ │ ├── private_include │ │ │ ├── ov2640.h │ │ │ ├── ov2640_regs.h │ │ │ └── ov2640_settings.h │ │ └── ov2640.c │ ├── CMakeLists.txt │ └── conversions │ │ ├── private_include │ │ ├── yuv.h │ │ └── jpge.h │ │ ├── include │ │ ├── esp_jpg_decode.h │ │ └── img_converters.h │ │ ├── esp_jpg_decode.c │ │ ├── to_jpg.cpp │ │ ├── to_bmp.c │ │ ├── yuv.c │ │ └── jpge.cpp └── ov2640-readme.txt ├── Makefile ├── CMakeLists.txt ├── README.md ├── eye_gfx ├── buildraw.sh └── notes.txt └── sdkconfig /.gitmodules: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /main/eye.raw: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Spritetm/esp32-frekvens/HEAD/main/eye.raw -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | idf_component_register(SRCS "main.c display.c val2pwm.c" 2 | INCLUDE_DIRS ".") -------------------------------------------------------------------------------- /main/val2pwm.h: -------------------------------------------------------------------------------- 1 | 2 | //Converts an 0-255 intensity value to an equivalent 0-64k LED PWM value 3 | int valToPwm(int val); 4 | -------------------------------------------------------------------------------- /components/ov2640/camera/private_include/xclk.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "camera_common.h" 4 | 5 | esp_err_t camera_enable_out_clock(); 6 | 7 | void camera_disable_out_clock(); 8 | -------------------------------------------------------------------------------- /components/ov2640-readme.txt: -------------------------------------------------------------------------------- 1 | This is mostly (an old version of) the standard esp32 camera ov2640 module tweaked 2 | a bit to remove the psram dependency. Original is at https://github.com/espressif/esp32-camera 3 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | COMPONENT_EMBED_FILES = eye.raw 7 | 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := blink 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following five lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 6 | project(blink) 7 | -------------------------------------------------------------------------------- /components/ov2640/component.mk: -------------------------------------------------------------------------------- 1 | COMPONENT_ADD_INCLUDEDIRS := conversions/include camera/include 2 | COMPONENT_PRIV_INCLUDEDIRS := conversions/private_include camera/private_include sensors/private_include 3 | COMPONENT_SRCDIRS := conversions camera sensors 4 | CXXFLAGS += -fno-rtti 5 | -------------------------------------------------------------------------------- /components/ov2640/sensors/private_include/ov2640.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * OV2640 driver. 7 | * 8 | */ 9 | #ifndef __OV2640_H__ 10 | #define __OV2640_H__ 11 | #include "sensor.h" 12 | int ov2640_init(sensor_t *sensor); 13 | #endif // __OV2640_H__ 14 | -------------------------------------------------------------------------------- /components/ov2640/camera/sensor.c: -------------------------------------------------------------------------------- 1 | 2 | const int resolution[][2] = { 3 | { 160, 120 }, /* QQVGA */ 4 | { 128, 160 }, /* QQVGA2*/ 5 | { 176, 144 }, /* QCIF */ 6 | { 240, 176 }, /* HQVGA */ 7 | { 320, 240 }, /* QVGA */ 8 | { 400, 296 }, /* CIF */ 9 | { 640, 480 }, /* VGA */ 10 | { 800, 600 }, /* SVGA */ 11 | { 1024, 768 }, /* XGA */ 12 | { 1280, 1024 }, /* SXGA */ 13 | { 1600, 1200 }, /* UXGA */ 14 | }; 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | This is code that belongs to the project at http://spritesmods.com/?art=frekvens 3 | 4 | This firmware is intended for an ESP-Cam, but will possibly work on any board connected to 5 | an ov2640 camera. It does not use or require PSRAM. It's built for ESP-IDF 4.0, but may or may 6 | not also work with earlier or later versions. 7 | 8 | Connections from the ESP-Cams GPIOs to the Frekvens board: 9 | 10 | LAK - GPIO14 11 | CLK - GPIO15 12 | DA - GPIO13 13 | EN - GPIO12 (or connect to gnd) 14 | 15 | Button 1 - GPIO2 16 | Button 2 - GPIO4 (note: unused) 17 | Button common - GND 18 | 19 | -------------------------------------------------------------------------------- /components/ov2640/camera/private_include/sccb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * SCCB (I2C like) driver. 7 | * 8 | */ 9 | #ifndef __SCCB_H__ 10 | #define __SCCB_H__ 11 | #include 12 | int SCCB_Init(int pin_sda, int pin_scl); 13 | uint8_t SCCB_Probe(); 14 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg); 15 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data); 16 | #endif // __SCCB_H__ 17 | -------------------------------------------------------------------------------- /components/ov2640/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCS 2 | camera/camera.c 3 | camera/sccb.c 4 | camera/sensor.c 5 | camera/twi.c 6 | camera/xclk.c 7 | sensors/ov2640.c 8 | conversions/yuv.c 9 | conversions/to_jpg.cpp 10 | conversions/to_bmp.c 11 | conversions/jpge.cpp 12 | conversions/esp_jpg_decode.c 13 | ) 14 | 15 | set(COMPONENT_ADD_INCLUDEDIRS 16 | camera/include 17 | conversions/include 18 | ) 19 | 20 | set(COMPONENT_PRIV_INCLUDEDIRS 21 | camera/private_include 22 | sensors/private_include 23 | conversions/private_include 24 | ) 25 | 26 | set(COMPONENT_REQUIRES driver) 27 | set(COMPONENT_PRIV_REQUIRES freertos) 28 | 29 | register_component() 30 | -------------------------------------------------------------------------------- /main/display.h: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | Display driver for Frekvens LED display board. 4 | 5 | Note that this driver uses two framebuffers: a front- and a backbuffer. Normally, 6 | the frontbuffer is the buffer being displayed on the LEDs. The backbuffer can be modified 7 | by calling display_setpixel() to change individual pixels. The backbuffer and the frontbuffer 8 | can be swapped by calling display_flip(), at which point all the previous changed by calling 9 | display_setpixel() will become visible. 10 | */ 11 | 12 | //Initialize the LED display. 13 | void display_init(); 14 | 15 | //Set a pixel at (x,y) to a certain value v (0-255) in the backbuffer 16 | void display_setpixel(int x, int y, int v); 17 | 18 | //Flip front- and backbuffers 19 | void display_flip(); 20 | -------------------------------------------------------------------------------- /components/ov2640/conversions/private_include/yuv.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef _CONVERSIONS_YUV_H_ 15 | #define _CONVERSIONS_YUV_H_ 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #include 22 | 23 | void yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b); 24 | 25 | #ifdef __cplusplus 26 | } 27 | #endif 28 | 29 | #endif /* _CONVERSIONS_YUV_H_ */ 30 | -------------------------------------------------------------------------------- /components/ov2640/camera/private_include/camera_common.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include "rom/lldesc.h" 7 | #include "esp_err.h" 8 | #include "esp_intr_alloc.h" 9 | #include "freertos/FreeRTOS.h" 10 | #include "freertos/semphr.h" 11 | #include "freertos/task.h" 12 | #include "esp_camera.h" 13 | #include "sensor.h" 14 | 15 | typedef union { 16 | struct { 17 | uint8_t sample2; 18 | uint8_t unused2; 19 | uint8_t sample1; 20 | uint8_t unused1; 21 | }; 22 | uint32_t val; 23 | } dma_elem_t; 24 | 25 | typedef enum { 26 | /* camera sends byte sequence: s1, s2, s3, s4, ... 27 | * fifo receives: 00 s1 00 s2, 00 s2 00 s3, 00 s3 00 s4, ... 28 | */ 29 | SM_0A0B_0B0C = 0, 30 | /* camera sends byte sequence: s1, s2, s3, s4, ... 31 | * fifo receives: 00 s1 00 s2, 00 s3 00 s4, ... 32 | */ 33 | SM_0A0B_0C0D = 1, 34 | /* camera sends byte sequence: s1, s2, s3, s4, ... 35 | * fifo receives: 00 s1 00 00, 00 s2 00 00, 00 s3 00 00, ... 36 | */ 37 | SM_0A00_0B00 = 3, 38 | } i2s_sampling_mode_t; 39 | 40 | -------------------------------------------------------------------------------- /eye_gfx/buildraw.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #License for this hacky script... errm... either public domain or CC0, whichever you can use. 4 | 5 | #Box around the eye; the bit that you want to have show up on the LED screen 6 | EYE_COORDS="289x289+140+98" 7 | 8 | rm -f cropped.png eye.raw cropped.raw 9 | for x in *.tif; do 10 | #Cut out bit around eye. 11 | convert $x -crop "$EYE_COORDS" cropped.png 12 | #Tweak brightness/contrast, resize to 16x16 and convert to a raw grayscale file 13 | convert cropped.png -brightness-contrast -15x30% -resize 16x16 -channel B -separate -depth 8 gray:cropped.raw 14 | #Add to general file store 15 | cat cropped.raw >> eye.raw 16 | #Check where the first red dot is in the det/ image 17 | l=`convert det/${x%.tif}.png txt: | grep '#FF0000FF' | head -n 1 | sed 's/[,:]/ /g'` 18 | read x y c <<< $l 19 | #Top left / right are blink; the assumption is that the pupil coordinates are the same as the 20 | #non-blink image before. 21 | if [ $y -lt 30 ]; then 22 | if [ $x -lt 200 ]; then 23 | c=1 24 | else 25 | c=2 26 | fi 27 | x=$px 28 | y=$py 29 | else 30 | c=0 31 | px=$x 32 | py=$y 33 | fi 34 | echo -e "\t{$x, $y, $c}," 35 | done 36 | 37 | -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "Camera configuration" 2 | 3 | config XCLK_FREQ 4 | int "XCLK Frequency" 5 | default "20000000" 6 | help 7 | The XCLK Frequency in Herz. 8 | 9 | menu "Pin Configuration" 10 | config D0 11 | int "D0" 12 | default "5" 13 | config D1 14 | int "D1" 15 | default "18" 16 | config D2 17 | int "D2" 18 | default "19" 19 | config D3 20 | int "D3" 21 | default "21" 22 | config D4 23 | int "D4" 24 | default "36" 25 | config D5 26 | int "D5" 27 | default "39" 28 | config D6 29 | int "D6" 30 | default "34" 31 | config D7 32 | int "D7" 33 | default "35" 34 | config XCLK 35 | int "XCLK" 36 | default "0" 37 | config PCLK 38 | int "PCLK" 39 | default "22" 40 | config VSYNC 41 | int "VSYNC" 42 | default "25" 43 | config HREF 44 | int "HREF" 45 | default "23" 46 | config SDA 47 | int "SDA" 48 | default "26" 49 | config SCL 50 | int "SCL" 51 | default "27" 52 | config RESET 53 | int "RESET" 54 | default "32" 55 | endmenu 56 | 57 | endmenu 58 | -------------------------------------------------------------------------------- /components/ov2640/camera/private_include/twi.h: -------------------------------------------------------------------------------- 1 | /* 2 | twi.h - Software I2C library for ESP31B 3 | 4 | Copyright (c) 2015 Hristo Gochkov. All rights reserved. 5 | This file is part of the ESP31B core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #ifndef SI2C_h 22 | #define SI2C_h 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | void twi_init(unsigned char sda, unsigned char scl); 29 | void twi_stop(void); 30 | void twi_setClock(unsigned int freq); 31 | uint8_t twi_writeTo(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); 32 | uint8_t twi_readFrom(unsigned char address, unsigned char * buf, unsigned int len, unsigned char sendStop); 33 | 34 | #ifdef __cplusplus 35 | } 36 | #endif 37 | 38 | #endif -------------------------------------------------------------------------------- /components/ov2640/camera/xclk.c: -------------------------------------------------------------------------------- 1 | #include "driver/gpio.h" 2 | #include "driver/ledc.h" 3 | #include "esp_err.h" 4 | #include "esp_log.h" 5 | #include "xclk.h" 6 | 7 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 8 | #include "esp32-hal-log.h" 9 | #else 10 | #include "esp_log.h" 11 | static const char *TAG = "camera_xclk"; 12 | #endif 13 | 14 | esp_err_t camera_enable_out_clock(camera_config_t *config) 15 | { 16 | periph_module_enable(PERIPH_LEDC_MODULE); 17 | 18 | ledc_timer_config_t timer_conf={}; 19 | timer_conf.duty_resolution = 2; 20 | timer_conf.freq_hz = config->xclk_freq_hz; 21 | timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 22 | timer_conf.timer_num = config->ledc_timer; 23 | esp_err_t err = ledc_timer_config(&timer_conf); 24 | if (err != ESP_OK) 25 | { 26 | ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); 27 | return err; 28 | } 29 | 30 | ledc_channel_config_t ch_conf; 31 | ch_conf.gpio_num = config->pin_xclk; 32 | ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 33 | ch_conf.channel = config->ledc_channel; 34 | ch_conf.intr_type = LEDC_INTR_DISABLE; 35 | ch_conf.timer_sel = config->ledc_timer; 36 | ch_conf.duty = 2; 37 | ch_conf.hpoint = 0; 38 | err = ledc_channel_config(&ch_conf); 39 | if (err != ESP_OK) 40 | { 41 | ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err); 42 | return err; 43 | } 44 | return ESP_OK; 45 | } 46 | 47 | void camera_disable_out_clock() 48 | { 49 | periph_module_disable(PERIPH_LEDC_MODULE); 50 | } 51 | -------------------------------------------------------------------------------- /components/ov2640/conversions/include/esp_jpg_decode.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef _ESP_JPG_DECODE_H_ 15 | #define _ESP_JPG_DECODE_H_ 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include "esp_err.h" 25 | 26 | typedef enum { 27 | JPG_SCALE_NONE, 28 | JPG_SCALE_2X, 29 | JPG_SCALE_4X, 30 | JPG_SCALE_8X, 31 | JPG_SCALE_MAX = JPG_SCALE_8X 32 | } jpg_scale_t; 33 | 34 | typedef size_t (* jpg_reader_cb)(void * arg, size_t index, uint8_t *buf, size_t len); 35 | typedef bool (* jpg_writer_cb)(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data); 36 | 37 | esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg); 38 | 39 | #ifdef __cplusplus 40 | } 41 | #endif 42 | 43 | #endif /* _ESP_JPG_DECODE_H_ */ 44 | -------------------------------------------------------------------------------- /eye_gfx/notes.txt: -------------------------------------------------------------------------------- 1 | Sorry, I'm not going to include the original imagery and all the side products 2 | here. I'm not too comfortable with having detailed pictures of my iris out 3 | there... Instead, I'll tell you the process so you can hopefully recreate it 4 | yourself. This is from memory, forgive any small mistakes please. 5 | 6 | How this is generated: 7 | 8 | - Take video of your eye/face, looking in a bunch of directions and blinking 9 | - Cut video up in frames, generously cropping the region around one eye, 10 | plus a bit of the nose and side of face for reference: 11 | 12 | mplayer -ao null -vf eq2=1:1.8:0 -vf-add crop=500:500:910:450 \ 13 | -vf-add flip,mirror VID_20200226_194203920.mp4 -vf-add scale -vo jpeg 14 | 15 | (You probably want to adjust the crop parameters for your situation.) 16 | 17 | - Use geeqie or another image viewer to remove 3/4th of the resulting frames as 18 | they're more-or-less duplicate or useless and the rest of the steps will take 19 | forever unless you reduce the amount of frames. No need to closely pick the 20 | frames you're going to use, though, feel free to leave some superfluous frames 21 | in, just remove the bulk of the useless ones. 22 | 23 | - Using Hugin, align the images to get rid of camera and head movement: 24 | align_image_stack -v -l -a aligned *.jpg 25 | Yes, this will take a fairly long time, depending on the amount of images you 26 | have left. 27 | 28 | - Generate black-and-white images where you can mark the pupil 29 | 30 | mkdir det/ 31 | for x in aligned*.tif; do convert $x -grayscale Rec709Luminance -type TrueColor -define png:color-type=6 det/{$x%.tif}.png; done 32 | 33 | - Open all the files in the det/ directory and use a red dot (#ff0000) to mark them: place a dot in the 34 | center of the pupil if the eye is open, in the top left corner if it's half-closed and the top right 35 | if it's entirely closed. 36 | 37 | - Get the size and top left (x,y) coordinates of the bit of the eye that you would like to show on the 38 | box and edit them on the top of buildraw.sh 39 | 40 | - Run buildraw.sh 41 | 42 | - Copy the list of data that it generates into ../main/main.c under the line 'const imgdesc_t images[]={' 43 | 44 | - Copy eye.raw to ../main/eye.raw 45 | 46 | - Compile, flash, go! 47 | -------------------------------------------------------------------------------- /components/ov2640/camera/sccb.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * SCCB (I2C like) driver. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "sccb.h" 13 | #include "twi.h" 14 | #include 15 | #include "sdkconfig.h" 16 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 17 | #include "esp32-hal-log.h" 18 | #else 19 | #include "esp_log.h" 20 | static const char* TAG = "sccb"; 21 | #endif 22 | 23 | 24 | #define SCCB_FREQ (100000) // We don't need fast I2C. 100KHz is fine here. 25 | #define TIMEOUT (1000) /* Can't be sure when I2C routines return. Interrupts 26 | while polling hardware may result in unknown delays. */ 27 | 28 | 29 | int SCCB_Init(int pin_sda, int pin_scl) 30 | { 31 | twi_init(pin_sda, pin_scl); 32 | return 0; 33 | } 34 | 35 | uint8_t SCCB_Probe() 36 | { 37 | uint8_t reg = 0x00; 38 | uint8_t slv_addr = 0x00; 39 | 40 | for (uint8_t i=0; i<127; i++) { 41 | if (twi_writeTo(i, ®, 1, true) == 0) { 42 | slv_addr = i; 43 | break; 44 | } 45 | 46 | if (i!=126) { 47 | vTaskDelay(1 / portTICK_PERIOD_MS); // Necessary for OV7725 camera (not for OV2640). 48 | } 49 | } 50 | return slv_addr; 51 | } 52 | 53 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg) 54 | { 55 | uint8_t data=0; 56 | 57 | int rc = twi_writeTo(slv_addr, ®, 1, true); 58 | if (rc != 0) { 59 | data = 0xff; 60 | } else { 61 | rc = twi_readFrom(slv_addr, &data, 1, true); 62 | if (rc != 0) { 63 | data=0xFF; 64 | } 65 | } 66 | if (rc != 0) { 67 | ESP_LOGE(TAG, "SCCB_Read [%02x] failed rc=%d\n", reg, rc); 68 | } 69 | return data; 70 | } 71 | 72 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data) 73 | { 74 | uint8_t ret=0; 75 | uint8_t buf[] = {reg, data}; 76 | 77 | if(twi_writeTo(slv_addr, buf, 2, true) != 0) { 78 | ret=0xFF; 79 | } 80 | if (ret != 0) { 81 | printf("SCCB_Write [%02x]=%02x failed\n", reg, data); 82 | } 83 | return ret; 84 | } 85 | -------------------------------------------------------------------------------- /main/val2pwm.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * For the bits that are actually copyrightable: 4 | * ---------------------------------------------------------------------------- 5 | * "THE BEER-WARE LICENSE" (Revision 42): 6 | * Jeroen Domburg wrote this file. As long as you retain 7 | * this notice you can do whatever you want with this stuff. If we meet some day, 8 | * and you think this stuff is worth it, you can buy me a beer in return. 9 | * ---------------------------------------------------------------------------- 10 | */ 11 | 12 | 13 | #include 14 | #include "val2pwm.h" 15 | 16 | //C/p'ed from https://ledshield.wordpress.com/2012/11/13/led-brightness-to-your-eye-gamma-correction-no/ 17 | const uint16_t lumConvTab[]={ 18 | 65535, 65508, 65479, 65451, 65422, 65394, 65365, 65337, 19 | 65308, 65280, 65251, 65223, 65195, 65166, 65138, 65109, 20 | 65081, 65052, 65024, 64995, 64967, 64938, 64909, 64878, 21 | 64847, 64815, 64781, 64747, 64711, 64675, 64637, 64599, 22 | 64559, 64518, 64476, 64433, 64389, 64344, 64297, 64249, 23 | 64200, 64150, 64099, 64046, 63992, 63937, 63880, 63822, 24 | 63763, 63702, 63640, 63577, 63512, 63446, 63379, 63310, 25 | 63239, 63167, 63094, 63019, 62943, 62865, 62785, 62704, 26 | 62621, 62537, 62451, 62364, 62275, 62184, 62092, 61998, 27 | 61902, 61804, 61705, 61604, 61501, 61397, 61290, 61182, 28 | 61072, 60961, 60847, 60732, 60614, 60495, 60374, 60251, 29 | 60126, 59999, 59870, 59739, 59606, 59471, 59334, 59195, 30 | 59053, 58910, 58765, 58618, 58468, 58316, 58163, 58007, 31 | 57848, 57688, 57525, 57361, 57194, 57024, 56853, 56679, 32 | 56503, 56324, 56143, 55960, 55774, 55586, 55396, 55203, 33 | 55008, 54810, 54610, 54408, 54203, 53995, 53785, 53572, 34 | 53357, 53140, 52919, 52696, 52471, 52243, 52012, 51778, 35 | 51542, 51304, 51062, 50818, 50571, 50321, 50069, 49813, 36 | 49555, 49295, 49031, 48764, 48495, 48223, 47948, 47670, 37 | 47389, 47105, 46818, 46529, 46236, 45940, 45641, 45340, 38 | 45035, 44727, 44416, 44102, 43785, 43465, 43142, 42815, 39 | 42486, 42153, 41817, 41478, 41135, 40790, 40441, 40089, 40 | 39733, 39375, 39013, 38647, 38279, 37907, 37531, 37153, 41 | 36770, 36385, 35996, 35603, 35207, 34808, 34405, 33999, 42 | 33589, 33175, 32758, 32338, 31913, 31486, 31054, 30619, 43 | 30181, 29738, 29292, 28843, 28389, 27932, 27471, 27007, 44 | 26539, 26066, 25590, 25111, 24627, 24140, 23649, 23153, 45 | 22654, 22152, 21645, 21134, 20619, 20101, 19578, 19051, 46 | 18521, 17986, 17447, 16905, 16358, 15807, 15252, 14693, 47 | 14129, 13562, 12990, 12415, 11835, 11251, 10662, 10070, 48 | 9473, 8872, 8266, 7657, 7043, 6424, 5802, 5175, 49 | 4543, 3908, 3267, 2623, 1974, 1320, 662, 0}; 50 | 51 | 52 | int valToPwm(int val) { 53 | if (val<0) val=0; 54 | if (val>255) val=255; 55 | return (65535-lumConvTab[val]); 56 | } 57 | -------------------------------------------------------------------------------- /components/ov2640/conversions/esp_jpg_decode.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include "esp_jpg_decode.h" 15 | #include "rom/tjpgd.h" 16 | 17 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 18 | #include "esp32-hal-log.h" 19 | #define TAG "" 20 | #else 21 | #include "esp_log.h" 22 | static const char* TAG = "esp_jpg_decode"; 23 | #endif 24 | 25 | typedef struct { 26 | jpg_scale_t scale; 27 | jpg_reader_cb reader; 28 | jpg_writer_cb writer; 29 | void * arg; 30 | size_t len; 31 | size_t index; 32 | } esp_jpg_decoder_t; 33 | 34 | static const char * jd_errors[] = { 35 | "Succeeded", 36 | "Interrupted by output function", 37 | "Device error or wrong termination of input stream", 38 | "Insufficient memory pool for the image", 39 | "Insufficient stream input buffer", 40 | "Parameter error", 41 | "Data format error", 42 | "Right format but not supported", 43 | "Not supported JPEG standard" 44 | }; 45 | 46 | static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect) 47 | { 48 | uint16_t x = rect->left; 49 | uint16_t y = rect->top; 50 | uint16_t w = rect->right + 1 - x; 51 | uint16_t h = rect->bottom + 1 - y; 52 | uint8_t *data = (uint8_t *)bitmap; 53 | 54 | esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device; 55 | 56 | if (jpeg->writer) { 57 | return jpeg->writer(jpeg->arg, x, y, w, h, data); 58 | } 59 | return 0; 60 | } 61 | 62 | static uint32_t _jpg_read(JDEC *decoder, uint8_t *buf, uint32_t len) 63 | { 64 | esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device; 65 | if (jpeg->len && len > (jpeg->len - jpeg->index)) { 66 | len = jpeg->len - jpeg->index; 67 | } 68 | if (len) { 69 | len = jpeg->reader(jpeg->arg, jpeg->index, buf, len); 70 | if (!len) { 71 | ESP_LOGE(TAG, "Read Fail at %u/%u", jpeg->index, jpeg->len); 72 | } 73 | jpeg->index += len; 74 | } 75 | return len; 76 | } 77 | 78 | esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg) 79 | { 80 | static uint8_t work[3100]; 81 | JDEC decoder; 82 | esp_jpg_decoder_t jpeg; 83 | 84 | jpeg.len = len; 85 | jpeg.reader = reader; 86 | jpeg.writer = writer; 87 | jpeg.arg = arg; 88 | jpeg.scale = scale; 89 | jpeg.index = 0; 90 | 91 | JRESULT jres = jd_prepare(&decoder, _jpg_read, work, 3100, &jpeg); 92 | if(jres != JDR_OK){ 93 | ESP_LOGE(TAG, "JPG Header Parse Failed! %s", jd_errors[jres]); 94 | return ESP_FAIL; 95 | } 96 | 97 | uint16_t output_width = decoder.width / (1 << (uint8_t)(jpeg.scale)); 98 | uint16_t output_height = decoder.height / (1 << (uint8_t)(jpeg.scale)); 99 | 100 | //output start 101 | writer(arg, 0, 0, output_width, output_height, NULL); 102 | //output write 103 | jres = jd_decomp(&decoder, _jpg_write, (uint8_t)jpeg.scale); 104 | //output end 105 | writer(arg, output_width, output_height, output_width, output_height, NULL); 106 | 107 | if (jres != JDR_OK) { 108 | ESP_LOGE(TAG, "JPG Decompression Failed! %s", jd_errors[jres]); 109 | return ESP_FAIL; 110 | } 111 | //check if all data has been consumed. 112 | if (len && jpeg.index < len) { 113 | _jpg_read(&decoder, NULL, len - jpeg.index); 114 | } 115 | 116 | return ESP_OK; 117 | } 118 | 119 | -------------------------------------------------------------------------------- /components/ov2640/camera/include/sensor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * Sensor abstraction layer. 7 | * 8 | */ 9 | #ifndef __SENSOR_H__ 10 | #define __SENSOR_H__ 11 | #include 12 | 13 | #define OV2640_PID (0x26) 14 | 15 | typedef enum 16 | { 17 | PIXFORMAT_RGB565, // 2BPP/RGB565 18 | PIXFORMAT_YUV422, // 2BPP/YUV422 19 | PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE 20 | PIXFORMAT_JPEG, // JPEG/COMPRESSED 21 | PIXFORMAT_RGB888, // 3BPP/RGB888 22 | } pixformat_t; 23 | 24 | typedef enum 25 | { 26 | FRAMESIZE_QQVGA, // 160x120 27 | FRAMESIZE_QQVGA2, // 128x160 28 | FRAMESIZE_QCIF, // 176x144 29 | FRAMESIZE_HQVGA, // 240x176 30 | FRAMESIZE_QVGA, // 320x240 31 | FRAMESIZE_CIF, // 400x296 32 | FRAMESIZE_VGA, // 640x480 33 | FRAMESIZE_SVGA, // 800x600 34 | FRAMESIZE_XGA, // 1024x768 35 | FRAMESIZE_SXGA, // 1280x1024 36 | FRAMESIZE_UXGA, // 1600x1200 37 | } framesize_t; 38 | 39 | typedef enum 40 | { 41 | GAINCEILING_2X, 42 | GAINCEILING_4X, 43 | GAINCEILING_8X, 44 | GAINCEILING_16X, 45 | GAINCEILING_32X, 46 | GAINCEILING_64X, 47 | GAINCEILING_128X, 48 | } gainceiling_t; 49 | 50 | typedef struct 51 | { 52 | uint8_t MIDH; 53 | uint8_t MIDL; 54 | uint8_t PID; 55 | uint8_t VER; 56 | } sensor_id_t; 57 | 58 | typedef struct 59 | { 60 | framesize_t framesize; //0 - 10 61 | uint8_t quality; //0 - 63 62 | int8_t brightness; //-2 - 2 63 | int8_t contrast; //-2 - 2 64 | int8_t saturation; //-2 - 2 65 | uint8_t special_effect; //0 - 6 66 | uint8_t wb_mode; //0 - 4 67 | uint8_t awb; 68 | uint8_t awb_gain; 69 | uint8_t aec; 70 | uint8_t aec2; 71 | int8_t ae_level; //-2 - 2 72 | uint16_t aec_value; //0 - 1200 73 | uint8_t agc; 74 | uint8_t agc_gain; //0 - 30 75 | uint8_t gainceiling; //0 - 6 76 | uint8_t bpc; 77 | uint8_t wpc; 78 | uint8_t raw_gma; 79 | uint8_t lenc; 80 | uint8_t hmirror; 81 | uint8_t vflip; 82 | uint8_t dcw; 83 | uint8_t colorbar; 84 | } camera_status_t; 85 | 86 | typedef struct _sensor sensor_t; 87 | typedef struct _sensor 88 | { 89 | sensor_id_t id; // Sensor ID. 90 | uint8_t slv_addr; // Sensor I2C slave address. 91 | pixformat_t pixformat; 92 | camera_status_t status; 93 | 94 | // Sensor function pointers 95 | int (*init_status)(sensor_t *sensor); 96 | int (*reset)(sensor_t *sensor); 97 | int (*set_pixformat)(sensor_t *sensor, pixformat_t pixformat); 98 | int (*set_framesize)(sensor_t *sensor, framesize_t framesize); 99 | int (*set_contrast)(sensor_t *sensor, int level); 100 | int (*set_brightness)(sensor_t *sensor, int level); 101 | int (*set_saturation)(sensor_t *sensor, int level); 102 | int (*set_gainceiling)(sensor_t *sensor, gainceiling_t gainceiling); 103 | int (*set_quality)(sensor_t *sensor, int quality); 104 | int (*set_colorbar)(sensor_t *sensor, int enable); 105 | int (*set_whitebal)(sensor_t *sensor, int enable); 106 | int (*set_gain_ctrl)(sensor_t *sensor, int enable); 107 | int (*set_exposure_ctrl)(sensor_t *sensor, int enable); 108 | int (*set_hmirror)(sensor_t *sensor, int enable); 109 | int (*set_vflip)(sensor_t *sensor, int enable); 110 | 111 | int (*set_aec2)(sensor_t *sensor, int enable); 112 | int (*set_awb_gain)(sensor_t *sensor, int enable); 113 | int (*set_agc_gain)(sensor_t *sensor, int gain); 114 | int (*set_aec_value)(sensor_t *sensor, int gain); 115 | 116 | int (*set_special_effect)(sensor_t *sensor, int effect); 117 | int (*set_wb_mode)(sensor_t *sensor, int mode); 118 | int (*set_ae_level)(sensor_t *sensor, int level); 119 | 120 | int (*set_dcw)(sensor_t *sensor, int enable); 121 | int (*set_bpc)(sensor_t *sensor, int enable); 122 | int (*set_wpc)(sensor_t *sensor, int enable); 123 | 124 | int (*set_raw_gma)(sensor_t *sensor, int enable); 125 | int (*set_lenc)(sensor_t *sensor, int enable); 126 | } sensor_t; 127 | 128 | // Resolution table (in camera.c) 129 | extern const int resolution[][2]; 130 | 131 | #endif /* __SENSOR_H__ */ 132 | -------------------------------------------------------------------------------- /components/ov2640/conversions/include/img_converters.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef _IMG_CONVERTERS_H_ 15 | #define _IMG_CONVERTERS_H_ 16 | 17 | #ifdef __cplusplus 18 | extern "C" { 19 | #endif 20 | 21 | #include 22 | #include 23 | #include 24 | #include "esp_camera.h" 25 | 26 | typedef size_t (* jpg_out_cb)(void * arg, size_t index, const void* data, size_t len); 27 | 28 | /** 29 | * @brief Convert image buffer to JPEG 30 | * 31 | * @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format 32 | * @param src_len Length in bytes of the source buffer 33 | * @param width Width in pixels of the source image 34 | * @param height Height in pixels of the source image 35 | * @param format Format of the source image 36 | * @param quality JPEG quality of the resulting image 37 | * @param cp Callback to be called to write the bytes of the output JPEG 38 | * @param arg Pointer to be passed to the callback 39 | * 40 | * @return true on success 41 | */ 42 | bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg); 43 | 44 | /** 45 | * @brief Convert camera frame buffer to JPEG 46 | * 47 | * @param fb Source camera frame buffer 48 | * @param quality JPEG quality of the resulting image 49 | * @param cp Callback to be called to write the bytes of the output JPEG 50 | * @param arg Pointer to be passed to the callback 51 | * 52 | * @return true on success 53 | */ 54 | bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg); 55 | 56 | /** 57 | * @brief Convert image buffer to JPEG buffer 58 | * 59 | * @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format 60 | * @param src_len Length in bytes of the source buffer 61 | * @param width Width in pixels of the source image 62 | * @param height Height in pixels of the source image 63 | * @param format Format of the source image 64 | * @param quality JPEG quality of the resulting image 65 | * @param out Pointer to be populated with the address of the resulting buffer 66 | * @param out_len Pointer to be populated with the length of the output buffer 67 | * 68 | * @return true on success 69 | */ 70 | bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len); 71 | 72 | /** 73 | * @brief Convert camera frame buffer to JPEG buffer 74 | * 75 | * @param fb Source camera frame buffer 76 | * @param quality JPEG quality of the resulting image 77 | * @param out Pointer to be populated with the address of the resulting buffer 78 | * @param out_len Pointer to be populated with the length of the output buffer 79 | * 80 | * @return true on success 81 | */ 82 | bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len); 83 | 84 | /** 85 | * @brief Convert image buffer to BMP buffer 86 | * 87 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format 88 | * @param src_len Length in bytes of the source buffer 89 | * @param width Width in pixels of the source image 90 | * @param height Height in pixels of the source image 91 | * @param format Format of the source image 92 | * @param out Pointer to be populated with the address of the resulting buffer 93 | * @param out_len Pointer to be populated with the length of the output buffer 94 | * 95 | * @return true on success 96 | */ 97 | bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len); 98 | 99 | /** 100 | * @brief Convert camera frame buffer to BMP buffer 101 | * 102 | * @param fb Source camera frame buffer 103 | * @param out Pointer to be populated with the address of the resulting buffer 104 | * @param out_len Pointer to be populated with the length of the output buffer 105 | * 106 | * @return true on success 107 | */ 108 | bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len); 109 | 110 | /** 111 | * @brief Convert image buffer to RGB888 buffer (used for face detection) 112 | * 113 | * @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format 114 | * @param src_len Length in bytes of the source buffer 115 | * @param format Format of the source image 116 | * @param rgb_buf Pointer to the output buffer (width * height * 3) 117 | * 118 | * @return true on success 119 | */ 120 | bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf); 121 | 122 | #ifdef __cplusplus 123 | } 124 | #endif 125 | 126 | #endif /* _IMG_CONVERTERS_H_ */ 127 | -------------------------------------------------------------------------------- /components/ov2640/conversions/private_include/jpge.h: -------------------------------------------------------------------------------- 1 | // jpge.h - C++ class for JPEG compression. 2 | // Public domain, Rich Geldreich 3 | // Alex Evans: Added RGBA support, linear memory allocator. 4 | #ifndef JPEG_ENCODER_H 5 | #define JPEG_ENCODER_H 6 | 7 | namespace jpge 8 | { 9 | typedef unsigned char uint8; 10 | typedef signed short int16; 11 | typedef signed int int32; 12 | typedef unsigned short uint16; 13 | typedef unsigned int uint32; 14 | typedef unsigned int uint; 15 | 16 | // JPEG chroma subsampling factors. Y_ONLY (grayscale images) and H2V2 (color images) are the most common. 17 | enum subsampling_t { Y_ONLY = 0, H1V1 = 1, H2V1 = 2, H2V2 = 3 }; 18 | 19 | // JPEG compression parameters structure. 20 | struct params { 21 | inline params() : m_quality(85), m_subsampling(H2V2) { } 22 | 23 | inline bool check() const { 24 | if ((m_quality < 1) || (m_quality > 100)) { 25 | return false; 26 | } 27 | if ((uint)m_subsampling > (uint)H2V2) { 28 | return false; 29 | } 30 | return true; 31 | } 32 | 33 | // Quality: 1-100, higher is better. Typical values are around 50-95. 34 | int m_quality; 35 | 36 | // m_subsampling: 37 | // 0 = Y (grayscale) only 38 | // 1 = H1V1 subsampling (YCbCr 1x1x1, 3 blocks per MCU) 39 | // 2 = H2V1 subsampling (YCbCr 2x1x1, 4 blocks per MCU) 40 | // 3 = H2V2 subsampling (YCbCr 4x1x1, 6 blocks per MCU-- very common) 41 | subsampling_t m_subsampling; 42 | }; 43 | 44 | // Output stream abstract class - used by the jpeg_encoder class to write to the output stream. 45 | // put_buf() is generally called with len==JPGE_OUT_BUF_SIZE bytes, but for headers it'll be called with smaller amounts. 46 | class output_stream { 47 | public: 48 | virtual ~output_stream() { }; 49 | virtual bool put_buf(const void* Pbuf, int len) = 0; 50 | virtual uint get_size() const = 0; 51 | }; 52 | 53 | // Lower level jpeg_encoder class - useful if more control is needed than the above helper functions. 54 | class jpeg_encoder { 55 | public: 56 | jpeg_encoder(); 57 | ~jpeg_encoder(); 58 | 59 | // Initializes the compressor. 60 | // pStream: The stream object to use for writing compressed data. 61 | // params - Compression parameters structure, defined above. 62 | // width, height - Image dimensions. 63 | // channels - May be 1, or 3. 1 indicates grayscale, 3 indicates RGB source data. 64 | // Returns false on out of memory or if a stream write fails. 65 | bool init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params = params()); 66 | 67 | // Call this method with each source scanline. 68 | // width * src_channels bytes per scanline is expected (RGB or Y format). 69 | // You must call with NULL after all scanlines are processed to finish compression. 70 | // Returns false on out of memory or if a stream write fails. 71 | bool process_scanline(const void* pScanline); 72 | 73 | // Deinitializes the compressor, freeing any allocated memory. May be called at any time. 74 | void deinit(); 75 | 76 | private: 77 | jpeg_encoder(const jpeg_encoder &); 78 | jpeg_encoder &operator =(const jpeg_encoder &); 79 | 80 | typedef int32 sample_array_t; 81 | enum { JPGE_OUT_BUF_SIZE = 512 }; 82 | 83 | output_stream *m_pStream; 84 | params m_params; 85 | uint8 m_num_components; 86 | uint8 m_comp_h_samp[3], m_comp_v_samp[3]; 87 | int m_image_x, m_image_y, m_image_bpp, m_image_bpl; 88 | int m_image_x_mcu, m_image_y_mcu; 89 | int m_image_bpl_xlt, m_image_bpl_mcu; 90 | int m_mcus_per_row; 91 | int m_mcu_x, m_mcu_y; 92 | uint8 *m_mcu_lines[16]; 93 | uint8 m_mcu_y_ofs; 94 | sample_array_t m_sample_array[64]; 95 | int16 m_coefficient_array[64]; 96 | 97 | int m_last_dc_val[3]; 98 | uint8 m_out_buf[JPGE_OUT_BUF_SIZE]; 99 | uint8 *m_pOut_buf; 100 | uint m_out_buf_left; 101 | uint32 m_bit_buffer; 102 | uint m_bits_in; 103 | uint8 m_pass_num; 104 | bool m_all_stream_writes_succeeded; 105 | 106 | bool jpg_open(int p_x_res, int p_y_res, int src_channels); 107 | 108 | void flush_output_buffer(); 109 | void put_bits(uint bits, uint len); 110 | 111 | void emit_byte(uint8 i); 112 | void emit_word(uint i); 113 | void emit_marker(int marker); 114 | 115 | void emit_jfif_app0(); 116 | void emit_dqt(); 117 | void emit_sof(); 118 | void emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag); 119 | void emit_dhts(); 120 | void emit_sos(); 121 | 122 | void compute_quant_table(int32 *dst, const int16 *src); 123 | void load_quantized_coefficients(int component_num); 124 | 125 | void load_block_8_8_grey(int x); 126 | void load_block_8_8(int x, int y, int c); 127 | void load_block_16_8(int x, int c); 128 | void load_block_16_8_8(int x, int c); 129 | 130 | void code_coefficients_pass_two(int component_num); 131 | void code_block(int component_num); 132 | 133 | void process_mcu_row(); 134 | bool process_end_of_image(); 135 | void load_mcu(const void* src); 136 | void clear(); 137 | void init(); 138 | }; 139 | 140 | } // namespace jpge 141 | 142 | #endif // JPEG_ENCODER 143 | -------------------------------------------------------------------------------- /main/display.c: -------------------------------------------------------------------------------- 1 | //Driver for the LED board in an IKEA Frekvens LED display block thing. This driver does 2 | //8-bit BAM in order to get grayscales. 3 | 4 | /* 5 | * ---------------------------------------------------------------------------- 6 | * "THE BEER-WARE LICENSE" (Revision 42): 7 | * Jeroen Domburg wrote this file. As long as you retain 8 | * this notice you can do whatever you want with this stuff. If we meet some day, 9 | * and you think this stuff is worth it, you can buy me a beer in return. 10 | * ---------------------------------------------------------------------------- 11 | */ 12 | 13 | #include 14 | #include 15 | #include 16 | #include "freertos/FreeRTOS.h" 17 | #include "freertos/task.h" 18 | #include "freertos/queue.h" 19 | #include "freertos/semphr.h" 20 | #include "esp_system.h" 21 | #include "driver/periph_ctrl.h" 22 | #include "driver/timer.h" 23 | #include "driver/spi_master.h" 24 | #include "driver/gpio.h" 25 | #include "esp_types.h" 26 | #include "val2pwm.h" 27 | 28 | //Frekvens uses 16 SCT2024 LED drivers 29 | //http://www.starchips.com.tw/pdf/datasheet/SCT2024V01_03.pdf 30 | 31 | //I/O pins that go to the Frekvens. 32 | #define GPIO_LAK 14 33 | #define GPIO_CLK 15 34 | #define GPIO_DA 13 35 | #define GPIO_EN 12 //Note that this pin is always low; you could just wire it to gnd directly if you want. 36 | 37 | #define BITPLANE_CT 8 38 | 39 | #define BAM_DIV 50 //1MHz/(BAM_DIV*(1<> 32); 63 | TIMERG0.hw_timer[0].alarm_low = (uint32_t) alrm; 64 | 65 | /* After the alarm has been triggered 66 | we need enable it again, so it is triggered the next time */ 67 | TIMERG0.hw_timer[0].config.alarm_en = TIMER_ALARM_EN; 68 | 69 | //update bam_bit for what is going to be sent next 70 | bam_bit=bam_bit+1; 71 | if (bam_bit==BITPLANE_CT) { 72 | bam_bit=0; 73 | } 74 | 75 | //Poke the display task so it can send over the pixel data for the next bit. 76 | xSemaphoreGiveFromISR(bam_sema, NULL); 77 | 78 | //All done. 79 | portYIELD_FROM_ISR(); 80 | } 81 | 82 | 83 | 84 | static void display_task(void *arg) { 85 | spi_device_handle_t spi; 86 | esp_err_t ret; 87 | 88 | //latch is used as a gpio in the timer int 89 | gpio_pad_select_gpio(GPIO_LAK); 90 | gpio_set_direction(GPIO_LAK, GPIO_MODE_OUTPUT); 91 | //always enable outputs 92 | gpio_pad_select_gpio(GPIO_EN); 93 | gpio_set_direction(GPIO_EN, GPIO_MODE_OUTPUT); 94 | gpio_set_level(GPIO_EN, 0); //low active 95 | 96 | bam_bit=0; 97 | 98 | spi_bus_config_t buscfg={ 99 | .miso_io_num=-1, 100 | .mosi_io_num=GPIO_DA, 101 | .sclk_io_num=GPIO_CLK, 102 | .quadwp_io_num=-1, 103 | .quadhd_io_num=-1, 104 | .max_transfer_sz=16*16 105 | }; 106 | spi_device_interface_config_t devcfg={ 107 | .clock_speed_hz=10*1000*1000, //Clock out at 10 MHz 108 | .mode=0, //SPI mode 0 109 | .spics_io_num=-1, //we'll handle latch in the timer 110 | .queue_size=2, 111 | }; 112 | //Initialize the SPI bus 113 | ret=spi_bus_initialize(HSPI_HOST, &buscfg, 2); 114 | ESP_ERROR_CHECK(ret); 115 | //Attach the device to the SPI bus 116 | ret=spi_bus_add_device(HSPI_HOST, &devcfg, &spi); 117 | ESP_ERROR_CHECK(ret); 118 | 119 | bam_sema=xSemaphoreCreateBinary(); 120 | 121 | /* Select and initialize basic parameters of the timer */ 122 | timer_config_t config={ 123 | .divider = 80, //1MHz 124 | .counter_dir = TIMER_COUNT_UP, 125 | .counter_en = TIMER_PAUSE, 126 | .alarm_en = TIMER_ALARM_EN, 127 | .intr_type = TIMER_INTR_LEVEL, 128 | .auto_reload = 1, //auto-reset on int 129 | // .clk_src = TIMER_SRC_CLK_APB, 130 | }; 131 | timer_init(TIMER_GROUP_0, TIMER_0, &config); 132 | //counter start 133 | timer_set_counter_value(TIMER_GROUP_0, TIMER_0, 0x00000000ULL); 134 | 135 | /* Configure the alarm value and the interrupt on alarm. */ 136 | timer_set_alarm_value(TIMER_GROUP_0, TIMER_0, 1000); 137 | timer_isr_register(TIMER_GROUP_0, TIMER_0, bam_timer_isr, NULL, ESP_INTR_FLAG_IRAM, NULL); 138 | timer_start(TIMER_GROUP_0, TIMER_0); 139 | timer_enable_intr(TIMER_GROUP_0, TIMER_0); 140 | 141 | spi_transaction_t trans={ 142 | .length=16*16 //we send 256 bits per update 143 | }; 144 | 145 | while(1) { 146 | //Send the next bitplane 147 | trans.tx_buffer=&bam_bitplane_cur[bam_bit*16]; 148 | ret=spi_device_polling_transmit(spi, &trans); //Transmit! 149 | assert(ret==ESP_OK); //Should have had no issues. 150 | if (bam_bit==0) { 151 | //buffer flip, if needed 152 | bam_bitplane_cur=bam_bitplane_next; 153 | } 154 | //wait for timer to latch this data 155 | xSemaphoreTake(bam_sema, portMAX_DELAY); 156 | } 157 | } 158 | 159 | void display_setpixel(int x, int y, int v) { 160 | //Refrobnicating coordinates because pixels are located weirdly in hardware 161 | int bx=(x&7); 162 | int by=y/2; 163 | if (y&1) bx+=8; 164 | if ((x&8)==0) by+=8; 165 | //do luminance correction 166 | v=valToPwm(v)>>(16-BITPLANE_CT); 167 | 168 | int bitmask=1; 169 | int pixmask=(1<width, fb->height, fb->pixformat, fb->buf, fb->len); 58 | 59 | //return the frame buffer back to be reused 60 | esp_camera_fb_return(fb); 61 | 62 | return ESP_OK; 63 | } 64 | */ 65 | 66 | #pragma once 67 | 68 | #include "esp_err.h" 69 | #include "driver/ledc.h" 70 | #include "sensor.h" 71 | 72 | #ifdef __cplusplus 73 | extern "C" { 74 | #endif 75 | 76 | /** 77 | * @brief Configuration structure for camera initialization 78 | */ 79 | typedef struct { 80 | int pin_pwdn; /*!< GPIO pin for camera power down line */ 81 | int pin_reset; /*!< GPIO pin for camera reset line */ 82 | int pin_xclk; /*!< GPIO pin for camera XCLK line */ 83 | int pin_sscb_sda; /*!< GPIO pin for camera SDA line */ 84 | int pin_sscb_scl; /*!< GPIO pin for camera SCL line */ 85 | int pin_d7; /*!< GPIO pin for camera D7 line */ 86 | int pin_d6; /*!< GPIO pin for camera D6 line */ 87 | int pin_d5; /*!< GPIO pin for camera D5 line */ 88 | int pin_d4; /*!< GPIO pin for camera D4 line */ 89 | int pin_d3; /*!< GPIO pin for camera D3 line */ 90 | int pin_d2; /*!< GPIO pin for camera D2 line */ 91 | int pin_d1; /*!< GPIO pin for camera D1 line */ 92 | int pin_d0; /*!< GPIO pin for camera D0 line */ 93 | int pin_vsync; /*!< GPIO pin for camera VSYNC line */ 94 | int pin_href; /*!< GPIO pin for camera HREF line */ 95 | int pin_pclk; /*!< GPIO pin for camera PCLK line */ 96 | 97 | int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz. Either 10KHz or 20KHz */ 98 | 99 | ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */ 100 | ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */ 101 | 102 | pixformat_t pixel_format; /*!< Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG */ 103 | framesize_t frame_size; /*!< Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA */ 104 | 105 | int jpeg_quality; /*!< Quality of JPEG output. 0-63 lower means higher quality */ 106 | size_t fb_count; /*!< Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed) */ 107 | } camera_config_t; 108 | 109 | /** 110 | * @brief Data structure of camera frame buffer 111 | */ 112 | typedef struct { 113 | uint8_t * buf; /*!< Pointer to the pixel data */ 114 | size_t len; /*!< Length of the buffer in bytes */ 115 | size_t width; /*!< Width of the buffer in pixels */ 116 | size_t height; /*!< Height of the buffer in pixels */ 117 | pixformat_t format; /*!< Format of the pixel data */ 118 | } camera_fb_t; 119 | 120 | #define ESP_ERR_CAMERA_BASE 0x20000 121 | #define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1) 122 | #define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2) 123 | #define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 3) 124 | 125 | /** 126 | * @brief Initialize the camera driver 127 | * 128 | * @note call camera_probe before calling this function 129 | * 130 | * This function detects and configures camera over I2C interface, 131 | * allocates framebuffer and DMA buffers, 132 | * initializes parallel I2S input, and sets up DMA descriptors. 133 | * 134 | * Currently this function can only be called once and there is 135 | * no way to de-initialize this module. 136 | * 137 | * @param config Camera configuration parameters 138 | * 139 | * @return ESP_OK on success 140 | */ 141 | esp_err_t esp_camera_init(const camera_config_t* config); 142 | 143 | /** 144 | * @brief Deinitialize the camera driver 145 | * 146 | * @return 147 | * - ESP_OK on success 148 | * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet 149 | */ 150 | esp_err_t esp_camera_deinit(); 151 | 152 | /** 153 | * @brief Obtain pointer to a frame buffer. 154 | * 155 | * @return pointer to the frame buffer 156 | */ 157 | camera_fb_t* esp_camera_fb_get(); 158 | 159 | /** 160 | * @brief Return the frame buffer to be reused again. 161 | * 162 | * @param fb Pointer to the frame buffer 163 | */ 164 | void esp_camera_fb_return(camera_fb_t * fb); 165 | 166 | /** 167 | * @brief Get a pointer to the image sensor control structure 168 | * 169 | * @return pointer to the sensor 170 | */ 171 | sensor_t * esp_camera_sensor_get(); 172 | 173 | 174 | #ifdef __cplusplus 175 | } 176 | #endif 177 | 178 | #include "img_converters.h" 179 | 180 | -------------------------------------------------------------------------------- /components/ov2640/conversions/to_jpg.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include 15 | #include 16 | #include "esp_spiram.h" 17 | #include "esp_attr.h" 18 | #include "soc/efuse_reg.h" 19 | #include "esp_heap_caps.h" 20 | #include "esp_camera.h" 21 | #include "img_converters.h" 22 | #include "jpge.h" 23 | #include "yuv.h" 24 | 25 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 26 | #include "esp32-hal-log.h" 27 | #define TAG "" 28 | #else 29 | #include "esp_log.h" 30 | static const char* TAG = "to_bmp"; 31 | #endif 32 | 33 | static void *_malloc(size_t size) 34 | { 35 | void * res = malloc(size); 36 | if(res) { 37 | return res; 38 | } 39 | return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); 40 | } 41 | 42 | static IRAM_ATTR void convert_line_format(uint8_t * src, pixformat_t format, uint8_t * dst, size_t width, size_t in_channels, size_t line) 43 | { 44 | int i=0, o=0, l=0; 45 | if(format == PIXFORMAT_GRAYSCALE) { 46 | memcpy(dst, src + line * width, width); 47 | } else if(format == PIXFORMAT_RGB888) { 48 | l = width * 3; 49 | src += l * line; 50 | for(i=0; i> 3; 61 | dst[o++] = (src[i+1] & 0x1F) << 3; 62 | } 63 | } else if(format == PIXFORMAT_YUV422) { 64 | uint8_t y0, y1, u, v; 65 | uint8_t r, g, b; 66 | l = width * 2; 67 | src += l * line; 68 | for(i=0; i 100) { 100 | quality = 100; 101 | } 102 | 103 | jpge::params comp_params = jpge::params(); 104 | comp_params.m_subsampling = subsampling; 105 | comp_params.m_quality = quality; 106 | 107 | jpge::jpeg_encoder dst_image; 108 | 109 | if (!dst_image.init(dst_stream, width, height, num_channels, comp_params)) { 110 | ESP_LOGE(TAG, "JPG encoder init failed"); 111 | return false; 112 | } 113 | 114 | uint8_t* line = (uint8_t*)_malloc(width * num_channels); 115 | if(!line) { 116 | ESP_LOGE(TAG, "Scan line malloc failed"); 117 | return false; 118 | } 119 | 120 | for (int i = 0; i < height; i++) { 121 | convert_line_format(src, format, line, width, num_channels, i); 122 | if (!dst_image.process_scanline(line)) { 123 | ESP_LOGE(TAG, "JPG process line %u failed", i); 124 | free(line); 125 | return false; 126 | } 127 | } 128 | free(line); 129 | 130 | if (!dst_image.process_scanline(NULL)) { 131 | ESP_LOGE(TAG, "JPG image finish failed"); 132 | return false; 133 | } 134 | dst_image.deinit(); 135 | return true; 136 | } 137 | 138 | class callback_stream : public jpge::output_stream { 139 | protected: 140 | jpg_out_cb ocb; 141 | void * oarg; 142 | size_t index; 143 | 144 | public: 145 | callback_stream(jpg_out_cb cb, void * arg) : ocb(cb), oarg(arg), index(0) { } 146 | virtual ~callback_stream() { } 147 | virtual bool put_buf(const void* data, int len) 148 | { 149 | index += ocb(oarg, index, data, len); 150 | return true; 151 | } 152 | virtual size_t get_size() const 153 | { 154 | return index; 155 | } 156 | }; 157 | 158 | bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg) 159 | { 160 | callback_stream dst_stream(cb, arg); 161 | return convert_image(src, width, height, format, quality, &dst_stream); 162 | } 163 | 164 | bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg) 165 | { 166 | return fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, cb, arg); 167 | } 168 | 169 | 170 | 171 | class memory_stream : public jpge::output_stream { 172 | protected: 173 | uint8_t *out_buf; 174 | size_t max_len, index; 175 | 176 | public: 177 | memory_stream(void *pBuf, uint buf_size) : out_buf(static_cast(pBuf)), max_len(buf_size), index(0) { } 178 | 179 | virtual ~memory_stream() { } 180 | 181 | virtual bool put_buf(const void* pBuf, int len) 182 | { 183 | if (!pBuf) { 184 | //end of image 185 | return true; 186 | } 187 | if ((size_t)len > (max_len - index)) { 188 | ESP_LOGW(TAG, "JPG output overflow: %d bytes", len - (max_len - index)); 189 | len = max_len - index; 190 | } 191 | if (len) { 192 | memcpy(out_buf + index, pBuf, len); 193 | index += len; 194 | } 195 | return true; 196 | } 197 | 198 | virtual size_t get_size() const 199 | { 200 | return index; 201 | } 202 | }; 203 | 204 | bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len) 205 | { 206 | //todo: allocate proper buffer for holding JPEG data 207 | //this should be enough for CIF frame size 208 | int jpg_buf_len = 24*1024; 209 | 210 | 211 | uint8_t * jpg_buf = (uint8_t *)_malloc(jpg_buf_len); 212 | if(jpg_buf == NULL) { 213 | ESP_LOGE(TAG, "JPG buffer malloc failed"); 214 | return false; 215 | } 216 | memory_stream dst_stream(jpg_buf, jpg_buf_len); 217 | 218 | if(!convert_image(src, width, height, format, quality, &dst_stream)) { 219 | free(jpg_buf); 220 | return false; 221 | } 222 | 223 | *out = jpg_buf; 224 | *out_len = dst_stream.get_size(); 225 | return true; 226 | } 227 | 228 | bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len) 229 | { 230 | return fmt2jpg(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, out, out_len); 231 | } 232 | -------------------------------------------------------------------------------- /components/ov2640/sensors/private_include/ov2640_regs.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * OV2640 register definitions. 7 | */ 8 | #ifndef __REG_REGS_H__ 9 | #define __REG_REGS_H__ 10 | /* DSP register bank FF=0x00*/ 11 | #define R_BYPASS 0x05 12 | #define QS 0x44 13 | #define CTRLI 0x50 14 | #define HSIZE 0x51 15 | #define VSIZE 0x52 16 | #define XOFFL 0x53 17 | #define YOFFL 0x54 18 | #define VHYX 0x55 19 | #define DPRP 0x56 20 | #define TEST 0x57 21 | #define ZMOW 0x5A 22 | #define ZMOH 0x5B 23 | #define ZMHH 0x5C 24 | #define BPADDR 0x7C 25 | #define BPDATA 0x7D 26 | #define CTRL2 0x86 27 | #define CTRL3 0x87 28 | #define SIZEL 0x8C 29 | #define HSIZE8 0xC0 30 | #define VSIZE8 0xC1 31 | #define CTRL0 0xC2 32 | #define CTRL1 0xC3 33 | #define R_DVP_SP 0xD3 34 | #define IMAGE_MODE 0xDA 35 | #define RESET 0xE0 36 | #define MS_SP 0xF0 37 | #define SS_ID 0xF7 38 | #define SS_CTRL 0xF7 39 | #define MC_BIST 0xF9 40 | #define MC_AL 0xFA 41 | #define MC_AH 0xFB 42 | #define MC_D 0xFC 43 | #define P_CMD 0xFD 44 | #define P_STATUS 0xFE 45 | #define BANK_SEL 0xFF 46 | 47 | #define CTRLI_LP_DP 0x80 48 | #define CTRLI_ROUND 0x40 49 | 50 | #define CTRL0_AEC_EN 0x80 51 | #define CTRL0_AEC_SEL 0x40 52 | #define CTRL0_STAT_SEL 0x20 53 | #define CTRL0_VFIRST 0x10 54 | #define CTRL0_YUV422 0x08 55 | #define CTRL0_YUV_EN 0x04 56 | #define CTRL0_RGB_EN 0x02 57 | #define CTRL0_RAW_EN 0x01 58 | 59 | #define CTRL2_DCW_EN 0x20 60 | #define CTRL2_SDE_EN 0x10 61 | #define CTRL2_UV_ADJ_EN 0x08 62 | #define CTRL2_UV_AVG_EN 0x04 63 | #define CTRL2_CMX_EN 0x01 64 | 65 | #define CTRL3_BPC_EN 0x80 66 | #define CTRL3_WPC_EN 0x40 67 | 68 | #define R_DVP_SP_AUTO_MODE 0x80 69 | 70 | #define R_BYPASS_DSP_EN 0x00 71 | #define R_BYPASS_DSP_BYPAS 0x01 72 | 73 | #define IMAGE_MODE_Y8_DVP_EN 0x40 74 | #define IMAGE_MODE_JPEG_EN 0x10 75 | #define IMAGE_MODE_YUV422 0x00 76 | #define IMAGE_MODE_RAW10 0x04 77 | #define IMAGE_MODE_RGB565 0x08 78 | #define IMAGE_MODE_HREF_VSYNC 0x02 79 | #define IMAGE_MODE_LBYTE_FIRST 0x01 80 | 81 | #define RESET_MICROC 0x40 82 | #define RESET_SCCB 0x20 83 | #define RESET_JPEG 0x10 84 | #define RESET_DVP 0x04 85 | #define RESET_IPU 0x02 86 | #define RESET_CIF 0x01 87 | 88 | #define MC_BIST_RESET 0x80 89 | #define MC_BIST_BOOT_ROM_SEL 0x40 90 | #define MC_BIST_12KB_SEL 0x20 91 | #define MC_BIST_12KB_MASK 0x30 92 | #define MC_BIST_512KB_SEL 0x08 93 | #define MC_BIST_512KB_MASK 0x0C 94 | #define MC_BIST_BUSY_BIT_R 0x02 95 | #define MC_BIST_MC_RES_ONE_SH_W 0x02 96 | #define MC_BIST_LAUNCH 0x01 97 | 98 | 99 | typedef enum { 100 | BANK_DSP, BANK_SENSOR, BANK_MAX 101 | } ov2640_bank_t; 102 | 103 | /* Sensor register bank FF=0x01*/ 104 | #define GAIN 0x00 105 | #define COM1 0x03 106 | #define REG04 0x04 107 | #define REG08 0x08 108 | #define COM2 0x09 109 | #define REG_PID 0x0A 110 | #define REG_VER 0x0B 111 | #define COM3 0x0C 112 | #define COM4 0x0D 113 | #define AEC 0x10 114 | #define CLKRC 0x11 115 | #define COM7 0x12 116 | #define COM8 0x13 117 | #define COM9 0x14 /* AGC gain ceiling */ 118 | #define COM10 0x15 119 | #define HSTART 0x17 120 | #define HSTOP 0x18 121 | #define VSTART 0x19 122 | #define VSTOP 0x1A 123 | #define MIDH 0x1C 124 | #define MIDL 0x1D 125 | #define AEW 0x24 126 | #define AEB 0x25 127 | #define VV 0x26 128 | #define REG2A 0x2A 129 | #define FRARL 0x2B 130 | #define ADDVSL 0x2D 131 | #define ADDVSH 0x2E 132 | #define YAVG 0x2F 133 | #define HSDY 0x30 134 | #define HEDY 0x31 135 | #define REG32 0x32 136 | #define ARCOM2 0x34 137 | #define REG45 0x45 138 | #define FLL 0x46 139 | #define FLH 0x47 140 | #define COM19 0x48 141 | #define ZOOMS 0x49 142 | #define COM22 0x4B 143 | #define COM25 0x4E 144 | #define BD50 0x4F 145 | #define BD60 0x50 146 | #define REG5D 0x5D 147 | #define REG5E 0x5E 148 | #define REG5F 0x5F 149 | #define REG60 0x60 150 | #define HISTO_LOW 0x61 151 | #define HISTO_HIGH 0x62 152 | 153 | #define REG04_DEFAULT 0x28 154 | #define REG04_HFLIP_IMG 0x80 155 | #define REG04_VFLIP_IMG 0x40 156 | #define REG04_VREF_EN 0x10 157 | #define REG04_HREF_EN 0x08 158 | #define REG04_SET(x) (REG04_DEFAULT|x) 159 | 160 | #define COM2_STDBY 0x10 161 | #define COM2_OUT_DRIVE_1x 0x00 162 | #define COM2_OUT_DRIVE_2x 0x01 163 | #define COM2_OUT_DRIVE_3x 0x02 164 | #define COM2_OUT_DRIVE_4x 0x03 165 | 166 | #define COM3_DEFAULT 0x38 167 | #define COM3_BAND_50Hz 0x04 168 | #define COM3_BAND_60Hz 0x00 169 | #define COM3_BAND_AUTO 0x02 170 | #define COM3_BAND_SET(x) (COM3_DEFAULT|x) 171 | 172 | #define COM7_SRST 0x80 173 | #define COM7_RES_UXGA 0x00 /* UXGA */ 174 | #define COM7_RES_SVGA 0x40 /* SVGA */ 175 | #define COM7_RES_CIF 0x20 /* CIF */ 176 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom */ 177 | #define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ 178 | 179 | #define COM8_DEFAULT 0xC0 180 | #define COM8_BNDF_EN 0x20 /* Enable Banding filter */ 181 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ 182 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ 183 | #define COM8_SET(x) (COM8_DEFAULT|x) 184 | 185 | #define COM9_DEFAULT 0x08 186 | #define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ 187 | #define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ 188 | #define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ 189 | #define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ 190 | #define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ 191 | #define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ 192 | #define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ 193 | #define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) 194 | 195 | #define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */ 196 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ 197 | #define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */ 198 | #define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */ 199 | #define COM10_HREF_NEG 0x08 /* HREF negative */ 200 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ 201 | #define COM10_HSYNC_NEG 0x01 /* HSYNC negative */ 202 | 203 | #define CTRL1_AWB 0x08 /* Enable AWB */ 204 | 205 | #define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) 206 | 207 | #define REG32_UXGA 0x36 208 | #define REG32_SVGA 0x09 209 | #define REG32_CIF 0x89 210 | 211 | #define CLKRC_2X 0x80 212 | 213 | #endif //__REG_REGS_H__ 214 | -------------------------------------------------------------------------------- /components/ov2640/conversions/to_bmp.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #include 15 | #include 16 | #include "img_converters.h" 17 | #include "esp_spiram.h" 18 | #include "soc/efuse_reg.h" 19 | #include "esp_heap_caps.h" 20 | #include "yuv.h" 21 | #include "sdkconfig.h" 22 | #include "esp_jpg_decode.h" 23 | 24 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 25 | #include "esp32-hal-log.h" 26 | #define TAG "" 27 | #else 28 | #include "esp_log.h" 29 | static const char* TAG = "to_bmp"; 30 | #endif 31 | 32 | static const int BMP_HEADER_LEN = 54; 33 | 34 | typedef struct { 35 | uint32_t filesize; 36 | uint32_t reserved; 37 | uint32_t fileoffset_to_pixelarray; 38 | uint32_t dibheadersize; 39 | int32_t width; 40 | int32_t height; 41 | uint16_t planes; 42 | uint16_t bitsperpixel; 43 | uint32_t compression; 44 | uint32_t imagesize; 45 | uint32_t ypixelpermeter; 46 | uint32_t xpixelpermeter; 47 | uint32_t numcolorspallette; 48 | uint32_t mostimpcolor; 49 | } bmp_header_t; 50 | 51 | typedef struct { 52 | uint16_t width; 53 | uint16_t height; 54 | uint16_t data_offset; 55 | const uint8_t *input; 56 | uint8_t *output; 57 | } rgb_jpg_decoder; 58 | 59 | static void *_malloc(size_t size) 60 | { 61 | return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT); 62 | } 63 | 64 | //output buffer and image width 65 | static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data) 66 | { 67 | rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg; 68 | if(!data){ 69 | if(x == 0 && y == 0){ 70 | //write start 71 | jpeg->width = w; 72 | jpeg->height = h; 73 | //if output is null, this is BMP 74 | if(!jpeg->output){ 75 | jpeg->output = (uint8_t *)_malloc((w*h*3)+jpeg->data_offset); 76 | if(!jpeg->output){ 77 | return false; 78 | } 79 | } 80 | } else { 81 | //write end 82 | } 83 | return true; 84 | } 85 | 86 | size_t jw = jpeg->width*3; 87 | size_t t = y * jw; 88 | size_t b = t + (h * jw); 89 | size_t l = x * 3; 90 | uint8_t *out = jpeg->output+jpeg->data_offset; 91 | uint8_t *o = out; 92 | size_t iy, ix; 93 | 94 | w = w * 3; 95 | 96 | for(iy=t; iyinput + index, len); 114 | } 115 | return len; 116 | } 117 | 118 | static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale) 119 | { 120 | rgb_jpg_decoder jpeg; 121 | jpeg.width = 0; 122 | jpeg.height = 0; 123 | jpeg.input = src; 124 | jpeg.output = out; 125 | jpeg.data_offset = 0; 126 | 127 | if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){ 128 | return false; 129 | } 130 | return true; 131 | } 132 | 133 | bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len) 134 | { 135 | 136 | rgb_jpg_decoder jpeg; 137 | jpeg.width = 0; 138 | jpeg.height = 0; 139 | jpeg.input = src; 140 | jpeg.output = NULL; 141 | jpeg.data_offset = BMP_HEADER_LEN; 142 | 143 | if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){ 144 | return false; 145 | } 146 | 147 | size_t output_size = jpeg.width*jpeg.height*3; 148 | 149 | jpeg.output[0] = 'B'; 150 | jpeg.output[1] = 'M'; 151 | bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2]; 152 | bitmap->reserved = 0; 153 | bitmap->filesize = output_size+BMP_HEADER_LEN; 154 | bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN; 155 | bitmap->dibheadersize = 40; 156 | bitmap->width = jpeg.width; 157 | bitmap->height = -jpeg.height;//set negative for top to bottom 158 | bitmap->planes = 1; 159 | bitmap->bitsperpixel = 24; 160 | bitmap->compression = 0; 161 | bitmap->imagesize = output_size; 162 | bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI 163 | bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI 164 | bitmap->numcolorspallette = 0; 165 | bitmap->mostimpcolor = 0; 166 | 167 | *out = jpeg.output; 168 | *out_len = output_size+BMP_HEADER_LEN; 169 | 170 | return true; 171 | } 172 | 173 | bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf) 174 | { 175 | int pix_count = 0; 176 | if(format == PIXFORMAT_JPEG) { 177 | return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE); 178 | } else if(format == PIXFORMAT_RGB888) { 179 | memcpy(rgb_buf, src_buf, src_len); 180 | } else if(format == PIXFORMAT_RGB565) { 181 | int i; 182 | uint8_t hb, lb; 183 | pix_count = src_len / 2; 184 | for(i=0; i> 3; 189 | *rgb_buf++ = hb & 0xF8; 190 | } 191 | } else if(format == PIXFORMAT_GRAYSCALE) { 192 | int i; 193 | uint8_t b; 194 | pix_count = src_len; 195 | for(i=0; ireserved = 0; 247 | bitmap->filesize = out_size; 248 | bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN; 249 | bitmap->dibheadersize = 40; 250 | bitmap->width = width; 251 | bitmap->height = -height;//set negative for top to bottom 252 | bitmap->planes = 1; 253 | bitmap->bitsperpixel = 24; 254 | bitmap->compression = 0; 255 | bitmap->imagesize = pix_count * 3; 256 | bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI 257 | bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI 258 | bitmap->numcolorspallette = 0; 259 | bitmap->mostimpcolor = 0; 260 | 261 | uint8_t * rgb_buf = out_buf + BMP_HEADER_LEN; 262 | uint8_t * src_buf = src; 263 | 264 | 265 | //convert data to RGB888 266 | if(format == PIXFORMAT_RGB888) { 267 | memcpy(rgb_buf, src_buf, pix_count*3); 268 | } else if(format == PIXFORMAT_RGB565) { 269 | int i; 270 | uint8_t hb, lb; 271 | for(i=0; i> 3; 276 | *rgb_buf++ = hb & 0xF8; 277 | } 278 | } else if(format == PIXFORMAT_GRAYSCALE) { 279 | int i; 280 | uint8_t b; 281 | for(i=0; ibuf, fb->len, fb->width, fb->height, fb->format, out, out_len); 316 | } 317 | -------------------------------------------------------------------------------- /components/ov2640/sensors/private_include/ov2640_settings.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #ifndef _OV2640_SETTINGS_H_ 15 | #define _OV2640_SETTINGS_H_ 16 | 17 | #include 18 | #include 19 | #include "esp_attr.h" 20 | #include "ov2640_regs.h" 21 | 22 | // 30fps@24MHz 23 | const DRAM_ATTR uint8_t ov2640_settings_cif[][2] = { 24 | {BANK_SEL, BANK_DSP}, 25 | {0x2c, 0xff}, 26 | {0x2e, 0xdf}, 27 | {BANK_SEL, BANK_SENSOR}, 28 | {0x3c, 0x32}, 29 | {CLKRC, 0x01}, 30 | {COM2, COM2_OUT_DRIVE_3x}, 31 | {REG04, REG04_DEFAULT}, 32 | {COM8, COM8_DEFAULT | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN}, 33 | {COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, 34 | {0x2c, 0x0c}, 35 | {0x33, 0x78}, 36 | {0x3a, 0x33}, 37 | {0x3b, 0xfB}, 38 | {0x3e, 0x00}, 39 | {0x43, 0x11}, 40 | {0x16, 0x10}, 41 | {0x39, 0x92}, 42 | {0x35, 0xda}, 43 | {0x22, 0x1a}, 44 | {0x37, 0xc3}, 45 | {0x23, 0x00}, 46 | {ARCOM2, 0xc0}, 47 | {0x06, 0x88}, 48 | {0x07, 0xc0}, 49 | {COM4, 0x87}, 50 | {0x0e, 0x41}, 51 | {0x4c, 0x00}, 52 | {0x4a, 0x81}, 53 | {0x21, 0x99}, 54 | {AEW, 0x40}, 55 | {AEB, 0x38}, 56 | {VV, VV_AGC_TH_SET(8,2)}, 57 | {0x5c, 0x00}, 58 | {0x63, 0x00}, 59 | {HISTO_LOW, 0x70}, 60 | {HISTO_HIGH, 0x80}, 61 | {0x7c, 0x05}, 62 | {0x20, 0x80}, 63 | {0x28, 0x30}, 64 | {0x6c, 0x00}, 65 | {0x6d, 0x80}, 66 | {0x6e, 0x00}, 67 | {0x70, 0x02}, 68 | {0x71, 0x94}, 69 | {0x73, 0xc1}, 70 | {0x3d, 0x34}, 71 | {0x5a, 0x57}, 72 | {BD50, 0xbb}, 73 | {BD60, 0x9c}, 74 | {COM7, COM7_RES_CIF}, 75 | {HSTART, 0x11}, 76 | {HSTOP, 0x43}, 77 | {VSTART, 0x00}, 78 | {VSTOP, 0x25}, 79 | {REG32, 0x89}, 80 | {0x37, 0xc0}, 81 | {BD50, 0xca}, 82 | {BD60, 0xa8}, 83 | {0x6d, 0x00}, 84 | {0x3d, 0x38}, 85 | {BANK_SEL, BANK_DSP}, 86 | {0xe5, 0x7f}, 87 | {MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL}, 88 | {0x41, 0x24}, 89 | {RESET, RESET_JPEG | RESET_DVP}, 90 | {0x76, 0xff}, 91 | {0x33, 0xa0}, 92 | {0x42, 0x20}, 93 | {0x43, 0x18}, 94 | {0x4c, 0x00}, 95 | {CTRL3, CTRL3_WPC_EN | 0x10 }, 96 | {0x88, 0x3f}, 97 | {0xd7, 0x03}, 98 | {0xd9, 0x10}, 99 | {R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x02}, 100 | {0xc8, 0x08}, 101 | {0xc9, 0x80}, 102 | {BPADDR, 0x00}, 103 | {BPDATA, 0x00}, 104 | {BPADDR, 0x03}, 105 | {BPDATA, 0x48}, 106 | {BPDATA, 0x48}, 107 | {BPADDR, 0x08}, 108 | {BPDATA, 0x20}, 109 | {BPDATA, 0x10}, 110 | {BPDATA, 0x0e}, 111 | {0x90, 0x00}, 112 | {0x91, 0x0e}, 113 | {0x91, 0x1a}, 114 | {0x91, 0x31}, 115 | {0x91, 0x5a}, 116 | {0x91, 0x69}, 117 | {0x91, 0x75}, 118 | {0x91, 0x7e}, 119 | {0x91, 0x88}, 120 | {0x91, 0x8f}, 121 | {0x91, 0x96}, 122 | {0x91, 0xa3}, 123 | {0x91, 0xaf}, 124 | {0x91, 0xc4}, 125 | {0x91, 0xd7}, 126 | {0x91, 0xe8}, 127 | {0x91, 0x20}, 128 | {0x92, 0x00}, 129 | {0x93, 0x06}, 130 | {0x93, 0xe3}, 131 | {0x93, 0x05}, 132 | {0x93, 0x05}, 133 | {0x93, 0x00}, 134 | {0x93, 0x04}, 135 | {0x93, 0x00}, 136 | {0x93, 0x00}, 137 | {0x93, 0x00}, 138 | {0x93, 0x00}, 139 | {0x93, 0x00}, 140 | {0x93, 0x00}, 141 | {0x93, 0x00}, 142 | {0x96, 0x00}, 143 | {0x97, 0x08}, 144 | {0x97, 0x19}, 145 | {0x97, 0x02}, 146 | {0x97, 0x0c}, 147 | {0x97, 0x24}, 148 | {0x97, 0x30}, 149 | {0x97, 0x28}, 150 | {0x97, 0x26}, 151 | {0x97, 0x02}, 152 | {0x97, 0x98}, 153 | {0x97, 0x80}, 154 | {0x97, 0x00}, 155 | {0x97, 0x00}, 156 | {0xa4, 0x00}, 157 | {0xa8, 0x00}, 158 | {0xc5, 0x11}, 159 | {0xc6, 0x51}, 160 | {0xbf, 0x80}, 161 | {0xc7, 0x10}, 162 | {0xb6, 0x66}, 163 | {0xb8, 0xA5}, 164 | {0xb7, 0x64}, 165 | {0xb9, 0x7C}, 166 | {0xb3, 0xaf}, 167 | {0xb4, 0x97}, 168 | {0xb5, 0xFF}, 169 | {0xb0, 0xC5}, 170 | {0xb1, 0x94}, 171 | {0xb2, 0x0f}, 172 | {0xc4, 0x5c}, 173 | {CTRL1, 0xfd}, 174 | {0x7f, 0x00}, 175 | {0xe5, 0x1f}, 176 | {0xe1, 0x67}, 177 | {0xdd, 0x7f}, 178 | {IMAGE_MODE, 0x00}, 179 | {RESET, 0x00}, 180 | {R_BYPASS, R_BYPASS_DSP_EN}, 181 | {0, 0} 182 | }; 183 | 184 | const DRAM_ATTR uint8_t ov2640_settings_to_cif[][2] = { 185 | {BANK_SEL, BANK_SENSOR}, 186 | {COM7, COM7_RES_CIF}, 187 | 188 | //Set the sensor output window 189 | {COM1, 0x0A}, 190 | {REG32, REG32_CIF}, 191 | {HSTART, 0x11}, 192 | {HSTOP, 0x43}, 193 | {VSTART, 0x00}, 194 | {VSTOP, 0x25}, 195 | 196 | {CLKRC, 0x01}, 197 | {BD50, 0xca}, 198 | {BD60, 0xa8}, 199 | {0x5a, 0x23}, 200 | {0x6d, 0x00}, 201 | {0x3d, 0x38}, 202 | {0x39, 0x92}, 203 | {0x35, 0xda}, 204 | {0x22, 0x1a}, 205 | {0x37, 0xc3}, 206 | {0x23, 0x00}, 207 | {ARCOM2, 0xc0}, 208 | {0x06, 0x88}, 209 | {0x07, 0xc0}, 210 | {COM4, 0x87}, 211 | {0x0e, 0x41}, 212 | {0x4c, 0x00}, 213 | {BANK_SEL, BANK_DSP}, 214 | {RESET, RESET_DVP}, 215 | 216 | //Set the sensor resolution (UXGA, SVGA, CIF) 217 | {HSIZE8, 0x32}, 218 | {VSIZE8, 0x25}, 219 | {SIZEL, 0x00}, 220 | 221 | //Set the image window size >= output size 222 | {HSIZE, 0x64}, 223 | {VSIZE, 0x4a}, 224 | {XOFFL, 0x00}, 225 | {YOFFL, 0x00}, 226 | {VHYX, 0x00}, 227 | {TEST, 0x00}, 228 | 229 | {CTRL2, CTRL2_DCW_EN | 0x1D}, 230 | {CTRLI, CTRLI_LP_DP | 0x00}, 231 | {R_DVP_SP, 0x82}, 232 | {0, 0} 233 | }; 234 | 235 | const DRAM_ATTR uint8_t ov2640_settings_to_svga[][2] = { 236 | {BANK_SEL, BANK_SENSOR}, 237 | {COM7, COM7_RES_SVGA}, 238 | 239 | //Set the sensor output window 240 | {COM1, 0x0A}, 241 | {REG32, REG32_SVGA}, 242 | {HSTART, 0x11}, 243 | {HSTOP, 0x43}, 244 | {VSTART, 0x00}, 245 | {VSTOP, 0x4b}, 246 | 247 | {CLKRC, 0x01}, 248 | {0x37, 0xc0}, 249 | {BD50, 0xca}, 250 | {BD60, 0xa8}, 251 | {0x5a, 0x23}, 252 | {0x6d, 0x00}, 253 | {0x3d, 0x38}, 254 | {0x39, 0x92}, 255 | {0x35, 0xda}, 256 | {0x22, 0x1a}, 257 | {0x37, 0xc3}, 258 | {0x23, 0x00}, 259 | {ARCOM2, 0xc0}, 260 | {0x06, 0x88}, 261 | {0x07, 0xc0}, 262 | {COM4, 0x87}, 263 | {0x0e, 0x41}, 264 | {0x42, 0x03}, 265 | {0x4c, 0x00}, 266 | {BANK_SEL, BANK_DSP}, 267 | {RESET, RESET_DVP}, 268 | 269 | //Set the sensor resolution (UXGA, SVGA, CIF) 270 | {HSIZE8, 0x64}, 271 | {VSIZE8, 0x4B}, 272 | {SIZEL, 0x00}, 273 | 274 | //Set the image window size >= output size 275 | {HSIZE, 0xC8}, 276 | {VSIZE, 0x96}, 277 | {XOFFL, 0x00}, 278 | {YOFFL, 0x00}, 279 | {VHYX, 0x00}, 280 | {TEST, 0x00}, 281 | 282 | {CTRL2, CTRL2_DCW_EN | 0x1D}, 283 | {CTRLI, CTRLI_LP_DP | 0x00}, 284 | {R_DVP_SP, 0x80}, 285 | {0, 0} 286 | }; 287 | 288 | const DRAM_ATTR uint8_t ov2640_settings_to_uxga[][2] = { 289 | {BANK_SEL, BANK_SENSOR}, 290 | {COM7, COM7_RES_UXGA}, 291 | 292 | //Set the sensor output window 293 | {COM1, 0x0F}, 294 | {REG32, REG32_UXGA}, 295 | {HSTART, 0x11}, 296 | {HSTOP, 0x75}, 297 | {VSTART, 0x01}, 298 | {VSTOP, 0x97}, 299 | 300 | {CLKRC, 0x01}, 301 | {0x3d, 0x34}, 302 | {BD50, 0xbb}, 303 | {BD60, 0x9c}, 304 | {0x5a, 0x57}, 305 | {0x6d, 0x80}, 306 | {0x39, 0x82}, 307 | {0x23, 0x00}, 308 | {0x07, 0xc0}, 309 | {0x4c, 0x00}, 310 | {0x35, 0x88}, 311 | {0x22, 0x0a}, 312 | {0x37, 0x40}, 313 | {ARCOM2, 0xa0}, 314 | {0x06, 0x02}, 315 | {COM4, 0xb7}, 316 | {0x0e, 0x01}, 317 | {0x42, 0x83}, 318 | {BANK_SEL, BANK_DSP}, 319 | {RESET, RESET_DVP}, 320 | 321 | //Set the sensor resolution (UXGA, SVGA, CIF) 322 | {HSIZE8, 0xc8}, 323 | {VSIZE8, 0x96}, 324 | {SIZEL, 0x00}, 325 | 326 | //Set the image window size >= output size 327 | {HSIZE, 0x90}, 328 | {VSIZE, 0x2c}, 329 | {XOFFL, 0x00}, 330 | {YOFFL, 0x00}, 331 | {VHYX, 0x88}, 332 | {TEST, 0x00}, 333 | 334 | {CTRL2, CTRL2_DCW_EN | 0x1d}, 335 | {CTRLI, 0x00}, 336 | {R_DVP_SP, 0x82}, 337 | {0, 0} 338 | }; 339 | 340 | const DRAM_ATTR uint8_t ov2640_settings_jpeg3[][2] = { 341 | {BANK_SEL, BANK_DSP}, 342 | {RESET, RESET_JPEG | RESET_DVP}, 343 | {IMAGE_MODE, IMAGE_MODE_JPEG_EN | IMAGE_MODE_HREF_VSYNC}, 344 | {0xD7, 0x03}, 345 | {0xE1, 0x77}, 346 | {0xE5, 0x1F}, 347 | {0xD9, 0x10}, 348 | {0xDF, 0x80}, 349 | {0x33, 0x80}, 350 | {0x3C, 0x10}, 351 | {R_DVP_SP, 0x04}, 352 | {0xEB, 0x30}, 353 | {0xDD, 0x7F}, 354 | {RESET, 0x00}, 355 | {0, 0} 356 | }; 357 | 358 | static const uint8_t ov2640_settings_yuv422[][2] = { 359 | {BANK_SEL, BANK_DSP}, 360 | {RESET, RESET_DVP}, 361 | {IMAGE_MODE, IMAGE_MODE_YUV422}, 362 | {0xD7, 0x01}, 363 | {0xE1, 0x67}, 364 | {RESET, 0x00}, 365 | {0, 0}, 366 | }; 367 | 368 | static const uint8_t ov2640_settings_rgb565[][2] = { 369 | {BANK_SEL, BANK_DSP}, 370 | {RESET, RESET_DVP}, 371 | {IMAGE_MODE, IMAGE_MODE_RGB565}, 372 | {0xD7, 0x03}, 373 | {0xE1, 0x77}, 374 | {RESET, 0x00}, 375 | {0, 0}, 376 | }; 377 | 378 | #define NUM_BRIGHTNESS_LEVELS (5) 379 | static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { 380 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 381 | {0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ 382 | {0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ 383 | {0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ 384 | {0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ 385 | {0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ 386 | }; 387 | 388 | #define NUM_CONTRAST_LEVELS (5) 389 | static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { 390 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA }, 391 | {0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ 392 | {0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ 393 | {0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ 394 | {0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ 395 | {0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ 396 | }; 397 | 398 | #define NUM_SATURATION_LEVELS (5) 399 | static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { 400 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 401 | {0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */ 402 | {0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */ 403 | {0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */ 404 | {0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */ 405 | {0x00, 0x02, 0x03, 0x68, 0x68 }, /* +2 */ 406 | }; 407 | 408 | #define NUM_SPECIAL_EFFECTS (7) 409 | static const uint8_t special_effects_regs[NUM_SPECIAL_EFFECTS + 1][5] = { 410 | {BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 411 | {0x00, 0X00, 0x05, 0X80, 0X80 }, /* no effect */ 412 | {0x00, 0X40, 0x05, 0X80, 0X80 }, /* negative */ 413 | {0x00, 0X18, 0x05, 0X80, 0X80 }, /* black and white */ 414 | {0x00, 0X18, 0x05, 0X40, 0XC0 }, /* reddish */ 415 | {0x00, 0X18, 0x05, 0X40, 0X40 }, /* greenish */ 416 | {0x00, 0X18, 0x05, 0XA0, 0X40 }, /* blue */ 417 | {0x00, 0X18, 0x05, 0X40, 0XA6 }, /* retro */ 418 | }; 419 | 420 | #define NUM_WB_MODES (4) 421 | static const uint8_t wb_modes_regs[NUM_WB_MODES + 1][3] = { 422 | {0XCC, 0XCD, 0XCE }, 423 | {0x5E, 0X41, 0x54 }, /* sunny */ 424 | {0x65, 0X41, 0x4F }, /* cloudy */ 425 | {0x52, 0X41, 0x66 }, /* office */ 426 | {0x42, 0X3F, 0x71 }, /* home */ 427 | }; 428 | 429 | #define NUM_AE_LEVELS (5) 430 | static const uint8_t ae_levels_regs[NUM_AE_LEVELS + 1][3] = { 431 | { AEW, AEB, VV }, 432 | {0x20, 0X18, 0x60 }, 433 | {0x34, 0X1C, 0x00 }, 434 | {0x3E, 0X38, 0x81 }, 435 | {0x48, 0X40, 0x81 }, 436 | {0x58, 0X50, 0x92 }, 437 | }; 438 | 439 | const uint8_t agc_gain_tbl[31] = { 440 | 0x00, 0x10, 0x18, 0x30, 0x34, 0x38, 0x3C, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E, 0xF0, 441 | 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF 442 | }; 443 | 444 | #endif /* _OV2640_SETTINGS_H_ */ 445 | -------------------------------------------------------------------------------- /components/ov2640/camera/twi.c: -------------------------------------------------------------------------------- 1 | /* 2 | si2c.c - Software I2C library for ESP31B 3 | 4 | Copyright (c) 2015 Hristo Gochkov. All rights reserved. 5 | This file is part of the ESP31B core for Arduino environment. 6 | 7 | This library is free software; you can redistribute it and/or 8 | modify it under the terms of the GNU Lesser General Public 9 | License as published by the Free Software Foundation; either 10 | version 2.1 of the License, or (at your option) any later version. 11 | 12 | This library is distributed in the hope that it will be useful, 13 | but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | Lesser General Public License for more details. 16 | 17 | You should have received a copy of the GNU Lesser General Public 18 | License along with this library; if not, write to the Free Software 19 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 | */ 21 | #include 22 | #include 23 | #include "twi.h" 24 | #include "soc/gpio_reg.h" 25 | #include "soc/gpio_struct.h" 26 | #include "soc/io_mux_reg.h" 27 | #include "driver/rtc_io.h" 28 | #include 29 | 30 | 31 | #define LOW 0x0 32 | #define HIGH 0x1 33 | 34 | //GPIO FUNCTIONS 35 | #define INPUT 0x01 36 | #define OUTPUT 0x02 37 | #define PULLUP 0x04 38 | #define INPUT_PULLUP 0x05 39 | #define PULLDOWN 0x08 40 | #define INPUT_PULLDOWN 0x09 41 | #define OPEN_DRAIN 0x10 42 | #define OUTPUT_OPEN_DRAIN 0x12 43 | #define SPECIAL 0xF0 44 | #define FUNCTION_1 0x00 45 | #define FUNCTION_2 0x20 46 | #define FUNCTION_3 0x40 47 | #define FUNCTION_4 0x60 48 | #define FUNCTION_5 0x80 49 | #define FUNCTION_6 0xA0 50 | 51 | #define ESP_REG(addr) *((volatile uint32_t *)(addr)) 52 | 53 | const uint8_t pin_to_mux[40] = { 0x44, 0x88, 0x40, 0x84, 0x48, 0x6c, 0x60, 0x64, 0x68, 0x54, 0x58, 0x5c, 0x34, 0x38, 0x30, 0x3c, 0x4c, 0x50, 0x70, 0x74, 0x78, 0x7c, 0x80, 0x8c, 0, 0x24, 0x28, 0x2c, 0, 0, 0, 0, 0x1c, 0x20, 0x14, 0x18, 0x04, 0x08, 0x0c, 0x10}; 54 | 55 | static void pinMode(uint8_t pin, uint8_t mode) 56 | { 57 | if(pin >= 40) { 58 | return; 59 | } 60 | 61 | uint32_t rtc_reg = rtc_gpio_desc[pin].reg; 62 | 63 | //RTC pins PULL settings 64 | if(rtc_reg) { 65 | //lock rtc 66 | ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux); 67 | if(mode & PULLUP) { 68 | ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pullup) & ~(rtc_gpio_desc[pin].pulldown); 69 | } else if(mode & PULLDOWN) { 70 | ESP_REG(rtc_reg) = (ESP_REG(rtc_reg) | rtc_gpio_desc[pin].pulldown) & ~(rtc_gpio_desc[pin].pullup); 71 | } else { 72 | ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown); 73 | } 74 | //unlock rtc 75 | } 76 | 77 | uint32_t pinFunction = 0, pinControl = 0; 78 | 79 | //lock gpio 80 | if(mode & INPUT) { 81 | if(pin < 32) { 82 | GPIO.enable_w1tc = BIT(pin); 83 | } else { 84 | GPIO.enable1_w1tc.val = BIT(pin - 32); 85 | } 86 | } else if(mode & OUTPUT) { 87 | if(pin > 33) { 88 | //unlock gpio 89 | return;//pins above 33 can be only inputs 90 | } else if(pin < 32) { 91 | GPIO.enable_w1ts = BIT(pin); 92 | } else { 93 | GPIO.enable1_w1ts.val = BIT(pin - 32); 94 | } 95 | } 96 | 97 | if(mode & PULLUP) { 98 | pinFunction |= FUN_PU; 99 | } else if(mode & PULLDOWN) { 100 | pinFunction |= FUN_PD; 101 | } 102 | 103 | pinFunction |= ((uint32_t)2 << FUN_DRV_S);//what are the drivers? 104 | pinFunction |= FUN_IE;//input enable but required for output as well? 105 | 106 | if(mode & (INPUT | OUTPUT)) { 107 | pinFunction |= ((uint32_t)2 << MCU_SEL_S); 108 | } else if(mode == SPECIAL) { 109 | pinFunction |= ((uint32_t)(((pin)==1||(pin)==3)?0:1) << MCU_SEL_S); 110 | } else { 111 | pinFunction |= ((uint32_t)(mode >> 5) << MCU_SEL_S); 112 | } 113 | 114 | ESP_REG(DR_REG_IO_MUX_BASE + pin_to_mux[pin]) = pinFunction; 115 | 116 | if(mode & OPEN_DRAIN) { 117 | pinControl = (1 << GPIO_PIN0_PAD_DRIVER_S); 118 | } 119 | 120 | GPIO.pin[pin].val = pinControl; 121 | //unlock gpio 122 | } 123 | 124 | static void digitalWrite(uint8_t pin, uint8_t val) 125 | { 126 | if(val) { 127 | if(pin < 32) { 128 | GPIO.out_w1ts = BIT(pin); 129 | } else if(pin < 34) { 130 | GPIO.out1_w1ts.val = BIT(pin - 32); 131 | } 132 | } else { 133 | if(pin < 32) { 134 | GPIO.out_w1tc = BIT(pin); 135 | } else if(pin < 34) { 136 | GPIO.out1_w1tc.val = BIT(pin - 32); 137 | } 138 | } 139 | } 140 | 141 | 142 | unsigned char twi_dcount = 18; 143 | static unsigned char twi_sda, twi_scl; 144 | 145 | 146 | static inline void SDA_LOW() 147 | { 148 | //Enable SDA (becomes output and since GPO is 0 for the pin, 149 | // it will pull the line low) 150 | if (twi_sda < 32) { 151 | GPIO.enable_w1ts = BIT(twi_sda); 152 | } else { 153 | GPIO.enable1_w1ts.val = BIT(twi_sda - 32); 154 | } 155 | } 156 | 157 | static inline void SDA_HIGH() 158 | { 159 | //Disable SDA (becomes input and since it has pullup it will go high) 160 | if (twi_sda < 32) { 161 | GPIO.enable_w1tc = BIT(twi_sda); 162 | } else { 163 | GPIO.enable1_w1tc.val = BIT(twi_sda - 32); 164 | } 165 | } 166 | 167 | static inline uint32_t SDA_READ() 168 | { 169 | if (twi_sda < 32) { 170 | return (GPIO.in & BIT(twi_sda)) != 0; 171 | } else { 172 | return (GPIO.in1.val & BIT(twi_sda - 32)) != 0; 173 | } 174 | } 175 | 176 | static void SCL_LOW() 177 | { 178 | if (twi_scl < 32) { 179 | GPIO.enable_w1ts = BIT(twi_scl); 180 | } else { 181 | GPIO.enable1_w1ts.val = BIT(twi_scl - 32); 182 | } 183 | } 184 | 185 | static void SCL_HIGH() 186 | { 187 | if (twi_scl < 32) { 188 | GPIO.enable_w1tc = BIT(twi_scl); 189 | } else { 190 | GPIO.enable1_w1tc.val = BIT(twi_scl - 32); 191 | } 192 | } 193 | 194 | static uint32_t SCL_READ() 195 | { 196 | if (twi_scl < 32) { 197 | return (GPIO.in & BIT(twi_scl)) != 0; 198 | } else { 199 | return (GPIO.in1.val & BIT(twi_scl - 32)) != 0; 200 | } 201 | } 202 | 203 | 204 | #ifndef FCPU80 205 | #define FCPU80 80000000L 206 | #endif 207 | 208 | #if F_CPU == FCPU80 209 | #define TWI_CLOCK_STRETCH 800 210 | #else 211 | #define TWI_CLOCK_STRETCH 1600 212 | #endif 213 | 214 | void twi_setClock(unsigned int freq) 215 | { 216 | #if F_CPU == FCPU80 217 | if(freq <= 100000) { 218 | twi_dcount = 19; //about 100KHz 219 | } else if(freq <= 200000) { 220 | twi_dcount = 8; //about 200KHz 221 | } else if(freq <= 300000) { 222 | twi_dcount = 3; //about 300KHz 223 | } else if(freq <= 400000) { 224 | twi_dcount = 1; //about 400KHz 225 | } else { 226 | twi_dcount = 1; //about 400KHz 227 | } 228 | #else 229 | if(freq <= 100000) { 230 | twi_dcount = 32; //about 100KHz 231 | } else if(freq <= 200000) { 232 | twi_dcount = 14; //about 200KHz 233 | } else if(freq <= 300000) { 234 | twi_dcount = 8; //about 300KHz 235 | } else if(freq <= 400000) { 236 | twi_dcount = 5; //about 400KHz 237 | } else if(freq <= 500000) { 238 | twi_dcount = 3; //about 500KHz 239 | } else if(freq <= 600000) { 240 | twi_dcount = 2; //about 600KHz 241 | } else { 242 | twi_dcount = 1; //about 700KHz 243 | } 244 | #endif 245 | } 246 | 247 | void twi_init(unsigned char sda, unsigned char scl) 248 | { 249 | twi_sda = sda; 250 | twi_scl = scl; 251 | pinMode(twi_sda, OUTPUT); 252 | pinMode(twi_scl, OUTPUT); 253 | 254 | digitalWrite(twi_sda, 0); 255 | digitalWrite(twi_scl, 0); 256 | 257 | pinMode(twi_sda, INPUT_PULLUP); 258 | pinMode(twi_scl, INPUT_PULLUP); 259 | twi_setClock(100000); 260 | } 261 | 262 | void twi_stop(void) 263 | { 264 | pinMode(twi_sda, INPUT); 265 | pinMode(twi_scl, INPUT); 266 | } 267 | 268 | static void twi_delay(unsigned char v) 269 | { 270 | unsigned int i; 271 | #pragma GCC diagnostic push 272 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 273 | unsigned int reg; 274 | for(i=0; i255)?255:(v)) 286 | 287 | void IRAM_ATTR yuv2rgb(uint8_t y, uint8_t u, uint8_t v, uint8_t *r, uint8_t *g, uint8_t *b) 288 | { 289 | int16_t ri, gi, bi; 290 | 291 | ri = yuv_table[y].vY + yuv_table[v].vVr; 292 | gi = yuv_table[y].vY + yuv_table[u].vUg + yuv_table[v].vVg; 293 | bi = yuv_table[y].vY + yuv_table[u].vUb; 294 | 295 | *r = YUYV_CONSTRAIN(ri); 296 | *g = YUYV_CONSTRAIN(gi); 297 | *b = YUYV_CONSTRAIN(bi); 298 | } 299 | -------------------------------------------------------------------------------- /components/ov2640/sensors/ov2640.c: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of the OpenMV project. 3 | * Copyright (c) 2013/2014 Ibrahim Abdelkader 4 | * This work is licensed under the MIT license, see the file LICENSE for details. 5 | * 6 | * OV2640 driver. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "sccb.h" 13 | #include "ov2640.h" 14 | #include "ov2640_regs.h" 15 | #include "ov2640_settings.h" 16 | #include "freertos/FreeRTOS.h" 17 | #include "freertos/task.h" 18 | 19 | #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG) 20 | #include "esp32-hal-log.h" 21 | #else 22 | #include "esp_log.h" 23 | static const char* TAG = "ov2640"; 24 | #endif 25 | 26 | static volatile ov2640_bank_t reg_bank = BANK_MAX; 27 | static int set_bank(sensor_t *sensor, ov2640_bank_t bank) 28 | { 29 | int res = 0; 30 | if (bank != reg_bank) { 31 | reg_bank = bank; 32 | res = SCCB_Write(sensor->slv_addr, BANK_SEL, bank); 33 | } 34 | return res; 35 | } 36 | 37 | static int write_regs(sensor_t *sensor, const uint8_t (*regs)[2]) 38 | { 39 | int i=0, res = 0; 40 | while (regs[i][0]) { 41 | if (regs[i][0] == BANK_SEL) { 42 | res = set_bank(sensor, regs[i][1]); 43 | } else { 44 | res = SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 45 | } 46 | if (res) { 47 | return res; 48 | } 49 | i++; 50 | } 51 | return res; 52 | } 53 | 54 | static int write_reg(sensor_t *sensor, ov2640_bank_t bank, uint8_t reg, uint8_t value) 55 | { 56 | int ret = set_bank(sensor, bank); 57 | if(!ret) { 58 | ret = SCCB_Write(sensor->slv_addr, reg, value); 59 | } 60 | return ret; 61 | } 62 | 63 | static int set_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t offset, uint8_t mask, uint8_t value) 64 | { 65 | int ret = 0; 66 | uint8_t c_value, new_value; 67 | 68 | ret = set_bank(sensor, bank); 69 | if(ret) { 70 | return ret; 71 | } 72 | c_value = SCCB_Read(sensor->slv_addr, reg); 73 | new_value = (c_value & ~(mask << offset)) | ((value & mask) << offset); 74 | ret = SCCB_Write(sensor->slv_addr, reg, new_value); 75 | return ret; 76 | } 77 | 78 | static int read_reg(sensor_t *sensor, ov2640_bank_t bank, uint8_t reg) 79 | { 80 | if(set_bank(sensor, bank)){ 81 | return 0; 82 | } 83 | return SCCB_Read(sensor->slv_addr, reg); 84 | } 85 | 86 | static uint8_t get_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t offset, uint8_t mask) 87 | { 88 | return (read_reg(sensor, bank, reg) >> offset) & mask; 89 | } 90 | 91 | static int write_reg_bits(sensor_t *sensor, uint8_t bank, uint8_t reg, uint8_t mask, int enable) 92 | { 93 | return set_reg_bits(sensor, bank, reg, 0, mask, enable?mask:0); 94 | } 95 | 96 | #define WRITE_REGS_OR_RETURN(regs) ret = write_regs(sensor, regs); if(ret){return ret;} 97 | #define WRITE_REG_OR_RETURN(bank, reg, val) ret = write_reg(sensor, bank, reg, val); if(ret){return ret;} 98 | #define SET_REG_BITS_OR_RETURN(bank, reg, offset, mask, val) ret = set_reg_bits(sensor, bank, reg, offset, mask, val); if(ret){return ret;} 99 | 100 | static int reset(sensor_t *sensor) 101 | { 102 | int ret = 0; 103 | WRITE_REG_OR_RETURN(BANK_SENSOR, COM7, COM7_SRST); 104 | vTaskDelay(10 / portTICK_PERIOD_MS); 105 | WRITE_REGS_OR_RETURN(ov2640_settings_cif); 106 | return ret; 107 | } 108 | 109 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) 110 | { 111 | int ret = 0; 112 | sensor->pixformat = pixformat; 113 | switch (pixformat) { 114 | case PIXFORMAT_RGB565: 115 | case PIXFORMAT_RGB888: 116 | WRITE_REGS_OR_RETURN(ov2640_settings_rgb565); 117 | break; 118 | case PIXFORMAT_YUV422: 119 | case PIXFORMAT_GRAYSCALE: 120 | WRITE_REGS_OR_RETURN(ov2640_settings_yuv422); 121 | break; 122 | case PIXFORMAT_JPEG: 123 | WRITE_REGS_OR_RETURN(ov2640_settings_jpeg3); 124 | break; 125 | default: 126 | ret = -1; 127 | break; 128 | } 129 | if(!ret) { 130 | vTaskDelay(10 / portTICK_PERIOD_MS); 131 | } 132 | 133 | return ret; 134 | } 135 | 136 | //Functions are not needed currently 137 | #if 0 138 | //Set the sensor output window 139 | int set_output_window(sensor_t *sensor, uint16_t x, uint16_t y, uint16_t width, uint16_t height) 140 | { 141 | int ret = 0; 142 | uint16_t endx, endy; 143 | uint8_t com1, reg32; 144 | 145 | endy = y + height / 2; 146 | com1 = read_reg(sensor, BANK_SENSOR, COM1); 147 | WRITE_REG_OR_RETURN(BANK_SENSOR, COM1, (com1 & 0XF0) | (((endy & 0X03) << 2) | (y & 0X03))); 148 | WRITE_REG_OR_RETURN(BANK_SENSOR, VSTART, y >> 2); 149 | WRITE_REG_OR_RETURN(BANK_SENSOR, VSTOP, endy >> 2); 150 | 151 | endx = x + width / 2; 152 | reg32 = read_reg(sensor, BANK_SENSOR, REG32); 153 | WRITE_REG_OR_RETURN(BANK_SENSOR, REG32, (reg32 & 0XC0) | (((endx & 0X07) << 3) | (x & 0X07))); 154 | WRITE_REG_OR_RETURN(BANK_SENSOR, HSTART, x >> 3); 155 | WRITE_REG_OR_RETURN(BANK_SENSOR, HSTOP, endx >> 3); 156 | 157 | return ret; 158 | } 159 | 160 | // Set the image output size (final output resolution) 161 | int set_output_size(sensor_t *sensor, uint16_t width, uint16_t height) 162 | { 163 | int ret = 0; 164 | uint16_t h, w; 165 | 166 | if(width % 4) { 167 | return -1; 168 | } 169 | if(height % 4 ) { 170 | return -2; 171 | } 172 | 173 | w = width / 4; 174 | h = height / 4; 175 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP); 176 | WRITE_REG_OR_RETURN(BANK_DSP, ZMOW, w & 0XFF); 177 | WRITE_REG_OR_RETURN(BANK_DSP, ZMOH, h & 0XFF); 178 | WRITE_REG_OR_RETURN(BANK_DSP, ZMHH, ((w >> 8) & 0X03) | ((h >> 6) & 0X04)); 179 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00); 180 | 181 | return ret; 182 | } 183 | 184 | //Set the image window size >= output size 185 | int set_window_size(sensor_t *sensor, uint16_t x, uint16_t y, uint16_t width, uint16_t height) 186 | { 187 | int ret = 0; 188 | uint16_t w, h; 189 | 190 | if(width % 4) { 191 | return -1; 192 | } 193 | if(height % 4) { 194 | return -2; 195 | } 196 | 197 | w = width / 4; 198 | h = height / 4; 199 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP); 200 | WRITE_REG_OR_RETURN(BANK_DSP, HSIZE, w & 0XFF); 201 | WRITE_REG_OR_RETURN(BANK_DSP, VSIZE, h & 0XFF); 202 | WRITE_REG_OR_RETURN(BANK_DSP, XOFFL, x & 0XFF); 203 | WRITE_REG_OR_RETURN(BANK_DSP, YOFFL, y & 0XFF); 204 | WRITE_REG_OR_RETURN(BANK_DSP, VHYX, ((h >> 1) & 0X80) | ((y >> 4) & 0X70) | ((w >> 5) & 0X08) | ((x >> 8) & 0X07)); 205 | WRITE_REG_OR_RETURN(BANK_DSP, TEST, (w >> 2) & 0X80); 206 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00); 207 | 208 | return ret; 209 | } 210 | 211 | //Set the sensor resolution (UXGA, SVGA, CIF) 212 | int set_image_size(sensor_t *sensor, uint16_t width, uint16_t height) 213 | { 214 | int ret = 0; 215 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, RESET_DVP); 216 | WRITE_REG_OR_RETURN(BANK_DSP, HSIZE8, (width >> 3) & 0XFF); 217 | WRITE_REG_OR_RETURN(BANK_DSP, VSIZE8, (height >> 3) & 0XFF); 218 | WRITE_REG_OR_RETURN(BANK_DSP, SIZEL, ((width & 0X07) << 3) | ((width >> 4) & 0X80) | (height & 0X07)); 219 | //WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0X00); 220 | 221 | return ret; 222 | } 223 | #endif 224 | 225 | static int set_framesize(sensor_t *sensor, framesize_t framesize) 226 | { 227 | int ret = 0; 228 | uint16_t w = resolution[framesize][0]; 229 | uint16_t h = resolution[framesize][1]; 230 | const uint8_t (*regs)[2]; 231 | 232 | sensor->status.framesize = framesize; 233 | 234 | if (framesize <= FRAMESIZE_CIF) { 235 | regs = ov2640_settings_to_cif; 236 | } else if (framesize <= FRAMESIZE_SVGA) { 237 | regs = ov2640_settings_to_svga; 238 | } else { 239 | regs = ov2640_settings_to_uxga; 240 | } 241 | 242 | WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_BYPAS); 243 | WRITE_REGS_OR_RETURN(regs); 244 | WRITE_REG_OR_RETURN(BANK_DSP, ZMOW, (w>>2)&0xFF); // OUTW[7:0] (real/4) 245 | WRITE_REG_OR_RETURN(BANK_DSP, ZMOH, (h>>2)&0xFF); // OUTH[7:0] (real/4) 246 | WRITE_REG_OR_RETURN(BANK_DSP, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); // OUTH[8]/OUTW[9:8] 247 | WRITE_REG_OR_RETURN(BANK_DSP, RESET, 0x00); 248 | WRITE_REG_OR_RETURN(BANK_DSP, R_BYPASS, R_BYPASS_DSP_EN); 249 | 250 | vTaskDelay(10 / portTICK_PERIOD_MS); 251 | //required when changing resolution 252 | set_pixformat(sensor, sensor->pixformat); 253 | 254 | return ret; 255 | } 256 | 257 | static int set_contrast(sensor_t *sensor, int level) 258 | { 259 | int ret=0; 260 | level += 3; 261 | if (level <= 0 || level > NUM_CONTRAST_LEVELS) { 262 | return -1; 263 | } 264 | sensor->status.contrast = level-3; 265 | for (int i=0; i<7; i++) { 266 | WRITE_REG_OR_RETURN(BANK_DSP, contrast_regs[0][i], contrast_regs[level][i]); 267 | } 268 | return ret; 269 | } 270 | 271 | static int set_brightness(sensor_t *sensor, int level) 272 | { 273 | int ret=0; 274 | level += 3; 275 | if (level <= 0 || level > NUM_BRIGHTNESS_LEVELS) { 276 | return -1; 277 | } 278 | sensor->status.brightness = level-3; 279 | for (int i=0; i<5; i++) { 280 | WRITE_REG_OR_RETURN(BANK_DSP, brightness_regs[0][i], brightness_regs[level][i]); 281 | } 282 | return ret; 283 | } 284 | 285 | static int set_saturation(sensor_t *sensor, int level) 286 | { 287 | int ret=0; 288 | level += 3; 289 | if (level <= 0 || level > NUM_SATURATION_LEVELS) { 290 | return -1; 291 | } 292 | sensor->status.saturation = level-3; 293 | for (int i=0; i<5; i++) { 294 | WRITE_REG_OR_RETURN(BANK_DSP, saturation_regs[0][i], saturation_regs[level][i]); 295 | } 296 | return ret; 297 | } 298 | 299 | static int set_special_effect(sensor_t *sensor, int effect) 300 | { 301 | int ret=0; 302 | effect++; 303 | if (effect <= 0 || effect > NUM_SPECIAL_EFFECTS) { 304 | return -1; 305 | } 306 | sensor->status.special_effect = effect-1; 307 | for (int i=0; i<5; i++) { 308 | WRITE_REG_OR_RETURN(BANK_DSP, special_effects_regs[0][i], special_effects_regs[effect][i]); 309 | } 310 | return ret; 311 | } 312 | 313 | static int set_wb_mode(sensor_t *sensor, int mode) 314 | { 315 | int ret=0; 316 | if (mode < 0 || mode > NUM_WB_MODES) { 317 | return -1; 318 | } 319 | sensor->status.wb_mode = mode; 320 | SET_REG_BITS_OR_RETURN(BANK_DSP, 0XC7, 6, 1, mode?1:0); 321 | if(mode) { 322 | for (int i=0; i<3; i++) { 323 | WRITE_REG_OR_RETURN(BANK_DSP, wb_modes_regs[0][i], wb_modes_regs[mode][i]); 324 | } 325 | } 326 | return ret; 327 | } 328 | 329 | static int set_ae_level(sensor_t *sensor, int level) 330 | { 331 | int ret=0; 332 | level += 3; 333 | if (level <= 0 || level > NUM_AE_LEVELS) { 334 | return -1; 335 | } 336 | sensor->status.ae_level = level-3; 337 | for (int i=0; i<3; i++) { 338 | WRITE_REG_OR_RETURN(BANK_SENSOR, ae_levels_regs[0][i], ae_levels_regs[level][i]); 339 | } 340 | return ret; 341 | } 342 | 343 | static int set_quality(sensor_t *sensor, int quality) 344 | { 345 | if(quality < 0) { 346 | quality = 0; 347 | } else if(quality > 63) { 348 | quality = 63; 349 | } 350 | sensor->status.quality = quality; 351 | return write_reg(sensor, BANK_DSP, QS, quality); 352 | } 353 | 354 | static int set_agc_gain(sensor_t *sensor, int gain) 355 | { 356 | if(gain < 0) { 357 | gain = 0; 358 | } else if(gain > 30) { 359 | gain = 30; 360 | } 361 | sensor->status.agc_gain = gain; 362 | return write_reg(sensor, BANK_SENSOR, GAIN, agc_gain_tbl[gain]); 363 | } 364 | 365 | static int set_gainceiling_sensor(sensor_t *sensor, gainceiling_t gainceiling) 366 | { 367 | sensor->status.gainceiling = gainceiling; 368 | //return write_reg(sensor, BANK_SENSOR, COM9, COM9_AGC_SET(gainceiling)); 369 | return set_reg_bits(sensor, BANK_SENSOR, COM9, 5, 7, gainceiling); 370 | } 371 | 372 | static int set_aec_value(sensor_t *sensor, int value) 373 | { 374 | if(value < 0) { 375 | value = 0; 376 | } else if(value > 1200) { 377 | value = 1200; 378 | } 379 | sensor->status.aec_value = value; 380 | return set_reg_bits(sensor, BANK_SENSOR, REG04, 0, 3, value & 0x3) 381 | || write_reg(sensor, BANK_SENSOR, AEC, (value >> 2) & 0xFF) 382 | || set_reg_bits(sensor, BANK_SENSOR, REG45, 0, 0x3F, value >> 10); 383 | } 384 | 385 | static int set_aec2(sensor_t *sensor, int enable) 386 | { 387 | sensor->status.aec2 = enable; 388 | return set_reg_bits(sensor, BANK_DSP, CTRL0, 6, 1, enable?0:1); 389 | } 390 | 391 | static int set_colorbar(sensor_t *sensor, int enable) 392 | { 393 | sensor->status.colorbar = enable; 394 | return write_reg_bits(sensor, BANK_SENSOR, COM7, COM7_COLOR_BAR, enable?1:0); 395 | } 396 | 397 | static int set_agc_sensor(sensor_t *sensor, int enable) 398 | { 399 | sensor->status.agc = enable; 400 | return write_reg_bits(sensor, BANK_SENSOR, COM8, COM8_AGC_EN, enable?1:0); 401 | } 402 | 403 | static int set_aec_sensor(sensor_t *sensor, int enable) 404 | { 405 | sensor->status.aec = enable; 406 | return write_reg_bits(sensor, BANK_SENSOR, COM8, COM8_AEC_EN, enable?1:0); 407 | } 408 | 409 | static int set_hmirror_sensor(sensor_t *sensor, int enable) 410 | { 411 | sensor->status.hmirror = enable; 412 | return write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_HFLIP_IMG, enable?1:0); 413 | } 414 | 415 | static int set_vflip_sensor(sensor_t *sensor, int enable) 416 | { 417 | int ret = 0; 418 | sensor->status.vflip = enable; 419 | ret = write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_VREF_EN, enable?1:0); 420 | return ret & write_reg_bits(sensor, BANK_SENSOR, REG04, REG04_VFLIP_IMG, enable?1:0); 421 | } 422 | 423 | static int set_raw_gma_dsp(sensor_t *sensor, int enable) 424 | { 425 | sensor->status.raw_gma = enable; 426 | return set_reg_bits(sensor, BANK_DSP, CTRL1, 5, 1, enable?1:0); 427 | } 428 | 429 | static int set_awb_dsp(sensor_t *sensor, int enable) 430 | { 431 | sensor->status.awb = enable; 432 | return set_reg_bits(sensor, BANK_DSP, CTRL1, 3, 1, enable?1:0); 433 | } 434 | 435 | static int set_awb_gain_dsp(sensor_t *sensor, int enable) 436 | { 437 | sensor->status.awb_gain = enable; 438 | return set_reg_bits(sensor, BANK_DSP, CTRL1, 2, 1, enable?1:0); 439 | } 440 | 441 | static int set_lenc_dsp(sensor_t *sensor, int enable) 442 | { 443 | sensor->status.lenc = enable; 444 | return set_reg_bits(sensor, BANK_DSP, CTRL1, 1, 1, enable?1:0); 445 | } 446 | 447 | static int set_dcw_dsp(sensor_t *sensor, int enable) 448 | { 449 | sensor->status.dcw = enable; 450 | return set_reg_bits(sensor, BANK_DSP, CTRL2, 5, 1, enable?1:0); 451 | } 452 | 453 | static int set_bpc_dsp(sensor_t *sensor, int enable) 454 | { 455 | sensor->status.bpc = enable; 456 | return set_reg_bits(sensor, BANK_DSP, CTRL3, 7, 1, enable?1:0); 457 | } 458 | 459 | static int set_wpc_dsp(sensor_t *sensor, int enable) 460 | { 461 | sensor->status.wpc = enable; 462 | return set_reg_bits(sensor, BANK_DSP, CTRL3, 6, 1, enable?1:0); 463 | } 464 | 465 | static int init_status(sensor_t *sensor){ 466 | sensor->status.brightness = 0; 467 | sensor->status.contrast = 0; 468 | sensor->status.saturation = 0; 469 | sensor->status.ae_level = 0; 470 | sensor->status.special_effect = 0; 471 | sensor->status.wb_mode = 0; 472 | 473 | sensor->status.agc_gain = 30; 474 | int agc_gain = read_reg(sensor, BANK_SENSOR, GAIN); 475 | for (int i=0; i<30; i++){ 476 | if(agc_gain >= agc_gain_tbl[i] && agc_gain < agc_gain_tbl[i+1]){ 477 | sensor->status.agc_gain = i; 478 | break; 479 | } 480 | } 481 | 482 | sensor->status.aec_value = ((uint16_t)get_reg_bits(sensor, BANK_SENSOR, REG45, 0, 0x3F) << 10) 483 | | ((uint16_t)read_reg(sensor, BANK_SENSOR, AEC) << 2) 484 | | get_reg_bits(sensor, BANK_SENSOR, REG04, 0, 3);//0 - 1200 485 | sensor->status.quality = read_reg(sensor, BANK_DSP, QS); 486 | sensor->status.gainceiling = get_reg_bits(sensor, BANK_SENSOR, COM9, 5, 7); 487 | 488 | sensor->status.awb = get_reg_bits(sensor, BANK_DSP, CTRL1, 3, 1); 489 | sensor->status.awb_gain = get_reg_bits(sensor, BANK_DSP, CTRL1, 2, 1); 490 | sensor->status.aec = get_reg_bits(sensor, BANK_SENSOR, COM8, 0, 1); 491 | sensor->status.aec2 = get_reg_bits(sensor, BANK_DSP, CTRL0, 6, 1); 492 | sensor->status.agc = get_reg_bits(sensor, BANK_SENSOR, COM8, 2, 1); 493 | sensor->status.bpc = get_reg_bits(sensor, BANK_DSP, CTRL3, 7, 1); 494 | sensor->status.wpc = get_reg_bits(sensor, BANK_DSP, CTRL3, 6, 1); 495 | sensor->status.raw_gma = get_reg_bits(sensor, BANK_DSP, CTRL1, 5, 1); 496 | sensor->status.lenc = get_reg_bits(sensor, BANK_DSP, CTRL1, 1, 1); 497 | sensor->status.hmirror = get_reg_bits(sensor, BANK_SENSOR, REG04, 7, 1); 498 | sensor->status.vflip = get_reg_bits(sensor, BANK_SENSOR, REG04, 6, 1); 499 | sensor->status.dcw = get_reg_bits(sensor, BANK_DSP, CTRL2, 5, 1); 500 | sensor->status.colorbar = get_reg_bits(sensor, BANK_SENSOR, COM7, 1, 1); 501 | return 0; 502 | } 503 | 504 | int ov2640_init(sensor_t *sensor) 505 | { 506 | sensor->reset = reset; 507 | sensor->init_status = init_status; 508 | sensor->set_pixformat = set_pixformat; 509 | sensor->set_framesize = set_framesize; 510 | sensor->set_contrast = set_contrast; 511 | sensor->set_brightness= set_brightness; 512 | sensor->set_saturation= set_saturation; 513 | 514 | sensor->set_quality = set_quality; 515 | sensor->set_colorbar = set_colorbar; 516 | 517 | sensor->set_gainceiling = set_gainceiling_sensor; 518 | sensor->set_gain_ctrl = set_agc_sensor; 519 | sensor->set_exposure_ctrl = set_aec_sensor; 520 | sensor->set_hmirror = set_hmirror_sensor; 521 | sensor->set_vflip = set_vflip_sensor; 522 | 523 | sensor->set_whitebal = set_awb_dsp; 524 | sensor->set_aec2 = set_aec2; 525 | sensor->set_aec_value = set_aec_value; 526 | sensor->set_special_effect = set_special_effect; 527 | sensor->set_wb_mode = set_wb_mode; 528 | sensor->set_ae_level = set_ae_level; 529 | 530 | sensor->set_dcw = set_dcw_dsp; 531 | sensor->set_bpc = set_bpc_dsp; 532 | sensor->set_wpc = set_wpc_dsp; 533 | sensor->set_awb_gain = set_awb_gain_dsp; 534 | sensor->set_agc_gain = set_agc_gain; 535 | 536 | sensor->set_raw_gma = set_raw_gma_dsp; 537 | sensor->set_lenc = set_lenc_dsp; 538 | 539 | ESP_LOGD(TAG, "OV2640 Attached"); 540 | return 0; 541 | } 542 | -------------------------------------------------------------------------------- /main/main.c: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * ---------------------------------------------------------------------------- 4 | * "THE BEER-WARE LICENSE" (Revision 42): 5 | * Jeroen Domburg wrote this file. As long as you retain 6 | * this notice you can do whatever you want with this stuff. If we meet some day, 7 | * and you think this stuff is worth it, you can buy me a beer in return. 8 | * ---------------------------------------------------------------------------- 9 | */ 10 | 11 | 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "freertos/FreeRTOS.h" 21 | #include "freertos/task.h" 22 | #include "freertos/event_groups.h" 23 | 24 | #include "esp_camera.h" 25 | 26 | #include "display.h" 27 | 28 | //Make 1 to output picture data on the serial port, in base64. 29 | //Picture is encoded as 160x120 8-bit grayscale raw image data. 30 | #define DUMP_PIC_SERIAL 0 31 | 32 | //This refers the raw set of 16x16 images. 33 | extern const uint8_t eye_raw_image_data[] asm("_binary_eye_raw_start"); 34 | 35 | typedef struct { 36 | int px; //x pos of pupil 37 | int py; //y pos of pupil 38 | int pc; //status: 0 open 1 half-closed, 2 fully-closed blink 39 | } imgdesc_t; 40 | 41 | //This array contains the information for each 16x16 image in eye_raw_image_data: we use 42 | //this info to pick the correct image to display for a given center of movement and blink status. 43 | //Note pupil x/y is in the *original, unscaled* image data, and as such is more-or-less used as 44 | //an indication. 45 | //Note that this has been mostly autogenerated, see eye_gfx/readme.txt for more info 46 | const imgdesc_t images[]={ 47 | {257, 197, 0}, 48 | {257, 197, 1}, 49 | {257, 197, 2}, 50 | {250, 207, 0}, 51 | {240, 205, 0}, 52 | {232, 208, 0}, 53 | {231, 208, 0}, 54 | {231, 208, 1}, 55 | {231, 208, 2}, 56 | {218, 217, 0}, 57 | {214, 225, 0}, 58 | {214, 225, 1}, 59 | {214, 225, 2}, 60 | {206, 250, 0}, 61 | {206, 250, 1}, 62 | {206, 250, 2}, 63 | {208, 259, 0}, 64 | {212, 270, 0}, 65 | {212, 270, 1}, 66 | {212, 270, 2}, 67 | {220, 276, 0}, 68 | {224, 279, 0}, 69 | {228, 281, 0}, 70 | {228, 281, 1}, 71 | {228, 281, 2}, 72 | {254, 294, 0}, 73 | {254, 294, 1}, 74 | {254, 294, 2}, 75 | {292, 285, 0}, 76 | {292, 285, 1}, 77 | {292, 285, 2}, 78 | {318, 268, 0}, 79 | {318, 268, 1}, 80 | {318, 268, 2}, 81 | {326, 248, 0}, 82 | {326, 248, 1}, 83 | {324, 225, 0}, 84 | {331, 219, 0}, 85 | {336, 219, 0}, 86 | {336, 219, 1}, 87 | {336, 219, 2}, 88 | {314, 193, 0}, 89 | {314, 193, 1}, 90 | {314, 193, 2}, 91 | {281, 193, 0}, 92 | {273, 192, 0}, 93 | {273, 192, 1}, 94 | {273, 192, 2}, 95 | {241, 200, 0}, 96 | {241, 200, 1}, 97 | {241, 200, 2}, 98 | {253, 211, 0}, 99 | {250, 210, 0}, 100 | {250, 210, 1}, 101 | {250, 210, 2}, 102 | {224, 217, 0}, 103 | {224, 226, 0}, 104 | {224, 226, 1}, 105 | {224, 226, 2}, 106 | {223, 226, 0}, 107 | {218, 243, 0}, 108 | {218, 243, 1}, 109 | {218, 243, 2}, 110 | {216, 257, 0}, 111 | {223, 265, 0}, 112 | {227, 262, 0}, 113 | {227, 262, 1}, 114 | {227, 262, 2}, 115 | {234, 284, 0}, 116 | {234, 284, 1}, 117 | {234, 284, 2}, 118 | {269, 283, 0}, 119 | {269, 283, 1}, 120 | {269, 283, 2}, 121 | {288, 285, 0}, 122 | {295, 284, 0}, 123 | {295, 284, 1}, 124 | {295, 284, 2}, 125 | {321, 264, 0}, 126 | {309, 268, 0}, 127 | {324, 242, 0}, 128 | {324, 242, 1}, 129 | {324, 242, 2}, 130 | {322, 213, 0}, 131 | {308, 220, 0}, 132 | {308, 220, 1}, 133 | {308, 220, 2}, 134 | {261, 216, 0}, 135 | {250, 215, 0}, 136 | {250, 215, 1}, 137 | {250, 215, 2}, 138 | {237, 224, 0}, 139 | {237, 224, 1}, 140 | {237, 224, 2}, 141 | {227, 245, 0}, 142 | {236, 234, 0}, 143 | {236, 234, 1}, 144 | {236, 234, 2}, 145 | {248, 241, 0}, 146 | {248, 241, 1}, 147 | {248, 241, 2}, 148 | {269, 238, 0}, 149 | {285, 235, 0}, 150 | {285, 235, 1}, 151 | {285, 235, 2}, 152 | {310, 238, 0}, 153 | {310, 238, 1}, 154 | {310, 238, 2}, 155 | {341, 240, 0}, 156 | {341, 240, 1}, 157 | {341, 240, 2}, 158 | {328, 259, 0}, 159 | {328, 259, 1}, 160 | {328, 259, 2}, 161 | {295, 256, 0}, 162 | {306, 252, 0}, 163 | {306, 252, 1}, 164 | {306, 252, 2}, 165 | {260, 254, 0}, 166 | {260, 254, 1}, 167 | {260, 254, 2}, 168 | {239, 255, 0}, 169 | {239, 255, 1}, 170 | {239, 255, 2}, 171 | {227, 258, 0}, 172 | {227, 258, 1}, 173 | {227, 258, 2}, 174 | {243, 277, 0}, 175 | {253, 276, 0}, 176 | {253, 276, 1}, 177 | {253, 276, 2}, 178 | {279, 276, 0}, 179 | {279, 276, 1}, 180 | {279, 276, 2}, 181 | {288, 262, 0}, 182 | {288, 262, 1}, 183 | {288, 262, 2}, 184 | {313, 266, 0}, 185 | {313, 266, 1}, 186 | {313, 266, 2}, 187 | {278, 285, 0}, 188 | {263, 281, 0}, 189 | {263, 281, 1}, 190 | {263, 281, 2}, 191 | {242, 278, 0}, 192 | {242, 278, 1}, 193 | {242, 278, 2}, 194 | {319, 236, 0}, 195 | {340, 236, 0}, 196 | {0,0,-1} //final 197 | }; 198 | 199 | //Parameters to tweak the mapping between the pupil xpos and ypos and the corresponding 200 | //center of movement. 201 | #define EYE_XMIN 200 202 | #define EYE_XMAX 390 203 | #define EYE_YMIN 170 204 | #define EYE_YMAX 320 205 | 206 | //QQVGA 207 | #define CAMW 160 208 | #define CAMH 120 209 | 210 | //Debug function to base64-encode an image or other data 211 | static void __attribute__((unused)) base64_dump(const unsigned char *src, size_t len, int *ll) { 212 | static const unsigned char base64_table[65] = 213 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 214 | const unsigned char *end, *in; 215 | int line_len; 216 | 217 | end = src + len; 218 | in = src; 219 | if (ll) line_len = *ll; else line_len=0; 220 | while (end - in >= 3) { 221 | putchar(base64_table[in[0] >> 2]); 222 | putchar(base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]); 223 | putchar(base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]); 224 | putchar(base64_table[in[2] & 0x3f]); 225 | in += 3; 226 | line_len += 4; 227 | if (line_len >= 72) { 228 | putchar('\n'); 229 | line_len = 0; 230 | } 231 | } 232 | 233 | if (end - in) { 234 | putchar(base64_table[in[0] >> 2]); 235 | if (end - in == 1) { 236 | putchar(base64_table[(in[0] & 0x03) << 4]); 237 | putchar('='); 238 | } else { 239 | putchar(base64_table[((in[0] & 0x03) << 4) | 240 | (in[1] >> 4)]); 241 | putchar(base64_table[(in[1] & 0x0f) << 2]); 242 | } 243 | putchar('='); 244 | line_len += 4; 245 | } 246 | if (ll) *ll=line_len; 247 | } 248 | 249 | //Camera config is specific for an esp-cam board 250 | static camera_config_t camera_config = { 251 | .pin_pwdn = -1, 252 | .pin_reset = CONFIG_RESET, 253 | .pin_xclk = CONFIG_XCLK, 254 | .pin_sscb_sda = CONFIG_SDA, 255 | .pin_sscb_scl = CONFIG_SCL, 256 | 257 | .pin_d7 = CONFIG_D7, 258 | .pin_d6 = CONFIG_D6, 259 | .pin_d5 = CONFIG_D5, 260 | .pin_d4 = CONFIG_D4, 261 | .pin_d3 = CONFIG_D3, 262 | .pin_d2 = CONFIG_D2, 263 | .pin_d1 = CONFIG_D1, 264 | .pin_d0 = CONFIG_D0, 265 | .pin_vsync = CONFIG_VSYNC, 266 | .pin_href = CONFIG_HREF, 267 | .pin_pclk = CONFIG_PCLK, 268 | 269 | //XCLK 20MHz or 10MHz 270 | .xclk_freq_hz = CONFIG_XCLK_FREQ, 271 | .ledc_timer = LEDC_TIMER_0, 272 | .ledc_channel = LEDC_CHANNEL_0, 273 | 274 | .pixel_format = PIXFORMAT_GRAYSCALE, //YUV422,GRAYSCALE,RGB565,JPEG 275 | .frame_size = FRAMESIZE_QQVGA, //QQVGA-UXGA Do not use sizes above QVGA when not JPEG 276 | 277 | .jpeg_quality = 12, //0-63 lower number means higher quality 278 | .fb_count = 2 //if more than one, i2s runs in continuous mode. Use only with JPEG 279 | }; 280 | 281 | 282 | //For a given center of movement (indicated by x and y) and a blink status (indicated by p), this 283 | //returns the index of the most applicable raw image. 284 | int eye_find(int x, int y, int p) { 285 | //quick transform qqvga coords -> eye pupil coords. 286 | x=(x*(EYE_XMAX-EYE_XMIN))/CAMH+EYE_XMIN; 287 | y=(y*(EYE_YMAX-EYE_YMIN))/CAMW+EYE_YMIN; 288 | //printf("Eye %d %d\n", x, y); 289 | //find image with given status with pupil closest to x,y 290 | int mindist=999999999; 291 | int minno=0; 292 | //Loop over all images, find best. 293 | for (int t=0; images[t].pc>=0; t++) { 294 | if (images[t].pc==p) { 295 | int dx=images[t].px-x; 296 | int dy=images[t].py-y; 297 | int d=dx*dx+dy*dy; 298 | if (d0 && *v<32767-w) *v+=w; 311 | if (w<0 && *v>-32767-w) *v+=w; 312 | } 313 | 314 | /* 315 | This function calculates a mask to filter out the fact that the camera can see some LEDs. It takes 316 | picures while the LEDs around the camera are on and pictures while LEDs away from the camera are on, 317 | and substracts the two in order to generate a mask that allows us to filter out these pixels. In the 318 | resulting mask, 0 means the pixel is normal, 255 means it's entirely obscured by an LED. 319 | */ 320 | void calc_mask(uint8_t *mask) { 321 | camera_fb_t *pic; 322 | int iter=32; 323 | int intens=192; 324 | //Allocate work buffers 325 | int16_t *w=calloc(CAMW, CAMH*2); 326 | int16_t *w2=calloc(CAMW, CAMH*2); 327 | 328 | //Turn on LEDs around camera 329 | for (int y=0; y<16; y++) { 330 | for (int x=0; x<16; x++) { 331 | int c=0; 332 | if (x>=6 && x<10 && y>=4 && y<8) c=intens; 333 | display_setpixel(15-y, x, c); 334 | } 335 | } 336 | display_flip(); 337 | vTaskDelay(200 / portTICK_RATE_MS); 338 | //throw away some frames as they're potentially made before the LEDs turned on 339 | esp_camera_fb_return(esp_camera_fb_get()); 340 | esp_camera_fb_return(esp_camera_fb_get()); 341 | esp_camera_fb_return(esp_camera_fb_get()); 342 | printf("Mask: sample with leds on\n"); 343 | //Take and average pictures 344 | for (int i=0; ibuf, CAMW*CAMH, NULL); 349 | printf("\n\n"); 350 | } 351 | #endif 352 | for (int y=0; ybuf[y]; 354 | } 355 | esp_camera_fb_return(pic); 356 | } 357 | printf("Sampled.\n"); 358 | 359 | //Turn on two lines of LEDs away from the camera 360 | for (int y=0; y<16; y++) { 361 | for (int x=0; x<16; x++) { 362 | int c=0; 363 | if (x==3 || x==12) c=intens; 364 | display_setpixel(15-y, x, c); 365 | } 366 | } 367 | display_flip(); 368 | vTaskDelay(200 / portTICK_RATE_MS); 369 | //throw away some frames as they're potentially made before the LEDs turned on 370 | esp_camera_fb_return(esp_camera_fb_get()); 371 | esp_camera_fb_return(esp_camera_fb_get()); 372 | esp_camera_fb_return(esp_camera_fb_get()); 373 | printf("Mask: sample with leds off\n"); 374 | //Sample a few pictures 375 | for (int i=0; ibuf, CAMW*CAMH, NULL); 380 | printf("\n\n"); 381 | } 382 | #endif 383 | for (int y=0; ybuf[y]; 385 | } 386 | esp_camera_fb_return(pic); 387 | } 388 | 389 | 390 | int avg=0; 391 | 392 | //We 393 | for (int smooth_iter=0; smooth_iter<12; smooth_iter++) { 394 | //First of all, calculate the average pixel value. 395 | avg=0; 396 | for (int y=0; yavg*2) d=64*iter; 411 | //if (w2[y*CAMW+x]253*iter) { 440 | mask[y]=255; 441 | } else { 442 | mask[y]=w[y]/iter; 443 | } 444 | } 445 | #if DUMP_PIC_SERIAL 446 | base64_dump(mask, CAMW*CAMH, NULL); 447 | printf("\n\n"); 448 | #endif 449 | free(w); 450 | free(w2); 451 | } 452 | 453 | int cam_gain, cam_exposure; 454 | 455 | //Very simple automatic gain and exposure adjustment. 456 | //Takes a frame, counts the 'hot' and 'dark' pixels and tweaks exposure and gain to make 457 | //sure both are more-or-less in balance. incr indicates how fast we should modify the 458 | //values - higher means larger steps to compensate. 459 | //Note that the added value here is that it can be passed a mask that masks out all the 460 | //pixels that are looking directly at a LED - by doing that, the exposure won't fly 461 | //up and down because those LEDs happen to be on or off. 462 | void adjust_exposure(sensor_t *sensor, uint8_t *mask, uint8_t *fb, int incr) { 463 | int under=0; 464 | int over=0; 465 | //Count under- and over-exposed pixels 466 | for (int y=0; y251) over++; 470 | } 471 | } 472 | //Adjust exposure based on that. 473 | if (under>20) cam_exposure+=incr; 474 | if (over>20) cam_exposure-=incr; 475 | //If exposure is too high or low, tweak gain instead. 476 | if (cam_exposure>1000) { 477 | cam_exposure=900; 478 | cam_gain++; 479 | } 480 | if (cam_exposure<10) { 481 | cam_exposure=100; 482 | cam_gain--; 483 | } 484 | //printf("Under %d over %d Exp %d gain %d\n", under, over, cam_exposure, cam_gain); 485 | sensor->set_agc_gain(sensor, cam_gain); //0-30 486 | sensor->set_aec_value(sensor, cam_exposure); //0-1200 487 | } 488 | 489 | //This is used to quickly calculate the initial exposure after the camera is turned 490 | //on. It takes a bunch of pics and uses them to quickly (depending on chg) tune in 491 | //to what should be more-or-less the correct values. 492 | void calc_initial_exposure(sensor_t *sensor, uint8_t *mask, int iter, int chg) { 493 | camera_fb_t *pic; 494 | //Turn off all LEDs 495 | for (int y=0; y<16; y++) { 496 | for (int x=0; x<16; x++) { 497 | display_setpixel(15-y, x, 0); 498 | } 499 | } 500 | display_flip(); 501 | 502 | for (int i=0; ibuf, chg); 505 | esp_camera_fb_return(pic); 506 | } 507 | } 508 | 509 | 510 | //The heart of the code. It's kinda spagetti-ey, sorry for that. 511 | void app_main(void) { 512 | esp_camera_init(&camera_config); 513 | printf("Camera inited.\n"); 514 | display_init(); 515 | printf("Display inited.\n"); 516 | sensor_t *sensor=esp_camera_sensor_get(); 517 | sensor->set_gain_ctrl(sensor, 0); 518 | sensor->set_exposure_ctrl(sensor, 0); 519 | cam_gain=1; 520 | cam_exposure=500; 521 | 522 | //Alocate images for motion detecting 523 | uint8_t *prev_img, *diff_img, *mask; 524 | prev_img=calloc(CAMW, CAMH); 525 | diff_img=calloc(CAMW, CAMH); 526 | mask=calloc(CAMW, CAMH); 527 | 528 | //buttons 529 | gpio_config_t io_conf={ 530 | .intr_type=GPIO_INTR_DISABLE, 531 | .mode=GPIO_MODE_INPUT, 532 | .pull_up_en=1, 533 | .pin_bit_mask=(1<<2)|(1<<4) 534 | }; 535 | gpio_config(&io_conf); 536 | 537 | //Display mode: you can press a button to go into a different mode to 538 | //see what the motion sensing algo does 539 | int mode=2; 540 | 541 | camera_fb_t *pic; 542 | 543 | printf("Calculating mask\n"); 544 | calc_mask(mask); 545 | 546 | //large steps 547 | calc_initial_exposure(sensor, mask, 10, 30); 548 | //fine tune 549 | calc_initial_exposure(sensor, mask, 10, 5); 550 | 551 | //Holds the time until the next blink 552 | int blink_timer=10; 553 | //Amount of frames the motion detection code should ignore after a blink or an eye movement 554 | int blink_ignore_cam=11; 555 | 556 | //starting positions of eye 557 | float eye_x=100, eye_y=100; 558 | int eye_idx=0, eye_idx_old=0; 559 | while(1) { 560 | //Handle button presses 561 | if (gpio_get_level(GPIO_NUM_2)==0) { 562 | mode++; 563 | printf("Mode %d\n", mode); 564 | if (mode==4) mode=0; 565 | while(gpio_get_level(GPIO_NUM_2)==0) { 566 | vTaskDelay(100 / portTICK_RATE_MS); 567 | } 568 | } 569 | 570 | pic = esp_camera_fb_get(); //note: gets 160x120 picture 571 | if (pic==NULL) { 572 | printf("Huh, no frame?\n"); 573 | continue; 574 | } 575 | // printf("Got frame\n"); 576 | 577 | //Remove masked-out pixels 578 | for (int y=0; ybuf[y*CAMW+x] - (int)mask[y*CAMW+x]; 581 | if (d<0) { 582 | d=0; 583 | } 584 | pic->buf[y*CAMW+x]=d; 585 | } 586 | } 587 | 588 | //Calculate difference between this and prev frame 589 | int avgdif; 590 | avgdif=0; 591 | for (int y=0; ybuf[y*CAMW+x]; 594 | d=(d*d)/32; //square of the difference 595 | if (d>255) d=255; //clip 596 | diff_img[y*CAMW+x]=d; 597 | avgdif+=d; 598 | } 599 | } 600 | //Calculate average squared difference. This is an indicator of how much actually moved 601 | //in the scene. 602 | avgdif=avgdif/(CAMH*CAMW); 603 | //printf("avgdif %d\n", avgdif); 604 | 605 | //figure out center of movement 606 | //We do that by taking the average of all coordinates weighted by the difference. We ignore 607 | //pixels that changed less than the average, to keep out noise. 608 | int cx, cy, cn; 609 | cx=0; cy=0; cn=0; 610 | for (int y=0; yavgdif+2) { 614 | //note again: x and y are exchanged because the camera is rotated 615 | cx+=y*d; 616 | cy+=x*d; 617 | cn+=d; 618 | } 619 | } 620 | } 621 | 622 | if (cn) { //don't divide by zero 623 | cx=cx/cn; 624 | cy=cy/cn; 625 | } 626 | //Save current image for next loop. 627 | memcpy(prev_img, pic->buf, CAMW*CAMH); 628 | 629 | //Use cx/cy/cn to find new eye pos. 630 | //Note we can use cn as a movement amount indicator. 631 | if (cn>5000 && blink_ignore_cam==0) { 632 | float th=(cn/200000.0); 633 | if (th>1) th=1; 634 | eye_x=eye_x*(1.0-th)+cx*th; 635 | eye_y=eye_y*(1.0-th)+cy*th; 636 | } 637 | if (blink_ignore_cam!=0) blink_ignore_cam--; 638 | if (blink_timer==3) blink_ignore_cam=5; 639 | if (blink_timer==0) blink_timer=50+(rand()%30); 640 | blink_timer--; 641 | 642 | eye_idx_old=eye_idx; 643 | eye_idx=eye_find(eye_x, eye_y, blink_timer==1?2:blink_timer<3?1:0); 644 | //Ignore a frame or two if the eye image changed, so we don't trigger off reflections. 645 | if (eye_idx_old!=eye_idx) blink_ignore_cam=2; 646 | // printf("cx %d cy %d cn %d ei %d\n", cx, cy, cn, eye_idx); 647 | 648 | //Depending on mode, we draw something different. 649 | const uint8_t *drawfb=diff_img; 650 | if (mode==0) drawfb=pic->buf; //Mode 0: camera view 651 | if (mode==1) drawfb=diff_img; //Mode 1: motion detection view 652 | if (mode==2) drawfb=&eye_raw_image_data[eye_idx*256]; //Mode 2: main eye view 653 | if (mode==3) drawfb=mask; //Mode 3: inspect mask 654 | //Draw selected image on LEDs 655 | for (int x=0; x<16; x++) { 656 | for (int y=0; y<16; y++) { 657 | if (mode==2) { 658 | display_setpixel(15-y, x, *drawfb++); 659 | } else { 660 | //Scale image 661 | int sc=0; 662 | for (int sy=0; sy<7; sy++) { 663 | for (int sx=0; sx<10; sx++) { 664 | sc+=drawfb[(y*7+sy)*160+(x*10+sx)]; 665 | } 666 | } 667 | //note: camera is 45 degrees rotated wrt display 668 | display_setpixel(15-y, x, sc/70); 669 | } 670 | } 671 | } 672 | 673 | //On the debug images, show the center of motion as well as the current eye position. 674 | if (mode!=2) display_setpixel(15-cx/7, cy/10, 128); 675 | if (mode!=2) display_setpixel(15-eye_x/7, eye_y/10, 64); 676 | //Show frame 677 | display_flip(); 678 | adjust_exposure(sensor, mask, pic->buf, 1); 679 | esp_camera_fb_return(pic); 680 | } 681 | } 682 | 683 | -------------------------------------------------------------------------------- /sdkconfig: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file. DO NOT EDIT. 3 | # Espressif IoT Development Framework (ESP-IDF) Project Configuration 4 | # 5 | CONFIG_IDF_TARGET_ESP32=y 6 | CONFIG_IDF_TARGET="esp32" 7 | CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000 8 | 9 | # 10 | # SDK tool configuration 11 | # 12 | CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-" 13 | CONFIG_SDK_PYTHON="python" 14 | CONFIG_SDK_MAKE_WARN_UNDEFINED_VARIABLES=y 15 | CONFIG_APP_COMPILE_TIME_DATE=y 16 | # CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set 17 | # CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set 18 | # CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set 19 | # CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set 20 | # CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set 21 | CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y 22 | # CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set 23 | # CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set 24 | CONFIG_BOOTLOADER_LOG_LEVEL=3 25 | CONFIG_BOOTLOADER_SPI_WP_PIN=7 26 | CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y 27 | # CONFIG_BOOTLOADER_FACTORY_RESET is not set 28 | # CONFIG_BOOTLOADER_APP_TEST is not set 29 | CONFIG_BOOTLOADER_WDT_ENABLE=y 30 | # CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set 31 | CONFIG_BOOTLOADER_WDT_TIME_MS=9000 32 | # CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set 33 | # CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set 34 | # CONFIG_SECURE_BOOT_ENABLED is not set 35 | # CONFIG_SECURE_FLASH_ENC_ENABLED is not set 36 | CONFIG_ESPTOOLPY_PORT="/dev/ttyUSB0" 37 | CONFIG_ESPTOOLPY_BAUD_115200B=y 38 | # CONFIG_ESPTOOLPY_BAUD_230400B is not set 39 | # CONFIG_ESPTOOLPY_BAUD_921600B is not set 40 | # CONFIG_ESPTOOLPY_BAUD_2MB is not set 41 | # CONFIG_ESPTOOLPY_BAUD_OTHER is not set 42 | CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 43 | CONFIG_ESPTOOLPY_BAUD=115200 44 | CONFIG_ESPTOOLPY_COMPRESSED=y 45 | CONFIG_ESPTOOLPY_FLASHMODE_QIO=y 46 | # CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set 47 | # CONFIG_ESPTOOLPY_FLASHMODE_DIO is not set 48 | # CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set 49 | CONFIG_ESPTOOLPY_FLASHMODE="dio" 50 | CONFIG_ESPTOOLPY_FLASHFREQ_80M=y 51 | # CONFIG_ESPTOOLPY_FLASHFREQ_40M is not set 52 | # CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set 53 | # CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set 54 | CONFIG_ESPTOOLPY_FLASHFREQ="80m" 55 | # CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set 56 | # CONFIG_ESPTOOLPY_FLASHSIZE_2MB is not set 57 | CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y 58 | # CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set 59 | # CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set 60 | CONFIG_ESPTOOLPY_FLASHSIZE="4MB" 61 | CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y 62 | CONFIG_ESPTOOLPY_BEFORE_RESET=y 63 | # CONFIG_ESPTOOLPY_BEFORE_NORESET is not set 64 | CONFIG_ESPTOOLPY_BEFORE="default_reset" 65 | CONFIG_ESPTOOLPY_AFTER_RESET=y 66 | # CONFIG_ESPTOOLPY_AFTER_NORESET is not set 67 | CONFIG_ESPTOOLPY_AFTER="hard_reset" 68 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set 69 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set 70 | CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y 71 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set 72 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set 73 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set 74 | # CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set 75 | CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200 76 | CONFIG_ESPTOOLPY_MONITOR_BAUD=115200 77 | CONFIG_XCLK_FREQ=20000000 78 | CONFIG_D0=5 79 | CONFIG_D1=18 80 | CONFIG_D2=19 81 | CONFIG_D3=21 82 | CONFIG_D4=36 83 | CONFIG_D5=39 84 | CONFIG_D6=34 85 | CONFIG_D7=35 86 | CONFIG_XCLK=0 87 | CONFIG_PCLK=22 88 | CONFIG_VSYNC=25 89 | CONFIG_HREF=23 90 | CONFIG_SDA=26 91 | CONFIG_SCL=27 92 | CONFIG_RESET=32 93 | CONFIG_PARTITION_TABLE_SINGLE_APP=y 94 | # CONFIG_PARTITION_TABLE_TWO_OTA is not set 95 | # CONFIG_PARTITION_TABLE_CUSTOM is not set 96 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" 97 | CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" 98 | CONFIG_PARTITION_TABLE_OFFSET=0x8000 99 | CONFIG_PARTITION_TABLE_MD5=y 100 | CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG=y 101 | # CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set 102 | CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y 103 | # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set 104 | # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set 105 | # CONFIG_COMPILER_CXX_EXCEPTIONS is not set 106 | CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y 107 | # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set 108 | # CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set 109 | # CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set 110 | # CONFIG_COMPILER_STACK_CHECK is not set 111 | # CONFIG_COMPILER_WARN_WRITE_STRINGS is not set 112 | # CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set 113 | # CONFIG_ESP32_APPTRACE_DEST_TRAX is not set 114 | CONFIG_ESP32_APPTRACE_DEST_NONE=y 115 | # CONFIG_ESP32_APPTRACE_ENABLE is not set 116 | CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y 117 | # CONFIG_BT_ENABLED is not set 118 | CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0 119 | CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0 120 | CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0 121 | CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0 122 | CONFIG_BTDM_CTRL_PINNED_TO_CORE=0 123 | CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1 124 | CONFIG_BT_RESERVE_DRAM=0 125 | # CONFIG_BLE_MESH is not set 126 | # CONFIG_ADC_FORCE_XPD_FSM is not set 127 | CONFIG_ADC_DISABLE_DAC=y 128 | # CONFIG_SPI_MASTER_IN_IRAM is not set 129 | CONFIG_SPI_MASTER_ISR_IN_IRAM=y 130 | # CONFIG_SPI_SLAVE_IN_IRAM is not set 131 | CONFIG_SPI_SLAVE_ISR_IN_IRAM=y 132 | # CONFIG_EFUSE_CUSTOM_TABLE is not set 133 | # CONFIG_EFUSE_VIRTUAL is not set 134 | # CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set 135 | CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y 136 | # CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set 137 | CONFIG_EFUSE_MAX_BLK_LEN=192 138 | # CONFIG_ESP_TLS_SERVER is not set 139 | CONFIG_ESP32_REV_MIN_0=y 140 | # CONFIG_ESP32_REV_MIN_1 is not set 141 | # CONFIG_ESP32_REV_MIN_2 is not set 142 | # CONFIG_ESP32_REV_MIN_3 is not set 143 | CONFIG_ESP32_REV_MIN=0 144 | CONFIG_ESP32_DPORT_WORKAROUND=y 145 | # CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set 146 | # CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set 147 | CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y 148 | CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 149 | # CONFIG_ESP32_SPIRAM_SUPPORT is not set 150 | # CONFIG_ESP32_MEMMAP_TRACEMEM is not set 151 | # CONFIG_ESP32_MEMMAP_TRACEMEM_TWOBANKS is not set 152 | # CONFIG_ESP32_TRAX is not set 153 | CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0 154 | # CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set 155 | CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y 156 | CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4 157 | # CONFIG_ESP32_ULP_COPROC_ENABLED is not set 158 | CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0 159 | # CONFIG_ESP32_PANIC_PRINT_HALT is not set 160 | CONFIG_ESP32_PANIC_PRINT_REBOOT=y 161 | # CONFIG_ESP32_PANIC_SILENT_REBOOT is not set 162 | # CONFIG_ESP32_PANIC_GDBSTUB is not set 163 | CONFIG_ESP32_DEBUG_OCDAWARE=y 164 | CONFIG_ESP32_DEBUG_STUBS_ENABLE=y 165 | CONFIG_ESP32_BROWNOUT_DET=y 166 | CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y 167 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set 168 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set 169 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set 170 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set 171 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set 172 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set 173 | # CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set 174 | CONFIG_ESP32_BROWNOUT_DET_LVL=0 175 | CONFIG_ESP32_REDUCE_PHY_TX_POWER=y 176 | CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y 177 | # CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set 178 | # CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set 179 | # CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set 180 | CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y 181 | # CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set 182 | # CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set 183 | # CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set 184 | CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 185 | CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 186 | CONFIG_ESP32_XTAL_FREQ_40=y 187 | # CONFIG_ESP32_XTAL_FREQ_26 is not set 188 | # CONFIG_ESP32_XTAL_FREQ_AUTO is not set 189 | CONFIG_ESP32_XTAL_FREQ=40 190 | # CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set 191 | # CONFIG_ESP32_NO_BLOBS is not set 192 | # CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set 193 | # CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set 194 | CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5 195 | # CONFIG_PM_ENABLE is not set 196 | CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y 197 | CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y 198 | CONFIG_ADC_CAL_LUT_ENABLE=y 199 | # CONFIG_ESP_TIMER_PROFILING is not set 200 | CONFIG_ESP_ERR_TO_NAME_LOOKUP=y 201 | CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32 202 | CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304 203 | CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584 204 | CONFIG_ESP_IPC_TASK_STACK_SIZE=1024 205 | CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584 206 | CONFIG_ESP_CONSOLE_UART_DEFAULT=y 207 | # CONFIG_ESP_CONSOLE_UART_CUSTOM is not set 208 | # CONFIG_ESP_CONSOLE_UART_NONE is not set 209 | CONFIG_ESP_CONSOLE_UART_NUM=0 210 | CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200 211 | CONFIG_ESP_INT_WDT=y 212 | CONFIG_ESP_INT_WDT_TIMEOUT_MS=300 213 | CONFIG_ESP_INT_WDT_CHECK_CPU1=y 214 | CONFIG_ESP_TASK_WDT=y 215 | # CONFIG_ESP_TASK_WDT_PANIC is not set 216 | CONFIG_ESP_TASK_WDT_TIMEOUT_S=5 217 | CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y 218 | CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y 219 | CONFIG_ETH_USE_ESP32_EMAC=y 220 | CONFIG_ETH_PHY_INTERFACE_RMII=y 221 | # CONFIG_ETH_PHY_INTERFACE_MII is not set 222 | CONFIG_ETH_RMII_CLK_INPUT=y 223 | # CONFIG_ETH_RMII_CLK_OUTPUT is not set 224 | CONFIG_ETH_RMII_CLK_IN_GPIO=0 225 | CONFIG_ETH_DMA_BUFFER_SIZE=512 226 | CONFIG_ETH_DMA_RX_BUFFER_NUM=10 227 | CONFIG_ETH_DMA_TX_BUFFER_NUM=10 228 | CONFIG_ETH_USE_SPI_ETHERNET=y 229 | # CONFIG_ETH_SPI_ETHERNET_DM9051 is not set 230 | # CONFIG_ESP_EVENT_LOOP_PROFILING is not set 231 | CONFIG_ESP_EVENT_POST_FROM_ISR=y 232 | CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y 233 | CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y 234 | # CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set 235 | CONFIG_HTTPD_MAX_REQ_HDR_LEN=512 236 | CONFIG_HTTPD_MAX_URI_LEN=512 237 | CONFIG_HTTPD_ERR_RESP_NO_DELAY=y 238 | CONFIG_HTTPD_PURGE_BUF_LEN=32 239 | # CONFIG_HTTPD_LOG_PURGE_DATA is not set 240 | # CONFIG_OTA_ALLOW_HTTP is not set 241 | # CONFIG_ESP_HTTPS_SERVER_ENABLE is not set 242 | CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 243 | CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 244 | CONFIG_ESP32_WIFI_STATIC_TX_BUFFER=y 245 | # CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER is not set 246 | CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=0 247 | CONFIG_ESP32_WIFI_STATIC_TX_BUFFER_NUM=16 248 | # CONFIG_ESP32_WIFI_CSI_ENABLED is not set 249 | CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y 250 | CONFIG_ESP32_WIFI_TX_BA_WIN=6 251 | CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y 252 | CONFIG_ESP32_WIFI_RX_BA_WIN=6 253 | CONFIG_ESP32_WIFI_NVS_ENABLED=y 254 | CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y 255 | # CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set 256 | CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752 257 | CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32 258 | # CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set 259 | CONFIG_ESP32_WIFI_IRAM_OPT=y 260 | CONFIG_ESP32_WIFI_RX_IRAM_OPT=y 261 | CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y 262 | # CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set 263 | CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 264 | CONFIG_ESP32_PHY_MAX_TX_POWER=20 265 | # CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set 266 | # CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set 267 | CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y 268 | # CONFIG_ESP32_ENABLE_COREDUMP is not set 269 | # CONFIG_FATFS_CODEPAGE_DYNAMIC is not set 270 | CONFIG_FATFS_CODEPAGE_437=y 271 | # CONFIG_FATFS_CODEPAGE_720 is not set 272 | # CONFIG_FATFS_CODEPAGE_737 is not set 273 | # CONFIG_FATFS_CODEPAGE_771 is not set 274 | # CONFIG_FATFS_CODEPAGE_775 is not set 275 | # CONFIG_FATFS_CODEPAGE_850 is not set 276 | # CONFIG_FATFS_CODEPAGE_852 is not set 277 | # CONFIG_FATFS_CODEPAGE_855 is not set 278 | # CONFIG_FATFS_CODEPAGE_857 is not set 279 | # CONFIG_FATFS_CODEPAGE_860 is not set 280 | # CONFIG_FATFS_CODEPAGE_861 is not set 281 | # CONFIG_FATFS_CODEPAGE_862 is not set 282 | # CONFIG_FATFS_CODEPAGE_863 is not set 283 | # CONFIG_FATFS_CODEPAGE_864 is not set 284 | # CONFIG_FATFS_CODEPAGE_865 is not set 285 | # CONFIG_FATFS_CODEPAGE_866 is not set 286 | # CONFIG_FATFS_CODEPAGE_869 is not set 287 | # CONFIG_FATFS_CODEPAGE_932 is not set 288 | # CONFIG_FATFS_CODEPAGE_936 is not set 289 | # CONFIG_FATFS_CODEPAGE_949 is not set 290 | # CONFIG_FATFS_CODEPAGE_950 is not set 291 | CONFIG_FATFS_CODEPAGE=437 292 | CONFIG_FATFS_LFN_NONE=y 293 | # CONFIG_FATFS_LFN_HEAP is not set 294 | # CONFIG_FATFS_LFN_STACK is not set 295 | CONFIG_FATFS_FS_LOCK=0 296 | CONFIG_FATFS_TIMEOUT_MS=10000 297 | CONFIG_FATFS_PER_FILE_CACHE=y 298 | CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150 299 | CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200 300 | CONFIG_FMB_QUEUE_LENGTH=20 301 | CONFIG_FMB_SERIAL_TASK_STACK_SIZE=2048 302 | CONFIG_FMB_SERIAL_BUF_SIZE=256 303 | CONFIG_FMB_SERIAL_TASK_PRIO=10 304 | # CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT is not set 305 | CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20 306 | CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 307 | CONFIG_FMB_CONTROLLER_STACK_SIZE=4096 308 | CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20 309 | CONFIG_FMB_TIMER_PORT_ENABLED=y 310 | CONFIG_FMB_TIMER_GROUP=0 311 | CONFIG_FMB_TIMER_INDEX=0 312 | # CONFIG_FREERTOS_UNICORE is not set 313 | CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF 314 | CONFIG_FREERTOS_CORETIMER_0=y 315 | # CONFIG_FREERTOS_CORETIMER_1 is not set 316 | CONFIG_FREERTOS_HZ=100 317 | CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y 318 | # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set 319 | # CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set 320 | CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y 321 | # CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set 322 | CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y 323 | CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 324 | CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y 325 | # CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set 326 | # CONFIG_FREERTOS_ASSERT_DISABLE is not set 327 | CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 328 | CONFIG_FREERTOS_ISR_STACKSIZE=1536 329 | # CONFIG_FREERTOS_LEGACY_HOOKS is not set 330 | CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 331 | CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y 332 | # CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set 333 | CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1 334 | CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048 335 | CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10 336 | CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 337 | # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set 338 | # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set 339 | # CONFIG_FREERTOS_DEBUG_INTERNALS is not set 340 | CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y 341 | CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y 342 | # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set 343 | CONFIG_HEAP_POISONING_DISABLED=y 344 | # CONFIG_HEAP_POISONING_LIGHT is not set 345 | # CONFIG_HEAP_POISONING_COMPREHENSIVE is not set 346 | CONFIG_HEAP_TRACING_OFF=y 347 | # CONFIG_HEAP_TRACING_STANDALONE is not set 348 | # CONFIG_HEAP_TRACING_TOHOST is not set 349 | # CONFIG_HEAP_TRACING is not set 350 | # CONFIG_LOG_DEFAULT_LEVEL_NONE is not set 351 | # CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set 352 | # CONFIG_LOG_DEFAULT_LEVEL_WARN is not set 353 | CONFIG_LOG_DEFAULT_LEVEL_INFO=y 354 | # CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set 355 | # CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set 356 | CONFIG_LOG_DEFAULT_LEVEL=3 357 | CONFIG_LOG_COLORS=y 358 | CONFIG_LWIP_LOCAL_HOSTNAME="espressif" 359 | # CONFIG_LWIP_L2_TO_L3_COPY is not set 360 | # CONFIG_LWIP_IRAM_OPTIMIZATION is not set 361 | CONFIG_LWIP_TIMERS_ONDEMAND=y 362 | CONFIG_LWIP_MAX_SOCKETS=10 363 | # CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set 364 | CONFIG_LWIP_SO_REUSE=y 365 | CONFIG_LWIP_SO_REUSE_RXTOALL=y 366 | # CONFIG_LWIP_SO_RCVBUF is not set 367 | CONFIG_LWIP_IP_FRAG=y 368 | # CONFIG_LWIP_IP_REASSEMBLY is not set 369 | # CONFIG_LWIP_STATS is not set 370 | # CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set 371 | CONFIG_LWIP_ESP_GRATUITOUS_ARP=y 372 | CONFIG_LWIP_GARP_TMR_INTERVAL=60 373 | CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32 374 | CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y 375 | # CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set 376 | CONFIG_LWIP_DHCPS_LEASE_UNIT=60 377 | CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 378 | # CONFIG_LWIP_AUTOIP is not set 379 | CONFIG_LWIP_NETIF_LOOPBACK=y 380 | CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 381 | CONFIG_LWIP_MAX_ACTIVE_TCP=16 382 | CONFIG_LWIP_MAX_LISTENING_TCP=16 383 | CONFIG_LWIP_TCP_MAXRTX=12 384 | CONFIG_LWIP_TCP_SYNMAXRTX=6 385 | CONFIG_LWIP_TCP_MSS=1436 386 | CONFIG_LWIP_TCP_MSL=60000 387 | CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744 388 | CONFIG_LWIP_TCP_WND_DEFAULT=5744 389 | CONFIG_LWIP_TCP_RECVMBOX_SIZE=6 390 | CONFIG_LWIP_TCP_QUEUE_OOSEQ=y 391 | # CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set 392 | CONFIG_LWIP_TCP_OVERSIZE_MSS=y 393 | # CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set 394 | # CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set 395 | CONFIG_LWIP_MAX_UDP_PCBS=16 396 | CONFIG_LWIP_UDP_RECVMBOX_SIZE=6 397 | CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072 398 | CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y 399 | # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set 400 | # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set 401 | CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF 402 | # CONFIG_LWIP_PPP_SUPPORT is not set 403 | # CONFIG_LWIP_MULTICAST_PING is not set 404 | # CONFIG_LWIP_BROADCAST_PING is not set 405 | CONFIG_LWIP_MAX_RAW_PCBS=16 406 | CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 407 | CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000 408 | CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y 409 | # CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set 410 | # CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set 411 | CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y 412 | CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384 413 | CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096 414 | # CONFIG_MBEDTLS_DEBUG is not set 415 | # CONFIG_MBEDTLS_ECP_RESTARTABLE is not set 416 | # CONFIG_MBEDTLS_CMAC_C is not set 417 | CONFIG_MBEDTLS_HARDWARE_AES=y 418 | CONFIG_MBEDTLS_HARDWARE_MPI=y 419 | # CONFIG_MBEDTLS_MPI_USE_INTERRUPT is not set 420 | CONFIG_MBEDTLS_HARDWARE_SHA=y 421 | CONFIG_MBEDTLS_HAVE_TIME=y 422 | # CONFIG_MBEDTLS_HAVE_TIME_DATE is not set 423 | CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y 424 | # CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set 425 | # CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set 426 | # CONFIG_MBEDTLS_TLS_DISABLED is not set 427 | CONFIG_MBEDTLS_TLS_SERVER=y 428 | CONFIG_MBEDTLS_TLS_CLIENT=y 429 | CONFIG_MBEDTLS_TLS_ENABLED=y 430 | CONFIG_MBEDTLS_PSK_MODES=y 431 | CONFIG_MBEDTLS_KEY_EXCHANGE_PSK=y 432 | CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_PSK=y 433 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_PSK=y 434 | CONFIG_MBEDTLS_KEY_EXCHANGE_RSA_PSK=y 435 | CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y 436 | CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y 437 | CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y 438 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y 439 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y 440 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y 441 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y 442 | CONFIG_MBEDTLS_SSL_RENEGOTIATION=y 443 | # CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set 444 | CONFIG_MBEDTLS_SSL_PROTO_TLS1=y 445 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y 446 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y 447 | CONFIG_MBEDTLS_SSL_PROTO_DTLS=y 448 | CONFIG_MBEDTLS_SSL_ALPN=y 449 | CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y 450 | CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y 451 | CONFIG_MBEDTLS_AES_C=y 452 | # CONFIG_MBEDTLS_CAMELLIA_C is not set 453 | # CONFIG_MBEDTLS_DES_C is not set 454 | CONFIG_MBEDTLS_RC4_DISABLED=y 455 | # CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set 456 | # CONFIG_MBEDTLS_RC4_ENABLED is not set 457 | # CONFIG_MBEDTLS_BLOWFISH_C is not set 458 | # CONFIG_MBEDTLS_XTEA_C is not set 459 | CONFIG_MBEDTLS_CCM_C=y 460 | CONFIG_MBEDTLS_GCM_C=y 461 | # CONFIG_MBEDTLS_RIPEMD160_C is not set 462 | CONFIG_MBEDTLS_PEM_PARSE_C=y 463 | CONFIG_MBEDTLS_PEM_WRITE_C=y 464 | CONFIG_MBEDTLS_X509_CRL_PARSE_C=y 465 | CONFIG_MBEDTLS_X509_CSR_PARSE_C=y 466 | CONFIG_MBEDTLS_ECP_C=y 467 | CONFIG_MBEDTLS_ECDH_C=y 468 | CONFIG_MBEDTLS_ECDSA_C=y 469 | CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y 470 | CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y 471 | CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y 472 | CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y 473 | CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y 474 | CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y 475 | CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y 476 | CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y 477 | CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y 478 | CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y 479 | CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y 480 | CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y 481 | CONFIG_MBEDTLS_ECP_NIST_OPTIM=y 482 | CONFIG_MDNS_MAX_SERVICES=10 483 | CONFIG_MQTT_PROTOCOL_311=y 484 | CONFIG_MQTT_TRANSPORT_SSL=y 485 | CONFIG_MQTT_TRANSPORT_WEBSOCKET=y 486 | CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y 487 | # CONFIG_MQTT_USE_CUSTOM_CONFIG is not set 488 | # CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set 489 | # CONFIG_MQTT_CUSTOM_OUTBOX is not set 490 | CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y 491 | # CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set 492 | # CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set 493 | # CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set 494 | # CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set 495 | CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y 496 | # CONFIG_NEWLIB_NANO_FORMAT is not set 497 | # CONFIG_OPENSSL_DEBUG is not set 498 | # CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set 499 | CONFIG_OPENSSL_ASSERT_EXIT=y 500 | CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5 501 | CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 502 | CONFIG_PTHREAD_STACK_MIN=768 503 | CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y 504 | # CONFIG_PTHREAD_DEFAULT_CORE_0 is not set 505 | # CONFIG_PTHREAD_DEFAULT_CORE_1 is not set 506 | CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1 507 | CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread" 508 | # CONFIG_SPI_FLASH_VERIFY_WRITE is not set 509 | # CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set 510 | CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y 511 | CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y 512 | # CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set 513 | # CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set 514 | # CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set 515 | CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y 516 | CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y 517 | CONFIG_SPIFFS_MAX_PARTITIONS=3 518 | CONFIG_SPIFFS_CACHE=y 519 | CONFIG_SPIFFS_CACHE_WR=y 520 | # CONFIG_SPIFFS_CACHE_STATS is not set 521 | CONFIG_SPIFFS_PAGE_CHECK=y 522 | CONFIG_SPIFFS_GC_MAX_RUNS=10 523 | # CONFIG_SPIFFS_GC_STATS is not set 524 | CONFIG_SPIFFS_PAGE_SIZE=256 525 | CONFIG_SPIFFS_OBJ_NAME_LEN=32 526 | CONFIG_SPIFFS_USE_MAGIC=y 527 | CONFIG_SPIFFS_USE_MAGIC_LENGTH=y 528 | CONFIG_SPIFFS_META_LENGTH=4 529 | CONFIG_SPIFFS_USE_MTIME=y 530 | # CONFIG_SPIFFS_DBG is not set 531 | # CONFIG_SPIFFS_API_DBG is not set 532 | # CONFIG_SPIFFS_GC_DBG is not set 533 | # CONFIG_SPIFFS_CACHE_DBG is not set 534 | # CONFIG_SPIFFS_CHECK_DBG is not set 535 | # CONFIG_SPIFFS_TEST_VISUALISATION is not set 536 | CONFIG_NETIF_IP_LOST_TIMER_INTERVAL=120 537 | CONFIG_TCPIP_LWIP=y 538 | CONFIG_UNITY_ENABLE_FLOAT=y 539 | CONFIG_UNITY_ENABLE_DOUBLE=y 540 | # CONFIG_UNITY_ENABLE_COLOR is not set 541 | CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y 542 | # CONFIG_UNITY_ENABLE_FIXTURE is not set 543 | # CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set 544 | CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y 545 | CONFIG_VFS_SUPPORT_TERMIOS=y 546 | CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1 547 | CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128 548 | # CONFIG_WL_SECTOR_SIZE_512 is not set 549 | CONFIG_WL_SECTOR_SIZE_4096=y 550 | CONFIG_WL_SECTOR_SIZE=4096 551 | CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16 552 | CONFIG_WPA_MBEDTLS_CRYPTO=y 553 | # CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set 554 | 555 | # Deprecated options for backward compatibility 556 | CONFIG_TOOLPREFIX="xtensa-esp32-elf-" 557 | CONFIG_PYTHON="python" 558 | CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y 559 | # CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set 560 | # CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set 561 | # CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set 562 | CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y 563 | # CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set 564 | # CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set 565 | CONFIG_LOG_BOOTLOADER_LEVEL=3 566 | # CONFIG_APP_ROLLBACK_ENABLE is not set 567 | # CONFIG_FLASH_ENCRYPTION_ENABLED is not set 568 | CONFIG_FLASHMODE_QIO=y 569 | # CONFIG_FLASHMODE_QOUT is not set 570 | # CONFIG_FLASHMODE_DIO is not set 571 | # CONFIG_FLASHMODE_DOUT is not set 572 | # CONFIG_MONITOR_BAUD_9600B is not set 573 | # CONFIG_MONITOR_BAUD_57600B is not set 574 | CONFIG_MONITOR_BAUD_115200B=y 575 | # CONFIG_MONITOR_BAUD_230400B is not set 576 | # CONFIG_MONITOR_BAUD_921600B is not set 577 | # CONFIG_MONITOR_BAUD_2MB is not set 578 | # CONFIG_MONITOR_BAUD_OTHER is not set 579 | CONFIG_MONITOR_BAUD_OTHER_VAL=115200 580 | CONFIG_MONITOR_BAUD=115200 581 | CONFIG_OPTIMIZATION_LEVEL_DEBUG=y 582 | # CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set 583 | CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y 584 | # CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set 585 | # CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set 586 | # CONFIG_CXX_EXCEPTIONS is not set 587 | CONFIG_STACK_CHECK_NONE=y 588 | # CONFIG_STACK_CHECK_NORM is not set 589 | # CONFIG_STACK_CHECK_STRONG is not set 590 | # CONFIG_STACK_CHECK_ALL is not set 591 | # CONFIG_STACK_CHECK is not set 592 | # CONFIG_WARN_WRITE_STRINGS is not set 593 | # CONFIG_DISABLE_GCC8_WARNINGS is not set 594 | CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0 595 | CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0 596 | CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0 597 | CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 598 | CONFIG_ADC2_DISABLE_DAC=y 599 | # CONFIG_SPIRAM_SUPPORT is not set 600 | # CONFIG_MEMMAP_TRACEMEM is not set 601 | # CONFIG_MEMMAP_TRACEMEM_TWOBANKS is not set 602 | CONFIG_TRACEMEM_RESERVE_DRAM=0x0 603 | # CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set 604 | CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y 605 | CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 606 | # CONFIG_ULP_COPROC_ENABLED is not set 607 | CONFIG_ULP_COPROC_RESERVE_MEM=0 608 | CONFIG_BROWNOUT_DET=y 609 | CONFIG_BROWNOUT_DET_LVL_SEL_0=y 610 | # CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set 611 | # CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set 612 | # CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set 613 | # CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set 614 | # CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set 615 | # CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set 616 | # CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set 617 | CONFIG_BROWNOUT_DET_LVL=0 618 | CONFIG_REDUCE_PHY_TX_POWER=y 619 | CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y 620 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set 621 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set 622 | # CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set 623 | # CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set 624 | # CONFIG_NO_BLOBS is not set 625 | # CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set 626 | CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 627 | CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 628 | CONFIG_MAIN_TASK_STACK_SIZE=3584 629 | CONFIG_IPC_TASK_STACK_SIZE=1024 630 | CONFIG_TIMER_TASK_STACK_SIZE=3584 631 | CONFIG_CONSOLE_UART_DEFAULT=y 632 | # CONFIG_CONSOLE_UART_CUSTOM is not set 633 | # CONFIG_CONSOLE_UART_NONE is not set 634 | CONFIG_CONSOLE_UART_NUM=0 635 | CONFIG_CONSOLE_UART_BAUDRATE=115200 636 | CONFIG_INT_WDT=y 637 | CONFIG_INT_WDT_TIMEOUT_MS=300 638 | CONFIG_INT_WDT_CHECK_CPU1=y 639 | CONFIG_TASK_WDT=y 640 | # CONFIG_TASK_WDT_PANIC is not set 641 | CONFIG_TASK_WDT_TIMEOUT_S=5 642 | CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y 643 | CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y 644 | # CONFIG_EVENT_LOOP_PROFILING is not set 645 | CONFIG_POST_EVENTS_FROM_ISR=y 646 | CONFIG_POST_EVENTS_FROM_IRAM_ISR=y 647 | CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150 648 | CONFIG_MB_MASTER_DELAY_MS_CONVERT=200 649 | CONFIG_MB_QUEUE_LENGTH=20 650 | CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048 651 | CONFIG_MB_SERIAL_BUF_SIZE=256 652 | CONFIG_MB_SERIAL_TASK_PRIO=10 653 | # CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set 654 | CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20 655 | CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20 656 | CONFIG_MB_CONTROLLER_STACK_SIZE=4096 657 | CONFIG_MB_EVENT_QUEUE_TIMEOUT=20 658 | CONFIG_MB_TIMER_PORT_ENABLED=y 659 | CONFIG_MB_TIMER_GROUP=0 660 | CONFIG_MB_TIMER_INDEX=0 661 | CONFIG_SUPPORT_STATIC_ALLOCATION=y 662 | # CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set 663 | CONFIG_TIMER_TASK_PRIORITY=1 664 | CONFIG_TIMER_TASK_STACK_DEPTH=2048 665 | CONFIG_TIMER_QUEUE_LENGTH=10 666 | # CONFIG_L2_TO_L3_COPY is not set 667 | # CONFIG_USE_ONLY_LWIP_SELECT is not set 668 | CONFIG_ESP_GRATUITOUS_ARP=y 669 | CONFIG_GARP_TMR_INTERVAL=60 670 | CONFIG_TCPIP_RECVMBOX_SIZE=32 671 | CONFIG_TCP_MAXRTX=12 672 | CONFIG_TCP_SYNMAXRTX=6 673 | CONFIG_TCP_MSS=1436 674 | CONFIG_TCP_MSL=60000 675 | CONFIG_TCP_SND_BUF_DEFAULT=5744 676 | CONFIG_TCP_WND_DEFAULT=5744 677 | CONFIG_TCP_RECVMBOX_SIZE=6 678 | CONFIG_TCP_QUEUE_OOSEQ=y 679 | # CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set 680 | CONFIG_TCP_OVERSIZE_MSS=y 681 | # CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set 682 | # CONFIG_TCP_OVERSIZE_DISABLE is not set 683 | CONFIG_UDP_RECVMBOX_SIZE=6 684 | CONFIG_TCPIP_TASK_STACK_SIZE=3072 685 | CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y 686 | # CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set 687 | # CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set 688 | CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF 689 | # CONFIG_PPP_SUPPORT is not set 690 | CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 691 | CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 692 | CONFIG_ESP32_PTHREAD_STACK_MIN=768 693 | CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y 694 | # CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set 695 | # CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set 696 | CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1 697 | CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread" 698 | CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y 699 | # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set 700 | # CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set 701 | CONFIG_IP_LOST_TIMER_INTERVAL=120 702 | CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y 703 | CONFIG_SUPPORT_TERMIOS=y 704 | # End of deprecated options 705 | -------------------------------------------------------------------------------- /components/ov2640/conversions/jpge.cpp: -------------------------------------------------------------------------------- 1 | // jpge.cpp - C++ class for JPEG compression. 2 | // Public domain, Rich Geldreich 3 | // v1.01, Dec. 18, 2010 - Initial release 4 | // v1.02, Apr. 6, 2011 - Removed 2x2 ordered dither in H2V1 chroma subsampling method load_block_16_8_8(). (The rounding factor was 2, when it should have been 1. Either way, it wasn't helping.) 5 | // v1.03, Apr. 16, 2011 - Added support for optimized Huffman code tables, optimized dynamic memory allocation down to only 1 alloc. 6 | // Also from Alex Evans: Added RGBA support, linear memory allocator (no longer needed in v1.03). 7 | // v1.04, May. 19, 2012: Forgot to set m_pFile ptr to NULL in cfile_stream::close(). Thanks to Owen Kaluza for reporting this bug. 8 | // Code tweaks to fix VS2008 static code analysis warnings (all looked harmless). 9 | // Code review revealed method load_block_16_8_8() (used for the non-default H2V1 sampling mode to downsample chroma) somehow didn't get the rounding factor fix from v1.02. 10 | 11 | #include "jpge.h" 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #define JPGE_MAX(a,b) (((a)>(b))?(a):(b)) 18 | #define JPGE_MIN(a,b) (((a)<(b))?(a):(b)) 19 | 20 | namespace jpge { 21 | 22 | static inline void *jpge_malloc(size_t nSize) { return malloc(nSize); } 23 | static inline void jpge_free(void *p) { free(p); } 24 | 25 | // Various JPEG enums and tables. 26 | enum { M_SOF0 = 0xC0, M_DHT = 0xC4, M_SOI = 0xD8, M_EOI = 0xD9, M_SOS = 0xDA, M_DQT = 0xDB, M_APP0 = 0xE0 }; 27 | enum { DC_LUM_CODES = 12, AC_LUM_CODES = 256, DC_CHROMA_CODES = 12, AC_CHROMA_CODES = 256, MAX_HUFF_SYMBOLS = 257, MAX_HUFF_CODESIZE = 32 }; 28 | 29 | static const uint8 s_zag[64] = { 0,1,8,16,9,2,3,10,17,24,32,25,18,11,4,5,12,19,26,33,40,48,41,34,27,20,13,6,7,14,21,28,35,42,49,56,57,50,43,36,29,22,15,23,30,37,44,51,58,59,52,45,38,31,39,46,53,60,61,54,47,55,62,63 }; 30 | static const int16 s_std_lum_quant[64] = { 16,11,12,14,12,10,16,14,13,14,18,17,16,19,24,40,26,24,22,22,24,49,35,37,29,40,58,51,61,60,57,51,56,55,64,72,92,78,64,68,87,69,55,56,80,109,81,87,95,98,103,104,103,62,77,113,121,112,100,120,92,101,103,99 }; 31 | static const int16 s_std_croma_quant[64] = { 17,18,18,24,21,24,47,26,26,47,99,66,56,66,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99,99 }; 32 | static const uint8 s_dc_lum_bits[17] = { 0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0 }; 33 | static const uint8 s_dc_lum_val[DC_LUM_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; 34 | static const uint8 s_ac_lum_bits[17] = { 0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d }; 35 | static const uint8 s_ac_lum_val[AC_LUM_CODES] = { 36 | 0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0, 37 | 0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49, 38 | 0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89, 39 | 0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5, 40 | 0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 41 | 0xf9,0xfa 42 | }; 43 | static const uint8 s_dc_chroma_bits[17] = { 0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0 }; 44 | static const uint8 s_dc_chroma_val[DC_CHROMA_CODES] = { 0,1,2,3,4,5,6,7,8,9,10,11 }; 45 | static const uint8 s_ac_chroma_bits[17] = { 0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77 }; 46 | static const uint8 s_ac_chroma_val[AC_CHROMA_CODES] = { 47 | 0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0, 48 | 0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48, 49 | 0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87, 50 | 0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3, 51 | 0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8, 52 | 0xf9,0xfa 53 | }; 54 | 55 | const int YR = 19595, YG = 38470, YB = 7471, CB_R = -11059, CB_G = -21709, CB_B = 32768, CR_R = 32768, CR_G = -27439, CR_B = -5329; 56 | 57 | static int32 m_last_quality = 0; 58 | static int32 m_quantization_tables[2][64]; 59 | 60 | static bool m_huff_initialized = false; 61 | static uint m_huff_codes[4][256]; 62 | static uint8 m_huff_code_sizes[4][256]; 63 | static uint8 m_huff_bits[4][17]; 64 | static uint8 m_huff_val[4][256]; 65 | 66 | static inline uint8 clamp(int i) { 67 | if (i < 0) { 68 | i = 0; 69 | } else if (i > 255){ 70 | i = 255; 71 | } 72 | return static_cast(i); 73 | } 74 | 75 | static void RGB_to_YCC(uint8* pDst, const uint8 *pSrc, int num_pixels) { 76 | for ( ; num_pixels; pDst += 3, pSrc += 3, num_pixels--) { 77 | const int r = pSrc[0], g = pSrc[1], b = pSrc[2]; 78 | pDst[0] = static_cast((r * YR + g * YG + b * YB + 32768) >> 16); 79 | pDst[1] = clamp(128 + ((r * CB_R + g * CB_G + b * CB_B + 32768) >> 16)); 80 | pDst[2] = clamp(128 + ((r * CR_R + g * CR_G + b * CR_B + 32768) >> 16)); 81 | } 82 | } 83 | 84 | static void RGB_to_Y(uint8* pDst, const uint8 *pSrc, int num_pixels) { 85 | for ( ; num_pixels; pDst++, pSrc += 3, num_pixels--) { 86 | pDst[0] = static_cast((pSrc[0] * YR + pSrc[1] * YG + pSrc[2] * YB + 32768) >> 16); 87 | } 88 | } 89 | 90 | static void Y_to_YCC(uint8* pDst, const uint8* pSrc, int num_pixels) { 91 | for( ; num_pixels; pDst += 3, pSrc++, num_pixels--) { 92 | pDst[0] = pSrc[0]; 93 | pDst[1] = 128; 94 | pDst[2] = 128; 95 | } 96 | } 97 | 98 | // Forward DCT - DCT derived from jfdctint. 99 | enum { CONST_BITS = 13, ROW_BITS = 2 }; 100 | #define DCT_DESCALE(x, n) (((x) + (((int32)1) << ((n) - 1))) >> (n)) 101 | #define DCT_MUL(var, c) (static_cast(var) * static_cast(c)) 102 | #define DCT1D(s0, s1, s2, s3, s4, s5, s6, s7) \ 103 | int32 t0 = s0 + s7, t7 = s0 - s7, t1 = s1 + s6, t6 = s1 - s6, t2 = s2 + s5, t5 = s2 - s5, t3 = s3 + s4, t4 = s3 - s4; \ 104 | int32 t10 = t0 + t3, t13 = t0 - t3, t11 = t1 + t2, t12 = t1 - t2; \ 105 | int32 u1 = DCT_MUL(t12 + t13, 4433); \ 106 | s2 = u1 + DCT_MUL(t13, 6270); \ 107 | s6 = u1 + DCT_MUL(t12, -15137); \ 108 | u1 = t4 + t7; \ 109 | int32 u2 = t5 + t6, u3 = t4 + t6, u4 = t5 + t7; \ 110 | int32 z5 = DCT_MUL(u3 + u4, 9633); \ 111 | t4 = DCT_MUL(t4, 2446); t5 = DCT_MUL(t5, 16819); \ 112 | t6 = DCT_MUL(t6, 25172); t7 = DCT_MUL(t7, 12299); \ 113 | u1 = DCT_MUL(u1, -7373); u2 = DCT_MUL(u2, -20995); \ 114 | u3 = DCT_MUL(u3, -16069); u4 = DCT_MUL(u4, -3196); \ 115 | u3 += z5; u4 += z5; \ 116 | s0 = t10 + t11; s1 = t7 + u1 + u4; s3 = t6 + u2 + u3; s4 = t10 - t11; s5 = t5 + u2 + u4; s7 = t4 + u1 + u3; 117 | 118 | static void DCT2D(int32 *p) { 119 | int32 c, *q = p; 120 | for (c = 7; c >= 0; c--, q += 8) { 121 | int32 s0 = q[0], s1 = q[1], s2 = q[2], s3 = q[3], s4 = q[4], s5 = q[5], s6 = q[6], s7 = q[7]; 122 | DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); 123 | q[0] = s0 << ROW_BITS; q[1] = DCT_DESCALE(s1, CONST_BITS-ROW_BITS); q[2] = DCT_DESCALE(s2, CONST_BITS-ROW_BITS); q[3] = DCT_DESCALE(s3, CONST_BITS-ROW_BITS); 124 | q[4] = s4 << ROW_BITS; q[5] = DCT_DESCALE(s5, CONST_BITS-ROW_BITS); q[6] = DCT_DESCALE(s6, CONST_BITS-ROW_BITS); q[7] = DCT_DESCALE(s7, CONST_BITS-ROW_BITS); 125 | } 126 | for (q = p, c = 7; c >= 0; c--, q++) { 127 | int32 s0 = q[0*8], s1 = q[1*8], s2 = q[2*8], s3 = q[3*8], s4 = q[4*8], s5 = q[5*8], s6 = q[6*8], s7 = q[7*8]; 128 | DCT1D(s0, s1, s2, s3, s4, s5, s6, s7); 129 | q[0*8] = DCT_DESCALE(s0, ROW_BITS+3); q[1*8] = DCT_DESCALE(s1, CONST_BITS+ROW_BITS+3); q[2*8] = DCT_DESCALE(s2, CONST_BITS+ROW_BITS+3); q[3*8] = DCT_DESCALE(s3, CONST_BITS+ROW_BITS+3); 130 | q[4*8] = DCT_DESCALE(s4, ROW_BITS+3); q[5*8] = DCT_DESCALE(s5, CONST_BITS+ROW_BITS+3); q[6*8] = DCT_DESCALE(s6, CONST_BITS+ROW_BITS+3); q[7*8] = DCT_DESCALE(s7, CONST_BITS+ROW_BITS+3); 131 | } 132 | } 133 | 134 | // Compute the actual canonical Huffman codes/code sizes given the JPEG huff bits and val arrays. 135 | static void compute_huffman_table(uint *codes, uint8 *code_sizes, uint8 *bits, uint8 *val) 136 | { 137 | int i, l, last_p, si; 138 | static uint8 huff_size[257]; 139 | static uint huff_code[257]; 140 | uint code; 141 | 142 | int p = 0; 143 | for (l = 1; l <= 16; l++) { 144 | for (i = 1; i <= bits[l]; i++) { 145 | huff_size[p++] = (char)l; 146 | } 147 | } 148 | 149 | huff_size[p] = 0; 150 | last_p = p; // write sentinel 151 | 152 | code = 0; si = huff_size[0]; p = 0; 153 | 154 | while (huff_size[p]) { 155 | while (huff_size[p] == si) { 156 | huff_code[p++] = code++; 157 | } 158 | code <<= 1; 159 | si++; 160 | } 161 | 162 | memset(codes, 0, sizeof(codes[0])*256); 163 | memset(code_sizes, 0, sizeof(code_sizes[0])*256); 164 | for (p = 0; p < last_p; p++) { 165 | codes[val[p]] = huff_code[p]; 166 | code_sizes[val[p]] = huff_size[p]; 167 | } 168 | } 169 | 170 | void jpeg_encoder::flush_output_buffer() 171 | { 172 | if (m_out_buf_left != JPGE_OUT_BUF_SIZE) { 173 | m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(m_out_buf, JPGE_OUT_BUF_SIZE - m_out_buf_left); 174 | } 175 | m_pOut_buf = m_out_buf; 176 | m_out_buf_left = JPGE_OUT_BUF_SIZE; 177 | } 178 | 179 | void jpeg_encoder::emit_byte(uint8 i) 180 | { 181 | *m_pOut_buf++ = i; 182 | if (--m_out_buf_left == 0) { 183 | flush_output_buffer(); 184 | } 185 | } 186 | 187 | void jpeg_encoder::put_bits(uint bits, uint len) 188 | { 189 | uint8 c = 0; 190 | m_bit_buffer |= ((uint32)bits << (24 - (m_bits_in += len))); 191 | while (m_bits_in >= 8) { 192 | c = (uint8)((m_bit_buffer >> 16) & 0xFF); 193 | emit_byte(c); 194 | if (c == 0xFF) { 195 | emit_byte(0); 196 | } 197 | m_bit_buffer <<= 8; 198 | m_bits_in -= 8; 199 | } 200 | } 201 | 202 | void jpeg_encoder::emit_word(uint i) 203 | { 204 | emit_byte(uint8(i >> 8)); emit_byte(uint8(i & 0xFF)); 205 | } 206 | 207 | // JPEG marker generation. 208 | void jpeg_encoder::emit_marker(int marker) 209 | { 210 | emit_byte(uint8(0xFF)); emit_byte(uint8(marker)); 211 | } 212 | 213 | // Emit JFIF marker 214 | void jpeg_encoder::emit_jfif_app0() 215 | { 216 | emit_marker(M_APP0); 217 | emit_word(2 + 4 + 1 + 2 + 1 + 2 + 2 + 1 + 1); 218 | emit_byte(0x4A); emit_byte(0x46); emit_byte(0x49); emit_byte(0x46); /* Identifier: ASCII "JFIF" */ 219 | emit_byte(0); 220 | emit_byte(1); /* Major version */ 221 | emit_byte(1); /* Minor version */ 222 | emit_byte(0); /* Density unit */ 223 | emit_word(1); 224 | emit_word(1); 225 | emit_byte(0); /* No thumbnail image */ 226 | emit_byte(0); 227 | } 228 | 229 | // Emit quantization tables 230 | void jpeg_encoder::emit_dqt() 231 | { 232 | for (int i = 0; i < ((m_num_components == 3) ? 2 : 1); i++) 233 | { 234 | emit_marker(M_DQT); 235 | emit_word(64 + 1 + 2); 236 | emit_byte(static_cast(i)); 237 | for (int j = 0; j < 64; j++) 238 | emit_byte(static_cast(m_quantization_tables[i][j])); 239 | } 240 | } 241 | 242 | // Emit start of frame marker 243 | void jpeg_encoder::emit_sof() 244 | { 245 | emit_marker(M_SOF0); /* baseline */ 246 | emit_word(3 * m_num_components + 2 + 5 + 1); 247 | emit_byte(8); /* precision */ 248 | emit_word(m_image_y); 249 | emit_word(m_image_x); 250 | emit_byte(m_num_components); 251 | for (int i = 0; i < m_num_components; i++) 252 | { 253 | emit_byte(static_cast(i + 1)); /* component ID */ 254 | emit_byte((m_comp_h_samp[i] << 4) + m_comp_v_samp[i]); /* h and v sampling */ 255 | emit_byte(i > 0); /* quant. table num */ 256 | } 257 | } 258 | 259 | // Emit Huffman table. 260 | void jpeg_encoder::emit_dht(uint8 *bits, uint8 *val, int index, bool ac_flag) 261 | { 262 | emit_marker(M_DHT); 263 | 264 | int length = 0; 265 | for (int i = 1; i <= 16; i++) 266 | length += bits[i]; 267 | 268 | emit_word(length + 2 + 1 + 16); 269 | emit_byte(static_cast(index + (ac_flag << 4))); 270 | 271 | for (int i = 1; i <= 16; i++) 272 | emit_byte(bits[i]); 273 | 274 | for (int i = 0; i < length; i++) 275 | emit_byte(val[i]); 276 | } 277 | 278 | // Emit all Huffman tables. 279 | void jpeg_encoder::emit_dhts() 280 | { 281 | emit_dht(m_huff_bits[0+0], m_huff_val[0+0], 0, false); 282 | emit_dht(m_huff_bits[2+0], m_huff_val[2+0], 0, true); 283 | if (m_num_components == 3) { 284 | emit_dht(m_huff_bits[0+1], m_huff_val[0+1], 1, false); 285 | emit_dht(m_huff_bits[2+1], m_huff_val[2+1], 1, true); 286 | } 287 | } 288 | 289 | // emit start of scan 290 | void jpeg_encoder::emit_sos() 291 | { 292 | emit_marker(M_SOS); 293 | emit_word(2 * m_num_components + 2 + 1 + 3); 294 | emit_byte(m_num_components); 295 | for (int i = 0; i < m_num_components; i++) 296 | { 297 | emit_byte(static_cast(i + 1)); 298 | if (i == 0) 299 | emit_byte((0 << 4) + 0); 300 | else 301 | emit_byte((1 << 4) + 1); 302 | } 303 | emit_byte(0); /* spectral selection */ 304 | emit_byte(63); 305 | emit_byte(0); 306 | } 307 | 308 | void jpeg_encoder::load_block_8_8_grey(int x) 309 | { 310 | uint8 *pSrc; 311 | sample_array_t *pDst = m_sample_array; 312 | x <<= 3; 313 | for (int i = 0; i < 8; i++, pDst += 8) 314 | { 315 | pSrc = m_mcu_lines[i] + x; 316 | pDst[0] = pSrc[0] - 128; pDst[1] = pSrc[1] - 128; pDst[2] = pSrc[2] - 128; pDst[3] = pSrc[3] - 128; 317 | pDst[4] = pSrc[4] - 128; pDst[5] = pSrc[5] - 128; pDst[6] = pSrc[6] - 128; pDst[7] = pSrc[7] - 128; 318 | } 319 | } 320 | 321 | void jpeg_encoder::load_block_8_8(int x, int y, int c) 322 | { 323 | uint8 *pSrc; 324 | sample_array_t *pDst = m_sample_array; 325 | x = (x * (8 * 3)) + c; 326 | y <<= 3; 327 | for (int i = 0; i < 8; i++, pDst += 8) 328 | { 329 | pSrc = m_mcu_lines[y + i] + x; 330 | pDst[0] = pSrc[0 * 3] - 128; pDst[1] = pSrc[1 * 3] - 128; pDst[2] = pSrc[2 * 3] - 128; pDst[3] = pSrc[3 * 3] - 128; 331 | pDst[4] = pSrc[4 * 3] - 128; pDst[5] = pSrc[5 * 3] - 128; pDst[6] = pSrc[6 * 3] - 128; pDst[7] = pSrc[7 * 3] - 128; 332 | } 333 | } 334 | 335 | void jpeg_encoder::load_block_16_8(int x, int c) 336 | { 337 | uint8 *pSrc1, *pSrc2; 338 | sample_array_t *pDst = m_sample_array; 339 | x = (x * (16 * 3)) + c; 340 | int a = 0, b = 2; 341 | for (int i = 0; i < 16; i += 2, pDst += 8) 342 | { 343 | pSrc1 = m_mcu_lines[i + 0] + x; 344 | pSrc2 = m_mcu_lines[i + 1] + x; 345 | pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3] + pSrc2[ 0 * 3] + pSrc2[ 1 * 3] + a) >> 2) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3] + pSrc2[ 2 * 3] + pSrc2[ 3 * 3] + b) >> 2) - 128; 346 | pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3] + pSrc2[ 4 * 3] + pSrc2[ 5 * 3] + a) >> 2) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3] + pSrc2[ 6 * 3] + pSrc2[ 7 * 3] + b) >> 2) - 128; 347 | pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3] + pSrc2[ 8 * 3] + pSrc2[ 9 * 3] + a) >> 2) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3] + pSrc2[10 * 3] + pSrc2[11 * 3] + b) >> 2) - 128; 348 | pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3] + pSrc2[12 * 3] + pSrc2[13 * 3] + a) >> 2) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3] + pSrc2[14 * 3] + pSrc2[15 * 3] + b) >> 2) - 128; 349 | int temp = a; a = b; b = temp; 350 | } 351 | } 352 | 353 | void jpeg_encoder::load_block_16_8_8(int x, int c) 354 | { 355 | uint8 *pSrc1; 356 | sample_array_t *pDst = m_sample_array; 357 | x = (x * (16 * 3)) + c; 358 | for (int i = 0; i < 8; i++, pDst += 8) 359 | { 360 | pSrc1 = m_mcu_lines[i + 0] + x; 361 | pDst[0] = ((pSrc1[ 0 * 3] + pSrc1[ 1 * 3]) >> 1) - 128; pDst[1] = ((pSrc1[ 2 * 3] + pSrc1[ 3 * 3]) >> 1) - 128; 362 | pDst[2] = ((pSrc1[ 4 * 3] + pSrc1[ 5 * 3]) >> 1) - 128; pDst[3] = ((pSrc1[ 6 * 3] + pSrc1[ 7 * 3]) >> 1) - 128; 363 | pDst[4] = ((pSrc1[ 8 * 3] + pSrc1[ 9 * 3]) >> 1) - 128; pDst[5] = ((pSrc1[10 * 3] + pSrc1[11 * 3]) >> 1) - 128; 364 | pDst[6] = ((pSrc1[12 * 3] + pSrc1[13 * 3]) >> 1) - 128; pDst[7] = ((pSrc1[14 * 3] + pSrc1[15 * 3]) >> 1) - 128; 365 | } 366 | } 367 | 368 | void jpeg_encoder::load_quantized_coefficients(int component_num) 369 | { 370 | int32 *q = m_quantization_tables[component_num > 0]; 371 | int16 *pDst = m_coefficient_array; 372 | for (int i = 0; i < 64; i++) 373 | { 374 | sample_array_t j = m_sample_array[s_zag[i]]; 375 | if (j < 0) 376 | { 377 | if ((j = -j + (*q >> 1)) < *q) 378 | *pDst++ = 0; 379 | else 380 | *pDst++ = static_cast(-(j / *q)); 381 | } 382 | else 383 | { 384 | if ((j = j + (*q >> 1)) < *q) 385 | *pDst++ = 0; 386 | else 387 | *pDst++ = static_cast((j / *q)); 388 | } 389 | q++; 390 | } 391 | } 392 | 393 | void jpeg_encoder::code_coefficients_pass_two(int component_num) 394 | { 395 | int i, j, run_len, nbits, temp1, temp2; 396 | int16 *pSrc = m_coefficient_array; 397 | uint *codes[2]; 398 | uint8 *code_sizes[2]; 399 | 400 | if (component_num == 0) 401 | { 402 | codes[0] = m_huff_codes[0 + 0]; codes[1] = m_huff_codes[2 + 0]; 403 | code_sizes[0] = m_huff_code_sizes[0 + 0]; code_sizes[1] = m_huff_code_sizes[2 + 0]; 404 | } 405 | else 406 | { 407 | codes[0] = m_huff_codes[0 + 1]; codes[1] = m_huff_codes[2 + 1]; 408 | code_sizes[0] = m_huff_code_sizes[0 + 1]; code_sizes[1] = m_huff_code_sizes[2 + 1]; 409 | } 410 | 411 | temp1 = temp2 = pSrc[0] - m_last_dc_val[component_num]; 412 | m_last_dc_val[component_num] = pSrc[0]; 413 | 414 | if (temp1 < 0) 415 | { 416 | temp1 = -temp1; temp2--; 417 | } 418 | 419 | nbits = 0; 420 | while (temp1) 421 | { 422 | nbits++; temp1 >>= 1; 423 | } 424 | 425 | put_bits(codes[0][nbits], code_sizes[0][nbits]); 426 | if (nbits) put_bits(temp2 & ((1 << nbits) - 1), nbits); 427 | 428 | for (run_len = 0, i = 1; i < 64; i++) 429 | { 430 | if ((temp1 = m_coefficient_array[i]) == 0) 431 | run_len++; 432 | else 433 | { 434 | while (run_len >= 16) 435 | { 436 | put_bits(codes[1][0xF0], code_sizes[1][0xF0]); 437 | run_len -= 16; 438 | } 439 | if ((temp2 = temp1) < 0) 440 | { 441 | temp1 = -temp1; 442 | temp2--; 443 | } 444 | nbits = 1; 445 | while (temp1 >>= 1) 446 | nbits++; 447 | j = (run_len << 4) + nbits; 448 | put_bits(codes[1][j], code_sizes[1][j]); 449 | put_bits(temp2 & ((1 << nbits) - 1), nbits); 450 | run_len = 0; 451 | } 452 | } 453 | if (run_len) 454 | put_bits(codes[1][0], code_sizes[1][0]); 455 | } 456 | 457 | void jpeg_encoder::code_block(int component_num) 458 | { 459 | DCT2D(m_sample_array); 460 | load_quantized_coefficients(component_num); 461 | code_coefficients_pass_two(component_num); 462 | } 463 | 464 | void jpeg_encoder::process_mcu_row() 465 | { 466 | if (m_num_components == 1) 467 | { 468 | for (int i = 0; i < m_mcus_per_row; i++) 469 | { 470 | load_block_8_8_grey(i); code_block(0); 471 | } 472 | } 473 | else if ((m_comp_h_samp[0] == 1) && (m_comp_v_samp[0] == 1)) 474 | { 475 | for (int i = 0; i < m_mcus_per_row; i++) 476 | { 477 | load_block_8_8(i, 0, 0); code_block(0); load_block_8_8(i, 0, 1); code_block(1); load_block_8_8(i, 0, 2); code_block(2); 478 | } 479 | } 480 | else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 1)) 481 | { 482 | for (int i = 0; i < m_mcus_per_row; i++) 483 | { 484 | load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); 485 | load_block_16_8_8(i, 1); code_block(1); load_block_16_8_8(i, 2); code_block(2); 486 | } 487 | } 488 | else if ((m_comp_h_samp[0] == 2) && (m_comp_v_samp[0] == 2)) 489 | { 490 | for (int i = 0; i < m_mcus_per_row; i++) 491 | { 492 | load_block_8_8(i * 2 + 0, 0, 0); code_block(0); load_block_8_8(i * 2 + 1, 0, 0); code_block(0); 493 | load_block_8_8(i * 2 + 0, 1, 0); code_block(0); load_block_8_8(i * 2 + 1, 1, 0); code_block(0); 494 | load_block_16_8(i, 1); code_block(1); load_block_16_8(i, 2); code_block(2); 495 | } 496 | } 497 | } 498 | 499 | void jpeg_encoder::load_mcu(const void *pSrc) 500 | { 501 | const uint8* Psrc = reinterpret_cast(pSrc); 502 | 503 | uint8* pDst = m_mcu_lines[m_mcu_y_ofs]; // OK to write up to m_image_bpl_xlt bytes to pDst 504 | 505 | if (m_num_components == 1) { 506 | if (m_image_bpp == 3) 507 | RGB_to_Y(pDst, Psrc, m_image_x); 508 | else 509 | memcpy(pDst, Psrc, m_image_x); 510 | } else { 511 | if (m_image_bpp == 3) 512 | RGB_to_YCC(pDst, Psrc, m_image_x); 513 | else 514 | Y_to_YCC(pDst, Psrc, m_image_x); 515 | } 516 | 517 | // Possibly duplicate pixels at end of scanline if not a multiple of 8 or 16 518 | if (m_num_components == 1) 519 | memset(m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt, pDst[m_image_bpl_xlt - 1], m_image_x_mcu - m_image_x); 520 | else 521 | { 522 | const uint8 y = pDst[m_image_bpl_xlt - 3 + 0], cb = pDst[m_image_bpl_xlt - 3 + 1], cr = pDst[m_image_bpl_xlt - 3 + 2]; 523 | uint8 *q = m_mcu_lines[m_mcu_y_ofs] + m_image_bpl_xlt; 524 | for (int i = m_image_x; i < m_image_x_mcu; i++) 525 | { 526 | *q++ = y; *q++ = cb; *q++ = cr; 527 | } 528 | } 529 | 530 | if (++m_mcu_y_ofs == m_mcu_y) 531 | { 532 | process_mcu_row(); 533 | m_mcu_y_ofs = 0; 534 | } 535 | } 536 | 537 | // Quantization table generation. 538 | void jpeg_encoder::compute_quant_table(int32 *pDst, const int16 *pSrc) 539 | { 540 | int32 q; 541 | if (m_params.m_quality < 50) 542 | q = 5000 / m_params.m_quality; 543 | else 544 | q = 200 - m_params.m_quality * 2; 545 | for (int i = 0; i < 64; i++) 546 | { 547 | int32 j = *pSrc++; j = (j * q + 50L) / 100L; 548 | *pDst++ = JPGE_MIN(JPGE_MAX(j, 1), 255); 549 | } 550 | } 551 | 552 | // Higher-level methods. 553 | bool jpeg_encoder::jpg_open(int p_x_res, int p_y_res, int src_channels) 554 | { 555 | m_num_components = 3; 556 | switch (m_params.m_subsampling) 557 | { 558 | case Y_ONLY: 559 | { 560 | m_num_components = 1; 561 | m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; 562 | m_mcu_x = 8; m_mcu_y = 8; 563 | break; 564 | } 565 | case H1V1: 566 | { 567 | m_comp_h_samp[0] = 1; m_comp_v_samp[0] = 1; 568 | m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; 569 | m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; 570 | m_mcu_x = 8; m_mcu_y = 8; 571 | break; 572 | } 573 | case H2V1: 574 | { 575 | m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 1; 576 | m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; 577 | m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; 578 | m_mcu_x = 16; m_mcu_y = 8; 579 | break; 580 | } 581 | case H2V2: 582 | { 583 | m_comp_h_samp[0] = 2; m_comp_v_samp[0] = 2; 584 | m_comp_h_samp[1] = 1; m_comp_v_samp[1] = 1; 585 | m_comp_h_samp[2] = 1; m_comp_v_samp[2] = 1; 586 | m_mcu_x = 16; m_mcu_y = 16; 587 | } 588 | } 589 | 590 | m_image_x = p_x_res; m_image_y = p_y_res; 591 | m_image_bpp = src_channels; 592 | m_image_bpl = m_image_x * src_channels; 593 | m_image_x_mcu = (m_image_x + m_mcu_x - 1) & (~(m_mcu_x - 1)); 594 | m_image_y_mcu = (m_image_y + m_mcu_y - 1) & (~(m_mcu_y - 1)); 595 | m_image_bpl_xlt = m_image_x * m_num_components; 596 | m_image_bpl_mcu = m_image_x_mcu * m_num_components; 597 | m_mcus_per_row = m_image_x_mcu / m_mcu_x; 598 | 599 | if ((m_mcu_lines[0] = static_cast(jpge_malloc(m_image_bpl_mcu * m_mcu_y))) == NULL) return false; 600 | for (int i = 1; i < m_mcu_y; i++) 601 | m_mcu_lines[i] = m_mcu_lines[i-1] + m_image_bpl_mcu; 602 | 603 | if(m_last_quality != m_params.m_quality){ 604 | m_last_quality = m_params.m_quality; 605 | compute_quant_table(m_quantization_tables[0], s_std_lum_quant); 606 | compute_quant_table(m_quantization_tables[1], s_std_croma_quant); 607 | } 608 | 609 | if(!m_huff_initialized){ 610 | m_huff_initialized = true; 611 | 612 | memcpy(m_huff_bits[0+0], s_dc_lum_bits, 17); memcpy(m_huff_val[0+0], s_dc_lum_val, DC_LUM_CODES); 613 | memcpy(m_huff_bits[2+0], s_ac_lum_bits, 17); memcpy(m_huff_val[2+0], s_ac_lum_val, AC_LUM_CODES); 614 | memcpy(m_huff_bits[0+1], s_dc_chroma_bits, 17); memcpy(m_huff_val[0+1], s_dc_chroma_val, DC_CHROMA_CODES); 615 | memcpy(m_huff_bits[2+1], s_ac_chroma_bits, 17); memcpy(m_huff_val[2+1], s_ac_chroma_val, AC_CHROMA_CODES); 616 | 617 | compute_huffman_table(&m_huff_codes[0+0][0], &m_huff_code_sizes[0+0][0], m_huff_bits[0+0], m_huff_val[0+0]); 618 | compute_huffman_table(&m_huff_codes[2+0][0], &m_huff_code_sizes[2+0][0], m_huff_bits[2+0], m_huff_val[2+0]); 619 | compute_huffman_table(&m_huff_codes[0+1][0], &m_huff_code_sizes[0+1][0], m_huff_bits[0+1], m_huff_val[0+1]); 620 | compute_huffman_table(&m_huff_codes[2+1][0], &m_huff_code_sizes[2+1][0], m_huff_bits[2+1], m_huff_val[2+1]); 621 | } 622 | 623 | m_out_buf_left = JPGE_OUT_BUF_SIZE; 624 | m_pOut_buf = m_out_buf; 625 | m_bit_buffer = 0; 626 | m_bits_in = 0; 627 | m_mcu_y_ofs = 0; 628 | m_pass_num = 2; 629 | memset(m_last_dc_val, 0, 3 * sizeof(m_last_dc_val[0])); 630 | 631 | // Emit all markers at beginning of image file. 632 | emit_marker(M_SOI); 633 | emit_jfif_app0(); 634 | emit_dqt(); 635 | emit_sof(); 636 | emit_dhts(); 637 | emit_sos(); 638 | 639 | return m_all_stream_writes_succeeded; 640 | } 641 | 642 | bool jpeg_encoder::process_end_of_image() 643 | { 644 | if (m_mcu_y_ofs) { 645 | if (m_mcu_y_ofs < 16) { // check here just to shut up static analysis 646 | for (int i = m_mcu_y_ofs; i < m_mcu_y; i++) { 647 | memcpy(m_mcu_lines[i], m_mcu_lines[m_mcu_y_ofs - 1], m_image_bpl_mcu); 648 | } 649 | } 650 | process_mcu_row(); 651 | } 652 | 653 | put_bits(0x7F, 7); 654 | emit_marker(M_EOI); 655 | flush_output_buffer(); 656 | m_all_stream_writes_succeeded = m_all_stream_writes_succeeded && m_pStream->put_buf(NULL, 0); 657 | m_pass_num++; // purposely bump up m_pass_num, for debugging 658 | return true; 659 | } 660 | 661 | void jpeg_encoder::clear() 662 | { 663 | m_mcu_lines[0] = NULL; 664 | m_pass_num = 0; 665 | m_all_stream_writes_succeeded = true; 666 | } 667 | 668 | jpeg_encoder::jpeg_encoder() 669 | { 670 | clear(); 671 | } 672 | 673 | jpeg_encoder::~jpeg_encoder() 674 | { 675 | deinit(); 676 | } 677 | 678 | bool jpeg_encoder::init(output_stream *pStream, int width, int height, int src_channels, const params &comp_params) 679 | { 680 | deinit(); 681 | if (((!pStream) || (width < 1) || (height < 1)) || ((src_channels != 1) && (src_channels != 3) && (src_channels != 4)) || (!comp_params.check())) return false; 682 | m_pStream = pStream; 683 | m_params = comp_params; 684 | return jpg_open(width, height, src_channels); 685 | } 686 | 687 | void jpeg_encoder::deinit() 688 | { 689 | jpge_free(m_mcu_lines[0]); 690 | clear(); 691 | } 692 | 693 | bool jpeg_encoder::process_scanline(const void* pScanline) 694 | { 695 | if ((m_pass_num < 1) || (m_pass_num > 2)) { 696 | return false; 697 | } 698 | if (m_all_stream_writes_succeeded) { 699 | if (!pScanline) { 700 | if (!process_end_of_image()) { 701 | return false; 702 | } 703 | } else { 704 | load_mcu(pScanline); 705 | } 706 | } 707 | return m_all_stream_writes_succeeded; 708 | } 709 | 710 | } // namespace jpge 711 | --------------------------------------------------------------------------------