@@ -69,6 +69,12 @@ static portMUX_TYPE g_psram_dma_lock = portMUX_INITIALIZER_UNLOCKED;
6969#define CAM_SOI_PROBE_BYTES 32
7070#endif
7171
72+ /* Number of bytes copied to SRAM for EOI validation when capturing
73+ * directly to PSRAM. Tunable to probe more of the frame tail if needed. */
74+ #ifndef CAM_EOI_PROBE_BYTES
75+ #define CAM_EOI_PROBE_BYTES 32
76+ #endif
77+
7278/*
7379 * PSRAM DMA may bypass the CPU cache. Always call esp_cache_msync() on the
7480 * SOI probe region so cached reads see the data written by DMA.
@@ -669,7 +675,37 @@ camera_fb_t *cam_take(TickType_t timeout)
669675
670676 if (cam_obj -> jpeg_mode ) {
671677 /* find the end marker for JPEG. Data after that can be discarded */
672- int offset_e = cam_verify_jpeg_eoi (dma_buffer -> buf , dma_buffer -> len );
678+ int offset_e = -1 ;
679+ if (cam_obj -> psram_mode ) {
680+ size_t probe_len = dma_buffer -> len ;
681+ if (probe_len > CAM_EOI_PROBE_BYTES ) {
682+ probe_len = CAM_EOI_PROBE_BYTES ;
683+ }
684+ if (probe_len == 0 ) {
685+ goto skip_eoi_check ;
686+ }
687+ size_t line = dcache_line_size ();
688+ if (line == 0 ) {
689+ line = 32 ; /* sane fallback */
690+ }
691+ uintptr_t addr = (uintptr_t )(dma_buffer -> buf + dma_buffer -> len - probe_len );
692+ uintptr_t start = addr & ~(line - 1 );
693+ size_t sync_len = (probe_len + (addr - start ) + line - 1 ) & ~(line - 1 );
694+ esp_cache_msync ((void * )start , sync_len ,
695+ ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE );
696+
697+ uint8_t eoi_probe [CAM_EOI_PROBE_BYTES ];
698+ memcpy (eoi_probe , dma_buffer -> buf + dma_buffer -> len - probe_len , probe_len );
699+ int off = cam_verify_jpeg_eoi (eoi_probe , probe_len );
700+ if (off >= 0 ) {
701+ offset_e = dma_buffer -> len - probe_len + off ;
702+ }
703+ } else {
704+ offset_e = cam_verify_jpeg_eoi (dma_buffer -> buf , dma_buffer -> len );
705+ }
706+
707+ skip_eoi_check :
708+
673709 if (offset_e >= 0 ) {
674710 dma_buffer -> len = offset_e + sizeof (JPEG_EOI_MARKER );
675711 return dma_buffer ;
0 commit comments