Introduction

One of the most exciting milestones when working with embedded systems is running an operating system (OS). Among all options, Linux stands out as the premier choice—especially being free, open-source, and backed by a massive ecosystem of tools and community support. The ability to run Linux on custom FPGA-based SoCs opens up endless possibilities for prototyping, research, and production systems.

In this guide, we’ll walk through the complete process of booting Linux on a Tang Nano 20K FPGA using LiteX to generate a RISC-V SoC and Buildroot to create a minimal Linux system.

Hardware Requirements

Before we begin, make sure you have:

  • Tang Nano 20K FPGA board
  • MicroSD card (at least 512MB, formatted as FAT32)
  • USB-C cable for programming and serial communication
  • SD card adapter (if your Tang Nano doesn’t have a built-in slot)

Understanding the Tang Nano 20K Limitations

The Tang Nano 20K is an excellent low-cost FPGA platform, but it comes with certain constraints we need to work within:

Memory Constraints

The most significant limitation is RAM: we can synthesize a maximum of 8 MiB of block RAM on this device. This is actually quite restrictive for a full-fledged Linux system, so we need to:

  • Build a minimal kernel with only essential drivers
  • Keep the root filesystem small and efficient
  • Avoid memory-intensive applications
  • Use compressed kernel images

FPGA Resources

The GW2A-LV18PG256C8/I7 FPGA on the Tang Nano 20K provides:

  • 20,160 Logic Cells (LUT4)
  • 15,552 Flip-Flops
  • 41,472 bits of distributed SRAM
  • 828 Kbits of Block SRAM (our main constraint)

This means our SoC design must be optimized to fit within these resources while still providing enough functionality to run Linux.

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.

Preparing the SD Card

We’ll boot from an SD card because it provides the fastest and most reliable boot method for this setup. Here’s what you need to know:

SD Card Requirements

  • Capacity: At least 512MB (though 1GB or larger is recommended)
  • Format: FAT32 filesystem
  • Speed: Class 10 or higher for better performance

Required Files

The SD card must contain these four essential files:

1. boot.json

This JSON configuration file defines the memory layout and boot sequence. It tells the bootloader:

  • Which files to load
  • Where in memory to place them
  • The execution order

Example structure:

{
  "Image":       "0x40000000",
  "rv32.dtb":    "0x40780000",
  "opensbi.bin.tangnano20k": "0x407c0000"
}

2. Image

This is your compressed Linux kernel image. It contains:

  • The kernel binary
  • Built-in drivers
  • Initial RAM disk (if configured)
  • Root filesystem (for minimal setups)

Typical size: 1-3 MB (compressed)

3. opensbi.bin.tangnano20k

OpenSBI (Open Source Supervisor Binary Interface) is the RISC-V equivalent of a BIOS. It provides:

  • Hardware abstraction layer
  • SBI runtime services
  • Platform-specific initialization
  • Secure boot capabilities

This file is specifically compiled for the Tang Nano 20K configuration.

4. rv32.dtb

The Device Tree Blob is a compiled description of your hardware. It tells Linux about:

  • CPU configuration
  • Memory layout
  • Peripheral addresses
  • Interrupt routing
  • Clock frequencies

Boot Procedure

  1. Insert the prepared SD card into your Tang Nano 20K
  2. Power up the FPGA
  3. Connect via serial terminal: litex_term /dev/ttyUSBX --speed 115200
  4. At the LiteX BIOS prompt, type: sdcardboot
  5. Watch Linux boot!

Tip: Some configurations can be set to auto-boot from SD card, eliminating the need to manually type sdcardboot.


Step-by-Step: Running Linux on Tang Nano 20K

I’ve already prepared everything needed to run Linux on the Tang Nano without much hassle. Follow these steps to get your system up and running:

Prerequisites

First, make sure you have the necessary tools installed:

# Install LiteX and dependencies
pip install litex
pip install litedram litesdcard liteeth

# Install development tools
sudo apt-get install build-essential device-tree-compiler

Option 1: Quick Start with Precompiled Bitstream

If you want to get started immediately without building from source:

# Clone the repository
git clone https://github.com/SantaCRC/tutorials.git
cd tutorials/litex_linux

# Flash the precompiled bitstream
openFPGALoader --cable ft2232 --bitstream firmware/sipeed_tang_nano_20k.fs

Option 2: Build from Source

For those who want to build the complete system:

# Generate and load the bitstream (temporary, lost on power cycle)
python3 linux_tang.py --build --load

Or, if you want to flash it permanently to the FPGA’s SPI flash:

# Flash permanently (survives power cycles)
python3 linux_tang.py --build --flash

Build time: Expect 10-30 minutes depending on your computer’s performance.

Connecting to the System

Then, connect using litex_term, without inserting the SD card yet. This allows us to verify the BIOS is working correctly:

# Find your USB serial port (usually /dev/ttyUSB0 or /dev/ttyUSB1)
ls /dev/ttyUSB*

# Connect to the system
litex_term /dev/ttyUSB0 --speed 115200

You should see the LiteX BIOS prompt with available commands:

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

Booting Linux

Now insert the SD card (prepared with the four required files) and type the boot command:

litex> sdcardboot

If everything goes well, you should see the boot sequence start. Here’s what a successful boot looks like:

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+ (riscv64-linux-gnu-gcc 12.2.0) #10
[    0.000000] Machine model: LiteX VexRiscv-SMP
[    0.000000] earlycon: uart0 at MMIO32 0xf0001000
[    0.000000] printk: bootconsole [uart0] enabled
...
[    2.450000] Run /init as init process
Starting system...
Welcome to Buildroot
buildroot login: root
# 

Congratulations! 🎉 You’re now running Linux on your Tang Nano 20K FPGA!

Exploring Your Linux System

Once logged in, you can explore the system. Here are some useful commands:

# Check system information
uname -a

# List running processes
ps aux

# Check memory usage
free -m

# List available storage
df -h

# Check CPU information
cat /proc/cpuinfo

# View system logs
dmesg | less

The system includes BusyBox, which provides most common Unix utilities in a tiny package perfect for our memory-constrained environment.

Repository Structure

I’ve organized all the necessary files in my repository to make your life easier:

Directory Layout

litex_linux/
├── software/          # Pre-built files for your SD card
│   ├── boot.json
│   ├── Image
│   ├── opensbi.bin.tangnano20k
│   └── rv32.dtb
├── misc/              # Build scripts and utilities
│   └── linux_tang.py  # Main build and flash script
├── firmware/          # Precompiled FPGA bitstreams
│   └── sipeed_tang_nano_20k.fs  # Ready-to-flash bitstream
└── README.md          # Detailed instructions

What’s Included

software/ folder: Contains all four files needed for your SD card. Simply copy these to a FAT32-formatted SD card and you’re ready to boot!

misc/ folder: Contains the linux_tang.py script that:

  • Configures the LiteX SoC for Tang Nano 20K
  • Generates the FPGA bitstream
  • Programs or flashes the FPGA
  • Handles all build dependencies

firmware/ folder: Precompiled bitstream if you want to skip the build process entirely. Perfect for quick testing or if you encounter build issues.

Troubleshooting

SD Card Not Detected

If sdcard_detect shows no SD card:

  1. Check that the SD card is properly inserted
  2. Verify the card is formatted as FAT32
  3. Try a different SD card (some cards are incompatible)
  4. Check your wiring if using an external SD card adapter

Boot Hangs or Fails

If the boot process hangs:

  1. Verify all four files are on the SD card
  2. Check that file names match exactly (case-sensitive)
  3. Ensure files are not corrupted (re-download if needed)
  4. Try reformatting the SD card
  5. Check serial connection baud rate (should be 115200)

FPGA Won’t Program

If programming fails:

  1. Check USB cable connection
  2. Verify you have correct permissions: sudo usermod -a -G dialout $USER
  3. Install/update openFPGALoader: pip install openfpgaloader
  4. Try a different USB port

What’s Next?

Now that you have Linux running on your Tang Nano 20K, here are some ideas for next steps:

  1. Customize the kernel: Add drivers for specific peripherals
  2. Expand the filesystem: Include your own applications
  3. Network connectivity: Add Ethernet support if you have the hardware
  4. GPIO control: Write programs to control external hardware
  5. Cross-compilation: Build custom applications on your PC and run them on the FPGA

In future posts, I’ll cover:

  • Deep dive into Buildroot: Customizing your Linux build
  • Adding peripherals: SPI, I2C, GPIO expansion
  • Performance optimization: Squeezing more out of 8MB RAM
  • Multi-core setup: Utilizing multiple VexRiscv cores

Additional Resources

Documentation

Community


Conclusion

Running Linux on an FPGA might seem daunting at first, but with tools like LiteX and Buildroot, it’s more accessible than ever. The Tang Nano 20K, despite its modest resources, proves that you don’t need expensive hardware to experiment with custom SoC designs and embedded Linux.

This is just the beginning—the real power comes from being able to customize every aspect of your system, from the CPU architecture to the peripheral set to the software stack. You now have a complete development platform for exploring RISC-V architecture, FPGA design, and embedded Linux development.

Happy hacking! 🚀