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