Skip to content

Commit b633f87

Browse files
committed
cam_hal: drop caches for psram_mode frames before hand-off to application
Invalidate data-cache lines for the image captured via dma (in psram_mode) before the buffer is handed off to the application. This ensures the the CPU will read the correct data from the PSRAM instead of cached segments from the previous image stored in this buffer. Other work: - The cache invalidation was refactored into `cam_drop_psram_cache()` Performance consideration: On an ESP32-S3 @ 240 MHz with 32-byte cache lines: |------------------------------------------------| | Image size | Lines flushed | Cycles | Time | |------------|---------------|--------|----------| | 100 KiB | 3 200 | 16 000 | 66.7 µs | | 300 KiB | 9 600 | 48 000 | 200 µs | |________________________________________________|
1 parent cddfb94 commit b633f87

File tree

1 file changed

+31
-20
lines changed

1 file changed

+31
-20
lines changed

driver/cam_hal.c

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)