Last edited one month ago

How to use one or multiple multi-stream MIPI CSI cameras

Applicable for STM32MP21x lines, STM32MP23x lines, STM32MP25x lines


1. Article purpose[edit | edit source]

This article introduces the MIPI® CSI‑2 concepts of Virtual Channels (VC) and Data Types (DT), explaining how they can be used to transport, organize and distinguish multiple video streams over a single MIPI® CSI-2 link, and then details how these VC/DT pairs are selected and routed on STM32MP2 series through the MIPI® CSI-2 receiver and the DCMIPP camera pipeline (Dump/Main/Aux pipes), including their control via the Linux media‑controller API. It also provides a practical, end‑to‑end example based on the Arducam V3Link bridge[1] and two IMX219 sensors connected to the STM32MP257 Evaluation board, covering the required kernel updates, the device‑tree configuration, the media‑ctl and v4l2‑ctl usage and GStreamer[2] commands, so that this setup can be reused or adapted to other multi‑camera/multi‑stream designs on STM32MP21x lines , STM32MP23x lines  and STM32MP25x lines .

2. Brief introduction about MIPI® CSI-2 channels & data-types[edit | edit source]

The MIPI® CSI-2 (Camera Serial Interface) feeding the STM32MP2 series offers the possibility to transfer several data streams together over a single physical link. This enables use cases such as a sensor streaming multiple kinds of data in parallel, as well as devices performing concatenation or aggregation of several streams (from multiple sources) into a single MIPI® CSI-2 link to feed a downstream device.

In this context, the most important notions are the VC (Virtual Channel) and the DT (Data Type). A Virtual Channel can contain several streams, each stream using a different Data Type that represents its data format. All streams within the same Virtual Channel share the same frame boundaries (for example: start of frame, end of frame). It is also possible to have multiple Virtual Channels transferred on the same MIPI® CSI-2 link.

A typical case is a device streaming two kinds of data from the same sensor (for example: Infra Red and Bayer data). This would be transmitted as two different DTs within a single VC.

By contrast, when dealing with a bridge device that aggregates several device streams into one MIPI® CSI-2 link, the data is often transmitted using multiple VCs, with each VC carrying the streams from a different device.

CSI

  • VC#0 (device 0)
    • DT#0 (Device 0 - Bayer data)
    • DT#1 (Device 0 - Infra Red data)
  • VC#1 (device 1)
    • DT#1 (Device 1 - YUV data)

Above is an example of what could be the VC/DT usage if 2 devices (sources) were streaming together on the same CSI link: a 1st device (0) sending Bayer & Infra Red data and a 2nd device (1) sending YUV data.

3. STM32MP2 series multi-streams/multi-camera[edit | edit source]

When the STM32MP2 series DCMIPP camera pipeline input is the CSI-Host internal peripheral, a specific VC/DT pair can be selected so that only a subset of the incoming data is routed to each pipe (Dump, Main, and/or Aux).

Based on the example given above and considering the STM32MP2 series constraints, the pipe usage would be:

  • Dump pipe: VC0 / DT#1 (IR data from device 0)
  • Main pipe: VC0 / DT#0 (Bayer data from device 0)
  • Aux pipe: VC1 / DT#0 (YUV data from device 1)

It is important to consider the DCMIPP block diagram, as described below:

DCMIPP pipelines architecture view (extracted from the STM32 MPU reference manuals)
DCMIPP pipelines architecture view (extracted from the STM32 MPU reference manuals)

As shown in the above DCMIPP block diagram, the selection of the VC/DT within the DCMIPP is performed at the input of each pipe in the Flow selection block. The Aux pipe can be connected either directly to the DCMIPP input or to the Main pipe ISP block. In the latter case, the data received by the Aux pipe will be the same as the data received by the Main pipe, thanks to the Main pipe input selection.

4. Controlling and routing streams[edit | edit source]

The multi-stream processing is controlled via the media-controller API (using media-ctl from the command line). In a multi-stream-enabled environment, media-controller entity pads can carry several streams (instead of a single one as before) and are represented as follows:

	- entity 64: 48020000.csi (2 pads, 2 links, 2 routes)
	             type V4L2 subdev subtype Unknown flags 0
	             device node name /dev/v4l-subdev6
		routes:
			0/0 -> 1/0 [ACTIVE]
			0/1 -> 1/1 [ACTIVE]

		pad0: Sink
			[stream:0 fmt:SRGGB8_1X8/640x480 field:none colorspace:raw xfer:none quantization:full-range]
			[stream:1 fmt:SRGGB10_1X10/640x480 field:none colorspace:raw xfer:none quantization:full-range]
			<- "ds90ub960 0-0030":4 [ENABLED,IMMUTABLE]
		pad1: Source
			[stream:0 fmt:SRGGB8_1X8/640x480 field:none colorspace:raw xfer:none quantization:full-range]
			[stream:1 fmt:SRGGB10_1X10/640x480 field:none colorspace:raw xfer:none quantization:full-range]
			-> "dcmipp_input":0 [ENABLED]

When applicable, streams are described below each pad. In the example above, both sink and source pads have two streams. An additional routes section describes the relationship between sink and source streams. Here, streams 0 and 1 from pad 0 (Sink) (i.e. 0/0 and 0/1) are routed as streams 0 and 1 of pad 1 (Source) (i.e. 1/0 and 1/1).

Routing describes how a stream coming from a sink pad is forwarded (or not) to a source pad. If a stream is not described, it will not be routed and will therefore not be transferred further down the pipeline.

Routing can be controlled via the media-ctl command as shown below:

media-ctl -d platform:48030000.dcmipp --set-routes "'48020000.csi'[0/0->1/0[1],0/1->1/1[1]]"

Streams can then be configured via the media-ctl command as shown below:

media-ctl -d platform:48030000.dcmipp --set-v4l2 "'48020000.csi':1/0[fmt:SRGGB8_1X8/640x480]"

Notice that the syntax is identical to the one used when configuring a pad format, except for the /0 appended after the pad number, which indicates the ID of the stream carried by that pad.

5. Multi-stream routing within the STM32MP2x CSI camera pipeline[edit | edit source]

Within the pipeline, both the 48020000.csi subdev (CSI receiver) and dcmipp_input (input stage of the DCMIPP) are responsible for the CSI routing configuration. All streams that must be handled by the DCMIPP also have to be described and routed within the 48020000.csi subdev. At the input of the DCMIPP (dcmipp_input subdev), it is then necessary to specify how the streams are handled by routing them to one or more source pads (Dump/Main/Aux). By default, stream 0 of the sink pad is routed to all three source pads.

The example below shows the routing of three hypothetical streams from the input of the CSI receiver to each of the DCMIPP pipes.

media-ctl -d platform:48030000.dcmipp --set-routes "'48020000.csi'[0/0->1/0[1],0/1->1/1[1],0/2->1/2[1]]"
media-ctl -d platform:48030000.dcmipp --set-routes "'dcmipp_input'[0/0->1/0[1],0/1->2/0[1],0/2->3/0[1]]"

The result of those commands is as below:

	- entity 64: 48020000.csi (2 pads, 2 links, 3 routes)
	             type V4L2 subdev subtype Unknown flags 0
	             device node name /dev/v4l-subdev6
		routes:
			0/0 -> 1/0 [ACTIVE]
			0/1 -> 1/1 [ACTIVE]
			0/2 -> 1/2 [ACTIVE]
	...

	- entity 1: dcmipp_input (4 pads, 5 links, 3 routes)
	            type V4L2 subdev subtype Unknown flags 0
	            device node name /dev/v4l-subdev0
		routes:
			0/0 -> 1/0 [ACTIVE]
			0/1 -> 2/0 [ACTIVE]
			0/2 -> 3/0 [ACTIVE]

6. Running the Arducam V3Link bridge on the STM32MP25-EV1 board[edit | edit source]

The Arducam V3Link[1] allows connecting up to four IMX219 sensors to the STM32MP257F-EV1 Evaluation board . The already upstreamed DS90UB960 (deserializer) and DS90UB953 (serializer) drivers are used to control the board.

6.1. Kernel preparation & building[edit | edit source]

In order to be able to exercise the Arducam V3Link bridge[1] on the STM32MP257F-EV1 Evaluation board , some additional Linux commits unrelated to the STM32MPx and coming from the Linux tree must be added:

6.1.1. Add possibility to output RGB24/RAW8 or RAW10 out of the bridge[edit | edit source]

This patch, available in more recent Linux kernel, allows to have the DS90UB960 handle RGB24/RAW8 and RAW10 as output formats.

Linux upstream commit: 0aac971d427c ("media: i2c: ds90ub960: Add RGB24, RAW8 and RAW10 formats")

Click on the right to see/hide the patch
commit 0aac971d427c7929c7da42bb4388416cb6ad49a5
Author: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Date:   Fri Dec 6 10:26:44 2024 +0200

    media: i2c: ds90ub960: Add RGB24, RAW8 and RAW10 formats
    
    Add RGB24 and RAW8 and RAW10 bayer formats. RGB24 is mostly for TPG
    purposes, but RAW8 and RAW10 are widely used by sensors.
    
    Reviewed-by: Jai Luthra <jai.luthra@ideasonboard.com>
    Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
    Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
    Signed-off-by: Mauro Carvalho Chehab <mchehab+huawei@kernel.org>

diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c
index 670edb1e3e75..ac221b5d382c 100644
--- a/drivers/media/i2c/ds90ub960.c
+++ b/drivers/media/i2c/ds90ub960.c
@@ -580,11 +580,23 @@ struct ub960_format_info {
 };
 
 static const struct ub960_format_info ub960_formats[] = {
+       { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, .datatype = MIPI_CSI2_DT_RGB888, },
+
        { .code = MEDIA_BUS_FMT_YUYV8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, },
        { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, },
        { .code = MEDIA_BUS_FMT_VYUY8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, },
        { .code = MEDIA_BUS_FMT_YVYU8_1X16, .bpp = 16, .datatype = MIPI_CSI2_DT_YUV422_8B, },
 
+       { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, },
+       { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, },
+       { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, },
+       { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, .datatype = MIPI_CSI2_DT_RAW8, },
+
+       { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, },
+       { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, },
+       { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, },
+       { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, .datatype = MIPI_CSI2_DT_RAW10, },
+
        { .code = MEDIA_BUS_FMT_SBGGR12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, },
        { .code = MEDIA_BUS_FMT_SGBRG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, },
        { .code = MEDIA_BUS_FMT_SGRBG12_1X12, .bpp = 12, .datatype = MIPI_CSI2_DT_RAW12, },

6.1.2. Add IMX219 frame description information[edit | edit source]

The commit isn't yet merged into the Linux kernel tree but can be found on the linux-media mailing list:

A patched adapted for the Linux Kernel used on the STM32MP2x is available below.

Click on the right to see/hide the patch
From 5b628978aa592964ea6df5c2e6c4c9ab92ec5280 Mon Sep 17 00:00:00 2001
From: Alain Volmat <alain.volmat@foss.st.com>
Date: Mon, 20 Jan 2025 16:52:17 +0100
Subject: [PATCH] media: i2c: imx219: add frame_desc

From serie: PATCH-v7-00-15-media-Add-driver-for-the-Raspberry-Pi-5-CSI-2-receiver
Latest version here:
https://lore.kernel.org/linux-media/20250825095107.1332313-62-sakari.ailus@linux.intel.com/#t

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 drivers/media/i2c/imx219.c | 46 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index a3d5a8a7c660..907d84602bd7 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -22,6 +22,7 @@
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
 
+#include <media/mipi-csi2.h>
 #include <media/v4l2-cci.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-device.h>
@@ -705,6 +706,24 @@ static int imx219_set_pad_format(struct v4l2_subdev *sd,
 	return 0;
 }
 
+static unsigned int imx219_format_bpp(u32 code)
+{
+	switch (code) {
+	case MEDIA_BUS_FMT_SRGGB8_1X8:
+	case MEDIA_BUS_FMT_SGRBG8_1X8:
+	case MEDIA_BUS_FMT_SGBRG8_1X8:
+	case MEDIA_BUS_FMT_SBGGR8_1X8:
+		return 8;
+
+	case MEDIA_BUS_FMT_SRGGB10_1X10:
+	case MEDIA_BUS_FMT_SGRBG10_1X10:
+	case MEDIA_BUS_FMT_SGBRG10_1X10:
+	case MEDIA_BUS_FMT_SBGGR10_1X10:
+	default:
+		return 10;
+	}
+}
+
 static int imx219_set_framefmt(struct imx219 *imx219,
 			       const struct v4l2_mbus_framefmt *format)
 {
@@ -1028,6 +1047,32 @@ static int imx219_identify_module(struct imx219 *imx219)
 	return 0;
 }
 
+static int imx219_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+				 struct v4l2_mbus_frame_desc *fd)
+{
+	const struct v4l2_mbus_framefmt *fmt;
+	struct v4l2_subdev_state *state;
+	u32 code;
+
+	state = v4l2_subdev_lock_and_get_active_state(sd);
+	fmt = v4l2_subdev_state_get_format(state, 0, 0);
+	code = fmt->code;
+	v4l2_subdev_unlock_state(state);
+
+	fd->type = V4L2_MBUS_FRAME_DESC_TYPE_CSI2;
+	fd->num_entries = 1;
+
+	memset(fd->entry, 0, sizeof(fd->entry));
+
+	fd->entry[0].pixelcode = code;
+	fd->entry[0].stream = 0;
+	fd->entry[0].bus.csi2.vc = 0;
+	fd->entry[0].bus.csi2.dt = imx219_format_bpp(code) == 8
+				 ? MIPI_CSI2_DT_RAW8 : MIPI_CSI2_DT_RAW10;
+
+	return 0;
+}
+
 static const struct v4l2_subdev_core_ops imx219_core_ops = {
 	.subscribe_event = v4l2_ctrl_subdev_subscribe_event,
 	.unsubscribe_event = v4l2_event_subdev_unsubscribe,
@@ -1044,6 +1089,7 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
 	.set_fmt = imx219_set_pad_format,
 	.get_selection = imx219_get_selection,
 	.enum_frame_size = imx219_enum_frame_size,
+	.get_frame_desc = imx219_get_frame_desc,
 };
 
 static const struct v4l2_subdev_ops imx219_subdev_ops = {
-- 
2.34.1

6.1.3. STM32MP257F-EV1 Evaluation board device-tree updates[edit | edit source]

The patch below updates the STM32MP257F-EV1 Evaluation board device-tree in order to reference the V3Link information instead of the default IMX335 device shipped with the evaluation board.

Click on the right to see/hide the patch
From feecfc5b17c483400a5c14b92784c906dbaba0a1 Mon Sep 17 00:00:00 2001
From: Alain Volmat <alain.volmat@foss.st.com>
Date: Mon, 20 Jan 2025 17:19:04 +0100
Subject: [PATCH] arm64: dts: add FDLink3 serializer/deserializer instead of
 imx335 on stm32mp257f-ev1

Signed-off-by: Alain Volmat <alain.volmat@foss.st.com>
---
 arch/arm64/boot/dts/st/stm32mp257f-ev1.dts | 206 ++++++++++++++++++++-
 1 file changed, 203 insertions(+), 3 deletions(-)

diff --git a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
index bafe74a860a7..545c92d8deab 100644
--- a/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
+++ b/arch/arm64/boot/dts/st/stm32mp257f-ev1.dts
@@ -60,6 +60,12 @@ pad_clk: pad-clk {
 			compatible = "fixed-clock";
 			clock-frequency = <100000000>;
 		};
+
+		clk_fusion_25M_fixed: fixed-clock-25M {
+			compatible = "fixed-clock";
+			#clock-cells = <0>;
+			clock-frequency = <25000000>;
+		};
 	};
 
 	clock_critical: clock_critical {
@@ -290,7 +296,7 @@ ports {
 		port@0 {
 			reg = <0>;
 			csi_sink: endpoint {
-				remote-endpoint = <&imx335_ep>;
+				remote-endpoint = <&ds90ub960_0_csi_out>;
 				data-lanes = <1 2>;
 				bus-type = <4>;
 			};
@@ -432,11 +438,11 @@ imx335: camera@1a {
 		dvdd-supply = <&scmi_v3v3>;
 		reset-gpios = <&gpioi 7 (GPIO_ACTIVE_LOW | GPIO_PUSH_PULL)>;
 		powerdown-gpios = <&gpioi 0 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>;
-		status = "okay";
+		status = "disabled";
 
 		port {
 			imx335_ep: endpoint {
-				remote-endpoint = <&csi_sink>;
+//				remote-endpoint = <&csi_sink>;
 				clock-lanes = <0>;
 				data-lanes = <1 2>;
 				link-frequencies = /bits/ 64 <594000000>;
@@ -444,6 +450,200 @@ imx335_ep: endpoint {
 		};
 	};
 
+	ds90ub960_0: deser@30 {
+		compatible = "ti,ds90ub960-q1";
+
+		reg = <0x30>;
+
+		clocks = <&clk_fusion_25M_fixed>;
+		clock-names = "refclk";
+
+		powerdown-gpios = <&gpioi 0 (GPIO_ACTIVE_HIGH | GPIO_PUSH_PULL)>;
+
+		i2c-alias-pool = <0x4a 0x4b 0x4c 0x4d 0x4e 0x4f>;
+
+		status = "okay";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* Port 0, Camera 0 */
+			port@0 {
+				reg = <0>;
+
+				ub960_fpd3_1_in: endpoint {
+					remote-endpoint = <&ub953_1_out>;
+				};
+			};
+
+			/* Port 1, Camera 1 */
+			port@1 {
+				reg = <1>;
+
+				ub960_fpd3_2_in: endpoint {
+					remote-endpoint = <&ub953_2_out>;
+				};
+			};
+
+			/* Port 2, unconnected */
+			port@2 {
+				reg = <2>;
+			};
+
+			/* Port 3, unconnected */
+			port@3 {
+				reg = <3>;
+			};
+
+			/* CSI-2 */
+			port@4 {
+				reg = <4>;
+				ds90ub960_0_csi_out: endpoint {
+					data-lanes = <1 2>;
+					link-frequencies = /bits/ 64 <400000000>;
+					remote-endpoint = <&csi_sink>;
+				};
+			};
+
+			/* Port 5, unconnected */
+			port@5 {
+				reg = <5>;
+			};
+		};
+
+		links {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			/* Link 0 has DS90UB953 serializer and IMX219 sensor */
+			link@0 {
+				reg = <0>;
+				i2c-alias = <0x44>;
+
+				ti,rx-mode = <3>;
+
+				serializer1: serializer {
+					compatible = "ti,ds90ub953-q1";
+
+					gpio-controller;
+					#gpio-cells = <2>;
+
+					#clock-cells = <0>;
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0>;
+
+							ub953_1_in: endpoint {
+								data-lanes = <1 2>;
+								remote-endpoint = <&sensor_1_out>;
+							};
+						};
+
+						port@1 {
+							reg = <1>;
+
+							ub953_1_out: endpoint {
+								remote-endpoint = <&ub960_fpd3_1_in>;
+							};
+						};
+					};
+
+					i2c {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						sensor@10 {
+							compatible = "sony,imx219";
+							reg = <0x10>;
+
+							clocks = <&clk_ext_camera>;
+							clock-names = "xclk";
+
+							reset-gpios = <&serializer1 0 GPIO_ACTIVE_LOW>;
+
+							port {
+								sensor_1_out: endpoint {
+									remote-endpoint = <&ub953_1_in>;
+									link-frequencies = /bits/ 64 <456000000>;
+									clock-lanes = <0>;
+									data-lanes = <1 2>;
+								};
+							};
+						};
+					};
+				};
+			};
+
+			/* Link 1 has DS90UB953 serializer and IMX219 sensor */
+			link@1 {
+				reg = <1>;
+				i2c-alias = <0x45>;
+
+				ti,rx-mode = <3>;
+
+				serializer2: serializer {
+					compatible = "ti,ds90ub953-q1";
+
+					gpio-controller;
+					#gpio-cells = <2>;
+
+					#clock-cells = <0>;
+
+					ports {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						port@0 {
+							reg = <0>;
+
+							ub953_2_in: endpoint {
+								data-lanes = <1 2>;
+								remote-endpoint = <&sensor_2_out>;
+							};
+						};
+
+						port@1 {
+							reg = <1>;
+
+							ub953_2_out: endpoint {
+								remote-endpoint = <&ub960_fpd3_2_in>;
+							};
+						};
+					};
+
+					i2c {
+						#address-cells = <1>;
+						#size-cells = <0>;
+
+						sensor@10 {
+							compatible = "sony,imx219";
+							reg = <0x10>;
+
+							clocks = <&clk_ext_camera>;
+							clock-names = "xclk";
+
+							reset-gpios = <&serializer2 0 GPIO_ACTIVE_LOW>;
+
+							port {
+								sensor_2_out: endpoint {
+									remote-endpoint = <&ub953_2_in>;
+									link-frequencies = /bits/ 64 <456000000>;
+									clock-lanes = <0>;
+									data-lanes = <1 2>;
+								};
+							};
+						};
+					};
+				};
+			};
+		};
+	};
+
 	adv753x: hdmi@3d {
 		/*
 		 * With MB1232 board, use "adi,adv7533" (1080p30)
-- 
2.34.1

6.1.4. Linux kernel configuration & compilation[edit | edit source]

Prior to compiling the Linux kernel and its device-tree, ensure that the following drivers are enabled in the configuration:

  Device Drivers --->
    <M> Multimedia support --->
      Media ancillary drivers --->
        Camera sensor devices  --->
          <M> Sony IMX219 sensor support
      Video serializers and deserializers  --->
          <M> TI FPD-Link III/IV CSI-2 Serializers
          <M> TI FPD-Link III/IV Deserializers


6.2. Running dual CSI camera on the STM32MP257F-EV1 Evaluation board [edit | edit source]

With two IMX219 sensors connected to the Arducam V3Link bridge, and the bridge attached to the CSI connector of the STM32MP257F-EV1 Evaluation board , boot OSTL to the shell prompt.

To demonstrate the configuration capabilities of the system and make the setup easier to understand, the following use case is implemented: 1st IMX219: configured as 8‑bit Bayer RGGB with a resolution of 640×480, routed to the DCMIPP DUMP pipe and rendered in software using the GStreamer[2] bayer2rgb element.

2nd IMX219: configured as 10‑bit Bayer RGGB with a resolution of 640×480, routed to the DCMIPP MAIN pipe (including the DCMIPP ISP) and also displayed via GStreamer[2].


6.2.1. Configuration of the full camera pipeline[edit | edit source]

#Reset media-controller configuration
media-ctl -d platform:48030000.dcmipp -r

###############################################
#Perform camera pipeline routing configuration 
###############################################

#Enable DCMIPP CSI input
media-ctl -d platform:48030000.dcmipp -l "'48020000.csi':1->'dcmipp_input':0[1]"
media-ctl -d platform:48030000.dcmipp --set-routes "'48020000.csi'[0/0->1/0[1],0/1->1/1[1]]" 

#Route CSI stream #0 to pipe DUMP and stream #1 to pipe MAIN
media-ctl -d platform:48030000.dcmipp --set-routes "'dcmipp_input'[0/0->1/0[1],0/1->2/0[1],0/2->3/0[0]]"
media-ctl -d platform:48030000.dcmipp -l "'dcmipp_input':1->'dcmipp_dump_postproc':0[1]"
media-ctl -d platform:48030000.dcmipp -l "'dcmipp_input':2->'dcmipp_main_isp':0[1]"

#Perform bridge routing configuration
#Stream #0 of the 1st IMX219 is routed as Stream #0 out of the bridge
#Stream #0 of the 2nd IMX219 is routed as Stream #1 out of the bridge
media-ctl -d platform:48030000.dcmipp --set-routes "'ds90ub960 0-0030'[0/0->4/0[1],1/0->4/1[1]]"

###############################
#Perform streams configuration 
###############################

#Perform sensor #1 configuration in binned mode
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'imx219 1-0010':0[fmt:SRGGB8_1X8/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'ds90ub953 0-0044':1[fmt:SRGGB8_1X8/640x480]"  

#Perform sensor #2 configuration in binned mode
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'imx219 2-0010':0[fmt:SRGGB10_1X10/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'ds90ub953 0-0045':1[fmt:SRGGB10_1X10/640x480]"

#Perform bridge routing configuration
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'ds90ub960 0-0030':4/0[fmt:SRGGB8_1X8/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'ds90ub960 0-0030':4/1[fmt:SRGGB10_1X10/640x480]"

#Perform CSI receiver stream #0 output configuration
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'48020000.csi':1/0[fmt:SRGGB8_1X8/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'48020000.csi':1/1[fmt:SRGGB10_1X10/640x480]"

#Perform DCMIPP pipes configuration
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'dcmipp_input':1[fmt:SRGGB8_1X8/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'dcmipp_dump_postproc':1[fmt:SRGGB8_1X8/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'dcmipp_input':2[fmt:SRGGB10_1X10/640x480]"
media-ctl -d platform:48030000.dcmipp --set-v4l2 "'dcmipp_main_isp':1[fmt:RGB888_1X24/640x480 field:none]" 

#####################################
#DCMIPP output streams configuration
#####################################

v4l2-ctl -d `media-ctl -d platform:48030000.dcmipp -e 'dcmipp_dump_capture'` --set-fmt-video=width=640,height=480,pixelformat=RGGB
v4l2-ctl -d `media-ctl -d platform:48030000.dcmipp -e 'dcmipp_main_capture'` --set-fmt-video=width=640,height=480,pixelformat=RGBP

6.2.2. Dual stream playback using gst-launch-1.0[edit | edit source]

The DCMIPP can handle only a single Bayer stream at a time (via the Main pipe). Therefore, in this demonstration, one stream is processed through the Main pipe (using DCMIPP for demosaicing), while the second stream is captured via the DUMP pipe and then demosaising is done in software using the bayer2rgb GStreamer plugin element.

############################################################
#GStreamer commands for displaying both streams in parallel 
############################################################
#Display the 1st stream (via DUMP) using bayer2rgb
gst-launch-1.0 v4l2src device=`media-ctl -d platform:48030000.dcmipp -e 'dcmipp_dump_capture'` ! video/x-bayer,format=rggb,width=640,height=480 ! bayer2rgb ! autovideosink &

#Display the 2nd stream (via MAIN)
gst-launch-1.0 v4l2src device=`media-ctl -d platform:48030000.dcmipp -e 'dcmipp_main_capture'` ! video/x-raw,format=RGB16,width=640,height=480 ! autovideosink &

7. References[edit | edit source]