2024.08.06

Beepy + Radxa Zero Notes

Beepy is a handheld Linux device, with a Blackberry-like keyboard and monochrome Sharp Memory LCD. It's normally powered by a Raspberry Pi Zero W.

This document contains my notes for swapping out the Raspberry Pi Zero for a Radxa Zero instead.

Why Radxa Zero over Raspberry Pi Zero?

Raspberry Pi is great, but not ideal for handheld, battery-powered devices. Raspberry Pi doesn't implement suspend to RAM or hibernate, due to various reasons related to the boot chain and Broadcom's closed first stage boot. Additionally, the Pi also doesn't have a good concept of a poweroff state. The Pi draws significant current even in "poweroff", and there is also no way to initiate boot from poweroff outside of cycling the power.

These limitations are fine for a lot of projects, but isn't a great fit for Beepy, which is trying to be a chat device that can stay idle for days/weeks at a time. To address this, Beepy has a management MCU (RP2040), which performs power management in addition to providing keyboard support. The MCU controls the power rail to the Pi, solving the issue of the Pi's quiescent current draw in poweroff. The MCU also sequences power on based on the power key, or an RTC-based timer. The concept is to optimize the Pi's Linux boot times, and have the MCU periodically boot it to quickly check for messages before powering off again. Since the display is a Sharp Memory LCD, notifications and alerts can remain on the screen, even in this soft shutdown state.

Still, it would be great if we could just... have working suspend and hibernate instead of dealing with all this. The Radxa Zero uses an Amlogic SoC that supports suspend and hibernate, and the goal of this project is to see if we can get acceptable suspend power draw with it.

None of this stuff is really polished, but it should generally work for day-to-day use. Suspend power still needs to be investigated and optimized, but worst case, you can just enter shutdown and be at feature parity with the Raspberry Pi Zero. :)

Buying

Radxa Zero

You want a SKU that doesn't come with the headers pre-soldered, so it can mate with the Beepy pogo pins.

I purchased mine from Allnet, an official Radxa distributor.

I wasn't able to get eMMC boot working with Armbian, so YMMV if you want the larger eMMC models.

Antenna

All the SKUs without headers seem to also only have external antenna. Any small 2.4/5 GHz flex antenna with a U.FL connector should work. I bought this one off Digi-Key.

OS Setup

I'm running Armbian 23.11 Bookworm. I haven't tested on later releases, so use a newer major release at your own risk.

If you have an eMMC model, follow the instructions to erase the eMMC to enable microSD boot.

Flash the system image to the microSD card and boot as usual.

You won't have Beepy keyboard or display support at this point, so a micro-HDMI cable and USB-C hub will come in handy here. Once you have Wi-Fi and SSH set up, you can just SSH in for subsequent boots.

Install Kernel Modules

There are two kernel modules to install, for display and keyboard support. These are forked from the Beepy drivers. The main changes are to provide Radxa Zero Device Tree configs and modify the Makefile to build and install on Armbian.

The following steps should be performed on your Radxa Zero.

Dependencies

apt install linux-headers-current-meson64

Display Driver

git clone https://github.com/Hylian/sharp-drm-driver.git
cd sharp-drm-driver
make
make install

Troubleshooting

Once the driver is loaded, you should see a framebuffer device show up at /dev/fb0. Writing to this device should update the screen (e.g. cat /dev/random > /dev/fb0).

If you aren't seeing the TTY show up on the display, your fbcon mapping may be incorrect. The Makefile install target adds a fbcon boot arg to /boot/armbianEnv.txt, with an fbcon mapping that worked for me. Try modifying /boot/armbianEnv.txt with a different mapping and reboot. If you only see console messages without a TTY appearing, you are probably in this state.

Keyboard Driver

git clone https://github.com/Hylian/beepberry-keyboard-driver.git
cd beepberry-keyboard-driver
make
make install

Finishing up

Reboot your device.

Developing

One-liner to rsync and install:

rsync -a ~/dev/beepy/beepberry-keyboard-driver root@radxa-wifi.local:~/ && ssh root@radxa-wifi.local "cd ~/beepberry-keyboard-driver && make && make install && rmmod beepy_kbd && modprobe beepy_kbd"

Quirks and Tweaks

My Beepy randomly suspends while typing!

This may happen when you try to type - (Alt + i). This is because the Beepy MCU firmware emits keycode 142 for that key, which then gets mapped to minus in the keyboard map. Keycode 142 collides with KEY_SLEEP.

Fix

Configure logind to ignore the sleep key.

How do I suspend?

The systemctl suspend command will put the Radxa into suspend. You should see the cursor stop blinking, and the system will resume upon any keypress. You can also check dmesg to confirm that it entered suspend.

Can I remap the power key to suspend?

Yes, you can modify the keyboard driver. Change this line to instead invoke systemctl suspend. Then configure the kernel module to handle poweroff in-driver. The power button long press event from firmware should now invoke suspend.

Shutting down from shell should still work fine, as when the keyboard driver is unloaded during poweroff, it informs the MCU. The MCU should enter deep sleep and power on the Radxa like normal on the next power button press.

How do I measure battery state of charge?

These sysfs exports are available via the keyboard driver:

/sys/firmware/beepy/battery_raw

/sys/firmware/beepy/battery_volts

/sys/firmware/beepy/battery_percent

Note that the model used for battery percentage is pretty rough, and may not be accurate.

Optimizing Power

Power Measurements

(08/24): Measured with a USB power meter, battery unplugged.

RadxaRP2040Watts
ActiveActive0.8W
SuspendActive0.45W
SuspendDeep SleepTODO
PoweroffDeep Sleep0.05W

According to the measurements in the RP2040 repo, MCU active draws 0.125W, so Radxa in suspend should be contributing 0.275W power draw.

That means in suspend, we'll draw: (Radxa_suspend + RP2040_deepsleep) = (275mW + 25mW) = 300mW

Beepy battery is 7.4Wh, so total suspend time should be: (7.4Wh/300mW) = 24.67 hours