@@ -92,6 +92,24 @@ static inline size_t dcache_line_size(void)
9292#endif
9393}
9494
95+ /*
96+ * Invalidate CPU data cache lines that cover a region in PSRAM which
97+ * has just been written by DMA. This guarantees subsequent CPU reads
98+ * fetch the fresh data from PSRAM rather than stale cache contents.
99+ * Both address and length are aligned to the data cache line size.
100+ */
101+ static inline void cam_drop_psram_cache (void * addr , size_t len )
102+ {
103+ size_t line = dcache_line_size ();
104+ if (line == 0 ) {
105+ line = 32 ; /* sane fallback */
106+ }
107+ uintptr_t start = (uintptr_t )addr & ~(line - 1 );
108+ size_t sync_len = (len + ((uintptr_t )addr - start ) + line - 1 ) & ~(line - 1 );
109+ esp_cache_msync ((void * )start , sync_len ,
110+ ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE );
111+ }
112+
95113/* Throttle repeated warnings printed from tight loops / ISRs.
96114 *
97115 * counter – static DRAM/IRAM uint16_t you pass in
@@ -256,15 +274,7 @@ static void cam_task(void *arg)
256274 probe_len = CAM_SOI_PROBE_BYTES ;
257275 }
258276 /* Invalidate cache lines for the DMA buffer before probing */
259- size_t line = dcache_line_size ();
260- if (line == 0 ) {
261- line = 32 ; /* sane fallback */
262- }
263- uintptr_t addr = (uintptr_t )frame_buffer_event -> buf ;
264- uintptr_t start = addr & ~(line - 1 );
265- size_t sync_len = (probe_len + (addr - start ) + line - 1 ) & ~(line - 1 );
266- esp_cache_msync ((void * )start , sync_len ,
267- ESP_CACHE_MSYNC_FLAG_DIR_M2C | ESP_CACHE_MSYNC_FLAG_INVALIDATE );
277+ cam_drop_psram_cache (frame_buffer_event -> buf , probe_len );
268278
269279 uint8_t soi_probe [CAM_SOI_PROBE_BYTES ];
270280 memcpy (soi_probe , frame_buffer_event -> buf , probe_len );
@@ -684,15 +694,7 @@ camera_fb_t *cam_take(TickType_t timeout)
684694 if (probe_len == 0 ) {
685695 goto skip_eoi_check ;
686696 }
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 );
697+ cam_drop_psram_cache (dma_buffer -> buf + dma_buffer -> len - probe_len , probe_len );
696698
697699 uint8_t eoi_probe [CAM_EOI_PROBE_BYTES ];
698700 memcpy (eoi_probe , dma_buffer -> buf + dma_buffer -> len - probe_len , probe_len );
@@ -704,13 +706,17 @@ camera_fb_t *cam_take(TickType_t timeout)
704706 offset_e = cam_verify_jpeg_eoi (dma_buffer -> buf , dma_buffer -> len );
705707 }
706708
707- skip_eoi_check :
708-
709709 if (offset_e >= 0 ) {
710710 dma_buffer -> len = offset_e + sizeof (JPEG_EOI_MARKER );
711+ if (cam_obj -> psram_mode ) {
712+ /* DMA may bypass cache, ensure full frame is visible */
713+ cam_drop_psram_cache (dma_buffer -> buf , dma_buffer -> len );
714+ }
711715 return dma_buffer ;
712716 }
713717
718+ skip_eoi_check :
719+
714720 CAM_WARN_THROTTLE (warn_eoi_miss_cnt ,
715721 "NO-EOI - JPEG end marker missing" );
716722 cam_give (dma_buffer );
@@ -721,6 +727,11 @@ camera_fb_t *cam_take(TickType_t timeout)
721727 dma_buffer -> len = ll_cam_memcpy (cam_obj , dma_buffer -> buf , dma_buffer -> buf , dma_buffer -> len );
722728 }
723729
730+ if (cam_obj -> psram_mode ) {
731+ /* DMA may bypass cache, ensure full frame is visible to the app */
732+ cam_drop_psram_cache (dma_buffer -> buf , dma_buffer -> len );
733+ }
734+
724735 return dma_buffer ;
725736 }
726737}
0 commit comments