One of the key goals when working with embedded systems is to run an operating system (OS), and there’s one that stands out—especially being free and open-source: Linux. Plus, there are plenty of tools that help us tailor it to our needs.

Limitations of the Tang Nano 20K

The Tang Nano 20K has quite a few limitations in terms of FPGA resources, which is understandable given its low cost. The main one is RAM: we can only generate a maximum of 8 MiB, so our Linux system needs to be conservative.

Buildroot

To compile our OS, we’ll use Buildroot, a tool that greatly simplifies the process—though it’s still a bit exhausting. That’s why I’ll provide precompiled files so you can skip this step. In a future post, I’ll explain how to generate and modify them to create your own kernel.

Linux-on-LiteX

This is a project that provides all the necessary configuration so Buildroot can properly compile the image and binaries that will run on a LiteX SoC, which we’ll implement on the Tang Nano 20K. As mentioned earlier, I’ve already done this work, so you don’t need to repeat it—unless you want to build your own (but be warned: it takes a few hours).

LiteX

This is the foundation of the entire series. There’s not much to add about LiteX; I’ve already covered it in previous posts. For this one, I’ve also prepared most of the setup: a script that generates a RISC-V rv32 CPU compatible with Linux and mountable on the Tang Nano 20K. So, you just need to generate the bitstream or use the precompiled one I’ll provide, then flash it to your Tang Nano. Once done, if you connect via litex-term, you’ll see that it supports booting from SD. It can also boot via serial, but it’s way too slow, and I don’t have time for that.

The SD Card

As mentioned, we boot from an SD card because it’s the fastest way for this setup. The important part is that it’s formatted as FAT and contains the required files for the kernel to work:

  • boot.json: Defines where and which files will be loaded into the FPGA’s RAM.
  • Image: Our Linux system.
  • opensbi.bin.tangnano20k: The BIOS responsible for loading Linux.
  • rv32.dtb: The device tree that defines the board and its peripherals.

With these files on the SD card, just power up the FPGA and boot it using sdcardboot, in case it doesn’t do so automatically.


Running Linux

I’ve already prepared everything needed to run Linux on the Tang Nano without much hassle. In upcoming posts, we’ll explore how to customize the system further. But for now, just run this command from the litex-linux repo folder:

python3 linux_tang.py --build --load

Or, if you want to flash it permanently:

python3 linux_tang.py --build --flash

Then, connect using litex_term, without inserting the SD card yet. You should see something like this:

litex> help

LiteX BIOS, available commands:

leds                     - Set Leds value
buttons                  - Get Buttons value
flush_l2_cache           - Flush L2 cache
flush_cpu_dcache         - Flush CPU data cache
crc                      - Compute CRC32 of a part of the address space
ident                    - Identifier of the system
help                     - Print this help

sdcardboot               - Boot from SDCard
serialboot               - Boot from Serial (SFL)
reboot                   - Reboot
boot                     - Boot from Memory

mem_cmp                  - Compare memory content
mem_speed                - Test memory speed
mem_test                 - Test memory access
mem_copy                 - Copy address space
mem_write                - Write address space
mem_read                 - Read address space
mem_list                 - List available memory regions

sdram_mr_write           - Write SDRAM Mode Register
sdram_test               - Test SDRAM
sdram_init               - Initialize SDRAM (Init + Calibration)

sdcard_write             - Write SDCard block
sdcard_read              - Read SDCard block
sdcard_freq              - Set SDCard clock freq
sdcard_init              - Initialize SDCard
sdcard_detect            - Detect SDCard

Now insert the SD card and type the command:

sdcardboot

If everything goes well, you should see something similar—indicating that you’re now running Linux.

Booting from SDCard in SD-Mode...
Booting from boot.json...
Copying Image to 0x40000000 (1818868 bytes)...
[########################################]
Copying sipeed_tang_nano_20k.dtb to 0x40780000 (2115 bytes)...
[########################################]
Copying opensbi.bin.tangnano20k to 0x407c0000 (49636 bytes)...
[########################################]
Executing booted program at 0x407c0000

--============= Liftoff! ===============--

OpenSBI v0.8-2-ga9ce3ad
   ____                    _____ ____ _____
  / __ \                  / ____|  _ \_   _|
 | |  | |_ __   ___ _ __ | (___ | |_) || |
 | |  | | '_ \ / _ \ '_ \ \___ \|  _ < | |
 | |__| | |_) |  __/ | | |____) | |_) || |_
  \____/| .__/ \___|_| |_|_____/|____/_____|
        | |
        |_|

Platform Name       : LiteX / VexRiscv-SMP
Platform Features   : timer,mfdeleg
Platform HART Count : 8
Boot HART ID        : 0
Boot HART ISA       : rv32imasu
BOOT HART Features  : pmp,time
BOOT HART PMP Count : 16
Firmware Base       : 0x407c0000
Firmware Size       : 120 KB
Runtime SBI Version : 0.2

MIDELEG : 0x00000222
MEDELEG : 0x0000b109
[    0.000000] Linux version 6.4.0-rc1+ (zjs@CL-A-00022) (riscv64-linux-gnu-gcc (Debian 12.2.0-13) 12.2.0, GNU ld (GNU Binutils for Debian) 2.40) #10 Tue May 16 09:20:49 CST 2023

The Files

As mentioned, I already compiled the required files, so no need to reinvent the wheel. You’ll find everything in my repository:

  • In the software/ folder are the files to copy to your SD card.
  • In misc/ you’ll find the script to upload and generate the bitstream.
  • If you prefer using a precompiled bitstream, it’s inside firmware/.

Links