Nix-raspi-camera: Raspberry PI camera module and apps

Raspberry Pi provides a hardware camera interface and API based on libisp, libcamera and rpicam-apps.

My project which brings the above parts together into a draft flake-based Nixos module.

The module sets up runs a simple RTSP broadcasting server on a RaspberryPi 4B board, offering few or no configurable options. I do not currently plan to enhance anything or make tests with other boards. Still, I hope that it might become a reference example for other programmers.

Please let me know if you want me to share the link on the Nixos raspberry pi wiki page or somewhere else.

3 Likes

I am bungling my way through trying to get my zero2 w working with the camera v 2 module on nixos, and came across your repo and this post.

You mentioned in “Problems” looking for the dts overlay, is it this?

I am bungling my way through trying to get my zero2 w working with the camera v 2 module on nixos

Did you succeed in getting the camera v2 module to work? I kinda gave up with my raspberry pi 4.

Hi @aou . Sorry I missed your question. Indeed, the link you provided points to a promising dts source. A good thing to do would be to try removing the binary patch I used and including this source as described here.

@7FM I had to put this project on hold as other stuff bubbled up… hopefully will get back to trying eventually!

That’s the correct file.

Check also implementation in raspberry-pi-nix and Raspberry Pi camera on NixOS

Following steps should be required:

1. device tree overlay part

  1. download / copy the file (maybe stick to default or lts branches, master only has compiled .dtbo so no .dts on master use the one on the branch matching your kernel version, currently 6.6y branch for NixOS 25.05 linux/arch/arm/boot/dts/overlays/ov5647-overlay.dts at rpi-6.6.y · raspberrypi/linux · GitHub)
  2. replace compatible = "brcm,bcm2835"; with what’ts compatible with your device
    e.g for Zero 2 W, it should be compatible = "brcm,bcm2837";
  3. replace the #include "ov5647.dtsi" with the content of ov5647.dtsi
  4. file should then look like this:
// SPDX-License-Identifier: GPL-2.0-only
// Definitions for OV5647 camera module on VC I2C bus
/dts-v1/;
/plugin/;

/{
	compatible = "brcm,bcm2837";

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

			cam_node: ov5647@36 {
				compatible = "ovti,ov5647";
				reg = <0x36>;
				status = "disabled";

				clocks = <&cam1_clk>;

				avdd-supply = <&cam1_reg>;
				dovdd-supply = <&cam_dummy_reg>;
				dvdd-supply = <&cam_dummy_reg>;

				rotation = <0>;
				orientation = <2>;

				port {
					cam_endpoint: endpoint {
						clock-lanes = <0>;
						data-lanes = <1 2>;
						clock-noncontinuous;
						link-frequencies =
							/bits/ 64 <297000000>;
					};
				};
			};

			vcm_node: ad5398@c {
				compatible = "adi,ad5398";
				reg = <0x0c>;
				status = "disabled";
				VANA-supply = <&cam1_reg>;
			};
		};
	};

	csi_frag: fragment@1 {
		target = <&csi1>;
		csi: __overlay__ {
			status = "okay";
			brcm,media-controller;

			port {
				csi_ep: endpoint {
					remote-endpoint = <&cam_endpoint>;
					data-lanes = <1 2>;
				};
			};
		};
	};

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

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

	reg_frag: fragment@4 {
		target = <&cam1_reg>;
		__overlay__ {
			startup-delay-us = <20000>;
		};
	};

	clk_frag: fragment@5 {
		target = <&cam1_clk>;
		__overlay__ {
			status = "okay";
			clock-frequency = <25000000>;
		};
	};

	__overrides__ {
		rotation = <&cam_node>,"rotation:0";
		orientation = <&cam_node>,"orientation:0";
		media-controller = <&csi>,"brcm,media-controller?";
		cam0 = <&i2c_frag>, "target:0=",<&i2c_csi_dsi0>,
		       <&csi_frag>, "target:0=",<&csi0>,
		       <&reg_frag>, "target:0=",<&cam0_reg>,
		       <&clk_frag>, "target:0=",<&cam0_clk>,
		       <&cam_node>, "clocks:0=",<&cam0_clk>,
		       <&cam_node>, "avdd-supply:0=",<&cam0_reg>,
		       <&vcm_node>, "VANA-supply:0=",<&cam0_reg>;
		vcm = <&vcm_node>, "status=okay",
		       <&cam_node>,"lens-focus:0=", <&vcm_node>;
	};
};

&cam_node {
	status = "okay";
};

&cam_endpoint {
	remote-endpoint = <&csi_ep>;
};
  1. find the correct hardware.deviceTree.filter - that will depends on kernel used, if using *rpi* kernels, then check here for naming per model
    e.g for Zero 2 W use smth like bcm2837-rpi-zero-2*
  2. add dts file to your config hardware.deviceTree
{
  hardware = {
    deviceTree = {
      enable = true;
      filter = "bcm2837-rpi-zero-2*";;

      overlays = [
        {
          name = "ov5647-overlay";
          dtsFile = ./path/to/ov5647-overlay.dts;
        }
      ];
    };
  };
}

2. libcamera and rpicam-apps

You’ll need to package these as not in nixpkgs, rpicam-apps uses a fork of libcamera so can’t use the pkgs.libcamera directly.
See @SergeyMironov solution.

3. config.txt

Following will be needed:

camera_auto_detect=0
gpu_mem=128
cma=256
dtoverlay=ov5647 # or other overlay, depending on camera model
disable_fw_kms_setup=1

Important:
disable_fw_kms_setup=1 must be set on a fresh install, otherwise it would not work and camera won’t get detected (if added after the 1st boot) - idk the correct process to disable that after it was enabled, as assuming some setup gets done and needs to be un-installed therefore


overlay “patching” can be automated

here’s an example that generates the file and output required attributes to add to the deviceTree.overlays: nixos-raspberry-pi-build/modules/camera/overlays/ov5647.nix at main · JimJ92120/nixos-raspberry-pi-build · GitHub

Then import like this

1 Like