├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── M5CAM-ESP32-A1-POWER.pdf ├── Makefile ├── README.md ├── components └── camera │ ├── Kconfig │ ├── bitmap.c │ ├── camera.c │ ├── camera_common.h │ ├── component.mk │ ├── include │ ├── bitmap.h │ └── camera.h │ ├── ov2640.c │ ├── ov2640.h │ ├── ov2640_regs.h │ ├── ov7725.c │ ├── ov7725.h │ ├── ov7725_regs.h │ ├── sccb.c │ ├── sccb.h │ ├── sensor.h │ ├── twi.c │ ├── twi.h │ ├── wiring.c │ ├── wiring.h │ ├── xclk.c │ └── xclk.h ├── m5cam-firmware.zip ├── main ├── Kconfig.projbuild ├── app_main.c └── component.mk ├── pictures ├── chessboard-core-board-v2-ov7725.jpg ├── chessboard-esp-wrover-v1-ov7725.jpg ├── core-board-v2.jpg ├── daughter-board-camera-module-side.jpg ├── daughter-board-esp32-module-side.jpg ├── esp-wrover-v1.jpg ├── ov7725-alternate-wiring.png ├── ov7725-camera-module.jpg ├── sw-operation-diagram.png ├── wiring-1-core-board-v2-ov7725.jpg ├── wiring-2-core-board-v2-ov7725.jpg └── wiring-esp-wrover-v1-ov7725.jpg ├── sdkconfig └── sdkconfig.defaults /.gitignore: -------------------------------------------------------------------------------- 1 | sdkconfig.old 2 | build 3 | .cproject 4 | .project 5 | .settings 6 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "components/http_server"] 2 | path = components/http_server 3 | url = https://github.com/igrr/esp32-http-server.git 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: bash 3 | os: 4 | - linux 5 | 6 | addons: 7 | apt: 8 | packages: 9 | - gperf 10 | - python 11 | - python-serial 12 | 13 | before_install: 14 | # Save path to the git respository 15 | - PROJECT_PATH=$(pwd) 16 | 17 | install: 18 | # Install ESP32 toochain following steps as desribed 19 | # in http://esp-idf.readthedocs.io/en/latest/linux-setup.html 20 | # 21 | # Get required packages - already done above, see addons: apt: packages: 22 | # - sudo apt-get install git wget make libncurses-dev flex bison gperf python python-serial 23 | # Prepare directory for the toolchain 24 | - mkdir -p ~/esp 25 | - cd ~/esp 26 | # Download binary toolchain for the ESP32 27 | - wget https://dl.espressif.com/dl/xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz 28 | - tar -xzf xtensa-esp32-elf-linux64-1.22.0-61-gab8375a-5.2.0.tar.gz 29 | # Make xtensa-esp32-elf available for all terminal sessions 30 | - export PATH=$PATH:$HOME/esp/xtensa-esp32-elf/bin 31 | # Get ESP-IDF from github 32 | - git clone --recursive https://github.com/espressif/esp-idf.git 33 | # Set the path to ESP-IDF directory 34 | - export IDF_PATH=~/esp/esp-idf 35 | 36 | script: 37 | # Go back to the git repository 38 | - cd $PROJECT_PATH 39 | # Update configuration so that kconfig doesn't start interactive mode 40 | - make defconfig 41 | # Build project from the git repository 42 | - make 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /M5CAM-ESP32-A1-POWER.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/M5CAM-ESP32-A1-POWER.pdf -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | PROJECT_NAME := esp32-cam-demo 2 | 3 | include $(IDF_PATH)/make/project.mk 4 | 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 Camera Demo 2 | 3 | Code provided in this repository gets the image from camera and prints it out as ASCII art to the serial port. 4 | 5 | ## M5CAMERA 6 | 1Z实验室(1zlab): [中文文档](https://github.com/1zlab/esp-cam-tutorial) 7 | 8 | ## Build Status 9 | 10 | [![Build Status](https://travis-ci.org/igrr/esp32-cam-demo.svg?branch=master)](https://travis-ci.org/igrr/esp32-cam-demo) 11 | 12 | ## Table of Contents 13 | - [ESP32 Camera Demo](#esp32-camera-demo) 14 | - [M5CAMERA](#m5camera) 15 | - [Build Status](#build-status) 16 | - [Table of Contents](#table-of-contents) 17 | - [Components](#components) 18 | - [ESP32](#esp32) 19 | - [Camera](#camera) 20 | - [ESP-IDF](#esp-idf) 21 | - [Quick Start](#quick-start) 22 | - [Connect](#connect) 23 | - [Flash](#flash) 24 | - [Shoot](#shoot) 25 | - [How it Works](#how-it-works) 26 | - [Software](#software) 27 | - [Operation](#operation) 28 | - [Troubleshooting](#troubleshooting) 29 | - [Showcase](#showcase) 30 | - [Next Steps](#next-steps) 31 | - [Contribute](#contribute) 32 | - [Acknowledgments](#acknowledgments) 33 | 34 | ## Components 35 | 36 | To make this code work, you need the following components: 37 | 38 | * This repository. It contains submodules, so make sure you clone it with `--recursive` option. If you have already cloned it without `--recursive`, run `git submodule update --init`. 39 | * [ESP32](https://espressif.com/en/products/hardware/esp32/overview) module 40 | * Camera module 41 | * PC with [esp-idf](https://github.com/espressif/esp-idf) 42 | 43 | See the following sections for more details. 44 | 45 | ### ESP32 46 | 47 | Any ESP32 module should work, if it has sufficient number of GPIO pins available to interface with camera. See section [Connect](#connect) for more details. 48 | 49 | If you are an owner of [ESP-WROVER V1 (aka DevKitJ)](http://dl.espressif.com/dl/schematics/ESP32-DevKitJ-v1_sch.pdf), then camera connector is already broken out. 50 | 51 | ### Camera 52 | 53 | This example has been tested with OV7725 camera module. Use it, if this is your first exposure to interfacing a microcontroller with a camera. 54 | 55 | Other OV7xxx series should work as well, with some changes to camera configuration code. OV5xxx can work too, but it is advisable to choose the ones which support RGB or YUV 8-bit wide output bus. The ones which only output 10-bit raw data may be a bit harder to work with. Also choose the camera which can output a scaled down (QVGA or VGA) image. Use of larger frame buffers will require external SPI RAM. 56 | 57 | ### ESP-IDF 58 | 59 | Configure your PC according to [ESP32 Documentation](http://esp-idf.readthedocs.io/en/latest/?badge=latest). [Windows](http://esp-idf.readthedocs.io/en/latest/windows-setup.html), [Linux](http://esp-idf.readthedocs.io/en/latest/linux-setup.html) and [Mac OS](http://esp-idf.readthedocs.io/en/latest/macos-setup.html) are supported. If this is you first exposure to ESP32 and [esp-idf](https://github.com/espressif/esp-idf), then get familiar with [01_hello_world](https://github.com/espressif/esp-idf/tree/master/examples/01_hello_world) and [02_blink](https://github.com/espressif/esp-idf/tree/master/examples/02_blink) examples. Make them work and understand before proceeding further. 60 | 61 | ## Quick Start 62 | 63 | If you have your components ready, follow this section to [connect](#connect) the camera to ESP32 module, [flash](#flash) application to the ESP32 and finally [shoot](#shoot) and display the image. 64 | 65 | ## Connect 66 | 67 | Specific pins used in this example to connect ESP32 and camera are shown in table below. Pinout can be adjusted to some extent in software. Table below provides two options of pin mapping (last two columns). 68 | 69 | | Interface | Camera Pin | Pin Mapping for ESP32 DevKitJ | Alternate ESP32 Pin Mapping | M5Cam | 70 | | :--- | :---: | :---: | :---: | :---: | 71 | | SCCB Clock | SIOC | IO27 | IO23 | IO23 | 72 | | SCCB Data | SIOD | IO26 | IO25 | IO25 | 73 | | System Clock | XCLK | IO21 | IO27 | IO27 | 74 | | Vertical Sync | VSYNC | IO25 | IO22 | IO22 | 75 | | Horizontal Reference | HREF | IO23 | IO26 | IO26 | 76 | | Pixel Clock | PCLK | IO22 | IO21 | IO21 | 77 | | Pixel Data Bit 0 | D2 | IO4 | IO35 | IO17 | 78 | | Pixel Data Bit 1 | D3 | IO5 | IO17 | IO35 | 79 | | Pixel Data Bit 2 | D4 | IO18 | IO34 | IO34 | 80 | | Pixel Data Bit 3 | D5 | IO19 | IO5 | IO5 | 81 | | Pixel Data Bit 4 | D6 | IO36 | IO39 | IO39 | 82 | | Pixel Data Bit 5 | D7 | IO39 | IO18 | IO18 | 83 | | Pixel Data Bit 6 | D8 | IO34 | IO36 | IO36 | 84 | | Pixel Data Bit 7 | D9 | IO35 | IO19 | IO19 85 | | Camera Reset | RESET | IO2 | IO15 | IO15 | 86 | | Camera Power Down | PWDN | *see Note 3* | *see Note 3* | *see Note 3* | 87 | | Power Supply 3.3V | 3V3 | 3V3 | 3V3 | 3V3 | 88 | | Ground | GND | GND | GND | GND | 89 | 90 | Notes: 91 | 92 | 1. **Important:** Make the connections short or you are likely to get noisy or even not legible images. More on that is discussed in section [Showcase](#showcase) 93 | 2. **Camera pin** column refers to pinout on OV7725 camera module 94 | 3. **Camera Power Down** pin does not need to be connected to ESP32 GPIO. Instead it may be pulled down to ground with 10 kOhm resistor. 95 | 4. OV7725 supports 10 bit image pixels. In this example the upper 8 bits are processed and saved. The pins corresponding with LSB are marked D0 and D1 and are left not connected. 96 | 97 | If you have [ESP-WROVER V1 (aka DevKitJ)](http://dl.espressif.com/dl/schematics/ESP32-DevKitJ-v1_sch.pdf), then camera connector is already broken out and labeled Camera / JP4. Solder 2.54 mm / 0.1" double row, 18 pin socket in provided space and plug the camera module right into it. Line up 3V3 and GND pins on camera module and on ESP-WROVER. D0 and D1 should be left not connected outside the socket. 98 | 99 | To connect the camera to Core Board V2 (aka DevKitC), consider alternate pin mapping (see the last column of table) that provides clean wiring layout shown below. 100 | 101 | ![alt text](pictures/ov7725-alternate-wiring.png "Wiring for Core Board V2 (aka DevKitC)") 102 | 103 | 2.2uF capacitor conencted between GND and EN pins of ESP32module is added to resolve [ESP32 Reset To Bootloader Issues on Windows #136](https://github.com/espressif/esptool/issues/136). 104 | 105 | ### Flash 106 | 107 | Clone the code provided in this repository to your PC, compile with the latest [esp-idf](https://github.com/espressif/esp-idf) installed from GitHub and download to the module. 108 | 109 | If all h/w components are connected properly you are likely to see the following message during download: 110 | 111 | ``` 112 | Krzysztof@tdk-kmb-op780 MSYS /esp/esp32-cam-demo 113 | $ make flash 114 | Flashing binaries to serial port com18 (app at offset 0x10000)... 115 | esptool.py v2.0-dev 116 | Connecting... 117 | 118 | A fatal error occurred: Failed to connect to ESP32: Timed out waiting for packet header 119 | make: *** [C:/msys32/esp-idf/components/esptool_py/Makefile.projbuild:48: flash] Error 2 120 | ``` 121 | This is due to a pullup on the camera reset line. It is stronger than the internal pull-down on `GPIO2` of the ESP32, so the chip cannot go into programming mode. 122 | 123 | There are couple of options how to resolve this issue: 124 | 125 | * If you are using ESP-WROVER V1 then connect GPIO2 to GND while flashing. 126 | * Power down the camera module by removing it from the socket (ESP-WROVER V1) or by uplugging 3.3V wire. 127 | * Map Camera Reset line to another GPIO pin on ESP32, for instance `GPIO15`. 128 | 129 | ### Shoot 130 | 131 | Once module is loaded with code, open a serial terminal. 132 | 133 | Camera demo application will first configure XCLK output that is timing operation of the camera chip. 134 | 135 | ``` 136 | D (1527) camera: Enabling XCLK output 137 | I (1527) ledc: LEDC_PWM CHANNEL 0|GPIO 21|Duty 0004|Time 0 138 | ``` 139 | This clock is also timing output of pixel data on camera output interface - see I2S and DMA described below. 140 | 141 | Then [SCCB](http://www.ovt.com/download_document.php?type=document&DID=63) interface is set up: 142 | 143 | ``` 144 | D (1527) camera: Initializing SSCB 145 | I (1537) gpio: GPIO[26]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 146 | I (1537) gpio: GPIO[27]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 147 | I (1547) gpio: GPIO[26]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 148 | I (1557) gpio: GPIO[27]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0 149 | ``` 150 | 151 | In next step the communication with camera should be established. ESP will retrieve camera's address and signature. 152 | 153 | ``` 154 | D (1567) camera: Resetting camera 155 | D (1587) camera: Searching for camera address 156 | D (1587) camera: Detected camera at address=0x21 157 | D (1587) camera: Camera PID=0x77 VER=0x21 MIDL=0x7f MIDH=0xa2 158 | ``` 159 | 160 | If communication fails, the following message is shown: 161 | 162 | ``` 163 | E (1076) camera: Camera address not found 164 | E (1076) camera_demo: Camera init failed with error = 131073 165 | ``` 166 | 167 | If communication with camera module is established, ESP will reset the camera sensor and reserve memory for video frame buffer: 168 | 169 | ``` 170 | D (1587) camera: Doing SW reset of sensor 171 | D (1647) camera: Setting frame size at 320x240 172 | D (1677) camera: Allocating frame buffer (320x240, 76800 bytes) 173 | ``` 174 | 175 | Image from camera is retrieved using I2S communication for all eight pixel bits at once and saved in memory line by line. Log below shows completion of initialization steps for I2S and DMA: 176 | 177 | ``` 178 | D (1677) camera: Initializing I2S and DMA 179 | I (1677) gpio: GPIO[35]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 180 | I (1677) gpio: GPIO[34]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 181 | I (1687) gpio: GPIO[39]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 182 | I (1697) gpio: GPIO[36]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 183 | I (1707) gpio: GPIO[19]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 184 | I (1717) gpio: GPIO[18]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 185 | I (1727) gpio: GPIO[5]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 186 | I (1737) gpio: GPIO[4]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 187 | I (1747) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 188 | I (1757) gpio: GPIO[23]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 189 | I (1767) gpio: GPIO[22]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 190 | D (1777) intr_alloc: Connected src 32 to int 3 (cpu 0) 191 | D (1777) camera: Allocating DMA buffer #0, size=1280 192 | D (1787) camera: Allocating DMA buffer #1, size=1280 193 | D (1817) camera: Init done 194 | ``` 195 | 196 | Finally ESP32 will retrieve image from camera and show it as ASCII art on serial terminal. Image will be retrieved in a loop once per second. 197 | 198 | ``` 199 | D (1817) camera: Waiting for positive edge on VSYNC 200 | D (1847) camera: Got VSYNC 201 | D (1847) camera: Waiting for frame 202 | D (1887) camera: Frame done 203 | D (1887) camera_demo: Done 204 | |@@ ......... @@@@@@@@@@@@ .@@@@@@@@@@@@@ .. ....... @@@@@@@+. @@@@@@@| 205 | |@@. ... .+@@@@@@@@@@@@ @@@@@@@@@@@@@ .. .. @@@@@@@@@@.:. %@| 206 | |@+ .@@@@@@@@@@@@@ @@@@@@@@@@@@@ .. . @@@@@@@@@@@......| 207 | |@ @@@@@@@@@@@@@ @@@@@@@@@@@@@.. . ..@@@@@@@@@@@......| 208 | |@ @@@@@@@@@@@@@ @@@@@@@@@@@@@-... .@@@@@@@@@@@......| 209 | |:@@@@@@@@@@@ =@@@@@@@@@@@@@ @@@@@@@%=. @@@@@@@@@@@ .....| 210 | |%@@@@@@@@@@@ %@@@@@@@@@@@@@ .@@@@@@@@@@@@@ . @@* | 211 | |@@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@@@@@ . @@@@@@| 212 | |@@@@@@@@@@@% @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@| 213 | |@@@@@@@@@@@- @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@| 214 | |@@@@@@@@@@@ @@@@@@@@@@@@@@ @@@@@@@@@@@@@ @@@@@@| 215 | ``` 216 | 217 | ## How it Works 218 | 219 | ### Software 220 | 221 | The core of camera software is contained in `camera` folder and consists of the following files. 222 | 223 | * [camera.c](components/camera/camera.c) and [include/camera.h](components/camera/include/camera.h) - main file responsible for configuration of ESP32's GPIO, clock, I2S and DMA to interface with camera module. Once interface is established, it perfroms camera configuration to then retrieve image and save it in ESP32 memory. Access to camera is executed using lower level routines in the following files. 224 | 225 | * [ov7725.c](components/camera/ov7725.c), [ov7725.h](components/camera/ov7725.h), [ov7725_regs.h](components/camera/ov7725_regs.h) and [sensor.h](components/camera/sensor.h) - definition of registers of OV7725 to configure camera funcinality. Functions to set register groups to reset camera to default configuration and configure specific functionality like resolution or pixel format. Setting he registers is performed by lower level function in files below. 226 | 227 | * [sccb.c](components/camera/sccb.c) and [sccb.h](components/camera/sccb.h) - implementation of [Serial Camera Control Bus (SCCB)](http://www.ovt.com/download_document.php?type=document&DID=63) protocol to set camera registers. 228 | 229 | * [twi.c](components/camera/twi.c) and [twi.h](components/camera/twi.h) - implementation of software I2C routines used by SCCB protocol. 230 | 231 | * [wiring.c](components/camera/wiring.c) and [wiring.h](components/camera/wiring.h) - the lowest level routines to set GPIO pin mode, set GPIO pin level and delay program execution by required number of ms. 232 | 233 | * [component.mk](components/camera/component.mk) - file used by C `make` command to access component during compilation. 234 | 235 | * [Kconfig.projbuild](components/camera/Kconfig.projbuild) - file used by `make menuconfig` that provides menu option to switch camera test pattern on / off. 236 | 237 | All above are called _esp-idf component_ and placed in `components` folder. Esp-idf framework provides `components` folder as a standard place to add modular functionality to a project. 238 | 239 | Application starts and the top level control is executed from [app_main.c](main/app_main.c) file located in [main](main) folder. 240 | 241 | ### Operation 242 | 243 | Interconnections between application and h/w internals of ESP32 to acquire an image from the camera is shown on diagram below. 244 | 245 | ![alt text](pictures/sw-operation-diagram.png "Operation diagram of camera application") 246 | 247 | ## Troubleshooting 248 | 249 | If you have issues to get the live image right, enable test pattern and see what is retrieved. 250 | 251 | To do so, run `make menuconfig`, open `Example Configuration` menu option and check `[ ] Enable test pattern on camera output`. 252 | 253 | Optionally change the following define in file `camera.c`: 254 | 255 | ``` 256 | # define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN 257 | ``` 258 | 259 | Camera sensor will then output test pattern instead of live image. 260 | 261 | ``` 262 | D (5692) camera: Waiting for positive edge on VSYNC 263 | D (5722) camera: Got VSYNC 264 | D (5722) camera: Waiting for frame 265 | D (5752) camera: Frame done 266 | D (5752) camera_demo: Done 267 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 268 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 269 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 270 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 271 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 272 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 273 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 274 | |@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%########## +++++++++==========-::::::::: | 275 | ``` 276 | 277 | O 278 | nce test pattern is enabled, application will calculate standard variance of what is retrieved by ESP32 against pattern generated by the camera module. If there is noise on the lines or some pixels lines not connected or shortcut, this should be reported below displayed image. 279 | 280 | ``` 281 | Frames / mismatch : 4630 / 70 (1%), (6531449) 282 | ``` 283 | The value in brackets with % sign provides number of frames that differ from the test pattern. See code inline comments for more information on this functionality. 284 | 285 | ## Showcase 286 | 287 | This code has been tested with hardware presented below. 288 | 289 | | ![alt text](pictures/core-board-v2.jpg "Core Board V2 (aka DevKitC)") | ![alt text](pictures/esp-wrover-v1.jpg "ESP-WROVER V1 (aka DevKitJ)") | ![alt text](pictures/ov7725-camera-module.jpg "OV7725 Camera module") | 290 | | --- | --- | --- | 291 | | Core Board V2 (aka DevKitC) | ESP-WROVER V1 (aka DevKitJ) | OV7725 Camera module | 292 | 293 | Connections between camera and ESP32 should be made short or you are likely to get noisy images. In worst case you will not be able to retrieve any legible data from the camera. Using the above h/w it has been established, that connection length between OV7725 camera module header and ESP32 chip should not be longer than 90 mm. 294 | 295 | In particular, if you are using [ESP-WROVER V1 (aka DevKitJ)](http://dl.espressif.com/dl/schematics/ESP32-DevKitJ-v1_sch.pdf), then camera module should be plugged right into socket soldered to the board. Attempt to use a cable header as shown below on left did not work. Image retrieved from camera was not legible. Test stand on right is showing ESP-WROVER V1 with a cable header. The chessboard test pattern retrieved in such set up is not legible. Module should be plugged right into the socket soldered on ESP-WROVER V1. 296 | 297 | | ![alt text](pictures/wiring-esp-wrover-v1-ov7725.jpg "Wiring of OV7725 to ESP-WROVER V1 - SUCH LONG WIRING DOES NOT WORK!") | ![alt text](pictures/chessboard-esp-wrover-v1-ov7725.jpg "Not legible chessboard test pattern for ESP-WROVER V1 with a cable header") | 298 | | --- | --- | 299 | | Wiring of OV7725 to ESP-WROVER V1 - SUCH LONG WIRING DOES NOT WORK! | Not legible chessboard test pattern for ESP-WROVER V1 with a cable header | 300 | 301 | To give you the idea of length of cable connection that does not cause issues with image retrieval, below is an example of wiring of Core Board V2 (aka DevKitC). 302 | 303 | | ![alt text](pictures/wiring-1-core-board-v2-ov7725.jpg "Wiring of OV7725 to Core Board V2") | ![alt text](pictures/wiring-2-core-board-v2-ov7725.jpg "Wiring of OV7725 to Core Board V2") | 304 | | --- | --- | 305 | | Core Board V2 and camera on test stand | Core Board V2 and camera wiring | 306 | 307 | A rigid test rig without any loose wires may be constructed using a proto-board and standard 2.54" sockets. It will work as a daughter board placed in-between Core Board V2 and camera module. Pictures below shows both sides of such rig wired according to alternate [pin mapping](#connect). 308 | 309 | | ![alt text](pictures/daughter-board-esp32-module-side.jpg "Daughter board - ESP32 Core Board V2 side") | ![alt text](pictures/daughter-board-camera-module-side.jpg "Daughter board - OV7725 camera module side") | 310 | | --- | --- | 311 | | Daughter board - ESP32 Core Board V2 side | Daughter board - OV7725 camera module side| 312 | 313 | Using short wires or a daughter board there are no problems with noise on the chessboard test pattern retrieved from the camera. 314 | 315 | ![alt text](pictures/chessboard-core-board-v2-ov7725.jpg "Chessboard test pattern for Core Board V2") 316 | 317 | ## Next Steps 318 | 319 | We are planning to test and compare images captured using: 320 | 321 | * ESP-WROVER V1 with camera module directly plugged in. 322 | * Core Board V2 and camera module interconnected with a daughter board instead of loose cables. 323 | 324 | In longer perspective we plan the following: 325 | 326 | * Describe what's inside [camera component](https://github.com/igrr/esp32-cam-demo/tree/master/components/camera) 327 | * LCD support 328 | * QR Code reading 329 | * Web interface to control the camera 330 | * Camera component API development 331 | 332 | ## Contribute 333 | 334 | You are welcome to contribute to this repository by providing documentation to code, submitting issue reports, enhancement requests and pull requests. Contributions should follow [Contributions Guide](http://esp-idf.readthedocs.io/en/latest/contributing.html) section of ESP32 Programming Guide. 335 | 336 | ## Acknowledgments 337 | 338 | This application is using code developed by: 339 | * OpenMV implementation for OV7725 by Ibrahim Abdelkader 340 | * Software I2C library for ESP31B by Hristo Gochkov 341 | -------------------------------------------------------------------------------- /components/camera/Kconfig: -------------------------------------------------------------------------------- 1 | menu "Camera configuration" 2 | 3 | config ENABLE_TEST_PATTERN 4 | bool "Enable test pattern on camera output" 5 | default n 6 | help 7 | Configure the camera module to output test pattern instead of live image. 8 | 9 | Use this option to troubleshoot image issues like noise, 10 | distortion, not legible and missing live image. 11 | Instead, module will generate regular vertical bars 12 | in shades from dark to white. 13 | 14 | config OV2640_SUPPORT 15 | bool "OV2640 Support" 16 | default y 17 | help 18 | Enable this option if you want to use the OV2640. 19 | Disable this option to safe memory. 20 | 21 | config OV7725_SUPPORT 22 | bool "OV7725 Support" 23 | default y 24 | help 25 | Enable this option if you want to use the OV7725. 26 | Disable this option to safe memory. 27 | 28 | endmenu 29 | -------------------------------------------------------------------------------- /components/camera/bitmap.c: -------------------------------------------------------------------------------- 1 | //https://stackoverflow.com/a/23303847 2 | #include "bitmap.h" 3 | #include 4 | #include 5 | 6 | 7 | bitmap_header_t *bmp_create_header(int w, int h) 8 | { 9 | bitmap_header_t *pbitmap = (bitmap_header_t*)calloc(1, sizeof(bitmap_header_t)); 10 | int _pixelbytesize = w * h * _bitsperpixel/8; 11 | int _filesize = _pixelbytesize+sizeof(bitmap_header_t); 12 | strcpy((char*)pbitmap->fileheader.signature, "BM"); 13 | pbitmap->fileheader.filesize = _filesize; 14 | pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap_header_t); 15 | pbitmap->bitmapinfoheader.dibheadersize = sizeof(bitmapinfoheader); 16 | pbitmap->bitmapinfoheader.width = w; 17 | pbitmap->bitmapinfoheader.height = h; 18 | pbitmap->bitmapinfoheader.planes = _planes; 19 | pbitmap->bitmapinfoheader.bitsperpixel = _bitsperpixel; 20 | pbitmap->bitmapinfoheader.compression = _compression; 21 | pbitmap->bitmapinfoheader.imagesize = _pixelbytesize; 22 | pbitmap->bitmapinfoheader.ypixelpermeter = _ypixelpermeter ; 23 | pbitmap->bitmapinfoheader.xpixelpermeter = _xpixelpermeter ; 24 | pbitmap->bitmapinfoheader.numcolorspallette = 0; 25 | return pbitmap; 26 | } 27 | -------------------------------------------------------------------------------- /components/camera/camera.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 17 | #include "time.h" 18 | #include "sys/time.h" 19 | #include "freertos/FreeRTOS.h" 20 | #include "freertos/task.h" 21 | #include "freertos/semphr.h" 22 | #include "rom/lldesc.h" 23 | #include "soc/soc.h" 24 | #include "soc/gpio_sig_map.h" 25 | #include "soc/i2s_reg.h" 26 | #include "soc/i2s_struct.h" 27 | #include "soc/io_mux_reg.h" 28 | #include "driver/gpio.h" 29 | #include "driver/rtc_io.h" 30 | #include "driver/periph_ctrl.h" 31 | #include "esp_intr_alloc.h" 32 | #include "esp_log.h" 33 | #include "sensor.h" 34 | #include "sccb.h" 35 | #include "wiring.h" 36 | #include "camera.h" 37 | #include "camera_common.h" 38 | #include "xclk.h" 39 | #if CONFIG_OV2640_SUPPORT 40 | #include "ov2640.h" 41 | #endif 42 | #if CONFIG_OV7725_SUPPORT 43 | #include "ov7725.h" 44 | #endif 45 | 46 | #define ENABLE_TEST_PATTERN CONFIG_ENABLE_TEST_PATTERN 47 | 48 | #define REG_PID 0x0A 49 | #define REG_VER 0x0B 50 | #define REG_MIDH 0x1C 51 | #define REG_MIDL 0x1D 52 | 53 | static const char* TAG = "camera"; 54 | 55 | camera_state_t* s_state = NULL; 56 | 57 | const int resolution[][2] = { 58 | { 40, 30 }, /* 40x30 */ 59 | { 64, 32 }, /* 64x32 */ 60 | { 64, 64 }, /* 64x64 */ 61 | { 88, 72 }, /* QQCIF */ 62 | { 160, 120 }, /* QQVGA */ 63 | { 128, 160 }, /* QQVGA2*/ 64 | { 176, 144 }, /* QCIF */ 65 | { 240, 160 }, /* HQVGA */ 66 | { 320, 240 }, /* QVGA */ 67 | { 352, 288 }, /* CIF */ 68 | { 640, 480 }, /* VGA */ 69 | { 800, 600 }, /* SVGA */ 70 | { 1280, 1024 }, /* SXGA */ 71 | { 1600, 1200 }, /* UXGA */ 72 | }; 73 | 74 | static void i2s_init(); 75 | static void i2s_run(); 76 | static void IRAM_ATTR gpio_isr(void* arg); 77 | static void IRAM_ATTR i2s_isr(void* arg); 78 | static esp_err_t dma_desc_init(); 79 | static void dma_desc_deinit(); 80 | static void dma_filter_task(void *pvParameters); 81 | static void dma_filter_grayscale(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 82 | static void dma_filter_grayscale_highspeed(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 83 | static void dma_filter_jpeg(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 84 | static void dma_filter_rgb565(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 85 | static void i2s_stop(); 86 | 87 | static bool is_hs_mode() 88 | { 89 | return s_state->config.xclk_freq_hz > 10000000; 90 | } 91 | 92 | static size_t i2s_bytes_per_sample(i2s_sampling_mode_t mode) 93 | { 94 | switch(mode) { 95 | case SM_0A00_0B00: 96 | return 4; 97 | case SM_0A0B_0B0C: 98 | return 4; 99 | case SM_0A0B_0C0D: 100 | return 2; 101 | default: 102 | assert(0 && "invalid sampling mode"); 103 | return 0; 104 | } 105 | } 106 | 107 | static void vsync_intr_disable() 108 | { 109 | gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_DISABLE); 110 | } 111 | 112 | static void vsync_intr_enable() 113 | { 114 | gpio_set_intr_type(s_state->config.pin_vsync, GPIO_INTR_NEGEDGE); 115 | } 116 | 117 | 118 | esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera_model) 119 | { 120 | if (s_state != NULL) { 121 | return ESP_ERR_INVALID_STATE; 122 | } 123 | 124 | s_state = (camera_state_t*) calloc(sizeof(*s_state), 1); 125 | if (!s_state) { 126 | return ESP_ERR_NO_MEM; 127 | } 128 | 129 | ESP_LOGD(TAG, "Enabling XCLK output"); 130 | camera_enable_out_clock(config); 131 | 132 | ESP_LOGD(TAG, "Initializing SSCB"); 133 | SCCB_Init(config->pin_sscb_sda, config->pin_sscb_scl); 134 | 135 | ESP_LOGD(TAG, "Resetting camera"); 136 | gpio_config_t conf = { 0 }; 137 | conf.pin_bit_mask = 1LL << config->pin_reset; 138 | conf.mode = GPIO_MODE_OUTPUT; 139 | gpio_config(&conf); 140 | 141 | gpio_set_level(config->pin_reset, 0); 142 | delay(10); 143 | gpio_set_level(config->pin_reset, 1); 144 | delay(10); 145 | 146 | ESP_LOGD(TAG, "Searching for camera address"); 147 | /* Probe the sensor */ 148 | delay(10); 149 | uint8_t slv_addr = SCCB_Probe(); 150 | if (slv_addr == 0) { 151 | *out_camera_model = CAMERA_NONE; 152 | return ESP_ERR_CAMERA_NOT_DETECTED; 153 | } 154 | s_state->sensor.slv_addr = slv_addr; 155 | ESP_LOGD(TAG, "Detected camera at address=0x%02x", slv_addr); 156 | sensor_id_t* id = &s_state->sensor.id; 157 | id->PID = SCCB_Read(slv_addr, REG_PID); 158 | id->VER = SCCB_Read(slv_addr, REG_VER); 159 | id->MIDL = SCCB_Read(slv_addr, REG_MIDL); 160 | id->MIDH = SCCB_Read(slv_addr, REG_MIDH); 161 | delay(10); 162 | ESP_LOGD(TAG, "Camera PID=0x%02x VER=0x%02x MIDL=0x%02x MIDH=0x%02x", 163 | id->PID, id->VER, id->MIDH, id->MIDL); 164 | 165 | switch (id->PID) { 166 | #if CONFIG_OV2640_SUPPORT 167 | case OV2640_PID: 168 | *out_camera_model = CAMERA_OV2640; 169 | ov2640_init(&s_state->sensor); 170 | break; 171 | #endif 172 | #if CONFIG_OV7725_SUPPORT 173 | case OV7725_PID: 174 | *out_camera_model = CAMERA_OV7725; 175 | ov7725_init(&s_state->sensor); 176 | break; 177 | #endif 178 | default: 179 | id->PID = 0; 180 | *out_camera_model = CAMERA_UNKNOWN; 181 | ESP_LOGD(TAG, "Detected camera not supported."); 182 | return ESP_ERR_CAMERA_NOT_SUPPORTED; 183 | } 184 | 185 | ESP_LOGD(TAG, "Doing SW reset of sensor"); 186 | s_state->sensor.reset(&s_state->sensor); 187 | 188 | return ESP_OK; 189 | } 190 | 191 | esp_err_t camera_init(const camera_config_t* config) 192 | { 193 | if (!s_state) { 194 | return ESP_ERR_INVALID_STATE; 195 | } 196 | if (s_state->sensor.id.PID == 0) { 197 | return ESP_ERR_CAMERA_NOT_SUPPORTED; 198 | } 199 | memcpy(&s_state->config, config, sizeof(*config)); 200 | esp_err_t err = ESP_OK; 201 | framesize_t frame_size = (framesize_t) config->frame_size; 202 | pixformat_t pix_format = (pixformat_t) config->pixel_format; 203 | s_state->width = resolution[frame_size][0]; 204 | s_state->height = resolution[frame_size][1]; 205 | s_state->sensor.set_pixformat(&s_state->sensor, pix_format); 206 | 207 | ESP_LOGD(TAG, "Setting frame size to %dx%d", s_state->width, s_state->height); 208 | if (s_state->sensor.set_framesize(&s_state->sensor, frame_size) != 0) { 209 | ESP_LOGE(TAG, "Failed to set frame size"); 210 | err = ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE; 211 | goto fail; 212 | } 213 | s_state->sensor.set_pixformat(&s_state->sensor, pix_format); 214 | 215 | #if ENABLE_TEST_PATTERN 216 | /* Test pattern may get handy 217 | if you are unable to get the live image right. 218 | Once test pattern is enable, sensor will output 219 | vertical shaded bars instead of live image. 220 | */ 221 | s_state->sensor.set_colorbar(&s_state->sensor, 1); 222 | ESP_LOGD(TAG, "Test pattern enabled"); 223 | #endif 224 | 225 | if (pix_format == PIXFORMAT_GRAYSCALE) { 226 | if (s_state->sensor.id.PID != OV7725_PID) { 227 | ESP_LOGE(TAG, "Grayscale format is only supported for ov7225"); 228 | err = ESP_ERR_NOT_SUPPORTED; 229 | goto fail; 230 | } 231 | s_state->fb_size = s_state->width * s_state->height; 232 | if (is_hs_mode()) { 233 | s_state->sampling_mode = SM_0A0B_0B0C; 234 | s_state->dma_filter = &dma_filter_grayscale_highspeed; 235 | } else { 236 | s_state->sampling_mode = SM_0A0B_0C0D; 237 | s_state->dma_filter = &dma_filter_grayscale; 238 | } 239 | s_state->in_bytes_per_pixel = 2; // camera sends YUYV 240 | s_state->fb_bytes_per_pixel = 1; // frame buffer stores Y8 241 | } else if (pix_format == PIXFORMAT_RGB565) { 242 | if (s_state->sensor.id.PID != OV7725_PID) { 243 | ESP_LOGE(TAG, "RGB565 format is only supported for ov7225"); 244 | err = ESP_ERR_NOT_SUPPORTED; 245 | goto fail; 246 | } 247 | s_state->fb_size = s_state->width * s_state->height * 3; 248 | if (is_hs_mode()) { 249 | s_state->sampling_mode = SM_0A0B_0B0C; 250 | } else { 251 | s_state->sampling_mode = SM_0A00_0B00; 252 | } 253 | s_state->in_bytes_per_pixel = 2; // camera sends RGB565 (2 bytes) 254 | s_state->fb_bytes_per_pixel = 3; // frame buffer stores RGB888 255 | s_state->dma_filter = &dma_filter_rgb565; 256 | 257 | } else if (pix_format == PIXFORMAT_JPEG) { 258 | if (s_state->sensor.id.PID != OV2640_PID) { 259 | ESP_LOGE(TAG, "JPEG format is only supported for ov2640"); 260 | err = ESP_ERR_NOT_SUPPORTED; 261 | goto fail; 262 | } 263 | int qp = config->jpeg_quality; 264 | int compression_ratio_bound; 265 | if (qp >= 30) { 266 | compression_ratio_bound = 5; 267 | } else if (qp >= 10) { 268 | compression_ratio_bound = 10; 269 | } else { 270 | compression_ratio_bound = 20; 271 | } 272 | (*s_state->sensor.set_quality)(&s_state->sensor, qp); 273 | size_t equiv_line_count = s_state->height / compression_ratio_bound; 274 | s_state->fb_size = s_state->width * equiv_line_count * 2 /* bpp */; 275 | s_state->dma_filter = &dma_filter_jpeg; 276 | if (is_hs_mode()) { 277 | s_state->sampling_mode = SM_0A0B_0B0C; 278 | } else { 279 | s_state->sampling_mode = SM_0A00_0B00; 280 | } 281 | s_state->in_bytes_per_pixel = 2; 282 | s_state->fb_bytes_per_pixel = 2; 283 | } else { 284 | ESP_LOGE(TAG, "Requested format is not supported"); 285 | err = ESP_ERR_NOT_SUPPORTED; 286 | goto fail; 287 | } 288 | 289 | ESP_LOGD(TAG, "in_bpp: %d, fb_bpp: %d, fb_size: %d, mode: %d, width: %d height: %d", 290 | s_state->in_bytes_per_pixel, s_state->fb_bytes_per_pixel, 291 | s_state->fb_size, s_state->sampling_mode, 292 | s_state->width, s_state->height); 293 | 294 | ESP_LOGD(TAG, "Allocating frame buffer (%d bytes)", s_state->fb_size); 295 | s_state->fb = (uint8_t*) calloc(s_state->fb_size, 1); 296 | if (s_state->fb == NULL) { 297 | ESP_LOGE(TAG, "Failed to allocate frame buffer"); 298 | err = ESP_ERR_NO_MEM; 299 | goto fail; 300 | } 301 | 302 | ESP_LOGD(TAG, "Initializing I2S and DMA"); 303 | i2s_init(); 304 | err = dma_desc_init(); 305 | if (err != ESP_OK) { 306 | ESP_LOGE(TAG, "Failed to initialize I2S and DMA"); 307 | goto fail; 308 | } 309 | 310 | s_state->data_ready = xQueueCreate(16, sizeof(size_t)); 311 | s_state->frame_ready = xSemaphoreCreateBinary(); 312 | if (s_state->data_ready == NULL || s_state->frame_ready == NULL) { 313 | ESP_LOGE(TAG, "Failed to create semaphores"); 314 | err = ESP_ERR_NO_MEM; 315 | goto fail; 316 | } 317 | if (!xTaskCreatePinnedToCore(&dma_filter_task, "dma_filter", 4096, NULL, 10, &s_state->dma_filter_task, 1)) { 318 | ESP_LOGE(TAG, "Failed to create DMA filter task"); 319 | err = ESP_ERR_NO_MEM; 320 | goto fail; 321 | } 322 | 323 | ESP_LOGD(TAG, "Initializing GPIO interrupts"); 324 | vsync_intr_disable(); 325 | err = gpio_isr_handler_add(s_state->config.pin_vsync, &gpio_isr, NULL); 326 | if (err != ESP_OK) { 327 | ESP_LOGE(TAG, "gpio_isr_handler_add failed (%x)", err); 328 | goto fail; 329 | } 330 | 331 | // skip at least one frame after changing camera settings 332 | while (gpio_get_level(s_state->config.pin_vsync) == 0) { 333 | ; 334 | } 335 | while (gpio_get_level(s_state->config.pin_vsync) != 0) { 336 | ; 337 | } 338 | while (gpio_get_level(s_state->config.pin_vsync) == 0) { 339 | ; 340 | } 341 | s_state->frame_count = 0; 342 | ESP_LOGD(TAG, "Init done"); 343 | return ESP_OK; 344 | 345 | fail: 346 | camera_deinit(); 347 | return err; 348 | } 349 | 350 | esp_err_t camera_deinit() 351 | { 352 | if (s_state == NULL) { 353 | return ESP_ERR_INVALID_STATE; 354 | } 355 | if (s_state->dma_filter_task) { 356 | vTaskDelete(s_state->dma_filter_task); 357 | } 358 | if (s_state->data_ready) { 359 | vQueueDelete(s_state->data_ready); 360 | } 361 | if (s_state->frame_ready) { 362 | vSemaphoreDelete(s_state->frame_ready); 363 | } 364 | gpio_isr_handler_remove(s_state->config.pin_vsync); 365 | if (s_state->i2s_intr_handle) { 366 | esp_intr_disable(s_state->i2s_intr_handle); 367 | esp_intr_free(s_state->i2s_intr_handle); 368 | } 369 | dma_desc_deinit(); 370 | free(s_state->fb); 371 | free(s_state); 372 | s_state = NULL; 373 | camera_disable_out_clock(); 374 | periph_module_disable(PERIPH_I2S0_MODULE); 375 | return ESP_OK; 376 | } 377 | 378 | uint8_t* camera_get_fb() 379 | { 380 | if (s_state == NULL) { 381 | return NULL; 382 | } 383 | return s_state->fb; 384 | } 385 | 386 | int camera_get_fb_width() 387 | { 388 | if (s_state == NULL) { 389 | return 0; 390 | } 391 | return s_state->width; 392 | } 393 | 394 | int camera_get_fb_height() 395 | { 396 | if (s_state == NULL) { 397 | return 0; 398 | } 399 | return s_state->height; 400 | } 401 | 402 | size_t camera_get_data_size() 403 | { 404 | if (s_state == NULL) { 405 | return 0; 406 | } 407 | return s_state->data_size; 408 | } 409 | 410 | esp_err_t camera_run() 411 | { 412 | if (s_state == NULL) { 413 | return ESP_ERR_INVALID_STATE; 414 | } 415 | struct timeval tv_start; 416 | gettimeofday(&tv_start, NULL); 417 | #ifndef _NDEBUG 418 | memset(s_state->fb, 0, s_state->fb_size); 419 | #endif // _NDEBUG 420 | i2s_run(); 421 | ESP_LOGD(TAG, "Waiting for frame"); 422 | xSemaphoreTake(s_state->frame_ready, portMAX_DELAY); 423 | struct timeval tv_end; 424 | gettimeofday(&tv_end, NULL); 425 | int time_ms = (tv_end.tv_sec - tv_start.tv_sec) * 1000 + (tv_end.tv_usec - tv_start.tv_usec) / 1000; 426 | ESP_LOGI(TAG, "Frame %d done in %d ms", s_state->frame_count, time_ms); 427 | s_state->frame_count++; 428 | return ESP_OK; 429 | } 430 | 431 | static esp_err_t dma_desc_init() 432 | { 433 | assert(s_state->width % 4 == 0); 434 | size_t line_size = s_state->width * s_state->in_bytes_per_pixel * 435 | i2s_bytes_per_sample(s_state->sampling_mode); 436 | ESP_LOGD(TAG, "Line width (for DMA): %d bytes", line_size); 437 | size_t dma_per_line = 1; 438 | size_t buf_size = line_size; 439 | while (buf_size >= 4096) { 440 | buf_size /= 2; 441 | dma_per_line *= 2; 442 | } 443 | size_t dma_desc_count = dma_per_line * 4; 444 | s_state->dma_buf_width = line_size; 445 | s_state->dma_per_line = dma_per_line; 446 | s_state->dma_desc_count = dma_desc_count; 447 | ESP_LOGD(TAG, "DMA buffer size: %d, DMA buffers per line: %d", buf_size, dma_per_line); 448 | ESP_LOGD(TAG, "DMA buffer count: %d", dma_desc_count); 449 | 450 | s_state->dma_buf = (dma_elem_t**) malloc(sizeof(dma_elem_t*) * dma_desc_count); 451 | if (s_state->dma_buf == NULL) { 452 | return ESP_ERR_NO_MEM; 453 | } 454 | s_state->dma_desc = (lldesc_t*) malloc(sizeof(lldesc_t) * dma_desc_count); 455 | if (s_state->dma_desc == NULL) { 456 | return ESP_ERR_NO_MEM; 457 | } 458 | size_t dma_sample_count = 0; 459 | for (int i = 0; i < dma_desc_count; ++i) { 460 | ESP_LOGD(TAG, "Allocating DMA buffer #%d, size=%d", i, buf_size); 461 | dma_elem_t* buf = (dma_elem_t*) malloc(buf_size); 462 | if (buf == NULL) { 463 | return ESP_ERR_NO_MEM; 464 | } 465 | s_state->dma_buf[i] = buf; 466 | ESP_LOGV(TAG, "dma_buf[%d]=%p", i, buf); 467 | 468 | lldesc_t* pd = &s_state->dma_desc[i]; 469 | pd->length = buf_size; 470 | if (s_state->sampling_mode == SM_0A0B_0B0C && 471 | (i + 1) % dma_per_line == 0) { 472 | pd->length -= 4; 473 | } 474 | dma_sample_count += pd->length / 4; 475 | pd->size = pd->length; 476 | pd->owner = 1; 477 | pd->sosf = 1; 478 | pd->buf = (uint8_t*) buf; 479 | pd->offset = 0; 480 | pd->empty = 0; 481 | pd->eof = 1; 482 | pd->qe.stqe_next = &s_state->dma_desc[(i + 1) % dma_desc_count]; 483 | } 484 | s_state->dma_done = false; 485 | s_state->dma_sample_count = dma_sample_count; 486 | return ESP_OK; 487 | } 488 | 489 | static void dma_desc_deinit() 490 | { 491 | if (s_state->dma_buf) { 492 | for (int i = 0; i < s_state->dma_desc_count; ++i) { 493 | free(s_state->dma_buf[i]); 494 | } 495 | } 496 | free(s_state->dma_buf); 497 | free(s_state->dma_desc); 498 | } 499 | 500 | static inline void i2s_conf_reset() 501 | { 502 | const uint32_t lc_conf_reset_flags = I2S_IN_RST_M | I2S_AHBM_RST_M 503 | | I2S_AHBM_FIFO_RST_M; 504 | I2S0.lc_conf.val |= lc_conf_reset_flags; 505 | I2S0.lc_conf.val &= ~lc_conf_reset_flags; 506 | 507 | const uint32_t conf_reset_flags = I2S_RX_RESET_M | I2S_RX_FIFO_RESET_M 508 | | I2S_TX_RESET_M | I2S_TX_FIFO_RESET_M; 509 | I2S0.conf.val |= conf_reset_flags; 510 | I2S0.conf.val &= ~conf_reset_flags; 511 | while (I2S0.state.rx_fifo_reset_back) { 512 | ; 513 | } 514 | } 515 | 516 | static void i2s_init() 517 | { 518 | camera_config_t* config = &s_state->config; 519 | 520 | // Configure input GPIOs 521 | gpio_num_t pins[] = { 522 | config->pin_d7, 523 | config->pin_d6, 524 | config->pin_d5, 525 | config->pin_d4, 526 | config->pin_d3, 527 | config->pin_d2, 528 | config->pin_d1, 529 | config->pin_d0, 530 | config->pin_vsync, 531 | config->pin_href, 532 | config->pin_pclk 533 | }; 534 | gpio_config_t conf = { 535 | .mode = GPIO_MODE_INPUT, 536 | .pull_up_en = GPIO_PULLUP_ENABLE, 537 | .pull_down_en = GPIO_PULLDOWN_DISABLE, 538 | .intr_type = GPIO_INTR_DISABLE 539 | }; 540 | for (int i = 0; i < sizeof(pins) / sizeof(gpio_num_t); ++i) { 541 | if (rtc_gpio_is_valid_gpio(pins[i])) { 542 | rtc_gpio_deinit(pins[i]); 543 | } 544 | conf.pin_bit_mask = 1LL << pins[i]; 545 | gpio_config(&conf); 546 | } 547 | 548 | // Route input GPIOs to I2S peripheral using GPIO matrix 549 | gpio_matrix_in(config->pin_d0, I2S0I_DATA_IN0_IDX, false); 550 | gpio_matrix_in(config->pin_d1, I2S0I_DATA_IN1_IDX, false); 551 | gpio_matrix_in(config->pin_d2, I2S0I_DATA_IN2_IDX, false); 552 | gpio_matrix_in(config->pin_d3, I2S0I_DATA_IN3_IDX, false); 553 | gpio_matrix_in(config->pin_d4, I2S0I_DATA_IN4_IDX, false); 554 | gpio_matrix_in(config->pin_d5, I2S0I_DATA_IN5_IDX, false); 555 | gpio_matrix_in(config->pin_d6, I2S0I_DATA_IN6_IDX, false); 556 | gpio_matrix_in(config->pin_d7, I2S0I_DATA_IN7_IDX, false); 557 | gpio_matrix_in(config->pin_vsync, I2S0I_V_SYNC_IDX, false); 558 | gpio_matrix_in(0x38, I2S0I_H_SYNC_IDX, false); 559 | gpio_matrix_in(config->pin_href, I2S0I_H_ENABLE_IDX, false); 560 | gpio_matrix_in(config->pin_pclk, I2S0I_WS_IN_IDX, false); 561 | 562 | // Enable and configure I2S peripheral 563 | periph_module_enable(PERIPH_I2S0_MODULE); 564 | // Toggle some reset bits in LC_CONF register 565 | // Toggle some reset bits in CONF register 566 | i2s_conf_reset(); 567 | // Enable slave mode (sampling clock is external) 568 | I2S0.conf.rx_slave_mod = 1; 569 | // Enable parallel mode 570 | I2S0.conf2.lcd_en = 1; 571 | // Use HSYNC/VSYNC/HREF to control sampling 572 | I2S0.conf2.camera_en = 1; 573 | // Configure clock divider 574 | I2S0.clkm_conf.clkm_div_a = 1; 575 | I2S0.clkm_conf.clkm_div_b = 0; 576 | I2S0.clkm_conf.clkm_div_num = 2; 577 | // FIFO will sink data to DMA 578 | I2S0.fifo_conf.dscr_en = 1; 579 | // FIFO configuration 580 | I2S0.fifo_conf.rx_fifo_mod = s_state->sampling_mode; 581 | I2S0.fifo_conf.rx_fifo_mod_force_en = 1; 582 | I2S0.conf_chan.rx_chan_mod = 1; 583 | // Clear flags which are used in I2S serial mode 584 | I2S0.sample_rate_conf.rx_bits_mod = 0; 585 | I2S0.conf.rx_right_first = 0; 586 | I2S0.conf.rx_msb_right = 0; 587 | I2S0.conf.rx_msb_shift = 0; 588 | I2S0.conf.rx_mono = 0; 589 | I2S0.conf.rx_short_sync = 0; 590 | I2S0.timing.val = 0; 591 | 592 | // Allocate I2S interrupt, keep it disabled 593 | esp_intr_alloc(ETS_I2S0_INTR_SOURCE, 594 | ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, 595 | &i2s_isr, NULL, &s_state->i2s_intr_handle); 596 | } 597 | 598 | 599 | static void i2s_stop() 600 | { 601 | esp_intr_disable(s_state->i2s_intr_handle); 602 | vsync_intr_disable(); 603 | i2s_conf_reset(); 604 | I2S0.conf.rx_start = 0; 605 | size_t val = SIZE_MAX; 606 | BaseType_t higher_priority_task_woken; 607 | xQueueSendFromISR(s_state->data_ready, &val, &higher_priority_task_woken); 608 | } 609 | 610 | static void i2s_run() 611 | { 612 | #ifndef _NDEBUG 613 | for (int i = 0; i < s_state->dma_desc_count; ++i) { 614 | lldesc_t* d = &s_state->dma_desc[i]; 615 | ESP_LOGV(TAG, "DMA desc %2d: %u %u %u %u %u %u %p %p", 616 | i, d->length, d->size, d->offset, d->eof, d->sosf, d->owner, d->buf, d->qe.stqe_next); 617 | memset(s_state->dma_buf[i], 0, d->length); 618 | } 619 | #endif 620 | 621 | // wait for vsync 622 | ESP_LOGD(TAG, "Waiting for positive edge on VSYNC"); 623 | while (gpio_get_level(s_state->config.pin_vsync) == 0) { 624 | ; 625 | } 626 | while (gpio_get_level(s_state->config.pin_vsync) != 0) { 627 | ; 628 | } 629 | ESP_LOGD(TAG, "Got VSYNC"); 630 | 631 | s_state->dma_done = false; 632 | s_state->dma_desc_cur = 0; 633 | s_state->dma_received_count = 0; 634 | s_state->dma_filtered_count = 0; 635 | esp_intr_disable(s_state->i2s_intr_handle); 636 | i2s_conf_reset(); 637 | 638 | I2S0.rx_eof_num = s_state->dma_sample_count; 639 | I2S0.in_link.addr = (uint32_t) &s_state->dma_desc[0]; 640 | I2S0.in_link.start = 1; 641 | I2S0.int_clr.val = I2S0.int_raw.val; 642 | I2S0.int_ena.val = 0; 643 | I2S0.int_ena.in_done = 1; 644 | esp_intr_enable(s_state->i2s_intr_handle); 645 | if (s_state->config.pixel_format == CAMERA_PF_JPEG) { 646 | vsync_intr_enable(); 647 | } 648 | I2S0.conf.rx_start = 1; 649 | 650 | } 651 | 652 | static void IRAM_ATTR signal_dma_buf_received(bool* need_yield) 653 | { 654 | size_t dma_desc_filled = s_state->dma_desc_cur; 655 | s_state->dma_desc_cur = (dma_desc_filled + 1) % s_state->dma_desc_count; 656 | s_state->dma_received_count++; 657 | BaseType_t higher_priority_task_woken; 658 | BaseType_t ret = xQueueSendFromISR(s_state->data_ready, &dma_desc_filled, &higher_priority_task_woken); 659 | if (ret != pdTRUE) { 660 | ESP_EARLY_LOGW(TAG, "queue send failed (%d), dma_received_count=%d", ret, s_state->dma_received_count); 661 | } 662 | *need_yield = (ret == pdTRUE && higher_priority_task_woken == pdTRUE); 663 | } 664 | 665 | static void IRAM_ATTR i2s_isr(void* arg) 666 | { 667 | I2S0.int_clr.val = I2S0.int_raw.val; 668 | bool need_yield; 669 | signal_dma_buf_received(&need_yield); 670 | ESP_EARLY_LOGV(TAG, "isr, cnt=%d", s_state->dma_received_count); 671 | if (s_state->dma_received_count == s_state->height * s_state->dma_per_line) { 672 | i2s_stop(); 673 | } 674 | if (need_yield) { 675 | portYIELD_FROM_ISR(); 676 | } 677 | } 678 | 679 | static void IRAM_ATTR gpio_isr(void* arg) 680 | { 681 | bool need_yield = false; 682 | ESP_EARLY_LOGV(TAG, "gpio isr, cnt=%d", s_state->dma_received_count); 683 | if (gpio_get_level(s_state->config.pin_vsync) == 0 && 684 | s_state->dma_received_count > 0 && 685 | !s_state->dma_done) { 686 | signal_dma_buf_received(&need_yield); 687 | i2s_stop(); 688 | } 689 | if (need_yield) { 690 | portYIELD_FROM_ISR(); 691 | } 692 | } 693 | 694 | static size_t get_fb_pos() 695 | { 696 | return s_state->dma_filtered_count * s_state->width * 697 | s_state->fb_bytes_per_pixel / s_state->dma_per_line; 698 | } 699 | 700 | static void IRAM_ATTR dma_filter_task(void *pvParameters) 701 | { 702 | while (true) { 703 | size_t buf_idx; 704 | xQueueReceive(s_state->data_ready, &buf_idx, portMAX_DELAY); 705 | if (buf_idx == SIZE_MAX) { 706 | s_state->data_size = get_fb_pos(); 707 | xSemaphoreGive(s_state->frame_ready); 708 | continue; 709 | } 710 | 711 | size_t fb_pos = get_fb_pos(); 712 | assert(fb_pos <= s_state->fb_size + s_state->width * 713 | s_state->fb_bytes_per_pixel / s_state->dma_per_line); 714 | 715 | uint8_t* pfb = s_state->fb + fb_pos; 716 | const dma_elem_t* buf = s_state->dma_buf[buf_idx]; 717 | lldesc_t* desc = &s_state->dma_desc[buf_idx]; 718 | (*s_state->dma_filter)(buf, desc, pfb); 719 | s_state->dma_filtered_count++; 720 | ESP_LOGV(TAG, "dma_flt: flt_count=%d ", s_state->dma_filtered_count); 721 | } 722 | } 723 | 724 | static void IRAM_ATTR dma_filter_grayscale(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) 725 | { 726 | assert(s_state->sampling_mode == SM_0A0B_0C0D); 727 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; 728 | for (size_t i = 0; i < end; ++i) { 729 | // manually unrolling 4 iterations of the loop here 730 | dst[0] = src[0].sample1; 731 | dst[1] = src[1].sample1; 732 | dst[2] = src[2].sample1; 733 | dst[3] = src[3].sample1; 734 | src += 4; 735 | dst += 4; 736 | } 737 | } 738 | 739 | static void IRAM_ATTR dma_filter_grayscale_highspeed(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) 740 | { 741 | assert(s_state->sampling_mode == SM_0A0B_0B0C); 742 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 8; 743 | for (size_t i = 0; i < end; ++i) { 744 | // manually unrolling 4 iterations of the loop here 745 | dst[0] = src[0].sample1; 746 | dst[1] = src[2].sample1; 747 | dst[2] = src[4].sample1; 748 | dst[3] = src[6].sample1; 749 | src += 8; 750 | dst += 4; 751 | } 752 | // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling 753 | if ((dma_desc->length & 0x7) != 0) { 754 | dst[0] = src[0].sample1; 755 | dst[1] = src[2].sample1; 756 | } 757 | } 758 | 759 | static void IRAM_ATTR dma_filter_jpeg(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) 760 | { 761 | assert(s_state->sampling_mode == SM_0A0B_0B0C || 762 | s_state->sampling_mode == SM_0A00_0B00 ); 763 | size_t end = dma_desc->length / sizeof(dma_elem_t) / 4; 764 | // manually unrolling 4 iterations of the loop here 765 | for (size_t i = 0; i < end; ++i) { 766 | dst[0] = src[0].sample1; 767 | dst[1] = src[1].sample1; 768 | dst[2] = src[2].sample1; 769 | dst[3] = src[3].sample1; 770 | src += 4; 771 | dst += 4; 772 | } 773 | // the final sample of a line in SM_0A0B_0B0C sampling mode needs special handling 774 | if ((dma_desc->length & 0x7) != 0) { 775 | dst[0] = src[0].sample1; 776 | dst[1] = src[1].sample1; 777 | dst[2] = src[2].sample1; 778 | dst[3] = src[2].sample2; 779 | } 780 | } 781 | 782 | static inline void rgb565_to_888(uint8_t in1, uint8_t in2, uint8_t* dst) 783 | { 784 | dst[0] = (in2 & 0b00011111) << 3; // blue 785 | dst[1] = ((in1 & 0b111) << 5) | ((in2 & 0b11100000 >> 5)); // green 786 | dst[2] = in1 & 0b11111000; // red 787 | } 788 | 789 | static void IRAM_ATTR dma_filter_rgb565(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst) 790 | { 791 | assert(s_state->sampling_mode == SM_0A0B_0B0C || 792 | s_state->sampling_mode == SM_0A00_0B00); 793 | 794 | const int unroll = 2; // manually unrolling 2 iterations of the loop 795 | const int samples_per_pixel = 2; 796 | const int bytes_per_pixel = 3; 797 | size_t end = dma_desc->length / sizeof(dma_elem_t) / unroll / samples_per_pixel; 798 | for (size_t i = 0; i < end; ++i) { 799 | rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); 800 | rgb565_to_888(src[2].sample1, src[3].sample1, &dst[3]); 801 | dst += bytes_per_pixel * unroll; 802 | src += samples_per_pixel * unroll; 803 | } 804 | if ((dma_desc->length & 0x7) != 0) { 805 | rgb565_to_888(src[0].sample1, src[1].sample1, &dst[0]); 806 | rgb565_to_888(src[2].sample1, src[2].sample2, &dst[3]); 807 | } 808 | } 809 | -------------------------------------------------------------------------------- /components/camera/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 "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 | typedef void (*dma_filter_t)(const dma_elem_t* src, lldesc_t* dma_desc, uint8_t* dst); 41 | 42 | typedef struct { 43 | camera_config_t config; 44 | sensor_t sensor; 45 | uint8_t *fb; 46 | size_t fb_size; 47 | size_t data_size; 48 | size_t width; 49 | size_t height; 50 | size_t in_bytes_per_pixel; 51 | size_t fb_bytes_per_pixel; 52 | size_t stride; 53 | size_t frame_count; 54 | 55 | lldesc_t *dma_desc; 56 | dma_elem_t **dma_buf; 57 | bool dma_done; 58 | size_t dma_desc_count; 59 | size_t dma_desc_cur; 60 | size_t dma_received_count; 61 | size_t dma_filtered_count; 62 | size_t dma_per_line; 63 | size_t dma_buf_width; 64 | size_t dma_sample_count; 65 | i2s_sampling_mode_t sampling_mode; 66 | dma_filter_t dma_filter; 67 | intr_handle_t i2s_intr_handle; 68 | QueueHandle_t data_ready; 69 | SemaphoreHandle_t frame_ready; 70 | TaskHandle_t dma_filter_task; 71 | } camera_state_t; 72 | 73 | -------------------------------------------------------------------------------- /components/camera/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/components/camera/component.mk -------------------------------------------------------------------------------- /components/camera/include/bitmap.h: -------------------------------------------------------------------------------- 1 | #ifndef _BITMAP_H_ 2 | #define _BITMAP_H_ 3 | #include 4 | 5 | #define _bitsperpixel 24 6 | #define _planes 1 7 | #define _compression 0 8 | #define _xpixelpermeter 0x130B //2835 , 72 DPI 9 | #define _ypixelpermeter 0x130B //2835 , 72 DPI 10 | #define pixel 0xFF 11 | 12 | typedef struct __attribute__((packed, aligned(1))) { 13 | uint8_t signature[2]; 14 | uint32_t filesize; 15 | uint32_t reserved; 16 | uint32_t fileoffset_to_pixelarray; 17 | } fileheader; 18 | typedef struct __attribute__((packed, aligned(1))) { 19 | uint32_t dibheadersize; 20 | uint32_t width; 21 | uint32_t height; 22 | uint16_t planes; 23 | uint16_t bitsperpixel; 24 | uint32_t compression; 25 | uint32_t imagesize; 26 | uint32_t ypixelpermeter; 27 | uint32_t xpixelpermeter; 28 | uint32_t numcolorspallette; 29 | uint32_t mostimpcolor; 30 | } bitmapinfoheader; 31 | typedef struct { 32 | fileheader fileheader; 33 | bitmapinfoheader bitmapinfoheader; 34 | } bitmap_header_t; 35 | 36 | bitmap_header_t *bmp_create_header(int w, int h); 37 | #endif 38 | -------------------------------------------------------------------------------- /components/camera/include/camera.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 | 15 | #pragma once 16 | 17 | #include "esp_err.h" 18 | #include "driver/ledc.h" 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | typedef enum { 25 | CAMERA_PF_RGB565 = 0, //!< RGB, 2 bytes per pixel (not implemented) 26 | CAMERA_PF_YUV422 = 1, //!< YUYV, 2 bytes per pixel (not implemented) 27 | CAMERA_PF_GRAYSCALE = 2, //!< 1 byte per pixel 28 | CAMERA_PF_JPEG = 3, //!< JPEG compressed 29 | } camera_pixelformat_t; 30 | 31 | typedef enum { 32 | CAMERA_FS_QQVGA = 4, //!< 160x120 33 | CAMERA_FS_QVGA = 8, //!< 320x240 34 | CAMERA_FS_VGA = 10, //!< 640x480 35 | CAMERA_FS_SVGA = 11, //!< 800x600 36 | } camera_framesize_t; 37 | 38 | typedef enum { 39 | CAMERA_NONE = 0, 40 | CAMERA_UNKNOWN = 1, 41 | CAMERA_OV7725 = 7725, 42 | CAMERA_OV2640 = 2640, 43 | } camera_model_t; 44 | 45 | typedef struct { 46 | int pin_reset; /*!< GPIO pin for camera reset line */ 47 | int pin_xclk; /*!< GPIO pin for camera XCLK line */ 48 | int pin_sscb_sda; /*!< GPIO pin for camera SDA line */ 49 | int pin_sscb_scl; /*!< GPIO pin for camera SCL line */ 50 | int pin_d7; /*!< GPIO pin for camera D7 line */ 51 | int pin_d6; /*!< GPIO pin for camera D6 line */ 52 | int pin_d5; /*!< GPIO pin for camera D5 line */ 53 | int pin_d4; /*!< GPIO pin for camera D4 line */ 54 | int pin_d3; /*!< GPIO pin for camera D3 line */ 55 | int pin_d2; /*!< GPIO pin for camera D2 line */ 56 | int pin_d1; /*!< GPIO pin for camera D1 line */ 57 | int pin_d0; /*!< GPIO pin for camera D0 line */ 58 | int pin_vsync; /*!< GPIO pin for camera VSYNC line */ 59 | int pin_href; /*!< GPIO pin for camera HREF line */ 60 | int pin_pclk; /*!< GPIO pin for camera PCLK line */ 61 | 62 | int xclk_freq_hz; /*!< Frequency of XCLK signal, in Hz */ 63 | 64 | ledc_timer_t ledc_timer; /*!< LEDC timer to be used for generating XCLK */ 65 | ledc_channel_t ledc_channel; /*!< LEDC channel to be used for generating XCLK */ 66 | 67 | camera_pixelformat_t pixel_format; 68 | camera_framesize_t frame_size; 69 | 70 | int jpeg_quality; 71 | } camera_config_t; 72 | 73 | #define ESP_ERR_CAMERA_BASE 0x20000 74 | #define ESP_ERR_CAMERA_NOT_DETECTED (ESP_ERR_CAMERA_BASE + 1) 75 | #define ESP_ERR_CAMERA_FAILED_TO_SET_FRAME_SIZE (ESP_ERR_CAMERA_BASE + 2) 76 | #define ESP_ERR_CAMERA_NOT_SUPPORTED (ESP_ERR_CAMERA_BASE + 3) 77 | 78 | /** 79 | * @brief Probe the camera 80 | * This function enables LEDC peripheral to generate XCLK signal, 81 | * detects the camera I2C address and detects camera model. 82 | * 83 | * @param config camera configuration parameters 84 | * @param[out] out_camera_model output, detected camera model 85 | * @return ESP_OK if camera was detected 86 | */ 87 | esp_err_t camera_probe(const camera_config_t* config, camera_model_t* out_camera_model); 88 | 89 | /** 90 | * @brief Initialize the camera driver 91 | * 92 | * @note call camera_probe before calling this function 93 | * 94 | * This function configures camera over I2C interface, 95 | * allocates framebuffer and DMA buffers, 96 | * initializes parallel I2S input, and sets up DMA descriptors. 97 | * 98 | * Currently this function can only be called once and there is 99 | * no way to de-initialize this module. 100 | * 101 | * @param config Camera configuration parameters 102 | * @return ESP_OK on success 103 | */ 104 | esp_err_t camera_init(const camera_config_t* config); 105 | 106 | /** 107 | * Deinitialize the camera driver 108 | * 109 | * @return 110 | * - ESP_OK on success 111 | * - ESP_ERR_INVALID_STATE if the driver hasn't been initialized yet 112 | */ 113 | esp_err_t camera_deinit(); 114 | 115 | /** 116 | * @brief Obtain the pointer to framebuffer allocated by camera_init function. 117 | * 118 | * @return pointer to framebuffer 119 | */ 120 | uint8_t* camera_get_fb(); 121 | 122 | /** 123 | * @brief Return the size of valid data in the framebuffer 124 | * 125 | * For grayscale mode, this function returns width * height of the framebuffer. 126 | * For JPEG mode, this function returns the actual size of encoded JPEG image. 127 | * @return size of valid data in framebuffer, in bytes 128 | */ 129 | size_t camera_get_data_size(); 130 | 131 | /** 132 | * @brief Get the width of framebuffer, in pixels. 133 | * @return width of framebuffer, in pixels 134 | */ 135 | int camera_get_fb_width(); 136 | 137 | /** 138 | * @brief Get the height of framebuffer, in pixels. 139 | * @return height of framebuffer, in pixels 140 | */ 141 | int camera_get_fb_height(); 142 | 143 | /** 144 | * @brief Acquire one frame and store it into framebuffer 145 | * 146 | * This function waits for the next VSYNC, starts DMA to get data from camera, 147 | * and blocks until all lines of the image are stored into the framebuffer. 148 | * Once all lines are stored, the function returns. 149 | * 150 | * @return ESP_OK on success 151 | */ 152 | esp_err_t camera_run(); 153 | 154 | /** 155 | * @brief Print contents of framebuffer on terminal 156 | * 157 | */ 158 | void camera_print_fb(); 159 | 160 | 161 | #ifdef __cplusplus 162 | } 163 | #endif 164 | -------------------------------------------------------------------------------- /components/camera/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 | 16 | #define SVGA_HSIZE (800) 17 | #define SVGA_VSIZE (600) 18 | 19 | #define UXGA_HSIZE (1600) 20 | #define UXGA_VSIZE (1200) 21 | 22 | static const uint8_t default_regs[][2] = { 23 | { BANK_SEL, BANK_SEL_DSP }, 24 | { 0x2c, 0xff }, 25 | { 0x2e, 0xdf }, 26 | { BANK_SEL, BANK_SEL_SENSOR }, 27 | { 0x3c, 0x32 }, 28 | { CLKRC, 0x80 }, /* Set PCLK divider */ 29 | { COM2, COM2_OUT_DRIVE_3x }, /* Output drive x2 */ 30 | #ifdef OPENMV2 31 | { REG04, 0xF8}, /* Mirror/VFLIP/AEC[1:0] */ 32 | #else 33 | { REG04_SET(REG04_HREF_EN)}, 34 | #endif 35 | { COM8, COM8_SET(COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN) }, 36 | { COM9, COM9_AGC_SET(COM9_AGC_GAIN_8x)}, 37 | {COM10, 0}, //Invert VSYNC 38 | { 0x2c, 0x0c }, 39 | { 0x33, 0x78 }, 40 | { 0x3a, 0x33 }, 41 | { 0x3b, 0xfb }, 42 | { 0x3e, 0x00 }, 43 | { 0x43, 0x11 }, 44 | { 0x16, 0x10 }, 45 | { 0x39, 0x02 }, 46 | { 0x35, 0x88 }, 47 | { 0x22, 0x0a }, 48 | { 0x37, 0x40 }, 49 | { 0x23, 0x00 }, 50 | { ARCOM2, 0xa0 }, 51 | { 0x06, 0x02 }, 52 | { 0x06, 0x88 }, 53 | { 0x07, 0xc0 }, 54 | { 0x0d, 0xb7 }, 55 | { 0x0e, 0x01 }, 56 | { 0x4c, 0x00 }, 57 | { 0x4a, 0x81 }, 58 | { 0x21, 0x99 }, 59 | { AEW, 0x40 }, 60 | { AEB, 0x38 }, 61 | /* AGC/AEC fast mode operating region */ 62 | { VV, VV_AGC_TH_SET(0x08, 0x02) }, 63 | { COM19, 0x00 }, /* Zoom control 2 MSBs */ 64 | { ZOOMS, 0x00 }, /* Zoom control 8 MSBs */ 65 | { 0x5c, 0x00 }, 66 | { 0x63, 0x00 }, 67 | { FLL, 0x00 }, 68 | { FLH, 0x00 }, 69 | 70 | /* Set banding filter */ 71 | { COM3, COM3_BAND_SET(COM3_BAND_AUTO) }, 72 | { REG5D, 0x55 }, 73 | { REG5E, 0x7d }, 74 | { REG5F, 0x7d }, 75 | { REG60, 0x55 }, 76 | { HISTO_LOW, 0x70 }, 77 | { HISTO_HIGH, 0x80 }, 78 | { 0x7c, 0x05 }, 79 | { 0x20, 0x80 }, 80 | { 0x28, 0x30 }, 81 | { 0x6c, 0x00 }, 82 | { 0x6d, 0x80 }, 83 | { 0x6e, 0x00 }, 84 | { 0x70, 0x02 }, 85 | { 0x71, 0x94 }, 86 | { 0x73, 0xc1 }, 87 | { 0x3d, 0x34 }, 88 | //{ COM7, COM7_RES_UXGA | COM7_ZOOM_EN }, 89 | { 0x5a, 0x57 }, 90 | { BD50, 0xbb }, 91 | { BD60, 0x9c }, 92 | 93 | { BANK_SEL, BANK_SEL_DSP }, 94 | { 0xe5, 0x7f }, 95 | { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL }, 96 | { 0x41, 0x24 }, 97 | { RESET, RESET_JPEG | RESET_DVP }, 98 | { 0x76, 0xff }, 99 | { 0x33, 0xa0 }, 100 | { 0x42, 0x20 }, 101 | { 0x43, 0x18 }, 102 | { 0x4c, 0x00 }, 103 | { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 }, 104 | { 0x88, 0x3f }, 105 | { 0xd7, 0x03 }, 106 | { 0xd9, 0x10 }, 107 | { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 }, 108 | { 0xc8, 0x08 }, 109 | { 0xc9, 0x80 }, 110 | { BPADDR, 0x00 }, 111 | { BPDATA, 0x00 }, 112 | { BPADDR, 0x03 }, 113 | { BPDATA, 0x48 }, 114 | { BPDATA, 0x48 }, 115 | { BPADDR, 0x08 }, 116 | { BPDATA, 0x20 }, 117 | { BPDATA, 0x10 }, 118 | { BPDATA, 0x0e }, 119 | { 0x90, 0x00 }, 120 | { 0x91, 0x0e }, 121 | { 0x91, 0x1a }, 122 | { 0x91, 0x31 }, 123 | { 0x91, 0x5a }, 124 | { 0x91, 0x69 }, 125 | { 0x91, 0x75 }, 126 | { 0x91, 0x7e }, 127 | { 0x91, 0x88 }, 128 | { 0x91, 0x8f }, 129 | { 0x91, 0x96 }, 130 | { 0x91, 0xa3 }, 131 | { 0x91, 0xaf }, 132 | { 0x91, 0xc4 }, 133 | { 0x91, 0xd7 }, 134 | { 0x91, 0xe8 }, 135 | { 0x91, 0x20 }, 136 | { 0x92, 0x00 }, 137 | { 0x93, 0x06 }, 138 | { 0x93, 0xe3 }, 139 | { 0x93, 0x03 }, 140 | { 0x93, 0x03 }, 141 | { 0x93, 0x00 }, 142 | { 0x93, 0x02 }, 143 | { 0x93, 0x00 }, 144 | { 0x93, 0x00 }, 145 | { 0x93, 0x00 }, 146 | { 0x93, 0x00 }, 147 | { 0x93, 0x00 }, 148 | { 0x93, 0x00 }, 149 | { 0x93, 0x00 }, 150 | { 0x96, 0x00 }, 151 | { 0x97, 0x08 }, 152 | { 0x97, 0x19 }, 153 | { 0x97, 0x02 }, 154 | { 0x97, 0x0c }, 155 | { 0x97, 0x24 }, 156 | { 0x97, 0x30 }, 157 | { 0x97, 0x28 }, 158 | { 0x97, 0x26 }, 159 | { 0x97, 0x02 }, 160 | { 0x97, 0x98 }, 161 | { 0x97, 0x80 }, 162 | { 0x97, 0x00 }, 163 | { 0x97, 0x00 }, 164 | { 0xa4, 0x00 }, 165 | { 0xa8, 0x00 }, 166 | { 0xc5, 0x11 }, 167 | { 0xc6, 0x51 }, 168 | { 0xbf, 0x80 }, 169 | { 0xc7, 0x10 }, 170 | { 0xb6, 0x66 }, 171 | { 0xb8, 0xA5 }, 172 | { 0xb7, 0x64 }, 173 | { 0xb9, 0x7C }, 174 | { 0xb3, 0xaf }, 175 | { 0xb4, 0x97 }, 176 | { 0xb5, 0xFF }, 177 | { 0xb0, 0xC5 }, 178 | { 0xb1, 0x94 }, 179 | { 0xb2, 0x0f }, 180 | { 0xc4, 0x5c }, 181 | { 0xa6, 0x00 }, 182 | { 0xa7, 0x20 }, 183 | { 0xa7, 0xd8 }, 184 | { 0xa7, 0x1b }, 185 | { 0xa7, 0x31 }, 186 | { 0xa7, 0x00 }, 187 | { 0xa7, 0x18 }, 188 | { 0xa7, 0x20 }, 189 | { 0xa7, 0xd8 }, 190 | { 0xa7, 0x19 }, 191 | { 0xa7, 0x31 }, 192 | { 0xa7, 0x00 }, 193 | { 0xa7, 0x18 }, 194 | { 0xa7, 0x20 }, 195 | { 0xa7, 0xd8 }, 196 | { 0xa7, 0x19 }, 197 | { 0xa7, 0x31 }, 198 | { 0xa7, 0x00 }, 199 | { 0xa7, 0x18 }, 200 | { 0x7f, 0x00 }, 201 | { 0xe5, 0x1f }, 202 | { 0xe1, 0x77 }, 203 | { 0xdd, 0x7f }, 204 | { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN }, 205 | { 0x00, 0x00 } 206 | }; 207 | 208 | static const uint8_t cif_regs[][2] = { 209 | }; 210 | 211 | static const uint8_t svga_regs[][2] = { 212 | { BANK_SEL, BANK_SEL_SENSOR }, 213 | /* DSP input image resoultion and window size control */ 214 | { COM7, COM7_RES_SVGA}, 215 | { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ 216 | { REG32, 0x09 }, /* UXGA=0x36, SVGA/CIF=0x09 */ 217 | 218 | { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ 219 | { HSTOP, 0x43 }, /* UXGA=0x75, SVGA/CIF=0x43 */ 220 | 221 | { VSTART, 0x00 }, /* UXGA=0x01, SVGA/CIF=0x00 */ 222 | { VSTOP, 0x4b }, /* UXGA=0x97, SVGA/CIF=0x4b */ 223 | { 0x3d, 0x38 }, /* UXGA=0x34, SVGA/CIF=0x38 */ 224 | 225 | { 0x35, 0xda }, 226 | { 0x22, 0x1a }, 227 | { 0x37, 0xc3 }, 228 | { 0x34, 0xc0 }, 229 | { 0x06, 0x88 }, 230 | { 0x0d, 0x87 }, 231 | { 0x0e, 0x41 }, 232 | { 0x42, 0x03 }, 233 | 234 | /* Set DSP input image size and offset. 235 | The sensor output image can be scaled with OUTW/OUTH */ 236 | { BANK_SEL, BANK_SEL_DSP }, 237 | { R_BYPASS, R_BYPASS_DSP_BYPAS }, 238 | 239 | { RESET, RESET_DVP }, 240 | { HSIZE8, (SVGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ 241 | { VSIZE8, (SVGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ 242 | 243 | /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ 244 | { SIZEL, ((SVGA_HSIZE>>6)&0x40) | ((SVGA_HSIZE&0x7)<<3) | (SVGA_VSIZE&0x7)}, 245 | 246 | { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ 247 | { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ 248 | { HSIZE, ((SVGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0]= HSIZE/4 */ 249 | { VSIZE, ((SVGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0]= VSIZE/4 */ 250 | 251 | /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ 252 | { VHYX, ((SVGA_VSIZE>>3)&0x80) | ((SVGA_HSIZE>>7)&0x08) }, 253 | { TEST, (SVGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ 254 | 255 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 256 | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 257 | 258 | /* H_DIVIDER/V_DIVIDER */ 259 | { CTRLI, CTRLI_LP_DP | 0x00}, 260 | /* DVP prescalar */ 261 | { R_DVP_SP, R_DVP_SP_AUTO_MODE}, 262 | 263 | { R_BYPASS, R_BYPASS_DSP_EN }, 264 | { RESET, 0x00 }, 265 | {0, 0}, 266 | }; 267 | 268 | static const uint8_t uxga_regs[][2] = { 269 | { BANK_SEL, BANK_SEL_SENSOR }, 270 | /* DSP input image resoultion and window size control */ 271 | { COM7, COM7_RES_UXGA}, 272 | { COM1, 0x0F }, /* UXGA=0x0F, SVGA=0x0A, CIF=0x06 */ 273 | { REG32, 0x36 }, /* UXGA=0x36, SVGA/CIF=0x09 */ 274 | 275 | { HSTART, 0x11 }, /* UXGA=0x11, SVGA/CIF=0x11 */ 276 | { HSTOP, 0x75 }, /* UXGA=0x75, SVGA/CIF=0x43 */ 277 | 278 | { VSTART, 0x01 }, /* UXGA=0x01, SVGA/CIF=0x00 */ 279 | { VSTOP, 0x97 }, /* UXGA=0x97, SVGA/CIF=0x4b */ 280 | { 0x3d, 0x34 }, /* UXGA=0x34, SVGA/CIF=0x38 */ 281 | 282 | { 0x35, 0x88 }, 283 | { 0x22, 0x0a }, 284 | { 0x37, 0x40 }, 285 | { 0x34, 0xa0 }, 286 | { 0x06, 0x02 }, 287 | { 0x0d, 0xb7 }, 288 | { 0x0e, 0x01 }, 289 | { 0x42, 0x83 }, 290 | 291 | /* Set DSP input image size and offset. 292 | The sensor output image can be scaled with OUTW/OUTH */ 293 | { BANK_SEL, BANK_SEL_DSP }, 294 | { R_BYPASS, R_BYPASS_DSP_BYPAS }, 295 | 296 | { RESET, RESET_DVP }, 297 | { HSIZE8, (UXGA_HSIZE>>3)}, /* Image Horizontal Size HSIZE[10:3] */ 298 | { VSIZE8, (UXGA_VSIZE>>3)}, /* Image Vertiacl Size VSIZE[10:3] */ 299 | 300 | /* {HSIZE[11], HSIZE[2:0], VSIZE[2:0]} */ 301 | { SIZEL, ((UXGA_HSIZE>>6)&0x40) | ((UXGA_HSIZE&0x7)<<3) | (UXGA_VSIZE&0x7)}, 302 | 303 | { XOFFL, 0x00 }, /* OFFSET_X[7:0] */ 304 | { YOFFL, 0x00 }, /* OFFSET_Y[7:0] */ 305 | { HSIZE, ((UXGA_HSIZE>>2)&0xFF) }, /* H_SIZE[7:0] real/4 */ 306 | { VSIZE, ((UXGA_VSIZE>>2)&0xFF) }, /* V_SIZE[7:0] real/4 */ 307 | 308 | /* V_SIZE[8]/OFFSET_Y[10:8]/H_SIZE[8]/OFFSET_X[10:8] */ 309 | { VHYX, ((UXGA_VSIZE>>3)&0x80) | ((UXGA_HSIZE>>7)&0x08) }, 310 | { TEST, (UXGA_HSIZE>>4)&0x80}, /* H_SIZE[9] */ 311 | 312 | { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN | 313 | CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN }, 314 | 315 | /* H_DIVIDER/V_DIVIDER */ 316 | { CTRLI, CTRLI_LP_DP | 0x00}, 317 | /* DVP prescalar */ 318 | { R_DVP_SP, R_DVP_SP_AUTO_MODE | 0x04}, 319 | 320 | { R_BYPASS, R_BYPASS_DSP_EN }, 321 | { RESET, 0x00 }, 322 | {0, 0}, 323 | }; 324 | 325 | static const uint8_t yuv422_regs[][2] = { 326 | { BANK_SEL, BANK_SEL_DSP }, 327 | { RESET, RESET_DVP}, 328 | { IMAGE_MODE, IMAGE_MODE_YUV422 }, 329 | { 0xD7, 0x01 }, 330 | { 0xE1, 0x67 }, 331 | { RESET, 0x00 }, 332 | {0, 0}, 333 | }; 334 | 335 | static const uint8_t rgb565_regs[][2] = { 336 | { BANK_SEL, BANK_SEL_DSP }, 337 | { RESET, RESET_DVP}, 338 | { IMAGE_MODE, IMAGE_MODE_RGB565 }, 339 | { 0xD7, 0x03 }, 340 | { 0xE1, 0x77 }, 341 | { RESET, 0x00 }, 342 | {0, 0}, 343 | }; 344 | 345 | static const uint8_t jpeg_regs[][2] = { 346 | { BANK_SEL, BANK_SEL_DSP }, 347 | { RESET, RESET_DVP}, 348 | { IMAGE_MODE, IMAGE_MODE_JPEG_EN|IMAGE_MODE_RGB565 }, 349 | { 0xD7, 0x03 }, 350 | { 0xE1, 0x77 }, 351 | { QS, 0x0C }, 352 | { RESET, 0x00 }, 353 | {0, 0}, 354 | }; 355 | 356 | //|IMAGE_MODE_HREF_VSYNC 357 | 358 | #define NUM_BRIGHTNESS_LEVELS (5) 359 | static const uint8_t brightness_regs[NUM_BRIGHTNESS_LEVELS + 1][5] = { 360 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 361 | { 0x00, 0x04, 0x09, 0x00, 0x00 }, /* -2 */ 362 | { 0x00, 0x04, 0x09, 0x10, 0x00 }, /* -1 */ 363 | { 0x00, 0x04, 0x09, 0x20, 0x00 }, /* 0 */ 364 | { 0x00, 0x04, 0x09, 0x30, 0x00 }, /* +1 */ 365 | { 0x00, 0x04, 0x09, 0x40, 0x00 }, /* +2 */ 366 | }; 367 | 368 | #define NUM_CONTRAST_LEVELS (5) 369 | static const uint8_t contrast_regs[NUM_CONTRAST_LEVELS + 1][7] = { 370 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA, BPDATA, BPDATA }, 371 | { 0x00, 0x04, 0x07, 0x20, 0x18, 0x34, 0x06 }, /* -2 */ 372 | { 0x00, 0x04, 0x07, 0x20, 0x1c, 0x2a, 0x06 }, /* -1 */ 373 | { 0x00, 0x04, 0x07, 0x20, 0x20, 0x20, 0x06 }, /* 0 */ 374 | { 0x00, 0x04, 0x07, 0x20, 0x24, 0x16, 0x06 }, /* +1 */ 375 | { 0x00, 0x04, 0x07, 0x20, 0x28, 0x0c, 0x06 }, /* +2 */ 376 | }; 377 | 378 | #define NUM_SATURATION_LEVELS (5) 379 | static const uint8_t saturation_regs[NUM_SATURATION_LEVELS + 1][5] = { 380 | { BPADDR, BPDATA, BPADDR, BPDATA, BPDATA }, 381 | { 0x00, 0x02, 0x03, 0x28, 0x28 }, /* -2 */ 382 | { 0x00, 0x02, 0x03, 0x38, 0x38 }, /* -1 */ 383 | { 0x00, 0x02, 0x03, 0x48, 0x48 }, /* 0 */ 384 | { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +1 */ 385 | { 0x00, 0x02, 0x03, 0x58, 0x58 }, /* +2 */ 386 | }; 387 | 388 | static int reset(sensor_t *sensor) 389 | { 390 | int i=0; 391 | const uint8_t (*regs)[2]; 392 | 393 | /* Reset all registers */ 394 | SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 395 | SCCB_Write(sensor->slv_addr, COM7, COM7_SRST); 396 | 397 | /* delay n ms */ 398 | delay(10); 399 | 400 | i = 0; 401 | regs = default_regs; 402 | /* Write initial regsiters */ 403 | while (regs[i][0]) { 404 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 405 | i++; 406 | } 407 | 408 | i = 0; 409 | regs = svga_regs; 410 | /* Write DSP input regsiters */ 411 | while (regs[i][0]) { 412 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 413 | i++; 414 | } 415 | 416 | return 0; 417 | } 418 | 419 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) 420 | { 421 | int i=0; 422 | const uint8_t (*regs)[2]=NULL; 423 | 424 | /* read pixel format reg */ 425 | switch (pixformat) { 426 | case PIXFORMAT_RGB565: 427 | regs = rgb565_regs; 428 | break; 429 | case PIXFORMAT_YUV422: 430 | case PIXFORMAT_GRAYSCALE: 431 | regs = yuv422_regs; 432 | break; 433 | case PIXFORMAT_JPEG: 434 | regs = jpeg_regs; 435 | break; 436 | default: 437 | return -1; 438 | } 439 | 440 | /* Write initial regsiters */ 441 | while (regs[i][0]) { 442 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 443 | i++; 444 | } 445 | 446 | /* delay n ms */ 447 | delay(30); 448 | 449 | return 0; 450 | } 451 | 452 | static int set_framesize(sensor_t *sensor, framesize_t framesize) 453 | { 454 | int ret=0; 455 | uint8_t clkrc; 456 | uint16_t w = resolution[framesize][0]; 457 | uint16_t h = resolution[framesize][1]; 458 | 459 | int i=0; 460 | const uint8_t (*regs)[2]; 461 | 462 | if (framesize <= FRAMESIZE_SVGA) { 463 | clkrc =0x83; 464 | regs = svga_regs; 465 | } else { 466 | clkrc =0x87; 467 | regs = uxga_regs; 468 | } 469 | 470 | /* Disable DSP */ 471 | 472 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 473 | ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_BYPAS); 474 | 475 | /* Write output width */ 476 | ret |= SCCB_Write(sensor->slv_addr, ZMOW, (w>>2)&0xFF); // OUTW[7:0] (real/4) 477 | ret |= SCCB_Write(sensor->slv_addr, ZMOH, (h>>2)&0xFF); // OUTH[7:0] (real/4) 478 | ret |= SCCB_Write(sensor->slv_addr, ZMHH, ((h>>8)&0x04)|((w>>10)&0x03)); // OUTH[8]/OUTW[9:8] 479 | 480 | /* Set CLKRC */ 481 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 482 | ret |= SCCB_Write(sensor->slv_addr, CLKRC, clkrc); 483 | 484 | /* Write DSP input regsiters */ 485 | while (regs[i][0]) { 486 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 487 | i++; 488 | } 489 | 490 | /* Enable DSP */ 491 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 492 | ret |= SCCB_Write(sensor->slv_addr, R_BYPASS, R_BYPASS_DSP_EN); 493 | /* delay n ms */ 494 | delay(30); 495 | 496 | return ret; 497 | } 498 | 499 | static int set_framerate(sensor_t *sensor, framerate_t framerate) 500 | { 501 | return 0; 502 | } 503 | 504 | static int set_contrast(sensor_t *sensor, int level) 505 | { 506 | int ret=0; 507 | 508 | level += (NUM_CONTRAST_LEVELS / 2 + 1); 509 | if (level < 0 || level > NUM_CONTRAST_LEVELS) { 510 | return -1; 511 | } 512 | 513 | /* Switch to DSP register bank */ 514 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 515 | 516 | /* Write contrast registers */ 517 | for (int i=0; islv_addr, contrast_regs[0][i], contrast_regs[level][i]); 519 | } 520 | 521 | return ret; 522 | } 523 | 524 | static int set_brightness(sensor_t *sensor, int level) 525 | { 526 | int ret=0; 527 | 528 | level += (NUM_BRIGHTNESS_LEVELS / 2 + 1); 529 | if (level < 0 || level > NUM_BRIGHTNESS_LEVELS) { 530 | return -1; 531 | } 532 | 533 | /* Switch to DSP register bank */ 534 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 535 | 536 | /* Write brightness registers */ 537 | for (int i=0; islv_addr, brightness_regs[0][i], brightness_regs[level][i]); 539 | } 540 | 541 | return ret; 542 | } 543 | 544 | static int set_saturation(sensor_t *sensor, int level) 545 | { 546 | int ret=0; 547 | 548 | level += (NUM_SATURATION_LEVELS / 2 + 1); 549 | if (level < 0 || level > NUM_SATURATION_LEVELS) { 550 | return -1; 551 | } 552 | 553 | /* Switch to DSP register bank */ 554 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 555 | 556 | /* Write contrast registers */ 557 | for (int i=0; islv_addr, saturation_regs[0][i], saturation_regs[level][i]); 559 | } 560 | 561 | return ret; 562 | } 563 | 564 | static int set_gainceiling(sensor_t *sensor, gainceiling_t gainceiling) 565 | { 566 | int ret =0; 567 | 568 | /* Switch to SENSOR register bank */ 569 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 570 | 571 | /* Write gain ceiling register */ 572 | ret |= SCCB_Write(sensor->slv_addr, COM9, COM9_AGC_SET(gainceiling)); 573 | 574 | return ret; 575 | } 576 | 577 | static int set_quality(sensor_t *sensor, int qs) 578 | { 579 | int ret=0; 580 | 581 | /* Switch to DSP register bank */ 582 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 583 | 584 | /* Write QS register */ 585 | ret |= SCCB_Write(sensor->slv_addr, QS, qs); 586 | 587 | return ret; 588 | } 589 | 590 | static int set_colorbar(sensor_t *sensor, int enable) 591 | { 592 | int ret=0; 593 | uint8_t reg; 594 | 595 | /* Switch to SENSOR register bank */ 596 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 597 | 598 | /* Update COM7 */ 599 | reg = SCCB_Read(sensor->slv_addr, COM7); 600 | 601 | if (enable) { 602 | reg |= COM7_COLOR_BAR; 603 | } else { 604 | reg &= ~COM7_COLOR_BAR; 605 | } 606 | 607 | ret |= SCCB_Write(sensor->slv_addr, COM7, reg); 608 | return ret; 609 | } 610 | 611 | static int set_whitebal(sensor_t *sensor, int enable) 612 | { 613 | int ret=0; 614 | uint8_t reg; 615 | 616 | /* Switch to SENSOR register bank */ 617 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_DSP); 618 | 619 | /* Update CTRL1 */ 620 | reg = SCCB_Read(sensor->slv_addr, CTRL1); 621 | 622 | if (enable) { 623 | reg |= CTRL1_AWB; 624 | } else { 625 | reg &= ~CTRL1_AWB; 626 | } 627 | 628 | ret |= SCCB_Write(sensor->slv_addr, CTRL1, reg); 629 | return ret; 630 | } 631 | 632 | static int set_gain_ctrl(sensor_t *sensor, int enable) 633 | { 634 | int ret=0; 635 | uint8_t reg; 636 | 637 | /* Switch to SENSOR register bank */ 638 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 639 | 640 | /* Update COM8 */ 641 | reg = SCCB_Read(sensor->slv_addr, COM8); 642 | 643 | if (enable) { 644 | reg |= COM8_AGC_EN; 645 | } else { 646 | reg &= ~COM8_AGC_EN; 647 | } 648 | 649 | ret |= SCCB_Write(sensor->slv_addr, COM8, reg); 650 | return ret; 651 | } 652 | 653 | static int set_exposure_ctrl(sensor_t *sensor, int enable) 654 | { 655 | int ret=0; 656 | uint8_t reg; 657 | 658 | /* Switch to SENSOR register bank */ 659 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 660 | 661 | /* Update COM8 */ 662 | reg = SCCB_Read(sensor->slv_addr, COM8); 663 | 664 | if (enable) { 665 | reg |= COM8_AEC_EN; 666 | } else { 667 | reg &= ~COM8_AEC_EN; 668 | } 669 | 670 | ret |= SCCB_Write(sensor->slv_addr, COM8, reg); 671 | return ret; 672 | } 673 | 674 | static int set_hmirror(sensor_t *sensor, int enable) 675 | { 676 | int ret=0; 677 | uint8_t reg; 678 | 679 | /* Switch to SENSOR register bank */ 680 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 681 | 682 | /* Update REG04 */ 683 | reg = SCCB_Read(sensor->slv_addr, REG04); 684 | 685 | if (enable) { 686 | reg |= REG04_HFLIP_IMG; 687 | } else { 688 | reg &= ~REG04_HFLIP_IMG; 689 | } 690 | 691 | ret |= SCCB_Write(sensor->slv_addr, REG04, reg); 692 | return ret; 693 | } 694 | 695 | static int set_vflip(sensor_t *sensor, int enable) 696 | { 697 | int ret=0; 698 | uint8_t reg; 699 | 700 | /* Switch to SENSOR register bank */ 701 | ret |= SCCB_Write(sensor->slv_addr, BANK_SEL, BANK_SEL_SENSOR); 702 | 703 | /* Update REG04 */ 704 | reg = SCCB_Read(sensor->slv_addr, REG04); 705 | 706 | if (enable) { 707 | reg |= REG04_VFLIP_IMG; 708 | } else { 709 | reg &= ~REG04_VFLIP_IMG; 710 | } 711 | 712 | ret |= SCCB_Write(sensor->slv_addr, REG04, reg); 713 | return ret; 714 | } 715 | 716 | int ov2640_init(sensor_t *sensor) 717 | { 718 | /* set function pointers */ 719 | sensor->reset = reset; 720 | sensor->set_pixformat = set_pixformat; 721 | sensor->set_framesize = set_framesize; 722 | sensor->set_framerate = set_framerate; 723 | sensor->set_contrast = set_contrast; 724 | sensor->set_brightness= set_brightness; 725 | sensor->set_saturation= set_saturation; 726 | sensor->set_gainceiling = set_gainceiling; 727 | sensor->set_quality = set_quality; 728 | sensor->set_colorbar = set_colorbar; 729 | sensor->set_gain_ctrl = set_gain_ctrl; 730 | sensor->set_exposure_ctrl = set_exposure_ctrl; 731 | sensor->set_whitebal = set_whitebal; 732 | sensor->set_hmirror = set_hmirror; 733 | sensor->set_vflip = set_vflip; 734 | 735 | // Set sensor flags 736 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); 737 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); 738 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); 739 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); 740 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); 741 | 742 | return 0; 743 | } 744 | -------------------------------------------------------------------------------- /components/camera/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/camera/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 QS 0x44 12 | #define HSIZE 0x51 13 | #define VSIZE 0x52 14 | #define XOFFL 0x53 15 | #define YOFFL 0x54 16 | #define VHYX 0x55 17 | #define DPRP 0x56 18 | #define TEST 0x57 19 | #define ZMOW 0x5A 20 | #define ZMOH 0x5B 21 | #define ZMHH 0x5C 22 | #define BPADDR 0x7C 23 | #define BPDATA 0x7D 24 | #define SIZEL 0x8C 25 | #define HSIZE8 0xC0 26 | #define VSIZE8 0xC1 27 | #define CTRL1 0xC3 28 | #define MS_SP 0xF0 29 | #define SS_ID 0xF7 30 | #define SS_CTRL 0xF7 31 | #define MC_AL 0xFA 32 | #define MC_AH 0xFB 33 | #define MC_D 0xFC 34 | #define P_CMD 0xFD 35 | #define P_STATUS 0xFE 36 | 37 | #define CTRLI 0x50 38 | #define CTRLI_LP_DP 0x80 39 | #define CTRLI_ROUND 0x40 40 | 41 | #define CTRL0 0xC2 42 | #define CTRL0_AEC_EN 0x80 43 | #define CTRL0_AEC_SEL 0x40 44 | #define CTRL0_STAT_SEL 0x20 45 | #define CTRL0_VFIRST 0x10 46 | #define CTRL0_YUV422 0x08 47 | #define CTRL0_YUV_EN 0x04 48 | #define CTRL0_RGB_EN 0x02 49 | #define CTRL0_RAW_EN 0x01 50 | 51 | #define CTRL2 0x86 52 | #define CTRL2_DCW_EN 0x20 53 | #define CTRL2_SDE_EN 0x10 54 | #define CTRL2_UV_ADJ_EN 0x08 55 | #define CTRL2_UV_AVG_EN 0x04 56 | #define CTRL2_CMX_EN 0x01 57 | 58 | #define CTRL3 0x87 59 | #define CTRL3_BPC_EN 0x80 60 | #define CTRL3_WPC_EN 0x40 61 | #define R_DVP_SP 0xD3 62 | #define R_DVP_SP_AUTO_MODE 0x80 63 | 64 | #define R_BYPASS 0x05 65 | #define R_BYPASS_DSP_EN 0x00 66 | #define R_BYPASS_DSP_BYPAS 0x01 67 | 68 | #define IMAGE_MODE 0xDA 69 | #define IMAGE_MODE_Y8_DVP_EN 0x40 70 | #define IMAGE_MODE_JPEG_EN 0x10 71 | #define IMAGE_MODE_YUV422 0x00 72 | #define IMAGE_MODE_RAW10 0x04 73 | #define IMAGE_MODE_RGB565 0x08 74 | #define IMAGE_MODE_HREF_VSYNC 0x02 75 | #define IMAGE_MODE_LBYTE_FIRST 0x01 76 | 77 | #define RESET 0xE0 78 | #define RESET_MICROC 0x40 79 | #define RESET_SCCB 0x20 80 | #define RESET_JPEG 0x10 81 | #define RESET_DVP 0x04 82 | #define RESET_IPU 0x02 83 | #define RESET_CIF 0x01 84 | 85 | #define MC_BIST 0xF9 86 | #define MC_BIST_RESET 0x80 87 | #define MC_BIST_BOOT_ROM_SEL 0x40 88 | #define MC_BIST_12KB_SEL 0x20 89 | #define MC_BIST_12KB_MASK 0x30 90 | #define MC_BIST_512KB_SEL 0x08 91 | #define MC_BIST_512KB_MASK 0x0C 92 | #define MC_BIST_BUSY_BIT_R 0x02 93 | #define MC_BIST_MC_RES_ONE_SH_W 0x02 94 | #define MC_BIST_LAUNCH 0x01 95 | 96 | #define BANK_SEL 0xFF 97 | #define BANK_SEL_DSP 0x00 98 | #define BANK_SEL_SENSOR 0x01 99 | 100 | /* Sensor register bank FF=0x01*/ 101 | #define GAIN 0x00 102 | #define COM1 0x03 103 | #define REG_PID 0x0A 104 | #define REG_VER 0x0B 105 | #define COM4 0x0D 106 | #define AEC 0x10 107 | #define CLKRC 0x11 108 | #define COM10 0x15 109 | #define HSTART 0x17 110 | #define HSTOP 0x18 111 | #define VSTART 0x19 112 | #define VSTOP 0x1A 113 | #define MIDH 0x1C 114 | #define MIDL 0x1D 115 | #define AEW 0x24 116 | #define AEB 0x25 117 | #define REG2A 0x2A 118 | #define FRARL 0x2B 119 | #define ADDVSL 0x2D 120 | #define ADDVSH 0x2E 121 | #define YAVG 0x2F 122 | #define HSDY 0x30 123 | #define HEDY 0x31 124 | #define ARCOM2 0x34 125 | #define REG45 0x45 126 | #define FLL 0x46 127 | #define FLH 0x47 128 | #define COM19 0x48 129 | #define ZOOMS 0x49 130 | #define COM22 0x4B 131 | #define COM25 0x4E 132 | #define BD50 0x4F 133 | #define BD60 0x50 134 | #define REG5D 0x5D 135 | #define REG5E 0x5E 136 | #define REG5F 0x5F 137 | #define REG60 0x60 138 | #define HISTO_LOW 0x61 139 | #define HISTO_HIGH 0x62 140 | 141 | #define REG04 0x04 142 | #define REG04_DEFAULT 0x28 143 | #define REG04_HFLIP_IMG 0x80 144 | #define REG04_VFLIP_IMG 0x40 145 | #define REG04_VREF_EN 0x10 146 | #define REG04_HREF_EN 0x08 147 | #define REG04_SET(x) (REG04_DEFAULT|x) 148 | 149 | #define REG08 0x08 150 | #define COM2 0x09 151 | #define COM2_STDBY 0x10 152 | #define COM2_OUT_DRIVE_1x 0x00 153 | #define COM2_OUT_DRIVE_2x 0x01 154 | #define COM2_OUT_DRIVE_3x 0x02 155 | #define COM2_OUT_DRIVE_4x 0x03 156 | 157 | #define COM3 0x0C 158 | #define COM3_DEFAULT 0x38 159 | #define COM3_BAND_50Hz 0x04 160 | #define COM3_BAND_60Hz 0x00 161 | #define COM3_BAND_AUTO 0x02 162 | #define COM3_BAND_SET(x) (COM3_DEFAULT|x) 163 | 164 | #define COM7 0x12 165 | #define COM7_SRST 0x80 166 | #define COM7_RES_UXGA 0x00 /* UXGA */ 167 | #define COM7_RES_SVGA 0x40 /* SVGA */ 168 | #define COM7_RES_CIF 0x20 /* CIF */ 169 | #define COM7_ZOOM_EN 0x04 /* Enable Zoom */ 170 | #define COM7_COLOR_BAR 0x02 /* Enable Color Bar Test */ 171 | 172 | #define COM8 0x13 173 | #define COM8_DEFAULT 0xC0 174 | #define COM8_BNDF_EN 0x20 /* Enable Banding filter */ 175 | #define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */ 176 | #define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */ 177 | #define COM8_SET(x) (COM8_DEFAULT|x) 178 | 179 | #define COM9 0x14 /* AGC gain ceiling */ 180 | #define COM9_DEFAULT 0x08 181 | #define COM9_AGC_GAIN_2x 0x00 /* AGC: 2x */ 182 | #define COM9_AGC_GAIN_4x 0x01 /* AGC: 4x */ 183 | #define COM9_AGC_GAIN_8x 0x02 /* AGC: 8x */ 184 | #define COM9_AGC_GAIN_16x 0x03 /* AGC: 16x */ 185 | #define COM9_AGC_GAIN_32x 0x04 /* AGC: 32x */ 186 | #define COM9_AGC_GAIN_64x 0x05 /* AGC: 64x */ 187 | #define COM9_AGC_GAIN_128x 0x06 /* AGC: 128x */ 188 | #define COM9_AGC_SET(x) (COM9_DEFAULT|(x<<5)) 189 | 190 | #define COM10 0x15 191 | #define COM10_HREF_EN 0x80 /* HSYNC changes to HREF */ 192 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ 193 | #define COM10_PCLK_FREE 0x20 /* PCLK output option: free running PCLK */ 194 | #define COM10_PCLK_EDGE 0x10 /* Data is updated at the rising edge of PCLK */ 195 | #define COM10_HREF_NEG 0x08 /* HREF negative */ 196 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ 197 | #define COM10_HSYNC_NEG 0x01 /* HSYNC negative */ 198 | 199 | #define CTRL1_AWB 0x08 /* Enable AWB */ 200 | 201 | #define VV 0x26 202 | #define VV_AGC_TH_SET(h,l) ((h<<4)|(l&0x0F)) 203 | 204 | #define REG32 0x32 205 | #define REG32_UXGA 0x36 206 | #define REG32_SVGA 0x09 207 | #define REG32_CIF 0x00 208 | #endif //__REG_REGS_H__ 209 | -------------------------------------------------------------------------------- /components/camera/ov7725.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 | * OV7725 driver. 7 | * 8 | */ 9 | #include 10 | #include 11 | #include 12 | #include "sccb.h" 13 | #include "ov7725.h" 14 | #include "ov7725_regs.h" 15 | #include 16 | 17 | static const uint8_t default_regs[][2] = { 18 | {COM3, COM3_SWAP_YUV}, 19 | {COM7, COM7_RES_QVGA | COM7_FMT_YUV}, 20 | 21 | {COM4, 0x01}, /* bypass PLL */ 22 | {CLKRC, 0xC0}, /* Res/Bypass pre-scalar */ 23 | 24 | // QVGA Window Size 25 | {HSTART, 0x3F}, 26 | {HSIZE, 0x50}, 27 | {VSTART, 0x03}, 28 | {VSIZE, 0x78}, 29 | {HREF, 0x00}, 30 | 31 | // Scale down to QVGA Resolution 32 | {HOUTSIZE, 0x50}, 33 | {VOUTSIZE, 0x78}, 34 | 35 | {COM12, 0x03}, 36 | {EXHCH, 0x00}, 37 | {TGT_B, 0x7F}, 38 | {FIXGAIN, 0x09}, 39 | {AWB_CTRL0, 0xE0}, 40 | {DSP_CTRL1, 0xFF}, 41 | 42 | {DSP_CTRL2, DSP_CTRL2_VDCW_EN | DSP_CTRL2_HDCW_EN | DSP_CTRL2_HZOOM_EN | DSP_CTRL2_VZOOM_EN}, 43 | 44 | {DSP_CTRL3, 0x00}, 45 | {DSP_CTRL4, 0x00}, 46 | {DSPAUTO, 0xFF}, 47 | 48 | {COM8, 0xF0}, 49 | {COM6, 0xC5}, 50 | {COM9, 0x11}, 51 | {COM10, COM10_VSYNC_NEG | COM10_PCLK_MASK}, //Invert VSYNC and MASK PCLK 52 | {BDBASE, 0x7F}, 53 | {DBSTEP, 0x03}, 54 | {AEW, 0x96}, 55 | {AEB, 0x64}, 56 | {VPT, 0xA1}, 57 | {EXHCL, 0x00}, 58 | {AWB_CTRL3, 0xAA}, 59 | {COM8, 0xFF}, 60 | 61 | //Gamma 62 | {GAM1, 0x0C}, 63 | {GAM2, 0x16}, 64 | {GAM3, 0x2A}, 65 | {GAM4, 0x4E}, 66 | {GAM5, 0x61}, 67 | {GAM6, 0x6F}, 68 | {GAM7, 0x7B}, 69 | {GAM8, 0x86}, 70 | {GAM9, 0x8E}, 71 | {GAM10, 0x97}, 72 | {GAM11, 0xA4}, 73 | {GAM12, 0xAF}, 74 | {GAM13, 0xC5}, 75 | {GAM14, 0xD7}, 76 | {GAM15, 0xE8}, 77 | 78 | {SLOP, 0x20}, 79 | {EDGE1, 0x05}, 80 | {EDGE2, 0x03}, 81 | {EDGE3, 0x00}, 82 | {DNSOFF, 0x01}, 83 | 84 | {MTX1, 0xB0}, 85 | {MTX2, 0x9D}, 86 | {MTX3, 0x13}, 87 | {MTX4, 0x16}, 88 | {MTX5, 0x7B}, 89 | {MTX6, 0x91}, 90 | {MTX_CTRL, 0x1E}, 91 | 92 | {BRIGHTNESS, 0x08}, 93 | {CONTRAST, 0x30}, 94 | {UVADJ0, 0x81}, 95 | {SDE, (SDE_CONT_BRIGHT_EN | SDE_SATURATION_EN)}, 96 | 97 | // For 30 fps/60Hz 98 | {DM_LNL, 0x00}, 99 | {DM_LNH, 0x00}, 100 | {BDBASE, 0x7F}, 101 | {DBSTEP, 0x03}, 102 | 103 | // Lens Correction, should be tuned with real camera module 104 | {LC_RADI, 0x10}, 105 | {LC_COEF, 0x10}, 106 | {LC_COEFB, 0x14}, 107 | {LC_COEFR, 0x17}, 108 | {LC_CTR, 0x05}, 109 | {COM5, 0xF5}, //0x65 110 | 111 | {0x00, 0x00}, 112 | }; 113 | 114 | 115 | static int reset(sensor_t *sensor) 116 | { 117 | int i=0; 118 | const uint8_t (*regs)[2]; 119 | 120 | // Reset all registers 121 | SCCB_Write(sensor->slv_addr, COM7, COM7_RESET); 122 | 123 | // Delay 10 ms 124 | systick_sleep(10); 125 | 126 | // Write default regsiters 127 | for (i=0, regs = default_regs; regs[i][0]; i++) { 128 | SCCB_Write(sensor->slv_addr, regs[i][0], regs[i][1]); 129 | } 130 | 131 | // Delay 132 | systick_sleep(30); 133 | 134 | return 0; 135 | } 136 | 137 | 138 | static int set_pixformat(sensor_t *sensor, pixformat_t pixformat) 139 | { 140 | int ret=0; 141 | // Read register COM7 142 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM7); 143 | 144 | switch (pixformat) { 145 | case PIXFORMAT_RGB565: 146 | reg = COM7_SET_FMT(reg, COM7_FMT_RGB) | COM7_FMT_RGB565; 147 | break; 148 | case PIXFORMAT_YUV422: 149 | case PIXFORMAT_GRAYSCALE: 150 | reg = COM7_SET_FMT(reg, COM7_FMT_YUV); 151 | break; 152 | default: 153 | return -1; 154 | } 155 | 156 | // Write back register COM7 157 | ret = SCCB_Write(sensor->slv_addr, COM7, reg); 158 | 159 | // Delay 160 | systick_sleep(30); 161 | 162 | return ret; 163 | } 164 | 165 | static int set_framesize(sensor_t *sensor, framesize_t framesize) 166 | { 167 | int ret=0; 168 | uint16_t w = resolution[framesize][0]; 169 | uint16_t h = resolution[framesize][1]; 170 | 171 | // Write MSBs 172 | ret |= SCCB_Write(sensor->slv_addr, HOUTSIZE, w>>2); 173 | ret |= SCCB_Write(sensor->slv_addr, VOUTSIZE, h>>1); 174 | 175 | // Write LSBs 176 | ret |= SCCB_Write(sensor->slv_addr, EXHCH, ((w&0x3) | ((h&0x1) << 2))); 177 | 178 | if (framesize < FRAMESIZE_VGA) { 179 | // Enable auto-scaling/zooming factors 180 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xFF); 181 | } else { 182 | // Disable auto-scaling/zooming factors 183 | ret |= SCCB_Write(sensor->slv_addr, DSPAUTO, 0xF3); 184 | 185 | // Clear auto-scaling/zooming factors 186 | ret |= SCCB_Write(sensor->slv_addr, SCAL0, 0x00); 187 | ret |= SCCB_Write(sensor->slv_addr, SCAL1, 0x00); 188 | ret |= SCCB_Write(sensor->slv_addr, SCAL2, 0x00); 189 | } 190 | 191 | // Delay 192 | systick_sleep(30); 193 | 194 | if (ret == 0) { 195 | sensor->framesize = framesize; 196 | } 197 | 198 | return ret; 199 | } 200 | 201 | static int set_colorbar(sensor_t *sensor, int enable) 202 | { 203 | int ret=0; 204 | uint8_t reg; 205 | 206 | // Read reg COM3 207 | reg = SCCB_Read(sensor->slv_addr, COM3); 208 | // Enable colorbar test pattern output 209 | reg = COM3_SET_CBAR(reg, enable); 210 | // Write back COM3 211 | ret |= SCCB_Write(sensor->slv_addr, COM3, reg); 212 | 213 | // Read reg DSP_CTRL3 214 | reg = SCCB_Read(sensor->slv_addr, DSP_CTRL3); 215 | // Enable DSP colorbar output 216 | reg = DSP_CTRL3_SET_CBAR(reg, enable); 217 | // Write back DSP_CTRL3 218 | ret |= SCCB_Write(sensor->slv_addr, DSP_CTRL3, reg); 219 | 220 | return ret; 221 | } 222 | 223 | static int set_whitebal(sensor_t *sensor, int enable) 224 | { 225 | // Read register COM8 226 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 227 | 228 | // Set white bal on/off 229 | reg = COM8_SET_AWB(reg, enable); 230 | 231 | // Write back register COM8 232 | return SCCB_Write(sensor->slv_addr, COM8, reg); 233 | } 234 | 235 | static int set_gain_ctrl(sensor_t *sensor, int enable) 236 | { 237 | // Read register COM8 238 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 239 | 240 | // Set white bal on/off 241 | reg = COM8_SET_AGC(reg, enable); 242 | 243 | // Write back register COM8 244 | return SCCB_Write(sensor->slv_addr, COM8, reg); 245 | } 246 | 247 | static int set_exposure_ctrl(sensor_t *sensor, int enable) 248 | { 249 | // Read register COM8 250 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM8); 251 | 252 | // Set white bal on/off 253 | reg = COM8_SET_AEC(reg, enable); 254 | 255 | // Write back register COM8 256 | return SCCB_Write(sensor->slv_addr, COM8, reg); 257 | } 258 | 259 | static int set_hmirror(sensor_t *sensor, int enable) 260 | { 261 | // Read register COM3 262 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); 263 | 264 | // Set mirror on/off 265 | reg = COM3_SET_MIRROR(reg, enable); 266 | 267 | // Write back register COM3 268 | return SCCB_Write(sensor->slv_addr, COM3, reg); 269 | } 270 | 271 | static int set_vflip(sensor_t *sensor, int enable) 272 | { 273 | // Read register COM3 274 | uint8_t reg = SCCB_Read(sensor->slv_addr, COM3); 275 | 276 | // Set mirror on/off 277 | reg = COM3_SET_FLIP(reg, enable); 278 | 279 | // Write back register COM3 280 | return SCCB_Write(sensor->slv_addr, COM3, reg); 281 | } 282 | 283 | int ov7725_init(sensor_t *sensor) 284 | { 285 | // Set function pointers 286 | sensor->reset = reset; 287 | sensor->set_pixformat = set_pixformat; 288 | sensor->set_framesize = set_framesize; 289 | sensor->set_colorbar = set_colorbar; 290 | sensor->set_whitebal = set_whitebal; 291 | sensor->set_gain_ctrl = set_gain_ctrl; 292 | sensor->set_exposure_ctrl = set_exposure_ctrl; 293 | sensor->set_hmirror = set_hmirror; 294 | sensor->set_vflip = set_vflip; 295 | 296 | // Retrieve sensor's signature 297 | sensor->id.MIDH = SCCB_Read(sensor->slv_addr, REG_MIDH); 298 | sensor->id.MIDL = SCCB_Read(sensor->slv_addr, REG_MIDL); 299 | sensor->id.PID = SCCB_Read(sensor->slv_addr, REG_PID); 300 | sensor->id.VER = SCCB_Read(sensor->slv_addr, REG_VER); 301 | 302 | // Set sensor flags 303 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_VSYNC, 1); 304 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_HSYNC, 0); 305 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_PIXCK, 1); 306 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_FSYNC, 1); 307 | SENSOR_HW_FLAGS_SET(sensor, SENSOR_HW_FLAGS_JPEGE, 0); 308 | 309 | return 0; 310 | } 311 | -------------------------------------------------------------------------------- /components/camera/ov7725.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 | * OV7725 driver. 7 | * 8 | */ 9 | #ifndef __OV7725_H__ 10 | #define __OV7725_H__ 11 | #include "sensor.h" 12 | 13 | int ov7725_init(sensor_t *sensor); 14 | #endif // __OV7725_H__ 15 | -------------------------------------------------------------------------------- /components/camera/ov7725_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 | #define GAIN 0x00 /* AGC – Gain control gain setting */ 11 | #define BLUE 0x01 /* AWB – Blue channel gain setting */ 12 | #define RED 0x02 /* AWB – Red channel gain setting */ 13 | #define GREEN 0x03 /* AWB – Green channel gain setting */ 14 | #define BAVG 0x05 /* U/B Average Level */ 15 | #define GAVG 0x06 /* Y/Gb Average Level */ 16 | #define RAVG 0x07 /* V/R Average Level */ 17 | #define AECH 0x08 /* Exposure Value – AEC MSBs */ 18 | 19 | #define COM2 0x09 /* Common Control 2 */ 20 | #define COM2_SOFT_SLEEP 0x10 /* Soft sleep mode */ 21 | #define COM2_OUT_DRIVE_1x 0x00 /* Output drive capability 1x */ 22 | #define COM2_OUT_DRIVE_2x 0x01 /* Output drive capability 2x */ 23 | #define COM2_OUT_DRIVE_3x 0x02 /* Output drive capability 3x */ 24 | #define COM2_OUT_DRIVE_4x 0x03 /* Output drive capability 4x */ 25 | 26 | #define REG_PID 0x0A /* Product ID Number MSB */ 27 | #define REG_VER 0x0B /* Product ID Number LSB */ 28 | 29 | #define COM3 0x0C /* Common Control 3 */ 30 | #define COM3_VFLIP 0x80 /* Vertical flip image ON/OFF selection */ 31 | #define COM3_MIRROR 0x40 /* Horizontal mirror image ON/OFF selection */ 32 | #define COM3_SWAP_BR 0x20 /* Swap B/R output sequence in RGB output mode */ 33 | #define COM3_SWAP_YUV 0x10 /* Swap Y/UV output sequence in YUV output mode */ 34 | #define COM3_SWAP_MSB 0x08 /* Swap output MSB/LSB */ 35 | #define COM3_TRI_CLOCK 0x04 /* Tri-state option for output clock at power-down period */ 36 | #define COM3_TRI_DATA 0x02 /* Tri-state option for output data at power-down period */ 37 | #define COM3_COLOR_BAR 0x01 /* Sensor color bar test pattern output enable */ 38 | #define COM3_SET_CBAR(r, x) ((r&0xFE)|((x&1)<<0)) 39 | #define COM3_SET_MIRROR(r, x) ((r&0xBF)|((x&1)<<6)) 40 | #define COM3_SET_FLIP(r, x) ((r&0x7F)|((x&1)<<7)) 41 | 42 | #define COM4 0x0D /* Common Control 4 */ 43 | #define COM4_PLL_BYPASS 0x00 /* Bypass PLL */ 44 | #define COM4_PLL_4x 0x40 /* PLL frequency 4x */ 45 | #define COM4_PLL_6x 0x80 /* PLL frequency 6x */ 46 | #define COM4_PLL_8x 0xc0 /* PLL frequency 8x */ 47 | #define COM4_AEC_FULL 0x00 /* AEC evaluate full window */ 48 | #define COM4_AEC_1_2 0x10 /* AEC evaluate 1/2 window */ 49 | #define COM4_AEC_1_4 0x20 /* AEC evaluate 1/4 window */ 50 | #define COM4_AEC_2_3 0x30 /* AEC evaluate 2/3 window */ 51 | 52 | #define COM5 0x0E /* Common Control 5 */ 53 | #define COM5_AFR 0x80 /* Auto frame rate control ON/OFF selection (night mode) */ 54 | #define COM5_AFR_SPEED 0x40 /* Auto frame rate control speed selection */ 55 | #define COM5_AFR_0 0x00 /* No reduction of frame rate */ 56 | #define COM5_AFR_1_2 0x10 /* Max reduction to 1/2 frame rate */ 57 | #define COM5_AFR_1_4 0x20 /* Max reduction to 1/4 frame rate */ 58 | #define COM5_AFR_1_8 0x30 /* Max reduction to 1/8 frame rate */ 59 | #define COM5_AFR_4x 0x04 /* Add frame when AGC reaches 4x gain */ 60 | #define COM5_AFR_8x 0x08 /* Add frame when AGC reaches 8x gain */ 61 | #define COM5_AFR_16x 0x0c /* Add frame when AGC reaches 16x gain */ 62 | #define COM5_AEC_NO_LIMIT 0x01 /* No limit to AEC increase step */ 63 | 64 | #define COM6 0x0F /* Common Control 6 */ 65 | #define COM6_AUTO_WINDOW 0x01 /* Auto window setting ON/OFF selection when format changes */ 66 | 67 | #define AEC 0x10 /* AEC[7:0] (see register AECH for AEC[15:8]) */ 68 | #define CLKRC 0x11 /* Internal Clock */ 69 | 70 | #define COM7 0x12 /* Common Control 7 */ 71 | #define COM7_RESET 0x80 /* SCCB Register Reset */ 72 | #define COM7_RES_VGA 0x00 /* Resolution VGA */ 73 | #define COM7_RES_QVGA 0x40 /* Resolution QVGA */ 74 | #define COM7_BT656 0x20 /* BT.656 protocol ON/OFF */ 75 | #define COM7_SENSOR_RAW 0x10 /* Sensor RAW */ 76 | #define COM7_FMT_GBR422 0x00 /* RGB output format GBR422 */ 77 | #define COM7_FMT_RGB565 0x04 /* RGB output format RGB565 */ 78 | #define COM7_FMT_RGB555 0x08 /* RGB output format RGB555 */ 79 | #define COM7_FMT_RGB444 0x0C /* RGB output format RGB444 */ 80 | #define COM7_FMT_YUV 0x00 /* Output format YUV */ 81 | #define COM7_FMT_P_BAYER 0x01 /* Output format Processed Bayer RAW */ 82 | #define COM7_FMT_RGB 0x02 /* Output format RGB */ 83 | #define COM7_FMT_R_BAYER 0x03 /* Output format Bayer RAW */ 84 | #define COM7_SET_FMT(r, x) ((r&0xFC)|((x&0x3)<<0)) 85 | 86 | #define COM8 0x13 /* Common Control 8 */ 87 | #define COM8_FAST_AUTO 0x80 /* Enable fast AGC/AEC algorithm */ 88 | #define COM8_STEP_VSYNC 0x00 /* AEC - Step size limited to vertical blank */ 89 | #define COM8_STEP_UNLIMIT 0x40 /* AEC - Step size unlimited step size */ 90 | #define COM8_BANDF_EN 0x20 /* Banding filter ON/OFF */ 91 | #define COM8_AEC_BANDF 0x10 /* Enable AEC below banding value */ 92 | #define COM8_AEC_FINE_EN 0x08 /* Fine AEC ON/OFF control */ 93 | #define COM8_AGC_EN 0x04 /* AGC Enable */ 94 | #define COM8_AWB_EN 0x02 /* AWB Enable */ 95 | #define COM8_AEC_EN 0x01 /* AEC Enable */ 96 | #define COM8_SET_AGC(r, x) ((r&0xFB)|((x&0x1)<<2)) 97 | #define COM8_SET_AWB(r, x) ((r&0xFD)|((x&0x1)<<1)) 98 | #define COM8_SET_AEC(r, x) ((r&0xFE)|((x&0x1)<<0)) 99 | 100 | #define COM9 0x14 /* Common Control 9 */ 101 | #define COM9_HISTO_AVG 0x80 /* Histogram or average based AEC/AGC selection */ 102 | #define COM9_AGC_GAIN_2x 0x00 /* Automatic Gain Ceiling 2x */ 103 | #define COM9_AGC_GAIN_4x 0x10 /* Automatic Gain Ceiling 4x */ 104 | #define COM9_AGC_GAIN_8x 0x20 /* Automatic Gain Ceiling 8x */ 105 | #define COM9_AGC_GAIN_16x 0x30 /* Automatic Gain Ceiling 16x */ 106 | #define COM9_AGC_GAIN_32x 0x40 /* Automatic Gain Ceiling 32x */ 107 | #define COM9_DROP_VSYNC 0x04 /* Drop VSYNC output of corrupt frame */ 108 | #define COM9_DROP_HREF 0x02 /* Drop HREF output of corrupt frame */ 109 | #define COM9_SET_AGC(r, x) ((r&0x8F)|((x&0x07)<<4)) 110 | 111 | #define COM10 0x15 /* Common Control 10 */ 112 | #define COM10_NEGATIVE 0x80 /* Output negative data */ 113 | #define COM10_HSYNC_EN 0x40 /* HREF changes to HSYNC */ 114 | #define COM10_PCLK_FREE 0x00 /* PCLK output option: free running PCLK */ 115 | #define COM10_PCLK_MASK 0x20 /* PCLK output option: masked during horizontal blank */ 116 | #define COM10_PCLK_REV 0x10 /* PCLK reverse */ 117 | #define COM10_HREF_REV 0x08 /* HREF reverse */ 118 | #define COM10_VSYNC_FALLING 0x00 /* VSYNC changes on falling edge of PCLK */ 119 | #define COM10_VSYNC_RISING 0x04 /* VSYNC changes on rising edge of PCLK */ 120 | #define COM10_VSYNC_NEG 0x02 /* VSYNC negative */ 121 | #define COM10_OUT_RANGE_8 0x01 /* Output data range: Full range */ 122 | #define COM10_OUT_RANGE_10 0x00 /* Output data range: Data from [10] to [F0] (8 MSBs) */ 123 | 124 | #define REG16 0x16 /* Register 16 */ 125 | #define REG16_BIT_SHIFT 0x80 /* Bit shift test pattern options */ 126 | #define HSTART 0x17 /* Horizontal Frame (HREF column) Start 8 MSBs (2 LSBs are at HREF[5:4]) */ 127 | #define HSIZE 0x18 /* Horizontal Sensor Size (2 LSBs are at HREF[1:0]) */ 128 | #define VSTART 0x19 /* Vertical Frame (row) Start 8 MSBs (1 LSB is at HREF[6]) */ 129 | #define VSIZE 0x1A /* Vertical Sensor Size (1 LSB is at HREF[2]) */ 130 | #define PSHFT 0x1B /* Data Format - Pixel Delay Select */ 131 | #define REG_MIDH 0x1C /* Manufacturer ID Byte – High */ 132 | #define REG_MIDL 0x1D /* Manufacturer ID Byte – Low */ 133 | #define LAEC 0x1F /* Fine AEC Value - defines exposure value less than one row period */ 134 | 135 | #define COM11 0x20 /* Common Control 11 */ 136 | #define COM11_SNGL_FRAME_EN 0x02 /* Single frame ON/OFF selection */ 137 | #define COM11_SNGL_XFR_TRIG 0x01 /* Single frame transfer trigger */ 138 | 139 | #define BDBASE 0x22 /* Banding Filter Minimum AEC Value */ 140 | #define DBSTEP 0x23 /* Banding Filter Maximum Step */ 141 | #define AEW 0x24 /* AGC/AEC - Stable Operating Region (Upper Limit) */ 142 | #define AEB 0x25 /* AGC/AEC - Stable Operating Region (Lower Limit) */ 143 | #define VPT 0x26 /* AGC/AEC Fast Mode Operating Region */ 144 | #define REG28 0x28 /* Selection on the number of dummy rows, N */ 145 | #define HOUTSIZE 0x29 /* Horizontal Data Output Size MSBs (2 LSBs at register EXHCH[1:0]) */ 146 | #define EXHCH 0x2A /* Dummy Pixel Insert MSB */ 147 | #define EXHCL 0x2B /* Dummy Pixel Insert LSB */ 148 | #define VOUTSIZE 0x2C /* Vertical Data Output Size MSBs (LSB at register EXHCH[2]) */ 149 | #define ADVFL 0x2D /* LSB of Insert Dummy Rows in Vertical Sync (1 bit equals 1 row) */ 150 | #define ADVFH 0x2E /* MSB of Insert Dummy Rows in Vertical Sync */ 151 | #define YAVE 0x2F /* Y/G Channel Average Value */ 152 | #define LUMHTH 0x30 /* Histogram AEC/AGC Luminance High Level Threshold */ 153 | #define LUMLTH 0x31 /* Histogram AEC/AGC Luminance Low Level Threshold */ 154 | #define HREF 0x32 /* Image Start and Size Control */ 155 | #define DM_LNL 0x33 /* Dummy Row Low 8 Bits */ 156 | #define DM_LNH 0x34 /* Dummy Row High 8 Bits */ 157 | #define ADOFF_B 0x35 /* AD Offset Compensation Value for B Channel */ 158 | #define ADOFF_R 0x36 /* AD Offset Compensation Value for R Channel */ 159 | #define ADOFF_GB 0x37 /* AD Offset Compensation Value for GB Channel */ 160 | #define ADOFF_GR 0x38 /* AD Offset Compensation Value for GR Channel */ 161 | #define OFF_B 0x39 /* AD Offset Compensation Value for B Channel */ 162 | #define OFF_R 0x3A /* AD Offset Compensation Value for R Channel */ 163 | #define OFF_GB 0x3B /* AD Offset Compensation Value for GB Channel */ 164 | #define OFF_GR 0x3C /* AD Offset Compensation Value for GR Channel */ 165 | #define COM12 0x3D /* DC offset compensation for analog process */ 166 | 167 | #define COM13 0x3E /* Common Control 13 */ 168 | #define COM13_BLC_EN 0x80 /* BLC enable */ 169 | #define COM13_ADC_EN 0x40 /* ADC channel BLC ON/OFF control */ 170 | #define COM13_ANALOG_BLC 0x20 /* Analog processing channel BLC ON/OFF control */ 171 | #define COM13_ABLC_GAIN_EN 0x04 /* ABLC gain trigger enable */ 172 | 173 | #define COM14 0x3F /* Common Control 14 */ 174 | #define COM15 0x40 /* Common Control 15 */ 175 | #define COM16 0x41 /* Common Control 16 */ 176 | #define TGT_B 0x42 /* BLC Blue Channel Target Value */ 177 | #define TGT_R 0x43 /* BLC Red Channel Target Value */ 178 | #define TGT_GB 0x44 /* BLC Gb Channel Target Value */ 179 | #define TGT_GR 0x45 /* BLC Gr Channel Target Value */ 180 | 181 | #define LC_CTR 0x46 /* Lens Correction Control */ 182 | #define LC_CTR_RGB_COMP_1 0x00 /* R, G, and B channel compensation coefficient is set by LC_COEF (0x49) */ 183 | #define LC_CTR_RGB_COMP_3 0x04 /* R, G, and B channel compensation coefficient is set by registers 184 | LC_COEFB (0x4B), LC_COEF (0x49), and LC_COEFR (0x4C), respectively */ 185 | #define LC_CTR_EN 0x01 /* Lens correction enable */ 186 | #define LC_XC 0x47 /* X Coordinate of Lens Correction Center Relative to Array Center */ 187 | #define LC_YC 0x48 /* Y Coordinate of Lens Correction Center Relative to Array Center */ 188 | #define LC_COEF 0x49 /* Lens Correction Coefficient */ 189 | #define LC_RADI 0x4A /* Lens Correction Radius */ 190 | #define LC_COEFB 0x4B /* Lens Correction B Channel Compensation Coefficient */ 191 | #define LC_COEFR 0x4C /* Lens Correction R Channel Compensation Coefficient */ 192 | 193 | #define FIXGAIN 0x4D /* Analog Fix Gain Amplifier */ 194 | #define AREF0 0x4E /* Sensor Reference Control */ 195 | #define AREF1 0x4F /* Sensor Reference Current Control */ 196 | #define AREF2 0x50 /* Analog Reference Control */ 197 | #define AREF3 0x51 /* ADC Reference Control */ 198 | #define AREF4 0x52 /* ADC Reference Control */ 199 | #define AREF5 0x53 /* ADC Reference Control */ 200 | #define AREF6 0x54 /* Analog Reference Control */ 201 | #define AREF7 0x55 /* Analog Reference Control */ 202 | #define UFIX 0x60 /* U Channel Fixed Value Output */ 203 | #define VFIX 0x61 /* V Channel Fixed Value Output */ 204 | #define AWBB_BLK 0x62 /* AWB Option for Advanced AWB */ 205 | 206 | #define AWB_CTRL0 0x63 /* AWB Control Byte 0 */ 207 | #define AWB_CTRL0_GAIN_EN 0x80 /* AWB gain enable */ 208 | #define AWB_CTRL0_CALC_EN 0x40 /* AWB calculate enable */ 209 | #define AWB_CTRL0_WBC_MASK 0x0F /* WBC threshold 2 */ 210 | 211 | #define DSP_CTRL1 0x64 /* DSP Control Byte 1 */ 212 | #define DSP_CTRL1_FIFO_EN 0x80 /* FIFO enable/disable selection */ 213 | #define DSP_CTRL1_UV_EN 0x40 /* UV adjust function ON/OFF selection */ 214 | #define DSP_CTRL1_SDE_EN 0x20 /* SDE enable */ 215 | #define DSP_CTRL1_MTRX_EN 0x10 /* Color matrix ON/OFF selection */ 216 | #define DSP_CTRL1_INTRP_EN 0x08 /* Interpolation ON/OFF selection */ 217 | #define DSP_CTRL1_GAMMA_EN 0x04 /* Gamma function ON/OFF selection */ 218 | #define DSP_CTRL1_BLACK_EN 0x02 /* Black defect auto correction ON/OFF */ 219 | #define DSP_CTRL1_WHITE_EN 0x01 /* White defect auto correction ON/OFF */ 220 | 221 | #define DSP_CTRL2 0x65 /* DSP Control Byte 2 */ 222 | #define DSP_CTRL2_VDCW_EN 0x08 /* Vertical DCW enable */ 223 | #define DSP_CTRL2_HDCW_EN 0x04 /* Horizontal DCW enable */ 224 | #define DSP_CTRL2_VZOOM_EN 0x02 /* Vertical zoom out enable */ 225 | #define DSP_CTRL2_HZOOM_EN 0x01 /* Horizontal zoom out enable */ 226 | 227 | #define DSP_CTRL3 0x66 /* DSP Control Byte 3 */ 228 | #define DSP_CTRL3_UV_EN 0x80 /* UV output sequence option */ 229 | #define DSP_CTRL3_CBAR_EN 0x20 /* DSP color bar ON/OFF selection */ 230 | #define DSP_CTRL3_FIFO_EN 0x08 /* FIFO power down ON/OFF selection */ 231 | #define DSP_CTRL3_SCAL1_PWDN 0x04 /* Scaling module power down control 1 */ 232 | #define DSP_CTRL3_SCAL2_PWDN 0x02 /* Scaling module power down control 2 */ 233 | #define DSP_CTRL3_INTRP_PWDN 0x01 /* Interpolation module power down control */ 234 | #define DSP_CTRL3_SET_CBAR(r, x) ((r&0xDF)|((x&1)<<5)) 235 | 236 | 237 | #define DSP_CTRL4 0x67 /* DSP Control Byte 4 */ 238 | #define DSP_CTRL4_YUV_RGB 0x00 /* Output selection YUV or RGB */ 239 | #define DSP_CTRL4_RAW8 0x02 /* Output selection RAW8 */ 240 | #define DSP_CTRL4_RAW10 0x03 /* Output selection RAW10 */ 241 | 242 | 243 | #define AWB_BIAS 0x68 /* AWB BLC Level Clip */ 244 | #define AWB_CTRL1 0x69 /* AWB Control 1 */ 245 | #define AWB_CTRL2 0x6A /* AWB Control 2 */ 246 | 247 | #define AWB_CTRL3 0x6B /* AWB Control 3 */ 248 | #define AWB_CTRL3_ADVANCED 0x80 /* AWB mode select - Advanced AWB */ 249 | #define AWB_CTRL3_SIMPLE 0x00 /* AWB mode select - Simple AWB */ 250 | 251 | #define AWB_CTRL4 0x6C /* AWB Control 4 */ 252 | #define AWB_CTRL5 0x6D /* AWB Control 5 */ 253 | #define AWB_CTRL6 0x6E /* AWB Control 6 */ 254 | #define AWB_CTRL7 0x6F /* AWB Control 7 */ 255 | #define AWB_CTRL8 0x70 /* AWB Control 8 */ 256 | #define AWB_CTRL9 0x71 /* AWB Control 9 */ 257 | #define AWB_CTRL10 0x72 /* AWB Control 10 */ 258 | #define AWB_CTRL11 0x73 /* AWB Control 11 */ 259 | #define AWB_CTRL12 0x74 /* AWB Control 12 */ 260 | #define AWB_CTRL13 0x75 /* AWB Control 13 */ 261 | #define AWB_CTRL14 0x76 /* AWB Control 14 */ 262 | #define AWB_CTRL15 0x77 /* AWB Control 15 */ 263 | #define AWB_CTRL16 0x78 /* AWB Control 16 */ 264 | #define AWB_CTRL17 0x79 /* AWB Control 17 */ 265 | #define AWB_CTRL18 0x7A /* AWB Control 18 */ 266 | #define AWB_CTRL19 0x7B /* AWB Control 19 */ 267 | #define AWB_CTRL20 0x7C /* AWB Control 20 */ 268 | #define AWB_CTRL21 0x7D /* AWB Control 21 */ 269 | #define GAM1 0x7E /* Gamma Curve 1st Segment Input End Point 0x04 Output Value */ 270 | #define GAM2 0x7F /* Gamma Curve 2nd Segment Input End Point 0x08 Output Value */ 271 | #define GAM3 0x80 /* Gamma Curve 3rd Segment Input End Point 0x10 Output Value */ 272 | #define GAM4 0x81 /* Gamma Curve 4th Segment Input End Point 0x20 Output Value */ 273 | #define GAM5 0x82 /* Gamma Curve 5th Segment Input End Point 0x28 Output Value */ 274 | #define GAM6 0x83 /* Gamma Curve 6th Segment Input End Point 0x30 Output Value */ 275 | #define GAM7 0x84 /* Gamma Curve 7th Segment Input End Point 0x38 Output Value */ 276 | #define GAM8 0x85 /* Gamma Curve 8th Segment Input End Point 0x40 Output Value */ 277 | #define GAM9 0x86 /* Gamma Curve 9th Segment Input End Point 0x48 Output Value */ 278 | #define GAM10 0x87 /* Gamma Curve 10th Segment Input End Point 0x50 Output Value */ 279 | #define GAM11 0x88 /* Gamma Curve 11th Segment Input End Point 0x60 Output Value */ 280 | #define GAM12 0x89 /* Gamma Curve 12th Segment Input End Point 0x70 Output Value */ 281 | #define GAM13 0x8A /* Gamma Curve 13th Segment Input End Point 0x90 Output Value */ 282 | #define GAM14 0x8B /* Gamma Curve 14th Segment Input End Point 0xB0 Output Value */ 283 | #define GAM15 0x8C /* Gamma Curve 15th Segment Input End Point 0xD0 Output Value */ 284 | #define SLOP 0x8D /* Gamma Curve Highest Segment Slope */ 285 | #define DNSTH 0x8E /* De-noise Threshold */ 286 | #define EDGE0 0x8F /* Edge Enhancement Strength Control */ 287 | #define EDGE1 0x90 /* Edge Enhancement Threshold Control */ 288 | #define DNSOFF 0x91 /* Auto De-noise Threshold Control */ 289 | #define EDGE2 0x92 /* Edge Enhancement Strength Upper Limit */ 290 | #define EDGE3 0x93 /* Edge Enhancement Strength Upper Limit */ 291 | #define MTX1 0x94 /* Matrix Coefficient 1 */ 292 | #define MTX2 0x95 /* Matrix Coefficient 2 */ 293 | #define MTX3 0x96 /* Matrix Coefficient 3 */ 294 | #define MTX4 0x97 /* Matrix Coefficient 4 */ 295 | #define MTX5 0x98 /* Matrix Coefficient 5 */ 296 | #define MTX6 0x99 /* Matrix Coefficient 6 */ 297 | 298 | #define MTX_CTRL 0x9A /* Matrix Control */ 299 | #define MTX_CTRL_DBL_EN 0x80 /* Matrix double ON/OFF selection */ 300 | 301 | #define BRIGHTNESS 0x9B /* Brightness Control */ 302 | #define CONTRAST 0x9C /* Contrast Gain */ 303 | #define UVADJ0 0x9E /* Auto UV Adjust Control 0 */ 304 | #define UVADJ1 0x9F /* Auto UV Adjust Control 1 */ 305 | #define SCAL0 0xA0 /* DCW Ratio Control */ 306 | #define SCAL1 0xA1 /* Horizontal Zoom Out Control */ 307 | #define SCAL2 0xA2 /* Vertical Zoom Out Control */ 308 | #define FIFODLYM 0xA3 /* FIFO Manual Mode Delay Control */ 309 | #define FIFODLYA 0xA4 /* FIFO Auto Mode Delay Control */ 310 | 311 | #define SDE 0xA6 /* Special Digital Effect Control */ 312 | #define SDE_NEGATIVE_EN 0x40 /* Negative image enable */ 313 | #define SDE_GRAYSCALE_EN 0x20 /* Gray scale image enable */ 314 | #define SDE_V_FIXED_EN 0x10 /* V fixed value enable */ 315 | #define SDE_U_FIXED_EN 0x08 /* U fixed value enable */ 316 | #define SDE_CONT_BRIGHT_EN 0x04 /* Contrast/Brightness enable */ 317 | #define SDE_SATURATION_EN 0x02 /* Saturation enable */ 318 | #define SDE_HUE_EN 0x01 /* Hue enable */ 319 | 320 | #define USAT 0xA7 /* U Component Saturation Gain */ 321 | #define VSAT 0xA8 /* V Component Saturation Gain */ 322 | #define HUECOS 0xA9 /* Cosine value × 0x80 */ 323 | #define HUESIN 0xAA /* Sine value × 0x80 */ 324 | #define SIGN_BIT 0xAB /* Sign Bit for Hue and Brightness */ 325 | 326 | #define DSPAUTO 0xAC /* DSP Auto Function ON/OFF Control */ 327 | #define DSPAUTO_AWB_EN 0x80 /* AWB auto threshold control */ 328 | #define DSPAUTO_DENOISE_EN 0x40 /* De-noise auto threshold control */ 329 | #define DSPAUTO_EDGE_EN 0x20 /* Sharpness (edge enhancement) auto strength control */ 330 | #define DSPAUTO_UV_EN 0x10 /* UV adjust auto slope control */ 331 | #define DSPAUTO_SCAL0_EN 0x08 /* Auto scaling factor control (register SCAL0 (0xA0)) */ 332 | #define DSPAUTO_SCAL1_EN 0x04 /* Auto scaling factor control (registers SCAL1 (0xA1 and SCAL2 (0xA2))*/ 333 | #define SET_REG(reg, x) (##reg_DEFAULT|x) 334 | #endif //__REG_REGS_H__ 335 | -------------------------------------------------------------------------------- /components/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 "wiring.h" 11 | #include "sccb.h" 12 | #include "twi.h" 13 | #include 14 | 15 | #define SCCB_FREQ (100000) // We don't need fast I2C. 100KHz is fine here. 16 | #define TIMEOUT (1000) /* Can't be sure when I2C routines return. Interrupts 17 | while polling hardware may result in unknown delays. */ 18 | 19 | 20 | int SCCB_Init(int pin_sda, int pin_scl) 21 | { 22 | twi_init(pin_sda, pin_scl); 23 | return 0; 24 | } 25 | 26 | uint8_t SCCB_Probe() 27 | { 28 | uint8_t reg = 0x00; 29 | uint8_t slv_addr = 0x00; 30 | 31 | for (uint8_t i=0; i<127; i++) { 32 | if (twi_writeTo(i, ®, 1, true) == 0) { 33 | slv_addr = i; 34 | break; 35 | } 36 | 37 | if (i!=126) { 38 | systick_sleep(1); // Necessary for OV7725 camera (not for OV2640). 39 | } 40 | } 41 | return slv_addr; 42 | } 43 | 44 | uint8_t SCCB_Read(uint8_t slv_addr, uint8_t reg) 45 | { 46 | uint8_t data=0; 47 | 48 | __disable_irq(); 49 | int rc = twi_writeTo(slv_addr, ®, 1, true); 50 | if (rc != 0) { 51 | data = 0xff; 52 | } 53 | else { 54 | rc = twi_readFrom(slv_addr, &data, 1, true); 55 | if (rc != 0) { 56 | data=0xFF; 57 | } 58 | } 59 | __enable_irq(); 60 | if (rc != 0) { 61 | printf("SCCB_Read [%02x] failed rc=%d\n", reg, rc); 62 | } 63 | return data; 64 | } 65 | 66 | uint8_t SCCB_Write(uint8_t slv_addr, uint8_t reg, uint8_t data) 67 | { 68 | uint8_t ret=0; 69 | uint8_t buf[] = {reg, data}; 70 | 71 | __disable_irq(); 72 | if(twi_writeTo(slv_addr, buf, 2, true) != 0) { 73 | ret=0xFF; 74 | } 75 | __enable_irq(); 76 | if (ret != 0) { 77 | printf("SCCB_Write [%02x]=%02x failed\n", reg, data); 78 | } 79 | return ret; 80 | } 81 | -------------------------------------------------------------------------------- /components/camera/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/camera/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 | #include "wiring.h" 13 | 14 | #define OV9650_PID (0x96) 15 | #define OV2640_PID (0x26) 16 | #define OV7725_PID (0x77) 17 | 18 | 19 | typedef struct { 20 | uint8_t MIDH; 21 | uint8_t MIDL; 22 | uint8_t PID; 23 | uint8_t VER; 24 | } sensor_id_t; 25 | 26 | typedef enum { 27 | PIXFORMAT_RGB565, // 2BPP/RGB565 28 | PIXFORMAT_YUV422, // 2BPP/YUV422 29 | PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE 30 | PIXFORMAT_JPEG, // JPEG/COMPRESSED 31 | } pixformat_t; 32 | 33 | typedef enum { 34 | FRAMESIZE_40x30, // 40x30 35 | FRAMESIZE_64x32, // 64x32 36 | FRAMESIZE_64x64, // 64x64 37 | FRAMESIZE_QQCIF, // 88x72 38 | FRAMESIZE_QQVGA, // 160x120 39 | FRAMESIZE_QQVGA2, // 128x160 40 | FRAMESIZE_QCIF, // 176x144 41 | FRAMESIZE_HQVGA, // 220x160 42 | FRAMESIZE_QVGA, // 320x240 43 | FRAMESIZE_CIF, // 352x288 44 | FRAMESIZE_VGA, // 640x480 45 | FRAMESIZE_SVGA, // 800x600 46 | FRAMESIZE_SXGA, // 1280x1024 47 | FRAMESIZE_UXGA, // 1600x1200 48 | } framesize_t; 49 | 50 | typedef enum { 51 | FRAMERATE_2FPS =0x9F, 52 | FRAMERATE_8FPS =0x87, 53 | FRAMERATE_15FPS=0x83, 54 | FRAMERATE_30FPS=0x81, 55 | FRAMERATE_60FPS=0x80, 56 | } framerate_t; 57 | 58 | typedef enum { 59 | GAINCEILING_2X, 60 | GAINCEILING_4X, 61 | GAINCEILING_8X, 62 | GAINCEILING_16X, 63 | GAINCEILING_32X, 64 | GAINCEILING_64X, 65 | GAINCEILING_128X, 66 | } gainceiling_t; 67 | 68 | typedef enum { 69 | SDE_NORMAL, 70 | SDE_NEGATIVE, 71 | } sde_t; 72 | 73 | typedef enum { 74 | ATTR_CONTRAST=0, 75 | ATTR_BRIGHTNESS, 76 | ATTR_SATURATION, 77 | ATTR_GAINCEILING, 78 | } sensor_attr_t; 79 | 80 | typedef enum { 81 | ACTIVE_LOW, 82 | ACTIVE_HIGH 83 | } reset_polarity_t; 84 | 85 | typedef void (*line_filter_t) (uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, void *args); 86 | 87 | #define SENSOR_HW_FLAGS_VSYNC (0) // vertical sync polarity. 88 | #define SENSOR_HW_FLAGS_HSYNC (1) // horizontal sync polarity. 89 | #define SENSOR_HW_FLAGS_PIXCK (2) // pixel clock edge. 90 | #define SENSOR_HW_FLAGS_FSYNC (3) // hardware frame sync. 91 | #define SENSOR_HW_FLAGS_JPEGE (4) // hardware JPEG encoder. 92 | #define SENSOR_HW_FLAGS_GET(s, x) ((s)->hw_flags & (1<hw_flags |= (v<hw_flags &= ~(1< 22 | #include 23 | #include "twi.h" 24 | #include "soc/gpio_reg.h" 25 | #include "wiring.h" 26 | #include 27 | 28 | unsigned char twi_dcount = 18; 29 | static unsigned char twi_sda, twi_scl; 30 | 31 | 32 | static inline void SDA_LOW() { 33 | //Enable SDA (becomes output and since GPO is 0 for the pin, 34 | // it will pull the line low) 35 | if (twi_sda < 32) { 36 | REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_sda)); 37 | } 38 | else { 39 | REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_sda - 32)); 40 | } 41 | } 42 | 43 | static inline void SDA_HIGH() { 44 | //Disable SDA (becomes input and since it has pullup it will go high) 45 | if (twi_sda < 32) { 46 | REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_sda)); 47 | } 48 | else { 49 | REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_sda - 32)); 50 | } 51 | } 52 | 53 | static inline uint32_t SDA_READ() { 54 | if (twi_sda < 32) { 55 | return (REG_READ(GPIO_IN_REG) & BIT(twi_sda)) != 0; 56 | } 57 | else { 58 | return (REG_READ(GPIO_IN1_REG) & BIT(twi_sda - 32)) != 0; 59 | } 60 | } 61 | 62 | static void SCL_LOW() { 63 | if (twi_scl < 32) { 64 | REG_WRITE(GPIO_ENABLE_W1TS_REG, BIT(twi_scl)); 65 | } 66 | else { 67 | REG_WRITE(GPIO_ENABLE1_W1TS_REG, BIT(twi_scl - 32)); 68 | } 69 | } 70 | 71 | static void SCL_HIGH() { 72 | if (twi_scl < 32) { 73 | REG_WRITE(GPIO_ENABLE_W1TC_REG, BIT(twi_scl)); 74 | } 75 | else { 76 | REG_WRITE(GPIO_ENABLE1_W1TC_REG, BIT(twi_scl - 32)); 77 | } 78 | } 79 | 80 | static uint32_t SCL_READ() { 81 | if (twi_scl < 32) { 82 | return (REG_READ(GPIO_IN_REG) & BIT(twi_scl)) != 0; 83 | } 84 | else { 85 | return (REG_READ(GPIO_IN1_REG) & BIT(twi_scl - 32)) != 0; 86 | } 87 | } 88 | 89 | 90 | #ifndef FCPU80 91 | #define FCPU80 80000000L 92 | #endif 93 | 94 | #if F_CPU == FCPU80 95 | #define TWI_CLOCK_STRETCH 800 96 | #else 97 | #define TWI_CLOCK_STRETCH 1600 98 | #endif 99 | 100 | void twi_setClock(unsigned int freq){ 101 | #if F_CPU == FCPU80 102 | if(freq <= 100000) twi_dcount = 19;//about 100KHz 103 | else if(freq <= 200000) twi_dcount = 8;//about 200KHz 104 | else if(freq <= 300000) twi_dcount = 3;//about 300KHz 105 | else if(freq <= 400000) twi_dcount = 1;//about 400KHz 106 | else twi_dcount = 1;//about 400KHz 107 | #else 108 | if(freq <= 100000) twi_dcount = 32;//about 100KHz 109 | else if(freq <= 200000) twi_dcount = 14;//about 200KHz 110 | else if(freq <= 300000) twi_dcount = 8;//about 300KHz 111 | else if(freq <= 400000) twi_dcount = 5;//about 400KHz 112 | else if(freq <= 500000) twi_dcount = 3;//about 500KHz 113 | else if(freq <= 600000) twi_dcount = 2;//about 600KHz 114 | else twi_dcount = 1;//about 700KHz 115 | #endif 116 | } 117 | 118 | void twi_init(unsigned char sda, unsigned char scl){ 119 | twi_sda = sda; 120 | twi_scl = scl; 121 | pinMode(twi_sda, OUTPUT); 122 | pinMode(twi_scl, OUTPUT); 123 | 124 | digitalWrite(twi_sda, 0); 125 | digitalWrite(twi_scl, 0); 126 | 127 | pinMode(twi_sda, INPUT_PULLUP); 128 | pinMode(twi_scl, INPUT_PULLUP); 129 | twi_setClock(100000); 130 | } 131 | 132 | void twi_stop(void){ 133 | pinMode(twi_sda, INPUT); 134 | pinMode(twi_scl, INPUT); 135 | } 136 | 137 | static void twi_delay(unsigned char v){ 138 | unsigned int i; 139 | #pragma GCC diagnostic push 140 | #pragma GCC diagnostic ignored "-Wunused-but-set-variable" 141 | unsigned int reg; 142 | for(i=0;i 5 | #include 6 | 7 | 8 | // Some functions from Arduino/Wiring 9 | void pinMode(int pin, int mode); 10 | void digitalWrite(int pin, int value); 11 | void delay(int millis); 12 | 13 | #define OUTPUT 0 14 | #define INPUT 1 15 | #define INPUT_PULLUP 2 16 | 17 | // Some functions to make OpenMV happy 18 | #define systick_sleep(t) delay(t) 19 | #define __disable_irq() 20 | #define __enable_irq() 21 | 22 | 23 | 24 | #endif //__OMV_PORT_H__ 25 | -------------------------------------------------------------------------------- /components/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 | static const char* TAG = "camera_xclk"; 8 | 9 | esp_err_t camera_enable_out_clock(camera_config_t* config) 10 | { 11 | periph_module_enable(PERIPH_LEDC_MODULE); 12 | 13 | ledc_timer_config_t timer_conf; 14 | timer_conf.duty_resolution = 1; 15 | timer_conf.freq_hz = config->xclk_freq_hz; 16 | timer_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 17 | timer_conf.timer_num = config->ledc_timer; 18 | esp_err_t err = ledc_timer_config(&timer_conf); 19 | if (err != ESP_OK) { 20 | ESP_LOGE(TAG, "ledc_timer_config failed, rc=%x", err); 21 | return err; 22 | } 23 | 24 | ledc_channel_config_t ch_conf; 25 | ch_conf.channel = config->ledc_channel; 26 | ch_conf.timer_sel = config->ledc_timer; 27 | ch_conf.intr_type = LEDC_INTR_DISABLE; 28 | ch_conf.duty = 1; 29 | ch_conf.speed_mode = LEDC_HIGH_SPEED_MODE; 30 | ch_conf.gpio_num = config->pin_xclk; 31 | ch_conf.hpoint = 0; 32 | err = ledc_channel_config(&ch_conf); 33 | if (err != ESP_OK) { 34 | ESP_LOGE(TAG, "ledc_channel_config failed, rc=%x", err); 35 | return err; 36 | } 37 | return ESP_OK; 38 | } 39 | 40 | void camera_disable_out_clock() 41 | { 42 | periph_module_disable(PERIPH_LEDC_MODULE); 43 | } 44 | -------------------------------------------------------------------------------- /components/camera/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 | -------------------------------------------------------------------------------- /m5cam-firmware.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/m5cam-firmware.zip -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "ESP32 Camera Demo Configuration" 2 | 3 | choice ESP_WIFI_MODE 4 | prompt "AP or STA" 5 | default ESP_WIFI_IS_SOFTAP 6 | help 7 | Whether the esp32 is softAP or station. 8 | 9 | config ESP_WIFI_IS_SOFTAP 10 | bool "SoftAP" 11 | config ESP_WIFI_IS_STATION 12 | bool "Station" 13 | endchoice 14 | 15 | config ESP_WIFI_MODE_AP 16 | bool 17 | default y if ESP_WIFI_IS_SOFTAP 18 | default n if ESP_WIFI_IS_STATION 19 | 20 | config ESP_WIFI_SSID 21 | string "WiFi SSID" 22 | default "M5Cam" 23 | help 24 | SSID (network name) for the example to connect to. 25 | 26 | config ESP_WIFI_PASSWORD 27 | string "WiFi Password" 28 | default "" 29 | help 30 | WiFi password (WPA or WPA2) for the example to use. 31 | 32 | config MAX_STA_CONN 33 | int "Max STA conn" 34 | default 1 35 | help 36 | Max number of the STA connects to AP. 37 | 38 | config XCLK_FREQ 39 | int "XCLK Frequency" 40 | default "20000000" 41 | help 42 | The XCLK Frequency in Herz. 43 | 44 | menu "Pin Configuration" 45 | config D0 46 | int "D0" 47 | default "17" 48 | config D1 49 | int "D1" 50 | default "35" 51 | config D2 52 | int "D2" 53 | default "34" 54 | config D3 55 | int "D3" 56 | default "5" 57 | config D4 58 | int "D4" 59 | default "39" 60 | config D5 61 | int "D5" 62 | default "18" 63 | config D6 64 | int "D6" 65 | default "36" 66 | config D7 67 | int "D7" 68 | default "19" 69 | config XCLK 70 | int "XCLK" 71 | default "27" 72 | config PCLK 73 | int "PCLK" 74 | default "21" 75 | config VSYNC 76 | int "VSYNC" 77 | default "22" 78 | config HREF 79 | int "HREF" 80 | default "26" 81 | config SDA 82 | int "SDA" 83 | default "25" 84 | config SCL 85 | int "SCL" 86 | default "23" 87 | config RESET 88 | int "RESET" 89 | default "15" 90 | endmenu 91 | 92 | endmenu -------------------------------------------------------------------------------- /main/app_main.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2017 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 | 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include "freertos/FreeRTOS.h" 21 | #include "freertos/task.h" 22 | #include "freertos/semphr.h" 23 | #include "freertos/event_groups.h" 24 | 25 | #include "esp_system.h" 26 | #include "esp_wifi.h" 27 | #include "esp_event_loop.h" 28 | #include "esp_log.h" 29 | #include "esp_err.h" 30 | #include "nvs_flash.h" 31 | 32 | #include "driver/gpio.h" 33 | #include "camera.h" 34 | #include "bitmap.h" 35 | #include "http_server.h" 36 | 37 | 38 | /* The examples use simple WiFi configuration that you can set via 39 | 'make menuconfig'. 40 | 41 | If you'd rather not, just change the below entries to strings with 42 | the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" 43 | */ 44 | #define EXAMPLE_ESP_WIFI_MODE_AP CONFIG_ESP_WIFI_MODE_AP // TRUE:AP FALSE:STA 45 | #define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID 46 | #define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD 47 | #define EXAMPLE_MAX_STA_CONN CONFIG_MAX_STA_CONN 48 | #define CAMERA_LED_GPIO 16 49 | 50 | #if EXAMPLE_ESP_WIFI_MODE_AP 51 | static void wifi_init_softap(void); 52 | #else 53 | static void wifi_init_sta(void); 54 | #endif 55 | 56 | static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx); 57 | static void handle_rgb_bmp(http_context_t http_ctx, void* ctx); 58 | static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx); 59 | static void handle_jpg(http_context_t http_ctx, void* ctx); 60 | static void handle_jpg_stream(http_context_t http_ctx, void* ctx); 61 | static esp_err_t event_handler(void *ctx, system_event_t *event); 62 | 63 | 64 | static const char* TAG = "camera_demo"; 65 | 66 | static const char* STREAM_CONTENT_TYPE = 67 | "multipart/x-mixed-replace; boundary=123456789000000000000987654321"; 68 | 69 | static const char* STREAM_BOUNDARY = "--123456789000000000000987654321"; 70 | 71 | static EventGroupHandle_t s_wifi_event_group; 72 | const int CONNECTED_BIT = BIT0; 73 | static ip4_addr_t s_ip_addr; 74 | static camera_pixelformat_t s_pixel_format; 75 | 76 | #define CAMERA_PIXEL_FORMAT CAMERA_PF_GRAYSCALE 77 | #define CAMERA_FRAME_SIZE CAMERA_FS_SVGA 78 | 79 | 80 | void app_main() 81 | { 82 | esp_log_level_set("wifi", ESP_LOG_WARN); 83 | esp_log_level_set("gpio", ESP_LOG_WARN); 84 | 85 | esp_err_t err = nvs_flash_init(); 86 | if (err != ESP_OK) { 87 | ESP_ERROR_CHECK( nvs_flash_erase() ); 88 | ESP_ERROR_CHECK( nvs_flash_init() ); 89 | } 90 | 91 | ESP_ERROR_CHECK(gpio_install_isr_service(0)); 92 | gpio_set_direction(CAMERA_LED_GPIO, GPIO_MODE_OUTPUT); 93 | gpio_set_level(CAMERA_LED_GPIO, 1); 94 | 95 | camera_config_t camera_config = { 96 | .ledc_channel = LEDC_CHANNEL_0, 97 | .ledc_timer = LEDC_TIMER_0, 98 | .pin_d0 = CONFIG_D0, 99 | .pin_d1 = CONFIG_D1, 100 | .pin_d2 = CONFIG_D2, 101 | .pin_d3 = CONFIG_D3, 102 | .pin_d4 = CONFIG_D4, 103 | .pin_d5 = CONFIG_D5, 104 | .pin_d6 = CONFIG_D6, 105 | .pin_d7 = CONFIG_D7, 106 | .pin_xclk = CONFIG_XCLK, 107 | .pin_pclk = CONFIG_PCLK, 108 | .pin_vsync = CONFIG_VSYNC, 109 | .pin_href = CONFIG_HREF, 110 | .pin_sscb_sda = CONFIG_SDA, 111 | .pin_sscb_scl = CONFIG_SCL, 112 | .pin_reset = CONFIG_RESET, 113 | .xclk_freq_hz = CONFIG_XCLK_FREQ, 114 | }; 115 | 116 | camera_model_t camera_model; 117 | err = camera_probe(&camera_config, &camera_model); 118 | if (err != ESP_OK) { 119 | ESP_LOGE(TAG, "Camera probe failed with error 0x%x", err); 120 | return; 121 | } 122 | 123 | if (camera_model == CAMERA_OV7725) { 124 | s_pixel_format = CAMERA_PIXEL_FORMAT; 125 | camera_config.frame_size = CAMERA_FRAME_SIZE; 126 | ESP_LOGI(TAG, "Detected OV7725 camera, using %s bitmap format", 127 | CAMERA_PIXEL_FORMAT == CAMERA_PF_GRAYSCALE ? 128 | "grayscale" : "RGB565"); 129 | } else if (camera_model == CAMERA_OV2640) { 130 | ESP_LOGI(TAG, "Detected OV2640 camera, using JPEG format"); 131 | s_pixel_format = CAMERA_PF_JPEG; 132 | camera_config.frame_size = CAMERA_FRAME_SIZE; 133 | camera_config.jpeg_quality = 15; 134 | } else { 135 | ESP_LOGE(TAG, "Camera not supported"); 136 | return; 137 | } 138 | 139 | camera_config.pixel_format = s_pixel_format; 140 | err = camera_init(&camera_config); 141 | if (err != ESP_OK) { 142 | ESP_LOGE(TAG, "Camera init failed with error 0x%x", err); 143 | return; 144 | } 145 | 146 | #if EXAMPLE_ESP_WIFI_MODE_AP 147 | ESP_LOGI(TAG, "ESP_WIFI_MODE_AP"); 148 | wifi_init_softap(); 149 | #else 150 | ESP_LOGI(TAG, "ESP_WIFI_MODE_STA"); 151 | wifi_init_sta(); 152 | #endif 153 | 154 | http_server_t server; 155 | http_server_options_t http_options = HTTP_SERVER_OPTIONS_DEFAULT(); 156 | ESP_ERROR_CHECK( http_server_start(&http_options, &server) ); 157 | 158 | if (s_pixel_format == CAMERA_PF_GRAYSCALE) { 159 | ESP_ERROR_CHECK( http_register_handler(server, "/pgm", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_grayscale_pgm, NULL) ); 160 | ESP_LOGI(TAG, "Open http://" IPSTR "/pgm for a single image/x-portable-graymap image", IP2STR(&s_ip_addr)); 161 | } 162 | if (s_pixel_format == CAMERA_PF_RGB565) { 163 | ESP_ERROR_CHECK( http_register_handler(server, "/bmp", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp, NULL) ); 164 | ESP_LOGI(TAG, "Open http://" IPSTR "/bmp for single image/bitmap image", IP2STR(&s_ip_addr)); 165 | ESP_ERROR_CHECK( http_register_handler(server, "/bmp_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_rgb_bmp_stream, NULL) ); 166 | ESP_LOGI(TAG, "Open http://" IPSTR "/bmp_stream for multipart/x-mixed-replace stream of bitmaps", IP2STR(&s_ip_addr)); 167 | } 168 | if (s_pixel_format == CAMERA_PF_JPEG) { 169 | ESP_ERROR_CHECK( http_register_handler(server, "/jpg", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg, NULL) ); 170 | ESP_LOGI(TAG, "Open http://" IPSTR "/jpg for single image/jpg image", IP2STR(&s_ip_addr)); 171 | ESP_ERROR_CHECK( http_register_handler(server, "/jpg_stream", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) ); 172 | ESP_LOGI(TAG, "Open http://" IPSTR "/jpg_stream for multipart/x-mixed-replace stream of JPEGs", IP2STR(&s_ip_addr)); 173 | ESP_ERROR_CHECK( http_register_handler(server, "/", HTTP_GET, HTTP_HANDLE_RESPONSE, &handle_jpg_stream, NULL) ); 174 | } 175 | ESP_LOGI(TAG, "Free heap: %u", xPortGetFreeHeapSize()); 176 | ESP_LOGI(TAG, "Camera demo ready"); 177 | 178 | } 179 | 180 | static esp_err_t write_frame(http_context_t http_ctx) 181 | { 182 | http_buffer_t fb_data = { 183 | .data = camera_get_fb(), 184 | .size = camera_get_data_size(), 185 | .data_is_persistent = true 186 | }; 187 | return http_response_write(http_ctx, &fb_data); 188 | } 189 | 190 | static void handle_grayscale_pgm(http_context_t http_ctx, void* ctx) 191 | { 192 | esp_err_t err = camera_run(); 193 | if (err != ESP_OK) { 194 | ESP_LOGD(TAG, "Camera capture failed with error = %d", err); 195 | return; 196 | } 197 | char* pgm_header_str; 198 | asprintf(&pgm_header_str, "P5 %d %d %d\n", 199 | camera_get_fb_width(), camera_get_fb_height(), 255); 200 | if (pgm_header_str == NULL) { 201 | return; 202 | } 203 | 204 | size_t response_size = strlen(pgm_header_str) + camera_get_data_size(); 205 | http_response_begin(http_ctx, 200, "image/x-portable-graymap", response_size); 206 | http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.pgm"); 207 | http_buffer_t pgm_header = { .data = pgm_header_str }; 208 | http_response_write(http_ctx, &pgm_header); 209 | free(pgm_header_str); 210 | 211 | write_frame(http_ctx); 212 | http_response_end(http_ctx); 213 | } 214 | 215 | static void handle_rgb_bmp(http_context_t http_ctx, void* ctx) 216 | { 217 | esp_err_t err = camera_run(); 218 | if (err != ESP_OK) { 219 | ESP_LOGD(TAG, "Camera capture failed with error = %d", err); 220 | return; 221 | } 222 | 223 | bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height()); 224 | if (header == NULL) { 225 | return; 226 | } 227 | 228 | http_response_begin(http_ctx, 200, "image/bmp", sizeof(*header) + camera_get_data_size()); 229 | http_buffer_t bmp_header = { 230 | .data = header, 231 | .size = sizeof(*header) 232 | }; 233 | http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.bmp"); 234 | http_response_write(http_ctx, &bmp_header); 235 | free(header); 236 | 237 | write_frame(http_ctx); 238 | http_response_end(http_ctx); 239 | } 240 | 241 | static void handle_jpg(http_context_t http_ctx, void* ctx) 242 | { 243 | esp_err_t err = camera_run(); 244 | if (err != ESP_OK) { 245 | ESP_LOGD(TAG, "Camera capture failed with error = %d", err); 246 | return; 247 | } 248 | 249 | http_response_begin(http_ctx, 200, "image/jpeg", camera_get_data_size()); 250 | http_response_set_header(http_ctx, "Content-disposition", "inline; filename=capture.jpg"); 251 | write_frame(http_ctx); 252 | http_response_end(http_ctx); 253 | } 254 | 255 | 256 | static void handle_rgb_bmp_stream(http_context_t http_ctx, void* ctx) 257 | { 258 | http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); 259 | bitmap_header_t* header = bmp_create_header(camera_get_fb_width(), camera_get_fb_height()); 260 | if (header == NULL) { 261 | return; 262 | } 263 | http_buffer_t bmp_header = { 264 | .data = header, 265 | .size = sizeof(*header) 266 | }; 267 | 268 | 269 | while (true) { 270 | esp_err_t err = camera_run(); 271 | if (err != ESP_OK) { 272 | ESP_LOGD(TAG, "Camera capture failed with error = %d", err); 273 | return; 274 | } 275 | 276 | err = http_response_begin_multipart(http_ctx, "image/bitmap", 277 | camera_get_data_size() + sizeof(*header)); 278 | if (err != ESP_OK) { 279 | break; 280 | } 281 | err = http_response_write(http_ctx, &bmp_header); 282 | if (err != ESP_OK) { 283 | break; 284 | } 285 | err = write_frame(http_ctx); 286 | if (err != ESP_OK) { 287 | break; 288 | } 289 | err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY); 290 | if (err != ESP_OK) { 291 | break; 292 | } 293 | } 294 | 295 | free(header); 296 | http_response_end(http_ctx); 297 | } 298 | 299 | static void handle_jpg_stream(http_context_t http_ctx, void* ctx) 300 | { 301 | http_response_begin(http_ctx, 200, STREAM_CONTENT_TYPE, HTTP_RESPONSE_SIZE_UNKNOWN); 302 | 303 | while (true) { 304 | esp_err_t err = camera_run(); 305 | if (err != ESP_OK) { 306 | ESP_LOGD(TAG, "Camera capture failed with error = %d", err); 307 | return; 308 | } 309 | err = http_response_begin_multipart(http_ctx, "image/jpg", 310 | camera_get_data_size()); 311 | if (err != ESP_OK) { 312 | break; 313 | } 314 | err = write_frame(http_ctx); 315 | if (err != ESP_OK) { 316 | break; 317 | } 318 | err = http_response_end_multipart(http_ctx, STREAM_BOUNDARY); 319 | if (err != ESP_OK) { 320 | break; 321 | } 322 | } 323 | http_response_end(http_ctx); 324 | } 325 | 326 | 327 | // /* FreeRTOS event group to signal when we are connected*/ 328 | // static EventGroupHandle_t s_wifi_event_group; 329 | 330 | // /* The event group allows multiple bits for each event, 331 | // but we only care about one event - are we connected 332 | // to the AP with an IP? */ 333 | // const int WIFI_CONNECTED_BIT = BIT0; 334 | 335 | static esp_err_t event_handler(void* ctx, system_event_t* event) 336 | { 337 | switch (event->event_id) { 338 | case SYSTEM_EVENT_STA_START: 339 | esp_wifi_connect(); 340 | break; 341 | case SYSTEM_EVENT_STA_GOT_IP: 342 | ESP_LOGI(TAG, "got ip:%s", ip4addr_ntoa(&event->event_info.got_ip.ip_info.ip)); 343 | s_ip_addr = event->event_info.got_ip.ip_info.ip; 344 | xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT); 345 | break; 346 | case SYSTEM_EVENT_AP_STACONNECTED: 347 | ESP_LOGI(TAG, "station:" MACSTR " join, AID=%d", MAC2STR(event->event_info.sta_connected.mac), 348 | event->event_info.sta_connected.aid); 349 | #if EXAMPLE_ESP_WIFI_MODE_AP 350 | xEventGroupSetBits(s_wifi_event_group, CONNECTED_BIT); 351 | #endif 352 | break; 353 | case SYSTEM_EVENT_AP_STADISCONNECTED: 354 | ESP_LOGI(TAG, "station:" MACSTR "leave, AID=%d", MAC2STR(event->event_info.sta_disconnected.mac), 355 | event->event_info.sta_disconnected.aid); 356 | #if EXAMPLE_ESP_WIFI_MODE_AP 357 | xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); 358 | #endif 359 | break; 360 | case SYSTEM_EVENT_STA_DISCONNECTED: 361 | esp_wifi_connect(); 362 | xEventGroupClearBits(s_wifi_event_group, CONNECTED_BIT); 363 | break; 364 | default: 365 | break; 366 | } 367 | return ESP_OK; 368 | } 369 | 370 | #if EXAMPLE_ESP_WIFI_MODE_AP 371 | 372 | static void wifi_init_softap() 373 | { 374 | s_wifi_event_group = xEventGroupCreate(); 375 | 376 | tcpip_adapter_init(); 377 | ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); 378 | 379 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 380 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 381 | wifi_config_t wifi_config = { 382 | .ap = {.ssid = EXAMPLE_ESP_WIFI_SSID, 383 | .ssid_len = strlen(EXAMPLE_ESP_WIFI_SSID), 384 | .password = EXAMPLE_ESP_WIFI_PASS, 385 | .max_connection = EXAMPLE_MAX_STA_CONN, 386 | .authmode = WIFI_AUTH_WPA_WPA2_PSK}, 387 | }; 388 | if (strlen(EXAMPLE_ESP_WIFI_PASS) == 0) { 389 | wifi_config.ap.authmode = WIFI_AUTH_OPEN; 390 | } 391 | 392 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); 393 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config)); 394 | ESP_ERROR_CHECK(esp_wifi_start()); 395 | 396 | uint8_t addr[4] = {192, 168, 4, 1}; 397 | s_ip_addr = *(ip4_addr_t*)&addr; 398 | 399 | ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s", 400 | EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS); 401 | } 402 | 403 | #else 404 | 405 | static void wifi_init_sta() 406 | { 407 | s_wifi_event_group = xEventGroupCreate(); 408 | 409 | tcpip_adapter_init(); 410 | ESP_ERROR_CHECK(esp_event_loop_init(event_handler, NULL)); 411 | 412 | wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 413 | ESP_ERROR_CHECK(esp_wifi_init(&cfg)); 414 | wifi_config_t wifi_config = { 415 | .sta = {.ssid = EXAMPLE_ESP_WIFI_SSID, .password = EXAMPLE_ESP_WIFI_PASS}, 416 | }; 417 | 418 | ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); 419 | ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config)); 420 | ESP_ERROR_CHECK(esp_wifi_start()); 421 | 422 | ESP_LOGI(TAG, "wifi_init_sta finished."); 423 | ESP_LOGI(TAG, "connect to ap SSID:%s password:%s", EXAMPLE_ESP_WIFI_SSID, 424 | EXAMPLE_ESP_WIFI_PASS); 425 | 426 | xEventGroupWaitBits(s_wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); 427 | } 428 | #endif -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main Makefile. This is basically the same as a component makefile. 3 | # 4 | # This Makefile should, at the very least, just include $(SDK_PATH)/make/component.mk. By default, 5 | # this will take the sources in the src/ directory, compile them and link them into 6 | # lib(subdirectory_name).a in the build directory. This behaviour is entirely configurable, 7 | # please read the SDK documents if you need to do this. 8 | # 9 | 10 | -------------------------------------------------------------------------------- /pictures/chessboard-core-board-v2-ov7725.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/chessboard-core-board-v2-ov7725.jpg -------------------------------------------------------------------------------- /pictures/chessboard-esp-wrover-v1-ov7725.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/chessboard-esp-wrover-v1-ov7725.jpg -------------------------------------------------------------------------------- /pictures/core-board-v2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/core-board-v2.jpg -------------------------------------------------------------------------------- /pictures/daughter-board-camera-module-side.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/daughter-board-camera-module-side.jpg -------------------------------------------------------------------------------- /pictures/daughter-board-esp32-module-side.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/daughter-board-esp32-module-side.jpg -------------------------------------------------------------------------------- /pictures/esp-wrover-v1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/esp-wrover-v1.jpg -------------------------------------------------------------------------------- /pictures/ov7725-alternate-wiring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/ov7725-alternate-wiring.png -------------------------------------------------------------------------------- /pictures/ov7725-camera-module.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/ov7725-camera-module.jpg -------------------------------------------------------------------------------- /pictures/sw-operation-diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/sw-operation-diagram.png -------------------------------------------------------------------------------- /pictures/wiring-1-core-board-v2-ov7725.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/wiring-1-core-board-v2-ov7725.jpg -------------------------------------------------------------------------------- /pictures/wiring-2-core-board-v2-ov7725.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/wiring-2-core-board-v2-ov7725.jpg -------------------------------------------------------------------------------- /pictures/wiring-esp-wrover-v1-ov7725.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/m5stack/esp32-cam-demo/51dd0c79916e4b1b597545d2574b8c52395ebb24/pictures/wiring-esp-wrover-v1-ov7725.jpg -------------------------------------------------------------------------------- /sdkconfig: -------------------------------------------------------------------------------- 1 | # 2 | # Automatically generated file; DO NOT EDIT. 3 | # Espressif IoT Development Framework Configuration 4 | # 5 | 6 | # 7 | # SDK tool configuration 8 | # 9 | CONFIG_TOOLPREFIX="xtensa-esp32-elf-" 10 | CONFIG_PYTHON="python" 11 | CONFIG_MAKE_WARN_UNDEFINED_VARIABLES=y 12 | 13 | # 14 | # Bootloader config 15 | # 16 | CONFIG_LOG_BOOTLOADER_LEVEL_NONE= 17 | CONFIG_LOG_BOOTLOADER_LEVEL_ERROR= 18 | CONFIG_LOG_BOOTLOADER_LEVEL_WARN= 19 | CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y 20 | CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG= 21 | CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE= 22 | CONFIG_LOG_BOOTLOADER_LEVEL=3 23 | CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V= 24 | CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y 25 | CONFIG_BOOTLOADER_FACTORY_RESET= 26 | CONFIG_BOOTLOADER_APP_TEST= 27 | 28 | # 29 | # Security features 30 | # 31 | CONFIG_SECURE_BOOT_ENABLED= 32 | CONFIG_FLASH_ENCRYPTION_ENABLED= 33 | 34 | # 35 | # Serial flasher config 36 | # 37 | CONFIG_ESPTOOLPY_PORT="/dev/tty.SLAB_USBtoUART" 38 | CONFIG_ESPTOOLPY_BAUD_115200B= 39 | CONFIG_ESPTOOLPY_BAUD_230400B= 40 | CONFIG_ESPTOOLPY_BAUD_921600B=y 41 | CONFIG_ESPTOOLPY_BAUD_2MB= 42 | CONFIG_ESPTOOLPY_BAUD_OTHER= 43 | CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200 44 | CONFIG_ESPTOOLPY_BAUD=921600 45 | CONFIG_ESPTOOLPY_COMPRESSED=y 46 | CONFIG_FLASHMODE_QIO= 47 | CONFIG_FLASHMODE_QOUT= 48 | CONFIG_FLASHMODE_DIO=y 49 | CONFIG_FLASHMODE_DOUT= 50 | CONFIG_ESPTOOLPY_FLASHMODE="dio" 51 | CONFIG_ESPTOOLPY_FLASHFREQ_80M= 52 | CONFIG_ESPTOOLPY_FLASHFREQ_40M=y 53 | CONFIG_ESPTOOLPY_FLASHFREQ_26M= 54 | CONFIG_ESPTOOLPY_FLASHFREQ_20M= 55 | CONFIG_ESPTOOLPY_FLASHFREQ="40m" 56 | CONFIG_ESPTOOLPY_FLASHSIZE_1MB= 57 | CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y 58 | CONFIG_ESPTOOLPY_FLASHSIZE_4MB= 59 | CONFIG_ESPTOOLPY_FLASHSIZE_8MB= 60 | CONFIG_ESPTOOLPY_FLASHSIZE_16MB= 61 | CONFIG_ESPTOOLPY_FLASHSIZE="2MB" 62 | CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y 63 | CONFIG_ESPTOOLPY_BEFORE_RESET=y 64 | CONFIG_ESPTOOLPY_BEFORE_NORESET= 65 | CONFIG_ESPTOOLPY_BEFORE="default_reset" 66 | CONFIG_ESPTOOLPY_AFTER_RESET=y 67 | CONFIG_ESPTOOLPY_AFTER_NORESET= 68 | CONFIG_ESPTOOLPY_AFTER="hard_reset" 69 | CONFIG_MONITOR_BAUD_9600B= 70 | CONFIG_MONITOR_BAUD_57600B= 71 | CONFIG_MONITOR_BAUD_115200B=y 72 | CONFIG_MONITOR_BAUD_230400B= 73 | CONFIG_MONITOR_BAUD_921600B= 74 | CONFIG_MONITOR_BAUD_2MB= 75 | CONFIG_MONITOR_BAUD_OTHER= 76 | CONFIG_MONITOR_BAUD_OTHER_VAL=115200 77 | CONFIG_MONITOR_BAUD=115200 78 | 79 | # 80 | # ESP32 Camera Demo Configuration 81 | # 82 | CONFIG_ESP_WIFI_IS_SOFTAP=y 83 | CONFIG_ESP_WIFI_IS_STATION= 84 | CONFIG_ESP_WIFI_MODE_AP=y 85 | CONFIG_ESP_WIFI_SSID="M5Cam" 86 | CONFIG_ESP_WIFI_PASSWORD="" 87 | CONFIG_MAX_STA_CONN=1 88 | CONFIG_XCLK_FREQ=20000000 89 | 90 | # 91 | # Pin Configuration 92 | # 93 | CONFIG_D0=17 94 | CONFIG_D1=35 95 | CONFIG_D2=34 96 | CONFIG_D3=5 97 | CONFIG_D4=39 98 | CONFIG_D5=18 99 | CONFIG_D6=36 100 | CONFIG_D7=19 101 | CONFIG_XCLK=27 102 | CONFIG_PCLK=21 103 | CONFIG_VSYNC=22 104 | CONFIG_HREF=26 105 | CONFIG_SDA=25 106 | CONFIG_SCL=23 107 | CONFIG_RESET=15 108 | 109 | # 110 | # Partition Table 111 | # 112 | CONFIG_PARTITION_TABLE_SINGLE_APP=y 113 | CONFIG_PARTITION_TABLE_TWO_OTA= 114 | CONFIG_PARTITION_TABLE_CUSTOM= 115 | CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv" 116 | CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000 117 | CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv" 118 | CONFIG_APP_OFFSET=0x10000 119 | CONFIG_PARTITION_TABLE_MD5=y 120 | 121 | # 122 | # Compiler options 123 | # 124 | CONFIG_OPTIMIZATION_LEVEL_DEBUG=y 125 | CONFIG_OPTIMIZATION_LEVEL_RELEASE= 126 | CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y 127 | CONFIG_OPTIMIZATION_ASSERTIONS_SILENT= 128 | CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED= 129 | CONFIG_CXX_EXCEPTIONS= 130 | CONFIG_STACK_CHECK_NONE=y 131 | CONFIG_STACK_CHECK_NORM= 132 | CONFIG_STACK_CHECK_STRONG= 133 | CONFIG_STACK_CHECK_ALL= 134 | CONFIG_STACK_CHECK= 135 | CONFIG_WARN_WRITE_STRINGS= 136 | 137 | # 138 | # Component config 139 | # 140 | 141 | # 142 | # Application Level Tracing 143 | # 144 | CONFIG_ESP32_APPTRACE_DEST_TRAX= 145 | CONFIG_ESP32_APPTRACE_DEST_NONE=y 146 | CONFIG_ESP32_APPTRACE_ENABLE= 147 | CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y 148 | CONFIG_AWS_IOT_SDK= 149 | 150 | # 151 | # Bluetooth 152 | # 153 | CONFIG_BT_ENABLED= 154 | CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0 155 | CONFIG_BT_RESERVE_DRAM=0 156 | 157 | # 158 | # Camera configuration 159 | # 160 | CONFIG_ENABLE_TEST_PATTERN= 161 | CONFIG_OV2640_SUPPORT=y 162 | CONFIG_OV7725_SUPPORT=y 163 | 164 | # 165 | # ADC configuration 166 | # 167 | CONFIG_ADC_FORCE_XPD_FSM= 168 | CONFIG_ADC2_DISABLE_DAC=y 169 | 170 | # 171 | # ESP32-specific 172 | # 173 | CONFIG_ESP32_DEFAULT_CPU_FREQ_80= 174 | CONFIG_ESP32_DEFAULT_CPU_FREQ_160= 175 | CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y 176 | CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 177 | CONFIG_SPIRAM_SUPPORT= 178 | CONFIG_MEMMAP_TRACEMEM= 179 | CONFIG_MEMMAP_TRACEMEM_TWOBANKS= 180 | CONFIG_ESP32_TRAX= 181 | CONFIG_TRACEMEM_RESERVE_DRAM=0x0 182 | CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH= 183 | CONFIG_ESP32_ENABLE_COREDUMP_TO_UART= 184 | CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=y 185 | CONFIG_ESP32_ENABLE_COREDUMP= 186 | CONFIG_TWO_UNIVERSAL_MAC_ADDRESS= 187 | CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y 188 | CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4 189 | CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32 190 | CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304 191 | CONFIG_MAIN_TASK_STACK_SIZE=3584 192 | CONFIG_IPC_TASK_STACK_SIZE=1024 193 | CONFIG_TIMER_TASK_STACK_SIZE=3584 194 | CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y 195 | CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF= 196 | CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR= 197 | CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF= 198 | CONFIG_NEWLIB_STDIN_LINE_ENDING_LF= 199 | CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y 200 | CONFIG_NEWLIB_NANO_FORMAT= 201 | CONFIG_CONSOLE_UART_DEFAULT=y 202 | CONFIG_CONSOLE_UART_CUSTOM= 203 | CONFIG_CONSOLE_UART_NONE= 204 | CONFIG_CONSOLE_UART_NUM=0 205 | CONFIG_CONSOLE_UART_BAUDRATE=115200 206 | CONFIG_ULP_COPROC_ENABLED= 207 | CONFIG_ULP_COPROC_RESERVE_MEM=0 208 | CONFIG_ESP32_PANIC_PRINT_HALT= 209 | CONFIG_ESP32_PANIC_PRINT_REBOOT=y 210 | CONFIG_ESP32_PANIC_SILENT_REBOOT= 211 | CONFIG_ESP32_PANIC_GDBSTUB= 212 | CONFIG_ESP32_DEBUG_OCDAWARE=y 213 | CONFIG_ESP32_DEBUG_STUBS_ENABLE=y 214 | CONFIG_INT_WDT=y 215 | CONFIG_INT_WDT_TIMEOUT_MS=300 216 | CONFIG_INT_WDT_CHECK_CPU1=y 217 | CONFIG_TASK_WDT= 218 | CONFIG_BROWNOUT_DET=y 219 | CONFIG_BROWNOUT_DET_LVL_SEL_0=y 220 | CONFIG_BROWNOUT_DET_LVL_SEL_1= 221 | CONFIG_BROWNOUT_DET_LVL_SEL_2= 222 | CONFIG_BROWNOUT_DET_LVL_SEL_3= 223 | CONFIG_BROWNOUT_DET_LVL_SEL_4= 224 | CONFIG_BROWNOUT_DET_LVL_SEL_5= 225 | CONFIG_BROWNOUT_DET_LVL_SEL_6= 226 | CONFIG_BROWNOUT_DET_LVL_SEL_7= 227 | CONFIG_BROWNOUT_DET_LVL=0 228 | CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y 229 | CONFIG_ESP32_TIME_SYSCALL_USE_RTC= 230 | CONFIG_ESP32_TIME_SYSCALL_USE_FRC1= 231 | CONFIG_ESP32_TIME_SYSCALL_USE_NONE= 232 | CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y 233 | CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL= 234 | CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024 235 | CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000 236 | CONFIG_ESP32_XTAL_FREQ_40=y 237 | CONFIG_ESP32_XTAL_FREQ_26= 238 | CONFIG_ESP32_XTAL_FREQ_AUTO= 239 | CONFIG_ESP32_XTAL_FREQ=40 240 | CONFIG_DISABLE_BASIC_ROM_CONSOLE= 241 | CONFIG_NO_BLOBS= 242 | CONFIG_ESP_TIMER_PROFILING= 243 | CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS= 244 | CONFIG_ESP_ERR_TO_NAME_LOOKUP=y 245 | 246 | # 247 | # Wi-Fi 248 | # 249 | CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10 250 | CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32 251 | CONFIG_ESP32_WIFI_STATIC_TX_BUFFER= 252 | CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y 253 | CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1 254 | CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32 255 | CONFIG_ESP32_WIFI_CSI_ENABLED= 256 | CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y 257 | CONFIG_ESP32_WIFI_TX_BA_WIN=6 258 | CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y 259 | CONFIG_ESP32_WIFI_RX_BA_WIN=6 260 | CONFIG_ESP32_WIFI_NVS_ENABLED=y 261 | CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y 262 | CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1= 263 | 264 | # 265 | # PHY 266 | # 267 | CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y 268 | CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION= 269 | CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20 270 | CONFIG_ESP32_PHY_MAX_TX_POWER=20 271 | 272 | # 273 | # Power Management 274 | # 275 | CONFIG_PM_ENABLE= 276 | 277 | # 278 | # ADC-Calibration 279 | # 280 | CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y 281 | CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y 282 | CONFIG_ADC_CAL_LUT_ENABLE=y 283 | 284 | # 285 | # ESP HTTP client 286 | # 287 | CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y 288 | 289 | # 290 | # Ethernet 291 | # 292 | CONFIG_DMA_RX_BUF_NUM=10 293 | CONFIG_DMA_TX_BUF_NUM=10 294 | CONFIG_EMAC_L2_TO_L3_RX_BUF_MODE= 295 | CONFIG_EMAC_TASK_PRIORITY=20 296 | 297 | # 298 | # FAT Filesystem support 299 | # 300 | CONFIG_FATFS_CODEPAGE_DYNAMIC= 301 | CONFIG_FATFS_CODEPAGE_437=y 302 | CONFIG_FATFS_CODEPAGE_720= 303 | CONFIG_FATFS_CODEPAGE_737= 304 | CONFIG_FATFS_CODEPAGE_771= 305 | CONFIG_FATFS_CODEPAGE_775= 306 | CONFIG_FATFS_CODEPAGE_850= 307 | CONFIG_FATFS_CODEPAGE_852= 308 | CONFIG_FATFS_CODEPAGE_855= 309 | CONFIG_FATFS_CODEPAGE_857= 310 | CONFIG_FATFS_CODEPAGE_860= 311 | CONFIG_FATFS_CODEPAGE_861= 312 | CONFIG_FATFS_CODEPAGE_862= 313 | CONFIG_FATFS_CODEPAGE_863= 314 | CONFIG_FATFS_CODEPAGE_864= 315 | CONFIG_FATFS_CODEPAGE_865= 316 | CONFIG_FATFS_CODEPAGE_866= 317 | CONFIG_FATFS_CODEPAGE_869= 318 | CONFIG_FATFS_CODEPAGE_932= 319 | CONFIG_FATFS_CODEPAGE_936= 320 | CONFIG_FATFS_CODEPAGE_949= 321 | CONFIG_FATFS_CODEPAGE_950= 322 | CONFIG_FATFS_CODEPAGE=437 323 | CONFIG_FATFS_LFN_NONE=y 324 | CONFIG_FATFS_LFN_HEAP= 325 | CONFIG_FATFS_LFN_STACK= 326 | CONFIG_FATFS_FS_LOCK=0 327 | CONFIG_FATFS_TIMEOUT_MS=10000 328 | CONFIG_FATFS_PER_FILE_CACHE=y 329 | 330 | # 331 | # FreeRTOS 332 | # 333 | CONFIG_FREERTOS_UNICORE= 334 | CONFIG_FREERTOS_CORETIMER_0=y 335 | CONFIG_FREERTOS_CORETIMER_1= 336 | CONFIG_FREERTOS_HZ=100 337 | CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y 338 | CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE= 339 | CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL= 340 | CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y 341 | CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK= 342 | CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y 343 | CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1 344 | CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y 345 | CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE= 346 | CONFIG_FREERTOS_ASSERT_DISABLE= 347 | CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536 348 | CONFIG_FREERTOS_ISR_STACKSIZE=1536 349 | CONFIG_FREERTOS_LEGACY_HOOKS= 350 | CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16 351 | CONFIG_SUPPORT_STATIC_ALLOCATION= 352 | CONFIG_TIMER_TASK_PRIORITY=1 353 | CONFIG_TIMER_TASK_STACK_DEPTH=2048 354 | CONFIG_TIMER_QUEUE_LENGTH=10 355 | CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0 356 | CONFIG_FREERTOS_USE_TRACE_FACILITY= 357 | CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS= 358 | CONFIG_FREERTOS_DEBUG_INTERNALS= 359 | 360 | # 361 | # Heap memory debugging 362 | # 363 | CONFIG_HEAP_POISONING_DISABLED=y 364 | CONFIG_HEAP_POISONING_LIGHT= 365 | CONFIG_HEAP_POISONING_COMPREHENSIVE= 366 | CONFIG_HEAP_TRACING= 367 | 368 | # 369 | # libsodium 370 | # 371 | CONFIG_LIBSODIUM_USE_MBEDTLS_SHA=y 372 | 373 | # 374 | # Log output 375 | # 376 | CONFIG_LOG_DEFAULT_LEVEL_NONE= 377 | CONFIG_LOG_DEFAULT_LEVEL_ERROR= 378 | CONFIG_LOG_DEFAULT_LEVEL_WARN= 379 | CONFIG_LOG_DEFAULT_LEVEL_INFO=y 380 | CONFIG_LOG_DEFAULT_LEVEL_DEBUG= 381 | CONFIG_LOG_DEFAULT_LEVEL_VERBOSE= 382 | CONFIG_LOG_DEFAULT_LEVEL=3 383 | CONFIG_LOG_COLORS=y 384 | 385 | # 386 | # LWIP 387 | # 388 | CONFIG_L2_TO_L3_COPY= 389 | CONFIG_LWIP_IRAM_OPTIMIZATION= 390 | CONFIG_LWIP_MAX_SOCKETS=10 391 | CONFIG_USE_ONLY_LWIP_SELECT= 392 | CONFIG_LWIP_SO_REUSE=y 393 | CONFIG_LWIP_SO_REUSE_RXTOALL=y 394 | CONFIG_LWIP_SO_RCVBUF= 395 | CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1 396 | CONFIG_LWIP_IP_FRAG= 397 | CONFIG_LWIP_IP_REASSEMBLY= 398 | CONFIG_LWIP_STATS= 399 | CONFIG_LWIP_ETHARP_TRUST_IP_MAC=y 400 | CONFIG_TCPIP_RECVMBOX_SIZE=32 401 | CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y 402 | 403 | # 404 | # DHCP server 405 | # 406 | CONFIG_LWIP_DHCPS_LEASE_UNIT=60 407 | CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8 408 | CONFIG_LWIP_AUTOIP= 409 | CONFIG_LWIP_NETIF_LOOPBACK=y 410 | CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8 411 | 412 | # 413 | # TCP 414 | # 415 | CONFIG_LWIP_MAX_ACTIVE_TCP=16 416 | CONFIG_LWIP_MAX_LISTENING_TCP=16 417 | CONFIG_TCP_MAXRTX=12 418 | CONFIG_TCP_SYNMAXRTX=6 419 | CONFIG_TCP_MSS=1436 420 | CONFIG_TCP_MSL=60000 421 | CONFIG_TCP_SND_BUF_DEFAULT=5744 422 | CONFIG_TCP_WND_DEFAULT=5744 423 | CONFIG_TCP_RECVMBOX_SIZE=6 424 | CONFIG_TCP_QUEUE_OOSEQ=y 425 | CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES= 426 | CONFIG_TCP_OVERSIZE_MSS=y 427 | CONFIG_TCP_OVERSIZE_QUARTER_MSS= 428 | CONFIG_TCP_OVERSIZE_DISABLE= 429 | 430 | # 431 | # UDP 432 | # 433 | CONFIG_LWIP_MAX_UDP_PCBS=16 434 | CONFIG_UDP_RECVMBOX_SIZE=6 435 | CONFIG_TCPIP_TASK_STACK_SIZE=2048 436 | CONFIG_PPP_SUPPORT= 437 | 438 | # 439 | # ICMP 440 | # 441 | CONFIG_LWIP_MULTICAST_PING= 442 | CONFIG_LWIP_BROADCAST_PING= 443 | 444 | # 445 | # LWIP RAW API 446 | # 447 | CONFIG_LWIP_MAX_RAW_PCBS=16 448 | 449 | # 450 | # mbedTLS 451 | # 452 | CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384 453 | CONFIG_MBEDTLS_DEBUG= 454 | CONFIG_MBEDTLS_HARDWARE_AES=y 455 | CONFIG_MBEDTLS_HARDWARE_MPI= 456 | CONFIG_MBEDTLS_HARDWARE_SHA= 457 | CONFIG_MBEDTLS_HAVE_TIME=y 458 | CONFIG_MBEDTLS_HAVE_TIME_DATE= 459 | CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y 460 | CONFIG_MBEDTLS_TLS_SERVER_ONLY= 461 | CONFIG_MBEDTLS_TLS_CLIENT_ONLY= 462 | CONFIG_MBEDTLS_TLS_DISABLED= 463 | CONFIG_MBEDTLS_TLS_SERVER=y 464 | CONFIG_MBEDTLS_TLS_CLIENT=y 465 | CONFIG_MBEDTLS_TLS_ENABLED=y 466 | 467 | # 468 | # TLS Key Exchange Methods 469 | # 470 | CONFIG_MBEDTLS_PSK_MODES= 471 | CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y 472 | CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y 473 | CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y 474 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y 475 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y 476 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y 477 | CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y 478 | CONFIG_MBEDTLS_SSL_RENEGOTIATION=y 479 | CONFIG_MBEDTLS_SSL_PROTO_SSL3= 480 | CONFIG_MBEDTLS_SSL_PROTO_TLS1=y 481 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y 482 | CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y 483 | CONFIG_MBEDTLS_SSL_PROTO_DTLS= 484 | CONFIG_MBEDTLS_SSL_ALPN=y 485 | CONFIG_MBEDTLS_SSL_SESSION_TICKETS=y 486 | 487 | # 488 | # Symmetric Ciphers 489 | # 490 | CONFIG_MBEDTLS_AES_C=y 491 | CONFIG_MBEDTLS_CAMELLIA_C= 492 | CONFIG_MBEDTLS_DES_C= 493 | CONFIG_MBEDTLS_RC4_DISABLED=y 494 | CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT= 495 | CONFIG_MBEDTLS_RC4_ENABLED= 496 | CONFIG_MBEDTLS_BLOWFISH_C= 497 | CONFIG_MBEDTLS_XTEA_C= 498 | CONFIG_MBEDTLS_CCM_C=y 499 | CONFIG_MBEDTLS_GCM_C=y 500 | CONFIG_MBEDTLS_RIPEMD160_C= 501 | 502 | # 503 | # Certificates 504 | # 505 | CONFIG_MBEDTLS_PEM_PARSE_C=y 506 | CONFIG_MBEDTLS_PEM_WRITE_C=y 507 | CONFIG_MBEDTLS_X509_CRL_PARSE_C=y 508 | CONFIG_MBEDTLS_X509_CSR_PARSE_C=y 509 | CONFIG_MBEDTLS_ECP_C=y 510 | CONFIG_MBEDTLS_ECDH_C=y 511 | CONFIG_MBEDTLS_ECDSA_C=y 512 | CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y 513 | CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y 514 | CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y 515 | CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y 516 | CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y 517 | CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y 518 | CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y 519 | CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y 520 | CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y 521 | CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y 522 | CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y 523 | CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y 524 | CONFIG_MBEDTLS_ECP_NIST_OPTIM=y 525 | 526 | # 527 | # OpenSSL 528 | # 529 | CONFIG_OPENSSL_DEBUG= 530 | CONFIG_OPENSSL_ASSERT_DO_NOTHING=y 531 | CONFIG_OPENSSL_ASSERT_EXIT= 532 | 533 | # 534 | # PThreads 535 | # 536 | CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5 537 | CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072 538 | 539 | # 540 | # SPI Flash driver 541 | # 542 | CONFIG_SPI_FLASH_VERIFY_WRITE= 543 | CONFIG_SPI_FLASH_ENABLE_COUNTERS= 544 | CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y 545 | CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y 546 | CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS= 547 | CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED= 548 | 549 | # 550 | # SPIFFS Configuration 551 | # 552 | CONFIG_SPIFFS_MAX_PARTITIONS=3 553 | 554 | # 555 | # SPIFFS Cache Configuration 556 | # 557 | CONFIG_SPIFFS_CACHE=y 558 | CONFIG_SPIFFS_CACHE_WR=y 559 | CONFIG_SPIFFS_CACHE_STATS= 560 | CONFIG_SPIFFS_PAGE_CHECK=y 561 | CONFIG_SPIFFS_GC_MAX_RUNS=10 562 | CONFIG_SPIFFS_GC_STATS= 563 | CONFIG_SPIFFS_PAGE_SIZE=256 564 | CONFIG_SPIFFS_OBJ_NAME_LEN=32 565 | CONFIG_SPIFFS_USE_MAGIC=y 566 | CONFIG_SPIFFS_USE_MAGIC_LENGTH=y 567 | CONFIG_SPIFFS_META_LENGTH=4 568 | CONFIG_SPIFFS_USE_MTIME=y 569 | 570 | # 571 | # Debug Configuration 572 | # 573 | CONFIG_SPIFFS_DBG= 574 | CONFIG_SPIFFS_API_DBG= 575 | CONFIG_SPIFFS_GC_DBG= 576 | CONFIG_SPIFFS_CACHE_DBG= 577 | CONFIG_SPIFFS_CHECK_DBG= 578 | CONFIG_SPIFFS_TEST_VISUALISATION= 579 | 580 | # 581 | # tcpip adapter 582 | # 583 | CONFIG_IP_LOST_TIMER_INTERVAL=120 584 | 585 | # 586 | # Virtual file system 587 | # 588 | CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT=y 589 | 590 | # 591 | # Wear Levelling 592 | # 593 | CONFIG_WL_SECTOR_SIZE_512= 594 | CONFIG_WL_SECTOR_SIZE_4096=y 595 | CONFIG_WL_SECTOR_SIZE=4096 596 | -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | CONFIG_ENABLE_TEST_PATTERN=n 2 | CONFIG_OV2640_SUPPORT=y 3 | CONFIG_OV7725_SUPPORT=y 4 | CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y 5 | CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240 6 | CONFIG_MEMMAP_SMP=y 7 | CONFIG_TASK_WDT=n 8 | CONFIG_FREERTOS_UNICORE=n 9 | CONFIG_FREERTOS_HZ=100 10 | CONFIG_LOG_DEFAULT_LEVEL_INFO=y 11 | CONFIG_LOG_DEFAULT_LEVEL=3 12 | --------------------------------------------------------------------------------