Skip to content

Instantly share code, notes, and snippets.

@bernardoaraujor
Last active February 23, 2020 21:40
Show Gist options
  • Select an option

  • Save bernardoaraujor/48f2528cb02fd1fc808d81cdd783514b to your computer and use it in GitHub Desktop.

Select an option

Save bernardoaraujor/48f2528cb02fd1fc808d81cdd783514b to your computer and use it in GitHub Desktop.
QLE_de10-nano

This is a little guide so anyone who owns an Intel DE10-Nano can try out the first Qubic release.

I will not cover any HDL-related topics. This is only meant to get UBoot to load the FPGA Configuration bitstream into Linux's memory mapped device (a.k.a /dev/mem), and then use the devmem utility to peek and poke the QLEs and QLUTs residing in the soft-IP side of the SoCFPGA.

The steps are loosely based on the tutorials from this Intel repository, mainly writeup_linux.pdf, which can be found in its release page.

We assume you are using a Linux OS on your development host.

Preparing the SD card

We will use UBoot and Linux kernel from de10-nano-image-Angstrom-v2016.12.socfpga-sdimg.2017.03.31.tgz from Intel's Download Center.

  1. Flash the SD card (replace /dev/sdx with the proper value):
$ tar xf de10-nano-image-Angstrom-v2016.12.socfpga-sdimg.2017.03.31.tgz
$ sudo dd if=de10-nano-image-Angstrom-v2016.12.socfpga-sdimg of=/dev/sdx bs=16M
  1. Mount the FAT partition of the microSD card on the host PC, and copy the soc_system.rbf FPGA configuration bitstream to it. The FAT partition is partition 1 on the microSD card. The instructions below assume manual mounting is needed:
$ mkdir boot
$ sudo mount /dev/sdx1 boot
$ sudo cp soc_system.rbf boot
$ sudo umount boot
$ sudo sync
  1. Insert the SD card into the board, and configure the DIP-Switch with UP-DOWN-UP-DOWN-UP-UP. Plug a mini USB cable into the Terasic DE10-Nano UART console connector, then plug the other end of the USB cable into your host PC.

  2. On the host PC, start a serial terminal (for example minicom, or putty) and connect to the serial port corresponding to the Terasic DE10-Nano UART console using the serial communication settings: 115,200-8-N-1.

Log in as user root, with an empty password.

  1. On the UART connection, execute these commands on Linux to disable some services that expect the default FPGA design. If you don't do this, the OS will reboot everytime you load a custom design, which misses our point here.
root@de10-nano:~# systemctl disable de10-nano-fpga-leds.service
root@de10-nano:~# systemctl disable de10-nano-synergy-init.service
root@de10-nano:~# systemctl disable de10-nano-fftsw-init.service
root@de10-nano:~# systemctl disable de10-nano-fpga-init.service
root@de10-nano:~# systemctl disable de10-nano-xfce-init.service

Tip: I experienced some UART issues with copy-pasting commands into minicom. If your console freezes after pasting some command, make sure there's an Ethernet cable going from the board to a router with Internet access and DHCP, reboot the board, run ifconfig to find out its IP address and SSH into it.

Setting up UBoot so Linux loads the FPGA design

  1. Reboot the board. Make sure you send some characters via UART during UBoot bootup so you access its shell. You'll know you were successful when you see something like this:
U-Boot 2017.03-rc2 (Mar 30 2017 - 19:07:16 -0700)

CPU:   Altera SoCFPGA Platform
FPGA:  Altera Cyclone V, SE/A6 or SX/C6 or ST/D6, version 0x0
BOOT:  SD/MMC Internal Transceiver (3.0V)
       Watchdog enabled
I2C:   ready
DRAM:  1 GiB
MMC:   dwmmc0@ff704000: 0
*** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Model: Terasic DE10-Nano
Net:   
Error: ethernet@ff702000 address not set.
No ethernet found.
Hit any key to stop autoboot:  0 
=>  
  1. Type the following commands so Linux loads the FPGA design:
=> setenv fpga_file soc_system.rbf
=> run fpga_cfg
=> setenv load_kernel 'fatload mmc 0:1 ${kernel_addr_r} zImage'
=> setenv load_dtb 'fatload mmc 0:1 ${fdt_addr} socfpga_cyclone5_de10_nano.dtb'
=> setenv bootargs 'console=ttyS0,115200 root=/dev/mmcblk0p2 rootwait'
=> setenv bootcmd 'run fpga_cfg; run load_kernel; run load_dtb; bootz ${kernel_addr_r} - ${fdt_addr}'
=> saveenv
=> run bootcmd

It's important that you see the amber CONF_D LED turn on after you execute run fpga_cfg. That means the .rbf was correctly loaded into the FPGA. If that does not happen, there's either something wrong with the design or the compiled .rbf.

You shouldn't need to type in these commands everytime the board boots. After you've done it for the first time, the saveenv command saves the UBoot environment, so just allow the boot normaly the following times.

Setting up WiFi on the board

You will need an Internet connection on the board. If you're fine with Ethernet, you can skip this section.

To set up WiFi, we will rely on ConnMan to manage the connection.

  1. When you boot the board, make sure the OTG cable is not connected yet. That will cause the kernel to print out some annoyting messages. Boot the board, then insert the OTG. It will still print a few, but you can just ignore them.

  2. Disable unwanted services:

root@de10-nano:~# systemctl disable de10-nano-gadget-init.service
root@de10-nano:~# systemctl disable de10-nano-synergy-init.service
  1. Create a configuration file with the following contents. Use vim to edit it:
root@de10-nano:~# vim /var/lib/connman/wifi.config

Make sure it has the following contents (replace my_ssid and my_password with the appropriate values):

[service_home]
Type = wifi
IPv4 = dhcp
Security = wpa
Name = my_ssid
Passphrase = my_password
  1. Reboot the board:
root@de10-nano:~# reboot
  1. Log in again, and check you're connected to the WiFi LAN:
root@de10-nano:~# ifconfig wlan0
wlan0     Link encap:Ethernet  HWaddr 00:13:EF:90:06:82  
          inet addr:192.168.1.108  Bcast:192.168.1.255  Mask:255.255.255.0
          inet6 addr: fe80::213:efff:fe90:682%3070102176/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:34 errors:0 dropped:0 overruns:0 frame:0
          TX packets:74 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:3725 (3.6 KiB)  TX bytes:12644 (12.3 KiB)

If you have an address on the inet field that matches your LAN range, it means you are.

  1. Ping google to confirm that you have Internet access:
root@de10-nano:~# ping google.com
PING google.com (172.217.168.174): 56 data bytes
64 bytes from 172.217.168.174: seq=0 ttl=54 time=14.093 ms
64 bytes from 172.217.168.174: seq=1 ttl=54 time=11.190 ms
64 bytes from 172.217.168.174: seq=2 ttl=54 time=11.854 ms

Compiling devmem utility to interact with LUTs

We want to interact with the IP modules inside the FPGA fabric, and in the Linux environment there are a couple of utility programs that allow us to perform simple peek and poke operations into the memory map called devmem. This application is not built into the default image for the Terasic DE10-Nano, so we need to download it and use a script to build it.

  1. Let's do that:
root@de10-nano:~# git clone https://gfiber.googlesource.com/vendor/opensource/toolbox
root@de10-nano:~# cp toolbox/devmem.c .
root@de10-nano:~# rm -rf toolbox
root@de10-nano:~# curl https://raw.githubusercontent.com/intel-iot-devkit/terasic-de10-nano-kit/tutorials-v1.0.0/tutorials/MyFirstHPSSystem/writeup_linux/c_examples/build_devmem.sh -o build_devmem.sh
root@de10-nano:~# chmod +x build_devmem.sh 
root@de10-nano:~# ./build_devmem.sh
root@de10-nano:~# rm build_devmem.sh devmem.c devmem.c.orig 

After that, you should have a devmem binary sitting on your home directory. You can test it:

# ./devmem 
usage: devmem <addr> [default:32|16|8] [data]

Tip: I experienced some UART issues with copy-pasting commands into minicom. If your console freezes after pasting some command, make sure there's an Ethernet cable going from the board to a router with Internet access and DHCP, reboot the board, run ifconfig to find out its IP address and SSH into it.

  1. On your development host (not the DE10-nano), look at qubic_hps_0.h to find out SLAVE_BASE
$ cat qubic_hps_0.h 
...
/*
 * Macros for device 'QLUT_AVALON_0_qlut_cfg_avalon_slave', class 'QLUT_AVALON'
 * The macros are prefixed with 'QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_'.
 * The prefix is the slave descriptor.
 */
#define QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_COMPONENT_TYPE QLUT_AVALON
#define QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_COMPONENT_NAME QLUT_AVALON_0
#define QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE 0x30000
#define QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_SPAN 8192
#define QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_END 0x31fff

Read Generating SOPC header files to learn how to generate qubic_hps_0.h from soc_system.sopcinfo.

  1. On the UART/SSH connection with the board, use devmem to read the memory mapping of the slave device. Let's read the contents of $QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE:
# export QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE=0x30000
# ./devmem $QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE 32
0xe24cb004

Let's write into $QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE:

# ./devmem $QLUT_AVALON_0_QLUT_CFG_AVALON_SLAVE_BASE 32 0xde10de10
0xe24cb004
0xde10de10

Remember, if you didn't execute the steps in Setting up UBoot so Linux loads the FPGA design, the .rbf is not loaded and the FPGA design is not mapped into /dev/mem.

Generating SOPC header files

You should be able to download Intel Quartus Lite here.

Assuming your Quartus installation is on ${HOME}/intelFPGA_lite/19.1, and your .sopcinfo is at ${HOME}/Downloads, do this to generate the qubic_hps_0.h header from soc_system.sopcinfo:

$ export SOPC=${HOME}/Downloads
$ export ALTERAPATH="${HOME}/intelFPGA_lite/19.1"
$ export QUARTUS_ROOTDIR=${ALTERAPATH}/quartus
$ export SOPC_BUILDER=${QUARTUS_ROOTDIR}/sopc_builder/bin
$ export PATH=$PATH:${SOPC_BUILDER}
$ sopc-create-header-files ${SOPC}/soc_system.sopcinfo --single qubic_hps_0.h --module hps_0

Now you should have qubic_hps_0.h with macros that contain useful information about how the soft-IP devices are connected to the HPS.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment