What is a bootloader?
You will edit and compile programs on your laptop, and you will need to transfer the compiled program to the Pi when ready to execute it. One way to move a program from your laptop to the Pi is using a micro-SD card. You would prepare a card with the early-stage boot code and add your program to be launched afer booting. Each time you update the program, you would re-insert the card on your laptop, copy the latest program onto it, eject the card and then insert into Pi. You can see how this process would quickly become tedious!
Instead, you can set up a connection between your laptop and the Pi and use a bootloader to transfer the program. The bootloader runs on the Pi and waits, listening for a request. When you send a program from your laptop, the waiting bootloader receives it and writes the program to the memory of the Pi, a process called "loading" the program. To execute the program, you tell the bootloader to jump to the start address of the program.
Using a bootloader, the cycle to run a newly-compiled program is:
- Reset the Pi to re-enter the bootloader
- Use
xfel
on your laptop to send the program to the bootloader and execute it on the Pi
The bootloader we are using is called FEL/xfel
. FEL
(firmware exchange launch) is a low-level subroutine contained in the BootROM on Allwinner devices. It is used for initial programming and recovery of devices over USB.
BootROM is a small piece of read-only/write-protected memory embedded in the processor. It contains the very first code which is executed by the processor on power-on or reset. When the Pi is powered on, it enters FEL by default. FEL does a minimal first-stage boot and waits for further commands to come over the USB port.
The xfel
tool runs on your laptop and communicates with the bootloader.
Got xfel? You should have installed
xfel
as part of installing the developer tools. If you skipped this step, do it now. See section xfel in the installation guide for your OS.
Connect through OTG
FEL listens for commands over USB. The connection from your laptop to the OTG port that is powering the Pi is the same connection your laptop will use to communicate with the bootloader. Your usb cable/hub must support both charge and data, needed for power and communication, respectively.
Invoking xfel
with no arguments shows the available commands. The commands xfel ddr
, xfel write
and xfel exec
are the ones we will use most.
$ xfel
xfel(v1.3.2) - https://github.com/xboot/xfel
usage:
xfel version - Show chip version
xfel hexdump <address> <length> - Dumps memory region in hex
xfel dump <address> <length> - Binary memory dump to stdout
xfel read32 <address> - Read 32-bits value from device memory
xfel write32 <address> <value> - Write 32-bits value to device memory
xfel read <address> <length> <file> - Read memory to file
xfel write <address> <file> - Write file to memory
xfel exec <address> - Call function address
xfel reset - Reset device using watchdog
xfel sid - Show sid information
xfel jtag - Enable jtag debug
xfel ddr [type] - Initial ddr controller with optional type
xfel sign <public-key> <private-key> <file> - Generate ecdsa256 signature file for sha256 of sid
xfel spinor - Detect spi nor flash
xfel spinor erase <address> <length> - Erase spi nor flash
xfel spinor read <address> <length> <file> - Read spi nor flash to file
xfel spinor write <address> <file> - Write file to spi nor flash
xfel spinand - Detect spi nand flash
xfel spinand erase <address> <length> - Erase spi nand flash
xfel spinand read <address> <length> <file> - Read spi nand flash to file
xfel spinand write <address> <file> - Write file to spi nand flash
xfel spinand splwrite <split-size> <address> <file> - Write file to spi nand flash with split support
xfel extra [...] - The extra commands
Try xfel version
now. If you have a valid connection to the Pi and the bootloader is running, it should respond with the chip id.
$ xfel version
AWUSBFEX ID=0x00185900(D1/F133) dflag=0x44 dlength=0x08 scratchpad=0x00045000
If the Pi is not powered on or is not connected, xfel
cannot find the device and will report this error.
$ xfel version
ERROR: xfel found no connected FEL device.
If the Pi is powered on and connected but the bootloader is not running, xfel
will find the device and attempt to communicate with it, but since the bootloader is not listening, the message will fall on deaf ears. After a few unacknowledged retries, it will give up and report this error:
$ xfel version
ERROR: xfel had timeout comunicating with device (device not listening, needs reset?)
Use xfel read32/write32 to peek and poke
The commands xfel read32
and xfel write32
can be used to peek and poke values in memory. Admittedly these commands are more of a cute party trick than a useful way to control the Pi.
Try out these commands on the address of a GPIO peripheral register.
The blue on-board act led is controlled by GPIO PD18. The base address of config0 register for the PD group is 0x02000090
. The function of PD18 is set in config2 at address 0x02000098
. The data register for the PD group is address 0x020000a0
, the value for PD18 corresponds to the 18th bit in the register. The exchange below shows reading the value of config2 and data and then writing to config2 and data to configure PD18 as an output and set its value to 1. The blue act led on-board the Mango Pi should now turn on.
$ xfel read32 0x02000098
0x0fffffff
$ xfel read32 0x020000a0
0x00000000
$ xfel write32 0x02000098 0x100
$ xfel write32 0x020000a0 0x40000
The command xfel hexdump
will read a range of memory and printf it. Below shows a hexdump of some of the memory used for the GPIO peripheral registers.
$ xfel hexdump 0x02000000 100
02000000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02000010: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02000020: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02000030: ff ff ff ff 66 ff 0f 00 00 00 00 00 00 00 00 00 ....f...........
02000040: 00 00 00 00 11 11 11 11 11 11 01 00 00 00 00 00 ................
02000050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
02000060: ff ff ff ff ....
Use xfel to load and execute a program
Before loading a program, we must first bring up the memory controller. This requires a finely-tuned bit of hardware wizardry that is supplied by xfel
. We will use the command xfel ddr d1
to properly initialize the memory for the D1. You must always initialize the memory controller after reset and before running a program.
After the memory system has been initialized, use the command xfel write
to send a binary file from your laptop to the bootloader. The bootloader will receive the file and write it to memory at the address you specify. The command xfel exec
will start execution at that address. We load our programs to address 0x40000000
, the standard start location for RISC-V.
Try these commands out now. Change to the CS107E bin directory and send the blink-actled program:
$ cd $CS107E/bin
$ xfel ddr d1
Initial ddr controller succeeded
$ xfel write 0x40000000 blink-actled.bin
100% [================================================] 44.000 B, 23.620 KB/s
$ xfel exec 0x40000000
The blink-actled program sits in an endless loop blinking the blue on-board led.
To load and run a different program, your must first reset the Pi by briefly interrupting power. This step is necessary to reset the Pi and reenter the bootloader so it is ready to receive a new program. Your parts kit includes a usb cable with a rocker switch so you can perform a reset by a quick switch to off then back on.
Pro-tip: mango-run
You will need to re-play these commands (xfel ddr d1; xfel write; xfel exec
) so often that we wrote a small script to package this command sequence into the single command mango-run
.
If you invoke mango-run
with no arguments, it does a version check to confirm the Pi is connected and bootloader running and listening.
$ mango-run
Usage: ./mango-run <binary-file>
Simple script to run a program on the Mango Pi using xfel as bootloader.
(xfel ddr d1, xfel write, xfel exec)
xfel version
AWUSBFEX ID=0x00185900(D1/F133) dflag=0x44 dlength=0x08 scratchpad=0x00045000
If you invoke mango-run
with name of a binary program, it will send that to the bootloader and execute it:
$ cd $CS107E/bin
$ mango-run blink-actled.bin
xfel ddr d1
Initial ddr controller succeeded
xfel write 0x40000000 blink-actled.bin
100% [================================================] 44.000 B, 20.298 KB/s
xfel exec 0x40000000
There you have it, a simple way to execute programs on your Pi. Nifty!
Troubleshooting
Some suggestions of how to diagnose and resolve troubles with the bootloader.
Use xfel version
(or mango-run
with no arguments) to test communication with the bootloader.
- If response is chip id
AWUXBFEX ID=...
, you are good to go! It found the connection to the Pi, the bootloader is running, and the Pi responded with its id. All's right in your world. - If response is
ERROR: xfel found no connected FEL device.
, it could not find the Pi to connect.- Double-check the Pi is powered up, that your laptop is connected to the Mango OTG port, and the cable you are using supports both charge and data.
- In some situations, a connection that was fine a moment ago can stop working. This can happen if your laptop's usb system went a bit wonky and suspended the port. Unplugging from your laptop usb port and replug may prompt your laptop to reset the port, if not, reboot your laptop to set things right.
- If response is
ERROR: xfel had timeout comunicating with device (device not listening, needs reset?)
, it found the connection to Pi, but was not able to communicate with the bootloader.- This generally means the bootloader is not running/listening. If you previously bootloaded a different program and it is now executing on the Pi, the bootloader is no longer running. To re-enter the bootloader, you must restart the Pi. Reset by briefly cutting and restoring power using the switch on your usb cable.
Resources
- The
xfel
source code is published on github, we maintain a custom fork at https://github.com/cs107e/xfel - Documentation on
xfel
is available at https://xboot.org/xfel/ - The
mango-run
script is available in$CS107E/bin
.