From ff3e4e018304eb4da70a83c83e339b34955aba8b Mon Sep 17 00:00:00 2001 From: iabdalkader Date: Sun, 6 Jul 2025 14:26:03 +0200 Subject: [PATCH] ports/stm32: Refactor CSI ISP code. Signed-off-by: iabdalkader --- ports/stm32/omv_csi.c | 122 ++----------------------------- ports/stm32/stm_isp.c | 164 ++++++++++++++++++++++++++++++++++++++++++ ports/stm32/stm_isp.h | 45 ++++++++++++ 3 files changed, 216 insertions(+), 115 deletions(-) create mode 100644 ports/stm32/stm_isp.c create mode 100644 ports/stm32/stm_isp.h diff --git a/ports/stm32/omv_csi.c b/ports/stm32/omv_csi.c index 69f843c9c..907fb8c9e 100644 --- a/ports/stm32/omv_csi.c +++ b/ports/stm32/omv_csi.c @@ -42,6 +42,7 @@ #include "omv_i2c.h" #include "omv_csi.h" #include "stm_dma.h" +#include "stm_isp.h" #if defined(DMA2) #define USE_DMA (1) @@ -240,74 +241,9 @@ static int stm_csi_config(omv_csi_t *csi, omv_csi_config_t config) { } // Configure the pixel processing pipeline. - DCMIPP_PipeConfTypeDef pcfg = { .FrameRate = DCMIPP_FRAME_RATE_ALL }; - if (csi->pixformat == PIXFORMAT_RGB565) { - pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_RGB565_1; - } else if (csi->pixformat == PIXFORMAT_GRAYSCALE || csi->pixformat == PIXFORMAT_BAYER) { - pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_MONO_Y8_G8_1; - } else if (csi->pixformat == PIXFORMAT_YUV422) { - pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_YUV422_1; - } else { - return OMV_CSI_ERROR_PIXFORMAT_UNSUPPORTED; - } - if (HAL_DCMIPP_PIPE_SetConfig(&csi->dcmi, DCMIPP_PIPE, &pcfg) != HAL_OK) { + if (stm_isp_config_pipeline(&csi->dcmi, DCMIPP_PIPE, csi->pixformat, csi->raw_output)) { return OMV_CSI_ERROR_CSI_INIT_FAILED; } - - // Configure debayer. - if (csi->raw_output && csi->pixformat != PIXFORMAT_BAYER) { - DCMIPP_RawBayer2RGBConfTypeDef rawcfg = { - .RawBayerType = DCMIPP_RAWBAYER_BGGR, - .VLineStrength = DCMIPP_RAWBAYER_ALGO_NONE, - .HLineStrength = DCMIPP_RAWBAYER_ALGO_NONE, - .PeakStrength = DCMIPP_RAWBAYER_ALGO_NONE, - .EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE, - }; - - if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(&csi->dcmi, DCMIPP_PIPE, &rawcfg) != HAL_OK || - HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(&csi->dcmi, DCMIPP_PIPE) != HAL_OK) { - return OMV_CSI_ERROR_CSI_INIT_FAILED; - } - - DCMIPP_ExposureConfTypeDef expcfg = { - .ShiftRed = 0, - .MultiplierRed = 128, - .ShiftGreen = 0, - .MultiplierGreen = 128, - .ShiftBlue = 0, - .MultiplierBlue = 128, - }; - - if (HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmi, DCMIPP_PIPE, &expcfg) != HAL_OK || - HAL_DCMIPP_PIPE_EnableISPExposure(&csi->dcmi, DCMIPP_PIPE) != HAL_OK) { - return OMV_CSI_ERROR_CSI_INIT_FAILED; - } - - const uint32_t statsrc[] = { - DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_R, - DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_G, - DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_B - }; - DCMIPP_StatisticExtractionConfTypeDef statcfg[3]; - - for (size_t i = 0; i < 3; i++) { - statcfg[i].Source = statsrc[i]; - statcfg[i].Mode = DCMIPP_STAT_EXT_MODE_AVERAGE; - statcfg[i].Bins = DCMIPP_STAT_EXT_AVER_MODE_ALL_PIXELS; //NOEXT16; - } - - for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) { - if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(&csi->dcmi, - DCMIPP_PIPE, i, - &statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) { - return OMV_CSI_ERROR_CSI_INIT_FAILED; - } - - if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(&csi->dcmi, DCMIPP_PIPE, i) != HAL_OK) { - return OMV_CSI_ERROR_CSI_INIT_FAILED; - } - } - } #endif } return 0; @@ -603,54 +539,6 @@ void DCMI_DMAConvCpltUser(uint32_t addr) { } #endif -#if USE_DCMIPP -void omv_csi_update_awb(omv_csi_t *csi, uint32_t n_pixels) { - uint32_t avg[3]; - uint32_t shift[3]; - uint32_t multi[3]; - - for (int i = 0; i < 3; i++) { - // DCMIPP_STATEXT_MODULE1 - HAL_DCMIPP_PIPE_GetISPAccumulatedStatisticsCounter(&csi->dcmi, DCMIPP_PIPE, i + 1, &avg[i]); - } - - // Averages are collected from bayer components (4R 2G 4B). - avg[0] = OMV_MAX((avg[0] * 256 * 4) / n_pixels, 1); - avg[1] = OMV_MAX((avg[1] * 256 * 2) / n_pixels, 1); - avg[2] = OMV_MAX((avg[2] * 256 * 4) / n_pixels, 1); - - // Compute global luminance - float luminance = avg[0] * 0.299 + avg[1] * 0.587 + avg[2] * 0.114; - //printf("Luminance: %f AVG_R: %lu, AVG_G: %lu, AVG_B: %lu\n", (double) luminance, avg[0], avg[1], avg[2]); - - if (csi->ioctl) { - omv_csi_ioctl(csi, OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance)); - } - - // Calculate average and exposure factors for each channel (R, G, B) - for (int i = 0; i < 3; i++) { - shift[i] = 0; - multi[i] = roundf((luminance * 128.0f / avg[i])); - while (multi[i] >= 255.0f && shift[i] < 7) { - multi[i] /= 2; - shift[i]++; - } - //printf("Channel %d: Expf: %lu Shift: %lu, Multi: %lu\n", i, expf, shift[i], multi[i]); - } - - // Configure RGB exposure settings. - DCMIPP_ExposureConfTypeDef expcfg = { - .ShiftRed = shift[0], - .MultiplierRed = multi[0], - .ShiftGreen = shift[1], - .MultiplierGreen = multi[1], - .ShiftBlue = shift[2], - .MultiplierBlue = multi[2], - }; - HAL_DCMIPP_PIPE_SetISPExposureConfig(&csi->dcmi, DCMIPP_PIPE, &expcfg); -} -#endif - static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) { uint32_t length = 0; framebuffer_t *fb = csi->fb; @@ -915,7 +803,11 @@ static int stm_csi_snapshot(omv_csi_t *csi, image_t *image, uint32_t flags) { framebuffer_init_image(fb, image); #if USE_DCMIPP if (csi->raw_output) { - omv_csi_update_awb(csi, w * h); + float luminance = stm_isp_update_awb(&csi->dcmi, DCMIPP_PIPE, w * h); + if (csi->ioctl) { + omv_csi_ioctl(csi, OMV_CSI_IOCTL_UPDATE_AGC_AEC, fast_floorf(luminance)); + } + } #endif return 0; diff --git a/ports/stm32/stm_isp.c b/ports/stm32/stm_isp.c new file mode 100644 index 000000000..60477f6ed --- /dev/null +++ b/ports/stm32/stm_isp.c @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2023-2024 OpenMV, LLC. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Any redistribution, use, or modification in source or binary form + * is done solely for personal benefit and not for any commercial + * purpose or for monetary gain. For commercial licensing options, + * please contact openmv@openmv.io + * + * THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT + * OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * STM32 DCMIPP ISP driver. + */ + +#include +#include "imlib.h" +#include "stm_isp.h" +#include "omv_boardconfig.h" + +#ifdef DCMIPP +float stm_isp_update_awb(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, uint32_t n_pixels) { + uint32_t avg[3]; + uint32_t shift[3]; + uint32_t multi[3]; + + for (int i = 0; i < 3; i++) { + // DCMIPP_STATEXT_MODULE1 + HAL_DCMIPP_PIPE_GetISPAccumulatedStatisticsCounter(dcmipp, pipe, i + 1, &avg[i]); + } + + // Averages are collected from bayer components (4R 2G 4B). + avg[0] = OMV_MAX((avg[0] * 256 * 4) / n_pixels, 1); + avg[1] = OMV_MAX((avg[1] * 256 * 2) / n_pixels, 1); + avg[2] = OMV_MAX((avg[2] * 256 * 4) / n_pixels, 1); + + // Compute global luminance + float luminance = avg[0] * 0.299 + avg[1] * 0.587 + avg[2] * 0.114; + + // Calculate average and exposure factors for each channel (R, G, B) + for (int i = 0; i < 3; i++) { + shift[i] = 0; + multi[i] = roundf((luminance * 128.0f / avg[i])); + while (multi[i] >= 255.0f && shift[i] < 7) { + multi[i] /= 2; + shift[i]++; + } + } + + // Configure RGB exposure settings. + DCMIPP_ExposureConfTypeDef expcfg = { + .ShiftRed = shift[0], + .MultiplierRed = multi[0], + .ShiftGreen = shift[1], + .MultiplierGreen = multi[1], + .ShiftBlue = shift[2], + .MultiplierBlue = multi[2], + }; + + HAL_DCMIPP_PIPE_SetISPExposureConfig(dcmipp, pipe, &expcfg); + + return luminance; +} + +int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, + pixformat_t pixformat, bool raw_output) { + // Configure the pixel processing pipeline. + DCMIPP_PipeConfTypeDef pcfg = { + .FrameRate = DCMIPP_FRAME_RATE_ALL + }; + + if (pixformat == PIXFORMAT_RGB565) { + pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_RGB565_1; + } else if (pixformat == PIXFORMAT_GRAYSCALE || pixformat == PIXFORMAT_BAYER) { + pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_MONO_Y8_G8_1; + } else if (pixformat == PIXFORMAT_YUV422) { + pcfg.PixelPackerFormat = DCMIPP_PIXEL_PACKER_FORMAT_YUV422_1; + } else { + return -1; + } + + if (HAL_DCMIPP_PIPE_SetConfig(dcmipp, pipe, &pcfg) != HAL_OK) { + return -1; + } + + // Early exit if no debayer is needed. + if (!raw_output || pixformat == PIXFORMAT_BAYER) { + return 0; + } + + // Configure ISP debayer. + DCMIPP_RawBayer2RGBConfTypeDef rawcfg = { + .RawBayerType = DCMIPP_RAWBAYER_BGGR, + .VLineStrength = DCMIPP_RAWBAYER_ALGO_NONE, + .HLineStrength = DCMIPP_RAWBAYER_ALGO_NONE, + .PeakStrength = DCMIPP_RAWBAYER_ALGO_NONE, + .EdgeStrength = DCMIPP_RAWBAYER_ALGO_NONE, + }; + + if (HAL_DCMIPP_PIPE_SetISPRawBayer2RGBConfig(dcmipp, pipe, &rawcfg) != HAL_OK || + HAL_DCMIPP_PIPE_EnableISPRawBayer2RGB(dcmipp, pipe) != HAL_OK) { + return -1; + } + + DCMIPP_ExposureConfTypeDef expcfg = { + .ShiftRed = 0, + .MultiplierRed = 128, + .ShiftGreen = 0, + .MultiplierGreen = 128, + .ShiftBlue = 0, + .MultiplierBlue = 128, + }; + + if (HAL_DCMIPP_PIPE_SetISPExposureConfig(dcmipp, pipe, &expcfg) != HAL_OK || + HAL_DCMIPP_PIPE_EnableISPExposure(dcmipp, pipe) != HAL_OK) { + return -1; + } + + const uint32_t statsrc[] = { + DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_R, + DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_G, + DCMIPP_STAT_EXT_SOURCE_PRE_BLKLVL_B + }; + DCMIPP_StatisticExtractionConfTypeDef statcfg[3]; + + for (size_t i = 0; i < 3; i++) { + statcfg[i].Source = statsrc[i]; + statcfg[i].Mode = DCMIPP_STAT_EXT_MODE_AVERAGE; + statcfg[i].Bins = DCMIPP_STAT_EXT_AVER_MODE_ALL_PIXELS; //NOEXT16; + } + + for (size_t i = DCMIPP_STATEXT_MODULE1; i <= DCMIPP_STATEXT_MODULE3; i++) { + if (HAL_DCMIPP_PIPE_SetISPStatisticExtractionConfig(dcmipp, + pipe, i, + &statcfg[i - DCMIPP_STATEXT_MODULE1]) != HAL_OK) { + return -1; + } + + if (HAL_DCMIPP_PIPE_EnableISPStatisticExtraction(dcmipp, pipe, i) != HAL_OK) { + return -1; + } + } + + return 0; +} +#endif // DCMIPP diff --git a/ports/stm32/stm_isp.h b/ports/stm32/stm_isp.h new file mode 100644 index 000000000..549edb6cf --- /dev/null +++ b/ports/stm32/stm_isp.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2023-2024 OpenMV, LLC. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * 3. Any redistribution, use, or modification in source or binary form + * is done solely for personal benefit and not for any commercial + * purpose or for monetary gain. For commercial licensing options, + * please contact openmv@openmv.io + * + * THIS SOFTWARE IS PROVIDED BY THE LICENSOR AND COPYRIGHT OWNER "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE LICENSOR OR COPYRIGHT + * OWNER BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * STM32 DCMIPP ISP driver. + */ +#ifndef __STM_ISP_H__ +#define __STM_ISP_H__ +#include +#include +#include STM32_HAL_H + +#ifdef DCMIPP +int stm_isp_config_pipeline(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, + pixformat_t pixformat, bool raw_output); +float stm_isp_update_awb(DCMIPP_HandleTypeDef *dcmipp, uint32_t pipe, uint32_t n_pixels); +#endif + +#endif // __STM_ISP_H__