trarbr
By default when you boot an RPi running Nerves it will output a lot of log
messages to the screen. Super useful when you’re in development, but not so
pretty when used for products that have a screen attached to the RPi. We have
one such product that we might migrate to Nerves, so we decided to figure out
how to put a fancy boot splash on the RPi.
This requires two things:
- Suppressing log output.
- Outputting an image to the screen.
I will start by explaining the general steps, and then follow up with a few
tips to enabling this only in production (so we keep all the useful log
messages for development devices). I’ve also made a branch off the official
Nerves RPi3 system with the changes described. The changes required are in
the two most recent commits
here. Go there if you need a TL;DR ![]()
Note that this requires customizing the official Nerves RPi system - if
you’re not sure what that means, check this out.
Suppressing log output
Both the RPi bootloader, the Linux kernel and our Nerves application will
output stuff (log messages and images) on screen by default. This can be
disabled by setting some options in the files config.txt and cmdline.txt,
which are generated by Buildroot. The settings are:
-
In
config.txtmake sure to setdisable_splash=1. This will disable the
boot rainbow. This is already set by default on the RPi3, so we actually
don’t need to do anything here. -
The kernel boot parameters must be adjusted to suppress log output. The
parameters are set in one long line in the filecmdline.txt. There’s two
ways to suppress the logout: a) quiet and redirect the console output or b)
disable the framebuffer console entirely.
a) Quiet and redirect console output
This is the less draconian approach. Instead of printing to tty1, we’ll
direct all output to tty3. This means the output will still be available,
but it won’t be on-screen by default. You can access it by switching to tty3
by clicking CTRL+ALT+F3. It’s not a perfect solution though. For some reason,
some of the output might still be printed on screen. Therefore, we also
minimize the amount of kernel output. To achieve this, ensure the following
options are set in cmdline.txt:
console=tty3 quiet loglevel=0 logo.nologo vt.global_cursor_default=0
The console= option is already specified as tty1 by default, so that has
to be updated. The other keys are new. Their meanings are:
quiet: Disables most log messages.loglevel=0: This sets the loglevel of the kernel. Setting it to 0 means it
only prints emergency level warnings.logo.nologo: This disables printing of the Raspberry Pi logos.vt.global_cursor_default=0: This disables the blinking cursor.
(A good reference to the kernel boot parameters can be found here:
(Linux Kernel Parameters)
We also need to make sure that the log output from our Nerves application goes
to tty3. This is done by setting -c tty3 in the erlinit.config file (by
default it is set to tty1).
All these settings will generally result in a silent boot, but I have read
that the Linux kernel may still print a few log messages to the screen. If
this is not acceptable, we must disable the framebuffer console instead.
b) Disable the framebuffer console
This is the more draconian method. Disabling the framebuffer console will
quelch all output, but it also means you can no longer interact with the
device using screen and keyboard. This is actually an added bonus for us, as
we don’t want that to be possible on production devices. So even though the
less draconian method worked for us, we chose to disable the framebuffer for
this reason.
Disabling the framebuffer console is done by setting the following to
cmdline.txt: fbcon=map:2. This will allocate the console to an
unavailable framebuffer (the RPi only has one framebuffer), effectively
disabling it. Thus, it replaces all the other options suggested above, and
you don’t need to update erlinit.config either.
Outputting an image to the screen
Buildroot has a package for a program called fbv, which can be used for
outputting an image to the screen. It does this by writing to the framebuffer
(I had no idea what that meant, but there is a nice explanation
here). It’s
not included by default by Nerves, so it must be added to the
nerves_defconfig file. You can do this through the Buildroot menuconfig
interface, or by adding the line BR2_PACKAGE_FBV=y to the file.
Once fbv has been added to the system, it must be invoked at boot. We can
do this by telling erlinit to invoke a script before starting the Erlang
VM. This is done by adding the following to the erlinit.config file:
--pre-run-exec "sh /splash.sh". The file splash.sh must be added to
the rootfs_overlay directory, and is a simple one-liner:
#! /bin/sh
# The call to fbv must be backgrounded, otherwise it blocks which means
# the Erlang VM won't boot
fbv /splash.png &
This call to fbv will render the image /splash.png to the framebuffer.
Thus, add an image with that name to the rootfs_overlay directory, and
you’re done.
Enabling it only in production
To enable this only in production, we need to have two different cmdline.txt files
available, one for production and one for development. Thus, you will need two files,
cmdline-dev.txt and cmdline-prod.txt. cmdline-dev.txt should be a copy of the
current cmdline.txt, while cmdline-prod.txt should be modified to either suppress
the kernel logs or disable the framebuffer console, as described above.
To ensure the right cmdline.txt file is used depending on the value of
MIX_ENV, we’ll use that variable in fwup.conf to select the correct file
when generating firmware. Add a fallback definition of MIX_ENV and then
update the host path for the file:
...
#
# Firmware metadata
#
define(MIX_ENV, "${MIX_ENV:-dev}") # Add this line
...
file-resource cmdline.txt {
host-path = "${NERVES_SYSTEM}/images/cmdline-${MIX_ENV}.txt" # Update this line
}
...
Next, we’ll also add a firmware variable with the content of MIX_ENV.
This will be used to check whether the splash screen is to be rendered or not.
Add a line in the complete task in fwup.conf:
...
task complete {
...
uboot_setenv(uboot-env, "nerves_fw_devpath", ${NERVES_FW_DEVPATH})
uboot_setenv(uboot-env, "mix_env", ${MIX_ENV}) # Add this line
uboot_setenv(uboot-env, "a.nerves_fw_application_part0_devpath", ${NERVES_FW_APPLICATION_PART0_DEVPATH})
...
}
...
Then update the splash.sh script to check the mix_env variable:
#! /bin/sh
if fw_printenv | grep -q "mix_env=prod"; then
# The call to fbv must be backgrounded, otherwise it blocks which means
# the Erlang VM won't boot
fbv /splash.png &
fi
And you’re done! If in doubt, you can see all the changes you need to make on
the two most recent commits here.
Extras
Of course, we’re never really done. One could also consider
- Rotating the splash screen to support upright screens. This can be done
with a firmware variable. - Add a requirement to firmware upgrades that their
MIX_ENVvariable
matches what is stored inmix_env.
Trending in Discussions
Other Trending Topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #library
- #deployment
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #elixirconf
- #channels
- #exunit
- #discussion
- #code-sync
- #podcasts
- #javascript
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixirconf-us
- #ai
- #blog-post
- #elixir-ls
- #phoenix_html
- #iex
- #graphql
- #genstage
- #websockets
- #supervisor
- #advent-of-code
- #distillery
- #processes
- #api
- #forms
- #hex
- #security
- #metaprogramming










Showing Posts 1 to 8- Show Best Posts
- Show All (oldest first)
- Show All (newest first)
lawik
This is great stuff. I’ve had it in my “you should read this”-notes for a while. It did not disappoint.
Do you think this would be a reasonable feature to work into the core Nerves systems? I figure the fbv package is a very minor addition, probably not very heavy.
The support for different cmdline.txt files might be more significant as well as the details of when to actually invoke the splash and stuff and when that code-path is desirable or not.
I think a lot of people want to do this both for production and DIY fun stuff. For businesses I think it is fairly expected that you might need a custom system. I can’t quite shake the feeling that this would be slick in the default Nerves system, could even start with a nerves logo
I also imagine it straddles the line of how many batteries the base install should include, so I expect opinions would fall on both sides of this particular fence.
Have you discussed that at all?
trarbr
Thanks, I’m happy it didn’t disappoint.
I have not talked with the Nerves team about this. fbv is pretty small, and it only depends on a few other small things like libpng and libjpeg. But the standard Nerves systems are pretty bare-bones so I don’t know if they want it in there - if they add this, why not X and Y as well?
One could also implement fbv in Elixir and then it would only require adding a library
samuelventura
Thank you for this great guide.
This is how it looks for me: https://photos.app.goo.gl/zdL84EwMoqyidph66
Any idea on how to improve on the following?
Thanks again.
trarbr
Hi @samuelventura, I’m glad you found the guide useful
Unfortunately, I don’t really have any ideas regarding the flash. I don’t remember if our devices have that flash, and I don’t have one at hand for testing right now. What hardware is your system based on, and what bootloader are you using?
I also don’t have any experience with using the kernel to show a splash screen. I only know that it requires the image to be formatted a certain way, and I am not sure what changes (if any) need to be made to the kernel/Buildroot system. I did find this article which seems to have some good info: Splash Screen on the Linux Kernel | Toradex Developer Center. However, it is for a Yocto-based system, not Buildroot.
outlog
I would try enabling psplash (BR2_PACKAGE_PSPLASH_IMAGE) and get that going..
but totally don’t know if it will work - see docs here buildroot/package/psplash/Config.in at 7ab915fe4cc14583df29d27c2ebe9be602d7df74 · buildroot/buildroot · GitHub
you might need to start it:
and potentially quit it as well:
if it works then config a custom png see package/psplash: add support to psplash personalized png image · buildroot/buildroot@7ab915f · GitHub
the default png is here https://git.yoctoproject.org/psplash/plain/base-images/psplash-poky.png
samuelventura
I am using a customized Nerves RPI3 System on an RPI CM3+ based industrialized HMI. The nerves system customization enables wifi drivers, sync, realtime clock, among other things. I great experience so far. Nerves makes it very straight forward.
A couple of videos (Spanish audio) of the custom HMIs we are building for industrial customers.
* HMI Demo 1
* HMI Demo 2
It is booting in around 20s and half of that time is blank screen. Having an early splash would easy out that wait.
Thank you for the link about the kernel based splash. I will look into it.
samuelventura
Hey uotlog. I found psplash to be much more powerful and complex for what I need and hence I went for the fbv option. Also, psplash is userland as well right? So it would launch at the same time nerves erlinit currently launches my fbv solution. Thank you for your suggestion. Let me know if any of my assumtions is wrong to try it out.
trarbr
Cool, thanks for sharing the videos.