Building bare-metal C programs for DE10-Nano development kit with Eclipse IDE for Embedded C/C++ Developers


Introduction


This began from wanting to create a project with the DE10-Nano development board (Intel Cyclone V SoC-FPGA) for data acquisition. In my design I wanted to use the FPGA side for capturing medium fast ADC samples (100MS/s) from an external ADC board, and use the HPS side with its built-in USB 2.0 or 1GB ethernet to send data to a PC as fast as possible.

Such a project would require the ability to transfer data from the FPGA side to the HPS side where the USB and ethernet exists. One solution is to use configured Linux (e.g. Angstrom) system from a SD card or flash memory. I could modify the Linux device tree to reserve a block of RAM for the FPGA ensuring it won't be used by Linux. Next, edit the Linux boot script to call memmap (kernel command) to map the reserved kernel address space to a user address space, or alternatively map using the C mmap() function (linux system call) with a Linux program on /dev/mem (device file to physical memory). Then finally develop a Linux program to access the user address space. To be honest, my Linux setup skills are not that good and it would be a lot to learn - I'm going to leave that for a rainy day.

Searching for another solution, I see that Intel provides us with "SoC FPGA HWLib" - a library which supports the SoC-FPGA hardware. Note, for DE-10 (Cyclone V) we would use the hwlib from the armv7a folder. The library is for bare-metal C programming, which is essentially low level programming, and is frequently used in the embedded MCU development world. Because I have developed programs for the PIC and STM32 MCUs in the past, this is an interesting route to pursue.

This brings us back to the original topic of building bare-metal C progamming. I have found a few SoC-FPGA bare-metal guides on the Internet but all of them require Arm DS-5 IDE, which is now superseded by Arm Development Studio. DS-5 or Arm Development Studio is a commercial product and requires a paid license to work. In the past, Arm offered a 30 day free trial but this is no longer available! Anyway, for hobbyists a commercial route is not a suitable path.

I have been building DE10-Nano programs the hard way: through commandline and plain text editor. My build flow was running a GNU C/C++ toolchain using a few Bash shell scripts on Ubuntu Linux, and running tests using SD card images with printf debugging by outputting debug messages to the serial UART. Having to physically switch the SD card between the PC and the dev kit was very time-consuming, and also without break points debugging it was very difficult to fix complex problems. I wanted something like DS-5; an IDE that builds, uploads elf, run and debug with the click of a button.

After a year, I have finally found a solution! My guide will show you how to setup the various tools so that you can build, run and debug using the widely known Eclipse IDE for Embedded C/C++ Developers.

1. Getting the pre-requisite tools and files


Files

In this guide we will be using Windows host for our development. All of these tools are available for Linux so it should be straight forward to adapt these steps for Linux. We start by getting the required tools.

1.1. Get Arm GNU toolchain for C/C++

Toolchain is a set of tools for building the C/C++ source code, it includes the compiler, linker, disassembler, GDB, and other useful tools.

Download a version for Windows ("win32-x64" in the file name) from xPack GNU Arm Embedded GCC releases and extract it to a folder of your choice.

For the purpose of this guide we are using v13.2.1-1.1 and is extracted to "C:\devtools\xpack-arm-none-eabi-gcc-13.2.1-1.1"

Note

The official GNU Toolchain for Arm distribution is open source so there exists variants of it. We are using xPack's version in this guide, but you may prefer another, e.g. Arm's own version. There are other variants such as Linaro Arm GNU toolchain (Linux host only) which is abandoned, Code Sourcery ARM Toolchain (Linux host only), any of these can be used instead but may have small differences.

If you want to use GDB for debugging on Ubuntu, unfortunately, in Arm's own version (12.3.Rel1), their GDB binary (in latest version) is hardcoded to use Python v3.8, this bug prevents it working on the latest Ubuntu, which installs latest Python version through its update, as of writing Python v3.10. For Ubuntu I suggest you use the xPack version instead.

Arm GNU Toolchain download
1.2. Get Eclipse IDE for Embedded C/C++ Developers

Eclipse IDE for Embedded is used by many microcontroller manufacturers. Most manufacturer's offer their own IDE but many are actually a customised version of this.

Download the Windows x86_64 installer from Eclipse IDE Installer

Run the installer, during the install select "Eclipse IDE for Embedded C/C++ Developers", which will install a version of Eclipse and plugins taylored for embedded C/C++ programming.

Note: On Ubuntu you must trust all source links, which you can do so within the installer from the menu and tick "Trust all content", or within Eclipse IDE from the menu "Windows/Preferences" then in the dialog "Install/Update/Trust" then tick "Trust all content"

In this guide we will simply call this Eclipse.

Eclipse installer
1.3. Get Windows port of GNU Make

This is a Windows port of the GNU make utility.

The GNU make utility is a popular scripting tool for automating C/C++ development on Linux. It is the interpreter for GNU "make" scripts, which enables the script to run. On Linux the make scripting language is a popular choice for automating the task of executing tools to build programs. It provides prerequisite (timestamp update dependency) logic for rules (conditions) more suitable for updating the build process, e.g. you want to only compile objects that are out of date to the sources. The main problem is that scripting languages, e.g. Bash, KornShell, Borne shell, MSDOS, PowerShell do not provide such built-in logic.

Eclipse itself requires a build tool - one that it supports. We will set it up to use this tool.

We will use xPack's version which is a more complete port than the GnuWin32 one.

Download a release version from xPack Windows Build tools releases and extract it to a folder of your choice.

For the purpose of this guide we are using v4.4.1-2 and is extracted to "C:\devtools\xpack-windows-build-tools-4.4.1-2"

1.4. Get the driver for USB Blaster II programming adapter

The USB Blaster II is the official programming JTAG adapter for Intel FPGAs, and it is already integrated on the DE10-Nano board. It requires a driver and the firmware file blaster_6810.hex to work. The driver and firmware file comes bundled with "Quartus Prime Programmer and Tools" and also "Quartus Prime Lite", and so you can install either one. If you're not going to use "Quartus Prime Lite", you may prefer the smaller size of "Quartus Prime Programmer and Tools". During the setup just make sure to include the driver as part of the installation.

OpenOCD requires the path to the blaster_6810.hex file to be specified. Since the installation of Quartus creates environment variable QUARTUS_ROOTDIR or QSYS_ROOTDIR for us, I've added TCL code to the default target script (altera-usb-blaster2.cfg) to use these to find the path of the blaster_6810.hex file.

In this guide we will simply call "Quartus Prime Lite" as "Quartus Prime".

1.5. Get OpenOCD

This is a popular low level layer debugging software for embedded devices. It is able to communicate with hardware debug adapters and send debug commands or signals to control the target processor. It understands the low level industry standards JTAG/SWD/Arm CoreSight commands and has support for various debug adapters.

Eclipse supports the OpenOCD debugging software.

The github OpenOCD master branch contains the latest commits (changes) but normally is ongoing code so I prefer to use a Release version instead.

I am too lazy to build OpenOCD from the source files so will use xPacks's binary release. Download a version from xPack OpenOCD releases and extract it to a folder of your choice.

For the purpose of this guide we are using v0.12.0-2 and is extracted to "C:\devtools\xpack-openocd-0.12.0-2"

OpenOCD download OpenOCD target

At this time, OpenOCD does not include a target script file for the DE10-Nano, download it from my github: DE10-Nano scripts.

Download and extract the script "altera_fpgasoc_de.cfg" (from the openocd-config-scripts/target folder) into the "target" of your OpenOCD installed folder. In this guide the location is:
"C:\devtools\xpack-openocd-0.12.0-2\share\openocd\scripts\target"

Also:

In newer versions of OpenOCD it no longer searches for the USB Blaster II firmware (blaster_6810.hex found inside bin, bin64 or linux64 in the Quartus Prime installation folder), so you have two options:

  1. Extract the script "altera-usb-blaster2.cfg" into the "interface" folder of your OpenOCD folder. In this guide the location is:
    "C:\devtools\xpack-openocd-0.12.0-2\share\openocd\scripts\interface". My TCL script attempts to search for the firmware using the environment variables QSYS_ROOTDIR or QUARTUS_ROOTDIR, which is set by the Quartus Prime installation.
  2. Or, alternatively, you can use the default OpenOCD "altera-usb-blaster2.cfg" script and simply set the correct path on this line:
    usb_blaster firmware /path/to/quartus/blaster_6810.hex

1.6. Get "Hello, World" semihosting example

This contains my example source code with Eclipse project.

Download from the pre-requisite list above.

Extract it to a folder of your choice. For the purpose of this guide it is extracted to "D:\Documents\de10nano-baremetal-guide"

2. Setting up Eclipse IDE for Embedded C/C++ Developers


Eclipse is really only the editor and the integration, it relies on external tools for the compiling, scripting and debugging.

In this step we will setup some global settings, but note, this only needs to be setup once. Note, the global settings are saved to the workspace directory, not your project directory.

2.1. Start Eclipse

When starting Eclipse it will prompt for a workspace location. We will use the default, just click the "Launch" button, and tick remember my decision if you would like.

Eclipse launcher
2.2. Display the global settings
To bring up the global settings dialog:
  • Select from the menu "Windows/Preferences". The dialog displayed is for configuring all of the global and workspace settings.
  • We are interested in the MCU tree, click the greater than icon ">" to open up the tree
2.3. Set global toolchain path
Steps:
  • In the MCU tree, click the "Global Arm Toolchains Paths"
  • For the "Default toolchain", select "xPack GNU Arm Embedded GCC (arm-none-eabi-gcc)"
  • Click the "Browse" button and select the bin folder of the "Arm GNU toolchain". In this guide the location is: "C:\devtools\xpack-arm-none-eabi-gcc-13.2.1-1.1\bin"
Eclipse toolchain path
2.4. Set global build tools path
Steps:
  • In the MCU tree, click the "Global Build Tools Path"
  • Click the "Browse" button and select the bin folder of the make utility. In this guide the location is: "C:\devtools\xpack-windows-build-tools-4.4.1-2\bin"
Eclipse build tools path
2.5. Set the global OpenOCD path
Steps:
  • In the MCU tree, click the "Global OpenOCD Path"
  • For the "Executable" box, leave it defaulted as "openocd.exe", or if no default (empty) then type it in
  • Click the "Browse" button and select the bin folder of the OpenOCD. In this guide the location is: "C:\devtools\xpack-openocd-0.12.0-2\bin"
Eclipse OpenOCD path

3. Building (compiling) the example source files


At this stage, we would normally create a new C project, but first we will look at some basic tasks with the use of my ready made example project.

3.1. Import the "Hello, World" semihosting example project
Steps:
  • Start "Eclipse IDE for Embedded C/C++ Developers"
  • The "Eclipse IDE Launcher" is displayed and prompts "select a directory as workspace". The default path is fine, just click the "Launch" button
  • In Eclipse, select from the menu "File/Open Projects from File System..."
  • On the "Import Projects" dialog window, click the "Directory..." button and select the parent directory of the example, in this guide it is "D:\Documents\de10nano-baremetal-guide"
  • Notice that the parent folder is listed as a selectable option (a tick box item) - this enables a single folder (parent folder) to store & manage settings for multiple projects, but I think is not ideal for our use case. All my projects are independent so should have their own settings. Click the "Deselect All" button and tick only "..\hello_world_semihosting" project (see the picture)
  • Click the "Finish" button
Note, in practice, from the start we could have selected the project folder instead of the parent "D:\Documents\de10nano-baremetal-guide\hello_world_semihosting", then we will not need to deselect anything.
Eclipse import
3.2. Build using the DebugSemihosting build configuration (profile)

On the toolbar there is a hammer icon - this is the build icon. Also, just next to it is a down-arrow icon - this is the build configuration select icon. It should be defaulted to the Debug configuration, let's change it. Click the dropdown next to the hammer and select "DebugSemihosting" to switch. Notice switching automatically starts building the source code.

If successful, you should see a message in the build console like this: "Build Finished. 0 errors, 1 warnings. (took 885ms)"

Ignore the 1 warning regarding the load segment with RWX permissions. That refers to the permissions of the On-Chip RAM load section defined in the linker file.

Eclipse build debug profile

4. Running and debugging


4.1. Set a debug breakpoint

As an exercise, we will set a breakpoint, this will halt the execution at that point (location), and will enable us to begin stepping lines of code within the counting loop.

The vertical space to the left of the line numbers can be used to set or unset breakpoints:
  • Within the Project Explorer, double-click main.c file to open it
  • Double-click the space to the left of line 65 to set a breakpoint, indicated by a round dot if set, see the picture

Note: A breakpoint will only work where there is code. Eclipse is not able to prevent setting invalid breakpoint locations - it is not within their control, the toolchain would need to support such a feature.

Eclipse debug set breakpoint
4.2. Connect the USB Blaster II (J-TAG adapter)

The compiled elf program will not run on your PC, if we wish to run and debug the elf from the PC we will need to use an emulator, such as QEMU, or use debug tools, such as OpenOCD and GDB, we will use this latter option.

First we need to prepare the board:
  • If there is a SD card in the slot, remove it
  • Set the mode switches on the DE10-Nano for booting from SD card so that nothing boots (this is the default if you didn't change these switches before)
  • Attach a USB 2.0 cable between the USB Blaster II connector and your PC (the USB port on the same side as the 5V power supply socket)
  • Apply power to the DE10-Nano board
4.3. Debug configuration

In the hello world project you will find my pre-configured GDB & OpenOCD eclipse debug configurations.

To start a debug session in Eclipse:
  • From the menu, select "Run" and then "Debug Configurations..."
  • In the tree of "GDB OpenOCD Debugging", click the "hello_world_semihosting_debug" profile
  • Click the "Debug" button and some magic stuff happens
  • If prompted to switch into debug perspective, click "Switch" (also tick "Remember my decision" if you want)
Eclipse debug configuration Eclipse debug perspective
4.4. Break on main
The debug process takes a bit of time to get ready. In the background it does quite a bit:
  1. Issues a soft processor reset
  2. Loads and executes U-Boot-SPL to initialise the DE10-Nano processor system (HPS), which also enables the SD-RAM to be used
  3. Finally, loads and executes your elf program

When ready, your program should now be running on the DE10-Nano board. The execution is halted at a breakpoint as indicated in Eclipse by a green line in the main.c source file.

Note: By default a breakpoint is set at the start of main within the debug configuration profile, but this can be turned off. Also there is a bug in Eclipse OpenOCD & GDB plugin. When disabling the "Set breakpoint at: main" doesn't work, i.e. checkbox is unticked but it still breaks on main, you need to select "Remove all breakpoints" from the Run menu. I think this setting creates an invisible breakpoint in main, which is not synched (a round dot not shown) in the IDE source editor

Noticed the layout, panels and toolbars have changed, Eclipse has switched into the debug perspective. Perspective is Eclipse's jargon for layout profile

At the top the toolbar contains useful debug controls: resume, suspend, terminate, step into (F5) and step over (F6).

Click the resume button to continue the execution.

Eclipse debug break main Eclipse debug set breakpoint Eclipse debug remove all break points
4.5. Debugging with semihosting

Semihosting is a mechanism which allows us to view and input debug messages through the debug adapter and a console. Eclipse conveniently includes a built-in console panel at the bottom.

You should be able to see "Hello, World" as a debug message inside the console panel. This comes directly from the elf running on the DE10-Nano.

Execution should be prompting for an input. Click inside the console panel and enter a number, for example 10, then press enter.

Eclipse debug input
4.6. Step the code

The execution should reach our breakpoint we made earlier and is now halted. We will use the toolbar at the top to step each line of the for loop.

Click on the "step over" button (or press F6) to advance a step. Keep stepping and notice the console at the bottom outputs the for loop count sequence. Also, the variables panel displays a table of variables with their live content, these are read automatically from the target Arm processor on DE10-Nano via GDB & OpenOCD through the USB Blaster II (JTAG) adapter.

Keep stepping, until you see "Test completed" message. Stepping any further will get you into the infinity loop function.

Eclipse counting
4.7. Stop the debug session and switch back to the C/C++ perspective

Click the red button in the toolbar at the top, this terminates the debug session and also stops the debug connection (OpenOCD and GDB) between the USB Blaster II and Eclipse.

The layout is not automatically restored, click the C/C++ perspective button on the top right corner (see the picture). This restores the layout back to the C/C++ perspective.

Note, although the debug session has stopped, the execution continues to run on the DE10-Nano's processor. *Update*, in newer Eclipse GDB/OpenOCD it now halts the execution when session is stopped. But this is not an issue because my OpenOCD script sends a soft processor reset when another debug session is started.

Eclipse stop debug

5. The "Hello, World" source files


I've tried to keep the example source code to the minimum.

File Description
main.c The main source file.
hello_world_semihosting_debug.launch Debug configuration with GDB and OpenOCD debug settings. This can be used to launch a debugging session for the currently selected (active) build configuration.
u-boot-spl-nocache Compiled U-Boot SPL elf file. It is built with embedded SPL device tree, hardware watchdog timer disabled, L1 I-cache and D-cache disabled and bridges enabled.
util/newlib_ext.h/.c, c5_util.h, c5_uart.h/.c Contains functions for newlib stubs and my lowlevel functions for Cyclone V SoC.
hwlib_minimum/alt_base.c Stock low level startup source file from HWLib.
hwlib_minimum/cvav-ddr.ld Stock linker file from HWLib. A Cyclone V and Arria V linker file for running from DDR-3 SDRAM.

6. Creating a new project


In this step we will create and setup a completely new C project. We make it work with the HWLib library and to save time we will use some of the files from my second example "Hello, World!" UART. Download it from the pre-requisite list above.

6.1. Create a new project
In Eclipse:
  • Select from the menu "File/New/C/C++ Project"
  • Select "C Managed Build"
  • Click "Next"
Eclipse new project
6.2. Set project details
Steps:
  • Enter helloworld_uart for the project name
  • Uncheck "Use default location"
  • Browse and select your preferred location for this project. In this guide, create a new folder called helloworld_uart2 and select that for the location: D:\Documents\de10nano-baremetal-guide\helloworld_uart2
  • Select "Empty Project" for project type
  • Select "Arm Cross GCC" for toolchain
  • Click "Next"
Eclipse empty project
6.3. Set project toolchain
Steps:
  • For the toolchain name, use the dropdown to select "xPack GNU Arm Embedded GCC (arm-none-eabi-gcc)"
  • The path should be filled in automatically because we've previously set this toolchain up in the global settings
  • Click "Finish"
Eclipse project toolchain
6.4. Add files to the project

We cannot do much with an empty project, let's add in some files from the "Hello, World!" UART example.

Minimise Eclipse, and use File Explorer or a suitable program to extract the following files into your project folder (helloworld_uart2):
  • bsp_generated (entire folder)
  • hwlib (entire folder)
  • utils (entire folder)
  • main.c
  • u-boot-spl-nocache

Maximise Eclipse, then within Project Explorer, open up the tree, right-click the project name and select "Refresh" (or press F5)

Note, if you prefer to download the HWLib source from the official site, get it from here: Intel SoC FPGA HWLib. You will need the hwlib located inside the armv7a folder.

Extract helloworld uart sample Extracted helloworld uart sample Eclipse refresh

7. Configuring project build settings


7.1. Configure target processor for Debug build configuration

The project cannot be compiled yet, it needs the correct build settings.

Steps:
  • In "Project Explorer", right-click the project name and select "Properties"
  • A dialog displays the current build configuration, in this case is "Debug" indicated at the top by the dropdown
  • Open up "C/C++ Build" tree
  • Click on "Settings"
  • Click on "Target Processor" (If it is not already selected)
  • For the "Arm family" setting, select "cortex-a9"
  • For the "Instruction set" setting, select "Toolchain default" or "Arm". "Thumb" will not work
  • For the "Float ABI" setting, select any option you prefer. In this guide we select "FP instructions (hard)"
  • For the "FPU Type" setting, select "neon". This is only for hardware float, otherwise it is disabled
  • For the "Unaligned access" setting, select "Disabled (-mnu-unaligned-access)", which disables the triggerring of exception when accessing unaligned addresses
Eclipse project target processor
7.2. Configure user defines (symbols) for Debug build configuration

HWLib needs these defined symbols set when using a Cyclone V SoC-FPGA.

Steps:
  • Click on "Preprocessor" under "GNU Arm Cross C Compiler"
  • In "Defined symbols", use the "Add.." button to add the following defines
    • soc_cv_av
    • CYCLONEV
Eclipse project Debug preprocessor
7.3. Configure include paths for Debug build configuration

In my source files, the header includes don't use absolute paths so we need set the search paths here to tell it where to look for header files during a build.

Steps:
  • Click on "Includes" under "GNU Arm Cross C Compiler"
  • In the "Includes paths", use the "Add.." button add the following paths:
    • "${workspace_loc:/${ProjName}/bsp_generated}"
    • "${workspace_loc:/${ProjName}/hwlib/include}"
    • "${workspace_loc:/${ProjName}/hwlib/include/soc_cv_av}"
    • "${workspace_loc:/${ProjName}/util/include}"
Eclipse project Debug include paths
7.4. Configure linker script for Debug build configuration

Bare-metal require a suitable linker script for your board and processor, we will use HWLib's linker file.

Steps:
  • Click on "General" under "GNU Arm Cross C Linker"
  • In "script files", use the "Add.." button to add the file: "${workspace_loc:/${ProjName}/hwlib/src/linkerscripts/cvav-ddr.ld}"
Eclipse project Debug linker script
7.5. Configure linker miscellaneous for Debug build configuration
Steps:
  • Click on "Miscellaneous" under "GNU Arm Cross C Linker"
  • Tick the "Do not use syscalls" checkbox
Eclipse project Debug linker do not use syscalls
7.6. Configure create flash image for Debug build configuration

By default the "Create flash image" option is enabled with "Intel HEX" format. This option outputs an additional compiled file useful for creating images. It is not required now, but it will be required when creating a SD card image or a flash memory image, and this is because U-Boot-SPL does not support the .elf format, however it is able to load and start a binary file.

We will leave it enabled, but let's change the output to the more suitable binary format instead:
  • Click on "General" under "GNU Arm Cross Create Flash Image"
  • For "Output file format" select "Raw binary"
Alternatively, if you ever wish to disable this additional file:
  • Click on "Toolchains" tab
  • Untick the "Create flash image" checkbox
Finallly, click the "Apply" button to save the changes to the Debug build configuration. You may get a prompt about rebuilding index for the changes to take effect, go ahead and click on "Rebuild index".
Eclipse project Debug binary output Eclipse project Debug create flash image Eclipse rebuild index
7.7. Configure Release build configuration

Ok, let's switch to the Release configuration. Using the dropdown at the top, switch to the Release. The Release configuration requires the same changes we made for the Debug configuration, unfortunately you have to manually repeat the process.

We could have selected the "All configurations" at the beginning and then make our changes, but there is no indication (e.g. no colour coding or emphasis) to show which options are the same or different - I believe this is accident-prone for beginners.

Note: Don't forget to click "Apply" at the end, and if prompted rebuild the index.

Eclipse project release build
7.8. Create a new build configuration for semihosting

If we want to use Semihosting debug functionality we need to set linker library settings. We can set them in the Debug configuration but I prefer to create a separate build configuration for it.

We will copy the Debug configuration for the new semihosting configuration:
  • Click "Manage Configurations..." button
  • Click "New..." button
  • For the "Name" enter "DebugSemihosting"
  • Under the "Copy settings from" and "Existing configuration" ensure "Debug" is selected
  • Click "OK" button
  • In the "Manage Configuration also click the "OK" button
Eclipse project manage configurations Eclipse project Semihosting configuration
7.9. Configure user defines (symbols) for semihosting build configuration

We will add a user defined symbol (a made up symbol) for use in our code to conditionally enable and disable semihosting code.

Steps:
  • Use the dropdown at the top to switch to DebugSemihosting
  • Click on "Preprocessor" under "GNU Arm Cross C Compiler"
  • In "Defined symbols", select the last symbol so that we can add to the end of the list
  • Use the "Add.." button to add the define "SEMIHOSTING"
Eclipse project Semihosting build
7.10. Configure linker library for semihosting build configuration

To use semihosting we need to link to the rdimon library and also set specs flag for rdimon. The rdimon library comes with the GNU C/C++ Arm cross toolchain we are using so no need to install anything.

Steps:
  • Click on "Libraries" under "GNU Arm Cross C Linker"
  • In "Libraries", use the "Add.." button and enter "rdimon" and press "OK"
  • Click on "Miscellaneous" and for "Other linker flags" input box enter "--specs=rdimon.specs"
  • Click "Apply" button, and if prompted rebuild the index
Eclipse project Semihosting rdimon library Eclipse project Semihosting rdimon specs
7.11. Create a new build configuration for printf to UART

If you find semihosting too slow, you may prefer to output debug messages to UART instead. I have written code to support this and is enabled by defining symbol TRU_DEBUG_PRINTF. We will create a separate build configuration for this.

We will copy the Debug configuration for the new debug by UART configuration:
  • In "Manage Configurations..." dialog
  • Click "New..." button
  • For the "Name" enter "DebugUART"
  • Under the "Copy settings from" and "Existing configuration" ensure "Debug" is selected
  • Click "OK" button
  • In the "Manage Configuration also click the "OK" button
Eclipse project create DebugByUART
7.12. Configure user defines (symbols) for DebugUART build configuration

We will add a user defined symbol (a made up symbol) to enable the TRU_DEBUG_PRINTF to output to UART0.

Steps:
  • Use the dropdown at the top to switch to DebugUART
  • Click on "Preprocessor" under "GNU Arm Cross C Compiler"
  • In "Defined symbols", select the last symbol so that we can add to the end of the list
  • Use the "Add.." button to add the define "TRU_PRINTF_UART"
  • Click "Apply and Close" button, and if prompted rebuild the index
Eclipse project DebugByUART symbol

8. Excluding source files from the build


8.1 Exclude unneeded HWLib source files

At this point, starting the build (compile) process results in several errors. This is because of the HWLib library, to eliminate these errors we need to exclude some source files.

Exclude Arria 10 SoC-FPGA sources (entire folder):
  • In "Project Explorer" open up the tree for "hwlib/src/hwmgr"
  • Right-click "soc_a10" folder and select "Resource Configurations/Exclude from Build..."
  • Click "Select All" to exclude from all build configurations
  • Click "OK"
Exclude ethernet sources (unsupported for Cyclone V series):
  • Within the same folder "hwlib/src/hwmgr", exclude the file "alt_eth_phy_ksz9031.c"
  • Within the same folder "hwlib/src/hwmgr", exclude the file "alt_ethernet.c"
Exclude duplicated startup source file:
  • Within the folder "hwlib/src/utils", exclude the file "alt_base.S"
Exclude their version of printf to UART source file:
  • Within the folder "hwlib/src/utils", exclude the file "alt_printf.c"
Eclipse project exclude SoC Arria 10 step 1 Eclipse project exclude SoC Arria 10 step 2 Eclipse project exclude

9. Creating GDB with OpenOCD debug configurations


9.1. Create a generic debug configuration profile

Let's create a debug configuration for any currently active build configuration.

Steps:
  • From the menu select "Run/Debug Configurations..."
  • Right-click "GDB OpenOCD Debugging" and select "New Configuration"
  • In the "C/C++ Application:" input box, type in: "${config_name:${project_name}}/${project_name}.elf"
  • For "Build Configuration", select "Use Active"
  • Click the "Debugger" tab (the second tab)
  • In "Config options" type in:
    -f interface/altera-usb-blaster2.cfg -f target/altera_fpgasoc_de.cfg -c "init; halt; c5_reset; halt; c5_spl u-boot-spl-nocache"
  • Click the "Startup" tab
  • Untick "Initial Reset" checkbox
  • Untick "Pre-run/Restart reset" checkbox
  • Untick "Set breakpoint at: main" checkbox
  • Click the "Common" tab
  • Under "Save as" select "Shared file" so that the config is saved inside your project instead of the workspace
  • Click "Apply" button to save the settings, then click "Close"
Eclipse project create semihosting debug config Eclipse project config semihosting debug config Eclipse project startup semihosting debug config Eclipse project common semihosting debug config

10. Known limitations


It seems the USB Blaster II works extremely slow through a virtual machine. I have tried Ubuntu 22.04.1 LTS (as guest) with Oracle Virtual Box and confirm that OpenOCD appear to hang trying to load U-Boot-SPL, if you can wait for about 4 minutes (yes, minutes to transfer a couple of kilobytes) it does finally complete!!

If you must use a virtual machine, I recommend to use an external compatible JTAG adapter (e.g. FTDI FT232H, FT2332H or FT4232H), connected to the DE10-Nano's JTAG header pins. You will also need to create/edit a suitable OpenOCD interface script for it - sorry I havn't the energy to do that atm.

11. Notes


Bare-metal C programming produces an elf or bin program for running natively on the target processor, in this case the dual core Arm Cortex-A9 (with hardware FPU and NEON). Compiling a program for a different type of processor is known as cross compiling. Bare-metal program runs bare, meaning without an OS and driver model, this naturally has low level development requirements (taken care of in my examples):

  • requires board settings which are specific to user's configuration
  • the usual standard C/C++ library cannot be used, e.g. C CRT and C++ STL libraries
  • requires a suitable linker file
  • requires a low level startup initialisation file

At startup or reset, as with any other hardware, the SoC-FPGA's processing system (HPS) requires initialising - a process that will set up the hardware components such as clocks, PLLs, RAM, interface bridges, peripherals etc. U-Boot-SPL is able to do this initialisation but your board settings will need to be compiled in.

Board settings come from your Quartus Prime project, more specifically from the settings of your HPS IP instance within Platform Designer. Platform Designer will generate hand-off files (plain-text data files) containing your configured settings that you generate. In the latest u-boot-socfpga (U-Boot fork) you will find a set of Python scripts (arch/arm/mach-socfpga/cv_bsp_generator/) for converting these hand-off files into U-Boot compatible C files. U-Boot requires the board settings to be provided as C files which are to be merged with its source files.

The example projects includes a U-Boot SPL that was compiled using my hand-off files but that means the configuration is specific to my Quartus Prime project. If you want to use your own configuration, then you must generate new hand-off files (result in folder hps_isw_handoff) using your own Quartus Prime project, convert them with the Python script, merge the source files (copy and paste) and then recompile U-Boot.

HWLib also requires one of the converted board settings C file (pll_config.h) to work. I have used mine for the example projects.

Most developers use Redhat's newlib library, a reduced C library that atleast provides us with some of the standard functionality. Currently, newlib library comes bundled with Arm's GNU C/C++ Toolchain so no need to install anything extra. By design, Redhat left some of the newlib functions as empty stubs, and they require overriding, these are taken care of by my newlib_ext.h/.c files.

For the linker and startup files I have simply used the ones from HWLib: cvav-ddr.ld and alt_base.c.

If I get the time, I will write a guide for configuring and building the U-Boot-SPL.

Currently, I am in the process of creating an Eclipse CDT plugin template extension wizard for the Cyclone V Soc-FPGA (DE10-Nano). I will release it when ready. This should make the creation of new projects alot easier for everyone.


Document date: Rev 4: 05 Feb 2024 - Added OpenOCD TCL script for USB Blaster II
Document date: Rev 3: 12 Dec 2023 - Updated tools to newer versions
Document date: Rev 2: 04 Dec 2023 - Updated OpenOCD target script
Document date: Rev 1: 27 Mar 2023