From 5bb9bfe5e4230c4045c8a75fc8c9876197851b0e Mon Sep 17 00:00:00 2001 From: RubenKelevra Date: Thu, 31 Jul 2025 11:21:35 +0200 Subject: [PATCH] rework psram_mode frame buffer overflow check - Do this check only in psram_mode - Improve code comment, to make clear that it will stop early on copy operations - Increase fb size by one dma_half_buffer_size in psram_mode Rationale: In psram_mode we will be called after each memory copy operation is completed, by the CAM_IN_SUC_EOF event. Since we cannot predict at this point, if the camera will copy another dma_half_buffer_size into the fb, we need to abort here, if there's not enough size in the fb for the next copy operation. This assumption means, we will abort even if this is indeed the last copy operation the camera did, and the next event will be a CAM_VSYNC, notifying us, that the copy operation is completed. Since we cannot predict this, we need one dma_half_buffer_size more space in the fb in psram_mode to allow images of the same size in psram_mode as in the regular mode. --- driver/cam_hal.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/driver/cam_hal.c b/driver/cam_hal.c index 877971afc8..cc3ddf97ad 100644 --- a/driver/cam_hal.c +++ b/driver/cam_hal.c @@ -17,6 +17,7 @@ #include #include "esp_heap_caps.h" #include "freertos/FreeRTOS.h" +#include "freertos/task.h" #include "ll_cam.h" #include "cam_hal.h" @@ -208,6 +209,18 @@ static void cam_task(void *arg) &frame_buffer_event->buf[frame_buffer_event->len], &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size], cam_obj->dma_half_buffer_size); + } else { + // stop if the next DMA copy would exceed the framebuffer slot + // size, since we're called only after the copy occurs + // This effectively reduces maximum usable frame buffer size + // by one DMA operation, as we can't predict here, if the next + // cam event will be a VSYNC + if (cnt + 1 >= cam_obj->frame_copy_cnt) { + ESP_CAMERA_ETS_PRINTF(DRAM_STR("cam_hal: DMA overflow\r\n")); + ll_cam_stop(cam_obj); + cam_obj->state = CAM_STATE_IDLE; + continue; + } } //Check for JPEG SOI in the first buffer. stop if not found if (cam_obj->jpeg_mode && cnt == 0 && cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len) != 0) { @@ -215,14 +228,6 @@ static void cam_task(void *arg) cam_obj->state = CAM_STATE_IDLE; } cnt++; - // stop when too many DMA copies occur so the PSRAM - // framebuffer slot doesn't overflow from runaway transfers - if (cnt >= cam_obj->frame_copy_cnt) { - ESP_LOGE(TAG, "DMA overflow"); - ll_cam_stop(cam_obj); - cam_obj->state = CAM_STATE_IDLE; - continue; - } } else if (cam_event == CAM_VSYNC_EVENT) { //DBG_PIN_SET(1); @@ -320,6 +325,9 @@ static esp_err_t cam_dma_config(const camera_config_t *config) cam_obj->dma_node_cnt = (cam_obj->dma_buffer_size) / cam_obj->dma_node_buffer_size; // Number of DMA nodes cam_obj->frame_copy_cnt = cam_obj->recv_size / cam_obj->dma_half_buffer_size; // Number of interrupted copies, ping-pong copy + if (cam_obj->psram_mode) { + cam_obj->frame_copy_cnt++; + } ESP_LOGI(TAG, "buffer_size: %d, half_buffer_size: %d, node_buffer_size: %d, node_cnt: %d, total_cnt: %d", (int) cam_obj->dma_buffer_size, (int) cam_obj->dma_half_buffer_size, (int) cam_obj->dma_node_buffer_size, @@ -338,6 +346,7 @@ static esp_err_t cam_dma_config(const camera_config_t *config) if (cam_obj->fb_size < cam_obj->recv_size) { fb_size = cam_obj->recv_size; } + fb_size += cam_obj->dma_half_buffer_size; } /* Allocate memory for frame buffer */