At some point you might need to port a new
RIOT, either because that specific development board is not yet supported or because you have a custom
BOARD for your project.
If you want to port a
RIOT you have two choices: doing it inside of
RIOTBASE or outside. In either case the file structure is basically the same and moving from one to another is easy.
This guide details the generic structure you need to add a new
RIOT, the different files as well as their functionality.
CPU_MODEL is already supported in
RIOT so no peripheral or cpu implementation is needed.
Header files in
board-foo/include define physical mappings or configurations. e.g:
periph_conf.h: defines configurations and mappings for peripherals as well as clock configurations.
board.h: holds board specific definitions or mappings, for example LEDs, buttons. It might as well override default drivers parameters (e.g.: assigning specific pin connections to a LCD screen, radio, etc.). Some boards might also define optimized
XTIMER_% values (e.g. XTIMER_BACKOFF).
gpio_params.h: if the board supports SAUL then its saul_gpio_params_t is defined here. (Analogously, a
adc_params.h can contain a saul_adc_params_t, and
pwm_params.h a saul_pwm_rgb_params_t and a saul_pwm_dimmer_params_t).
include/, but if defined somewhere else then they must be added to the include path. In
INCLUDES += -I<some>/<directory>/<path>
Board initialization functions are defined in
board.c. This file can define a
board_init() function that is called at startup. It is run before the scheduler is started, so it must not block (e.g. by performing I2C operations).
A board's Makefile just needs to include
Makefile.base in the RIOT repository and define the
board (see modules for more details)
Dependencies on other
FEATURES can be defined here. This might specify
MODULES or dependencies that need to be pulled under specific configurations. e.g.: if your board has a sx1276 lora chip:
Makefile.dep is processed only once so you have to take care of adding the dependency block for your board before its dependencies pull in their own dependencies.
As explained in Default Configurations, there are two pseudomodules that are used to indicate that certain drivers of devices present in the platform should be enabled. Each board (or CPU) has knowledge as to which drivers should be enabled in each case.
The previous code snippet shows how a board which has a Semtech SX1272 and SX1276 radios driver device, pulls in its driver when the default network interfaces are required.
When the pseudomodule
saul_default is enabled, the board should pull in all the drivers of the devices it has which provide a [S]ensor [A]ctuator [U]ber [L]ayer interface. This is usually done as following:
This file defines all the features provided by the BOARD. These features might also need to be supported by the
CPU. Here, define the
CPU_MODEL (see build system basics for more details on these variables).
This file contains BSP or toolchain configurations for the
BOARD. It should at least define the configuration needed for flashing (i.e. specify a default programmer) as well as the serial configuration (if one is available). The default serial port configuration is provided by
makefiles/tools/serial.inc.mk and define the following values for the serial port (depends on the host OS):
So if the board is also using this, there's no need to redefine these variables in the board configuration.
For example a board that is using a custom serial port (via an USB to serial adapter) and that is flashed using openocd by default would have the following content in its
When using high level timers, i.e.
ztimer there is an overhead in calling for ztimer_sleep and ztimer_set functions. This offset can be compensated for. It can be measured by running
tests/sys/ztimer_overhead on your board, i.e:
The last two lines can be added as defines to the new board
Although not explicitly needed, if upstreamed and as a general good practice, this file holds all
BOARD documentation. This can include datasheet reference, documentation on how to flash, etc.
The documentation must be under the proper doxygen group, you can compile the documentation by calling
make doc and then open the generated html file on any browser.
To help you start porting a board, the RIOT build system provides the
generate-board make target. It is a wrapper around the riotgen command line tool that is helpful when starting to port a board: all required files are generated with copyright headers, doxygen groups, etc, so you can concentrate on the port. The board source files are created in the
boards/<board name> directory.
From the RIOT base directory, run:
Then answer a few questions about the driver:
Other global information (author name, email, organization) should be retrieved automatically from your git configuration.
To avoid code duplication, common code across boards has been grouped in
BOARDs based on the same cpu (
BOARDs having the same layout
In the case of source files this means some functions like
board_init can be already defined in the common code. Unless having specific configurations or initialization you might not need a
board.h. Another common use case is common peripheral configurations, for example in the
If you want to use common makefiles, include them at the end of the specific
Makefile, e.g. for a
BOARDs in RIOT reside in
RIOTBOARD being a make variable set to
If one wants to use a
BOARD outside of
RIOTBOARD, the way to go is setting the
EXTERNAL_BOARD_DIRS variable to the path to the directory containing your external boards, e.g.:
EXTERNAL_BOARD_DIRS=/home/external-boards/ (this would commonly be done in your application
Makefile or your environment). You can specify multiple directories separated by spaces.
If the external
BOARD is very similar to a
BOARD already present in
RIOTBOARD, the external
board-foo) can inherit from that parent
In this case some special considerations must be taken with the makefiles:
MODULE cannot be
foo-parent will already define
MODULE = board, so use any other name, lets say
MODULE = board-foo.
BOARD to inherit from (if there is one):
/Makefile.include to also include the parent board header. e.g: if inheriting from
INCLUDES += $(addprefix -I,$(wildcard /foo-parent/include))
board is added by default to
USEMODULE but since
board-foo is used for this
BOARD, it must be explicitly included by adding
USEMODULE += board-foo.
Makefile.* the corresponding parent
Makefile.*, just as it is done for common
BOARD code (as explained in Using Common code). e.g:
An example can be found in
Some scripts and tools available to ease
BOARD porting and testing:
dist/tools/insufficient_memory/add_insufficient_memory_board.sh <board> if your board has little memory. This updates the
Makefile.ci lists to exclude the
BOARD from automated compile-tests of applications that do not fit on the
dist/tools/compile_and_test_for_board/compile_and_test_for_board.py . <board> --with-test-only to run all automated tests on the new board.