Enabling SPI on the Raspberry Pi 3

In a project I’m working on I need to communicate with a BrickPi3 using a Raspberry Pi 3 Model B. For this reason I need to enable SPI. If I were using Raspbian it would mean just adding dtparam=spi=on to /boot/config.txt, but this file is not part of the NixOS boot process. I also want to just flash an SD-card and plug it into the Pi without having to run some actual installation:

{ pkgs, lib, ... }: {
  imports = [

  # We can only flash an uncompressed image.
  # Additionally, compression whilst emulating the platform takes a looong time.
  sdImage.compressImage = false;

  # Latest release of major 5 doesn't always play ball with the hardware.
  # Relase 4.19 is stable and "battle-tested".
  # See <https://github.com/NixOS/nixpkgs/issues/82455>.
  boot.kernelPackages = pkgs.linuxPackages_4_19;

  # Other system configurations (services, software environments)
  # omitted for brevity

A nixos-generate of the above derivation gives me an image that boots without problems.

Now, according to the NixOS wiki on the Raspberry, to enable audio one needs to add boot.loader.raspberryPi.firmwareConfig = ''dtparam=audio=on'' to the configuration, but mirroring this with dtparam=spi=on instead has no effect. Does anyone know how it should be done? In the end I expect some SPI driver to be listed by lsmod.

sd-image-aarch64.nix has a section that looks similar to what is usually written into a /boot/config.txt:

  sdImage = {
    populateFirmwareCommands = let
      configTxt = pkgs.writeText "config.txt" ''

        # Boot in 64-bit mode.

        # U-Boot used to need this to work, regardless of whether UART is actually used or not.
        # TODO: check when/if this can be removed.

        # Prevent the firmware from smashing the framebuffer setup done by the mainline kernel
        # when attempting to show low-voltage or overtemperature warnings.
      in ''
        (cd ${pkgs.raspberrypifw}/share/raspberrypi/boot && cp bootcode.bin fixup*.dat start*.elf $NIX_BUILD_TOP/firmware/)
        cp ${pkgs.ubootRaspberryPi3_64bit}/u-boot.bin firmware/u-boot-rpi3.bin
        cp ${configTxt} firmware/config.txt
    populateRootCommands = ''
      mkdir -p ./files/boot
      ${extlinux-conf-builder} -t 3 -c ${config.system.build.toplevel} -d ./files/boot

but appending dtparam=spi=on to the generated config.txt seems to have no effect.

The Nix approach to this problem seems to be by applying device tree overlays: nixos/hardware.deviceTree: new module by kwohlfahrt · Pull Request #60422 · NixOS/nixpkgs · GitHub. I’ll experiment a bit and see if I get things working.

I got some help over on the issue tracker. My final working configuration is linked in the tail-end of the thread.

1 Like

sorry for resurrecting a three year old thread here but I just can’t seem to get this working on my Raspberry Pi 3 Model B even applying your overlay @Tmplt - perhaps something changed in the last three years? :laughing: I know it’s a shot in the dark but if you still have this working I’d take any pointers. I’ve tried a few things but alas! it says it applies during a rebuild but I don’t see /dev/spi

  hardware.deviceTree = {
    enable = true;
    filter = "*rpi*.dtb";
    overlays = [
      { name = "spi"; dtsFile = ./dts/spi.dts; }

  users.groups.spi = {};

  services.udev.extraRules = ''
  SUBSYSTEM=="spidev", KERNEL=="spidev0.0", GROUP="spi", MODE="0660"

I can’t help you more than pointing to the project repo where the Pi was in use: GitHub - tmplt/ed7039e: Model, simulation and implementation of a mechatronical system for use in a mimicked industrial environment using UWB localization. Task dispatch via Arrowhead. Reproducibly built via Nix.. See mmc-image.nix, it’s a nix-shell shebang that builds a ready-to-use image. build.sh might also be of interest. Unfortunately there are no lock files, and I don’t know what nixpkgs rev I was on. It was probably the small stable release at the time.

I recall that I had to set the kernel to 4.19. After that HW played nice.

Also, consider checking feat(nix): pin nixpkgs, enable spi via dtso · tmplt/ed7039e@f45470d · GitHub out if you haven’t already.

Edit, found the nixpkgs pin: Commits · tmplt/nixpkgs · GitHub

yep, I used the bits from there to get the rebuild to work and it says it applies but no dice after a reboot. Anyway, I’m sure I’ll figure it out or just give up at some point. Thanks so much for the reply three years down the road!

For another datapoint, try https://github.com/hexamon-tech/nixos-lorawan-gateway/blob/f248cab90e560aea38d7c03963f7eedac9bfd497/modules/dts/spi.dts

Working for years for me with mainline Linux, currently Linux ttn-gw 5.10.93. Think I’ve built it last year, using boot.kernelPackages = pkgs.linuxPackages; (NixOS 22.05).


thanks @sorki that’s what I copied before posting here and it appears to do something during a rebuild but I can’t seem to see /dev/spi :crying_cat_face: I’m probably just applying the config wrong is my guess. but I see this during rebuild (using latest kernel as well (all this in an attempt to get some silly epaper HAT working)):

Applying overlay spi to bcm2837-rpi-cm3-io3.dtb... ok
Applying overlay spi to bcm2837-rpi-3-b.dtb... ok
Applying overlay spi to bcm2711-rpi-4-b.dtb... ok
Applying overlay spi to bcm2711-rpi-400.dtb... ok
Applying overlay spi to bcm2837-rpi-3-a-plus.dtb... ok
Applying overlay spi to bcm2837-rpi-zero-2-w.dtb... ok
Applying overlay spi to bcm2837-rpi-3-b-plus.dtb... ok
Skipping overlay spi: incompatible with imx8mm-venice-gw73xx-0x-rpidsi.dtb
Skipping overlay spi: incompatible with imx8mp-venice-gw74xx-rpidsi.dtb
Skipping overlay spi: incompatible with imx8mm-venice-gw72xx-0x-rpidsi.dtb
Skipping overlay spi: incompatible with msm8996pro-xiaomi-scorpio.dtb
created 6803 symlinks in user environment

so I assumed it was working :man_shrugging: but I really have no idea what I’m doing :slight_smile: