You are using staging server - a separate instance of the ESP Component Registry that allows you to try distribution tools and processes without affecting the real registry.
# ESP32 Parallel IO Camera Driver [](https://github.com/HaqqiHaziq/esp_cam_io_parl/releases) ## General Information This repository provides **ESP Parallel IO Camera** component (`esp_cam_io_parl`) that utilizes Parallel IO (PARLIO) peripheral to receive image data over DVP (Digital Video Port) using ESP32 SoCs that are capable of driving image sensors. ### Supported Targets - ESP32-C6 - ESP32-H2 - ESP32-P4 - ESP32-C5 ### Supported Sensors | Model | Max resolution | Color type | Output format | Lens Size | | ------- | -------------- | ---------- | ----------------------------------------------------------------- | --------- | | OV2640 | 1600 x 1200 | color | YUV(422/420)/YCbCr422<br>RGB565/555<br>8-bit compressed data<br>8/10-bit Raw RGB data | 1/4" | | OV3660 | 2048 x 1536 | color | raw RGB data<br/>RGB565/555/444<br/>CCIR656<br/>YCbCr422<br/>compression | 1/5" | | OV5640 | 2592 x 1944 | color | RAW RGB<br/>RGB565/555/444<br/>CCIR656<br/>YUV422/420<br/>YCbCr422<br/>compression | 1/4" | ### DVP Data Width | Target | Max data width | Max PCLK frequency (ideal conditions) | Sample method format | | --------- | ---------------------------- | ------------------------------------- | ----------------------| | ESP32-C6 | 16 (8 with valid signals) | 80MHz | Gated PCLK with software delimiter for 16 data lines, HREF (level delimiter) or HSYNC (pulse delimiter) signals for 8 data lines. | | ESP32-H2 | 8 (No valid signals) | 48MHz | Gated PCLK with software delimiter for 8 data lines. This target does not accept valid signals with 8 data lines. | | ESP32-P4 | 16 (8 with valid signals) | 80MHz | Gated PCLK with software delimiter for 16 data lines, HREF (level delimiter) or HSYNC (pulse delimiter) signals for 8 data lines. | | ESP32-C5 | 8 (No valid signals) | 80MHz | Gated PCLK with software delimiter for 8 data lines. This target does not accept valid signals with 8 data lines. | ## Important to Remember - It is recommended to have PSRAM installed and enabled for higher resolutions. Therefore, the ESP32-H2 is not recommended for image streaming due to its lack of PSRAM support and limited internal RAM. The ESP32-C6 can handle resolutions up to SVGA (tested with Wi-Fi enabled and a streaming web server, XGA can be reached with some tweaks). - This component currently only accepts JPEG image inputs from DVP sensors due to the limitations of the Parallel IO driver for some targets (e.g. ESP32-H2 and ESP32-C5). As a result, it uses software delimiter with PCLK gating to allow streaming JPEG image from the following image sensors (except OV2640). - Currently only OV3660 and OV5640 sensors are implemented to have gated PCLK signals. OV2640 requires the target to have valid signals (e.g. ESP32-C6 and ESP32-P4) so it can properly interface with the following sensor. It is highly recommended to use OV5640 or OV3660 for targets with limited data width. - This component does not utilize VSYNC signals for controlling frames at the moment, support for receiving raw data will be possible if it gets implemented. ## Additional Notes - You can also use this component to receive JPEG images from another target capable of sending parallel data. ## Installation Instructions ### Using with ESP-IDF - Download and extract the component file. - Insert the component under the `components` folder in your project file. - If possible, enable PSRAM in `menuconfig` (also set Flash and PSRAM frequiencies to 80MHz for optimal performance) - Include the component in your main code: ```c #include "esp_camera_sensor.h" #include "esp_cam_io_parl.h" ``` ### Using with Arduino #### Arduino IDE This component will be released as a library. --- # Examples ## Capture & Stream Image (AP) ```c #include <stdbool.h> #include <stdio.h> #include <unistd.h> #include "esp_err.h" #include "esp_event.h" #include "esp_heap_caps.h" #include "esp_http_server.h" #include "esp_log.h" #include "esp_mac.h" #include "esp_timer.h" #include "esp_wifi.h" #include "nvs_flash.h" #include "sdkconfig.h" #include "esp_cam_io_parl.h" #include "esp_camera_sensor.h" static const char *TAG = "parallel_io_camera"; // Camera Sensor Configuration. Set the pins according to your connection to the DVP camera. #define CAM_PWDN_PIN -1 // Power down pin, set to -1 if not used #define CAM_RESET_PIN 5 // Software reset will be performed if set to -1 #define CAM_XCLK_PIN -1 // Emulated by PWM (LEDC), set to -1 for sensors with built-in crystal oscillator #define CAM_SDA_PIN 26 #define CAM_SCL_PIN 25 #define CAM_D0_PIN 10 #define CAM_D1_PIN 9 #define CAM_D2_PIN 8 #define CAM_D3_PIN 7 #define CAM_D4_PIN 6 #define CAM_D5_PIN 1 #define CAM_D6_PIN 0 #define CAM_D7_PIN 3 #define CAM_VSYNC_PIN -1 // Not implemented at the moment #define CAM_HREF_PIN -1 // Can not use any additional signals on ESP32-C5/ESP32-H2 #define CAM_HSYNC_PIN -1 // Can not use any additional signals on ESP32-C5/ESP32-H2 #define CAM_PCLK_PIN 2 // Save the frame buffer in PSRAM, or set it to MALLOC_CAP_INTERNAL for targets without PSRAM support #define FRAME_BUFFER_CAPS MALLOC_CAP_SPIRAM // Wi-Fi details #define ESP_WIFI_SSID "camera@2.4GHz" #define ESP_WIFI_PASS "my_camera" #define ESP_WIFI_CHANNEL 2 // Set channel over 36 for 5GHz (ESP32-C5) #define MAX_STA_CONN 4 #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\n\r\n"; httpd_handle_t capture_httpd = NULL; httpd_handle_t stream_httpd = NULL; static esp_cam_io_parl_handle_t esp_cam_io_parl_handle; typedef struct { size_t size; //number of values used for filtering size_t index; //current value index size_t count; //value count int sum; int *values; //array to be filled with values } ra_filter_t; static ra_filter_t ra_filter; static ra_filter_t *ra_filter_init(ra_filter_t *filter, size_t sample_size) { memset(filter, 0, sizeof(ra_filter_t)); filter->values = (int *)malloc(sample_size * sizeof(int)); if (!filter->values) { return NULL; } memset(filter->values, 0, sample_size * sizeof(int)); filter->size = sample_size; return filter; } static int ra_filter_run(ra_filter_t *filter, int value) { if (!filter->values) { return value; } filter->sum -= filter->values[filter->index]; filter->values[filter->index] = value; filter->sum += filter->values[filter->index]; filter->index++; filter->index = filter->index % filter->size; if (filter->count < filter->size) { filter->count++; } return filter->sum / filter->count; } static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) { 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, reason=%d", MAC2STR(event->mac), event->aid, event->reason); } } static void wifi_init_softap(void) { ESP_ERROR_CHECK(esp_netif_init()); ESP_ERROR_CHECK(esp_event_loop_create_default()); esp_netif_t *netif_interface = esp_netif_create_default_wifi_ap(); wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); 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)); wifi_config_t wifi_config = { .ap = { .ssid = ESP_WIFI_SSID, .ssid_len = strlen(ESP_WIFI_SSID), .channel = ESP_WIFI_CHANNEL, .password = ESP_WIFI_PASS, .max_connection = MAX_STA_CONN, #ifdef CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT .authmode = WIFI_AUTH_WPA3_PSK, .sae_pwe_h2e = WPA3_SAE_PWE_BOTH, #else /* CONFIG_ESP_WIFI_SOFTAP_SAE_SUPPORT */ .authmode = WIFI_AUTH_WPA2_PSK, #endif .pmf_cfg = { .required = true, }, #ifdef CONFIG_ESP_WIFI_BSS_MAX_IDLE_SUPPORT .bss_max_idle_cfg = { .period = WIFI_AP_DEFAULT_MAX_IDLE_PERIOD, .protected_keep_alive = 1, }, #endif }, }; if (strlen(ESP_WIFI_PASS) == 0) { wifi_config.ap.authmode = WIFI_AUTH_OPEN; } ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_AP)); ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config)); ESP_ERROR_CHECK(esp_wifi_start()); /* // Uncomment if target is ESP32-C5 for 5GHz connectivity ESP_ERROR_CHECK(esp_wifi_set_band_mode(WIFI_BAND_MODE_5G_ONLY)); */ ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d", ESP_WIFI_SSID, ESP_WIFI_PASS, ESP_WIFI_CHANNEL); esp_netif_ip_info_t ip_info; esp_netif_get_ip_info(netif_interface, &ip_info); ESP_LOGI(TAG, "IP Address:" IPSTR, IP2STR(&ip_info.ip)); } static esp_err_t capture_handler(httpd_req_t *req) { esp_err_t res = ESP_OK; int64_t fr_start = esp_timer_get_time(); esp_cam_io_parl_trans_t frame; if (esp_cam_io_parl_receive(esp_cam_io_parl_handle, &frame, 5000) != ESP_OK) { ESP_LOGE(TAG, "Camera capture failed"); httpd_resp_send_500(req); return ESP_FAIL; } size_t frame_length = frame.length; 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", "*"); res = httpd_resp_send(req, (const char *)frame.buffer, frame.length); esp_cam_io_parl_free_buffer(frame); int64_t fr_end = esp_timer_get_time(); ESP_LOGI(TAG, "JPG: %uB %ums", frame_length, (uint32_t)((fr_end - fr_start) / 1000)); return res; } static esp_err_t stream_handler(httpd_req_t *req) { 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) { int64_t last_frame = esp_timer_get_time(); esp_cam_io_parl_trans_t image; if (esp_cam_io_parl_receive(esp_cam_io_parl_handle, &image, 5000) != ESP_OK) { ESP_LOGE(TAG, "Camera capture failed"); res = ESP_FAIL; } else { _jpg_buf_len = image.length; _jpg_buf = image.buffer; } 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); 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 (image.buffer) { esp_cam_io_parl_free_buffer(image); _jpg_buf = NULL; } else if (_jpg_buf) { free(_jpg_buf); _jpg_buf = NULL; } if (res != ESP_OK) { ESP_LOGE(TAG, "Send frame failed"); break; } int64_t frame_time = esp_timer_get_time() - last_frame; frame_time /= 1000; uint32_t avg_frame_time = ra_filter_run(&ra_filter, frame_time); ESP_LOGI(TAG, "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)", (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time, avg_frame_time, 1000.0 / avg_frame_time); } return res; } static void start_camera_server(void) { httpd_config_t config = HTTPD_DEFAULT_CONFIG(); httpd_uri_t capture_uri = { .uri = "/capture", .method = HTTP_GET, .handler = capture_handler, .user_ctx = NULL, #ifdef CONFIG_HTTPD_WS_SUPPORT .is_websocket = true, .handle_ws_control_frames = false, .supported_subprotocol = NULL, #endif }; httpd_uri_t stream_uri = { .uri = "/stream", .method = HTTP_GET, .handler = stream_handler, .user_ctx = NULL, #ifdef CONFIG_HTTPD_WS_SUPPORT .is_websocket = true, .handle_ws_control_frames = false, .supported_subprotocol = NULL, #endif }; ra_filter_init(&ra_filter, 20); ESP_LOGI(TAG, "Starting capture server on port: '%d'", config.server_port); if (httpd_start(&capture_httpd, &config) == ESP_OK) { httpd_register_uri_handler(capture_httpd, &capture_uri); } config.server_port += 1; config.ctrl_port += 1; ESP_LOGI(TAG, "Starting stream server on port: '%d'", config.server_port); if (httpd_start(&stream_httpd, &config) == ESP_OK) { httpd_register_uri_handler(stream_httpd, &stream_uri); } } void app_main(void) { 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); // Camera sensor configuration static esp_camera_sensor_config_t camera_sensor_config = { .pwdn_io = CAM_PWDN_PIN, .reset_io = CAM_RESET_PIN, .xclk_io = CAM_XCLK_PIN, .xclk_hz = 20000000, .sda_io = CAM_SDA_PIN, .scl_io = CAM_SCL_PIN, .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, .pixel_format = PIXFORMAT_JPEG, // esp_cam_io_parl only supports JPEG images at the moment .frame_size = FRAMESIZE_QVGA, .jpeg_quality = 8, }; // DVP port configuration static esp_cam_io_parl_config_t esp_cam_io_parl_config = { .data_width = 8, .queue_frames = 1, .pclk_io = CAM_PCLK_PIN, .de_io = CAM_HREF_PIN, .hsync_io = CAM_HSYNC_PIN, .vsync_io = CAM_VSYNC_PIN, // Not implemented .data_io = { CAM_D0_PIN, CAM_D1_PIN, CAM_D2_PIN, CAM_D3_PIN, CAM_D4_PIN, CAM_D5_PIN, CAM_D6_PIN, CAM_D7_PIN, }, .flags = { .free_clk = true, .allow_pd = true, }, }; esp_err_t err = esp_camera_sensor_init(&camera_sensor_config); if (err != ESP_OK) { ESP_LOGE(TAG, "Camera init failed with error 0x%x", err); return; } camera_sensor_t *sensor = esp_camera_sensor_get(); ESP_LOGI(TAG, "Camera detected! Current quality = %u", sensor->status.quality); sensor->set_vflip(sensor, true); // Adjust if the image is flipped vertically sensor->set_hmirror(sensor, false); // Adjust if the image is flipped horizontally ESP_ERROR_CHECK(esp_cam_new_io_parl(&esp_cam_io_parl_config, &esp_cam_io_parl_handle)); ESP_ERROR_CHECK(esp_cam_io_parl_enable(esp_cam_io_parl_handle, true)); image_info_t *image = esp_camera_sensor_get_image(); // Prepare the frame allocation ESP_ERROR_CHECK(esp_cam_io_parl_set_alloc_size(esp_cam_io_parl_handle, image->width * image->height / 4 + 2048, FRAME_BUFFER_CAPS)); wifi_init_softap(); start_camera_server(); } ``` --- # API Reference ## `esp_camera_sensor` #### ESP Camera Sensor component included in this package to interface with OV2640, OV3660 and OV5640 camera sensors. It is a modified version of `esp_camera.h` component by Espressif. ```c #include "esp_camera_sensor.h" ``` ### Data Types #### `esp_camera_sensor_config_t` Configuration structure for camera sensor initialization. | Field | Type | Description | | --------------- | -------------------- | ------------------------------------------- | | `pwdn_io` | `gpio_num_t` | GPIO pin for camera power-down line | | `reset_io` | `gpio_num_t` | GPIO pin for camera reset line | | `xclk_io` | `gpio_num_t` | GPIO pin for camera XCLK line | | `sda_io` | `gpio_num_t` | GPIO pin for camera SDA line | | `scl_io` | `gpio_num_t` | GPIO pin for camera SCL line | | `xclk_hz` | `uint32_t` | XCLK frequency in Hz | | `pixel_format` | `camera_pixformat_t` | Pixel format (`PIXFORMAT_*`) | | `frame_size` | `camera_framesize_t` | Frame size (`FRAMESIZE_*`) | | `ledc_timer` | `ledc_timer_t` | LEDC timer for XCLK generation | | `ledc_channel` | `ledc_channel_t` | LEDC channel for XCLK generation | | `jpeg_quality` | `int` | JPEG quality (0–63, lower = higher quality) | #### `image_info_t` Data structure containing image properties. | Field | Type | Description | | -------- | -------------------- | ---------------------- | | `width` | `size_t` | Image width in pixels | | `height` | `size_t` | Image height in pixels | | `format` | `camera_pixformat_t` | Pixel format | ### Functions #### `esp_camera_sensor_init` ```c esp_err_t esp_camera_sensor_init(const esp_camera_sensor_config_t *config); ``` Initialize the camera driver and configure the sensor via SCCB/I2C. **Parameters:** * `config` — Pointer to camera configuration parameters. **Returns:** * `ESP_OK` — Success * `ESP_ERR_INVALID_ARG` — Invalid parameters * `ESP_ERR_CAMERA_NOT_DETECTED` — Sensor not detected #### `esp_camera_sensor_deinit` ```c esp_err_t esp_camera_sensor_deinit(void); ``` Deinitialize the camera driver. **Returns:** * `ESP_OK` — Success * `ESP_ERR_INVALID_STATE` — Driver not initialized #### `esp_camera_sensor_get_image` ```c image_info_t *esp_camera_sensor_get_image(void); ``` Get image resolution information for frame allocation. **Returns:** Pointer to `image_info_t` structure. #### `esp_camera_sensor_get` ```c camera_sensor_t *esp_camera_sensor_get(void); ``` Get a pointer to the sensor control structure. **Returns:** Pointer to `camera_sensor_t` structure. #### `esp_camera_sensor_save_to_nvs` ```c esp_err_t esp_camera_sensor_save_to_nvs(const char *key); ``` Save camera settings to NVS. **Parameters:** * `key` — Unique key for camera settings. #### `esp_camera_sensor_load_from_nvs` ```c esp_err_t esp_camera_sensor_load_from_nvs(const char *key); ``` Load camera settings from NVS. **Parameters:** * `key` — Unique key for camera settings. --- ## `esp_cam_io_parl` #### ESP Parallel IO Camera component to interface with the DVP port of the following camera sensor. ```c #include "esp_cam_io_parl.h" ``` ### Data Types #### `esp_cam_io_parl_pclk_edge` > **PCLK edge configuration for sampling incoming data.** | Enumerator | Description | | -------------------------- | ------------------------------------- | | `ESP_CAM_IO_PARL_PCLK_NEG` | Sample PCLK data on the negative edge | | `ESP_CAM_IO_PARL_PCLK_POS` | Sample PCLK data on the positive edge | #### `esp_cam_io_parl_config_t` > **Configuration structure for `esp_cam_io_parl`.** | Field | Type | Description | | -------------------- | -------------- | ----------------------------------------------------------- | | `data_width` | `size_t` | DVP data width (8 or 16 bits depending on SoC capabilities) | | `queue_frames` | `size_t` | Number of frames to be queued | | `pclk_io` | `gpio_num_t` | PCLK GPIO pin | | `pclk_sample_edge` | `esp_cam_io_parl_pclk_edge` | Sampling edge (`ESP_CAM_IO_PARL_PCLK_NEG` or `ESP_CAM_IO_PARL_PCLK_POS`) | | `vsync_io` | `gpio_num_t` | VSYNC GPIO pin *(Not implemented)* | | `de_io` | `gpio_num_t` | DE (HREF) GPIO pin, set to -1 if unused | | `hsync_io` | `gpio_num_t` | HSYNC GPIO pin, set to -1 if unused | | `data_io[]` | `gpio_num_t` | Data line GPIOs | | `flags.invert_vsync` | `bool` | Invert VSYNC *(Not implemented)* | | `flags.invert_de` | `bool` | Invert DE pin (active low) | | `flags.invert_hsync` | `bool` | Invert HSYNC pin (active on rising edge) | | `flags.jpeg_en` | `bool` | JPEG input expected *(default)* | | `flags.free_clk` | `bool` | PCLK is free-running | | `flags.allow_pd` | `bool` | Allow power down | #### `esp_cam_io_parl_trans_t` > **Transaction buffer structure for received frames.** | Field | Type | Description | | -------- | ---------- | ----------------------- | | `buffer` | `uint8_t*` | Pointer to frame buffer | | `length` | `uint32_t` | Length of frame buffer | #### `esp_cam_io_parl_handle_t` > **Handle pointer to `esp_cam_io_parl`.** ### Functions #### `esp_cam_new_io_parl` ```c esp_err_t esp_cam_new_io_parl(const esp_cam_io_parl_config_t *config, esp_cam_io_parl_handle_t *ret_handle) ``` Creates and initializes a new `esp_cam_io_parl` handle. **Parameters:** * `config` — Pointer to configuration structure. * `ret_handle` — Output handle. **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid parameters. * `ESP_ERR_NO_MEM` — Out of memory. * `ESP_OK` — Success. #### `esp_cam_del_io_parl` ```c esp_err_t esp_cam_del_io_parl(esp_cam_io_parl_handle_t esp_cam_io_parl); ``` Deletes a `esp_cam_io_parl` handle and deinitializes resources. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` to delete. **Returns:** * `ESP_ERR_INVALID_ARG` — Handle is NULL. * `ESP_OK` — Success. #### `esp_cam_io_parl_set_alloc_size` ```c esp_err_t esp_cam_io_parl_set_alloc_size(esp_cam_io_parl_handle_t esp_cam_io_parl, uint32_t alloc_size, uint32_t heap_caps); ``` Sets the allocation size for the frame buffer. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` * `alloc_size` — Frame allocation size (JPEG recommended: `width * height / 4 + 2048`). * `heap_caps` — Memory type (`MALLOC_CAP_INTERNAL` or `MALLOC_CAP_SPIRAM`). **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid arguments. * `ESP_OK` — Success. #### `esp_cam_io_parl_enable` ```c esp_err_t esp_cam_io_parl_enable(esp_cam_io_parl_handle_t esp_cam_io_parl, bool reset_queue); ``` Enables frame reception. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` * `reset_queue` — Reset frame queue. **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid handle. * `ESP_ERR_INVALID_STATE` — Already enabled. * `ESP_OK` — Success. #### `esp_cam_io_parl_disable` ```c esp_err_t esp_cam_io_parl_disable(esp_cam_io_parl_handle_t esp_cam_io_parl) ``` Disables frame reception. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid handle. * `ESP_ERR_INVALID_STATE` — Already disabled. * `ESP_OK` — Success. #### `esp_cam_io_parl_receive` ```c esp_err_t esp_cam_io_parl_receive(esp_cam_io_parl_handle_t esp_cam_io_parl, esp_cam_io_parl_trans_t *frame, int32_t timeout_ms); ``` Receives a frame from the queue. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` * `frame` — the frame buffer object. * `timeout_ms` — Timeout in milliseconds (-1 for no timeout). **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid handle. * `ESP_ERR_TIMEOUT` — Timeout expired. * `ESP_OK` — Success. #### `esp_cam_io_parl_receive_from_isr` ```c esp_err_t esp_cam_io_parl_receive_from_isr(esp_cam_io_parl_handle_t esp_cam_io_parl, esp_cam_io_parl_trans_t *frame, bool *hp_task_woken); ``` Receives a frame from ISR context. **Notes:** * Should only be called in ISR. * Callback must be non-blocking. **Parameters:** * `esp_cam_io_parl` — Handle that was created with `esp_cam_new_io_parl` * `frame` — the frame buffer object. * `hp_task_woken` — Whether the high priority task is woken. **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid handle. * `ESP_ERR_INVALID_STATE` — Called outside ISR. * `ESP_FAIL` — Failed to receive. * `ESP_OK` — Success. #### `esp_cam_io_parl_free_buffer` ```c esp_err_t esp_cam_io_parl_free_buffer(esp_cam_io_parl_trans_t frame); ``` Frees a previously received frame buffer. **Parameters:** * `frame` — The frame buffer object. **Returns:** * `ESP_ERR_INVALID_ARG` — Invalid buffer. * `ESP_OK` — Success.
idf.py add-dependency "haqqihaziq/esp_cam_io_parl^0.1.0-beta.2"