killiia
Posts: 4
Joined: Tue Dec 08, 2020 11:56 am

CM4IO 2 ov9281 cameras on Cam0 and Cam1

Fri Dec 18, 2020 11:36 am

TLDR; see dmesg errors at the end. Rest above is documentation.

I have configured a second overlay(besides the default ov9281.dtbo) to enable both cam0 and cam1 with ov9281 camera sensors (from inno-maker).

A special thanks to 6by9 who is always around with valuable explanations.

The source for the raspberry original ov9281 overlay can be found in the kernel sources and I modified it as described in kjjohnsen/stereopi_ov9281.

This is the result, ov9281cam0.dts:

Code: Select all

// Definitions for OV9281 camera module
/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>

/{
	compatible = "brcm,bcm2835";

	fragment@0 {
		target-path = "/";
		__overlay__ {
			i2c_gpio: i2c@0 {
				reg = <0xffffffff>;
				compatible = "i2c-gpio";
				gpios = <&gpio 23 0 &gpio 24 0>;
				i2c-gpio,delay-us = <2>;
				#address-cells = <1>;
				#size-cells = <0>;
			};
		};
	};
	fragment@1 {
		target-path = "/aliases";
		__overlay__ {
			i2c_gpio = "/i2c@0";
		};
	};

	fragment@2 {
		target-path = "/__symbols__";
		__overlay__ {
			i2c_gpio = "/i2c@0";
		};
	};

	fragment@3 {
		target = <&i2c_gpio>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			ov9281_0: ov9281_0@60 {
				compatible = "ovti,ov9281";
				reg = <0x60>;
				status = "okay";

				clocks = <&ov9281_0_clk>;
				clock-names = "xvclk";

				avdd-supply = <&ov9281_0_avdd>;
				dovdd-supply = <&ov9281_0_dovdd>;
				dvdd-supply = <&ov9281_0_dvdd>;

				port {
					ov9281_0_0: endpoint {
						remote-endpoint = <&csi0_ep>;
						clock-lanes = <0>;
						data-lanes = <1 2>;
						clock-noncontinuous;
						link-frequencies =
							/bits/ 64 <400000000>;
					};
				};
			};
		};
	};

	fragment@4 {
		target = <&csi0>;
		__overlay__ {
			status = "okay";

			port {
				csi0_ep: endpoint {
					remote-endpoint = <&ov9281_0_0>;
					data-lanes = <1 2>;
					clock-noncontinuous;
				};
			};
		};
	};

	fragment@5 {
		target-path="/";
		__overlay__ {
			ov9281_0_avdd: fixedregulator@0 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_0_avdd";
				regulator-min-microvolt = <2800000>;
				regulator-max-microvolt = <2800000>;
				gpio = <&gpio 41 GPIO_ACTIVE_HIGH>;
				enable-active-high;
			};
			ov9281_0_dovdd: fixedregulator@1 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_0_dovdd";
				regulator-min-microvolt = <1800000>;
				regulator-max-microvolt = <1800000>;
			};
			ov9281_0_dvdd: fixedregulator@2 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_0_dvdd";
				regulator-min-microvolt = <1200000>;
				regulator-max-microvolt = <1200000>;
			};
			ov9281_0_clk: ov9281_0-clk {
				compatible = "fixed-clock";
				#clock-cells = <0>;
				clock-frequency = <24000000>;
			};
		};
	};

	fragment@6 {
		target-path="/__overrides__";
		__overlay__ {
			cam0-pwdn-ctrl = <&ov9281_0_avdd>,"gpio:0";
			cam0-pwdn      = <&ov9281_0_avdd>,"gpio:4";
		};
	};

	__overrides__ {
		i2c_gpio_sda = <&i2c_gpio>,"gpios:4";
		i2c_gpio_scl = <&i2c_gpio>,"gpios:16";
		i2c_gpio_delay_us = <&i2c_gpio>,"i2c-gpio,delay-us:0";
		bus = <&i2c_gpio>, "reg:0";
	};
};

/boot/config.txt uses overlays and configuration

Code: Select all

dtparam=i2c_arm=on
dtoverlay=ov9281
dtoverlay=ov9281cam0,bus=3,i2c_gpio_sda=0,i2c_gpio_scl=1

and there is no dt-blob.bin used

Code: Select all

$ uname -a
Linux raspberrypi 5.4.79-v7l+ #1373 SMP Mon Nov 23 13:27:40 GMT 2020 armv7l GNU/Linux
$ ls /boot/dt-*
ls: Zugriff auf '/boot/dt-*' nicht möglich: Datei oder Verzeichnis nicht gefunden

However, dmesg reports problems ("supply avdd not found, using dummy regulator"):

Code: Select all

$ dmesg | grep ov92
[    4.956764] unicam fe800000.csi: found subdevice /i2c@3/ov9281_0@60
[    4.956829] unicam fe800000.csi: subdevice /i2c@3/ov9281_0@60: CSI-2 bus, 2 data lanes, flags=0x00000200
[    4.961029] unicam fe801000.csi: found subdevice /soc/i2c0mux/i2c@1/ov9281@60
[    4.961096] unicam fe801000.csi: subdevice /soc/i2c0mux/i2c@1/ov9281@60: CSI-2 bus, 2 data lanes, flags=0x00000200
[    5.856865] ov9281 3-0060: Detected OV009281 sensor
[    5.856912] unicam fe800000.csi: Using sensor mov9281 3-0060 for capture
[    5.856954] unicam fe800000.csi: subdev mov9281 3-0060: code: 0x0000200a idx: 0
[    5.873010] ov9281 10-0060: 10-0060 supply avdd not found, using dummy regulator
[    5.873180] ov9281 10-0060: 10-0060 supply dovdd not found, using dummy regulator
[    5.873353] ov9281 10-0060: 10-0060 supply dvdd not found, using dummy regulator
[    5.878063] ov9281 10-0060: Detected OV009281 sensor
[    5.878110] unicam fe801000.csi: Using sensor mov9281 10-0060 for capture
[    5.878151] unicam fe801000.csi: subdev mov9281 10-0060: code: 0x0000200a idx: 0
[   31.837552] ov9281_0_dvdd: disabling
[   31.837569] ov9281_0_dovdd: disabling
[   31.837588] ov9281_0_avdd: disabling
==> Should I worry? What can I do?

Must these pins be defined?

Code: Select all

$ sudo vcdbg log msg
[...]
006544.364: *** Restart logging
006544.383: brfs: File read: 1997 bytes
006548.231: hdmi: HDMI:hdmi_get_state is deprecated, use hdmi_get_display_state instead
006569.693: HDMI0: hdmi_pixel_encoding: 300000000
006569.707: HDMI1: hdmi_pixel_encoding: 300000000
006570.383: gpioman: gpioman_get_pin_num: pin CAMERA_0_SDA_PIN not defined
006570.398: gpioman: gpioman_get_pin_num: pin CAMERA_0_SCL_PIN not defined
006570.414: gpioman: gpioman_get_pin_num: pin CAMERA_0_I2C_PORT not defined
006570.434: dtb_file 'bcm2711-rpi-cm4.dtb'
006577.870: brfs: File read: /mfs/sd/bcm2711-rpi-cm4.dtb
006577.885: Loading 'bcm2711-rpi-cm4.dtb' to 0x100 size 0xba0d
006590.163: brfs: File read: 47629 bytes
006603.547: brfs: File read: /mfs/sd/overlays/overlay_map.dtb
006658.860: brfs: File read: 1523 bytes
006663.153: brfs: File read: /mfs/sd/config.txt
006663.994: brfs: File read: 1997 bytes
...
006787.989: brfs: File read: /mfs/sd/overlays/ov9281.dtbo
006826.614: Loaded overlay 'ov9281'
007043.761: brfs: File read: 2981 bytes
007063.205: brfs: File read: /mfs/sd/overlays/ov9281cam0.dtbo
007089.080: Loaded overlay 'ov9281cam0'
007089.102: dtparam: bus=3
007090.058: dtparam: i2c_gpio_sda=0
007090.851: dtparam: i2c_gpio_scl=1
007294.062: brfs: File read: 3002 bytes
007298.595: brfs: File read: /mfs/sd/cmdline.txt
007298.678: Read command line from file 'cmdline.txt':
007298.709: 'console=serial0,115200 console=tty1 root=PARTUUID=852ce416-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait quiet splash plymouth.i
gnore-serial-consoles'
The cameras work as expected for now.
Attachments
screenshot_raspi_2cameras.jpg
screenshot_raspi_2cameras.jpg (200.08 KiB) Viewed 724 times

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 12353
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: CM4IO 2 ov9281 cameras on Cam0 and Cam1

Fri Dec 18, 2020 12:46 pm

Why are you using a bit-bashed I2C bus on GPIOs 23 & 24? Install the 2 jumpers on J6 and GPIOs 0&1 are routed through to CAM0 (and DISP0).

And note that if using any camera module that actually shuts down based on the shutdown line (eg Arducam's), then due to the shared shutdown line for the CAM0 & CAM1 connectors you need to share the regulator. You can't easily share a regulator between multiple overlays, therefore both have to be configured via the same overlay.

My overlay for dual OV9281's

Code: Select all

// SPDX-License-Identifier: GPL-2.0-only
// Definitions for dual OV9281 camera modules
/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>

/{
	compatible = "brcm,bcm2835";

	fragment@0 {
		target = <&i2c_csi_dsi>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			ov9281_0: ov9281_0@60 {
				compatible = "ovti,ov9281";
				reg = <0x60>;
				status = "okay";

				clocks = <&ov9281_clk_0>;
				clock-names = "xvclk";

				avdd-supply = <&ov9281_avdd>;
				dovdd-supply = <&ov9281_dovdd>;
				dvdd-supply = <&ov9281_dvdd>;

				port {
					ov9281_0_ep: endpoint {
						remote-endpoint = <&csi1_ep>;
						clock-lanes = <0>;
						data-lanes = <1 2>;
						clock-noncontinuous;
						link-frequencies =
							/bits/ 64 <400000000>;
					};
				};
			};
		};
	};

	fragment@1 {
		target = <&csi1>;
		__overlay__ {
			status = "okay";

			port {
				csi1_ep: endpoint {
					remote-endpoint = <&ov9281_0_ep>;
					data-lanes = <1 2>;
					clock-noncontinuous;
				};
			};
		};
	};

	fragment@10 {
		target = <&i2c_vc>;
		__overlay__ {
			#address-cells = <1>;
			#size-cells = <0>;
			status = "okay";

			ov9281_1: ov9281_1@60 {
				compatible = "ovti,ov9281";
				reg = <0x60>;
				status = "okay";

				clocks = <&ov9281_clk_1>;
				clock-names = "xvclk";

				avdd-supply = <&ov9281_avdd>;
				dovdd-supply = <&ov9281_dovdd>;
				dvdd-supply = <&ov9281_dvdd>;

				port {
					ov9281_1_ep: endpoint {
						remote-endpoint = <&csi0_ep>;
						clock-lanes = <0>;
						data-lanes = <1 2>;
						clock-noncontinuous;
						link-frequencies =
							/bits/ 64 <400000000>;
					};
				};
			};
		};
	};

	fragment@11 {
		target = <&csi0>;
		__overlay__ {
			status = "okay";

			port {
				csi0_ep: endpoint {
					remote-endpoint = <&ov9281_1_ep>;
					data-lanes = <1 2>;
					clock-noncontinuous;
				};
			};
		};
	};

	fragment@2 {
		target = <&i2c0if>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@3 {
		target-path="/";
		__overlay__ {
			ov9281_avdd: fixedregulator_ov9281@0 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_avdd";
				regulator-min-microvolt = <2800000>;
				regulator-max-microvolt = <2800000>;
				gpio = <&expgpio 5 GPIO_ACTIVE_HIGH>;
				enable-active-high;
			};
			ov9281_dovdd: fixedregulator_ov9281@1 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_dovdd";
				regulator-min-microvolt = <1800000>;
				regulator-max-microvolt = <1800000>;
			};
			ov9281_dvdd: fixedregulator_ov9281@2 {
				compatible = "regulator-fixed";
				regulator-name = "ov9281_dvdd";
				regulator-min-microvolt = <1200000>;
				regulator-max-microvolt = <1200000>;
			};
			ov9281_clk_0: ov9281-clk_ov9281_0 {
				compatible = "fixed-clock";
				#clock-cells = <0>;
				clock-frequency = <24000000>;
			};
			ov9281_clk_1: ov9281-clk_ov9281_1 {
				compatible = "fixed-clock";
				#clock-cells = <0>;
				clock-frequency = <24000000>;
			};
		};
	};

	fragment@4 {
		target = <&i2c0mux>;
		__overlay__ {
			status = "okay";
		};
	};

	fragment@5 {
		target-path="/__overrides__";
		__overlay__ {
			cam0-pwdn-ctrl = <&ov9281_avdd>,"gpio:0";
			cam0-pwdn      = <&ov9281_avdd>,"gpio:4";
		};
	};
};
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

6by9
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 12353
Joined: Wed Dec 04, 2013 11:27 am
Location: ZZ9 Plural Z Alpha, aka just outside Cambridge.

Re: CM4IO 2 ov9281 cameras on Cam0 and Cam1

Fri Dec 18, 2020 12:48 pm

Your "supply avdd not found, using dummy regulator" will be because it is trying to claim the GPIO to control the regulator, but the first instance of the regulator has already claimed it.
The regulator framework drops back to a dummy_regulator instead of outright failing - not sure of the thinking there.
Software Engineer at Raspberry Pi Trading. Views expressed are still personal views.
I'm not interested in doing contracts for bespoke functionality - please don't ask.

killiia
Posts: 4
Joined: Tue Dec 08, 2020 11:56 am

Re: CM4IO 2 ov9281 cameras on Cam0 and Cam1

Mon Dec 21, 2020 10:01 am

Why are you using a bit-bashed I2C bus on GPIOs 23 & 24?
Because I still do not understand the hardware intrinsics, more of a software guy :roll:

However, thank you very much. Works beautifully.

I have uploaded ready-to-use *.dtbo overlays at https://gist.github.com/kralo/5e489247d ... 6baa443416

Return to “Compute Module”