I finally have rpi zero 2w prepared for my 3D printer.
However I figured out that it doesn’t work.
It doesn’t boot.
Extlinux created a boot menu, and during early boot, the printer sends some data over UART, which disturbs the boot process. The disturbance occurs because U-Boot is waiting for a key press (‘hit any key to…’). As a result, some garbage is shown on the screen when UART is connected to the printer and boot process is happy, because it received magical any key ;P.
I’m still playing with it (device trees and overlays, try to hack extlinux boot process…) but I’m running out of ideas.
I definitely overlooked something.
I just don’t want to get data from UART at this early boot to be processed by boot loader, then boot a system and after all that, OctoPrint can handle printer.
Quicky more hacky way is below.
Basically just change activation string from any key,
to semi random string disables parsing of garbage received via UART.
So U-boot seems to be solved. Now extlinux menu hack follows.
Download module generic-extlinux-compatible from NixOS.
Put disabledModules = [ "${modulesPath}/system/boot/loader/generic-extlinux-compatible" ]; into my copy of default.nix from generic-extlinux-compatible module.
Update extlinux-conf-builder.sh to propagate my changes (just remove part where MENU and TIMEOUT were used).
Put import ./stage2/extra-modules/generic-extlinux-compatible into my flake.nix.
Profit.
I’m able to boot Raspberry Pi Zero 2w inside my printer.
@marmolak hey, thanks for sharing your progress and the solution that ultimately worked for you.
I’m trying to achieve the same thing with a rpi3a+ connected via uart to a prusa mk3s. The uart “noise” is also interfering with the boot process.
I wasn’t successful in making it work with your solution though. uboot seems to build fine with the extra config, but when running it plugged into the printer it still accepts input from the printers uart and ends up stuck.
Would you mind sharing a complete snippet of how you tamed uboot? (flake, or deriv of the sd-card image build). Thanks!
P.S. I am assuming that changes to extlinux.conf are optional and not necessary for uboot to ignore input from uart, so I haven’t tried applying them.
You really need mess with extlinux.conf, because recompiled uboot ignores input but extlinux menu not (yeah, extlinux compatibility is part of uboot). So boot is interrupted by noise later at next step.
I just messed with only two lines here.
Hope it helps.
This hack remove possibility to boot older generations but I don’t use this
feature because rpi si buried in my printer without any input device nor display connected.
PS: it’s just not tested version of private repository.
I was able to get past u-boot without needing to change extlinux.conf. Just requiring a keyed autoboot was enough to make things working for me. (I still wanted the ability to go back a generation, if I take the RPi out of the printer for debugging). Here are the config variables I used:
(self: super: {
ubootRaspberryPi3_64bit = super.ubootRaspberryPi3_64bit.overrideAttrs (oldAttrs: {
extraConfig = ''
CONFIG_AUTOBOOT=y
CONFIG_AUTOBOOT_KEYED=y
CONFIG_AUTOBOOT_STOP_STR="\x0b"
CONFIG_AUTOBOOT_KEYED_CTRLC=y
CONFIG_AUTOBOOT_PROMPT="autoboot in 1 second (hold 'CTRL^C' to abort)\n"
CONFIG_BOOT_RETRY_TIME=15
CONFIG_RESET_TO_RETRY=y
'';
});
})
Still, I couldn’t get uart to function after loading the kernel. The device would show up, but it would neither send nor receive any data.
Interestingly, because I had hooked up a uart<->usb dongle to test things, I noticed that the input and output u-boot would send & receive would turn out to be garbled. I didn’t verify this, but I assume that data wasn’t being sent or received at the configured 115200 baud rate. I haven’t spent the effort to find out what was the actual baud rate, but I confirmed it wasn’t any other “standard” one.
I have not experienced any issues with using the official RPiOS 2022-09-22 (kernel 5.15.61).
A couple of minor notes:
removing enable_uart=1 in config.txt does not seem to have any effect in u-boot not using the uart interface
I have tried various approaches in trying to get u-boot to completely ignore the serial device. I couldn’t find success in changing the device trees, applying patches to the rpi env config, tweaking the CONFIG variables to ignore serial support (it either doesn’t work when running, or ends up with a myriad of compilation errors).
I’m happy to discover this thread. The last system I have left not yet converted to NixOS is an rpi3, currently running a getting-a-bit-too-old ubuntu. It has a GPS hat for NTP, and the serial data from the GPS causes exactly this issue with uboot.
The solution with ubuntu was to simply not use uboot; it just uses the standard raspberry pi boot loader directly. That config didn’t boot NixOS when I tried previously, leaving me with a choice between debugging a broken boot using a standard bootloader that’s for some reason considered not supported anymore, or digging into compiling uboot without serial because it apparently has no simple options to just leave the serial alone.
Thank you. I tested your solution and it’s much better :).
Yeah, I was hurry to learn how modules work.
BTW: I started to have issues with wifi after specific revision on my rpi zero 2w.
I fully reflashed SD card with new image but I only encounter same issue (no wifi configured).
Maybe your solution and generations can help me with debugging this issues.
Seems like extlinux module hack is needed.
I created some generations and after using only changes proposed into u-boot, i stuck on boot menu again :(.
Do you have similar results when another generation is created?
I just can’t talk to the printer via uart on nixos, plain and simple it just doesn’t work. I have not yet figured out why and I haven’t dedicated any more time to it.
Chiming in to say that I managed to get the fixed extlinux.conf into both the SD image and into a remote update via a nixos-rebuild --target-host ... with this below abomination:
{ pkgs, lib, config, ... }:
# This below abomination is just to uncomment the MENU TITLE and TIMEOUT lines in extlinux.conf,
# for which the generic-extlinux-compatible.nix package doesn't provide any mechanism, so we need to
# replicate the minimum here manually
# copied together from https://github.com/NixOS/nixpkgs/blob/c796e4e5ac7393b7ef397b4addb9091fe7a27cf6/nixos/modules/system/boot/loader/generic-extlinux-compatible/default.nix
let
blCfg = config.boot.loader;
dtCfg = config.hardware.deviceTree;
cfg = blCfg.generic-extlinux-compatible;
timeoutStr = if blCfg.timeout == null then "-1" else toString blCfg.timeout;
builderScript =
<nixpkgs/nixos/modules/system/boot/loader/generic-extlinux-compatible/extlinux-conf-builder.sh>;
fixedBuilderScriptName = "extlinux-conf-builder-no-interaction.sh";
fixedBuilderScript = pkgs.runCommand fixedBuilderScriptName { } ''
(
set -x
${pkgs.perl}/bin/perl -pe 's/^((?:TIMEOUT|MENU TITLE).*)$/# $1 # commented to ignore UART input during boot/g' ${builderScript} > $out
)
'';
mkFixedBuilder = { pkgs }:
pkgs.substituteAll {
src = fixedBuilderScript;
isExecutable = true;
path = [ pkgs.coreutils pkgs.gnused pkgs.gnugrep ];
inherit (pkgs) bash;
};
fixedBuilder = mkFixedBuilder { inherit pkgs; };
fixedPopulateBuilder = mkFixedBuilder { pkgs = pkgs.buildPackages; };
builderArgs = "-g ${toString cfg.configurationLimit} -t ${timeoutStr}"
+ lib.optionalString (dtCfg.name != null) " -n ${dtCfg.name}"
+ lib.optionalString (!cfg.useGenerationDeviceTree) " -r";
in {
system.build.installBootLoader =
lib.mkForce "${fixedBuilder} ${builderArgs} -c";
# This doesn't work because it's a readOnly property 🙄
# boot.loader.generic-extlinux-compatible.populateCmd =
# lib.mkForce "${fixedPopulateBuilder} ${builderArgs}";
# So we have to set this instead, hopefully this is the only place where it was used.
# https://github.com/NixOS/nixpkgs/blob/c796e4e5ac7393b7ef397b4addb9091fe7a27cf6/nixos/modules/installer/sd-card/sd-image-aarch64.nix
sdImage.populateRootCommands = lib.mkForce ''
mkdir -p ./files/boot
${fixedPopulateBuilder} ${builderArgs} -c ${config.system.build.toplevel} -d ./files/boot
'';
# We need to recompile the u-boot bootloder, because apparently it doesn't have a config file where bootdelay=-2 can be set.
# At least I didn't find any. But we need to disable that the boot menu listens to UART input, because the dji drone sends garbage via it
# and interrupts the autoboot. Setting bootdelay=-2 for u-boot is *one* step towards this - extlinux.conf also must not have the MENU TITLE and TIMEOUT set.
# adapted from https://discourse.nixos.org/t/rpi-zero-2w-in-prusa-3d-printer-aka-data-received-via-uart-over-gpio-disturbs-the-boot-process/36133/9?u=nobodyinperson
nixpkgs.overlays = [
(final: prev: {
# The u-boot for rpi3 is also used for the rpi0
# (see https://github.com/NixOS/nixpkgs/blob/70bdadeb94ffc8806c0570eb5c2695ad29f0e421/nixos/modules/installer/sd-card/sd-image-aarch64.nix)
# where the [rpi02] section (should be rpi02w actually, right!?) specifies kernel=u-boot-rpi3.bin and below that comes from the ubootRaspberryPi3_64bit package
ubootRaspberryPi3_64bit = prev.ubootRaspberryPi3_64bit.overrideAttrs
(oldAttrs: {
extraConfig = ''
CONFIG_AUTOBOOT=y
CONFIG_BOOTDELAY=-2
'';
});
})
];
}
It really is massively inconvenient that boot.loader.generic-extlinux-compatible doesn’t have a mechanism to remove these two stupid lines…