Skip to content

Commit e6378d2

Browse files
authored
Merge pull request #776 from RubenKelevra/bugfix/implement_jpeg_soi_check_for_psram_dma
fix jpeg soi check for psram_mode (DMA)
2 parents 62b16fc + 1c0f7bd commit e6378d2

File tree

2 files changed

+84
-4
lines changed

2 files changed

+84
-4
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ if(IDF_TARGET STREQUAL "esp32" OR IDF_TARGET STREQUAL "esp32s2" OR IDF_TARGET ST
7575
)
7676
endif()
7777

78-
set(priv_requires freertos nvs_flash)
78+
set(priv_requires freertos nvs_flash esp_mm)
7979

8080
set(min_version_for_esp_timer "4.2")
8181
if (idf_version VERSION_GREATER_EQUAL min_version_for_esp_timer)

driver/cam_hal.c

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,13 @@
2424
#include "rom/ets_sys.h"
2525
#else
2626
#include "esp_timer.h"
27+
#include "esp_cache.h"
28+
#include "hal/cache_hal.h"
29+
#include "hal/cache_ll.h"
30+
#include "esp_idf_version.h"
31+
#ifndef ESP_CACHE_MSYNC_FLAG_DIR_M2C
32+
#define ESP_CACHE_MSYNC_FLAG_DIR_M2C 0
33+
#endif
2734
#if CONFIG_IDF_TARGET_ESP32
2835
#include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
2936
#elif CONFIG_IDF_TARGET_ESP32S2
@@ -56,6 +63,29 @@ static portMUX_TYPE g_psram_dma_lock = portMUX_INITIALIZER_UNLOCKED;
5663
#define CAM_LOG_SPAM_EVERY_FRAME 0 /* set to 1 to restore old behaviour */
5764
#endif
5865

66+
/* Number of bytes copied to SRAM for SOI validation when capturing
67+
* directly to PSRAM. Tunable to probe more of the frame start if needed. */
68+
#ifndef CAM_SOI_PROBE_BYTES
69+
#define CAM_SOI_PROBE_BYTES 32
70+
#endif
71+
72+
/*
73+
* PSRAM DMA may bypass the CPU cache. Always call esp_cache_msync() on the
74+
* SOI probe region so cached reads see the data written by DMA.
75+
*/
76+
77+
static inline size_t dcache_line_size(void)
78+
{
79+
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0)
80+
/* cache_hal_get_cache_line_size() added extra argument from IDF 5.2 */
81+
return cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA);
82+
#else
83+
/* Older releases only expose the ROM helper, all current targets
84+
* have a 32‑byte DCache line */
85+
return 32;
86+
#endif
87+
}
88+
5989
/* Throttle repeated warnings printed from tight loops / ISRs.
6090
*
6191
* counter – static DRAM/IRAM uint16_t you pass in
@@ -209,11 +239,61 @@ static void cam_task(void *arg)
209239
&cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
210240
cam_obj->dma_half_buffer_size);
211241
}
242+
212243
//Check for JPEG SOI in the first buffer. stop if not found
213-
if (cam_obj->jpeg_mode && cnt == 0 && cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len) != 0) {
214-
ll_cam_stop(cam_obj);
215-
cam_obj->state = CAM_STATE_IDLE;
244+
if (cam_obj->jpeg_mode && cnt == 0) {
245+
if (cam_obj->psram_mode) {
246+
/* dma_half_buffer_size already in BYTES (see ll_cam_memcpy()) */
247+
size_t probe_len = cam_obj->dma_half_buffer_size;
248+
/* clamp to avoid copying past the end of soi_probe */
249+
if (probe_len > CAM_SOI_PROBE_BYTES) {
250+
probe_len = CAM_SOI_PROBE_BYTES;
251+
}
252+
/* Invalidate cache lines for the DMA buffer before probing */
253+
size_t line = dcache_line_size();
254+
if (line == 0) {
255+
line = 32; /* sane fallback */
256+
}
257+
uintptr_t addr = (uintptr_t)frame_buffer_event->buf;
258+
uintptr_t start = addr & ~(line - 1);
259+
size_t sync_len = (probe_len + (addr - start) + line - 1) & ~(line - 1);
260+
esp_cache_msync((void *)start, sync_len,
261+
ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE);
262+
263+
uint8_t soi_probe[CAM_SOI_PROBE_BYTES];
264+
memcpy(soi_probe, frame_buffer_event->buf, probe_len);
265+
int soi_off = cam_verify_jpeg_soi(soi_probe, probe_len);
266+
if (soi_off != 0) {
267+
static uint16_t warn_psram_soi_cnt = 0;
268+
if (soi_off > 0) {
269+
CAM_WARN_THROTTLE(warn_psram_soi_cnt,
270+
"NO-SOI - JPEG start marker not at pos 0 (PSRAM)");
271+
} else {
272+
CAM_WARN_THROTTLE(warn_psram_soi_cnt,
273+
"NO-SOI - JPEG start marker missing (PSRAM)");
274+
}
275+
ll_cam_stop(cam_obj);
276+
cam_obj->state = CAM_STATE_IDLE;
277+
continue;
278+
}
279+
} else {
280+
int soi_off = cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len);
281+
if (soi_off != 0) {
282+
static uint16_t warn_soi_bad_cnt = 0;
283+
if (soi_off > 0) {
284+
CAM_WARN_THROTTLE(warn_soi_bad_cnt,
285+
"NO-SOI - JPEG start marker not at pos 0");
286+
} else {
287+
CAM_WARN_THROTTLE(warn_soi_bad_cnt,
288+
"NO-SOI - JPEG start marker missing");
289+
}
290+
ll_cam_stop(cam_obj);
291+
cam_obj->state = CAM_STATE_IDLE;
292+
continue;
293+
}
294+
}
216295
}
296+
217297
cnt++;
218298
// stop when too many DMA copies occur so the PSRAM
219299
// framebuffer slot doesn't overflow from runaway transfers

0 commit comments

Comments
 (0)