Merge pull request #776 from RubenKelevra/bugfix/implement_jpeg_soi_check_for_psram_dma

fix jpeg soi check for psram_mode (DMA)
This commit is contained in:
Me No Dev
2025-08-05 12:12:27 +03:00
committed by GitHub
2 changed files with 84 additions and 4 deletions

View File

@ -75,7 +75,7 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
) )
endif() endif()
set(priv_requires freertos nvs_flash) set(priv_requires freertos nvs_flash esp_mm)
set(min_version_for_esp_timer "4.2") set(min_version_for_esp_timer "4.2")
if (idf_version VERSION_GREATER_EQUAL min_version_for_esp_timer) if (idf_version VERSION_GREATER_EQUAL min_version_for_esp_timer)

View File

@ -24,6 +24,13 @@
#include "rom/ets_sys.h" #include "rom/ets_sys.h"
#else #else
#include "esp_timer.h" #include "esp_timer.h"
#include "esp_cache.h"
#include "hal/cache_hal.h"
#include "hal/cache_ll.h"
#include "esp_idf_version.h"
#ifndef ESP_CACHE_MSYNC_FLAG_DIR_M2C
#define ESP_CACHE_MSYNC_FLAG_DIR_M2C 0
#endif
#if CONFIG_IDF_TARGET_ESP32 #if CONFIG_IDF_TARGET_ESP32
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0 #include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
#elif CONFIG_IDF_TARGET_ESP32S2 #elif CONFIG_IDF_TARGET_ESP32S2
@ -56,6 +63,29 @@ static portMUX_TYPE g_psram_dma_lock = portMUX_INITIALIZER_UNLOCKED;
#define CAM_LOG_SPAM_EVERY_FRAME 0 /* set to 1 to restore old behaviour */ #define CAM_LOG_SPAM_EVERY_FRAME 0 /* set to 1 to restore old behaviour */
#endif #endif
/* Number of bytes copied to SRAM for SOI validation when capturing
* directly to PSRAM. Tunable to probe more of the frame start if needed. */
#ifndef CAM_SOI_PROBE_BYTES
#define CAM_SOI_PROBE_BYTES 32
#endif
/*
* PSRAM DMA may bypass the CPU cache. Always call esp_cache_msync() on the
* SOI probe region so cached reads see the data written by DMA.
*/
static inline size_t dcache_line_size(void)
{
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
/* cache_hal_get_cache_line_size() added extra argument from IDF 5.2 */
return cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
#else
/* Older releases only expose the ROM helper, all current targets
* have a 32byte DCache line */
return 32;
#endif
}
/* Throttle repeated warnings printed from tight loops / ISRs. /* Throttle repeated warnings printed from tight loops / ISRs.
* *
* counter static DRAM/IRAM uint16_t you pass in * counter static DRAM/IRAM uint16_t you pass in
@ -209,11 +239,61 @@ static void cam_task(void *arg)
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size], &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
cam_obj->dma_half_buffer_size); cam_obj->dma_half_buffer_size);
} }
//Check for JPEG SOI in the first buffer. stop if not found //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) { if (cam_obj->jpeg_mode && cnt == 0) {
ll_cam_stop(cam_obj); if (cam_obj->psram_mode) {
cam_obj->state = CAM_STATE_IDLE; /* dma_half_buffer_size already in BYTES (see ll_cam_memcpy()) */
size_t probe_len = cam_obj->dma_half_buffer_size;
/* clamp to avoid copying past the end of soi_probe */
if (probe_len > CAM_SOI_PROBE_BYTES) {
probe_len = CAM_SOI_PROBE_BYTES;
}
/* Invalidate cache lines for the DMA buffer before probing */
size_t line = dcache_line_size();
if (line == 0) {
line = 32; /* sane fallback */
}
uintptr_t addr = (uintptr_t)frame_buffer_event->buf;
uintptr_t start = addr & ~(line - 1);
size_t sync_len = (probe_len + (addr - start) + line - 1) & ~(line - 1);
esp_cache_msync((void *)start, sync_len,
ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
uint8_t soi_probe[CAM_SOI_PROBE_BYTES];
memcpy(soi_probe, frame_buffer_event->buf, probe_len);
int soi_off = cam_verify_jpeg_soi(soi_probe, probe_len);
if (soi_off != 0) {
static uint16_t warn_psram_soi_cnt = 0;
if (soi_off > 0) {
CAM_WARN_THROTTLE(warn_psram_soi_cnt,
"NO-SOI - JPEG start marker not at pos 0 (PSRAM)");
} else {
CAM_WARN_THROTTLE(warn_psram_soi_cnt,
"NO-SOI - JPEG start marker missing (PSRAM)");
}
ll_cam_stop(cam_obj);
cam_obj->state = CAM_STATE_IDLE;
continue;
}
} else {
int soi_off = cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len);
if (soi_off != 0) {
static uint16_t warn_soi_bad_cnt = 0;
if (soi_off > 0) {
CAM_WARN_THROTTLE(warn_soi_bad_cnt,
"NO-SOI - JPEG start marker not at pos 0");
} else {
CAM_WARN_THROTTLE(warn_soi_bad_cnt,
"NO-SOI - JPEG start marker missing");
}
ll_cam_stop(cam_obj);
cam_obj->state = CAM_STATE_IDLE;
continue;
}
}
} }
cnt++; cnt++;
// stop when too many DMA copies occur so the PSRAM // stop when too many DMA copies occur so the PSRAM
// framebuffer slot doesn't overflow from runaway transfers // framebuffer slot doesn't overflow from runaway transfers