diff --git a/ports/rp2/omv_csi.c b/ports/rp2/omv_csi.c index 31166f068..c61d582cf 100644 --- a/ports/rp2/omv_csi.c +++ b/ports/rp2/omv_csi.c @@ -51,8 +51,10 @@ static void dma_irq_handler() { // Clear the interrupt request. dma_irqn_acknowledge_channel(OMV_CSI_DMA, OMV_CSI_DMA_CHANNEL); - framebuffer_get_tail(fb, FB_NO_FLAGS); - vbuffer_t *buffer = framebuffer_get_tail(fb, FB_PEEK); + // Release the current buffer and acquire a new one. + framebuffer_release(fb, FB_FLAG_FREE | FB_FLAG_CHECK_LAST); + vbuffer_t *buffer = framebuffer_acquire(fb, FB_FLAG_FREE | FB_FLAG_PEEK); + if (buffer != NULL) { // Set next buffer and retrigger the DMA channel. dma_channel_set_write_addr(OMV_CSI_DMA_CHANNEL, buffer->data, true); @@ -66,6 +68,10 @@ static void dma_irq_handler() { } } +static bool rp2_csi_is_active(omv_csi_t *csi) { + return dma_channel_is_busy(OMV_CSI_DMA_CHANNEL); +} + static int rp2_csi_config(omv_csi_t *csi, omv_csi_config_t config) { if (config == OMV_CSI_CONFIG_INIT) { // PIXCLK @@ -153,37 +159,14 @@ int omv_csi_set_windowing(omv_csi_t *csi, int x, int y, int w, int h) { } static int rp2_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) { + vbuffer_t *buffer = NULL; framebuffer_t *fb = csi->fb; - // Compress the framebuffer for the IDE preview. - if (flags & OMV_CSI_CAPTURE_FLAGS_UPDATE) { - image_t tmp; - framebuffer_init_image(fb, &tmp); - framebuffer_update_jpeg_buffer(&tmp); - } - - if (omv_csi_check_framebuffer_size(csi) != 0) { - return OMV_CSI_ERROR_FRAMEBUFFER_OVERFLOW; - } - - // Free the current FB head. - framebuffer_free_current_buffer(fb); - - // Set framebuffer pixel format. - if (csi->pixformat == PIXFORMAT_INVALID) { - return OMV_CSI_ERROR_INVALID_PIXFORMAT; - } - fb->pixfmt = csi->pixformat; - - vbuffer_t *buffer = framebuffer_get_head(fb, FB_NO_FLAGS); - // If there's no ready buffer in the fifo, and the DMA is Not currently // transferring a new buffer, reconfigure and restart the DMA transfer. - if (buffer == NULL && !dma_channel_is_busy(OMV_CSI_DMA_CHANNEL)) { - framebuffer_setup_buffers(fb); - - buffer = framebuffer_get_tail(fb, FB_PEEK); - if (buffer == NULL) { + if (!rp2_csi_is_active(csi) && !framebuffer_readable(fb)) { + // Acquire a buffer from the free queue. + if (!(buffer = framebuffer_acquire(fb, FB_FLAG_FREE | FB_FLAG_PEEK))) { return OMV_CSI_ERROR_FRAMEBUFFER_ERROR; } @@ -216,17 +199,30 @@ static int rp2_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) { pio_sm_put_blocking(OMV_CSI_PIO, OMV_CSI_SM, (fb->u * fb->bpp) - 1); } - // Wait for the DMA to finish the transfer. - for (mp_uint_t ticks = mp_hal_ticks_ms(); buffer == NULL;) { - buffer = framebuffer_get_head(fb, FB_NO_FLAGS); - if ((mp_hal_ticks_ms() - ticks) > 3000) { + // One shot DMA transfers must be invalidated. + framebuffer_flags_t fb_flags = FB_FLAG_USED | FB_FLAG_PEEK | FB_FLAG_INVALIDATE; + + // Wait for a frame to be ready. + for (mp_uint_t start = mp_hal_ticks_ms(); ; mp_event_handle_nowait()) { + if ((buffer = framebuffer_acquire(fb, fb_flags))) { + break; + } + + if (flags & OMV_CSI_CAPTURE_FLAGS_NBLOCK) { + return OMV_CSI_ERROR_WOULD_BLOCK; + } + + if ((mp_hal_ticks_ms() - start) > OMV_CSI_TIMEOUT_MS) { omv_csi_abort(csi, true, false); return OMV_CSI_ERROR_CAPTURE_TIMEOUT; } } + // Set the framebuffer width/height. fb->w = fb->u; fb->h = fb->v; + // Set the framebuffer pixel format. + fb->pixfmt = csi->pixformat; // Set the user image. framebuffer_init_image(fb, image); diff --git a/ports/rp2/omv_portconfig.cmake b/ports/rp2/omv_portconfig.cmake index ec79981e1..979f89b37 100644 --- a/ports/rp2/omv_portconfig.cmake +++ b/ports/rp2/omv_portconfig.cmake @@ -122,6 +122,7 @@ target_sources(${MICROPY_TARGET} PRIVATE ${TOP_DIR}/common/umm_malloc.c ${TOP_DIR}/common/dma_alloc.c ${TOP_DIR}/common/unaligned_memcpy.c + ${TOP_DIR}/common/queue.c ${TOP_DIR}/drivers/sensors/ov2640.c ${TOP_DIR}/drivers/sensors/ov5640.c diff --git a/ports/rp2/omv_portconfig.mk b/ports/rp2/omv_portconfig.mk index 7e68714b5..51e71d9a3 100644 --- a/ports/rp2/omv_portconfig.mk +++ b/ports/rp2/omv_portconfig.mk @@ -28,7 +28,7 @@ export CXX= # Note this overrides USER_C_MODULES. MPY_MKARGS += BOARD=$(TARGET) BUILD=$(BUILD)/rp2 USER_C_MODULES="" \ - OMV_CMAKE=$(TOP_DIR)/$(OMV_DIR)/ports/$(PORT)/omv_portconfig.cmake + OMV_CMAKE=$(TOP_DIR)/ports/$(PORT)/omv_portconfig.cmake ################################################### all: $(OPENMV)