Flashing

This page explains how to flash an Ox64 board and a microSD card to boot the system. You will need a Linux machine, a serial UART adapter, the Ox64 board, and a microSD card.

Prepare images for flashing

Download the Ox64 images from the latest OpenBouffalo release. You may skip this whole section if you built your own images as per the instructions in the Building page.

mkdir -p ~/ox64/openbouffalo
cd ~/ox64/openbouffalo
wget https://github.com/openbouffalo/buildroot_bouffalo/releases/download/v1.0.1/bl808-linux-pine64_ox64_full_defconfig.tar.gz
tar -xvzf bl808-linux-pine64_ox64_full_defconfig.tar.gz
cd ~/ox64/openbouffalo/firmware
xz -v -d -k sdcard-pine64_ox64_full_defconfig.img.xz
mv sdcard-pine64_ox64_full_defconfig.img sdcard.img

Optional: create a combined SoC image

Use the following commands to combine m0_lowload_bl808_m0.bin, d0_lowload_bl808_d0.bin, and bl808-firmware.bin into a single image. This is mainly useful for troubleshooting (e.g. when using DevCube v1.8.4 or later).

cd ~/ox64/openbouffalo/firmware

fallocate -l 0x800000 bl808-combined.bin
dd conv=notrunc if=m0_lowload_bl808_m0.bin of=bl808-combined.bin
dd conv=notrunc if=d0_lowload_bl808_d0.bin of=bl808-combined.bin seek=$((0x100000))B
cat bl808-firmware.bin >> bl808-combined.bin

Check that you have the required files for flashing

cd ~/ox64/openbouffalo/firmware
ls *808*.bin *.img

Expected files:

  • sdcard.img — Kernel and root filesystem. Runs on the D0 core.

  • m0_lowload_bl808_m0.bin — Startup code for the M0 core.

  • d0_lowload_bl808_d0.bin — Startup code for the D0 core.

  • bl808-firmware.bin — OpenSBI and UBoot DTB files. Runs on the D0 core.

  • bl808-combined.bin — if you created the combined image

Set up your UART adapter

In this section we will configure and wire up a UART adapter in order to flash the Ox64. Choose one of the options below based on the hardware available to you; the first two are the most convenient since they minimise the number of times you will need to swap electrical connections.

Option 1: Raspberry Pi Pico

First, download the Raspberry Pi Pico firmware that allows it to act as a serial UART adapter.

mkdir -p ~/ox64/pico
cd ~/ox64/pico
wget https://github.com/Kris-Sekula/Pine64_Ox64_SBC/raw/main/uart/picoprobe.uf2

Put the Raspberry Pi Pico board into programming mode.

  • Press the BootSel button

  • Apply power by plugging the USB cable to PC

  • Release the BootSel button

As an alternative to pressing the BootSel button, you can also connect the probe point TP6 (located on the bottom of the Pico board) to any ground point (e.g. pin 28).

The Pico will now appear as a USB mass storage device. Copy the UF2 file to program it.

cp ~/ox64/pico/picoprobe.uf2 /media/<user>/RPI-RP2

Next, connect the Ox64 board to the Pico according to the following wiring diagram.

OX64                      PI PICO         /dev/tty
uart0_Tx_GPIO14_pin1 <->  uart0_Rx_pin17  ACM1 for flashing
uart0_Rx_GPIO15_pin2 <->  uart0_Tx_pin16  ACM1 for flashing
Rxd_GPIO17_pin31     <->  uart1_Tx_pin6   ACM0 for serial console
Txd_GPIO16_pin32     <->  uart1_Rx_pin7   ACM0 for serial console
gnd_pin38            <->  gnd_pin38/3
vbus5v_pin40         <->  vbus5v_pin40

With the Pico flashed and wired as per the instructions above, we have access to two of the Ox64’s UART connections at the same time. This configuration eliminates the need to switch the physical connections for flashing or testing the system.

Reconnect the Pico to your computer’s USB port and verify that we have access to all the serial ports we need.

ls /dev/ttyACM*

Expected result:

  • /dev/ttyACM0 connects to the D0 core’s (i.e. Linux’s) serial console

  • /dev/ttyACM1 is used for flashing (but also connects to the M0 core’s serial console)

Option 2: STM32 Bluepill

The Bluepill is an affordable STM32 development board, based on the STM32F103C8T6 chip. We can program it to act as a USB serial adapter, just like we did with the Raspberry Pi Pico.

The one catch is that you already need a serial adapter in order to program your Bluepill board. The good news is that you serial adapter does not have to be one from from the Compatible_UARTs list. If you own an SWD-capable debugger (ST-Link, J-link, etc.), you can use that for programming the Bluepill as well.

Download the Bluepill Serial Monster firmware.

mkdir -p ~/ox64/bluepill
cd ~/ox64/bluepill
wget https://github.com/r2axz/bluepill-serial-monster/releases/download/v2.6.4/bluepill-serial-monster.hex
sudo apt install stm32flash

Put the Bluepill into programming mode.

  • Set boot jumpers for booting from rom: Boot0=1, Boot1=0.

  • Connect it to a USB-Serial adapter with A9 to Rx, A10 to Tx, GND to GND, 3v3 to Vcc.

  • Apply power by plugging the USB cable to PC. Press the Reset button.

Upload the firmware. Replace /dev/ttyUSB0 with the device path of your USB serial adapter.

cd ~/ox64/bluepill
stm32flash -w  bluepill-serial-monster.hex /dev/ttyUSB0

After upload, set boot jumpers for boot from flash: Boot0=0, Boot1=0. Remove the USB serial adapter.

Next, connect the Ox64 board to the Bluepill according to the following wiring diagram.

OX64                      Bluepill      /dev/tty
uart0_Tx_GPIO14_pin1 <->  uart0_Rx_A3   ACM1 for flashing
uart0_Rx_GPIO15_pin2 <->  uart0_Tx_A2   ACM1 for flashing
Rxd_GPIO17_pin31     <->  uart1_Tx_A9   ACM0 for serial console
Txd_GPIO16_pin32     <->  uart1_Rx_A10  ACM0 for serial console
gnd_pin38            <->  GND
vbus5v_pin40         <->  5V

With the Bluepill flashed and wired as per the instructions above, we have access to two of the Ox64’s UART connections at the same time. This configuration eliminates the need to switch the physical connections for flashing or testing the system.

Connect the Bluepill to your computer’s USB port and verify that we have access to all the serial ports we need.

ls /dev/ttyACM*

Expected result:

  • /dev/ttyACM0 connects to the D0 core’s (i.e. Linux’s) serial console

  • /dev/ttyACM1 is used for flashing (but also connects to the M0 core’s serial console)

  • /dev/ttyACM2 (unused)

Option 3: Generic UART adapter

Check that you serial adapter is on the Compatible_UARTs list. You will (most likely) only have one serial interface available to you. For the purposes of this guide, let’s say it is /dev/ttyUSB0.

In addition, you will need a way of powering your Ox64. If your serial adapter has a 5V line, you can connect it to VBUS (pin 40). Otherwise, you can connect either the micro-B or the USB-C port on the Ox64 to any 5V power supply.

Refer to the pinout image below. Connect your UART adapter as follows.

  • RX → UART0_TX / GPIO14 / pin 1

  • TX → UART0_RX / GPIO15 / pin 2

  • GND → any ground (e.g. pin 3)

Proceed with the instructions in the sections that follow, up to and including Flashing the Ox64 and Flashing the microSD card, but replace all occurrences of /dev/ttyACM1 with /dev/ttyUSB0.

Next, power off the Ox64 and re-connect your UART adapter as follows.

  • RX → TXD / GPIO16 / pin 32

  • TX → RXD / GPIO17 / pin 31

  • GND → any ground (e.g. pin 33)

Then, follow the instructions in Booting for the first time, but replace all occurrences of /dev/ttyACM0 with /dev/ttyUSB0. You should then have a working Linux system.

Ox64 pinout

Download flashing tools

You have a choice of flashing software:

  • DevCube: GUI-based closed source flashing tool

  • CLI (bflb-iot-tool): command line open source flashing tool

CLI packages installation

Install bflb-iot-tool using your preferred method of managing PIP packages. One option is to set up a Python virtual environment as follows.

sudo apt install python3-venv
python3 -m venv ~/ox64_venv
. ~/ox64_venv/bin/activate
pip install bflb-iot-tool # we are *not* using bflb-mcu-tool
Each time you open a new terminal window you will need to re-run . ~/ox64_venv/bin/activate to reactivate the virtual environment.

DevCube installation

Download the latest DevCube flashing tool from BouffaloLab’s website.

mkdir -p ~/ox64/devcube
cd ~/ox64/devcube
wget https://dev.bouffalolab.com/media/upload/download/BouffaloLabDevCube-v1.8.9.zip
unzip BouffaloLabDevCube-v1.8.9.zip
chmod u+x BLDevCube-ubuntu

If you did not create a combined image you may need an older version of the DevCube. In that case, download v1.8.3 from one of the mirrors below.

Verify that your copy of BouffaloLabDevCube-v1.8.3.zip matches the hashes below.

  • SHA1: 0f2619e87d946f936f63ae97b0efd674357b1166

  • SHA256: e6e6db316359da40d29971a1889d41c9e97d5b1ff1a8636e9e6960b6ff960913

Flashing the Ox64

Put the Ox64 into programming mode.

  • Press the BOOT button

  • Apply power or re-plug the USB cable

  • Release the BOOT button

CLI flashing method

Set up some environment variables to save typing them out later.

PORT=/dev/ttyACM1 # or /dev/ttyUSB0, this will depend on which serial adapter you use
BAUD=230400       # safe value for macOS, if using Linux set to 2000000 for faster flashing

Change directory to the location of your image files.

cd ~/ox64/openbouffalo/firmware # if you downloaded pre-built images
# or
cd ~/ox64/buildroot/output/images # if you built your own images

Finally, flash the Ox64. If you created a combined image then run the command below.

bflb-iot-tool --chipname bl808 --interface uart --port $PORT --baudrate $BAUD --addr 0x0 \
              --firmware bl808-combined.bin --single

Otherwise, run the following commands.

bflb-iot-tool --chipname bl808 --interface uart --port $PORT --baudrate $BAUD --addr 0x0 \
              --firmware m0_lowload_bl808_m0.bin --single
bflb-iot-tool --chipname bl808 --interface uart --port $PORT --baudrate $BAUD --addr 0x100000 \
              --firmware d0_lowload_bl808_d0.bin --single
bflb-iot-tool --chipname bl808 --interface uart --port $PORT --baudrate $BAUD --addr 0x800000 \
              --firmware bl808-firmware.bin --single

If you get permission errors when running any of the commands above, you may need to add your user to the dialout group. Running the commands as root is not recommended since this will make bflb-iot-tool create root-owned files in your home directory.

BLDevCube flashing method

Open a new terminal window to run the DevCube flasher.

cd ~/ox64/devcube
./BLDevCube-ubuntu

Select chip [BL808], press Finish, and configure BOTH the [MCU] and [IOT] tabs as follows. When you switch between tabs double check that they still match the settings below.

Interface: UART
Port/SN: /dev/ttyACM1 or /dev/ttyUSB0 (make sure you don't use /dev/ttyACM0, it's used by the minicom console)
Uart rate 230400 (safe value for macOS, if using Linux set to 2000000 for faster flashing)

If you created a combined image then you only need to use the [IOT] tab.

Enable 'Single Download'
Image Address [0x0], [PATH to bl808-combined.bin]
Click 'Create & Download' and wait until it's done
Close DevCube

Otherwise, start in the [MCU] tab.

M0 Group[group0], Image Address [0x58000000], [PATH to m0_lowload_bl808_m0.bin]
D0 Group[group0], Image Address [0x58100000], [PATH to d0_lowload_bl808_d0.bin]
Click 'Create & Download' and wait until it's done

Then, switch to the [IOT] tab.

Enable 'Single Download'
Image Address [0x800000], [PATH to bl808-firmware.bin]
Click 'Create & Download' again and wait until it's done
Close DevCube

Flashing the microSD card

Insert the microSD card into your PC, locate its device file (/dev/sdb, for example), and write the image.

cd ~/ox64/openbouffalo/firmware # if you downloaded pre-built images
# or
cd ~/ox64/buildroot/output/images # if you built your own images
sudo dd if=sdcard.img of=/dev/sdb bs=1M status=progress conv=fsync

Booting for the first time

Power off your Ox64 and insert the microSD card.

Open a terminal window to connect to the D0 core’s (i.e. Linux’s) serial console.

minicom -b 2000000 -D /dev/ttyACM0

If you are using a Pico or Bluepill as your serial interface, open another terminal window to to monitor the M0 core’s serial console (reminder: /dev/ttyACM1 is the same port we previously used for flashing).

minicom -b 2000000 -D /dev/ttyACM1

Re-apply power to the Ox64.

On the ttyACM0 console you will see Linux booting up. When prompted, log in as root with no password. In case the SD card is missing or empty, you’ll get a Card did not respond to voltage select! : -110 error.

On the ttyACM1 console you’ll see following log, until the sytem is fully loaded.

[I][MBOX] Mailbox IRQ Stats:
[I][MBOX] Peripheral SDH (33): 0
[I][MBOX] Peripheral GPIO (60): 0
[I][MBOX] Unhandled Interupts: 0 Unhandled Signals 0

Once the system is running you’ll be able to manage the M0 multimedia core, i.e. wifi settings, etc. When prompted, type help to see available commands.

Connecting the Ox64 to your WiFi netowrk

The simplest way to connect is to run the following command from the Linux console (i.e. /dev/ttyACM0).

blctl connect_ap YourSSID YourPassword

Wait for it to connect (if you’re monitoring the M0 console on /dev/ttyACM1 it should tell you when it’s done), then run the following command from the Linux console.

udhcpc -i bleth0

Unfortunately the WiFi range leaves something to be desired. When you are performing the procedure above for the first time, move the Ox64 right next to your router. Once you are successfully connected, you can try experimenting with the maximum range.

For more information on using the blctl command, see here.

Appendix

Adding Nuttx RTOS

In this section, we will set up our Ox64 to dual-boot both Linux and the NuttX real-time operating system. For more information see the official documentation.

First, write the normal Linux image to the SD card if you have not done so already. For the purposes of this guide we will assume the SD card’s device file is /dev/sdb.

cd ~/ox64/openbouffalo/firmware # if you downloaded pre-built images
# or
cd ~/ox64/buildroot/output/images # if you built your own images
sudo dd if=/sdcard.img of=/dev/sdb bs=1M conv=fsync status=progress

Run the following command to re-read the partition tables. Re-inserting the SD card works too.

sudo blockdev --rereadpt /dev/sdb

Download the NuttX image.

mkdir -p ~/ox64/nuttx
cd ~/ox64/nuttx
wget -O ImageNuttx https://github.com/lupyuen2/wip-pinephone-nuttx/releases/download/bl808d-1/Image

Mount the boot partition and make the required modifications.

sudo mount /dev/sdb2 /mnt
sudo cp ImageNuttx /mnt/
sudo tee -a /mnt/extlinux/extlinux.conf <<EOF
LABEL Pine64 0X64 Nuttx
       KERNEL ../ImageNuttx
       FDT ../bl808-pine64-ox64.dtb
       APPEND root=PARTLABEL=rootfs rootwait rw rootfstype=ext4 console=ttyS0,2000000 loglevel=8 earlycon=sbi
EOF
sudo umount /mnt

Mount the rootfs and make the required modifications.

sudo mount /dev/sdb3 /mnt
sudo cp ImageNuttx /mnt/boot/
sudo tee -a /mnt/boot/extlinux/extlinux.conf <<EOF
LABEL Pine64 0X64 Nuttx
       KERNEL ../ImageNuttx
       FDT ../bl808-pine64-ox64.dtb
       APPEND root=PARTLABEL=rootfs rootwait rw rootfstype=ext4 console=ttyS0,2000000 loglevel=8 earlycon=sbi
EOF
sudo umount /mnt

Enjoy your new Nuttx booting option!