The radio / photo frame
Note: I did all this about 6 months ago, the details are a bit fuzzy in my memory. I wish I had taken better notes, but I remember getting frustrated more than once, and my note taking suffered quite a bit then.
For the past few year, I’ve been using a Raspberry Pi to play music at home.
To be precise:
- when at home I use a mobile browser on my phone to open a web page hosted on the Raspberry
- clicking on the links spawns a VLC command which streams the audio output to a Chromecast.
I mentioned that in this article, except I totally ditched the “ok Google” part.
Too many pies
And since November last year, I was also using every day the A/C Remote Solution I built in 2022, using 3 Raspberry Pi Zero W.
But things changed when we moved, no longer had A/C (nor the need for it), and now I have 3 Raspberry Pi Zero W sitting around. What to do with them? It seems like wasted hardware! My brother then showed me this LCD touchscreen which fits perfectly the Pi Zero and would give me an opportunity to play and be creative.
Two approaches
It was fairly easy to get the screen working, the instructions are decent and worked well.
Browser
My days as aLinux desktop user are far away and I haven’t really kept up with X.org vs. Wayland, but all in all I followed a few guide about how to setup a Raspberry Pi in “Kiosk Mode” and I was able to open Chrome and direct it to the page I needed.
The performance however was really unacceptable, not only for the startup time (which isn’t that important), but even for the reaction time to show the hourglass animation after I clicked on any station. There is very little I can do there, I’m using pretty basic javascript and nothing in the web page is complex, but with such low power and memory, that’s the name of the game.
I’ve tried a few other “lightweight” browsers and none worked much better.
Framebuffer
With a browser not doable, I could have looked into building/using something running on top of X or Wayland, but the main goal of this project was to have fun, so I decided to write something a little lower level, and interface with the frame buffer directly.
Setting up the toolchain
As in previous projects, I’m using Go and I was hoping this would mean that cross compilation would be a breeze.
I first thought of reusing prior art:
- gonutz’s framebuffer (
github.com/gonutz/framebuffer
) - or tjclement’s framebuffer-go (
github.com/tjclement/framebuffer-go
)
Both require using CGo, which makes sense for the ioctl
calls required to get the framebuffer’s current setting, and mmap
the file-to-buffer.
There are a bunch of tutorials out there on how to cross compile from Mac OS to Linux ARM, some/most of them suggest using a linux VM or a separate linux machine to build, and I originally didn’t want to do that. What I was hoping for is a true cross compilation from MacOS ARM (M2) to Linux ArmV6.
Trying directly
So I did try things:
brew install arm-linux-gnueabihf-binutils
- that actually doesn’t get you the cc compiler
- so
brew install gcc-arm-embedded
- it seems (and my understanding here is very limited) that the cross compiler is then for “none”, not “linux” architecture, and it won’t support -pthread
- Tried a couple of things Google/Gemini told me to try
I had to accept the fact that I was not going to build directly from Mac OS.
Let’s emulate a Rpi
I thought next best thing, since I’m not going to compile on the Pi Zero directly for obvious reasons, let’s emulate one, and make it “a little” faster.
So I looked at https://azeria-labs.com/emulate-raspberry-pi-with-qemu/. It’s using a very old image though, 2017. So trying to use something more recent, I probably lost a few hours there before giving up. At the end I’m not knowledgeable enough on QEMU to make this happen, and that’s not my project, just a means to an end.
During my journey, I stumbled upon https://github.com/dhruvvyas90/qemu-rpi-kernel/blob/master/README.md which made me thing I couldn’t just use a raspbian image anyway, it needs a different kernel. What a world!
Linux in a VM it is.
Ok, so I’ll use an Ubuntu VM. UTM is a good enough too to make that happen. I still wanted to edit directly on MacOS and it took me a little bit to get the sharing to work.
- virtfs was slow, very slow, and I was also foolishly sharing my ~/go directory
- I ended up using WebDav, but also really understood that sharing ~/go meant ~/go/bin was also going to be shared, which isn’t good as I do a bunch on things there directly on my Mac. Bad idea!
From my bash history, the rest of the process wasn’t too bad, essentially sudo apt-get install crossbuild-essential-armel
I’m now finding in my notes these 2 links:
- https://earthly.dev/blog/cross-compiling-raspberry-pi/
- This mentions “Creating a Raspbian Root File System”, I don’t think I had to do that at all
- https://manuel.bernhardt.io/posts/2022-11-04-rust-development-for-the-raspberry-pi-on-apple-silicon/
- Re-reading this now, I think I actually didn’t use any of this, but it’s a great read! And it’s now giving me ideas about vscode through SSH.
Another thing to have in mind is that your Linux VM and Raspbian need to be roughly on the same libc version.
Deployment script
Once I had it running well, I just had to create a quick script to build on the Linux VM and transfer to the pi.\
The important part here really is BUILD_CMD="GOARM=6 CC=arm-linux-gnueabi-gcc CGO_ENABLED=1 GOARCH=arm go build ."
#! /bin/bash
HERE=`pwd`
NAME=${HERE##*/}
DEBIAN_HOST="192.168.64.6"
DEBIAN_USER="bisounours"
DEBIAN_PWD="/home/bisounours/$NAME"
RPI_HOST="my-rpi-zero"
RPI_USER="pi"
BUILD_CMD="GOARM=6 CC=arm-linux-gnueabi-gcc CGO_ENABLED=1 GOARCH=arm go build ."
OUTPUT=$NAME
echo "Building"
echo ssh $DEBIAN_USER@$DEBIAN_HOST "cd ""$DEBIAN_PWD"" && $BUILD_CMD"
ssh $DEBIAN_USER@$DEBIAN_HOST "cd ""$DEBIAN_PWD"" && $BUILD_CMD"
if [ $? != 0 ]
then
echo "Build failed"
exit
fi
echo "Transferring"
DEST_BINARY_NAME=$NAME_`date +%Y%m%d%H%M%S`
[ -f "$OUTPUT" ] &&
scp "$OUTPUT" $RPI_USER@$RPI_HOST:$DEST_BINARY_NAME
if [ $? != 0 ]
then
echo "Transfer failed"
exit
fi
if [ "$1" = "--nolaunch" ]
then
echo "Not launching due to --nolaunch option"
exit 0
fi
echo "Launching with args $*"
ssh $RPI_USER@$RPI_HOST "./$OUTPUT $*"