feature(camera): add camera basic examples

This commit is contained in:
Wang Yu Xin 2022-04-19 17:23:37 +08:00 committed by Zhou Li
parent ce1d460938
commit 39ddd5dd99
45 changed files with 2264 additions and 0 deletions

3
.gitmodules vendored
View file

@ -4,3 +4,6 @@
[submodule "examples/hmi/lvgl_example/components/lv_examples/lv_examples"]
path = examples/hmi/lvgl_example/components/lv_examples/lv_examples
url = https://github.com/lvgl/lv_examples.git
[submodule "examples/camera/camera_components/esp32-camera"]
path = examples/camera/camera_components/esp32-camera
url = https://github.com/espressif/esp32-camera

BIN
docs/_static/camera-workflow.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

83
examples/camera/README.md Normal file
View file

@ -0,0 +1,83 @@
# Camera Examples
This directory contains a range of example [esp32-camera](https://github.com/espressif/esp32-camera) projects.
See the [README.md](../../README.md) file in the upper level directory for more information about examples.
## Camera driver workflow
![](../../docs/_static/camera-workflow.png)
The camera sensor transmits data to ESP32 device through DVP(parallel digital video port) interface. When initializing the camera, some `frame_buffer` will be allocated to store the data transmitted by the camera sensor. Once the camera is initialized, it starts working immediately, and the application can call `esp_camera_fb_get()` to get image data. After the application has applied the image data, the `frame_buffer` can be reused by calling `esp_camera_fb_return()`.
## Example Layout
* `basic` demonstrates basic usage of `ESP32-camera driver`.
* `pic_server` introduces how to control the action of taking pictures, and view the pictures immediately on the web page.
* `test_framerate` introduces how to evaluate the speed of the camera sensor and how to improve the speed of the camera sensor.
* `video_stream_server` demonstrates how to implement a video stream HTTP server on ESP32.
### More
* [ESP-WHO](https://github.com/espressif/esp-who) is an image processing development platform based on Espressif chips. It contains development examples that may be applied in practical applications.
* [USB_camera_examples](https://github.com/espressif/esp-iot-solution/tree/usb/add_usb_solutions/examples/usb/host) Contains some examples of using USB cameras.
## API Reference
The APIs included in the [esp32-camera](https://github.com/espressif/esp32-camera) are described below.
### Header File
- [esp32-camera/driver/include/esp_camera.h](https://github.com/espressif/esp32-camera/blob/master/driver/include/esp_camera.h)
#### Functions
- `esp_err_t esp_camera_init(const camera_config_t* config)`
Initialize the camera driver.
- `esp_err_t esp_camera_deinit()`
Deinitialize the camera driver.
- `camera_fb_t* esp_camera_fb_get()`
Obtain pointer to a frame buffer.
- `void esp_camera_fb_return(camera_fb_t * fb)`
Return the frame buffer to be reused again.
- `sensor_t * esp_camera_sensor_get()`
Get a pointer to the image sensor control structure.
- `esp_err_t esp_camera_save_to_nvs(const char *key)`
Save camera settings to non-volatile-storage (NVS).
- `esp_err_t esp_camera_load_from_nvs(const char *key)`
Load camera settings from non-volatile-storage (NVS).
### Header File
- [esp32-camera/driver/include/sensor.h](https://github.com/espressif/esp32-camera/blob/master/driver/include/sensor.h)
#### Functions
- `camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id)`
Get the camera sensor information.
### Header File
- [esp32-camera/conversions/include/img_converters.h](https://github.com/espressif/esp32-camera/blob/master/conversions/include/img_converters.h)
#### Functions
- `bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg)`
Convert image buffer to JPEG.
- `bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg)`
Convert camera frame buffer to JPEG.
- `bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len)`
Convert image buffer to JPEG buffer.
- `bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len)`
Convert image buffer to BMP buffer.
- `bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len)`
Convert camera frame buffer to BMP buffer.
- `bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len)`
Convert camera frame buffer to BMP buffer.
- `bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf)`
Convert image buffer to RGB888 buffer.
- `bool jpg2rgb565(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)`
Convert image buffer to RGB565 buffer.
### Header File
- [esp32-camera/conversions/include/esp_jpg_decode.h](https://github.com/espressif/esp32-camera/blob/master/conversions/include/esp_jpg_decode.h)
#### Functions
- `esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg)`
JPEG scaling function.

View file

@ -0,0 +1,18 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
#If IOT_SOLUTION_PATH is not defined, use relative path as default value
if(NOT DEFINED ENV{IOT_SOLUTION_PATH})
get_filename_component(IOT_SOLUTION_PATH "${CMAKE_SOURCE_DIR}/../../.." ABSOLUTE)
set(ENV{IOT_SOLUTION_PATH} ${IOT_SOLUTION_PATH})
message(WARNING "Can't detect IOT_SOLUTION_PATH in your environment, we infer it is $ENV{IOT_SOLUTION_PATH}")
endif()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/camera_example_common" "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/esp32-camera")
include($ENV{IOT_SOLUTION_PATH}/component.cmake)
add_compile_options(-fdiagnostics-color=always)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(camera_basic_example)

View file

@ -0,0 +1,55 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# Camera Basic Example
This example demonstrates how to initialize the camera sensor and then get the data captured by the sensor.
See the [README.md](../README.md) file in the upper level [camera](../) directory for more information about examples.
## How to use example
### Hardware Required
* A development board with camera module (e.g., ESP-EYE, ESP32-S2-Kaluga-1, ESP32-S3-EYE, etc.)
* A USB cable for power supply and programming
### Configure the project
```
idf.py menuconfig
```
* Open the project configuration menu (`idf.py menuconfig -> Camera Pin Configuration`) to configure camera pins.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
```
I (325) camera: Detected OV2640 camera
I (325) camera: Camera PID=0x26 VER=0x42 MIDL=0x7f MIDH=0xa2
I (504) s2 ll_cam: node_size: 3840, nodes_per_line: 1, lines_per_node: 6
I (504) s2 ll_cam: dma_half_buffer_min: 3840, dma_half_buffer: 15360, lines_per_half_buffer: 24, dma_buffer_size: 30720
I (512) cam_hal: buffer_size: 30720, half_buffer_size: 15360, node_buffer_size: 3840, node_cnt: 8, total_cnt: 10
I (522) cam_hal: Allocating 153600 Byte frame buffer in PSRAM
I (529) cam_hal: Allocating 153600 Byte frame buffer in PSRAM
I (535) cam_hal: cam config ok
I (539) ov2640: Set PLL: clk_2x: 1, clk_div: 3, pclk_auto: 1, pclk_div: 8
I (714) example:take_picture: Taking picture...
I (855) example:take_picture: Picture taken! Its size was: 153600 bytes
```
## Troubleshooting
* If the log shows "gpio: gpio_intr_disable(176): GPIO number error", then you probably need to check the configuration of camera pins, which you can find in the project configuration menu (`idf.py menuconfig`): Component config -> Camera Pin Config.
* If the initialization of the camera sensor fails. Please check the initialization parameters and pin configuration of your camera sensor.

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES nvs_flash esp32-camera camera_example_common)

View file

@ -0,0 +1,5 @@
#
# "main" pseudo-component makefile.
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)

View file

@ -0,0 +1,118 @@
/* Camera basic example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <esp_log.h>
#include <esp_system.h>
#include <nvs_flash.h>
#include <sys/param.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_camera.h"
#include "camera_pin.h"
static bool auto_jpeg_support = false; // whether the camera sensor support compression or JPEG encode
static const char *TAG = "example:take_picture";
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count)
{
camera_config_t camera_config = {
.pin_pwdn = CAMERA_PIN_PWDN,
.pin_reset = CAMERA_PIN_RESET,
.pin_xclk = CAMERA_PIN_XCLK,
.pin_sscb_sda = CAMERA_PIN_SIOD,
.pin_sscb_scl = CAMERA_PIN_SIOC,
.pin_d7 = CAMERA_PIN_D7,
.pin_d6 = CAMERA_PIN_D6,
.pin_d5 = CAMERA_PIN_D5,
.pin_d4 = CAMERA_PIN_D4,
.pin_d3 = CAMERA_PIN_D3,
.pin_d2 = CAMERA_PIN_D2,
.pin_d1 = CAMERA_PIN_D1,
.pin_d0 = CAMERA_PIN_D0,
.pin_vsync = CAMERA_PIN_VSYNC,
.pin_href = CAMERA_PIN_HREF,
.pin_pclk = CAMERA_PIN_PCLK,
// EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode.
.xclk_freq_hz = xclk_freq_hz,
.ledc_timer = LEDC_TIMER_0, // This is only valid on ESP32/ESP32-S2. ESP32-S3 use LCD_CAM interface.
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = pixel_format, // YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = frame_size, // QQVGA-UXGA, sizes above QVGA are not been recommended when not JPEG format.
.jpeg_quality = 30, // 0-63, used only with JPEG format.
.fb_count = fb_count, // For ESP32/ESP32-S2, if more than one, i2s runs in continuous mode.
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
.fb_location = CAMERA_FB_IN_PSRAM
};
// initialize the camera sensor
esp_err_t ret = esp_camera_init(&camera_config);
if (ret != ESP_OK) {
return ret;
}
// Get the sensor object, and then use some of its functions to adjust the parameters when taking a photo.
// Note: Do not call functions that set resolution, set picture format and PLL clock,
// If you need to reset the appeal parameters, please reinitialize the sensor.
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, 1); // flip it back
// initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_brightness(s, 1); // up the blightness just a bit
s->set_saturation(s, -2); // lower the saturation
}
if (s->id.PID == OV3660_PID || s->id.PID == OV2640_PID) {
s->set_vflip(s, 1); // flip it back
} else if (s->id.PID == GC0308_PID) {
s->set_hmirror(s, 0);
} else if (s->id.PID == GC032A_PID) {
s->set_vflip(s, 1);
}
// Get the basic information of the sensor.
camera_sensor_info_t *s_info = esp_camera_sensor_get_info(&(s->id));
if (ESP_OK == ret && PIXFORMAT_JPEG == pixel_format && s_info->support_jpeg == true) {
auto_jpeg_support = true;
}
return ret;
}
void app_main()
{
if (ESP_OK != init_camera(10 * 1000000, PIXFORMAT_RGB565, FRAMESIZE_QVGA, 2)) {
ESP_LOGE(TAG, "init camrea sensor fail");
return;
}
// take a picture every two seconds and print the size of the picture.
while (1) {
ESP_LOGI(TAG, "Taking picture...");
camera_fb_t *pic = esp_camera_fb_get();
if(pic){
// use pic->buf to access the image
ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len);
// To enable the frame buffer can be reused again.
// Note: If you don't call fb_return(), the next time you call fb_get() you may get
// an error "Failed to get the frame on time!"because there is no frame buffer space available.
esp_camera_fb_return(pic);
}
vTaskDelay(2000 / portTICK_RATE_MS);
}
}

View file

@ -0,0 +1,2 @@
CONFIG_SPIRAM_SUPPORT=n
CONFIG_ESP32S2_SPIRAM_SUPPORT=n

View file

@ -0,0 +1,24 @@
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_FREERTOS_HZ=1000
CONFIG_SPIRAM_SUPPORT=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MEMTEST=n
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1580
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS=y

View file

@ -0,0 +1,5 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
idf_component_register(INCLUDE_DIRS "include")

View file

@ -0,0 +1,156 @@
menu "Camera Pin Configuration"
choice CAMERA_MODULE
bool "Select Camera Pinout"
default CAMERA_MODULE_WROVER_KIT
help
Select Camera Pinout.
config CAMERA_MODULE_WROVER_KIT
bool "WROVER-KIT With OV2640 Module"
config CAMERA_MODULE_ESP_EYE
bool "ESP-EYE DevKit"
config CAMERA_MODULE_ESP_S2_KALUGA
bool "ESP32-S2-Kaluga-1 V1.3"
config CAMERA_MODULE_ESP_S3_EYE
bool "ESP-S3-EYE DevKit"
config CAMERA_MODEL_ESP32_CAM_BOARD
bool "ESP32 Camera Development Board"
config CAMERA_MODULE_M5STACK_PSRAM
bool "M5Stack Camera With PSRAM"
config CAMERA_MODULE_M5STACK_WIDE
bool "M5Stack Camera F (Wide)"
config CAMERA_MODULE_AI_THINKER
bool "ESP32-CAM by AI-Thinker"
config CAMERA_MODULE_CUSTOM
bool "Custom Camera Pinout"
endchoice
config CAMERA_PIN_PWDN
depends on CAMERA_MODULE_CUSTOM
int "Power Down pin"
range -1 33
default -1
help
Select Power Down pin or -1 for unmanaged.
config CAMERA_PIN_RESET
depends on CAMERA_MODULE_CUSTOM
int "Reset pin"
range -1 33
default -1
help
Select Camera Reset pin or -1 for software reset.
config CAMERA_PIN_XCLK
depends on CAMERA_MODULE_CUSTOM
int "XCLK pin"
range 0 33
default 21
help
Select Camera XCLK pin.
config CAMERA_PIN_SIOD
depends on CAMERA_MODULE_CUSTOM
int "SIOD pin"
range 0 33
default 26
help
Select Camera SIOD pin.
config CAMERA_PIN_SIOC
depends on CAMERA_MODULE_CUSTOM
int "SIOC pin"
range 0 33
default 27
help
Select Camera SIOC pin.
config CAMERA_PIN_VSYNC
depends on CAMERA_MODULE_CUSTOM
int "VSYNC pin"
range 0 39
default 25
help
Select Camera VSYNC pin.
config CAMERA_PIN_HREF
depends on CAMERA_MODULE_CUSTOM
int "HREF pin"
range 0 39
default 23
help
Select Camera HREF pin.
config CAMERA_PIN_PCLK
depends on CAMERA_MODULE_CUSTOM
int "PCLK pin"
range 0 39
default 25
help
Select Camera PCLK pin.
config CAMERA_PIN_Y2
depends on CAMERA_MODULE_CUSTOM
int "Y2 pin"
range 0 39
default 4
help
Select Camera Y2 pin.
config CAMERA_PIN_Y3
depends on CAMERA_MODULE_CUSTOM
int "Y3 pin"
range 0 39
default 5
help
Select Camera Y3 pin.
config CAMERA_PIN_Y4
depends on CAMERA_MODULE_CUSTOM
int "Y4 pin"
range 0 39
default 18
help
Select Camera Y4 pin.
config CAMERA_PIN_Y5
depends on CAMERA_MODULE_CUSTOM
int "Y5 pin"
range 0 39
default 19
help
Select Camera Y5 pin.
config CAMERA_PIN_Y6
depends on CAMERA_MODULE_CUSTOM
int "Y6 pin"
range 0 39
default 36
help
Select Camera Y6 pin.
config CAMERA_PIN_Y7
depends on CAMERA_MODULE_CUSTOM
int "Y7 pin"
range 0 39
default 39
help
Select Camera Y7 pin.
config CAMERA_PIN_Y8
depends on CAMERA_MODULE_CUSTOM
int "Y8 pin"
range 0 39
default 34
help
Select Camera Y8 pin.
config CAMERA_PIN_Y9
depends on CAMERA_MODULE_CUSTOM
int "Y9 pin"
range 0 39
default 35
help
Select Camera Y9 pin.
endmenu

View file

@ -0,0 +1,3 @@
# Camera Example Common
This directory contains component that is common for esp32-camera examples. The component defines camera pins used by different development boards.

View file

@ -0,0 +1,188 @@
#pragma once
#include "sdkconfig.h"
#if CONFIG_CAMERA_MODULE_WROVER_KIT
#define CAMERA_MODULE_NAME "Wrover Kit"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_XCLK 21
#define CAMERA_PIN_SIOD 26
#define CAMERA_PIN_SIOC 27
#define CAMERA_PIN_D7 35
#define CAMERA_PIN_D6 34
#define CAMERA_PIN_D5 39
#define CAMERA_PIN_D4 36
#define CAMERA_PIN_D3 19
#define CAMERA_PIN_D2 18
#define CAMERA_PIN_D1 5
#define CAMERA_PIN_D0 4
#define CAMERA_PIN_VSYNC 25
#define CAMERA_PIN_HREF 23
#define CAMERA_PIN_PCLK 22
#elif CONFIG_CAMERA_MODULE_ESP_EYE
#define CAMERA_MODULE_NAME "ESP-EYE"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_XCLK 4
#define CAMERA_PIN_SIOD 18
#define CAMERA_PIN_SIOC 23
#define CAMERA_PIN_D7 36
#define CAMERA_PIN_D6 37
#define CAMERA_PIN_D5 38
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 35
#define CAMERA_PIN_D2 14
#define CAMERA_PIN_D1 13
#define CAMERA_PIN_D0 34
#define CAMERA_PIN_VSYNC 5
#define CAMERA_PIN_HREF 27
#define CAMERA_PIN_PCLK 25
#elif CONFIG_CAMERA_MODULE_ESP_S2_KALUGA
#define CAMERA_MODULE_NAME "ESP-S2-KALUGA"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_XCLK 1
#define CAMERA_PIN_SIOD 8
#define CAMERA_PIN_SIOC 7
#define CAMERA_PIN_D7 38
#define CAMERA_PIN_D6 21
#define CAMERA_PIN_D5 40
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 42
#define CAMERA_PIN_D2 41
#define CAMERA_PIN_D1 37
#define CAMERA_PIN_D0 36
#define CAMERA_PIN_VSYNC 2
#define CAMERA_PIN_HREF 3
#define CAMERA_PIN_PCLK 33
#elif CONFIG_CAMERA_MODULE_ESP_S3_EYE
#define CAMERA_MODULE_NAME "ESP-S3-EYE"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_VSYNC 6
#define CAMERA_PIN_HREF 7
#define CAMERA_PIN_PCLK 13
#define CAMERA_PIN_XCLK 15
#define CAMERA_PIN_SIOD 4
#define CAMERA_PIN_SIOC 5
#define CAMERA_PIN_D0 11
#define CAMERA_PIN_D1 9
#define CAMERA_PIN_D2 8
#define CAMERA_PIN_D3 10
#define CAMERA_PIN_D4 12
#define CAMERA_PIN_D5 18
#define CAMERA_PIN_D6 17
#define CAMERA_PIN_D7 16
#elif CONFIG_CAMERA_MODEL_ESP32_CAM_BOARD
#define CAMERA_MODULE_NAME "ESP-DEVCAM"
#define CAMERA_PIN_PWDN 32
#define CAMERA_PIN_RESET 33
#define CAMERA_PIN_XCLK 4
#define CAMERA_PIN_SIOD 18
#define CAMERA_PIN_SIOC 23
#define CAMERA_PIN_D7 36
#define CAMERA_PIN_D6 19
#define CAMERA_PIN_D5 21
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 35
#define CAMERA_PIN_D2 14
#define CAMERA_PIN_D1 13
#define CAMERA_PIN_D0 34
#define CAMERA_PIN_VSYNC 5
#define CAMERA_PIN_HREF 27
#define CAMERA_PIN_PCLK 25
#elif CONFIG_CAMERA_MODULE_M5STACK_PSRAM
#define CAMERA_MODULE_NAME "M5STACK-PSRAM"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET 15
#define CAMERA_PIN_XCLK 27
#define CAMERA_PIN_SIOD 25
#define CAMERA_PIN_SIOC 23
#define CAMERA_PIN_D7 19
#define CAMERA_PIN_D6 36
#define CAMERA_PIN_D5 18
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 5
#define CAMERA_PIN_D2 34
#define CAMERA_PIN_D1 35
#define CAMERA_PIN_D0 32
#define CAMERA_PIN_VSYNC 22
#define CAMERA_PIN_HREF 26
#define CAMERA_PIN_PCLK 21
#elif CONFIG_CAMERA_MODULE_M5STACK_WIDE
#define CAMERA_MODULE_NAME "M5STACK-WIDE"
#define CAMERA_PIN_PWDN -1
#define CAMERA_PIN_RESET 15
#define CAMERA_PIN_XCLK 27
#define CAMERA_PIN_SIOD 22
#define CAMERA_PIN_SIOC 23
#define CAMERA_PIN_D7 19
#define CAMERA_PIN_D6 36
#define CAMERA_PIN_D5 18
#define CAMERA_PIN_D4 39
#define CAMERA_PIN_D3 5
#define CAMERA_PIN_D2 34
#define CAMERA_PIN_D1 35
#define CAMERA_PIN_D0 32
#define CAMERA_PIN_VSYNC 25
#define CAMERA_PIN_HREF 26
#define CAMERA_PIN_PCLK 21
#elif CONFIG_CAMERA_MODULE_AI_THINKER
#define CAMERA_MODULE_NAME "AI-THINKER"
#define CAMERA_PIN_PWDN 32
#define CAMERA_PIN_RESET -1
#define CAMERA_PIN_XCLK 0
#define CAMERA_PIN_SIOD 26
#define CAMERA_PIN_SIOC 27
#define CAMERA_PIN_D7 35
#define CAMERA_PIN_D6 34
#define CAMERA_PIN_D5 39
#define CAMERA_PIN_D4 36
#define CAMERA_PIN_D3 21
#define CAMERA_PIN_D2 19
#define CAMERA_PIN_D1 18
#define CAMERA_PIN_D0 5
#define CAMERA_PIN_VSYNC 25
#define CAMERA_PIN_HREF 23
#define CAMERA_PIN_PCLK 22
#elif CONFIG_CAMERA_MODULE_CUSTOM
#define CAMERA_MODULE_NAME "CUSTOM"
#define CAMERA_PIN_PWDN CONFIG_CAMERA_PIN_PWDN
#define CAMERA_PIN_RESET CONFIG_CAMERA_PIN_RESET
#define CAMERA_PIN_XCLK CONFIG_CAMERA_PIN_XCLK
#define CAMERA_PIN_SIOD CONFIG_CAMERA_PIN_SIOD
#define CAMERA_PIN_SIOC CONFIG_CAMERA_PIN_SIOC
#define CAMERA_PIN_D7 CONFIG_CAMERA_PIN_Y9
#define CAMERA_PIN_D6 CONFIG_CAMERA_PIN_Y8
#define CAMERA_PIN_D5 CONFIG_CAMERA_PIN_Y7
#define CAMERA_PIN_D4 CONFIG_CAMERA_PIN_Y6
#define CAMERA_PIN_D3 CONFIG_CAMERA_PIN_Y5
#define CAMERA_PIN_D2 CONFIG_CAMERA_PIN_Y4
#define CAMERA_PIN_D1 CONFIG_CAMERA_PIN_Y3
#define CAMERA_PIN_D0 CONFIG_CAMERA_PIN_Y2
#define CAMERA_PIN_VSYNC CONFIG_CAMERA_PIN_VSYNC
#define CAMERA_PIN_HREF CONFIG_CAMERA_PIN_HREF
#define CAMERA_PIN_PCLK CONFIG_CAMERA_PIN_PCLK
#endif

@ -0,0 +1 @@
Subproject commit 86a4951f507e86034725b04f2428c98c49496dfe

View file

@ -0,0 +1,16 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
#If IOT_SOLUTION_PATH is not defined, use relative path as default value
if(NOT DEFINED ENV{IOT_SOLUTION_PATH})
get_filename_component(IOT_SOLUTION_PATH "${CMAKE_SOURCE_DIR}/../../.." ABSOLUTE)
set(ENV{IOT_SOLUTION_PATH} ${IOT_SOLUTION_PATH})
message(WARNING "Can't detect IOT_SOLUTION_PATH in your environment, we infer it is $ENV{IOT_SOLUTION_PATH}")
endif()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/camera_example_common" "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/esp32-camera")
include($ENV{IOT_SOLUTION_PATH}/component.cmake)
# add_compile_options(-fdiagnostics-color=always)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(camera_pic_server)

View file

@ -0,0 +1,53 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# ESP Camera Picture Server
The example starts a web server on a local network. You can use a browser to access this server to view pictures.
See the [README.md](../README.md) file in the upper level [camera](../) directory for more information about examples.
## How to use the example
### Hardware Required
* A development board with camera module (e.g., ESP-EYE, ESP32-S2-Kaluga-1, ESP32-S3-EYE, etc.)
* A USB cable for power supply and programming
### Configure the project
step1: chose your taget chip.
````
idf.py menuconfig -> Camera Pin Configuration
````
step2: Configure your wifi.
```
idf.py menuconfig -> Example Connection Configuration
```
step3: Configure the camera.
```
idf.py menuconfig -> component config -> Camera Configuration
```
step 4: Launch and monitor
Flash the program and launch IDF Monitor:
```bash
idf.py flash monitor
```
step 5: Test the example interactively on a web browser (assuming IP is 192.168.43.130):
open path `http://192.168.43.130/pic` to see an HTML web page on the server.
step 6: Click the refresh button to get next picture on the HTML web page.
## Troubleshooting
* If the log shows "gpio: gpio_intr_disable(176): GPIO number error", then you probably need to check the configuration of camera pins, which you can find in the project configuration menu (`idf.py menuconfig`): Component config -> Camera Pin Config.
* If the initialization of the camera sensor fails. Please check the initialization parameters and pin configuration of your camera sensor.

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES esp32-camera nvs_flash esp_http_server camera_example_common)

View file

@ -0,0 +1,50 @@
menu "Example Connection Configuration"
config ESP_WIFI_SSID
string "WiFi STA SSID"
default ""
help
WiFi SSID (network name) to connect to or empty for Off.
config ESP_WIFI_PASSWORD
string "WiFi STA Password"
default ""
help
WiFi Password if WEP/WPA/WPA2 or empty if Open.
config ESP_WIFI_AP_SSID
string "WiFi AP SSID"
default "ESP32-Camera"
help
AP SSID (network name) to create or empty for Off.
config ESP_WIFI_AP_PASSWORD
string "WiFi AP Password"
default ""
help
AP password for WPA2 or empty for Open.
config MAX_STA_CONN
int "Maximal STA connections"
default 1
help
Max number of the STA connects to AP.
config ESP_WIFI_AP_CHANNEL
string "WiFi AP Channel"
default ""
help
AP channel for better connection performance.
config SERVER_IP
string "WiFi AP IP Address"
default "192.168.4.1"
help
IP address that the ESP will assign to it's AP interface. You can use this IP to connect to the camera after flashing.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu

View file

@ -0,0 +1,204 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "lwip/err.h"
#include "lwip/sys.h"
/* The examples use WiFi configuration that you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
#define EXAMPLE_ESP_WIFI_AP_SSID CONFIG_ESP_WIFI_AP_SSID
#define EXAMPLE_ESP_WIFI_AP_PASS CONFIG_ESP_WIFI_AP_PASSWORD
#define EXAMPLE_MAX_STA_CONN CONFIG_MAX_STA_CONN
#define EXAMPLE_IP_ADDR CONFIG_SERVER_IP
#define EXAMPLE_ESP_WIFI_AP_CHANNEL CONFIG_ESP_WIFI_AP_CHANNEL
static const char *TAG = "camera wifi";
static int s_retry_num = 0;
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group = NULL;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
/* AP mode */
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
/* Sta mode */
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
return;
}
static void wifi_init_softap(esp_netif_t * netif)
{
if (strcmp(EXAMPLE_IP_ADDR, "192.168.4.1")) {
int a, b, c, d;
sscanf(EXAMPLE_IP_ADDR, "%d.%d.%d.%d", &a, &b, &c, &d);
esp_netif_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, a, b, c, d);
IP4_ADDR(&ip_info.gw, a, b, c, d);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(esp_netif_dhcps_stop(netif));
ESP_ERROR_CHECK(esp_netif_set_ip_info(netif, &ip_info));
ESP_ERROR_CHECK(esp_netif_dhcps_start(netif));
}
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.ap.ssid, 32, "%s", EXAMPLE_ESP_WIFI_AP_SSID);
wifi_config.ap.ssid_len = strlen((char *)wifi_config.ap.ssid);
snprintf((char *)wifi_config.ap.password, 64, "%s", EXAMPLE_ESP_WIFI_AP_PASS);
wifi_config.ap.max_connection = EXAMPLE_MAX_STA_CONN;
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
if (strlen(EXAMPLE_ESP_WIFI_AP_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
if (strlen(EXAMPLE_ESP_WIFI_AP_CHANNEL)) {
int channel;
sscanf(EXAMPLE_ESP_WIFI_AP_CHANNEL, "%d", &channel);
wifi_config.ap.channel = channel;
}
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
EXAMPLE_ESP_WIFI_AP_SSID, EXAMPLE_ESP_WIFI_AP_PASS);
}
static void wifi_init_sta()
{
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.sta.ssid, 32, "%s", EXAMPLE_ESP_WIFI_SSID);
snprintf((char *)wifi_config.sta.password, 64, "%s", EXAMPLE_ESP_WIFI_PASS);
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "wifi_init_sta finished.");
ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}
void app_wifi_main()
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
wifi_mode_t mode = WIFI_MODE_NULL;
if (strlen(EXAMPLE_ESP_WIFI_AP_SSID) && strlen(EXAMPLE_ESP_WIFI_SSID)) {
mode = WIFI_MODE_APSTA;
} else if (strlen(EXAMPLE_ESP_WIFI_AP_SSID)) {
mode = WIFI_MODE_AP;
} else if (strlen(EXAMPLE_ESP_WIFI_SSID)) {
mode = WIFI_MODE_STA;
}
if (mode == WIFI_MODE_NULL) {
ESP_LOGW(TAG, "Neither AP or STA have been configured. WiFi will be off.");
return;
}
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&wifi_event_handler,
NULL,
NULL));
ESP_ERROR_CHECK(esp_wifi_set_mode(mode));
if (mode & WIFI_MODE_AP) {
esp_netif_t * ap_netif = esp_netif_create_default_wifi_ap();
wifi_init_softap(ap_netif);
}
if (mode & WIFI_MODE_STA) {
esp_netif_create_default_wifi_sta();
wifi_init_sta();
}
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_LOGI(TAG, "wifi init finished.");
if (mode & WIFI_MODE_STA) {
xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
}
vEventGroupDelete(s_wifi_event_group);
s_wifi_event_group = NULL;
}

View file

@ -0,0 +1,27 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _APP_WIFI_H_
#define _APP_WIFI_H_
#ifdef __cplusplus
extern "C" {
#endif
void app_wifi_main();
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,89 @@
// Copyright 2020-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_http_server.h"
#include "img_converters.h"
#include "sdkconfig.h"
#include "esp_log.h"
static httpd_handle_t pic_httpd = NULL;
static const char *TAG = "pic_s";
/* Handler to download a file kept on the server */
static esp_err_t pic_get_handler(httpd_req_t *req)
{
camera_fb_t *frame = NULL;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
httpd_resp_set_type(req, "image/jpeg");
httpd_resp_set_hdr(req, "Content-Disposition", "inline; filename=capture.jpg");
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
esp_camera_fb_return(esp_camera_fb_get());
frame = esp_camera_fb_get();
if (frame) {
if (frame->format == PIXFORMAT_JPEG) {
_jpg_buf = frame->buf;
_jpg_buf_len = frame->len;
} else if (!frame2jpg(frame, 60, &_jpg_buf, &_jpg_buf_len)) {
ESP_LOGE(TAG, "JPEG compression failed");
res = ESP_FAIL;
}
} else {
res = ESP_FAIL;
}
if (res == ESP_OK) {
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
if (frame->format != PIXFORMAT_JPEG) {
free(_jpg_buf);
_jpg_buf = NULL;
}
esp_camera_fb_return(frame);
ESP_LOGI(TAG, "pic len %d", _jpg_buf_len);
} else {
ESP_LOGW(TAG, "exit pic server");
return ESP_FAIL;
}
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
esp_err_t start_pic_server()
{
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.stack_size = 5120;
httpd_uri_t pic_uri = {
.uri = "/pic",
.method = HTTP_GET,
.handler = pic_get_handler,
.user_ctx = NULL
};
ESP_LOGI(TAG, "Starting pic server on port: '%d'", config.server_port);
if (httpd_start(&pic_httpd, &config) == ESP_OK) {
httpd_register_uri_handler(pic_httpd, &pic_uri);
return ESP_OK;
}
return ESP_FAIL;
}

View file

@ -0,0 +1,108 @@
/* Camera pic server example
This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "camera_pin.h"
#include "app_wifi.h"
#include "esp_camera.h"
#define TEST_ESP_OK(ret) assert(ret == ESP_OK)
#define TEST_ASSERT_NOT_NULL(ret) assert(ret != NULL)
static bool auto_jpeg_support = false; // whether the camera sensor support compression or JPEG encode
static const char *TAG = "pic server";
esp_err_t start_pic_server(void);
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count)
{
camera_config_t camera_config = {
.pin_pwdn = CAMERA_PIN_PWDN,
.pin_reset = CAMERA_PIN_RESET,
.pin_xclk = CAMERA_PIN_XCLK,
.pin_sscb_sda = CAMERA_PIN_SIOD,
.pin_sscb_scl = CAMERA_PIN_SIOC,
.pin_d7 = CAMERA_PIN_D7,
.pin_d6 = CAMERA_PIN_D6,
.pin_d5 = CAMERA_PIN_D5,
.pin_d4 = CAMERA_PIN_D4,
.pin_d3 = CAMERA_PIN_D3,
.pin_d2 = CAMERA_PIN_D2,
.pin_d1 = CAMERA_PIN_D1,
.pin_d0 = CAMERA_PIN_D0,
.pin_vsync = CAMERA_PIN_VSYNC,
.pin_href = CAMERA_PIN_HREF,
.pin_pclk = CAMERA_PIN_PCLK,
//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
.xclk_freq_hz = xclk_freq_hz,
.ledc_timer = LEDC_TIMER_0, // // This is only valid on ESP32/ESP32-S2. ESP32-S3 use LCD_CAM interface.
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = pixel_format, //YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = frame_size, //QQVGA-UXGA, sizes above QVGA are not been recommended when not JPEG format.
.jpeg_quality = 10, //0-63
.fb_count = fb_count, // For ESP32/ESP32-S2, if more than one, i2s runs in continuous mode. Use only with JPEG.
.grab_mode = CAMERA_GRAB_LATEST,
.fb_location = CAMERA_FB_IN_PSRAM
};
//initialize the camera
esp_err_t ret = esp_camera_init(&camera_config);
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, 1);//flip it back
//initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_saturation(s, -2);//lower the saturation
}
if (s->id.PID == OV3660_PID || s->id.PID == OV2640_PID) {
s->set_vflip(s, 1); //flip it back
} else if (s->id.PID == GC0308_PID) {
s->set_hmirror(s, 0);
} else if (s->id.PID == GC032A_PID) {
s->set_vflip(s, 1);
}
camera_sensor_info_t *s_info = esp_camera_sensor_get_info(&(s->id));
if (ESP_OK == ret && PIXFORMAT_JPEG == pixel_format && s_info->support_jpeg == true) {
auto_jpeg_support = true;
}
return ret;
}
void app_main()
{
app_wifi_main();
/* Check the image format supported by your camera sensor.
* Typically, when you need to obtain a larger resolution image, increase the xclk clock frequency.
* Similarly, when you need a smaller resolution image, please use a smaller xclk clock frequency,
* otherwise the warning `EV-EOF-OVF` may be triggered.
*/
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_YUV422, FRAMESIZE_QVGA, 2));
TEST_ESP_OK(start_pic_server());
ESP_LOGI(TAG, "Begin capture frame");
}

View file

@ -0,0 +1,2 @@
CONFIG_SPIRAM_SUPPORT=n
CONFIG_ESP32S2_SPIRAM_SUPPORT=n

View file

@ -0,0 +1,26 @@
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_FREERTOS_HZ=1000
CONFIG_SPIRAM_SUPPORT=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MEMTEST=n
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1580
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS=y
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1214

View file

@ -0,0 +1,16 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
#If IOT_SOLUTION_PATH is not defined, use relative path as default value
if(NOT DEFINED ENV{IOT_SOLUTION_PATH})
get_filename_component(IOT_SOLUTION_PATH "${CMAKE_SOURCE_DIR}/../../.." ABSOLUTE)
set(ENV{IOT_SOLUTION_PATH} ${IOT_SOLUTION_PATH})
message(WARNING "Can't detect IOT_SOLUTION_PATH in your environment, we infer it is $ENV{IOT_SOLUTION_PATH}")
endif()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/camera_example_common" "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/esp32-camera")
include($ENV{IOT_SOLUTION_PATH}/component.cmake)
# add_compile_options(-fdiagnostics-color=always)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(test_framerate)

View file

@ -0,0 +1,59 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# ESP Camera Sensor Frame Rate Test
This example is used to test the rate of images obtained from the camera sensor.
See the [README.md](../README.md) file in the upper level [camera](../) directory for more information about examples.
## Note about frame rate
The frame rate can be measured by how many images are obtained in 1s. This example estimates the rate by obtaining a certain number of pictures and testing the time to obtain these pictures.
fps(frames/sec) = `picture_count` / `time_consumed`.
The main factors affecting the camera frame rate are
| name | definition |
| ------------ | ---- |
| xclk |Clock frequency of driving camera sensor. Generally, increasing this clock frequency will improve the frame rate.|
| image format | Common output formats: RGB565/YUV422/JPEG. The data in JPEG format is compressed data, so selecting the image data in JPEG format can usually improve the frame rate. |
| image size | Image resolution. Larger resolution means that more data needs to be transmitted per unit time. Therefore, the higher the resolution, the lower the frame rate may be. |
| fb_count | The number of buffers used to receive the data transmitted by the sensor. Increasing this value may improve the frame rate. |
| jpeg_quality | Lower JPEG quality means less data needs to be transmitted, so it may help to improve the frame rate. |
All the above factors can be specified in the `esp_camera_init()`. You can try to change them and test their impact on the frame rate.
## How to use the example
### Hardware Required
* A development board with camera module (e.g., ESP-EYE, ESP32-S2-Kaluga-1, ESP32-S3-EYE, etc.)
* A USB cable for power supply and programming
### Configure the project
step1: chose your taget chip.
````
idf.py menuconfig -> Camera Pin Configuration
````
step2: Configure the camera.
```
idf.py menuconfig ->component config -> Camera Configuration
```
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(Replace PORT with the name of the serial port to use.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Troubleshooting
* If the log shows "gpio: gpio_intr_disable(176): GPIO number error", then you probably need to check the configuration of camera pins, which you can find in the project configuration menu (`idf.py menuconfig`): Component config -> Camera Pin Config.
* If the initialization of the camera sensor fails. Please check the initialization parameters and pin configuration of your camera sensor.

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES esp32-camera nvs_flash camera_example_common)

View file

@ -0,0 +1,154 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <mbedtls/base64.h>
#include "esp_log.h"
#include "esp_camera.h"
#include "camera_pin.h"
#define TEST_ESP_OK(ret) assert(ret == ESP_OK)
#define TEST_ASSERT_NOT_NULL(ret) assert(ret != NULL)
#define FB_COUNT_IN_RAM (2) // Frame buffer count used to storage frame passed by the sensor
#define PIC_COUNT_TEST (36) // Total number of pictures to be acquired for testing
static const char *TAG = "test camera";
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count)
{
camera_config_t camera_config = {
.pin_pwdn = CAMERA_PIN_PWDN,
.pin_reset = CAMERA_PIN_RESET,
.pin_xclk = CAMERA_PIN_XCLK,
.pin_sscb_sda = CAMERA_PIN_SIOD,
.pin_sscb_scl = CAMERA_PIN_SIOC,
.pin_d7 = CAMERA_PIN_D7,
.pin_d6 = CAMERA_PIN_D6,
.pin_d5 = CAMERA_PIN_D5,
.pin_d4 = CAMERA_PIN_D4,
.pin_d3 = CAMERA_PIN_D3,
.pin_d2 = CAMERA_PIN_D2,
.pin_d1 = CAMERA_PIN_D1,
.pin_d0 = CAMERA_PIN_D0,
.pin_vsync = CAMERA_PIN_VSYNC,
.pin_href = CAMERA_PIN_HREF,
.pin_pclk = CAMERA_PIN_PCLK,
// EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
.xclk_freq_hz = xclk_freq_hz,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = pixel_format, // YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = frame_size, // QQVGA-UXGA, sizes above QVGA when not JPEG format are not recommended.
.jpeg_quality = 30, // 0-63 lower number means higher quality
.fb_count = fb_count, // if more than one, i2s runs in continuous mode.
.grab_mode = CAMERA_GRAB_WHEN_EMPTY,
.fb_location = CAMERA_FB_IN_PSRAM
};
//initialize the camera
esp_err_t ret = esp_camera_init(&camera_config);
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, 1);//flip it back
return ret;
}
static bool camera_test_fps(uint16_t times, float *fps, uint32_t *size)
{
*fps = 0.0f;
*size = 0;
uint32_t s = 0;
uint32_t num = 0;
uint64_t total_time = esp_timer_get_time();
for (size_t i = 0; i < times; i++) {
camera_fb_t *pic = esp_camera_fb_get();
if (NULL == pic) {
ESP_LOGW(TAG, "fb get failed");
return 0;
} else {
s += pic->len;
num++;
}
esp_camera_fb_return(pic);
}
total_time = esp_timer_get_time() - total_time;
if (num) {
*fps = num * 1000000.0f / total_time;
*size = s / num;
}
return 1;
}
static void __attribute__((noreturn)) task_fatal_error(void)
{
ESP_LOGE(TAG, "Exiting task due to fatal error...");
(void)vTaskDelete(NULL);
while (1) {
;
}
}
static void camera_performance_test_with_format(uint32_t xclk_freq, uint32_t pic_num, pixformat_t pixel_format, framesize_t frame_size)
{
esp_err_t ret = ESP_OK;
uint64_t t1 = 0;
// detect sensor information
t1 = esp_timer_get_time();
TEST_ESP_OK(init_camera(10000000, pixel_format, frame_size, 2));
printf("Cam prob %llu\n", (esp_timer_get_time() - t1) / 1000);
// get sensor info
sensor_t *s = esp_camera_sensor_get();
camera_sensor_info_t *info = esp_camera_sensor_get_info(&s->id);
TEST_ASSERT_NOT_NULL(info);
// deinit sensor
TEST_ESP_OK(esp_camera_deinit());
vTaskDelay(500 / portTICK_RATE_MS);
struct fps_result {
float fps;
uint32_t size;
};
struct fps_result results = {0};
ret = init_camera(xclk_freq, pixel_format, frame_size, FB_COUNT_IN_RAM);
vTaskDelay(100 / portTICK_RATE_MS);
if (ESP_OK != ret) {
ESP_LOGW(TAG, "Testing init failed :-(, skip this item");
task_fatal_error();
}
camera_test_fps(pic_num, &results.fps, &results.size);
TEST_ESP_OK(esp_camera_deinit());
printf("FPS Result\n");
printf("fps, size \n");
printf("%5.2f, %7d \n",
results.fps, results.size);
printf("----------------------------------------------------------------------------------------\n");
}
void app_main()
{
camera_performance_test_with_format(20 * 1000000, PIC_COUNT_TEST, PIXFORMAT_RGB565, FRAMESIZE_QVGA);
}

View file

@ -0,0 +1,2 @@
CONFIG_SPIRAM_SUPPORT=n
CONFIG_ESP32S2_SPIRAM_SUPPORT=n

View file

@ -0,0 +1,24 @@
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_FREERTOS_HZ=1000
CONFIG_SPIRAM_SUPPORT=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MEMTEST=n
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1580
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON=y
CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS=y

View file

@ -0,0 +1,17 @@
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
#If IOT_SOLUTION_PATH is not defined, use relative path as default value
if(NOT DEFINED ENV{IOT_SOLUTION_PATH})
get_filename_component(IOT_SOLUTION_PATH "${CMAKE_SOURCE_DIR}/../../.." ABSOLUTE)
set(ENV{IOT_SOLUTION_PATH} ${IOT_SOLUTION_PATH})
message(WARNING "Can't detect IOT_SOLUTION_PATH in your environment, we infer it is $ENV{IOT_SOLUTION_PATH}")
endif()
list(APPEND EXTRA_COMPONENT_DIRS "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/camera_example_common" "$ENV{IOT_SOLUTION_PATH}/examples/camera/camera_components/esp32-camera")
include($ENV{IOT_SOLUTION_PATH}/component.cmake)
# add_compile_options(-fdiagnostics-color=always)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(video_stream_server)

View file

@ -0,0 +1,58 @@
| Supported Targets | ESP32 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- |
# ESP Camera Video Stream Server
The example starts a web server on a local network. You can view pictures dynamically through your browser.
See the [README.md](../README.md) file in the upper level [camera](../) directory for more information about examples.
## How to use the example
### Hardware Required
* A development board with camera module (e.g., ESP-EYE, ESP32-S2-Kaluga-1, ESP32-S3-EYE, etc.)
* A USB cable for power supply and programming
### Configure the project
step1: chose your taget chip.
````
idf.py menuconfig -> Camera Pin Configuration
````
step2: Configure your wifi.
```
idf.py menuconfig -> Example Connection Configuration
```
step3: Configure the camera.
```
idf.py menuconfig -> component config -> Camera Configuration
```
step 4: Launch and monitor
Flash the program and launch IDF Monitor:
```bash
idf.py flash monitor
```
step 5: Test the example interactively on a web browser (assuming IP is 192.168.43.130):
open path `http://192.168.43.130/stream` to see an HTML web page on the server.
**NOTE:** This example configures the output format of the camera sensor to JPEG format by default. Therefore, if your sensor does not support this function, please change this line of code:
```
TEST_ESP_OK(init_camera(20000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2)); // Change PIXFORMAT_JPEG to PIXFORMAT_RGB565/PIXFORMAT_YUV422 if the sensor does not support JPEG compression.
```
**NOTE:** The current camera sensor configuration is not optimal, so don't be surprised when the picture refresh is slow. Referring to the datasheet of the camera sensor, adjusting some register parameters may improve performance.
## Troubleshooting
* If the log shows "gpio: gpio_intr_disable(176): GPIO number error", then you probably need to check the configuration of camera pins, which you can find in the project configuration menu (`idf.py menuconfig`): Component config -> Camera Pin Config.
* If the initialization of the camera sensor fails. Please check the initialization parameters and pin configuration of your camera sensor.

View file

@ -0,0 +1,3 @@
idf_component_register(SRC_DIRS .
PRIV_INCLUDE_DIRS .
PRIV_REQUIRES esp32-camera nvs_flash esp_http_server camera_example_common)

View file

@ -0,0 +1,50 @@
menu "Example Connection Configuration"
config ESP_WIFI_SSID
string "WiFi STA SSID"
default ""
help
WiFi SSID (network name) to connect to or empty for Off.
config ESP_WIFI_PASSWORD
string "WiFi STA Password"
default ""
help
WiFi Password if WEP/WPA/WPA2 or empty if Open.
config ESP_WIFI_AP_SSID
string "WiFi AP SSID"
default "ESP32-Camera"
help
AP SSID (network name) to create or empty for Off.
config ESP_WIFI_AP_PASSWORD
string "WiFi AP Password"
default ""
help
AP password for WPA2 or empty for Open.
config MAX_STA_CONN
int "Maximal STA connections"
default 1
help
Max number of the STA connects to AP.
config ESP_WIFI_AP_CHANNEL
string "WiFi AP Channel"
default ""
help
AP channel for better connection performance.
config SERVER_IP
string "WiFi AP IP Address"
default "192.168.4.1"
help
IP address that the ESP will assign to it's AP interface. You can use this IP to connect to the camera after flashing.
config ESP_MAXIMUM_RETRY
int "Maximum retry"
default 5
help
Set the Maximum retry to avoid station reconnecting to the AP unlimited when the AP is really inexistent.
endmenu

View file

@ -0,0 +1,204 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "sdkconfig.h"
#include "lwip/err.h"
#include "lwip/sys.h"
/* The examples use WiFi configuration that you can set via 'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid"
*/
#define EXAMPLE_ESP_WIFI_SSID CONFIG_ESP_WIFI_SSID
#define EXAMPLE_ESP_WIFI_PASS CONFIG_ESP_WIFI_PASSWORD
#define EXAMPLE_ESP_MAXIMUM_RETRY CONFIG_ESP_MAXIMUM_RETRY
#define EXAMPLE_ESP_WIFI_AP_SSID CONFIG_ESP_WIFI_AP_SSID
#define EXAMPLE_ESP_WIFI_AP_PASS CONFIG_ESP_WIFI_AP_PASSWORD
#define EXAMPLE_MAX_STA_CONN CONFIG_MAX_STA_CONN
#define EXAMPLE_IP_ADDR CONFIG_SERVER_IP
#define EXAMPLE_ESP_WIFI_AP_CHANNEL CONFIG_ESP_WIFI_AP_CHANNEL
static const char *TAG = "camera wifi";
static int s_retry_num = 0;
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group = NULL;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
/* AP mode */
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
/* Sta mode */
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
ESP_LOGI(TAG, "retry to connect to the AP");
} else {
xEventGroupSetBits(s_wifi_event_group, WIFI_FAIL_BIT);
}
ESP_LOGI(TAG,"connect to the AP fail");
} else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event = (ip_event_got_ip_t*) event_data;
ESP_LOGI(TAG, "got ip:" IPSTR, IP2STR(&event->ip_info.ip));
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
}
return;
}
static void wifi_init_softap(esp_netif_t * netif)
{
if (strcmp(EXAMPLE_IP_ADDR, "192.168.4.1")) {
int a, b, c, d;
sscanf(EXAMPLE_IP_ADDR, "%d.%d.%d.%d", &a, &b, &c, &d);
esp_netif_ip_info_t ip_info;
IP4_ADDR(&ip_info.ip, a, b, c, d);
IP4_ADDR(&ip_info.gw, a, b, c, d);
IP4_ADDR(&ip_info.netmask, 255, 255, 255, 0);
ESP_ERROR_CHECK(esp_netif_dhcps_stop(netif));
ESP_ERROR_CHECK(esp_netif_set_ip_info(netif, &ip_info));
ESP_ERROR_CHECK(esp_netif_dhcps_start(netif));
}
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.ap.ssid, 32, "%s", EXAMPLE_ESP_WIFI_AP_SSID);
wifi_config.ap.ssid_len = strlen((char *)wifi_config.ap.ssid);
snprintf((char *)wifi_config.ap.password, 64, "%s", EXAMPLE_ESP_WIFI_AP_PASS);
wifi_config.ap.max_connection = EXAMPLE_MAX_STA_CONN;
wifi_config.ap.authmode = WIFI_AUTH_WPA_WPA2_PSK;
if (strlen(EXAMPLE_ESP_WIFI_AP_PASS) == 0) {
wifi_config.ap.authmode = WIFI_AUTH_OPEN;
}
if (strlen(EXAMPLE_ESP_WIFI_AP_CHANNEL)) {
int channel;
sscanf(EXAMPLE_ESP_WIFI_AP_CHANNEL, "%d", &channel);
wifi_config.ap.channel = channel;
}
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_AP, &wifi_config));
ESP_LOGI(TAG, "wifi_init_softap finished.SSID:%s password:%s",
EXAMPLE_ESP_WIFI_AP_SSID, EXAMPLE_ESP_WIFI_AP_PASS);
}
static void wifi_init_sta()
{
wifi_config_t wifi_config;
memset(&wifi_config, 0, sizeof(wifi_config_t));
snprintf((char *)wifi_config.sta.ssid, 32, "%s", EXAMPLE_ESP_WIFI_SSID);
snprintf((char *)wifi_config.sta.password, 64, "%s", EXAMPLE_ESP_WIFI_PASS);
ESP_ERROR_CHECK(esp_wifi_set_config(ESP_IF_WIFI_STA, &wifi_config));
ESP_LOGI(TAG, "wifi_init_sta finished.");
ESP_LOGI(TAG, "connect to ap SSID:%s password:%s",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS);
}
void app_wifi_main()
{
esp_err_t ret = nvs_flash_init();
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
ESP_ERROR_CHECK(ret);
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
wifi_mode_t mode = WIFI_MODE_NULL;
if (strlen(EXAMPLE_ESP_WIFI_AP_SSID) && strlen(EXAMPLE_ESP_WIFI_SSID)) {
mode = WIFI_MODE_APSTA;
} else if (strlen(EXAMPLE_ESP_WIFI_AP_SSID)) {
mode = WIFI_MODE_AP;
} else if (strlen(EXAMPLE_ESP_WIFI_SSID)) {
mode = WIFI_MODE_STA;
}
if (mode == WIFI_MODE_NULL) {
ESP_LOGW(TAG, "Neither AP or STA have been configured. WiFi will be off.");
return;
}
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&wifi_event_handler,
NULL,
NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT,
IP_EVENT_STA_GOT_IP,
&wifi_event_handler,
NULL,
NULL));
ESP_ERROR_CHECK(esp_wifi_set_mode(mode));
if (mode & WIFI_MODE_AP) {
esp_netif_t * ap_netif = esp_netif_create_default_wifi_ap();
wifi_init_softap(ap_netif);
}
if (mode & WIFI_MODE_STA) {
esp_netif_create_default_wifi_sta();
wifi_init_sta();
}
ESP_ERROR_CHECK(esp_wifi_start());
ESP_ERROR_CHECK(esp_wifi_set_ps(WIFI_PS_NONE));
ESP_LOGI(TAG, "wifi init finished.");
if (mode & WIFI_MODE_STA) {
xEventGroupWaitBits(s_wifi_event_group,
WIFI_CONNECTED_BIT | WIFI_FAIL_BIT,
pdFALSE,
pdFALSE,
portMAX_DELAY);
}
vEventGroupDelete(s_wifi_event_group);
s_wifi_event_group = NULL;
}

View file

@ -0,0 +1,27 @@
// Copyright 2021-2022 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _APP_WIFI_H_
#define _APP_WIFI_H_
#ifdef __cplusplus
extern "C" {
#endif
void app_wifi_main();
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,119 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "freertos/FreeRTOS.h"
#include "freertos/queue.h"
#include "esp_http_server.h"
#include "img_converters.h"
#include "sdkconfig.h"
#include "esp_log.h"
#define PART_BOUNDARY "123456789000000000000987654321"
static const char *_STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char *_STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %d.%06d\r\n\r\n";
static QueueHandle_t xQueueFrameI = NULL;
static bool gReturnFB = true;
static httpd_handle_t stream_httpd = NULL;
static const char *TAG = "stream_s";
static esp_err_t stream_handler(httpd_req_t *req)
{
camera_fb_t *frame = NULL;
struct timeval _timestamp;
esp_err_t res = ESP_OK;
size_t _jpg_buf_len = 0;
uint8_t *_jpg_buf = NULL;
char *part_buf[128];
res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
if (res != ESP_OK) {
return res;
}
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_set_hdr(req, "X-Framerate", "60");
while (true) {
if (xQueueReceive(xQueueFrameI, &frame, portMAX_DELAY)) {
_timestamp.tv_sec = frame->timestamp.tv_sec;
_timestamp.tv_usec = frame->timestamp.tv_usec;
if (frame->format == PIXFORMAT_JPEG) {
_jpg_buf = frame->buf;
_jpg_buf_len = frame->len;
} else if (!frame2jpg(frame, 60, &_jpg_buf, &_jpg_buf_len)) {
ESP_LOGE(TAG, "JPEG compression failed");
res = ESP_FAIL;
}
} else {
res = ESP_FAIL;
}
if (res == ESP_OK) {
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
if (res == ESP_OK) {
size_t hlen = snprintf((char *)part_buf, 128, _STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec);
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
}
if (res == ESP_OK) {
res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
}
if (frame->format != PIXFORMAT_JPEG) {
free(_jpg_buf);
_jpg_buf = NULL;
}
}
if (gReturnFB) {
esp_camera_fb_return(frame);
} else {
free(frame->buf);
}
if (res != ESP_OK) {
ESP_LOGE(TAG, "Break stream handler");
break;
}
}
return res;
}
esp_err_t start_stream_server(const QueueHandle_t frame_i, const bool return_fb)
{
xQueueFrameI = frame_i;
gReturnFB = return_fb;
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
config.stack_size = 5120;
httpd_uri_t stream_uri = {
.uri = "/stream",
.method = HTTP_GET,
.handler = stream_handler,
.user_ctx = NULL
};
esp_err_t err = httpd_start(&stream_httpd, &config);
if (err == ESP_OK) {
err = httpd_register_uri_handler(stream_httpd, &stream_uri);
ESP_LOGI(TAG, "Starting stream server on port: '%d'", config.server_port);
return err;
}
ESP_LOGE(TAG, "httpd start err = %s", esp_err_to_name(err));
return ESP_FAIL;
}

View file

@ -0,0 +1,122 @@
// Copyright 2020-2021 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include "esp_log.h"
#include "camera_pin.h"
#include "app_wifi.h"
#include "esp_camera.h"
#define TEST_ESP_OK(ret) assert(ret == ESP_OK)
#define TEST_ASSERT_NOT_NULL(ret) assert(ret != NULL)
static bool auto_jpeg_support = false; // whether the camera sensor support compression or JPEG encode
static QueueHandle_t xQueueIFrame = NULL;
static const char *TAG = "video s_server";
esp_err_t start_stream_server(const QueueHandle_t frame_i, const bool return_fb);
static esp_err_t init_camera(uint32_t xclk_freq_hz, pixformat_t pixel_format, framesize_t frame_size, uint8_t fb_count)
{
camera_config_t camera_config = {
.pin_pwdn = CAMERA_PIN_PWDN,
.pin_reset = CAMERA_PIN_RESET,
.pin_xclk = CAMERA_PIN_XCLK,
.pin_sscb_sda = CAMERA_PIN_SIOD,
.pin_sscb_scl = CAMERA_PIN_SIOC,
.pin_d7 = CAMERA_PIN_D7,
.pin_d6 = CAMERA_PIN_D6,
.pin_d5 = CAMERA_PIN_D5,
.pin_d4 = CAMERA_PIN_D4,
.pin_d3 = CAMERA_PIN_D3,
.pin_d2 = CAMERA_PIN_D2,
.pin_d1 = CAMERA_PIN_D1,
.pin_d0 = CAMERA_PIN_D0,
.pin_vsync = CAMERA_PIN_VSYNC,
.pin_href = CAMERA_PIN_HREF,
.pin_pclk = CAMERA_PIN_PCLK,
//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
.xclk_freq_hz = xclk_freq_hz,
.ledc_timer = LEDC_TIMER_0, // // This is only valid on ESP32/ESP32-S2. ESP32-S3 use LCD_CAM interface.
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = pixel_format, //YUV422,GRAYSCALE,RGB565,JPEG
.frame_size = frame_size, //QQVGA-UXGA, sizes above QVGA are not been recommended when not JPEG format.
.jpeg_quality = 10, //0-63
.fb_count = fb_count, // For ESP32/ESP32-S2, if more than one, i2s runs in continuous mode. Use only with JPEG.
.grab_mode = CAMERA_GRAB_LATEST,
.fb_location = CAMERA_FB_IN_PSRAM
};
//initialize the camera
esp_err_t ret = esp_camera_init(&camera_config);
sensor_t *s = esp_camera_sensor_get();
s->set_vflip(s, 1);//flip it back
//initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_saturation(s, -2);//lower the saturation
}
if (s->id.PID == OV3660_PID || s->id.PID == OV2640_PID) {
s->set_vflip(s, 1); //flip it back
} else if (s->id.PID == GC0308_PID) {
s->set_hmirror(s, 0);
} else if (s->id.PID == GC032A_PID) {
s->set_vflip(s, 1);
}
camera_sensor_info_t *s_info = esp_camera_sensor_get_info(&(s->id));
if (ESP_OK == ret && PIXFORMAT_JPEG == pixel_format && s_info->support_jpeg == true) {
auto_jpeg_support = true;
}
return ret;
}
void app_main()
{
app_wifi_main();
camera_fb_t *frame;
xQueueIFrame = xQueueCreate(2, sizeof(camera_fb_t *));
/* It is recommended to use a camera sensor with JPEG compression to maximize the speed */
TEST_ESP_OK(init_camera(10000000, PIXFORMAT_JPEG, FRAMESIZE_QVGA, 2));
TEST_ESP_OK(start_stream_server(xQueueIFrame, true));
ESP_LOGI(TAG, "Begin capture frame");
while (true) {
frame = esp_camera_fb_get();
if (frame) {
xQueueSend(xQueueIFrame, &frame, portMAX_DELAY);
}
}
}

View file

@ -0,0 +1,2 @@
CONFIG_SPIRAM_SUPPORT=n
CONFIG_ESP32S2_SPIRAM_SUPPORT=n

View file

@ -0,0 +1,38 @@
CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
CONFIG_ESPTOOLPY_FLASHSIZE_4MB=y
CONFIG_FREERTOS_HZ=1000
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_SPIRAM_SUPPORT=y
CONFIG_ESP32_SPIRAM_SUPPORT=y
CONFIG_ESP32S2_SPIRAM_SUPPORT=y
CONFIG_ESP32S3_SPIRAM_SUPPORT=y
CONFIG_SPIRAM_MODE_OCT=y
CONFIG_SPIRAM_SPEED_80M=y
CONFIG_SPIRAM_MEMTEST=n
#
# camera-optionally
#
CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=1580
CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=1536
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1214
#
# wifi-iperf-specific
#
CONFIG_MEMMAP_SMP=y
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=4096
CONFIG_FREERTOS_UNICORE=n
CONFIG_ESP_INT_WDT=n
CONFIG_ESP_TASK_WDT=n
CONFIG_LWIP_ETHARP_TRUST_IP_MAC=n
CONFIG_LWIP_IRAM_OPTIMIZATION=y

View file

@ -0,0 +1,19 @@
#
# ESP32-wifi-iperf-specific
#
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=32
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=32
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65534
CONFIG_LWIP_TCP_WND_DEFAULT=65534
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_40M=y

View file

@ -0,0 +1,26 @@
#
# ESP32S2-wifi-iperf-specific
#
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=8
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=24
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=24
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=16
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=16
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=28000
CONFIG_LWIP_TCP_WND_DEFAULT=28000
CONFIG_LWIP_TCP_RECVMBOX_SIZE=32
CONFIG_LWIP_UDP_RECVMBOX_SIZE=32
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S2_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESP32S2_INSTRUCTION_CACHE_16KB=y
CONFIG_ESP32S2_INSTRUCTION_CACHE_LINE_16B=y
CONFIG_ESP32S2_INSTRUCTION_CACHE_WRAP=y

View file

@ -0,0 +1,26 @@
#
# ESP32S3-wifi-iperf-specific
#
CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=64
CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=64
CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
CONFIG_ESP32_WIFI_TX_BA_WIN=32
CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
CONFIG_ESP32_WIFI_RX_BA_WIN=32
CONFIG_LWIP_TCP_SND_BUF_DEFAULT=65535
CONFIG_LWIP_TCP_WND_DEFAULT=65535
CONFIG_LWIP_TCP_RECVMBOX_SIZE=64
CONFIG_LWIP_UDP_RECVMBOX_SIZE=64
CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=64
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_240=y
CONFIG_ESP32S3_DEFAULT_CPU_FREQ_MHZ=240
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_32KB=y
CONFIG_ESP32S3_INSTRUCTION_CACHE_LINE_32B=y
# CONFIG_ESP32S3_INSTRUCTION_CACHE_WRAP=y

View file

@ -98,6 +98,59 @@
"esp32",
"esp32s2"
]
},
{
"name": "basic",
"buildsystem": [
"cmake"
],
"targets": [
"esp32",
"esp32s2",
"esp32s3"
]
},
{
"name": "pic_server",
"buildsystem": [
"cmake"
],
"targets": [
"esp32",
"esp32s2",
"esp32s3"
]
},
{
"name": "test_framerate",
"buildsystem": [
"cmake"
],
"targets": [
"esp32",
"esp32s2",
"esp32s3"
]
},
{
"name": "video_stream_server",
"buildsystem": [
"cmake"
],
"targets": [
"esp32",
"esp32s2",
"esp32s3"
]
},
{
"name": "examples",
"buildsystem": [
"cmake",
"make"
],
"targets": [
]
}
]
}