Trying to compile a .dts file and add the .dtbo output file to BalenaOS to enable external SD Card

Hi

Basically I’m trying to use an external SD card with my RPI CM4. Note: I am using an RPI CM4 with internal emmc memory hosting BalenaOS, so the SD card should only be used as external mass storage.

Following these steps, we cannot simply add dtoverlay=sdio to the /boot/config.txt file because this will enable the sdio interface but disable WiFi and Bluetooth too. So I follow the steps in the link above to compile a new .dts file and add the .dtbo output file to the /boot/overlays folder and then add the dtoverlay=sd0,sdio_overclock=50 to the /boot/config file. txt.

The following steps work correctly on RPI CM4 using raspbian OS and I was able to see and use the external SD card.

1) Write a sd0-overlay.dts file:

/*
 * Device tree overlay for enabling SD0 using the sdhost interface on GPIOs 22-27
 */

/dts-v1/;
/plugin/;

/{
    compatible = "brcm,bcm2711";

    fragment@0 {
        target = <&sdhost>;
        frag0: __overlay__ {
            pinctrl-names = "default";
            pinctrl-0 = <&sdhost_pins>;
            bus-width = <4>;
            brcm,overclock-50 = <0>;
            brcm,pio-limit = <1>;
            status = "okay";
        };
    };

    fragment@1 {
        target = <&gpio>;
        __overlay__ {
            sdhost_pins: sdhost_pins {
                brcm,pins = <22 23 24 25 26 27>;
                brcm,function = <4 4 4 4 4 4>; /* ALT0: SD0 */
                brcm,pull = <0 2 2 2 2 2>; /* pull up all except clk */
            };
        };
    };

    __overrides__ {
        overclock_50 = <&frag0>,"brcm,overclock-50:0";
        force_pio = <&frag0>,"brcm,force-pio?";
        pio_limit = <&frag0>,"brcm,pio-limit:0";
        debug = <&frag0>,"brcm,debug?";
    };
};

2. Compile the d0-overlay.dts

sudo dtc -@ -I dts -O dtb -o ./sd0.dtbo /tmp/sd0-overlay.dts

3. Add the .dtbo file to /boot/overlays folder and add the dtoverlay to /boot/config.txt

dtoverlay=sd0,overclock_50=50

4. Reboot the device

Problems using BalenaOS
The problem starts when I try to do something similar with BalenaOS. To configure this on BalenaOS I tried to create a new service/container to run only once to compile the .dts file and add the .dtbo file on the host aka BalenaOS in /mnt/boot/overlays and the dtoverlay in /mnt/ boot /config.txt.

Check the dockerfile, setup-overlay.sh and docker-compose.yml below:

Dockerfile:

FROM balenalib/aarch64-debian-python:latest-bullseye-build

RUN install_packages \
    build-essential \
    device-tree-compiler

# Clean up APT when done
RUN apt-get clean && rm -rf /var/lib/apt/lists/*

# Create overlay file to MicroSD Card 
# Copy the setup script into the container
COPY ./setup-sd0-overlay.sh /usr/src/app/setup-overlay.sh
# Give execute permissions to the script
RUN chmod +x /usr/src/app/setup-overlay.sh

# Set our working directory
WORKDIR /usr/src/app

# main.py will run when container starts up on the device
CMD ["/usr/src/app/setup-overlay.sh"]

setup-overlay.sh script:

#!/bin/bash

# Step 1: Create the sd0-overlay.dts file
cat <<EOL > /tmp/sd0-overlay.dts
/*
 * Device tree overlay for enabling SD0 using the sdhost interface on GPIOs 22-27
 */

/dts-v1/;
/plugin/;

/{
    compatible = "brcm,bcm2711";

    fragment@0 {
        target = <&sdhost>;
        frag0: __overlay__ {
            pinctrl-names = "default";
            pinctrl-0 = <&sdhost_pins>;
            bus-width = <4>;
            brcm,overclock-50 = <0>;
            brcm,pio-limit = <1>;
            status = "okay";
        };
    };

    fragment@1 {
        target = <&gpio>;
        __overlay__ {
            sdhost_pins: sdhost_pins {
                brcm,pins = <22 23 24 25 26 27>;
                brcm,function = <4 4 4 4 4 4>; /* ALT0: SD0 */
                brcm,pull = <0 2 2 2 2 2>; /* pull up all except clk */
            };
        };
    };

    __overrides__ {
        overclock_50 = <&frag0>,"brcm,overclock-50:0";
        force_pio = <&frag0>,"brcm,force-pio?";
        pio_limit = <&frag0>,"brcm,pio-limit:0";
        debug = <&frag0>,"brcm,debug?";
    };
};
EOL

# Step 2: Compile the overlay
sudo dtc -@ -I dts -O dtb -o ./sd0.dtbo /tmp/sd0-overlay.dts


# Clean up
rm /tmp/sd0-overlay.dts

Dockercompose.yml:

version: "2"
services:
  setup-rpi:
    build: ./setup-rpi
    volumes:
      - "/mnt/boot/overlays:/mnt/boot/overlays"
    privileged: true

However, when I tried to build the docker:

balena push <my-fleet>

I got the following error:

“Bind mounts are not allowed”.

It seems that Balena does not allow us to change the hostOS directly.

Alternatively, I ran docker on my laptop, used the same BalenaOS image and created the .dts file and compiled it to generate the .dtbo file. I then connected to my device running BalenaOS using ssh and ran a secure copy (scp) to copy the .dtbo file to the /mnt/boot/overlays directory and rebooted the system. However, even this attempt did not work. If I run the command below on hostOS:

dmesg | grep mmc 

I got the errors:

mmc2: error -22 whilst initialising SD card

mmc2: invalid bus width

How to solve this problem to hostOS detect the external SD Card?

The problem to escalate our fleet:
My client already has +30 devices on the market and we intend to deliver 300 more by the end of the year but from what I understand with all these problems is that there is no easy way to update hostOS for the entire fleet simultaneously. The only solution I’m seeing:

  1. An employee will travel across the country to update BalenaOS on all devices already shipped.

  2. Write a script to check all uuids of online devices and then one-by-one:

i) open a tunnel:

balena tunnel <device-uuid> -p 22222:4321

ii) secure copy through the tunnel to copy .dtbo file to /mnt/boot/overlays

scp -P 4321 /path/to/local/file root@127.0.0.1:/mnt/boot/overlays

We have seen the same issue for the cellular network, where we have to make changes to the network interface to allow cellular communication via the usb0 interface, but it appears there is no easy way to make a change in the hostOS on all devices already in the field simultaneously.

NOTE: the devices in the field already have all the necessary hw, it’s just a matter of updating Balena OS. To speed-up time-to-market we shipped the devices with all required hardware and now we are gradually enabling new features which requires changes in BalenaOS.

What I’m going to say now may be an exaggeration, but I found myself developing fleet management for Balena’s own fleet management to ensure I can make changes in hostOS running in the devices.

Is there something I’m not quite understanding how BalenaOS works and its features?