The AllWinner V3s and by extension the LicheePi Zero are designed to run Linux kernel-based operating systems, which includes both a distribution called "CamDroid" (a lightweight operating system based on Android) with a good support for MIPI cameras and H.264 video codecs, or more conventional Linux-based distributions, with a choice between an EmDebian or buildroot-based distribution.
We definitely discarded the CamDroid distro, as it requires the non-public AllWinner SDK to build which is encumbered with closed-source blobs, as we don't need its specificities here. Moreover, support seems very difficult, as all that can be found is mainly in Chinese.
Regarding plain Linux distros, there are some pre-built EmDebian and buildroot-based images with several build options (Xorg, gcc, Python, LXDE, minimal) available for download at https://licheepizero.us/.
Despite its attractive Debian-flavored facilities (well-known structure, number of available pre-built binary packages), we also discarded the EmDebian distro because:
- This distro is dead: "As of July 2014, updates to the Emdebian distributions ceased. There will be no further updates and no further stable releases."
- Even if it is tagged as "embedded", the resulting size is rather large for such a small amount of RAM
- boot time is > 10 s
Thus, we turned to buildroot to provide our distro. "Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation.". And this is really true:
- its core infrastructure is just a few hundred lines of make code
- it uses make code and kconfig for the configuration interface and language. Both technologies should be familiar to all embedded Linux developers
- compiling the whole distro is fast and don't take hours, even when re-building the cross-toolchain from scratch
- it is designed for small to medium sized embedded systems
On the down side, there is no runtime package management system (dpkg, rpm) and complete rebuilds are often required...
Linux Distro Dissection
Actually, an embedded Linux distribution is not a single piece of firmware: a first consideration are the required tools that are running on the host or build system, as opposed to the software running on the target machine.
In the case of buildroot, you have the core system which is made up of a few hundred lines of make code and kconfig scripts to run a simple menuconfig-like configuration interface. There are also a few required utilities that are built from their source tarball packages. But the piece of meat is the cross-toolchain that includes all the tools required to build executable software that will run on the target machine. With buildroot, you have the choice either to use a pre-built toolchain or build your own from scratch. Guess what we chose ;-)
On the target side, each independent piece of software is called a package, and is made up of a small, mostly declarative makefile, some patches and the source tarball package that is fetch from the original package maintainer location. These packages are cross-compiled using tha above toolchain and put into a set of firmware images that are burned into the target machine.
Even on the target machine, there are several distinct pieces of software that must be considered, described here in their boot order:
Boot ROM (BROM)
This one cannot be modified, as it is a read-only software that is first run upon boot-time. It is in charge of bringing up the minimum resources to startup the CPU. It also reads some GPIO inputs with either pull-up or pull-down resistors known as bootstrap configuration to select some operating options such as clock frequency, boot device, etc.
Secondary Program Loader (SPL)
The BROM then fetches the Secondary Program Loader (SPL) from the selected boot device (in our case, the SD Card) into the built-in small SRAM. The SPL's main task is to initialize the DRAM in order to fetch the next boot stage from SD Card into it.
U-Boot (u-boot.bin) and boot.scr
The SPL then loads the main U-Boot bootloader into the main DRAM and executes it. U-Boot i almost an operating system by itself, as it initializes many resources and is able to run scripts (boot.scr). The goal for the U-Boot is to load the binary Device Tree and the Linux kernel into DRAM and execute the kernel with the provided DTB.
In our case, the SPL and U-Boot images are combined into a single "u-boot-sunxi-with-spl.bin" image.
Device Tree Binary (DTBs: sun8i-v3s-licheepi-zero.dtb and sun8i-v3s-licheepi-zero-dock.dtb)
The binary device tree is an OS-independent structure that describes all the hardware resources. It is compiled from a corresponding Device Tree Source (DTS) file and loaded at run time by the operating system to configure its peripheral drivers according to the described hardware.
Linux Kernel (zImage)
Based on the binary device tree, the Linux kernel will initialize all the required operating subsystems, mount the root filesystem and start the first user task, then schedule all tasks in the background.
Root File System (rootfs.ext2, rootfs.ext4 and rootfs.tar)
The root file system is a disk or Flash memory partition organized as a structured file hierarchy containing directories, plain and pseudo-files that will be used during processing. The rootfs.ext2 and rootfs.ext4 are equivalent and linked symbolically, and the rotofs.tar may be used to mount the root filesystem over NFS (Network File System) instead of read locally from SD Card.
Distro Images Generation
Buildroot is able to generate all these images (u-boot-sunxi-with-spl.bin, boot.scr, sun8i-v3s-licheepi-zero.dtb and sun8i-v3s-licheepi-zero-dock.dtb, zImage, rootfs.ext2, rootfs.ext4 and rootfs.tar and build a single SD Card image that contains them all at their expected location using a single command.
Unfortunately, this was not the solution chosen by the LicheePi developers, who instead provided a set of handcrafted recipes and scripts to build the different images and the final SD Card image:
https://licheepizero.us/ (look for zero_imager.zip tool)
We decided to drop these weird tools and go back to a more standard all-buildroot generation, using the custom U-Boot and Linux kernel repositories containing all the required patches for the V3s and the LicheePi Zero board, based on the LicheePi Github repositories:
We generated a proper licheepi_zero buildroot default configuration for buildroot, so that you can generate all the images using a few simple commands that are standard to build all buildroot targets. A first patch has been submitted upstream to the builroot team to integrate the LicheePi Zero board into the mainstream buildroot disitrbution. Right now, a second version of the patch is under construction. Until it is integrated into buildroot, it is available in our own repository:
Building the SD Card image containing all the required images is then just obtained using:
$ git checkout firstname.lastname@example.org:Squonk42/buildroot-licheepi-zero.git $ cd buildroot-licheepi-zero $ make licheepi_zero_defconfig $ make menuconfig (optional) $ make
The resulting images are then located in the "output/images" directory:
output/images/ ├── boot.scr ├── boot.vfat ├── rootfs.ext2 ├── rootfs.ext4 -> rootfs.ext2 ├── rootfs.tar ├── sdcard.img ├── sun8i-v3s-licheepi-zero-dock.dtb ├── sun8i-v3s-licheepi-zero.dtb ├── u-boot.bin ├── u-boot-sunxi-with-spl.bin └── zImage
Once the build process is finished you will have an image called "sdcard.img" in the "output/images/ " directory.
Copy the bootable "sdcard.img" onto an SD card with "dd":
$ sudo dd if=output/images/sdcard.img of=/dev/sdX
Alternatively, you can use the Etcher graphical tool to burn the image to the SD card safely and on any platform:
Once the SD card is burned, insert it into your LicheePi Zero board, and power it up. Your new system should come up now and start a console on the UART0 serial port.