The C/C++ project templates for Hello World semihosted projects.

Overview

The first challenge when encountering a new board is to make it say Hello. This is even simpler than blinking a LED, since it does not require any peripheral drivers, like GPIO or timers.

The preferred way to output Hello message is via the standard output, routed to the semihosting trace channel, which is supported by most debuggers.

Such a project is a good starting point for writing unit tests, which generally are standard applications displaying various messages and returning an exit code.

Prerequisites

Before creating a new project, please be sure you checked all prerequisites described in the Prerequisites page,

xpm

Special consideration should be given to install node/npm/xpm, which are mandatory for instantiating xPack templates.

Pre-download binary tools

This is an optional step, but highly recommended. Without it the Eclipse plug-in will install all dependencies anyway, including the toolchains and all other binary tools, but, especially for the RISC-V toolchain which is very large, this will take quite a long time, without any feedback.

Thus it is recommended to manually download the dependencies before attempting to create a new project.

For Cortex-M and Arm 32-bit projects, the following commands can be used:

xpm install --global @xpack-dev-tools/arm-none-eabi-gcc@11.2.1-1.2.2 --verbose
xpm install --global @xpack-dev-tools/qemu-arm@7.0.0-1.1 --verbose

xpm install --global @xpack-dev-tools/cmake@3.21.6-1.1 --verbose
xpm install --global @xpack-dev-tools/ninja-build@1.11.0-1.1 --verbose

For RISC-V projects, replace the first lines with:

xpm install --global @xpack-dev-tools/riscv-none-embed-gcc@12.1.0-2.1 --verbose
xpm install --global @xpack-dev-tools/qemu-riscv@7.0.0-1.1 --verbose

Create a new C++ project

To create a new project, go to Eclipse menu, File → New (or the button in the upper left corner), and select the C++ Project:

Create a new C++ project

In the New C/C++ Project window, select C/C++ Managed Build and click the Next > button.

Create a new C++ project

In the C++ Project window:

  • in the Project name: field enter the name of the new project, for example hello-m7f
  • in the Project type: section expand the Executable type and select Hello World Arm QEMU xPack C/C++ Project
  • in the Toolchains: section select Arm Cross GCC
  • click the Next > button

New C++ hello project

In the Project settings window:

  • select the MCU: as Cortex-M7F
  • enable Check some warnings
  • disable all other
  • click the Next > button.

Hello processor settings

In the Select Configurations page leave the suggested Debug/Release configurations checked and click the Next > button.

Hello project configurations

In the Cross GNU Arm Toolchain window:

  • select the Toolchain name: xPack GNU Arm Embedded GCC (mandatory)
  • if the xPack was installed via xpm, click xPack… and select the version; otherwise browse for the bin folder within the toolchain folder; don’t be afraid to use the absolute path, it is not stored in the project
  • click the Finish button

Hello toolchain and path selection

Toolchain path

With all setting ready, the plug-in runs the external command xpm init --template ... to actually populate the project with files:

Toolchain path

This takes a few moments, and then the plug-in runs xpm install, which downloads all dependencies.

The result of the wizard is a simple project, with a main() function printing a greeting on the standard output.

The new C++ project

Build the project

To start the build:

  • select the new project in the Project Explorer section
  • click the hammer icon

Hammer Build

The build process should leave in the Console window a listing like this:

The build console

The files created by the build process are left in a folder named by the name of the configuration, for example Debug or Release.

Blinky Build Result

As seen above, the Debug folder is populated with:

  • all make files required for the build (makefile and various *.mk files, generated by CDT),
  • the object files and dependency files generated during the build (main.o and main.d)  and
  • the final executable file, with all debug symbols, useful for a debug session (hello-m7f.elf)
  • the binary executable file, ready to be programmed in flash (hello-m7f.hex)
  • a program map, with all symbols and their associated addresses (hello-m7f.map)

Run/Debug the test using QEMU Arm

The most convenient way to run a debug session with this test is to use the QEMU Debugging plug-in; no physical hardware is required.

Eclipse menu → Run → Debug Configurations…

The build console

  • expand the GDB QEMU arm Debugging category
  • select the hello-m7f-debug-qemu configuration
  • click the Debug button

The QEMU Debugger tab

Confirm the switch to the debugger perspective, and allow the plug-in to remember this setting.

The Eclipse debugger is started, with a breakpoint in main().

The QEMU Debugger tab

From here you can either step over several instructions, or click Resume (the green right pointing triangle).

QEMU will run the program and display some information, including several trace lines, in the console:

blinky debug

Full semihosting

Contrary to usual POSIX environments, like GNU/Linux, embedded systems usually do not provide standard input/output devices. In the code generated by the template, the output of the printf() calls, including trace_printf(), is redirected to a special debugging channel implemented by most debuggers, using the semihosting protocol.

Even more, the Arm semihosting specs also define read/write file operations, which can be used during tests to read input stimulus data and to output test results.

Project structure

The resulting project has a quite regular structure, with separate folders for the portable content, for the platform specific content, and for the dependencies.

The portable content

The portable content is located in the top src and include folders.

In this project, there is only a main.cpp file with its header:

% tree src include
src
└── main.cpp
include
└── main.h

0 directories, 2 files

The platform specific code

As configured when the template was instantiated, the project is expected to run on a Cortex-M7F, emulated by QEMU.

The project specific code for Cortex-M7F is in the platform-qemu-cortex-m7f folder:

% tree platform-qemu-cortex-m7f
platform-qemu-cortex-m7f
├── CMakeLists.txt
├── README.md
├── cmake
│   ├── dependencies.cmake
│   └── globals.cmake
├── include-config
│   └── micro-os-plus
│       └── config.h
├── include-platform
│   └── micro-os-plus
│       ├── platform-qemu-cortex-m7f
│       │   └── defines.h
│       └── platform.h
├── linker-scripts
└── src

8 directories, 7 files

Most of the files are placeholders, the only file with some content is include-config/micro-os-plus/config.h, which defines some startup and semihosting variables.

The actual code is in the dependent libraries installed in the xpacks folder.

The dependencies folders

As per the xPack design, the source libraries are downloaded and linked in the xpacks folder:

the xPacks folders

Each library has the usual structure, with a src folder for the C/C++ source files, an include folder with the headers, and some metadata for assisting the build.

For example, the @micro-os-plus/semihosting package has the following content:

% tree xpacks/micro-os-plus-semihosting
xpacks/micro-os-plus-semihosting
├── CHANGELOG.md
├── CMakeLists.txt
├── LICENSE
├── README.md
├── include
│   └── micro-os-plus
│       ├── semihosting-inlines.h
│       └── semihosting.h
├── meson.build
├── package.json
├── src
│   ├── semihosting-startup.cpp
│   ├── semihosting-syscalls.cpp
│   └── semihosting-trace.cpp
└── xpack.json

3 directories, 12 files

The dependent libraries are actually not located in the project, but in a central store, and the sub-folders below xpacks are symbolic links (junctions for Windows).

The xPack dependencies should not be saved in the project repository, since the xpacks folder can be easily recreated in a freshly cloned project with xpm install.

The content of the central store is read-only, such that the source files (which can be used by multiple projects) cannot be inadvertently changed.

For development purposes, it is possible to replace the links to the central store with links to a local repository, where the files can be edited, using a pair of the xpm link commands (see the xpm link page).

Headless builds

The template is a separate project that can be fully used in a terminal:

To run the builds, a series of actions are pre-configured, for example to build the Debug configuration for Cortex-M7, a prepare should be performed only once, and later the build step can be performed:

xpm run prepare --config qemu-cortex-m7f-cmake-debug
xpm run build --config qemu-cortex-m7f-cmake-debug

Support

If you encounter any problems when using this template, please refer to the Support page and do not send private emails.