|
24 | 24 | #include "rom/ets_sys.h"
|
25 | 25 | #else
|
26 | 26 | #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" |
27 | 31 | #if CONFIG_IDF_TARGET_ESP32
|
28 | 32 | #include "esp32/rom/ets_sys.h" // will be removed in idf v5.0
|
29 | 33 | #elif CONFIG_IDF_TARGET_ESP32S2
|
@@ -56,6 +60,26 @@ static portMUX_TYPE g_psram_dma_lock = portMUX_INITIALIZER_UNLOCKED;
|
56 | 60 | #define CAM_LOG_SPAM_EVERY_FRAME 0 /* set to 1 to restore old behaviour */
|
57 | 61 | #endif
|
58 | 62 |
|
| 63 | +/* Number of bytes copied to SRAM for SOI validation when capturing |
| 64 | + * directly to PSRAM. Tunable to probe more of the frame start if needed. */ |
| 65 | +#ifndef CAM_SOI_PROBE_BYTES |
| 66 | +#define CAM_SOI_PROBE_BYTES 32 |
| 67 | +#endif |
| 68 | + |
| 69 | +/* |
| 70 | + * PSRAM DMA may bypass the CPU cache. Always call esp_cache_msync() on the |
| 71 | + * SOI probe region so cached reads see the data written by DMA. |
| 72 | + */ |
| 73 | + |
| 74 | +static inline size_t dcache_line_size(void) |
| 75 | +{ |
| 76 | +#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 2, 0) |
| 77 | + return cache_hal_get_cache_line_size(CACHE_LL_LEVEL_EXT_MEM, CACHE_TYPE_DATA); |
| 78 | +#else |
| 79 | + return cache_hal_get_cache_line_size(CACHE_TYPE_DATA); |
| 80 | +#endif |
| 81 | +} |
| 82 | + |
59 | 83 | /* Throttle repeated warnings printed from tight loops / ISRs.
|
60 | 84 | *
|
61 | 85 | * counter – static DRAM/IRAM uint16_t you pass in
|
@@ -209,11 +233,53 @@ static void cam_task(void *arg)
|
209 | 233 | &cam_obj->dma_buffer[(cnt % cam_obj->dma_half_buffer_cnt) * cam_obj->dma_half_buffer_size],
|
210 | 234 | cam_obj->dma_half_buffer_size);
|
211 | 235 | }
|
| 236 | + |
212 | 237 | //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; |
| 238 | + if (cam_obj->jpeg_mode && cnt == 0) { |
| 239 | + if (cam_obj->psram_mode) { |
| 240 | + /* dma_half_buffer_size already in BYTES (see ll_cam_memcpy()) */ |
| 241 | + size_t probe_len = cam_obj->dma_half_buffer_size; |
| 242 | + /* clamp to avoid copying past the end of soi_probe */ |
| 243 | + if (probe_len > CAM_SOI_PROBE_BYTES) { |
| 244 | + probe_len = CAM_SOI_PROBE_BYTES; |
| 245 | + } |
| 246 | + /* Invalidate cache lines for the DMA buffer before probing */ |
| 247 | + size_t line = dcache_line_size(); |
| 248 | + if (line == 0) { |
| 249 | + line = 32; /* sane fallback */ |
| 250 | + } |
| 251 | + uintptr_t addr = (uintptr_t)frame_buffer_event->buf; |
| 252 | + uintptr_t start = addr & ~(line - 1); |
| 253 | + size_t sync_len = (probe_len + (addr - start) + line - 1) & ~(line - 1); |
| 254 | + esp_cache_msync((void *)start, sync_len, |
| 255 | + ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE); |
| 256 | + |
| 257 | + uint8_t soi_probe[CAM_SOI_PROBE_BYTES]; |
| 258 | + memcpy(soi_probe, frame_buffer_event->buf, probe_len); |
| 259 | + int soi_off = cam_verify_jpeg_soi(soi_probe, probe_len); |
| 260 | + if (soi_off != 0) { |
| 261 | + static uint16_t warn_psram_soi_cnt = 0; |
| 262 | + if (soi_off > 0) { |
| 263 | + CAM_WARN_THROTTLE(warn_psram_soi_cnt, |
| 264 | + "NO-SOI - JPEG start marker not at pos 0 (PSRAM)"); |
| 265 | + } else { |
| 266 | + CAM_WARN_THROTTLE(warn_psram_soi_cnt, |
| 267 | + "NO-SOI - JPEG start marker missing (PSRAM)"); |
| 268 | + } |
| 269 | + ll_cam_stop(cam_obj); |
| 270 | + cam_obj->state = CAM_STATE_IDLE; |
| 271 | + continue; |
| 272 | + } |
| 273 | + } else if (cam_verify_jpeg_soi(frame_buffer_event->buf, frame_buffer_event->len) != 0) { |
| 274 | + static uint16_t warn_soi_bad_cnt = 0; |
| 275 | + CAM_WARN_THROTTLE(warn_soi_bad_cnt, |
| 276 | + "NO-SOI - JPEG start marker not at pos 0"); |
| 277 | + ll_cam_stop(cam_obj); |
| 278 | + cam_obj->state = CAM_STATE_IDLE; |
| 279 | + continue; |
| 280 | + } |
216 | 281 | }
|
| 282 | + |
217 | 283 | cnt++;
|
218 | 284 | // stop when too many DMA copies occur so the PSRAM
|
219 | 285 | // framebuffer slot doesn't overflow from runaway transfers
|
|
0 commit comments