From 345b80358dccfcb6f33c513d7fa020e041def27c Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 2 Feb 2024 15:33:23 +0200 Subject: [PATCH 1/2] ports/all: Refactor frame buffer line copying code. --- src/omv/common/sensor.h | 16 ++----- src/omv/common/sensor_utils.c | 80 +++++++++++++++++++++++++++++++++++ src/omv/ports/mimxrt/sensor.c | 64 +--------------------------- src/omv/ports/stm32/sensor.c | 80 ++++++----------------------------- 4 files changed, 98 insertions(+), 142 deletions(-) diff --git a/src/omv/common/sensor.h b/src/omv/common/sensor.h index d279b720b..852755903 100644 --- a/src/omv/common/sensor.h +++ b/src/omv/common/sensor.h @@ -14,18 +14,6 @@ #include "omv_i2c.h" #include "imlib.h" -#define copy_transposed_line(dstp, srcp) \ - for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ - *dstp = *srcp++; \ - dstp += h; \ - } - -#define copy_transposed_line_rev16(dstp, srcp) \ - for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ - *dstp = __REV16(*srcp++); \ - dstp += h; \ - } - #define OV2640_SLV_ADDR (0x60) #define OV5640_SLV_ADDR (0x78) #define OV7725_SLV_ADDR (0x42) @@ -484,6 +472,10 @@ int sensor_check_framebuffer_size(); // Auto-crop frame buffer until it fits in RAM (may switch pixel format to BAYER). int sensor_auto_crop_framebuffer(); +// Copy a single line buffer to its destination. The copying process is +// DMA-accelerated, if available, and falls back to slow software if not. +int sensor_copy_line(void *dma, uint8_t *src, uint8_t *dst); + // Default snapshot function. int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags); diff --git a/src/omv/common/sensor_utils.c b/src/omv/common/sensor_utils.c index 37f918c7e..048b45528 100644 --- a/src/omv/common/sensor_utils.c +++ b/src/omv/common/sensor_utils.c @@ -30,6 +30,7 @@ #include "frogeye2020.h" #include "gc2145.h" #include "framebuffer.h" +#include "unaligned_memcpy.h" #include "omv_boardconfig.h" #include "omv_gpio.h" #include "omv_i2c.h" @@ -1249,6 +1250,85 @@ __weak int sensor_auto_crop_framebuffer() { return 0; } +#define copy_transposed_line(dstp, srcp) \ + for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ + *dstp = *srcp++; \ + dstp += h; \ + } + +#define copy_transposed_line_rev16(dstp, srcp) \ + for (int i = MAIN_FB()->u, h = MAIN_FB()->v; i; i--) { \ + *dstp = __REV16(*srcp++); \ + dstp += h; \ + } + +__weak int sensor_copy_line(void *dma, uint8_t *src, uint8_t *dst) { + uint16_t *src16 = (uint16_t *) src; + uint16_t *dst16 = (uint16_t *) dst; + #if OMA_ENABLE_DMA_MEMCPY + extern int sensor_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed); + #endif + + switch (sensor.pixformat) { + case PIXFORMAT_BAYER: + #if OMA_ENABLE_DMA_MEMCPY + sensor_dma_memcpy(dma, dst, src, sizeof(uint8_t), sensor.transpose); + #else + if (!sensor.transpose) { + unaligned_memcpy(dst, src, MAIN_FB()->u); + } else { + copy_transposed_line(dst, src); + } + #endif + break; + case PIXFORMAT_GRAYSCALE: + #if OMA_ENABLE_DMA_MEMCPY + sensor_dma_memcpy(dma, dst, src, sizeof(uint8_t), sensor.transpose); + #else + if (sensor.hw_flags.gs_bpp == 1) { + // 1BPP GRAYSCALE. + if (!sensor.transpose) { + unaligned_memcpy(dst, src, MAIN_FB()->u); + } else { + copy_transposed_line(dst, src); + } + } else { + // Extract Y channel from YUV. + if (!sensor.transpose) { + unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u); + } else { + copy_transposed_line(dst, src16); + } + } + #endif + break; + case PIXFORMAT_RGB565: + case PIXFORMAT_YUV422: + #if OMA_ENABLE_DMA_MEMCPY + sensor_dma_memcpy(dma, dst16, src16, sizeof(uint16_t), sensor.transpose); + #else + if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap) + || (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) { + if (!sensor.transpose) { + unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u); + } else { + copy_transposed_line_rev16(dst16, src16); + } + } else { + if (!sensor.transpose) { + unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t)); + } else { + copy_transposed_line(dst16, src16); + } + } + #endif + break; + default: + break; + } + return 0; +} + __weak int sensor_snapshot(sensor_t *sensor, image_t *image, uint32_t flags) { return -1; } diff --git a/src/omv/ports/mimxrt/sensor.c b/src/omv/ports/mimxrt/sensor.c index e043a774d..4711861f5 100644 --- a/src/omv/ports/mimxrt/sensor.c +++ b/src/omv/ports/mimxrt/sensor.c @@ -272,68 +272,8 @@ void sensor_line_callback(uint32_t addr) { dst += MAIN_FB()->u * bytes_per_pixel * (buffer->offset - MAIN_FB()->y); } - // Implement per line, per pixel cropping, and image transposing (for image rotation) in - // in software using the CPU to transfer the image from the line buffers to the frame buffer. - uint16_t *src16 = (uint16_t *) src; - uint16_t *dst16 = (uint16_t *) dst; - - switch (sensor.pixformat) { - case PIXFORMAT_BAYER: - #if (OMV_ENABLE_SENSOR_EDMA == 1) - edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose); - #else - if (!sensor.transpose) { - unaligned_memcpy(dst, src, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src); - } - #endif - break; - case PIXFORMAT_GRAYSCALE: - #if (OMV_ENABLE_SENSOR_EDMA == 1) - edma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose); - #else - if (sensor.hw_flags.gs_bpp == 1) { - // 1BPP GRAYSCALE. - if (!sensor.transpose) { - unaligned_memcpy(dst, src, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src); - } - } else { - // Extract Y channel from YUV. - if (!sensor.transpose) { - unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src16); - } - } - #endif - break; - case PIXFORMAT_RGB565: - case PIXFORMAT_YUV422: - #if (OMV_ENABLE_SENSOR_EDMA == 1) - edma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose); - #else - if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap) - || (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) { - if (!sensor.transpose) { - unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u); - } else { - copy_transposed_line_rev16(dst16, src16); - } - } else { - if (!sensor.transpose) { - unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t)); - } else { - copy_transposed_line(dst16, src16); - } - } - #endif - break; - default: - break; - } + // Copy line to frame buffer. + sensor_copy_line(NULL, src, dst); } if (++buffer->offset == resolution[sensor.framesize][1]) { diff --git a/src/omv/ports/stm32/sensor.c b/src/omv/ports/stm32/sensor.c index b2df2b335..fbd904adf 100644 --- a/src/omv/ports/stm32/sensor.c +++ b/src/omv/ports/stm32/sensor.c @@ -418,16 +418,13 @@ void HAL_DCMI_FrameEventCallback(DCMI_HandleTypeDef *hdcmi) { } #if defined(OMV_MDMA_CHANNEL_DCMI_0) -static void mdma_memcpy(vbuffer_t *buffer, void *dst, void *src, int bpp, bool transposed) { - // We're using two handles to give each channel the maximum amount of time possible to do the line - // transfer. In most situations only one channel will be running at a time. However, if SDRAM is - // backedup we don't have to disable the channel if it is flushing trailing data to SDRAM. - MDMA_HandleTypeDef *handle = (buffer->offset % 2) ? &DCMI_MDMA_Handle1 : &DCMI_MDMA_Handle0; +int sensor_dma_memcpy(void *dma, void *dst, void *src, int bpp, bool transposed) { + MDMA_HandleTypeDef *handle = dma; // Drop the frame if MDMA is not keeping up as the image will be corrupt. if (handle->Instance->CCR & MDMA_CCR_EN) { sensor.drop_frame = true; - return; + return 0; } // If MDMA is still running from a previous transfer HAL_MDMA_Start() will disable that transfer @@ -439,6 +436,7 @@ static void mdma_memcpy(vbuffer_t *buffer, void *dst, void *src, int bpp, bool t (uint32_t) dst, transposed ? bpp : (MAIN_FB()->u * bpp), transposed ? MAIN_FB()->u : 1); + return 0; } #endif @@ -564,68 +562,14 @@ void DCMI_DMAConvCpltUser(uint32_t addr) { dst += bytes_per_pixel * buffer->offset++; } - // Implement per line, per pixel cropping, and image transposing (for image rotation) in - // in software using the CPU to transfer the image from the line buffers to the frame buffer. - uint16_t *src16 = (uint16_t *) src; - uint16_t *dst16 = (uint16_t *) dst; - - switch (sensor.pixformat) { - case PIXFORMAT_BAYER: - #if defined(OMV_MDMA_CHANNEL_DCMI_0) - mdma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose); - #else - if (!sensor.transpose) { - unaligned_memcpy(dst, src, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src); - } - #endif - break; - case PIXFORMAT_GRAYSCALE: - #if defined(OMV_MDMA_CHANNEL_DCMI_0) - mdma_memcpy(buffer, dst, src, sizeof(uint8_t), sensor.transpose); - #else - if (sensor.hw_flags.gs_bpp == 1) { - // 1BPP GRAYSCALE. - if (!sensor.transpose) { - unaligned_memcpy(dst, src, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src); - } - } else { - // Extract Y channel from YUV. - if (!sensor.transpose) { - unaligned_2_to_1_memcpy(dst, src16, MAIN_FB()->u); - } else { - copy_transposed_line(dst, src16); - } - } - #endif - break; - case PIXFORMAT_RGB565: - case PIXFORMAT_YUV422: - #if defined(OMV_MDMA_CHANNEL_DCMI_0) - mdma_memcpy(buffer, dst16, src16, sizeof(uint16_t), sensor.transpose); - #else - if ((sensor.pixformat == PIXFORMAT_RGB565 && sensor.hw_flags.rgb_swap) - || (sensor.pixformat == PIXFORMAT_YUV422 && sensor.hw_flags.yuv_swap)) { - if (!sensor.transpose) { - unaligned_memcpy_rev16(dst16, src16, MAIN_FB()->u); - } else { - copy_transposed_line_rev16(dst16, src16); - } - } else { - if (!sensor.transpose) { - unaligned_memcpy(dst16, src16, MAIN_FB()->u * sizeof(uint16_t)); - } else { - copy_transposed_line(dst16, src16); - } - } - #endif - break; - default: - break; - } + #if defined(OMV_MDMA_CHANNEL_DCMI_0) + // We're using two handles to give each channel the maximum amount of time possible to do the line + // transfer. In most situations only one channel will be running at a time. However, if SDRAM is + // backedup we don't have to disable the channel if it is flushing trailing data to SDRAM. + sensor_copy_line((buffer->offset % 2) ? &DCMI_MDMA_Handle1 : &DCMI_MDMA_Handle0, src, dst); + #else + sensor_copy_line(NULL, src, dst); + #endif } #if defined(OMV_MDMA_CHANNEL_DCMI_0) From 725dcdd5cf6446812b82e97cc6e6b173c0e751c7 Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Fri, 2 Feb 2024 15:34:47 +0200 Subject: [PATCH 2/2] boards/all: Enable OMA_ENABLE_DMA_MEMCPY for boards that support it. --- src/omv/boards/ARDUINO_GIGA/omv_boardconfig.h | 3 +++ src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h | 3 +++ src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h | 3 +++ src/omv/boards/OPENMV4/omv_boardconfig.h | 3 +++ src/omv/boards/OPENMV4P/omv_boardconfig.h | 3 +++ src/omv/boards/OPENMV4_PRO/omv_boardconfig.h | 3 +++ src/omv/boards/OPENMVPT/omv_boardconfig.h | 3 +++ 7 files changed, 21 insertions(+) diff --git a/src/omv/boards/ARDUINO_GIGA/omv_boardconfig.h b/src/omv/boards/ARDUINO_GIGA/omv_boardconfig.h index 809f27c24..630c7d75e 100644 --- a/src/omv/boards/ARDUINO_GIGA/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_GIGA/omv_boardconfig.h @@ -31,6 +31,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h b/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h index dcb621df4..14ec2ce6b 100644 --- a/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_NICLA_VISION/omv_boardconfig.h @@ -35,6 +35,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h index e6d17f5bf..f56b2096f 100644 --- a/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h +++ b/src/omv/boards/ARDUINO_PORTENTA_H7/omv_boardconfig.h @@ -31,6 +31,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/OPENMV4/omv_boardconfig.h b/src/omv/boards/OPENMV4/omv_boardconfig.h index 2506ca07c..1d3422756 100644 --- a/src/omv/boards/OPENMV4/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4/omv_boardconfig.h @@ -45,6 +45,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/OPENMV4P/omv_boardconfig.h b/src/omv/boards/OPENMV4P/omv_boardconfig.h index eaefc168d..e1b6773b6 100644 --- a/src/omv/boards/OPENMV4P/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4P/omv_boardconfig.h @@ -45,6 +45,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/OPENMV4_PRO/omv_boardconfig.h b/src/omv/boards/OPENMV4_PRO/omv_boardconfig.h index 2123832d0..3a19739ae 100644 --- a/src/omv/boards/OPENMV4_PRO/omv_boardconfig.h +++ b/src/omv/boards/OPENMV4_PRO/omv_boardconfig.h @@ -30,6 +30,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1) diff --git a/src/omv/boards/OPENMVPT/omv_boardconfig.h b/src/omv/boards/OPENMVPT/omv_boardconfig.h index 12bd098b0..8287a8dae 100644 --- a/src/omv/boards/OPENMVPT/omv_boardconfig.h +++ b/src/omv/boards/OPENMVPT/omv_boardconfig.h @@ -45,6 +45,9 @@ // Enable hardware JPEG #define OMV_HARDWARE_JPEG (1) +// Enable fast line transfer with DMA. +#define OMA_ENABLE_DMA_MEMCPY (1) + // MDMA configuration #define OMV_MDMA_CHANNEL_DCMI_0 (0) #define OMV_MDMA_CHANNEL_DCMI_1 (1)