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
- Insert the prepared SD card into your Tang Nano 20K
- Power up the FPGA
- Connect via serial terminal:
litex_term /dev/ttyUSBX --speed 115200 - At the LiteX BIOS prompt, type:
sdcardboot - 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:
- Check that the SD card is properly inserted
- Verify the card is formatted as FAT32
- Try a different SD card (some cards are incompatible)
- Check your wiring if using an external SD card adapter
Boot Hangs or Fails
If the boot process hangs:
- Verify all four files are on the SD card
- Check that file names match exactly (case-sensitive)
- Ensure files are not corrupted (re-download if needed)
- Try reformatting the SD card
- Check serial connection baud rate (should be 115200)
FPGA Won’t Program
If programming fails:
- Check USB cable connection
- Verify you have correct permissions:
sudo usermod -a -G dialout $USER - Install/update openFPGALoader:
pip install openfpgaloader - 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:
- Customize the kernel: Add drivers for specific peripherals
- Expand the filesystem: Include your own applications
- Network connectivity: Add Ethernet support if you have the hardware
- GPIO control: Write programs to control external hardware
- 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
Project Links
- My Repository - Pre-built files and scripts
- Linux-on-LiteX-VexRiscv - Official project
- Buildroot - Embedded Linux build system
- LiteX - SoC builder
- Tang Nano 20K - Board documentation
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! 🚀