From 0066cff67425564368df332f76babecc768bc5dd Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 20:37:32 +0200 Subject: [PATCH 01/11] dts: bindings: stm32-dcmi: use endpoint based properties Update the bindings of the stm32-dcmi driver rely on properties described within the endpoints and already detailed within the video-interfaces.yaml. With that, several properties located at the node root are now moved into the port / endpoint: sensor -> endpoint: remote-endpoint-label vsync-active -> endpoint: vsync-active hsync-active -> endpoint: hsync-active pixelclk-active -> endpoint: pclk-sample bus-width -> endpoint: bus-width Signed-off-by: Alain Volmat --- dts/bindings/video/st,stm32-dcmi.yaml | 74 ++++----------------------- 1 file changed, 9 insertions(+), 65 deletions(-) diff --git a/dts/bindings/video/st,stm32-dcmi.yaml b/dts/bindings/video/st,stm32-dcmi.yaml index 567b8d0efa8c..89940a3609ba 100644 --- a/dts/bindings/video/st,stm32-dcmi.yaml +++ b/dts/bindings/video/st,stm32-dcmi.yaml @@ -11,23 +11,21 @@ description: | &dcmi { status = "okay"; - sensor = <&ov2640>; pinctrl-0 = <&dcmi_hsync_pa4 &dcmi_pixclk_pa6 &dcmi_vsync_pb7 &dcmi_d0_pc6 &dcmi_d1_pc7 &dcmi_d2_pe0 &dcmi_d3_pe1 &dcmi_d4_pe4 &dcmi_d5_pd3 &dcmi_d6_pe5 &dcmi_d7_pe6>; pinctrl-names = "default"; - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <1>; - capture-rate = <1>; dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; port { dcmi_ep_in: endpoint { - remote-endpoint = <&ov2640_ep_out>; + remote-endpoint-label = "ov2640_ep_out"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; }; }; }; @@ -40,64 +38,6 @@ properties: interrupts: required: true - sensor: - required: true - type: phandle - description: phandle of connected sensor device - - bus-width: - type: int - required: true - enum: - - 8 - - 10 - - 12 - - 14 - default: 8 - description: | - Number of data lines actively used, valid for the parallel busses. - - hsync-active: - type: int - required: true - enum: - - 0 - - 1 - description: | - Polarity of horizontal synchronization (DCMI_HSYNC_Polarity). - 0 Horizontal synchronization active Low. - 1 Horizontal synchronization active High. - - For example, if DCMI_HSYNC_Polarity is programmed active high: - When HSYNC is low, the data is valid. - When HSYNC is high, the data is not valid (horizontal blanking). - - vsync-active: - type: int - required: true - enum: - - 0 - - 1 - description: | - Polarity of vertical synchronization (DCMI_VSYNC_Polarity). - 0 Vertical synchronization active Low. - 1 Vertical synchronization active High. - - For example, if DCMI_VSYNC_Polarity is programmed active high: - When VSYNC is low, the data is valid. - When VSYNC is high, the data is not valid (vertical blanking). - - pixelclk-active: - type: int - required: true - enum: - - 0 - - 1 - description: | - Polarity of pixel clock (DCMI_PIXCK_Polarity). - 0 Pixel clock active on Falling edge. - 1 Pixel clock active on Rising edge. - capture-rate: type: int enum: @@ -122,3 +62,7 @@ properties: dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; + +child-binding: + child-binding: + include: video-interfaces.yaml From 110c454c6bd0775b2f9247ea67bbf585a2ec157e Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 20:42:24 +0200 Subject: [PATCH 02/11] video: stm32: dcmi: perform config based on endpoint properties Perform sensor interface properties parsing based on values retrieved via the endpoint rather than the root of the node. Use DT_PROP_OR to ensure proper configuration of optional settings. Signed-off-by: Alain Volmat --- drivers/video/video_stm32_dcmi.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index 53afb33c0b51..e145b0ef5b18 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -417,16 +417,22 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = { .Instance = (DCMI_TypeDef *) DT_INST_REG_ADDR(0), .Init = { .SynchroMode = DCMI_SYNCHRO_HARDWARE, - .PCKPolarity = (DT_INST_PROP(0, pixelclk_active) ? - DCMI_PCKPOLARITY_RISING : DCMI_PCKPOLARITY_FALLING), - .HSPolarity = (DT_INST_PROP(0, hsync_active) ? - DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW), - .VSPolarity = (DT_INST_PROP(0, vsync_active) ? - DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW), + .PCKPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), + pclk_sample, 0) ? + DCMI_PCKPOLARITY_RISING : + DCMI_PCKPOLARITY_FALLING, + .HSPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), + hsync_active, 0) ? + DCMI_HSPOLARITY_HIGH : DCMI_HSPOLARITY_LOW, + .VSPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), + vsync_active, 0) ? + DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW, .CaptureRate = STM32_DCMI_GET_CAPTURE_RATE( - DT_INST_PROP(0, capture_rate)), + DT_PROP_OR(DT_DRV_INST(inst), capture_rate, + 1)), .ExtendedDataMode = STM32_DCMI_GET_BUS_WIDTH( - DT_INST_PROP(0, bus_width)), + DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), + bus_width, 8)), .JPEGMode = DCMI_JPEG_DISABLE, .ByteSelectMode = DCMI_BSM_ALL, .ByteSelectStart = DCMI_OEBS_ODD, @@ -436,7 +442,7 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = { }, }; -#define SOURCE_DEV(n) DEVICE_DT_GET(DT_INST_PHANDLE(n, sensor)) +#define SOURCE_DEV(n) DEVICE_DT_GET(DT_NODE_REMOTE_DEVICE(DT_INST_ENDPOINT_BY_ID(n, 0, 0))) static const struct video_stm32_dcmi_config video_stm32_dcmi_config_0 = { .pclken = { From afe34335fe750791367147cebe38be0a4414b233 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 20:50:19 +0200 Subject: [PATCH 03/11] shields: weact_ov2640_cam_module: use endpoint based properties Update overlay following usage of video-interfaces based endpoint properties by the dcmi driver. Signed-off-by: Alain Volmat --- .../weact_ov2640_cam_module.overlay | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/boards/shields/weact_ov2640_cam_module/weact_ov2640_cam_module.overlay b/boards/shields/weact_ov2640_cam_module/weact_ov2640_cam_module.overlay index bc8c6ebddb28..5b0eb2abdbb4 100644 --- a/boards/shields/weact_ov2640_cam_module/weact_ov2640_cam_module.overlay +++ b/boards/shields/weact_ov2640_cam_module/weact_ov2640_cam_module.overlay @@ -21,7 +21,7 @@ port { ov2640_ep_out: endpoint { - remote-endpoint = <&zephyr_camera_dvp_in>; + remote-endpoint-label = "zephyr_camera_dvp_in"; }; }; }; @@ -29,16 +29,14 @@ &zephyr_camera_dvp { status = "okay"; - sensor = <&ov2640>; - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <1>; - capture-rate = <1>; port { zephyr_camera_dvp_in: endpoint { - remote-endpoint = <&ov2640_ep_out>; + remote-endpoint-label = "ov2640_ep_out"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; }; }; }; From 29d8cbee41dd75801e44c3f29e1639258f42710f Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 20:52:10 +0200 Subject: [PATCH 04/11] shields: st_b_cams_omv_mb1683: use endpoint based properties Update overlay following usage of video-interfaces based endpoint properties by the dcmi driver. Signed-off-by: Alain Volmat --- .../st_b_cams_omv_mb1683/st_b_cams_omv_mb1683.overlay | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/boards/shields/st_b_cams_omv_mb1683/st_b_cams_omv_mb1683.overlay b/boards/shields/st_b_cams_omv_mb1683/st_b_cams_omv_mb1683.overlay index 0ffb5669dadf..06b4ac0f9f7e 100644 --- a/boards/shields/st_b_cams_omv_mb1683/st_b_cams_omv_mb1683.overlay +++ b/boards/shields/st_b_cams_omv_mb1683/st_b_cams_omv_mb1683.overlay @@ -33,17 +33,14 @@ &st_cam_dvp { status = "okay"; - sensor = <&ov5640>; - - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <1>; - capture-rate = <1>; port { dcmi_ep_in: endpoint { remote-endpoint-label = "ov5640_ep_out"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <1>; }; }; }; From eb33bf3e71044363a473db02e491e6e9ab76da9c Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 20:52:59 +0200 Subject: [PATCH 05/11] boards: arduino_nicla_vision: use endpoint based properties Update overlay following usage of video-interfaces based endpoint properties by the dcmi driver. Signed-off-by: Alain Volmat --- .../arduino_nicla_vision_stm32h747xx_m7.dts | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts b/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts index 0028128f8e23..df2ece15f0ef 100644 --- a/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts +++ b/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts @@ -225,7 +225,7 @@ zephyr_udc0: &usbotg_hs { port { gc2145_ep_out: endpoint { - remote-endpoint = <&dcmi_ep_in>; + remote-endpoint-label = "dcmi_ep_in"; }; }; @@ -240,19 +240,17 @@ zephyr_udc0: &usbotg_hs { pinctrl-names = "default"; status = "okay"; - sensor = <&gc2145>; - bus-width = <8>; - hsync-active = <0>; - vsync-active = <0>; - pixelclk-active = <0>; - capture-rate = <1>; dmas = <&dma1 0 38 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; port { dcmi_ep_in: endpoint { - remote-endpoint = <&gc2145_ep_out>; + remote-endpoint-label = "gc2145_ep_out"; + bus-width = <8>; + hsync-active = <0>; + vsync-active = <0>; + pclk-sample = <0>; }; }; }; From 66df9222201209af4e2141dd0523c3859aac91a0 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 21:19:02 +0200 Subject: [PATCH 06/11] dts: st: h7: move dma property of dcmi in stm32h7.dtsi Usage of dma is mandatory for the dcmi and this property is tightly coupled with the soc itself since the configuration of the dma depends on the source/destination, and the request line is also fixed for an ip. Instead of having to always have the dma property part of the board or shield dts/overlay, add the dma property into the dcmi node of the stm32h7.dtsi. Signed-off-by: Alain Volmat --- .../nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts | 4 ---- .../st_b_cams_omv_mb1683/boards/stm32h7b3i_dk.overlay | 4 ---- .../weact_ov2640_cam_module/boards/mini_stm32h743.overlay | 6 ------ dts/arm/st/h7/stm32h7.dtsi | 3 +++ 4 files changed, 3 insertions(+), 14 deletions(-) diff --git a/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts b/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts index df2ece15f0ef..e9f39b173aef 100644 --- a/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts +++ b/boards/arduino/nicla_vision/arduino_nicla_vision_stm32h747xx_m7.dts @@ -240,10 +240,6 @@ zephyr_udc0: &usbotg_hs { pinctrl-names = "default"; status = "okay"; - dmas = <&dma1 0 38 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | - STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | - STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; - port { dcmi_ep_in: endpoint { remote-endpoint-label = "gc2145_ep_out"; diff --git a/boards/shields/st_b_cams_omv_mb1683/boards/stm32h7b3i_dk.overlay b/boards/shields/st_b_cams_omv_mb1683/boards/stm32h7b3i_dk.overlay index c6e629d23425..19b9aaa6eaf2 100644 --- a/boards/shields/st_b_cams_omv_mb1683/boards/stm32h7b3i_dk.overlay +++ b/boards/shields/st_b_cams_omv_mb1683/boards/stm32h7b3i_dk.overlay @@ -17,10 +17,6 @@ &dcmi_d0_pc6 &dcmi_d1_pc7 &dcmi_d2_pg10 &dcmi_d3_pc9 &dcmi_d4_pc11 &dcmi_d5_pd3 &dcmi_d6_pb8 &dcmi_d7_pb9>; pinctrl-names = "default"; - - dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | - STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | - STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; }; &dma1 { diff --git a/boards/shields/weact_ov2640_cam_module/boards/mini_stm32h743.overlay b/boards/shields/weact_ov2640_cam_module/boards/mini_stm32h743.overlay index e99237276078..80e3dbc96203 100644 --- a/boards/shields/weact_ov2640_cam_module/boards/mini_stm32h743.overlay +++ b/boards/shields/weact_ov2640_cam_module/boards/mini_stm32h743.overlay @@ -44,12 +44,6 @@ }; }; -&zephyr_camera_dvp { - dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | - STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | - STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; -}; - &dma1 { status = "okay"; }; diff --git a/dts/arm/st/h7/stm32h7.dtsi b/dts/arm/st/h7/stm32h7.dtsi index 409d0bb1edf3..635f859b3225 100644 --- a/dts/arm/st/h7/stm32h7.dtsi +++ b/dts/arm/st/h7/stm32h7.dtsi @@ -1086,6 +1086,9 @@ interrupts = <78 0>; interrupt-names = "dcmi"; clocks = <&rcc STM32_CLOCK(AHB2, 0U)>; + dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | + STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | + STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; status = "disabled"; }; }; From e5191a116eb65e3660e7f05fe874c03f7511b361 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Wed, 7 May 2025 21:23:35 +0200 Subject: [PATCH 07/11] dts: bindings: video: dcmi: remove the dma in board dts example With the addition of the dma property within the soc dtsi, it is no more necessary to add it within the board dts. Signed-off-by: Alain Volmat --- dts/bindings/video/st,stm32-dcmi.yaml | 3 --- 1 file changed, 3 deletions(-) diff --git a/dts/bindings/video/st,stm32-dcmi.yaml b/dts/bindings/video/st,stm32-dcmi.yaml index 89940a3609ba..85efc892874c 100644 --- a/dts/bindings/video/st,stm32-dcmi.yaml +++ b/dts/bindings/video/st,stm32-dcmi.yaml @@ -15,9 +15,6 @@ description: | &dcmi_d0_pc6 &dcmi_d1_pc7 &dcmi_d2_pe0 &dcmi_d3_pe1 &dcmi_d4_pe4 &dcmi_d5_pd3 &dcmi_d6_pe5 &dcmi_d7_pe6>; pinctrl-names = "default"; - dmas = <&dma1 0 75 (STM32_DMA_PERIPH_TO_MEMORY | STM32_DMA_PERIPH_NO_INC | - STM32_DMA_MEM_INC | STM32_DMA_PERIPH_8BITS | STM32_DMA_MEM_32BITS | - STM32_DMA_PRIORITY_HIGH) STM32_DMA_FIFO_1_4>; port { dcmi_ep_in: endpoint { From b9a3eb3b9889003f44f391711a5e18047d83a97c Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Thu, 8 May 2025 00:51:22 +0200 Subject: [PATCH 08/11] video: stm32-dcmi: correct get/set fmt handling This commit mainly correct the get/set format handling and how DCMI format is stored within the driver. struct video_format within the data structure is used to store the format. Reworked way to handle get format to avoid calling the sensor set_fmt whenever performing the get_fmt. Slightly adjusted code to as much as possible reuse return values provided by functions. Signed-off-by: Alain Volmat --- drivers/video/video_stm32_dcmi.c | 81 +++++++++++++++----------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index e145b0ef5b18..6a95ac1645aa 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -43,10 +43,6 @@ struct video_stm32_dcmi_data { struct video_format fmt; struct k_fifo fifo_in; struct k_fifo fifo_out; - uint32_t pixel_format; - uint32_t height; - uint32_t width; - uint32_t pitch; struct video_buffer *vbuf; }; @@ -127,7 +123,7 @@ static int stm32_dma_init(const struct device *dev) /* * DMA configuration - * Due to use of QSPI HAL API in current driver, + * Due to use of DMA HAL API in current driver, * both HAL and Zephyr DMA drivers should be configured. * The required configuration for Zephyr DMA driver should only provide * the minimum information to inform the DMA slot will be in used and @@ -179,7 +175,6 @@ static int stm32_dcmi_enable_clock(const struct device *dev) { const struct video_stm32_dcmi_config *config = dev->config; const struct device *dcmi_clock = DEVICE_DT_GET(STM32_CLOCK_CONTROL_NODE); - int err; if (!device_is_ready(dcmi_clock)) { LOG_ERR("clock control device not ready"); @@ -187,10 +182,15 @@ static int stm32_dcmi_enable_clock(const struct device *dev) } /* Turn on DCMI peripheral clock */ - err = clock_control_on(dcmi_clock, (clock_control_subsys_t *) &config->pclken); - if (err < 0) { - LOG_ERR("Failed to enable DCMI clock. Error %d", err); - return err; + return clock_control_on(dcmi_clock, (clock_control_subsys_t *)&config->pclken); +} + +static inline int video_stm32_dcmi_is_fmt_valid(uint32_t pixelformat, uint32_t pitch, + uint32_t height) +{ + if (video_bits_per_pixel(pixelformat) / BITS_PER_BYTE == 0 || + pitch * height > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX) { + return -EINVAL; } return 0; @@ -202,25 +202,24 @@ static int video_stm32_dcmi_set_fmt(const struct device *dev, { const struct video_stm32_dcmi_config *config = dev->config; struct video_stm32_dcmi_data *data = dev->data; - unsigned int bpp = video_bits_per_pixel(fmt->pixelformat) / BITS_PER_BYTE; + int ret; - if (bpp == 0 || (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL)) { + if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) { return -EINVAL; } - if ((fmt->pitch * fmt->height) > CONFIG_VIDEO_BUFFER_POOL_SZ_MAX) { - return -EINVAL; + ret = video_stm32_dcmi_is_fmt_valid(fmt->pixelformat, fmt->pitch, fmt->height); + if (ret < 0) { + return ret; } - data->pixel_format = fmt->pixelformat; - data->pitch = fmt->pitch; - data->height = fmt->height; - data->width = fmt->width; - - if (video_set_format(config->sensor_dev, ep, fmt)) { - return -EIO; + ret = video_set_format(config->sensor_dev, ep, fmt); + if (ret < 0) { + return ret; } + data->fmt = *fmt; + return 0; } @@ -230,33 +229,38 @@ static int video_stm32_dcmi_get_fmt(const struct device *dev, { struct video_stm32_dcmi_data *data = dev->data; const struct video_stm32_dcmi_config *config = dev->config; + int ret; if (fmt == NULL || (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL)) { return -EINVAL; } - if (!video_get_format(config->sensor_dev, ep, fmt)) { - /* align DCMI with sensor fmt */ - return video_stm32_dcmi_set_fmt(dev, ep, fmt); + /* Align DCMI format with the one provided by the sensor */ + ret = video_get_format(config->sensor_dev, ep, fmt); + if (ret < 0) { + return ret; + } + + ret = video_stm32_dcmi_is_fmt_valid(fmt->pixelformat, fmt->pitch, fmt->height); + if (ret < 0) { + return ret; } - fmt->pixelformat = data->pixel_format; - fmt->height = data->height; - fmt->width = data->width; - fmt->pitch = data->pitch; + data->fmt = *fmt; return 0; } static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable) { - int err; struct video_stm32_dcmi_data *data = dev->data; const struct video_stm32_dcmi_config *config = dev->config; + int err; if (!enable) { - if (video_stream_stop(config->sensor_dev)) { - return -EIO; + err = video_stream_stop(config->sensor_dev); + if (err < 0) { + return err; } err = HAL_DCMI_Stop(&data->hdcmi); @@ -285,11 +289,7 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable) return -EIO; } - if (video_stream_start(config->sensor_dev)) { - return -EIO; - } - - return 0; + return video_stream_start(config->sensor_dev); } static int video_stm32_dcmi_enqueue(const struct device *dev, @@ -297,7 +297,7 @@ static int video_stm32_dcmi_enqueue(const struct device *dev, struct video_buffer *vbuf) { struct video_stm32_dcmi_data *data = dev->data; - const uint32_t buffer_size = data->pitch * data->height; + const uint32_t buffer_size = data->fmt.pitch * data->fmt.height; if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) { return -EINVAL; @@ -339,7 +339,6 @@ static int video_stm32_dcmi_get_caps(const struct device *dev, struct video_caps *caps) { const struct video_stm32_dcmi_config *config = dev->config; - int ret = -ENODEV; if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) { return -EINVAL; @@ -349,9 +348,7 @@ static int video_stm32_dcmi_get_caps(const struct device *dev, caps->min_line_count = caps->max_line_count = LINE_COUNT_HEIGHT; /* Forward the message to the sensor device */ - ret = video_get_caps(config->sensor_dev, ep, caps); - - return ret; + return video_get_caps(config->sensor_dev, ep, caps); } static DEVICE_API(video, video_stm32_dcmi_driver_api) = { @@ -479,7 +476,7 @@ static int video_stm32_dcmi_init(const struct device *dev) err = stm32_dcmi_enable_clock(dev); if (err < 0) { LOG_ERR("Clock enabling failed."); - return -EIO; + return err; } data->dev = dev; From 7e4c5820e9176f87f409fde4da1dee927c1b7b6f Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Thu, 8 May 2025 16:42:10 +0200 Subject: [PATCH 09/11] video: stm32-dcmi: implement frame interval handling Implement the video API frame interval handling in order to control the framerate of capture. This allow to remove the capture-rate DT property as well. Signed-off-by: Alain Volmat --- drivers/video/video_stm32_dcmi.c | 137 ++++++++++++++++++++++++-- dts/bindings/video/st,stm32-dcmi.yaml | 14 --- 2 files changed, 128 insertions(+), 23 deletions(-) diff --git a/drivers/video/video_stm32_dcmi.c b/drivers/video/video_stm32_dcmi.c index 6a95ac1645aa..70de70e6d4be 100644 --- a/drivers/video/video_stm32_dcmi.c +++ b/drivers/video/video_stm32_dcmi.c @@ -41,6 +41,7 @@ struct video_stm32_dcmi_data { const struct device *dev; DCMI_HandleTypeDef hdcmi; struct video_format fmt; + int capture_rate; struct k_fifo fifo_in; struct k_fifo fifo_out; struct video_buffer *vbuf; @@ -251,6 +252,12 @@ static int video_stm32_dcmi_get_fmt(const struct device *dev, return 0; } +#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \ + ((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \ + (capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \ + (capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \ + DCMI_CR_ALL_FRAME) + static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable) { struct video_stm32_dcmi_data *data = dev->data; @@ -282,6 +289,10 @@ static int video_stm32_dcmi_set_stream(const struct device *dev, bool enable) return -ENOMEM; } + /* Set the frame control */ + data->hdcmi.Instance->CR &= ~(DCMI_CR_FCRC_0 | DCMI_CR_FCRC_1); + data->hdcmi.Instance->CR |= STM32_DCMI_GET_CAPTURE_RATE(data->capture_rate); + err = HAL_DCMI_Start_DMA(&data->hdcmi, DCMI_MODE_CONTINUOUS, (uint32_t)data->vbuf->buffer, data->vbuf->bytesused / 4); if (err != HAL_OK) { @@ -351,6 +362,119 @@ static int video_stm32_dcmi_get_caps(const struct device *dev, return video_get_caps(config->sensor_dev, ep, caps); } +static int video_stm32_dcmi_enum_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival_enum *fie) +{ + const struct video_stm32_dcmi_config *config = dev->config; + int ret; + + if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) { + return -EINVAL; + } + + ret = video_stm32_dcmi_is_fmt_valid(fie->format->pixelformat, fie->format->pitch, + fie->format->height); + if (ret < 0) { + return ret; + } + + ret = video_enum_frmival(config->sensor_dev, ep, fie); + if (ret < 0) { + return ret; + } + + /* Adapt the interval in order to report the frame drop capabilities */ + if (fie->type == VIDEO_FRMIVAL_TYPE_DISCRETE) { + struct video_frmival discrete = fie->discrete; + + fie->type = VIDEO_FRMIVAL_TYPE_STEPWISE; + fie->stepwise.max = discrete; + fie->stepwise.min.denominator = discrete.denominator; + fie->stepwise.min.numerator = discrete.numerator * 4; + fie->stepwise.step.denominator = discrete.denominator; + fie->stepwise.step.numerator = discrete.numerator * 2; + } else { + fie->stepwise.min.numerator *= 4; + fie->stepwise.step.numerator *= 2; + } + + return 0; +} + +#define STM32_DCMI_MAX_FRAME_DROP 4 +static int video_stm32_dcmi_set_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct video_stm32_dcmi_config *config = dev->config; + struct video_stm32_dcmi_data *data = dev->data; + struct video_frmival_enum fie = { + .format = &data->fmt, + }; + struct video_frmival best_sensor_frmival; + uint64_t best_diff_nsec = INT32_MAX; + uint64_t diff_nsec = 0, a, b; + int best_capture_rate = 1; + + if (ep != VIDEO_EP_OUT && ep != VIDEO_EP_ALL) { + return -EINVAL; + } + + /* + * Try to figure out a frameinterval setting allow to reach as close as + * possible to the request. At first without relying on DCMI frame control, + * then enabling it + */ + for (int capture_rate = 1; capture_rate <= STM32_DCMI_MAX_FRAME_DROP; capture_rate *= 2) { + /* + * Take into consideration the drop done by the DCMI hence multiply + * denominator by the rate introduced by the DCMI + */ + fie.discrete.numerator = frmival->numerator; + fie.discrete.denominator = frmival->denominator * capture_rate; + + a = video_frmival_nsec(&fie.discrete); + video_closest_frmival(config->sensor_dev, ep, &fie); + b = video_frmival_nsec(&fie.discrete); + diff_nsec = a > b ? a - b : b - a; + if (diff_nsec < best_diff_nsec) { + best_diff_nsec = diff_nsec; + best_sensor_frmival = fie.discrete; + best_capture_rate = capture_rate; + } + if (diff_nsec == 0) { + break; + } + } + + /* + * Give back the achieved frame interval achieved, ensuring to take into + * consideration the DCMI frame control + */ + frmival->numerator = best_sensor_frmival.numerator * best_capture_rate; + frmival->denominator = best_sensor_frmival.denominator; + + data->capture_rate = best_capture_rate; + + return video_set_frmival(config->sensor_dev, ep, &best_sensor_frmival); +} + +static int video_stm32_dcmi_get_frmival(const struct device *dev, enum video_endpoint_id ep, + struct video_frmival *frmival) +{ + const struct video_stm32_dcmi_config *config = dev->config; + struct video_stm32_dcmi_data *data = dev->data; + int ret; + + ret = video_get_frmival(config->sensor_dev, ep, frmival); + if (ret < 0) { + return ret; + } + + frmival->numerator *= data->capture_rate; + + return 0; +} + static DEVICE_API(video, video_stm32_dcmi_driver_api) = { .set_format = video_stm32_dcmi_set_fmt, .get_format = video_stm32_dcmi_get_fmt, @@ -358,6 +482,9 @@ static DEVICE_API(video, video_stm32_dcmi_driver_api) = { .enqueue = video_stm32_dcmi_enqueue, .dequeue = video_stm32_dcmi_dequeue, .get_caps = video_stm32_dcmi_get_caps, + .enum_frmival = video_stm32_dcmi_enum_frmival, + .set_frmival = video_stm32_dcmi_set_frmival, + .get_frmival = video_stm32_dcmi_get_frmival, }; static void video_stm32_dcmi_irq_config_func(const struct device *dev) @@ -389,12 +516,6 @@ static void video_stm32_dcmi_irq_config_func(const struct device *dev) PINCTRL_DT_INST_DEFINE(0); -#define STM32_DCMI_GET_CAPTURE_RATE(capture_rate) \ - ((capture_rate) == 1 ? DCMI_CR_ALL_FRAME : \ - (capture_rate) == 2 ? DCMI_CR_ALTERNATE_2_FRAME : \ - (capture_rate) == 4 ? DCMI_CR_ALTERNATE_4_FRAME : \ - DCMI_CR_ALL_FRAME) - #define STM32_DCMI_GET_BUS_WIDTH(bus_width) \ ((bus_width) == 8 ? DCMI_EXTEND_DATA_8B : \ (bus_width) == 10 ? DCMI_EXTEND_DATA_10B : \ @@ -424,9 +545,6 @@ static struct video_stm32_dcmi_data video_stm32_dcmi_data_0 = { .VSPolarity = DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), vsync_active, 0) ? DCMI_VSPOLARITY_HIGH : DCMI_VSPOLARITY_LOW, - .CaptureRate = STM32_DCMI_GET_CAPTURE_RATE( - DT_PROP_OR(DT_DRV_INST(inst), capture_rate, - 1)), .ExtendedDataMode = STM32_DCMI_GET_BUS_WIDTH( DT_PROP_OR(DT_INST_ENDPOINT_BY_ID(n, 0, 0), bus_width, 8)), @@ -482,6 +600,7 @@ static int video_stm32_dcmi_init(const struct device *dev) data->dev = dev; k_fifo_init(&data->fifo_in); k_fifo_init(&data->fifo_out); + data->capture_rate = 1; /* Run IRQ init */ config->irq_config(dev); diff --git a/dts/bindings/video/st,stm32-dcmi.yaml b/dts/bindings/video/st,stm32-dcmi.yaml index 85efc892874c..41da6c7659f9 100644 --- a/dts/bindings/video/st,stm32-dcmi.yaml +++ b/dts/bindings/video/st,stm32-dcmi.yaml @@ -35,20 +35,6 @@ properties: interrupts: required: true - capture-rate: - type: int - enum: - - 1 - - 2 - - 4 - default: 1 - description: | - The DCMI can capture all frames or alternate frames. If it is not specified, - the default is all frames. - 1 Capture all frames. - 2 Capture alternate frames. - 4 Capture one frame every 4 frames. - dmas: required: true description: | From 7ff24e16dd023fc197818fddd568339fba5144f0 Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Fri, 9 May 2025 00:58:07 +0200 Subject: [PATCH 10/11] tests: drivers: build_all: video: add testcase of stm32 dcmi Add a testcase for building the stm32 dcmi driver on all currently supported platforms / shields. Signed-off-by: Alain Volmat --- tests/drivers/build_all/video/testcase.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/drivers/build_all/video/testcase.yaml b/tests/drivers/build_all/video/testcase.yaml index 57e74e801686..8b356bb4f75e 100644 --- a/tests/drivers/build_all/video/testcase.yaml +++ b/tests/drivers/build_all/video/testcase.yaml @@ -22,3 +22,9 @@ tests: drivers.video.mcux_smartdma.build: platform_allow: - frdm_mcxn947/mcxn947/cpu0 + drivers.video.stm32_dcmi.build: + platform_allow: + - stm32h7b3i_dk/stm32h7b3xx + - arduino_nicla_vision/stm32h747xx/m7 + extra_args: + - platform:stm32h7b3i_dk/stm32h7b3xx:SHIELD=st_b_cams_omv_mb1683 From dba3ba47f7ce3ae5513f12687e7b4be8fdb34eea Mon Sep 17 00:00:00 2001 From: Alain Volmat Date: Mon, 12 May 2025 09:34:36 +0200 Subject: [PATCH 11/11] doc: releases: add note regarding dcmi binding update Add note regarding the move of the video/dcmi driver to the usage of endpoint based video-interfaces bindings. Signed-off-by: Alain Volmat --- doc/releases/migration-guide-4.2.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/releases/migration-guide-4.2.rst b/doc/releases/migration-guide-4.2.rst index 4d6aabf58ac0..028b3dad45ce 100644 --- a/doc/releases/migration-guide-4.2.rst +++ b/doc/releases/migration-guide-4.2.rst @@ -501,6 +501,13 @@ Video ``VIDEO_PIX_FMT_GRBG8`` becomes ``VIDEO_PIX_FMT_SGRBG8`` ``VIDEO_PIX_FMT_RGGB8`` becomes ``VIDEO_PIX_FMT_SRGGB8`` +* On STM32 devices, the DCMI driver (:dtcompatible:`st,stm32-dcmi`) now relies on endpoint based + video-interfaces.yaml bindings for sensor interface properties (such as bus width and + synchronization signals). + Also the ``capture-rate`` property has been replaced by the usage of the frame interval API + :c:func:`video_set_frmival`. + See (:github:`89627`). + Other subsystems ****************