Porting boards                                                 {#porting-boards}
================

At some point you might need to port a new `BOARD` to `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 `BOARD` to `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 `BOARD`
to `RIOT`, the different files as well as their functionality.

@note We assume here that your `CPU` and `CPU_MODEL` is already supported
in `RIOT` so no peripheral or cpu implementation is needed.

# General structure                                         {#general-structure}

Like @ref creating-an-application "applications" or @ref creating-modules
"modules", boards consist on a directory containing source files and
makefiles. Usually a `BOARD` directory has the following structure

```
  board-foo/
  |----dist/
      |----scripts
  |----board.c
  |----doc.txt
  |----include/
      |----periph_conf.h
      |----board.h
      |----gpio_params.h
  |----Makefile
  |----Makefile.dep
  |----Makefile.features
  |----Makefile.include
```

## Source files                                            {#board-source-files}

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. @ref XTIMER_BACKOFF).
- `gpio_params.h`: if the board supports @ref drivers_saul "SAUL" then its
  @ref saul_gpio_params_t is defined here.
- other: other specific headers needed by one `BOARD`

@note Header files do not need to be defined in `include/`, but if defined
somewhere else then they must be added to the include path. In
`Makefile.include`: `INCLUDES += -I<some>/<directory>/<path>`

Board initialization functions are defined in `board.c`. This file must at
least define a `board_init()` function that is called at startup. This
function initializes the `CPU` by calling`cpu_init()` among others.

```c
void board_init(void)
{
    /* initialize the CPU core */
    cpu_init();

    /* initialize GPIO or others... */
    ...
}
```

## Makefiles

### Makefile                                                         {#Makefile}

A board's Makefile just needs to include `Makefile.base` in the RIOT
repository and define the `MODULE` as `board` (see @ref creating-modules
"modules" for more details)

```mk
MODULE = board

include $(RIOTBASE)/Makefile.base
```

### Makefile.dep                                                 {#makefile-dep}

Dependencies on other `MODULES` or `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:

```mk
ifneq (,$(filter netdev_default,$(USEMODULE)))
  USEMODULE += sx1276
endif
```

@note `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.

### Makefile.features                                       {#makefile-features}

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` and
`CPU_MODEL` (see @ref build-system-basics "build system basics" for more details
 on these variables).

e.g.:

```mk
CPU = foo
CPU_MODEL = foobar

# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_uart
```

### Makefile.include                                         {#makefile-include}

This file contains BSP or toolchain configurations for the `BOARD`. It
should at least define the configuration needed for flashing (i.e. a
programmer) as well as the serial configuration (if one is available).

e.g.:

```mk
# Define the default port depending on the host OS
PORT_LINUX ?= /dev/ttyUSB0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial*)))

# setup serial terminal
include $(RIOTMAKE)/tools/serial.inc.mk

# this board uses openocd
include $(RIOTMAKE)/tools/openocd.inc.mk
```

## doc.txt                                                          {#board-doc}

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.

@code
/**
@defgroup    boards_foo FooBoard
@ingroup     boards
@brief       Support for the foo board
@author      FooName BarName <foo.bar@baz.com>

### User Interface

  ....

### Using UART

  ...

### Flashing the device

  ...

*/
@endcode

# Helper tools

To help you start porting a board, the RIOT build system provides the
`generate-board` make target. It is a wrapper around the
[riotgen](https://pypi.org/project/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.

**Usage:**

From the RIOT base directory, run:
```
make generate-board
```
Then answer a few questions about the driver:
- Board name: Enter a name for your board. It will be used as the name
  of the board directory under `boards`.
- Board displayed name: Enter the name of the board, as displayed in the
  Doxygen documentation.
- CPU name: Enter the name of the CPU embedded on the board.
- CPU model name: Enter the precise model name of the CPU.
- Features provided: CPU features provided (and configured) for this board.

Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.

# Using Common code                                         {#common-board-code}

To avoid code duplication, common code across boards has been grouped in
`boards/common`. e.g. `BOARD`s based on the same cpu (`boards/common/nrf52`) or
`BOARD`s having the same layout `boards/common/nucleo64`.

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.c` or `board.h`. Another common use
case is common peripheral configurations:

@code
-\#include "cfg_timer_tim5.h"
+/**
+ * @name   Timer configuration
+ * @{
+ */
+static const timer_conf_t timer_config[] = {
+    {
+        .dev      = TIM5,
+        .max      = 0xffffffff,
+        .rcc_mask = RCC_APB1ENR_TIM5EN,
+        .bus      = APB1,
+        .irqn     = TIM5_IRQn
+    }
+};
+
+#define TIMER_0_ISR         isr_tim5
+
+#define TIMER_NUMOF         ARRAY_SIZE(timer_config)
+/** @} */
@endcode

If you want to use common makefiles, include them at the end of the specific
`Makefile`, e.g. for a `Makefile.features`:

```mk
CPU = foo
CPU_MODEL = foobar

# Put defined MCU peripherals here (in alphabetical order)
FEATURES_PROVIDED += periph_i2c
FEATURES_PROVIDED += periph_spi
FEATURES_PROVIDED += periph_uart

include $(RIOTBOARD)/common/foo_common/Makefile.features
```

# Boards outside of RIOTBASE                       {#boards-outside-of-riotbase}

All `BOARD`s in RIOT reside in `RIOTBOARD` (`RIOTBOARD` being a make variable
set to `$(RIOTBOARD)/boards`).

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.

```
/home/
|----RIOT/
    |---- ...
|----external-boards/
    |----board-foo/
        |----dist/
            |----scripts
        |----board.c
        |----doc.txt
        |----include/
            |----periph_conf.h
            |----board.h
            |----gpio_params.h
        |----Makefile
        |----Makefile.dep
        |----Makefile.features
        |----Makefile.include
```

If the external `BOARD` is very similar to a `BOARD` already present in
`RIOTBOARD`, the external `BOARD` (`board-foo`) can inherit from that
parent `BOARD` (e.g: `foo-parent`).

In this case some special considerations must be taken with the makefiles:

- `Makefile`
  - `MODULE` cannot be `board`: `foo-parent` will already define
    `MODULE = board`, so use any other name, lets say `MODULE = board-foo`.
  - Include the location of the parent `BOARD` to inherit from (if there is
    one):

```mk
      DIRS += $(RIOTBOARD)/foo-parent
```

- `Makefile.include`
  - duplicate the include done by `$(RIOTBASE)/Makefile.include` to also
    include the parent board header. e.g: if inheriting from `foo-parent`
    ``INCLUDES += $(addprefix -I,$(wildcard $(RIOTBOARD)/foo-parent/include))`

- `Makefile.dep`: `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`.

- Then simply include in each `Makefile.*` the corresponding parent `BOARD`
  `Makefile.*`, just as it is done for common `BOARD` code (as explained in
  @ref common-board-code). e.g:
  `include $(RIOTBOARD)/foo-parent/Makefile.*include*`

An example can be found in
[`tests/external_board_native`](https://github.com/RIOT-OS/RIOT/tree/master/tests/external_board_native)

# Tools                                                          {#boards-tools}

Some scripts and tools available to ease `BOARD` porting and testing:

  - Run `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 `BOARD`s `CPU`.

  - Run `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.
