1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-12-14 17:13:50 +01:00

Merge pull request #21708 from AnnsAnns/more_migration

doc/guides: The Big Migration
This commit is contained in:
Teufelchen 2025-09-18 16:03:57 +00:00 committed by GitHub
commit bd93e286a7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
53 changed files with 4354 additions and 3397 deletions

View File

@ -22,7 +22,7 @@ affect a person's ability to participate within them.
If you believe someone is violating the code of conduct, we ask that you report
it by emailing <conduct@riot-os.org>. For more details please see our [Reporting
Guidelines](https://doc.riot-os.org/coc-reporting-guide.html).
Guidelines][reporting-guidelines].
- **Be friendly and patient.**
- **Be welcoming.** We strive to be a community that welcomes and supports
@ -39,7 +39,7 @@ Guidelines](https://doc.riot-os.org/coc-reporting-guide.html).
- **Be respectful.** Not all of us will agree all the time, but disagreement
is no excuse for poor behavior and poor manners. We might all experience
some frustration now and then, but we cannot allow that frustration to turn
into a personal attack. Its important to remember that a community where
into a personal attack. It's important to remember that a community where
people feel uncomfortable or threatened is not a productive one. Members of
the RIOT community should be respectful when dealing with other members as
well as with people outside the RIOT community.
@ -61,18 +61,23 @@ Guidelines](https://doc.riot-os.org/coc-reporting-guide.html).
- **When we disagree, try to understand why.** Disagreements, both social and
technical, happen all the time and RIOT is no exception. It is important
that we resolve disagreements and differing views constructively. Remember
that were different. The strength of RIOT comes from its varied community,
that we're different. The strength of RIOT comes from its varied community,
people from a wide range of backgrounds. Different people have different
perspectives on issues. Being unable to understand why someone holds a
viewpoint doesnt mean that theyre wrong. Dont forget that it is human to
err and blaming each other doesnt get us anywhere. Instead, focus on
viewpoint doesn't mean that they're wrong. Don't forget that it is human to
err and blaming each other doesn't get us anywhere. Instead, focus on
helping to resolve issues and learning from mistakes.
Text based on the Code of Conduct of the [Django
community](https://www.djangoproject.com/conduct/).
community][django-community].
Questions?
----------
If you have questions, please see [the FAQ](https://doc.riot-os.org/coc-faq.html).
If that doesn't answer your questions, feel free to [contact us](mailto:conduct@riot-os.org).
If you have questions, please see [the FAQ][faq].
If that doesn't answer your questions, feel free to [contact us][contact-us].
[reporting-guidelines]: https://guide.riot-os.org/general/code_of_conduct/reporting/
[django-community]: https://www.djangoproject.com/conduct/
[faq]: https://guide.riot-os.org/general/code_of_conduct/faq/
[contact-us]: mailto:conduct@riot-os.org

View File

@ -2618,7 +2618,7 @@ DOT_PATH =
# command).
# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS = dot/
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
# contain msc files that are included in the documentation (see the \mscfile

View File

@ -1,4 +1,4 @@
Advanced build system tricks {#advanced-build-system-tricks}
Advanced build system tricks (Deprecated) {#advanced-build-system-tricks}
============================
@deprecated See [Advanced Build System Tricks](https://guide.riot-os.org/build-system/advanced_build_system_tricks/)

View File

@ -1,4 +1,4 @@
# Build In Docker {#build-in-docker}
# Build In Docker (Deprecated) {#build-in-docker}
@deprecated This page is deprecated.
See [Build in Docker](https://guide.riot-os.org/build-system/build-in-docker/)

View File

@ -1,4 +1,4 @@
# Build System Basics {#build-system-basics}
# Build System Basics (Deprecated) {#build-system-basics}
@deprecated See [Build System Basics](https://guide.riot-os.org/build-system/build_system_basics/)
on the RIOT Guide Site for the latest information.

View File

@ -1,75 +1,4 @@
# FAQ {#coc-faq}
# FAQ (Deprecated) {#coc-faq}
This FAQ attempts to address common questions and concerns around the RIOT
community's [Code of Conduct][CoC]. If you still have questions after
reading it, please feel free to [contact us][CoC-question-mail].
--------------------------------------------------------------------------------
### Why have you adopted a Code of Conduct?
If you're familiar with the RIOT
community, you'll probably notice that the Code basically matches what we
already do. Think of this as documentation: we're taking implicit expectations
about behavior and making them explicit.
We're doing this because the RIOT community is growing faster than any of us
could have anticipated. This is on balance a very positive thing, but as we've
grown past the point where it's possible to know the whole community we think
it's very important to be clear about our values.
We know that the RIOT community is open, friendly, and welcoming. We want to
make sure everyone else knows it too.
### What does it mean to "adopt" a Code of Conduct?
For the most part, we don't think it means large changes. We think that the text
does a really good job describing the way the RIOT community already conducts
itself. We expect that most people will simply continue to behave in the awesome
way they have for years.
However, we do expect that people will abide by the spirit and words of the CoC
when in "official" RIOT spaces. This code has been adopted by the RIOT community
as a whole. That means that it'll apply in all community spaces.
In practice, this means the [RIOT forum](https://forum.riot-os.org), the Matrix
chats (e.g., [`#riot-os`](https://matrix.to/#/#riot-os:matrix.org) or
[`#riot-os-off-topic`](https://matrix.to/#/#riot-os-off-topic:matrix.org)),
mailing lists (e.g., security@riot-os.org), bug tracking and code review tools,
and "official" RIOT events such as Hack'n'ACKs or RIOT summits. In addition,
violations of this code outside these spaces may affect a person's ability to
participate within them.
### What happens if someone violates the Code of Conduct?
Our intent is that anyone in the community can stand up for this code, and
direct people who're unaware to this document. If that doesn't work, or if you
need more help, you can contact <conduct@riot-os.org>. For more details please see
our [Reporting Guidelines](@ref coc-reporting-guide).
### Why do we need a Code of Conduct? Everyone knows not to be a jerk.
Sadly, not everyone knows this.
However, even if everyone was kind, everyone was compassionate, and everyone was
familiar with codes of conduct it would still be incumbent upon our community to
publish our own. Maintaining a code of conduct forces us to consider and
articulate what kind of community we want to be, and serves as a constant
reminder to put our best foot forward. But most importantly, it serves as a
signpost to people looking to join our community that we feel these values are
important.
### This is censorship! I have the right to say whatever I want!
You do -- in *your* space. If you'd like to hang out in *our* spaces (as
clarified above), we have some simple guidelines to follow. If you want to, for
example, form a group where RIOT is discussed using language inappropriate for
general channels then nobody's stopping you. We respect your right to establish
whatever codes of conduct you want in the spaces that belong to you. Please
honor this Code of Conduct in our spaces.
#### References
This FAQ was adapted from the [Django Code of Conduct FAQ](https://www.djangoproject.com/conduct/faq/)
[CoC-question-mail]: mailto:riot@riot-os.org
[CoC]: @ref coc
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/general/code_of_conduct/faq/).
This page will be removed after release 2026.04.

View File

@ -1,8 +1,5 @@
Code of Conduct Information {#coc-info}
Code of Conduct Information (Deprecated) {#coc-info}
===========================
The following documents are describing all matters around our code of conduct:
- The \subpage coc itself,
- The \subpage coc-reporting-guide, and
- The \subpage coc-faq
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/general/code_of_conduct/).
This page will be removed after release 2026.04.

View File

@ -1,80 +1,4 @@
# Reporting Guidelines {#coc-reporting-guide}
# Reporting Guidelines (Deprecated) {#coc-reporting-guide}
If you believe someone is violating the [code of conduct][CoC] we ask that you
report it to us by emailing <conduct@riot-os.org>. Currently, the recipients of
this email address are [\@OlegHahm](https://github.com/OlegHahm) (Oleg Hahm) and
[\@miri64](https://github.com/miri64) (Martine Lenders).
**All reports will be kept confidential.** In some cases we may determine that a
public statement will need to be made. If that's the case, the identities of all
victims and reporters will remain confidential unless those individuals instruct
us otherwise.
**If you believe anyone is in physical danger, please notify appropriate law
enforcement first.** If you are unsure what law enforcement agency is
appropriate, please include this in your report and we will attempt to notify
them.
If you are unsure whether the incident is a violation, or whether the space
where it happened is covered by this Code of Conduct, we encourage you to still
report it. We would much rather have a few extra reports where we decide to take
no action, rather than miss a report of an actual violation. We do not look
negatively on you if we find the incident is not a violation. And knowing about
incidents that are not violations, or happen outside our spaces, can also help
us to improve the Code of Conduct or the processes surrounding it.
In your report please include:
- Your contact info (so we can get in touch with you if we need to follow up)
- Names (real, nicknames, or pseudonyms) of any individuals involved. If there
were other witnesses besides you, please try to include them as well.
- When and where the incident occurred. Please be as specific as possible.
- Your account of what occurred. If there is a publicly available record (e.g.
forum post, a mailing list archive, or a public Matrix chat link) please include a link.
- Any extra context you believe existed for the incident.
- If you believe this incident is ongoing.
- Any other information you believe we should have.
### What happens after you file a report?
You will receive an email from one of the core community members as soon as
possible. We promise to acknowledge receipt within 24 hours (and will aim for
much quicker than that).
They will review the incident and determine:
- What happened.
- Whether this event constitutes a code of conduct violation.
- Who the bad actor was.
- Whether this is an ongoing situation, or if there is a threat to anyone's
physical safety.
If this is determined to be an ongoing incident or a threat to physical safety,
their immediate priority will be to protect everyone involved.
This means we may delay an "official" response until we believe that the
situation has ended and that everyone is physically safe.
Once the working group has a complete account of the events they will make a
decision as to how to response. Responses may include:
- Nothing (if we determine no violation occurred).
- A private reprimand from us to the individual(s) involved.
- A public reprimand.
- An imposed vacation (i.e. asking someone to "take a week off" from the forum, the Matrix chats, or a mailing
list).
- A permanent or temporary ban from some or all RIOT spaces (forum, Matrix chats, mailing lists,
etc.)
- A request for a public or private apology.
We'll respond within one week to the person who filed the report with either a
resolution or an explanation of why the situation is not yet resolved.
Once we've determined our final action, we'll contact the original reporter to
let them know what action (if any) we'll be taking. We'll take into account
feedback from the reporter on the appropriateness of our response, but we don't
guarantee we'll act on it.
#### Reference
These reporting guidelines were adapted from the [Django reporting guidelines](https://www.djangoproject.com/conduct/reporting/)
[CoC]: @ref coc
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/general/code_of_conduct/reporting/).
This page will be removed after release 2026.04.

View File

@ -1,290 +1,5 @@
Creating an application {#creating-an-application}
Creating an application (Deprecated) {#creating-an-application}
=======================
[TOC]
To create your own application you need to create a directory containing one or
multiple C file(s) with your source code and a Makefile. A template Makefile is
available in the `dist` folder of the
[RIOT repository](https://github.com/RIOT-OS/RIOT).
The main function {#the-main-function}
=================
After the board is initialized, RIOT starts two threads: the idle thread and
the main thread. The idle thread has the lowest priority and will run whenever
no other thread is ready to run. It will automatically use the lowest possible
power mode for the device. The main thread - configured with a default priority
that is right in the middle between the lowest and the highest available
priorities - is the first thread that runs and calls the `main()` function.
This function needs to be defined in the source code of the application
(typically located in `main.c`).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.c}
#include <stdio.h>
int main(void)
{
puts("Hello World!");
return 0;
}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The application's Makefile {#the-applications-makefile}
==========================
The minimal Makefile {#the-minimal-makefile}
--------------------
At minimum the Makefile of an application (see @ref getting-started) needs to
define the following macros:
* `APPLICATION`: should contain the name of your application
* `RIOTBASE`: specifies the path to your copy of the RIOT repository (note
that you may want to use `$(CURDIR)` here, to give a relative path)
The `BOARD` macro is also required and recommended to be set to `native` by
default, but is recommended to be overridable with the `?=` operator.
Additionally, it is required to include the `Makefile.include` from the
`RIOTBASE`.
~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
# Set the name of your application:
APPLICATION = foobar
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../../RIOT
include $(RIOTBASE)/Makefile.include
~~~~~~~~~~~~~~~~~~~~~~~~~~~
How to handle unsupported boards? {#handle-unsupported-boards}
---------------------------------
Sometimes it is necessary to exclude boards because they don't provide a
required functionality or don't have sufficient memory. RIOT's build system
looks for the macros `BOARD_BLACKLIST`, `BOARD_WHITELIST`, and
`BOARD_INSUFFICIENT_MEMORY`. Any board name that is not included in
`BOARD_WHITELIST` will issue a message that one has to expect errors if they
build the application for the board referred by that name. The list can also be
used by a CI system to not build the application for this board at all. A board
that is included in `BOARD_BLACKLIST` will show the same behavior. The build
system evaluates `BOARD_WHITELIST` first and then `BOARD_BLACKLIST`. The
`BOARD_INSUFFICIENT_MEMORY` macro is similar to `BOARD_BLACKLIST` but will
build in any case. A CI system can use the information provided by the
`BOARD_INSUFFICIENT_MEMORY` macro to skip the linking step in the build
process, since some linkers will issue an error if the code won't fit the
target board's flash memory or RAM.
Including modules {#including-modules}
-----------------
By default a RIOT application comprises only of the applications' code itself,
the kernel, and platform specific code. In order to use additional modules,
such as a particular [device driver](@ref drivers) or [a system library](@ref sys)
(including [networking capabilities](@ref net)), you have to append the modules'
names to the USEMODULE variable. For example, to build an application using the
SHT11 temperature sensor and UDP/IPv6 functionalities of the GNRC network stack,
your Makefile needs to contain these lines:
~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
USEMODULE += sht11
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_udp
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Modules typically pull in all required dependencies.
## Including source files in subfolders
By default, all source files in an application's (or any RIOT module's) directory
are automatically compiled as part of the application. In order to organize source
code in a directory structure, two different approaches can be used:
1. Make each subdirectory a separate RIOT module with a unique name inside its
Makefile, either by adding the directory's path to `DIRS` or with the [out-of-tree
module support](#external-modules).
2. Add the source files within subdirectories to `SRC`, either explicitly or with
Makefile wildcards.
Both approaches are illustrated and explained in `examples/basic/subfolders`.
## Setting Board-specific Dependencies
Required dependencies of applications may change depending on the
target board or architecture. This is especially
relevant for networking applications where multiple hardware implementations
exist and the appropriate implementation has to be chosen for the given board
or architecture.
To achieve this task elegantly, a `Makefile.board.dep` file can be
created in the application folder, which is automatically included and
evaluated by RIOT build system during the dependency resolution phase.
This ensures that all the relevant variables such as `FEATURES_USED` or the
`USEMODULE` list are fully populated.
~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.mk}
ifneq (,$(filter arch_esp,$(FEATURES_USED)))
USEMODULE += esp_wifi
endif
ifneq (,$(filter native native32 native64,$(BOARD)))
USEMODULE += netdev_default
endif
~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Helper tools
To help you start writing an application within RIOT, the build system provides
the `generate-example` `generate-test` make targets. These targets are wrappers
around the [riotgen](https://pypi.org/project/riotgen/) command line tool and
are helpful when starting to implement an application: all required files are
generated with copyright headers, doxygen groups, etc, so you can concentrate
on the module implementation.
For applications, the `Makefile` is generated with the dependencies (modules,
packages, required features) included.
**Usage:**
To generate an example application, e.g in the `examples` directory, from the
RIOT base directory, run:
```
make generate-example
```
To generate a test application, e.g in the `tests` directory, from the
RIOT base directory, run:
```
make generate-test
```
Then answer a few questions about the application:
- Application name: enter a name for your application. It will be used as both
the name of the application directory under `examples` or `tests` and by
the build system module (set in the `APPLICATION` variable).
- Application brief description: Describe in one line what is this application
about.
- Target board: select the default target board. The value is set to `native`
by default.
- Modules: give the list of dependency modules, separated by commas. For
example: ztimer,fmt
- Packages: give the list of dependency packages, separated by commas.
- Features required: give the list of CPU features (`periph_*`, etc) required
by the application, all separated by commas.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
Once completed, the application files are either located in
`examples/<application name>` or `tests/<application name>` depending on the
target used.
**Testrunner:** when using the `make generate-test`, you can also automatically
add a testrunner Python script. Just answer 'y' when prompted.
# Creating an out of tree application structure
Applications written for RIOT do not have to reside in the RIOT tree. Out of
tree applications, modules and boards are supported.
For a full application with custom board and modules, the following directory
tree can be used:
```
├── apps
│   └── my_app
│   └── Makefile
├── boards
│   └── my_board
├── modules
│   └── my_module
│   ├── include
│   │   └── my_module.h
│   ├── Makefile
│   ├── Makefile.include
│   └── my_module.c
└── RIOT
```
In this example tree, the `apps` directory contains a collection of applications
for the project. The modules directory could contain extra modules for the
applications.
The make file inside the application needs at least the following as bare minimum:
```
APPLICATION = my_app
PROJECT_BASE ?= $(CURDIR)/../..
RIOTBASE ?= $(PROJECT_BASE)/RIOT
# Optionally, provide paths to where external boards and/or modules
# reside, so that they can be included in the app
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
include $(RIOTBASE)/Makefile.include
```
The `RIOTBASE` variable tells the build system where to find the RIOT source
tree and to need to point to the RIOT source tree used for the application for
the application to work.
The RIOT directory contains the sources of RIOT here. This can be either a
direct checkout of the sources or a git submodule, whichever has your
preference.
If your project has separate modules or separate boards, these can be contained
inside a modules os boards directory. The RIOT build system has both
`EXTERNAL_MODULE_DIRS` and `EXTERNAL_BOARD_DIRS` variables to specify
directories that contain extra modules and extra boards.
## External Boards
External boards can be ported in an identical way as porting a regular board to
RIOT, see @ref porting-boards.
One approach can be to copy over an existing board and modify it to suit the
needs. Boards in the RIOT tree can be included and used as dependency in the
custom boards. In case you connect additional hardware to an upstream board
(such as e.g. an Arduino shield) or you require a different hardware
configuration (e.g. configuring some of the pins configured as ADC as
additional PWM outputs instead) a copy of the upstream board that is then
customized to the application needs is the best course of action.
## External Modules {#external-modules}
Similar to the external boards, external modules can be written in a similar way
as regular in-tree modules.
One modification is the include directory inside the module directory. For this
include directory to be added to the include path during compilation, the
following snippet is required in the modules `Makefile.include`:
```
USEMODULE_INCLUDES_my_module := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_my_module)
```
Note that the make variable (here `USEMODULE_INCLUDES_my_module`) must be unique
for every module to make this work. Including the module name here is usually
sufficient.
## Extra Makefile Scaffolding
A bit of extra, but optional, Makefile scaffolding can help to keep the project
easy to maintain. An extra `Makefile.include` in the root directory of the
project that sets the necessary variables can help to deduplicate settings.
This includes the `RIOTBASE` variable and the include to the RIOT
`Makefile.include`:
```
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
RIOTBASE ?= $(PROJECT_BASE)/RIOT
include $(RIOTBASE)/Makefile.include
```
Applications then just have to set the `PROJECT_BASE` variable and include this
makefile and don't have to each add the external board and module directories.
The application makefile would then look like this:
```
APPLICATION = my_app
PROJECT_BASE ?= $(CURDIR)/../..
include $(PROJECT_BASE)/Makefile.include
```
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/advanced_tutorials/creating_application/).
This page will be removed after release 2026.04.

View File

@ -1,194 +1,5 @@
Creating modules {#creating-modules}
Creating modules (Deprecated) {#creating-modules}
================
Modules in RIOT are well-defined units of code that provide a set of features
to your application. This includes also drivers and to a certain extent ports
for CPUs and boards (with some exceptions, see <!-- @ref porting-guide --> the
porting guide for further information).
The general structure {#the-general-structure}
=====================
Like @ref creating-an-application "applications", modules are directories
containing source files and a Makefile. Additionally their API can be defined
in one or more header files, residing in the include path of their
super-module.
E.g. the @ref sys_shell module is implemented in `sys/shell` and defines its
API in `sys/include/shell.h` and the @ref drivers_isl29020 driver is
implemented in `drivers/isl29020` and defines its API in
`drivers/include/isl29020.h`.
A module's Makefile just needs to include `Makefile.base` in the RIOT
repository:
~~~~~~~~~~~~~~~~~~~ {.mk}
include $(RIOTBASE)/Makefile.base
~~~~~~~~~~~~~~~~~~~
If your module's name differs from the name of the directory it resides in you
need to set the `MODULE` macro in addition.
When compiled a module always provides a `MODULE_<MODULENAME>` macro to the
system. This way, other modules can check if the module is available in the
current configuration or not.
Modules can be used by adding their name to the `USEMODULE` macro of your
application's Makefile.
### Pitfalls ###
The `MODULE` name should be unique or build breaks as modules overwrite the
same output file. This might for example lead to `undefined reference to` errors
in the linker which can be hard to track down.
This problem happened in the past for:
* Packages root directory (libfixmath/u8g2)
* boards/cpu/periph and their common boards/cpu/periph
Note: even if all boards and cpus implement the `board` and `cpu` modules, only
one is used in an application so there is no conflict.
Module dependencies
===================
Your module may depend on other modules to minimize code duplication. These
dependencies are defined in `Makefile.dep` with the following syntax:
~~~~~~~~~~~~~~~~~~~ {.mk}
ifneq (,$(filter your_module,$(USEMODULE))) # if module in USEMODULE
USEMODULE += dep1 # add dependencies to USEMODULE
USEMODULE += dep2
endif
~~~~~~~~~~~~~~~~~~~
Note, that `Makefile.dep` is processed only once so you have to take care to
add the dependency block for your module *before* your dependencies pull in
their dependencies.
Modules outside of RIOTBASE {#modules-outside-of-riotbase}
===========================
Modules can be defined outside `RIOTBASE`. In addition to add it to `USEMODULE`
the user needs to add the directory (or directories) containing external modules
to `EXTERNAL_MODULE_DIRS`.
External modules can optionally define the following files:
* `Makefile.include` file to set global build configuration like `CFLAGS` or add
API headers include paths to the `USEMODULE_INCLUDES` variable.
* `Makefile.dep` file to set module dependencies
***NOTE:*** The name of an external module must be unique (both in regard to other
external modules, as well to native RIOT modules). Additionally, the
directory containing the module must match the module name, e.g.
module `foo` must be located in `<PATH_IN_EXTERNAL_MODULE_DIRS>/foo`.
An example can be found in
[`tests/build_system/external_module_dirs`](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/external_module_dirs)
Pseudomodules {#pseudomodules}
=============
Pseudomodules are modules that are not static libraries, i.e. do not generate a
`<module name>.a` file.
To create a pseudomodule just add its name to `makefiles/pseudomodules.inc.mk`
with `PSEUDOMODULES += <modulename>` in alphabetical order.
A Pseudomodule may or may not have a source file associated with it. To make the
distinction between them we will refer to those that don't as true-Pseudomodules.
The main use case for true-Pseudomodules is to provide base information for
dependencies to other modules or information to the code base via the
`MODULE_<MODULENAME>` macro.
Pseudomodules with source code exist under a "real" `MODULE` since they will
generate a `<pseudomodule_name>.o` file grouped under that `MODULE`s
`<module_name>.a` file.
These modules appear in RIOT under two forms:
1. Conditionally included source files:
```
foo/
|----foo_bar.c
|----foo.c
|----Makefile
```
In `foo/Makefile` you add the source file to the `SRC` variable, conditioned on
the Pseudomodule inclusion
```mk
ifneq (,$(filter foo_bar,$(USEMODULE)))
SRC += foo_bar.c
endif
```
See `sys/net/ble/skald` for an example in code.
2. Using the `SUBMODULES` mechanism:
```
foo/
|----spam.c
|----ham.c
|----eggs.c
|----Makefile
```
```mk
# make all code end up in "foo_bar.a", this can be any name
MODULE := foo_bar
# ensure that "foo_ham" or "bar_foo_ham" builds "foo_ham.c".
BASE_MODULE := foo
# list of source files that are not SUBMODULES
SRC := spam.c
# enable submodules by setting SUBMODULES = 1
SUBMODULES = 1
```
When using `SUBMODULES` in a `MODULE` all `SRC` file excluded from `foo/Makefile`
will be considered `SUBMODULES`. In the example above `ham.c` and `eggs.c`.
These source files will be conditionally included depending if the modules have
been added, i.e. `USEMODULE += foo_ham foo_eggs` (it's the same as case 1 but
handled automatically in `Makefile.base`).
The `SUBMODULES` mechanism is more flexible since `BASE_MODULE` allows matching
the only parts of compounded module names and only match against part of that name.
See `sys/ztimer/Makefile` for an example in code.
`SUBMODULES` can also be true-pseudomodules, or become one by conditionally excluding
the source files by adding them to `SUBMODULES_NO_SRC`.
# Helper tools
To help you start writing a module, the RIOT build system provides the
`generate-module` make target. It is a wrapper around the
[riotgen](https://pypi.org/project/riotgen/) command line tool that is helpful
when starting to implement a module: all required files are generated with
copyright headers, doxygen groups, etc, so you can concentrate on the module
implementation.
The module source files are created in the `sys` directory.
**Usage:**
From the RIOT base directory, run:
```
make generate-module
```
Then answer a few questions about the driver:
- Module name: enter a name for your module. It will be used as both the name
of the module directory under sys, where the source files are created, and
the build system module (used with `USEMODULE`).
- Module doxygen name: Enter the name of module, as displayed in the
Doxygen documentation.
- Brief doxygen description: Describe in one line what is this module about.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
Once completed, the module files are located in
`sys/<module name>/<module name>.c` and `sys/include/<module name>.h`.
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/advanced_tutorials/creating_modules/).
This page will be removed after release 2026.04.

View File

@ -1,48 +1,4 @@
# Debugging Tools {#debugging-tools}
# Debugging Tools (Deprecated) {#debugging-tools}
## Undefined Behavior Sanitizer (ubsan) {#ubsan}
RIOT contains makefile convenience support for gcc/clang's undefined
behaviour sanitizer.
### Overview
Both gcc and clang allow generation on code that does runtime checks for
undefined behavior (UB).
E.g., the following code might trigger UB for some parameters:
```C
void test(int foo) {
return (foo << 24);
}
```
In this case, the signed shift would be alright unless:
- it would "push out" all bits to the left, with undefined runtime result. Here,
that happens on architectures with 16-bit integers.
- `foo` is negative, with implementation defined runtime results.
Using ubsan, these can be caught at runtime.
There are three modes for ubsan that define what happens when the sanitizer
observed undefined behaviour:
1. `trap` -> cause a trap
2. `msg_exit` -> print a message and exit
3. `msg_recover` -> print a message and continue
`trap` is available on all RIOT platforms, whereas `msg_exit` and `msg_recover`
are currently only available on `native` when building with gcc, as they require runtime support in
the form of `libubsan`.
The default is `trap`, or `msg_exit` if available (currently, on native:gnu only).
### How to use
1. build with `make all-ubsan`.
2. build with `UBSAN_MODE=[trap|msg_exit|msg_recover] make all-ubsan` to
override the ubsan mode.
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/build-system/debugging_aids/).
This page will be removed after release 2026.04.

View File

@ -1,118 +1,4 @@
# Hints for quicker & better RIOT development {#dev-best-practices}
# Hints for quicker & better RIOT development (Deprecated) {#dev-best-practices}
[TOC]
* Use the [methodology](#methodology) described below.
* Use [`ccache`](https://guide.riot-os.org/build-system/advanced_build_system_tricks/#speed-up-builds-with-ccache) to speedup compilation
## Coding "Dos" and "Don'ts": {#coding-dos-and-donts}
### Dos
* Use static memory. See also [Static vs. Dynamic Memory](#static-vs-dynamic).
* Select the priorities carefully.
* Minimize stack usage with `DEVELHELP` and `CREATE_STACKTEST`.
* Use threads to increase flexibility, modularity, and robustness by leveraging IPC.
* Use unsigned or signed integer (`unsigned`, `int`, `size_t` or `ssize_t`) for loop variables wherever possible, but keep in mind that on some platforms an `int` has a width of only 16-bit. In general, you should avoid types like `uint8_t` for loop iterators as they will probably make it more expensive on some platforms.
* Join and factor out parts of the code with existing code in RIOT, where it makes sense.
* Check all `size/length` parameters when passing memory, e.g. using `sizeof(x)` or `strlen(x)` as appropriate. Make sure you don't use the wrong one with a pointer.
* Make sure all code paths can be reached. Make sure there are no always `true/false` conditions.
* Make sure all critical sections (`lock/unlock`, `acquire/release`, ...) are always closed on every code path.
* Make sure return values are consistent with our API documentation.
* Use `assert()` statements to check parameters rather than returning an error code at run-time, to keep the code size down.
* Use the `DEBUG(...)` macro rather than `log_x(...)`
* Declare all internal module variables and functions `static`
* Make sure variables are reduced in scope as much as possible
* Use an appropriate signedness in your variables
* Make sure the variables are big enough to prevent overflow. Be aware that the code may run on platforms with different sizes of variables. For example, `int/unsigned` is only 16-bit on msp430 and avr8. If in doubt, use portable types.
* Reduce the number of function calls as far as possible without duplicating code.
* Use good judgement when using `static inline` functions and macros. If they are used in multiple places, is the increase in performance worth the penalty in code size?
* Use memory judiciously in general. For example:
```c
typedef enum {
A,
B,
...
} foo_t;
int bar(foo_t v)
{
int abc;
...
switch(v) {
case A:
abc = 23;
break;
case B:
abc = 42;
break;
...
}
...
}
/* VS */
typedef enum {
A = 23,
B = 42,
...
} foo_t;
int bar(foo_t v) {
int abc = v;
...
}
```
### Don'ts
* Don't use too many threads. Try not to use more than one thread per module. Don't create threads for one-time tasks.
* Don't use the POSIX wrapper if implementing something from scratch.
* Don't allocate big chunks of memory (for instance the IPC message queue) on the stack, but use rather static memory for that.
* Don't over-provision memory.
* Don't pass stack memory between different contexts unless you can prove conclusively that it won't be a problem.
* Don't use enums for flags, because flags have a width in memory that is in most cases smaller than `sizeof(enum)` (most bitfields are 16 bits max, on most of our newer platforms, `sizeof(enum)` is however 32 bits). This results in every assignment needed to be cast to either `uint8_t` or `uint16_t`. With macros you don't need to cast since they are typeless. Making the enum packed makes its width unpredictable in terms of alignment issues, when used in struct.
* Don't duplicate code from elsewhere in the RIOT code base, unless there is a very good reason to do so.
* Don't duplicate code within your own code, unless there is a very good reason to do so. Use internal functions to this end.
* Don't mix up logical and bitwise operations (`!` vs `~`, or `&&` vs `&`)
## Methodology: emulator first, target IoT hardware last! {#methodology}
The below methodology is recommended, using well-known de facto standard tools from the FLOSS community that are compatible with RIOT. Using the below workflow improves time-to-running-code compared to typical IoT software workflows (which can be as retro as "LED-driven" debugging).
0. For newbies, preliminaries are typically faster with the provisioned virtual environment setup, e.g. with **Vagrant**.
1. To check your code, first use available **static analysis** as much as possible initially, which means (i) enable all compiler warnings and fix all problems found, then (ii) use a supported linter such as **cppcheck** to find bad coding patterns (i.e. code smells) and identify misuse of standard APIs.
2. Next, use available **dynamic analysis** tools to find further defects while running the code on **RIOT native**, which means (i) running unit tests and integration tests on RIOT native emulator, and (ii) using **Valgrind** memcheck, as well as the **GCC stack smashing detection**, to detect and avoid undefined behavior due to invalid memory access.
3. In case of networked applications or protocols, test **several instances of native** communicating via a virtual network mimicking the targeted scenario, which means (i) either using the default virtual full-mesh or other topologies configured via DESvirt, and (ii) using **Wireshark** to capture and analyze virtual network traffic, e.g. to ensure protocol packets are syntactically correct, and to observe network communication patterns.
4. In case of incorrect behavior at this stage, analyze the system state for semantic errors on native using the standard debugger **gdb**, which allows virtually unlimited conditional breakpoints, record and replay, catchpoints, tracepoints and watchpoints.
5. In case of suspected performance bottleneck, use performance profilers **gprof**, or else cachegrind, to identify precisely the bottlenecks.
6. At this stage the implementation has proven bug-free on the native emulator. One can thus finally move on to hardware-in-the-loop, which means (i) flashing the binary on the targeted IoT hardware, typically using standard flasher **OpenOCD** or **edbg**, and (ii) using the **RIOT shell** running on the target IoT device(s) for easier debugging on the target hardware.
7. In case the hardware is not available on-site, one can consider remotely flashing and testing the binary on supported open-access testbeds, e.g. [IoT-LAB](https://www.iot-lab.info) hardware is fully supported by RIOT.
8. In case of failure, after analyzing the failure and attempting to fix the defect, go back to step 1 to make sure the fix did not itself introduce a new defect.
## Static vs. Dynamic Memory {#static-vs-dynamic}
In your C program you have to decide where the memory you want to use comes from.
There are two ways to get memory in your C code:
1. Define static memory.
2. Use dynamic memory (call `malloc()`/`free()` to get memory from the heap).
Both ways have some drawbacks which are listed here.
If you want to analyze the static memory consumption of your code you can use [otm](https://github.com/LudwigOrtmann/otm) or `make cosy`.
### Static memory
* Access the memory in one operation O(1) ⇒ real time condition
* Programmer needs to know the amount of memory on compile time
* Leads to over and undersized buffers
* Forces the programmer to think about the amount of need memory at compile time
### Dynamic memory
* `malloc()` and `free()` are implemented in your `libc` (RIOT on ARM: `newlib`/`picolib`)
* Runtime behavior is not predictable
* Code can request the amount of memory it needs on runtime
* On most platforms: the size of the heap is `sizeof(<RAM>)-sizeof(<static memory>)`
* If you reduce your usage of static memory your heap gets bigger
* On some platforms calling `free()` will not or not always make heap memory available again (see @ref oneway_malloc on MSP430)
* Programmer needs to handle failed memory allocation calls at runtime
* Static code analysis is unable to find errors regarding memory management
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/misc/dev_best_practices/).
This page will be removed after release 2026.04.

View File

@ -1,501 +1,5 @@
Writing a Device Driver in RIOT {#driver-guide}
Writing a Device Driver in RIOT (Deprecated) {#driver-guide}
===============================
This document describes the requirement, design objectives, and some
non-function details when writing device drivers in/for RIOT. The term device
driver in this context includes all 'CPU-external' devices connected to the CPU
typically via peripherals like SPI, I2C, UART, GPIO, and similar. CPU
peripherals itself are in RIOT not considered to be device drivers, but
peripheral or low-level drivers. Typical devices are network devices like
radios, Ethernet adapters, sensors, and actuators.
[TOC]
# General Design Objectives {#driver-guide-design-objectives}
Device drivers should be as easy to use as possible. This implies an
'initialize->ready' paradigm, meaning, that device drivers should be ready to use
and in operation right after they have been initialized. On top, devices should
work with physical values wherever possible. So e.g. sensors should return
already converted values in some physical unit instead of RAW data, so that
users can work directly with data from different devices directly without having
to care about device specific conversion.
However, please avoid the use of `float` or `double`. Instead, multiply to the
next SI (or appropriate) unit. E.g. if an ADC would return values like `1.23 V`,
chose to return `1230 mV` instead.
Additionally, towards ease of use, all device drivers in RIOT should provide a
similar 'look and feel'. They should behave similarly in terms of their state
after initialization, like their used data representation and so on.
Secondly, all device drivers should be optimized for minimal RAM/ROM usage, as
RIOT targets (very) constrained devices. This implies that instead of exposing
all thinkable functionality, the drivers should focus on exporting and
implementing a device's core functionality, thus covering ~95% of the use cases.
Third, it should always be possible to handle more than a single device of the
same kind. Drivers and their interfaces are thus designed to keep their state
information in a parameterized location instead of driver defined global
variables.
Fourth, RIOT defines high-level interfaces for certain groups of devices (i.e.
netdev for network devices, SAUL for sensors and actuators), which enable users
to work with a wide variety of devices without having to know much about the
actual device that is mapped.
Fifth, during initialization, we make sure that we can communicate with a device.
Other functions should check the dev pointer is not void, and should also handle
error return values from the lower layer peripheral driver implementations,
where there are some.
Sixth, device drivers SHOULD be implemented independent of any CPU/board code.
To achieve this, the driver implementations should strictly be based on
platform independent interfaces as the peripheral drivers, xtimer, etc.
# General {#driver-guide-general}
## Documentation {#driver-guide-doc}
Document what your driver does! Most devices come with a very large number of
features, while the corresponding device driver only supports a subset of them.
This should be clearly stated in the device driver's documentation so that
anyone wanting to use the driver can find out the supported features without
having to scan through the code.
## Device descriptor and parameter configuration {#driver-guide-types}
Each device MUST supply a data structure, holding the devices state and
configuration, using the naming scheme of `DEVNAME_t` (e.g. `dht_t`, or
`at86rf2xx_t`). In the context of RIOT, we call this data structure the device
descriptor.
This device descriptor MUST contain all the state data of a device. By this, we
are not limited to the number of instances of the driver we can run
concurrently. The descriptor is hereby used for identifying the device we want
to interact with, and SHOULD always be the first parameter for all device driver
related functions.
Typical things found in these descriptors are e.g. used peripherals (e.g. SPI or
I2C bus used, interfacing GPIO pins), data buffers (e.g. RX/TX buffers where
needed), or state machine information.
On top of the device descriptor, each device driver MUST also define a data
structure holding the needed configuration data. The naming scheme for this type
is `DEVNAME_params_t`. In contrary to the device descriptor, this data structure
should only contain static information, that is needed for the device
initialization as it is preferably allocated in ROM.
A simple I2C temperature sensors' device descriptor could look like this:
@code{.c}
typedef struct {
tmpabc_params_t p; /**< device configuration parameter like I2C bus and bus addr */
int scale; /**< some custom scaling factor for converting the results */
} tmpabc_t;
/* with params being */
typedef struct {
i2c_t bus; /**< I2C bus the device is connected to */
uint8_t addr; /**< the device's address on the bus */
} tmpabc_params_t;
@endcode
**NOTE:** In many cases it makes sense, to copy the `xxx_params` data into the
device descriptor during initialization. In some cases, it is, however, better
to just link the `params` data via pointer and only copy selected data. This way,
configuration data that is only used once can be read directly from ROM, while
often used fields (e.g. used peripherals) are stored directly in the device
descriptor and one saves hereby one de-referencing step when accessing them.
## Default device configuration {#driver-guide-config}
Each device driver in RIOT MUST supply a default configuration file, named
`DEVNAME_params.h`. This file should be located in the `RIOT/drivers/...`. The
idea is that this file can be overridden by an application or a board, by
simply putting a file with the same name in the application's or the board's
include folders, while RIOT's build system takes care of preferring those files
instead of the default params file.
A default parameter header file for the example temperature sensor above would
look like this (`tmpabc_params.h`):
@code{.c}
/* ... */
#include "board.h" /* THIS INCLUDE IS MANDATORY */
#include "tmpabc.h"
/* ... */
/**
* @brief Default configuration parameters for TMPABC sensors
* @{
*/
#ifndef TMPABC_PARAM_I2C
#define TMPABC_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef TMPABC_PARAM_ADDR
#define TMPABC_PARAM_ADDR (0xab)
#endif
#ifndef TMPABC_PARAMS
#define TMPABC_PARAMS { .i2c = TMPABC_PARAM_I2C \
.addr = TMPABC_PARAM_ADDR }
#endif
/** @} */
/**
* @brief Allocation of TMPABC configuration
*/
static const tmpabc_params_t tmpabc_params[] = {
TMPABC_PARAMS
}
/* ... */
@endcode
Now to influence the default configuration parameters, we have these options:
First, we can override one or more of the parameter from the makesystem, e.g.
@code{.sh}
CFLAGS="-DTMPABC_PARAM_ADDR=0x23" make all
@endcode
Second, we can override selected parameters from the board configuration
(`board.h`):
@code
/* ... */
/**
* @brief TMPABC sensor configuration
* @{
*/
#define TMPABC_PARAM_I2C (I2C_DEV(1))
#define TMPABC_PARAM_ADDR (0x17)
/** @} */
/* ... */
@endcode
Third, we can define more than a single device in the board configuration
(`board.h`):
@code{.c}
/* ... */
/**
* @brief Configure the on-board temperature sensors
* @{
*/
#define TMPABC_PARAMS { \
.i2c = I2C_DEV(1), \
.addr = 0x31 \
}, \
{ \
.i2c = I2C_DEV(1), \
.addr = 0x21 \
}
/** @} */
/* ... */
@endcode
And finally, we can simply override the `tmpabc_params.h` file as described
above.
## Compile-time configuration documentation {#driver-guide-doxygen}
The macros that configure the driver during compilation is added to the listing
for [Compile time configurations](@ref config). Refer to the following example
that exposes
[TMP00x sensor](https://github.com/RIOT-OS/RIOT/blob/master/drivers/include/tmp00x.h#L96-L157)
to [sensors group](@ref config_drivers_sensors).
@code
/**
* @defgroup drivers_tmp00x_config TMP006/TMP007 Infrared Thermopile
* Sensor driver compile configuration
* @ingroup config_drivers_sensors
* @{
*/
/**
* @brief Default Address
* ....
*/
#ifndef TMP00X_I2C_ADDRESS
#define TMP00X_I2C_ADDRESS (0x40)
#endif
....
/** @} */
@endcode
Sub-groups defined for different types of drivers can be found in
[drivers/doc.txt](https://github.com/RIOT-OS/RIOT/blob/master/drivers/doc.txt)
## Initialization {#driver-guide-initialization}
In general, the initialization functions should do the following:
- initialize the device descriptor
- initialize non-shared peripherals they use, e.g. GPIO pins
- test for device connectivity, e.g. does an SPI/I2C slave react
- reset the device to a well-defined state, e.g. use external reset lines or do
a software rest
- do the actual device initialization
For testing a device's connectivity, it is recommended to read certain
configuration data with a defined value from the device. Some devices offer
`WHO_AM_I` or `DEVICE_ID` registers for this purpose. Writing and reading back
some data to the device is another valid option for testing its responsiveness.
For more detailed information on how the signature of the init functions should
look like, please refer below to the specific requirements for network devices
and sensors.
## Return Values {#driver-guide-return-values}
As stated above, we check communication of a device during initialization and
handle error return values from the lower layers, where they exist. To prevent
subsequent misuse by passing NULL pointers and similar to the subsequent
functions, the recommended way is to check the parameter using `assert`, e.g.:
@code{.c}
int16_t tmpabc_read(const tmpabc_t *dev)
{
assert(dev);
/* ... */
return value;
}
@endcode
Whenever you implement status/error return values in your driver, magic numbers
MUST ***NOT*** be used. Instead, use negative `errno` codes (such as `-EIO` for
an input/output error) and *document* every single error code that can be
return for each function using the `reval` Doxygen command. E.g. like this:
@code
/**
* @brief Initialize the foo device and its descriptor
* @param[out] dev Device descriptor to initialized
* @param[in] params Device initialization parameters
*
* @retval 0 Success
* @retval -ENXIO No foo device connected to the I2C bus
* @retval -ENODEV Device using the foo I2C address is not a foo device
* etc.
*/
int foo_init(foo_t *dev, const foo_params_t *params);
@endcode
You can multiplex this information whenever this is reasonable, as long as a
negative return value indicates an error without exceptions. E.g. like this:
@code
/**
* @brief Perform a relative humidity measurement
* @param[in] dev Humidity sensor to perform the measurement on
*
* @return The relative humidity in percent
* @retval -EIO Communication with the sensor failed
*/
int foo_humidity(const foo_t *dev);
@endcode
### Documenting Return Values {#driver-guide-return-values-doc}
With the exception of functions returning `void`, all return values have to be
documented. Use the `return` Doxygen command to describe what is returned. In
order to document special return value (such as error codes), use the `retval`
command. The `retval` command expects the specific value to document as first
argument (no spaces in the value allowed!), and a description (spaces allowed
here) as second. It is safe to use both `return` and `retval` commands, or just
one of them - whatever makes most sense for a given function.
## General Device Driver Checklist {#driver-guide-general-checklist}
- *MUST*: the supported feature set and any custom behavior is clearly
documented
- *MUST*: device descriptor is defined: `devab_t`
- *MUST*: device parameter `struct` is defined: `devab_params_t`
- *MUST*: a default parameter configuration file is present, e.g.
`RIOT/drivers/devab/include/devab_params.h`
- *MUST*: all error and status return codes are named, e.g.
`DEVAB_OK, DEVAB_NOSPI, DEVAB_OVERFLOW, ...`
- *MUST*: use `const devab_t *dev` when the device descriptor can be access
read-only
## Build system integration
### Internal include files
If the driver contains internal include files, a `Makefile.include` must be
added in the driver implementation directory, with the following content
(adapted to the name of the driver module):
```
USEMODULE_INCLUDES_<driver name> := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_<driver name>)
```
### External dependencies
If the driver has other module or CPU features dependencies (like `xtimer` or
`periph_i2c`), they must be added in the `$(RIOTBASE)/drivers/Makefile.dep`
file in a block like below (this is an example, you'll have to adapt to the
driver requirements):
```
ifneq (,$(filter <driver name>,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
USEMODULE += xtimer
endif
```
**Warning:** Please be careful with alphabetical order when modifying this file.
## Helper tools
To help you start writing a device driver, the RIOT build system provides the
`generate-driver` make target. It is a wrapper around the
[riotgen](https://pypi.org/project/riotgen/) command line tool that is helpful
when starting to implement a driver: all minimum files are generated with
copyright headers, doxygen groups, etc, so you can concentrate on the driver
implementation.
**Usage:**
From the RIOT base directory, run:
```
make generate-driver
```
Then answer a few questions about the driver:
- Driver name: enter a name for your driver. It will be used as both the name
of the driver directory where the source files are created and the build
system module.
- Driver doxygen group name: Enter the name of the driver, as displayed in the
Doxygen documentation.
- Brief doxygen description: Describe in one line what is this driver about.
- Parent driver Doxygen group: Enter the Doxygen group the driver belongs to.
It can be `actuators`, `display`, `misc`, `netdev`, `sensors`, `storage`.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
# Sensors {#driver-guide-sensors}
## SAUL {#driver-guide-saul}
All sensor drivers SHOULD implement the SAUL interface. It is however
recommended, that the drivers are written in a way, that the drivers do not
solely export the SAUL interface, but map the SAUL interface upon a driver
specific one.
For example, a temperature driver provides the following function (`tmpabc.c`):
@code{.c}
int16_t tmpabc_read(tmpabc_t *dev);
@endcode
which then can easily be mapped to SAUL (`tmpabc_saul.c`):
@code{.c}
int saul_read(saul_t *dev, phydat_t *data)
{
memset(data, 0, sizeof(phydat_t));
data->x = tmpabc_read((tmpabc_t *)dev);
data->unit = UNIT_TEMP_C;
data->scale = -2;
return 1;
}
@endcode
This ensures the versatility of the device driver, having in mind that one might
want to use the driver without SAUL or maybe in a context without RIOT.
## Initialization {#driver-guide-sensor-initialization}
Sensor device drivers are expected to implement a single initialization
function, `DEVNAME_init`, taking the device descriptor and the device's
parameter struct as argument:
@code{.c}
int tmpabc_init(tmpabc_t *dev, const tmpabc_params_t *params);
@endcode
After this function is called, the device MUST be running and usable.
## Value handling {#driver-guide-sensor-value-handling}
### Value semantics {#driver-guide-sensor-value-semantics}
All sensors in RIOT MUST return their reading results as real physical values.
When working with sensor data, these are the values of interest, and the
overhead of the conversion is normally neglectable.
### Typing {#driver-guide-sensor-types}
All values SHOULD be returned using integer types, with `int16_t` being the
preferred type where applicable.
In many situations, the physical values cannot be mapped directly to integer
values. For example, we do not want to map temperature values to integers
directly while using their fraction. The recommended way to solve this is by
scaling the result value using decimal fixed point arithmetic, in other words,
just return centi-degree instead of degree (e.g. 2372c°C instead of 23.72°C).
## Additional Sensor Driver Checklist {#driver-guide-sensor-checklist}
- *MUST*: mandatory device parameters are configurable through this file, e.g.
sampling rate, resolution, sensitivity
- *MUST*: an init function in the style of
`int devab_init(devab_t *dev, const devab_params_t *params);` exists
- *MUST*: after initialization, the device must be operational
- *MUST*: all error and return values are named, e.g.
`DEVAB_OK, DEVAB_NODEV, ...`
- *MUST*: all 'read' functions return values in their physical representation,
e.g. `centi-degree, Pa, lux, mili-G`
- *MUST*: all 'read' functions return integer values, preferably `int16_t`
- *SHOULD*: if multiple dimensions are read, they SHOULD be combined into a
data structure
- *SHOULD*: the driver implements the SAUL interface
- *SHOULD*: the driver exports functions for putting it to sleep and waking up
the device
# Network devices {#driver-guide-netdev}
## Initialization {#driver-guide-netdev-init}
The initialization process MUST be split into 2 steps: first, initialize the
device descriptor and if applicable the used peripherals, and secondly do the
actual device initialization. The reason for this is, that before a device is
actually activated and can start to process data, the network stack for the
device needs to be initialized. By supplying a second init function, that does
the actual initialization, we can hand the control over when this is done to the
actual network stacks.
The initialization functions SHOULD follow this naming scheme:
@code{.c}
void netabc_setup(netabc_t *dev, const netabc_params_t *params);
int netabs_init(netabc_t *dev);
@endcode
## netdev {#driver-guide-netdev-interface}
Device driver for network device SHOULD implement the `netdev` interface. It is
up to the implementer, if the device driver also offers a device specific
interface which is then mapped to the `netdev` interface, or if the device
driver can be purely interfaced using `netdev`. While the second option is
recommended for efficiency reasons, this is not mandatory.
## Additional Network Device Driver Checklist {#driver-guide-netdev-checklist}
- *MUST*: a setup function in the style of
`int devab_setup(devab_t *dev, const devab_params_t *params);` exists
- *MUST*: an init function in the style of `int devnet_init(devnet_t *dev)`
exists
- *SHOULD*: the driver implements 'netdev' [if applicable]
# TODO {#driver-guide-todo}
Add some information about how to handle multiple threads, when to use mutexes,
and how to deal with interrupts? And especially patterns for being nice from
other threads and power consumption point of view...
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/advanced_tutorials/device_drivers/).
This page will be removed after release 2026.04.

View File

@ -1,151 +1,5 @@
Emulators {#emulators}
Emulators (Deprecated) {#emulators}
=========
RIOT supports the [Qemu](https://www.qemu.org/) and [Renode](https://renode.io/)
emulation tools. The emulation offers a hardware-free development environment
for quickly testing applications.
From the build system point of view, the emulation support in RIOT is
transparent compared to the usual workflow: simply add `EMULATE=1` to the
command line and the emulator supported by the board will be called instead of
the board flashing/debugging tool.
Targets compatible with `EMULATE=1` are `term`, `cleanterm`, `debug`,
`debugserver` and `test`.
If a board supports multiple emulators, the emulator backend can be selected
with the `RIOT_EMULATOR` variable. Possible values are `qemu` and `renode`.
If no emulator is specified by the board configuration (e.g. in its
`Makefile.include`), the default emulator is `renode`.
The boards with emulator supported can be listed using the
`info-emulated-boards` target:
```
$ make info-emulated-boards
```
## Features
Be aware that not all hardware features provided by a board - and described as
such in the build system by `FEATURES_PROVIDED` - are implemented in emulators.
For example, the `hifive1b` provides the RTC peripheral feature but this is not
implemented by the renode driver.
So you may expect some failures when running advanced applications on the
emulator.
## Usage
All emulators can be used the same way. Just add `EMULATE=1` to the command
line.
To start an emulator and connect to the serial port of the emulated board, run:
```
$ EMULATE=1 make BOARD=<board> -C <application directory> all term
```
To start an emulator with a GDB server and connect a GDB client to it, run:
```
$ EMULATE=1 make BOARD=<board> -C <application directory> all debug
```
To start an automatic test script with the emulated board, run:
```
$ EMULATE=1 make BOARD=<board> -C <test application directory> all test
```
The `EMULATOR_SERIAL_PORT` variable can be used to specify a custom serial port
on the host running the emulator.
The default value is built based on a random temporary directory:
`$(EMULATOR_TMP_DIR)/uart`.
The randomness of this variable allows several emulated sessions of the same
application with the same board to run in parallel.
# Qemu
## Overview
[Qemu](https://www.qemu.org/) is a machine emulator and virtualizer. It can
be used to emulate regular computer architectures but also some microcontroller
based boards such as the @ref boards_microbit.
## Installation
Qemu is usually available via the package manager of common Linux distributions.
Depending on your local system, the installation procedure is described on the
[qemu website](https://www.qemu.org/download/).
## Boards supported
So far, in RIOT, only the @ref boards_microbit board is supported with qemu.
## Configuration
The QEMU emulated serial port is exposed on a local Unix socket, redirected to a
local PTY file (using [socat](http://www.dest-unreach.org/socat/)). This makes
it possible to open the PTY file in a regular serial port.
# Renode
## Overview
[Renode](http://renode.io) is a virtual development tool for multinode embedded
networks (both wired and wireless) enabling a scalable workflow for building
effective, tested and secure IoT systems, created by
Antmicro](http://antmicro.com/blog/2017/08/renode-press-release/).
It can easily be used to run applications on a broad range of embedded platforms
without any changes in the code itself, as if you were running on real
hardware - but with more possibilities.
## Installation
### From package
Packages for macOS, deb-based and rpm-based systems, for Windows and for Arch
Linux are available on [GitHub](https://github.com/renode/renode/releases/latest).
### From source
Follow the installation instructions on Renode's
[GitHub](https://github.com/renode/renode#installation) page.
If you choose to build renode from source, after the compilation is successful,
ensure that `renode` is available on your `PATH`.
One way to do so, is via symlink:
```
sudo ln -s path/to/renode/repository/renode /usr/local/bin/renode
```
### Testing
After installation, verify that Renode is working using `renode --help`. You
should be presented with a help screen.
## Documentation
Documentation for Renode can be found on [Read The Docs](https://renode.readthedocs.io).
## Usage
From within RIOT-OS, add `EMULATE=1` to start the emulation. The emulation
expects a board definition file in `boards/<BOARD>/dist/board.resc`.
The board definition file will tell Renode how to setup an emulation session.
The application binary file (`*.elf`) is available using the variable
`$image_file`.
For an example, refer to `boards/cc2538dk/dist/board.resc`.
The renode logging level can be configured from the command line using the
following variables:
- `RENODE_SHOW_LOG`: set it to 1 to show the logs in the standard output
- `RENODE_LOG_LEVEL`: set it to the desired log level, default is 2 (warning)
The renode monitor and serial console GUI windows are hidden by default but
they can be displayed by setting `RENODE_SHOW_GUI` to 1 in the command line.
If uart0 is not the default serial port used for stdio, use `RENODE_SYSBUS_UART`
to specify a custom one in the board `Makefile.include`.
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/misc/emulators/).
This page will be removed after release 2026.04.

View File

@ -1,523 +1,5 @@
Flashing via RIOT's Build System {#flashing}
Flashing via RIOT's Build System (Deprecated) {#flashing}
================================
[TOC]
General Approach {#flashing-general}
================
In general, flashing a board from RIOT is as straight forward as typing in a
shell (with the application directory as current working directory):
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make BOARD=<BOARD-TO-FLASH> flash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This will **rebuild** ***AND*** **flash** the application in the current working
directory for board `<BOARD-TO-FLASH>`, using its default programming tool. If
you want to use an alternative programming tool, say `stm32flash`, use:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
make BOARD=<BOARD-TO-FLASH> PROGRAMMER=stm32flash flash
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To flash without rebuilding use `flash-only` as target instead of `flash`.
Supported Tools {#flashing-supported-tools}
===============
RIOT supports plenty of flashing tools, that are below grouped into general
flashing tools that support multiple MCU families, and specialized tools that
only support one platform.
Note that some programmers require additional configuration on a per board
level or rely on features only available on some boards. Hence, a given board
may not be supported by a programmer listed as supported for the platform of
the board due to a missing board feature, bootloader, or similar.
To ease use the programmers are given by the value to pass via
`PROGRAMMER=<value>`, rather than the official spelling of the programmer.
Compatibility Matrix of Generic Tools {#flashing-supported-tools-generic}
--------------------
<!-- Note: Add flashers that theoretically support multiple platforms here,
even if RIOT does only have integration for one platform. The missing
integration may be added later on. -->
MCU Family | `bmp` | `dfu-util` | `jlink` | `openocd` | `pyocd` | `uf2conv`
---------------|--------|------------|---------|-----------|---------|----------
ATmega | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ATXmega | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
CC13xx / C26xx | ✗ | ✗ | ✓ | ✓ (1) | ✗ | ✗
CC2538 | ✗ | ✗ | ✓ | ✗ | ✗ | ✗
EFM32 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
ESP8266 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ESP32 (Xtensa) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ESP32 (RISC-V) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
FE310 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
GD32V | ✗ | ✗ | ✗ | ✓ (1) | ✗ | ✗
Kinetis | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
LPC1768 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
LPC23xx | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
MIPS32r2 | ✗ | ✗ | ✓ | ✗ | ✗ | ✗
MSP430 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
nRF51 | ✗ | ✗ | ✓ | ✓ | ✓ | ✗
nRF52 | ✓ | ✗ | ✓ | ✓ | ✓ | ✓
RP2040 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
SAM | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
Stellaris | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
STM32 | ✓ | ✓ | ✓ | ✓ | ✗ | ✗
Remarks:
1. Requires a patched version of the programmer tool
Specialized Flashing Tools Per Platform {#flashing-supported-tools-special}
---------------------------------------
The following list only contains single-platform flashing tools. Tools that
support multiple platforms are given in section
\ref flashing-supported-tools-generic above.
### AVR
- `avrdude`
### CC13xx / CC26xx
- `uniflash`
### CC2538
- `cc2538-bsl`
### ESP8266 / ESP32 (Xtensa) / ESP32 (RISC-V)
- `esptool`
### LPC23xx
- `lpc2k_pgm`
### MSP430
- `mspdebug`
- `goodfet`
### nRF52
- `adafruit-nrfutil`, `uf2conv` (requires Adafruit bootloader), see @ref boards_common_adafruit-nrf52-bootloader
- `nrfutil` (required nRF bootloader)
- `nrfjprog` (requires a separate J-Link debugger)
### RP2040
- `picotool`
### SAM
- `bossa`
- `edbg`
### STM32
- `stm32flash`
- `stm32loader`
- `cpy2remed` (requires integrated ST-Link programmer, e.g. Nucleo boards)
- `robotis-loader` (requires robotis bootloader, only one board supported)
Programmer Configuration {#flashing-configuration}
========================
This section will list additional configuration options to control the behavior
of a programming tool, such as selecting the hardware adapter used for
programming.
OpenOCD Configuration {#flashing-configuration-openocd}
---------------------
### OPENOCD_DEBUG_ADAPTER
`OPENOCD_DEBUG_ADAPTER` can be set via command line or as environment variable
to use non-default flashing hardware.
### OPENOCD_RESET_USE_CONNECT_ASSERT_SRST
`OPENOCD_RESET_USE_CONNECT_ASSERT_SRST` can be set via command line or as
environment variable to `0` to disable resetting the board via the `SRST` line.
This is useful when the `SRST` signal is not connected to the debug adapter or
when using cheap ST-Link V2 clones with broken `SRST` output. Note that it may
not be possible to attach the debugger while the MCU is in deep sleeping mode.
If this is set to `0` by the user, the user may need a carefully timed reset
button press to be able to flash the board.
### OPENOCD_PRE_FLASH_CMDS
`OPENOCD_PRE_FLASH_CMDS` can be set as environment variable to pass additional
commands to OpenOCD prior to flashing, e.g. to disable flash write protection.
### OPENOCD_PRE_VERIFY_CMDS
`OPENOCD_PRE_VERIFY_CMDS` can be set as environment variable to pass additional
flags to OpenOCD prior to verifying the flashed firmware. E.g. this is used
in the `pba-d-01-kw2x` to disable the watchdog to prevent it from disrupting
the verification process.
### OPENOCD_PRE_FLASH_CHECK_SCRIPT
`OPENOCD_PRE_FLASH_CHECK_SCRIPT` can be set via command line or as
environment variable to execute a script before OpenOCD starts flashing. It is
used for Kinetis boards to prevent bricking a board by locking the flash via
magic value in the flash configuration field protection bits.
The script is expected to exit with code `0` if flashing should resume, or with
exit code `1` if flashing should be aborted.
### OPENOCD_CONFIG
`OPENOCD_DEBUG_ADAPTER` can be set via command line or as environment variable
to use non-default OpenOCD configuration file.
### OPENOCD_TRANSPORT
`OPENOCD_TRANSPORT` can be set via command line or as environment variable to
select a non-default transport protocol. E.g. to use JTAG rather than SWD for a
board that defaults to SWD use:
```
make PROGRAMMER=openocd OPENOCD_TRANSPORT=jtag
```
Note that OpenOCD configuration file of a given board may only support SWD or
JTAG. Also JTAG requires more signal lines to be connected compared to SWD and
some internal programmers only have the SWD signal lines connected, so that
JTAG will not be possible.
stm32flash Configuration {#flashing-configuration-stm32flash}
------------------------
It is possible to automatically boot the STM32 board into the in-ROM bootloader
that `stm32flash` communicates with for flashing by connecting the RST pin to
DTR and the BOOT pin (or BOOT0 for STM32 MCU families with BOOT0 and BOOT1 pins)
to RTS of the TTL adapter. In addition, set `STM32FLASH_RESET` to `1` via
environment or command line to actually issue a reset with BOOT (or BOOT0)
pulled high prior flashing to enter the bootloader, and a second reset with BOOT
(or BOOT0) pulled low to reboot into the application. `STM32FLASH_RESET`
defaults to `0` as of know, as with `PROGRAMMER=stm32flash STM32FLASH_RESET=1`
additional terminal flags are set, so that `make term` doesn't accidentally
keeps the reset signal pulled low or boot the board into the bootloader.
The TTL adapter this was tested with had inverted RTS and DTR signal. By setting
`STM32FLASH_RESET_INVERT` to `1` RIOT will assume RTS and DTR signals to be
inverted, by setting it to `0` non-inverted signals will be generated. As of
now, `STM32FLASH_RESET_INVERT` is by default `1`. This may change if it
becomes evident that non-inverted TTL adapters are in fact more common than
inverted adapters.
MSPDEBUG Configuration {#flashing-configuration-mspdebug}
----------------------
All options can be passed as environment variables or as make arguments.
All options except for `DEBUGSERVER_PORT` apply to both debugging and flashing
alike.
`MSPDEBUG_PROGRAMMER` is used to set the hardware programmer/debugger to use
for programming and debugging. See `mspdebug --help` or `man mspdebug` for a
list of programmers.
`MSPDEBUG_PROTOCOL` is used to specify the debugger protocol. It is typically
set by the board used. Only JTAG and Spi-Bi-Wire are supported.
`MSPDEBUG_TTY` is used to connect via TTY interface instead of directly via
USB to the debugger. Usually, this is not required.
`DEBUG_ADAPTER_ID` is used to select the debugger/programmer by its serial. If
not set, `mspdebug` will select the first device with matching vendor and
product ID. Unless multiple debuggers of the same type are connected, this
options is typically not needed.
`DEBUGSERVER_PORT` is used to specify the TCP port to listen for GDB to
connect to. It defaults to 2000.
Handling Multiple Boards With UDEV-Rules {#multiple-boards-udev}
========================================
When developing and working with multiple boards the default `PORT`
configuration for a particular board might not apply anymore so `PORT` will need
to be specified whenever calling `make term/test`. This can also happen if
multiple `DEBUGGERS/PROGRAMMERS` are present so `DEBUG_ADAPTER_ID` will also
need to be passed. Keeping track of this will become annoying.
One way of handling this is to use `udev` rules to define `SYMLINKS` between the
boards serial port (`riot/tty-<board-name>`) and the actual serial port
(dev/ttyACM* or other). With this we can query the rest of the boards serial
`dev` information (`DEBUG_ADAPTER_ID`, `PORT`, etc.) to always flash and open a
terminal on the correct port.
Procedure:
- use `udevadm info /dev/ttyACM0` to query the udev database for information on
device on port `/dev/ttyACM0`.
or use `udevadm info --attribute-walk --name /dev/ttyACM0` for more detailed
output when the first level of information isn't enough
- create a udev rule with information of the device and one parent to create a
matching rule in `/etc/udev/rules.d/70-riotboards.rules`.
~~~~~~~~~~~~~~~~~~~
# samr21-xpro
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", \
ATTRS{idProduct}=="2111", ATTRS{manufacturer}=="Atmel Corp.", \
ATTRS{serial}=="ATML2127031800004957", SYMLINK+="riot/tty-samr21-xpro"
~~~~~~~~~~~~~~~~~~~
- reload rules: `udevadm control --reload-rules`
- Boards `PORT` are symlinked to /dev/riot/tty-`board-name`.
- Create a `makefile.pre` that will query the real `PORT` and the
`DEBUG_ADAPTER_ID` from the `SYMLINK` info
~~~~~~~~~~~~~~~~~~~
PORT = /dev/riot/tty-$(BOARD)
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n /ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p})
~~~~~~~~~~~~~~~~~~~
- You can now add `makefile.pre` to `RIOT_MAKEFILES_GLOBAL_PRE` as an environment
variable or on each `make` call:
~~~~~~~~~~~~~~~~~~~
$ RIOT_MAKEFILES_GLOBAL_PRE=/path/to/makefile.pre make -C examples/basic/hello-world flash term
~~~~~~~~~~~~~~~~~~~
@note if set as an environment variable it would be a good idea to add a
variable to enable/disable it, e.g:
~~~~~~~~~~~~~~~~~~~
ifeq (1,$(ENABLE_LOCAL_BOARDS))
PORT = /dev/riot/tty-$(BOARD)
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n /ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p})
endif
~~~~~~~~~~~~~~~~~~~
Handling Multiple Versions of the Same BOARD
--------------------------------------------
The above procedure works fine when handling different boards, but not
multiple times the same board, e.g: multiple `samr21-xpro`.
An option for this would be to add an identifier of that board to the mapped
`riot/tty-*`, there are multiple ways of handling this but in the end it means
having a way to identify every copy.
Another way would be to map the `DEBUG_ADAPTER_ID` in the name:
~~~~~~~~~~~~~~~~~~~
SYMLINK+="riot/node-$attr{serial}
~~~~~~~~~~~~~~~~~~~
But it will require to know in advance the serial number of each board you want
to use. Another option would be to add some kind of numbering and defining
multiple symlinks for each board. e.g. for `samr21-xpro` number `n`:
~~~~~~~~~~~~~~~~~~~
# samr21-xpro
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", \
ATTRS{idProduct}=="2111", ATTRS{manufacturer}=="Atmel Corp.", \
ATTRS{serial}=="ATML2127031800004957", SYMLINK+="riot/tty-samr21-xpro", \
SYMLINK+="riot/tty-samr21-xpro-n"
~~~~~~~~~~~~~~~~~~~
Then, when flashing, the number can be specified and the parsing adapted:
~~~~~~~~~~~~~~~~~~~
ifneq(,$(BOARD_NUM))
PORT = /dev/riot/tty-$(BOARD)-$(BOARD_NUM)
else
PORT = /dev/riot/tty-$(BOARD)
endif
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n /ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p})
~~~~~~~~~~~~~~~~~~~
~~~~~~~~~~~~~~~~~~~
BOARD=samr21-xpro BOARD_NUM=n make flash term
~~~~~~~~~~~~~~~~~~~
In the end, this would be the same as using the serial, but a simple number might
be easier to handle.
Notes
-----
Udev only parses SUBSYSTEM and one parent. For others, we will rely on ENV
variables defined by 60-serial.rules
So the current filename should be higher than 60-serial.rules
If for some reason re-writing the serial is needed there is a windows tool:
https://remoteqth.com/wiki/index.php?page=How+to+set+usb+device+SerialNumber
Documentation:
--------------
* The whole documentation
http://reactivated.net/writing_udev_rules.html#udevinfo
* Udev manpage
http://manpages.ubuntu.com/manpages/eoan/en/man7/udev.7.html
Handling Multiple Boards Without UDEV-Rules {#multiple-boards-no-udev}
===========================================
This is a simpler approach to the above mentioned issue. The solution here only
uses a makefile script for selecting the debugger and serial port. No
administrative privileges (e.g. to configure Udev) are required.
One of the limitations of the solution described here is that it currently
doesn't work with multiple boards of the same type. This limitation is a
limitation of the script and not of the mechanism used, it is possible to adapt
the script to support multiple boards of the same type. This modification is
left as an exercise to the reader.
The following Make snippet is used:
~~~~~~~~~~~~~~~~~~~
LOCAL_BOARD_MAP ?= 1
# Adapt this list to your board collection
SERIAL_nucleo-f103rb ?= 066BFF343633464257254156
SERIAL_same54-xpro ?= ATML2748051800005053
SERIAL_samr21-xpro ?= ATML2127031800008360
SERIAL_nrf52dk ?= 000682223007
ifeq (1,$(LOCAL_BOARD_MAP))
# Retrieve the serial of the selected board
BOARD_SERIAL = $(SERIAL_$(BOARD))
# Check if there is a serial for the board
ifneq (,$(BOARD_SERIAL))
# Set the variables used by various debug tools to the selected serial
SERIAL ?= $(BOARD_SERIAL)
DEBUG_ADAPTER_ID ?= $(BOARD_SERIAL)
JLINK_SERIAL ?= $(BOARD_SERIAL)
# Use the existing script to grab the matching /dev/ttyACM* device
PORT ?= $(shell $(RIOTTOOLS)/usb-serial/ttys.py --most-recent --format path --serial $(SERIAL))
endif
endif
~~~~~~~~~~~~~~~~~~~
The array of board serial numbers has to be edited to match your local boards.
The serial numbers used here is the USB device serial number as reported by
the debugger hardware. With the `make list-ttys` it is reported as the 'serial':
~~~~~~~~~~~~~~~~~~~
$ make list-ttys
path | driver | vendor | model | model_db | serial | ctime
-------------|---------|--------------------------|--------------------------------------|-----------------------|--------------------------|---------
/dev/ttyUSB0 | cp210x | Silicon Labs | CP2102 USB to UART Bridge Controller | CP210x UART Bridge | 0001 | 15:58:13
/dev/ttyACM1 | cdc_acm | STMicroelectronics | STM32 STLink | ST-LINK/V2.1 | 0671FF535155878281151932 | 15:58:04
/dev/ttyACM3 | cdc_acm | Arduino (www.arduino.cc) | EOS High Power | Mega ADK R3 (CDC ACM) | 75230313733351110120 | 15:59:57
/dev/ttyACM2 | cdc_acm | SEGGER | J-Link | J-Link | 000683475134 | 12:41:36
~~~~~~~~~~~~~~~~~~~
When the above make snippet is included as `RIOT_MAKEFILES_GLOBAL_PRE`, the
serial number of the USB device is automatically set if the used board is
included in the script. This will then ensure that the board debugger is used
for flashing and the board serial device is used when starting the serial
console.
It supports command line parameters to filter by vendor name, model name, serial
number, or driver. In addition, the `--most-recent` argument will only print the
most recently added interface (out of those matching the filtering by vendor,
model, etc.). The `--format path` argument will result in only the device path
being printed for convenient use in scripts.
Handling Multiple Boards: Simplest Approach {#multiple-boards-simple}
===========================================
Passing `MOST_RECENT_PORT=1` as environment variable or as parameter to
make will result in the most recently connected board being preferred over the
default PORT for the selected board.
For some boards `TTY_BOARD_FILTER` is provided, which filters TTYs e.g. by
vendor or model to only considered TTYs that actually may belong to the selected
board. E.g. for Nucleo boards this is `--model 'STM32 STLink'`, as they all use
an integrated STLink as programmer. As long as only one TTY is provided from an
STLink, this will reliably select the correct TTY for an Nucleo regardless of
which TTY was most recently connected. Some boards even provide info that
allows to always reliably identify them correctly (e.g. the firmware on the
ATmega16U2 used as USB to UART converted on Arduino Mega2560 will provide
identification data unique to that board).
Adding Board Filters
--------------------
After connecting as many variants of the board you target (and maybe some others
to test that the filter actually filters out non-matching boards). Then first
run `./dist/tools/usb-serial/ttys.py` without arguments and study the output.
When a genuine Arduino Mega 2560, a genuine Arduino Mega ADK (a variant of the
Mega 2560),a cheap Arduino Mega 2560 clone, a BBC micro:bit v2, and a
Nucleo F767-ZI are connected, the following output is shown:
path | driver | vendor | model | model_db | serial | ctime | iface_num
-------------|---------|--------------------------|--------------------------------------|------------------------------------------------------|--------------------------------------------------|----------|----------
/dev/ttyACM0 | cdc_acm | Arduino (www.arduino.cc) | 0042 | Mega 2560 R3 (CDC ACM) | 857353134333519002C1 | 12:13:55 | 0
/dev/ttyACM1 | cdc_acm | Arduino (www.arduino.cc) | EOS High Power | Mega ADK R3 (CDC ACM) | 75230313733351110120 | 15:59:57 | 0
/dev/ttyACM2 | cdc_acm | STMicroelectronics | STM32 STLink | ST-LINK/V2.1 | 0670FF535155878281123912 | 10:00:39 | 2
/dev/ttyACM3 | cdc_acm | Arm | BBC micro:bit CMSIS-DAP | ARM mbed | 99053602000528334c41b84da1f2f09d000000006e052820 | 12:21:03 | 1
/dev/ttyUSB0 | cp210x | Silicon Labs | CP2102 USB to UART Bridge Controller | CP2102/CP2109 UART Bridge Controller [CP210x family] | 0001 | 16:57:27 | 0
Now we add arguments to the invocation of `ttys.py` to filter the list e.g.
by model, vendor etc. (note: as regex!) ideally until only the target boards
are listed. Some boards do not provide enough information to e.g. tell them
apart from other boards using the same USB to UART bridge or the same debugger.
In that case we have to live with some "bycatch".
In the case of the Arduino Mega 2560 the parameters
`--vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'` will narrow down the
list to only show the genuine Arduino Mega versions. Se we add to the
`Makefile.include` in `boards/arduino-mega2560`:
```Makefile
TTY_BOARD_FILTER := --vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'
```
Note that also matching the `R3` in `Mega 2560 R3` would prevent matching older
or newer revisions than R3, so we don't add that to the regex.
Advances Board Filters
----------------------
In most cases, just adding a simple `TTY_BOARD_FILTER` is sufficient. If we
however have wildly different flavors of the same board (e.g. genuine Arduino
Mega 2560 with an ATmega16U2 and clones with a cheap USB to UART bridge) that we
all want to support, we have to instead provide a `TTY_SELECT_CMD` that prints
the path to and the serial of the TTY (separated by a space) and exists with
`0` if a TTY was found, or that exists with `1` and prints nothing when no TTY
was found. We can still use the `ttys.py` script to detect all Arduino Mega
2560 versions: We first try to detect a genuine Arduino Mega and fall back to
selecting cheap USB UART bridges when that fails using the `||` shell operator:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path serial \
--vendor 'Arduino' \
--model-db 'Mega 2560|Mega ADK' || \
$(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path serial \
--driver 'cp210x'
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/build-system/flashing/).
This page will be removed after release 2026.04.

View File

@ -25,7 +25,8 @@ subset of modules).
For instructions on how to configure via `CFLAGS` check the
@ref config "identified compile-time configurations". To learn how to use
Kconfig in RIOT, please refer to the @ref kconfig-users-guide.
Kconfig in RIOT, please refer to the
[User's guide to configure with Kconfig](https://guide.riot-os.org/build-system/kconfig/#configure-using-menuconfig).
Default configurations {#default-configurations}
----------------------

View File

@ -1,166 +1,5 @@
IO-Mapping and Shields {#iomaps}
IO-Mapping and Shields (Deprecated) {#iomaps}
======================
[TOC]
Introduction {#iomaps-intro}
============
Arduino has popularized the concept of adding an abstraction layer over the
MCU GPIOs and ADC multiplexer as "Digital Pins" and "Analog Pins". For historic
reasons as well as to express appreciation for the introduction of concept, we
prefix features and macros that map board pins to MCU pins with `ARDUINO`.
@note This means, we also explicitly use the Arduino feature for boards that
are neither official Arduino products nor compatible.
I/O Mappings {#iomaps-mapping}
============
All I/O mappings are provided by the `arduino_iomap.h` header file. This is
provided either by the board directly (e.g. in
`<RIOT git repo>/board/<board>/include/arduino_iomap.h`) or by the board
family (e.g. in `board/common/<board family>/include/arduino_iomap.h`).
To add support to new boards, start by copy-pasting the `arduino_iomap.h` from
an existing board and adapt/extend the macros as needed. Finally, add the
features to the `Makefile.features` and `KConfig` files of the board that
indicate the presence of the added mappings.
Digital Pins {#iomaps-mapping-gpio}
------------
The feature `arduino_pins` is provided by boards that do have a mapping to
digital pins. The GPIO for e.g. `D3` is provided as `ARDUINO_PIN_3`. The
number of the highest digital pin is provided as `ARDUINO_PIN_LAST`. E.g. if
`ARDUINO_PIN_LAST` is 42, digital pins `D0` to `D42` are typically provided.
@warning Some boards do have "gaps" in the pin mapping. It could be that
e.g. `ARDUINO_PIN_5` is defined, but `ARDUINO_PIN_4` is not.
@note Often aliases are provided for analog pins in digital mode. E.g.
to use the pin `A3` as digital pin, `ARDUINO_PIN_A3` can be used
to avoid looking up what digital number that pin has.
Analog Pins {#iomaps-mapping-adc}
-----------
The feature `arduino_analog` is provided by boards that do have a mapping of
ADC lines to analog pins. E.g. the ADC line corresponding to pin `A5` would
be `ARDUINO_A5`. The number of the highest analog pin is provided as
`ARDUINO_ANALOG_PIN_LAST`. The macro `ARDUINO_ANALOG_PIN_LAST` is defined if
and only if a mapping is provided (so it can be used to test for this feature).
@warning Some boards do have "gaps" in the analog pin mapping. It could be
that e.g. `ARDUINO_A3` is defined, but `ARDUINO_A2` is not.
DAC Pins {#iomaps-mapping-dac}
--------
The feature `arduino_dac` is provided by boards that do have a mapping of
DAC pins to DAC lines. E.g. the DAC line for the pin DAC1 would be
`ARDUINO_DAC1`. The number of the highest DAC pin is provided as
`ARDUINO_DAC_PIN_LAST`. The macro `ARDUINO_DAC_PIN_LAST` is defined if
and only if a mapping is provided (so it can be used to test for this feature).
@warning Some boards do have "gaps" in the analog pin mapping. It could be
that e.g. `ARDUINO_DAC4` is defined, but `ARDUINO_DAC3` is not.
PWM Pins {#iomaps-mapping-pwm}
--------
The feature `arduino_pwm` is provided by boards that do have a mapping of
digital pins to PWM settings. E.g. the PWM device connected to the digital pin
`D11` would be `ARDUINO_PIN_11_PWM_DEV` and the channel would be
`ARDUINO_PIN_11_PWM_CHAN`. A PWM frequency for all PWM pins is defined as
`ARDUINO_PWM_FREQU`.
@warning Typically only few digital pins support PWM. For pins without PWM
output no `ARDUINO_PIN_<NUM>_PWM_DEV` macro and no
`ARDUINO_PIN_<NUM>_PWM_DEV` is defined.
UART Device {#iomaps-mapping-uart}
-----------
The feature `arduino_uart` is provided by boards that do provide an UART device
mapping. For the official Arduino boards and compatible boards, the
`ARDUINO_UART_D0D1` macro refers to the UART device that uses the digital pins
`D0` and `D1`.
Please extend the table below to keep naming among boards of the same form
factor consistent:
| Form Factor | Macro Name | Description |
|:---------------- |:--------------------- |:--------------------------------- |
| Arduino Nano | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Arduino Uno | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Arduino Mega | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Seeedstudio XIAO | `ARDUINO_UART_DEV` | UART on D7 (RXD) and D6 (TXD) |
I²C Buses {#iomaps-mapping-i2c}
---------
The feature `arduino_i2c` is provided by boards that do provide an I²C bus
mapping.
| Form Factor | Macro Name | Description |
|:---------------- |:--------------------- |:--------------------------------- |
| Arduino Nano | `ARDUINO_I2C_NANO` | D18 (SDA) / D19 (SCL) |
| Arduino Uno | `ARDUINO_I2C_UNO` | D18 (SDA) / D19 (SCL) |
| Arduino Mega | `ARDUINO_I2C_UNO` | D20 (SDA) / D21 (SCL) |
| Arduino Zero | `ARDUINO_I2C_UNO` | D20 (SDA) / D21 (SCL) |
| Arduino Due | `ARDUINO_I2C_UNO` | D70 (SDA) / D71 (SCL) |
| Seeedstudio XIAO | `ARDUINO_I2C_DEV` | D4 (SDA) / D5 (SCL) |
The `ARDUINO_I2C_UNO` refers to the I²C bus next to the AREF pin (the topmost
pins on header on the top right) of an Arduino Uno compatible board, e.g.
such as the Arduino Mega2560. Even though the Arduino UNO, the Arduino MEGA2560,
the Arduino Zero and the Arduino Zero all having the I²C bus at the exact same
mechanical positions, the digital pin number of the I²C bus next to the AREF
differs between the versions.
SPI Buses {#iomaps-mapping-spi}
---------
The feature `arduino_spi` is provided by boards that do provide an SPI bus
mapping.
| Form Factor | Macro Name | Description |
|:---------------- |:------------------------- |:------------------------------------- |
| Arduino Nano | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Nano | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Arduino Uno | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Uno | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Arduino Mega | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Mega | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Seeedstudio XIAO | `ARDUINO_SPI_DEV` | D10 (MOSI) / D9 (MISO) / D8 (SCK) |
@note The original AVR based Arduinos only have a single hard SPI bus which
is only provided via the ISP header. Many modern Arduino compatible
boards do not provide the ISP header and only have SPI on D11/D12/D13
provided.
Mechanical and Electrical Compatibility {#iomaps-shields}
=======================================
Modules implementing drivers for extension boards, a.k.a. shields, can express
their mechanical and electrical requirements by depending on `arduino_shield_...`
features. The following list of features currently exists:
| Feature Name | Compatibility Claim |
|:--------------------- |:------------------------------------------------------------- |
| `arduino_shield_nano` | Board has side headers compatible with the Arduino Nano |
| `arduino_shield_uno` | Board has side headers compatible with the Arduino UNO |
| `arduino_shield_mega` | Board has side headers compatible with the Arduino MEGA |
| `feather_shield` | Board has headers compatible with the Adafruit Feather boards |
| `xiao_shield` | Board has headers compatible with the Seeedstudio XIAO boards |
@note A board providing `arduino_shield_mega` **MUST** also provide
`arduino_shield_uno`, as Arduino MEGA boards are backward compatible to
shields for the Arduino UNO.
E.g. a module that implements the W5100 based Ethernet shield would depend on
both `arduino_shield_uno` and `arduino_shield_isp` for electrical compatibility
as well as on `arduino_spi` for SPI bus mapping and `arduino_pins` for the CS
pin mapping. This module could reuse the existing `w5100` driver and just
supply the correct `w5100_params_t` using the I/O mappings.
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/misc/io_mapping_and_shields/).
This page will be removed after release 2026.04.

View File

@ -1,567 +1,4 @@
# Kconfig in RIOT {#kconfig-in-riot}
# Kconfig in RIOT (Deprecated) {#kconfig-in-riot}
[TOC]
The objective of using Kconfig in RIOT is to configure software modules at
compile-time. This means having a standard way of:
- Exposing configurable parameters
- Assigning application and user-specific configurations
- Verifying these parameters
- Check possible values
- Check valid configuration considering inter-dependencies
- Applying the selected configuration
# Overview {#kconfig-overview}
## Exposure
Modules in RIOT expose their configurable parameters via
Kconfig files (for more information on Kconfig syntax check
[the specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html)).
In these files documentation, restrictions, default values and dependencies can
be expressed.
Kconfig files are structured through the file system mirroring the current
module distribution. In time, all modules will have Kconfig files to make
themselves configurable through this system.
## Assignment
The user can assign values to the exposed parameters, either by manually writing
'.config' files or using an interface such as Menuconfig. Parameters with no
assigned values will take the default ones. For a detailed distinction between
Kconfig and '.config' files see [Appendix B](#kconfig-appendix-b).
## Verification and application
Using '.config' and Kconfig files the build system takes care of doing the
necessary checks on the values according to the parameter definition. After
that, the `autoconf.h` header file is generated, it contains all the
configurations in the form of (`CONFIG_` prefixed) macros.
---
# User's guide to configure with Kconfig {#kconfig-users-guide}
## Configure using menuconfig {#configure-using-menuconfig}
In order to use the graphical interface menuconfig to configure the
application, run `make menuconfig` in the application's folder. All available
configurations (based on the used modules) for the particular platform will be
presented. By default, the configuration of a module via Kconfig is not enabled.
In order to activate the configuration via Kconfig the corresponding option
should be selected. That will enable the configuration of all inner options, if
available.
Once the desired configuration is achieved save the configuration to the
default proposed path and exit. The saved configuration will be applied when
the code is compiled (`make all`).
If the current configuration will be used in the future it can be saved in the
application's folder as `user.config`, using the 'Save' option in menuconfig.
This way it will be persistent after cleaning the application directory
(`make clean`).
## Configure using '.config' files {#configure-using-files}
The second way to configure the application is by directly writing '.config'
files. Two files will be sources of configuration during the generation of the
final header file: `app.config` and `user.config`, which should be placed
inside the application's folder. `app.config` sets default configuration
values for the particular application, the user can override them by setting
them in `user.config`. Additionally, further `.config` files can be added to
the variable `KCONFIG_ADD_CONFIG`, which will be applied _after_ default CPU and
board configurations, `app.config` and `user.config`. This means that they will
have priority.
Let's say that the `SOCK_UTIL_SCHEME_MAXLEN` symbol in `sock_util` module needs
to be configured. The `user.config` file could look like:
```Makefile
# activate configuration of sock_util using Kconfig
CONFIG_KCONFIG_MODULE_SOCK_UTIL=y
# change scheme part length
CONFIG_SOCK_UTIL_SCHEME_MAXLEN=24
```
In this case, there is no need for using menuconfig. It's enough just to call
`make all` in the application folder, as this configuration will be read and
applied. Note that if any dependency issue occurs, warnings will be generated
(e.g. not enabling the configuration of a module via Kconfig).
## Application configuration with Kconfig {#app-config-kconfig}
To expose application-specific configuration options a `Kconfig` file can
be placed in the application's folder. For an example of this you can check
the [tests/build_system/kconfig](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/kconfig)
application.
## Configuration via environment variables {#env-config-kconfig}
For easy debugging of configuration or testing new modules by compiling them
into existing applications, one can also use environment variables prefixed by
`RIOT_CONFIG_`. To achieve the same configuration exemplified in
@ref configure-using-files, e.g., you could also use
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ {.sh}
RIOT_CONFIG_KCONFIG_MODULE_SOCK_UTIL=1 \
RIOT_CONFIG_SOCK_UTIL_SCHEME_MAXLEN=24 \
make
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
All the checks that apply for `.config` files also are done with this approach.
Mind that this is only meant to be used during development. In production,
please set the configuration via `.config` files.
## A note on the usage of CFLAGS
When a certain module is being configured via Kconfig the configuration macro
will no longer be overridable by means of CFLAGS (e.g. set on the
compilation command or on a Makefile). Consider this if you are getting a
'redefined warning'.
---
# Integration into the build system {#kconfig-integration-into-build-system}
The integration of Kconfig into the build system is mainly done in
`makefiles/kconfig.mk`.
## Steps during the build process {#kconfig-steps-build-process}
![Output of every step of the build process](kconfig_integration.svg)
### 0. Module dependency resolution
The resolution of module dependencies is performed by the build
system where all the used modules and packages end up listed in the `USEMODULE`
or `USEPKG` make variables.
#### Input
- Makefiles.
#### Output
- `USEMODULE` and `USEPKG` variables.
### 1. Module listing
The list of modules needed for the particular build is dumped into the
`$ (GENERATED_DIR)/Kconfig.dep` file, where each module is translated into a
Kconfig symbol as documented in [Appendix A](#kconfig-appendix-a).
#### Input
- `USEMODULE` and `USEPKG` variables
#### Output
- `$ (GENERATED_DIR)/Kconfig.dep` file
### 2. Merging all configuration sources {#kconfig-steps-merge-configs}
In this step configuration values are taken from multiple sources and merged
into a single `out.config` configuration file. This file is temporary and is
removed on clean. If the user needs to save a particular configuration
set, a backup has to be saved (this can be done using the menuconfig interface)
so it can be loaded later in this step.
To accomplish merging of multiple input files, the `genconfig` script is
used. Note that **the order matters**: existing configuration values are
merged in the order expressed in the input section, where the last value
assigned to a parameter has the highest priority. If no configuration files are
available all default values will be applied.
`out.config` is the only configuration input for the `autoconf.h` in the
[generation step](#kconfig-steps-header-gen).
Additionally this step generates a file `out.config.d` which holds the
information of all the used Kconfig files in Makefile format. This file is
included by the build system and allows to re-trigger the generation of
`out.conf` whenever a Kconfig file is modified.
#### Input
- Optional:
- `$ (APPDIR)/app.config`: Application specific default configurations.
- `$ (APPDIR)/user.config`: Configurations saved by user.
#### Output
- `$ (GENERATED_DIR)/out.config` file.
### 3. Menuconfig execution (optional)
Menuconfig is a graphical interface for software configuration. It is used for
the configuration of the Linux kernel. This section explains the process
that occurs when RIOT is being configured using the menuconfig interface.
The main `Kconfig` file is used in this step to show the configurable
parameters of the system. Kconfig will filter inapplicable parameters (i.e.
parameters exposed by modules that are not being used) based on the file
`$ (GENERATED_DIR)/Kconfig.dep` generated in step 1.
Note that if Kconfig is not used to configure a module, the corresponding
header files default values will be used.
`out.config` is one of the inputs for menuconfig. This means that any
configuration that the application defines in the `app.config` or a backup
configuration from the user in `user.config` are taken into account on the
first run (see [Appendix C](#kconfig-appendix-c)).
In this step the user chooses configuration values (or selects the minimal
configuration) and saves it to the `out.config` file. Here the user can
choose to save a backup configuration file for later at a different location
(e.g. a `user.config` file in the application folder).
If any changes occur to `out.config`, the
[generation of autoconf.h](#kconfig-steps-header-gen) is executed automatically.
#### Input
- `/Kconfig` file.
- Optional:
- `$ (APPDIR)/app.config`
- `$ (APPDIR)/user.config`
- `$ (GENERATED_DIR)/out.config`
#### Output
- Updated `$ (GENERATED_DIR)/out.config` file.
- `$ (GENERATED_DIR)/out.config.old` backup file.
### 4. Generation of the autoconf.h header {#kconfig-steps-header-gen}
With the addition of Kconfig a dependency has been added to the build
process: the `$ (GENERATED_DIR)/autoconf.h` header file. This header file is
the main output from the Kconfig configuration system. It holds all the macros
that should be used to configure modules in RIOT:
`CONFIG_<module>_<parameter>`.
In order to generate the `autoconf.h` file the `genconfig` script is used.
Inputs for this script are the main `Kconfig` file and `out.config`
configuration file, which holds the selected values for the exposed parameters.
#### Input:
- `$ (GENERATED_DIR)/out.config` file.
- Main `Kconfig` file exposing configuration of modules.
#### Output:
- `$ (GENERATED_DIR)/autoconf.h` configuration header file.
- Optional:
- `$ (GENERATED_DIR)/deps/*/*.h` header files that allow incremental builds
### Summary of files
These files are defined in `kconfig.mk`.
| File | Description |
| ---------------| ----------- |
| `Kconfig` | Defines configuration options of modules. |
| `Kconfig.dep` | Holds a list of the modules that are being compiled. |
| `app.config` | Holds default application configuration values. |
| `user.config` | Holds configuration values applied by the user. |
| `out.config` | Configuration file containing all the symbols defined in `autoconf.h`. |
| `out.config.d` | Dependency file of `out.config` containing the list of Kconfig files used to generate it. |
| `autoconf.h` | Header file containing the macros that applied the selected configuration. |
## Kconfig symbols in Makefiles
As '.config' files have Makefile syntax they can be included when building,
which allows to access the applied configuration from the build system.
During migration this is also useful, as it gives the ability to check if a
parameter is being configured via Kconfig or a default value via `CFLAGS` could
be injected. For example:
```Makefile
ifndef CONFIG_USB_VID
CFLAGS += -DCONFIG_USB_VID=0x1209
endif
```
Symbols will have the same name as the configuration macros (thus will always
have the `CONFIG_` prefix). As the configuration file is loaded in
`Makefile.include` care should be taken when performing checks in the
application's Makefile. The symbols will not be defined until after including
`Makefile.include`.
---
# Transition phase {#kconfig-transition-phase}
## Making configuration via Kconfig optional {#kconfig-configuration-optional}
During transition to the usage of Kconfig as the main configuration tool for
RIOT, the default behavior will be the traditional one: expose configuration
options in header files and use CFLAGS as inputs. To allow optional
configuration via Kconfig, a convention will be used when writing Kconfig files.
Modules should be contained in their own `menu` entries, this way the user
can choose to enable the configuration via Kconfig for an specific module.
These entries should define a dependency on the module they configure (see
[Appendix A](#kconfig-appendix-a) to see how to check if a module is being
used).
The module configuration must be enabled either via make dependency modelling.
## Modelling CPUs and boards {#kconfig-cpu-boards-fekconfig-cpu-boards}
CPUs and boards are being modelled in Kconfig. The following is a guide on how to
organize and name the symbols.
### CPUs
The proposed hierarchy for the classification of CPUs is as follows:
```
+------------+
More Specific | CPU_MODEL |
+ +------------+
|
|
| +------------+
| | CPU_FAM |
| +------------+
|
|
| +------------+
| | CPU_CORE |
| +------------+
|
|
v +------------+
Less Specific | CPU_ARCH |
+------------+
```
Where each hierarchy is defined as:
- `CPU_MODEL`: The specific identifier of the used CPU, used for some CPU
implementations to differentiate between different memory
layouts.
- `CPU_FAM`: An intermediate identifier between CPU and CPU_MODEL that
represents a sub-group of a Manufacturers CPU's.
- `CPU_CORE`: The specific identifier of the core present in the CPU.
- `CPU_ARCH`: The specific identifier of the architecture of the core defined
in `CPU_CORE`.
In order to model the hierarchies, a hidden boolean symbol must be declared for
each. The name of the symbol must begin with the correspondent prefix and must
be followed by the specific value. For instance, the 'samd21' family symbol is
named `CPU_FAM_SAMD21`.
In addition, a default value to the correspondent common symbol must be defined.
The default value must be guarded by the boolean symbol correspondent to the
hierarchy.
Features may be provided by any hierarchy symbol. Usually symbols are selected
from more specific to less specific. This means that a `CPU_MODEL_<model>`
symbol usually would select the correspondent `CPU_FAM_<family>` symbol,
which would in turn select the `CPU_CORE_<core>`. This may change in some cases
where `CPU_COMMON_` symbols are defined to avoid repetition. For convenience and
if it makes sense within a CPU vendor family, it's also allowed to use
intermediate grouping levels, like `CPU_LINE_<xxx>` used for STM32.
In addition to the symbols of the hierarchy described above, a default value
to the `CPU` symbol should be assigned, which will match the value of the `CPU`
Makefile variable in the build system.
The declaration of the symbols should be placed in a `Kconfig` file in the
folder that corresponds to the hierarchy. When the symbols are scattered into
multiple files, it is responsibility of file containing the most specific
symbols to `source` the less specific. Keep in mind that only the file located
in `/cpu/<CPU>/Kconfig` will be included by the root `/Kconfig` file.
#### Example
```Kconfig
# This is the most specific symbol (selected by the board)
# The CPU model selects the family it belongs to
config CPU_MODEL_SAMR21G18A
bool
select CPU_FAM_SAMD21
# In this case the family selects a common 'sam0' symbol (which provides some
# features), and the core it has (cortex-m0+)
config CPU_FAM_SAMD21
bool
select CPU_COMMON_SAM0
select CPU_CORE_CORTEX_M0PLUS
# The value of the common value depends on the selected model
config CPU_MODEL
default "samd21e18a" if CPU_MODEL_SAMD21E18A
default "samd21g18a" if CPU_MODEL_SAMD21G18A
default "samd21j18a" if CPU_MODEL_SAMD21J18A
default "samr21e18a" if CPU_MODEL_SAMR21E18A
default "samr21g18a" if CPU_MODEL_SAMR21G18A
config CPU_FAM
default "samd21" if CPU_FAM_SAMD21
```
### Boards
Boards must be modelled as hidden boolean symbols with the prefix `BOARD_` which
default to `y` and are placed in `/boards/<BOARD>/Kconfig`. This file will be
`source`d from the main `/Kconfig` file. The board symbol must select the
`CPU_MODEL_<model>` symbol that corresponds to the CPU model present on the
board. The board symbol must also select the symbols that correspond to the
features it provides.
In the same `Kconfig` file a default value must be assigned to the
common `BOARD` symbol. It must be guarded by the board's symbol, so it only
applies in that case.
There are cases when grouping common code for multiple boards helps to avoid
unnecessary repetition. In the case features are provided in a common board
folder (e.g. `/boards/common/arduino-atmega`) a symbol should be declared to
model this in Kconfig. Symbols for common boards must have the `BOARD_COMMON_`
prefix, and must select the common provided features.
#### Example
The samr21-xpro has a `samr21g18a` CPU and provides multiple features. Its
symbol is modelled as following:
```Kconfig
# /boards/samr21-xpro/Kconfig
config BOARD
default "samr21-xpro" if BOARD_SAMR21_XPRO
config BOARD_SAMR21_XPRO
bool
default y
select CPU_MODEL_SAMR21G18A
```
### Default configurations
Boards, common board directories, CPUs and common CPU directories may need to
override default configuration values. Visible configuration symbols are
configurable by the user and show on the menuconfig interface. `.config` files
are used to set their values. To allow multiple sources of `.config` files,
there are two Makefile variables developers should use: `KCONFIG_CPU_CONFIG` for
sources added by the CPU or common CPU directories, and `KCONFIG_BOARD_CONFIG`
for sources added by the board or common board directories. This ensures the
correct priority of the configurations.
The `Makefile.features` infrastructure is used to populate the
configuration sources. As the order in which `.config` files are merged matters,
configuration sources should be ordered from more generic to more specific.
Because board's `Makefile.features` is included before CPU's `Makefile.features`
it is important to utilize two different lists of configuration sources. For
instance, if `cpu/cortexm_common` adds its configuration, `cpu/stm32` should add
its configuration after it, and `boards/stm32f769i-disco` after it.
```Makefile
include $(RIOTCPU)/cortexm_common/Makefile.features
# Add stm32 configs after including cortexm_common so stm32 takes precedence
KCONFIG_CPU_CONFIG += $(RIOTCPU)/stm32/stm32.config
```
## Summary of reserved Kconfig prefixes
The following symbol prefixes have been assigned particular semantics and are
reserved for the cases described below:
<!-- Keep the table in alphabetical order -->
| Prefix | Description |
| :----- | :---------- |
| `BOARD_` | Models a board |
| `BOARD_COMMON_` | Used for common symbols used by multiple boards |
| `CPU_ARCH_` | Models a CPU architecture |
| `CPU_COMMON_` | Used for common symbols used by multiple CPUs |
| `CPU_CORE_` | Models a CPU core |
| `CPU_FAM_` | Models a family of CPUs |
| `CPU_MODEL_` | Models a particular model of CPU |
| `USEMODULE_` | Models a [RIOT module](creating-modules.html#creating-modules). Generated from `USEMODULE` variable |
| `USEPKG_` | Models an [external package](group__pkg.html). Generated from `USEPKG` variable |
---
# Appendixes {#kconfig-appendixes}
## Appendix A: Check if a module or package is used {#kconfig-appendix-a}
In order to show only the relevant configuration parameters to the user with
respect to a given application and board selection, Kconfig needs knowledge
about all modules and packages to be used for a compilation. The dependency
handling among modules is performed by the build system (via
`Makefile.dep` files). The interface defined to declared the used modules and
packages is the `$ (GENERATED_DIR)/Kconfig.dep` file.
There will be a symbol for every used module (i.e. every module in
`USEMODULE` make variable) and package. The names in the symbols will be
uppercase and separated by `_`. Based on these symbols configurability is
decided.
The following is an example of how to use these symbols in Kconfig files to
configure compile-time configurations with `USEMODULE` dependencies:
```Kconfig
menu "Configure Sock Utilities"
depends on USEMODULE_SOCK_UTIL
config SOCK_UTIL_SCHEME_MAXLEN
int "Maximum length of the scheme part for sock_urlsplit"
default 16
...
endmenu # Configure Sock Utilities
```
## Appendix B: Difference between 'Kconfig' and '.config' files {#kconfig-appendix-b}
Kconfig files describe a configuration database, which is a collection of
configuration options organized in a tree structure. Configuration options may
have dependencies (among other attributes), which are used to determine their
visibility.
Kconfig files are written in
[Kconfig language](https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt)
defined in the Linux kernel. Configuration options have attributes such as
types, prompts and default values.
#### Kconfig file
```Kconfig
menu "Buffer Sizes"
config GCOAP_PDU_BUF_SIZE
int "Request or response buffer size"
default 128
endmenu
```
On the other hand configuration files contain assignment of values to
configuration options and use Makefile syntax. They can also be used to save a
set of configuration values as backup.
#### '.config' file
```makefile
# enable Kconfig configuration for gcoap
CONFIG_KCONFIG_MODULE_GCOAP=y
# set the value
CONFIG_GCOAP_PDU_BUF_SIZE=12345
```
In other words: Kconfig files describe configuration options and '.config' files
assign their values.
## Appendix C: Pitfall when using different configuration interfaces {#kconfig-appendix-c}
In the current configuration flow the user can choose to configure RIOT using
the menuconfig graphical interface or writing '.config' files by hand.
As explained in the
['Configuration sources merging step'](#kconfig-steps-merge-configs)
of the configuration process, configuration from multiple sources are loaded to
create a single `out.config` file, and the order of merging matters: last
file has priority.
While editing values directly via '.config' files `out.config` will be
re-built. The user can also use menuconfig interface to modify the configuration
file (this is the recommended way, as it gives access to much more information
regarding dependencies and default values of the symbols). Menuconfig will
change `out.config` directly (a backup file `out.config.old` will be kept).
**It is recommended to save backups of the configurations, as any change on the
configuration sources would re-trigger the merging process and overwrite
`out.config`.**
## Appendix D: A few key aspects while exposing a macro to Kconfig {#kconfig-appendix-d}
A macro that holds a 0 or 1 is modelled in Kconfig as a `bool` symbol. References to this macro
can then make use of IS_ACTIVE macro from kernel_defines.h with C conditionals
for conditional compilation.
[FXOS8700 driver exposure to Kconfig](https://github.com/RIOT-OS/RIOT/pull/13914)
can be considered as an example. If the macro is defined as `TRUE` by default,
a new symbol gets introduced to invert the semantics. The recommended
practice is to add a new symbol and expose it to Kconfig while the old one is
tagged to be deprecated. The process is documented in this
[commit](https://github.com/RIOT-OS/RIOT/pull/13129/commits/c7b6dc587cf20f3177abe0417a408b6ab90d0ff8)
There may be cases where a macro is expected to hold only specific values, e.g.
'GNRC_IPV6_MSG_QUEUE_SIZE' expressed as the power of two. These may be modelled
in such a way that a new macro is introduced to hold the restricted figures
while operators are added to arrive at the desired value. The process is
documented in this [pull request.](https://github.com/RIOT-OS/RIOT/pull/14086)
# Useful references {#kconfig-useful-references}
- [Kconfig language specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html)
- [Kconfig macro language specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-macro-language.html)
- [Kconfig - Tips and Best Practices](https://docs.zephyrproject.org/latest/guides/kconfig/tips.html)
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/build-system/kconfig/).
This page will be removed after release 2026.04.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 14 KiB

View File

@ -1,466 +1,5 @@
Porting boards {#porting-boards}
Porting boards (Deprecated) {#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.
# Porting flowchart {#porting-flowchart}
@dotfile porting-boards.dot
# 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.md
|----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. (Analogously, a `adc_params.h` can
contain a @ref saul_adc_params_t, and `pwm_params.h` a @ref
saul_pwm_rgb_params_t and a @ref saul_pwm_dimmer_params_t).
- 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 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).
```c
void board_init(void)
{
/* 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.
#### Default configurations
As explained in @ref default-configurations "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 @ref drivers_sx127x
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 @ref drivers_saul interface. This is
usually done as following:
```mk
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
USEMODULE += apds9960
USEMODULE += bmp280_i2c
USEMODULE += lis3mdl
USEMODULE += sht3x
endif
```
### 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. 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):
```
PORT_LINUX ?= /dev/ttyACM0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbmodem*)))
```
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 `Makefile.include`:
```mk
# Define the default port depending on the host OS
PORT_LINUX ?= /dev/ttyUSB0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial*)))
# this board uses openocd
PROGRAMMER ?= openocd
```
## Timer Configurations {#board-timer-configurations}
When using the high level timer `ztimer` there is an overhead in calling
the @ref ztimer_sleep and @ref ztimer_set functions. This offset can be
compensated for. It can be measured by running `tests/sys/ztimer_overhead`
on your board, i.e:
```shell
$ BOARD=my-new-board make -C tests/sys/ztimer_overhead flash term
main(): This is RIOT!
ZTIMER_USEC auto_adjust params:
ZTIMER_USEC->adjust_set = xx
ZTIMER_USEC->adjust_sleep = xx
ZTIMER_USEC auto_adjust params cleared
zitmer_overhead_set...
min=6 max=7 avg_diff=6
zitmer_overhead_sleep...
min=21 max=21 avg_diff=21
ZTIMER_USEC adjust params for my-new-board:
CONFIG_ZTIMER_USEC_ADJUST_SET 6
CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21
```
The last two lines can be added as defines to the new board `board.h`:
```c
/**
* @name ztimer configuration values
* @{
*/
#define CONFIG_ZTIMER_USEC_ADJUST_SET 6
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21
/** @} */
```
Alternatively, the pseudomodule @ref pseudomodule_ztimer_auto_adjust can be used
in an application to enable automatic timer offset compensation at board startup.
This however incurs overhead both in the text segment and at bootup time.
## doc.md {#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.
```md
@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
...
```
Previously documentation was contained in `doc.txt` files with C-style comment
blocks. This style has been deprecated in favor of using `doc.md` files in
Markdown format, which eliminates formatting and interpretation issues.
Old style files will continually be replaced by the new format.
Up to version `0.9.2` the [riotgen](https://pypi.org/project/riotgen/) tool
will generate `doc.txt` files instead of `doc.md` files. You can upgrade it to
the latest version with
```sh
pip install --upgrade riotgen
```
# 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, for example in the `cfg_timer_tim5.h`:
```c
/**
* @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)
/** @} */
```
## New Style Common Code {#new-style-common-code}
The common board definitions of RIOT are currently being reworked to make the
usage of common code easier and less error prone. For example, if you want
to use the common code for the Adafruit nRF52 Bootloader that is used
by many of the nRF52 based boards from Adafruit, you simply have to add the
following line to the `Makefile.dep` of your board. Everything else
will be automatically included by the build system.
```mk
USEMODULE += boards_common_adafruit-nrf52-bootloader
```
Not all common code is migrated to the new style yet, so if you are unsure
whether it is or not, you can check if the `boards/Makefile` already
includes a reference to the common code you want to use. If you are still
unsure, you can still use the @ref old-style-common-code or ask the
community.
## Old Style Common Code {#old-style-common-code}
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
```
If the common code includes source files, it might be necessary
to explicitly include the directory in your `Makefile` so the Make system
finds all the necessary files:
```mk
MODULE = board
DIRS += $(RIOTBOARD)/common/myCommonFolder
include $(RIOTBASE)/Makefile.base
```
If possible, you should use the @ref new-style-common-code though.
# 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.md
|----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/build_system/external_board_native`](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/external_board_native).
# Board names and aliases {#boards-alias}
New boards should be named according to
[RDM0003](https://github.com/RIOT-OS/RIOT/blob/master/doc/memos/rdm0003.md).
Historically, some board names have not followed this structure.
For backwards compatibility, RIOT supports board aliases that can be used
in place of the actual board name in the environment or Make variable `BOARD`.
A list of all existing board aliases can be found in
[`makefiles/board_alias.inc.mk](https://github.com/RIOT-OS/RIOT/blob/master/makefiles/board_alias.inc.mk).
[`BOARD=native`](@ref boards_common_native) is a special alias in that it
resolves to either [`native32`](@ref boards_native32) or [`native64`](@ref boards_native64)
depending on the host architecture.
# 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.
# Further reference {#further-reference}
- [In her blog][martines-blog], Martine Lenders documented her approach of
porting the @ref boards_adafruit-feather-nrf52840-express in February 2020.
- [Over at HackMD][hackmd-slstk3400a], Akshai M documented his approach of
porting the @ref boards_slstk3400a in July 2020.
[martines-blog]: https://blog.martine-lenders.eu/riot-board-en.html
[hackmd-slstk3400a]: https://hackmd.io/njFHwQ33SNS3sQKAkLkNtQ
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/advanced_tutorials/porting_boards/).
This page will be removed after release 2026.04.

View File

@ -1,4 +1,4 @@
Release cycle {#release-cycle}
Release cycle (Deprecated) {#release-cycle}
=============
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/misc/release_cycle/).

View File

@ -1,136 +1,4 @@
# Roadmap {#roadmap}
# Roadmap (Deprecated) {#roadmap}
The aim of the roadmap is to identify priority areas of RIOT development & enhancements.
For each area, some near-future plans and concrete next steps are indicated.
The text and items below are tentative, up for discussion, to be updated by regular pull requests.
# Network Stack High layers
(contact/steering: [Martine](https://github.com/miri64))
- ICN stack support clean-up
- discuss mid- and long-term plans for network stack maintenance & development (GNRC vs other supported stacks)
- revisit network time synchronization
- Provide a border router into 6LoWPANs (a 6LBR) that works out of the box in common scenarios:
- [x] in IPv6 networks with working Prefix Delegation (PD)
- [ ] in IPv6 networks without working Prefix Delegation (eg. by means of ND Proxying) <!-- 6man-variable-slaac also sounds nice but is at best a step between PD and just-a-single-v6-address -->
- [ ] in legacy networks (eg. by means of tunneling)
- [ ] with configurable on-by-default fallbacks
# Network Stack Low layers
(contact/steering: [Peter](https://github.com/PeterKietzmann))
- Point-to-Point Protocol (PPP): finalize and merge `gnrc_ppp`
# Integrations
(contact/steering: [Teufelchen](https://github.com/teufelchen1))
- [Home-Assistant](https://www.home-assistant.io/) BTHome integration
- [Home-Assistant](https://www.home-assistant.io/) integration via [MQTT Discovery](https://www.home-assistant.io/integrations/mqtt#mqtt-discovery)
# Power Modes
(contact/steering: [benpicco](https://github.com/benpicco))
- concept to fix shell usage issue while LPM activated
- integrate generic power management functions in device driver APIs (netdev, SAUL, ...)
- more advanced LPM concepts:
- sleeping for short periods (in cases where it is not feasible to switch to the idle thread and back) -> mitigate active waiting
# Peripheral drivers
(contact/steering: [maribu](https://github.com/maribu))
## Timers
(contact/steering: [kaspar030](https://github.com/kaspar030), [benpicco](https://github.com/benpicco), [maribu](https://github.com/maribu))
- cleanup and unification of low-level timer interfaces (`timer`, `rtt`, `rtc`)
- implement capture mode
## SPI
- introduction of `spi_slave` interface
- transition to `spi_clk_t` being the frequency in Hz, not an `enum` constant, to allow arbitrary frequencies
- most implementations have been ported
- allow a way to detect the actual frequency an SPI bus is running at
- see https://github.com/RIOT-OS/RIOT/pull/16727 for one proposal
## I2C
- introduction of `i2c_slave` interface
- see https://github.com/RIOT-OS/RIOT/issues/19560 for a discussion
## GPIO
(contact/steering: [gschorcht](https://github.com/gschorcht), [maribu](https://github.com/maribu))
- add a port-based, feature-rich, thread-safe GPIO API
- [GPIO LL](https://doc.riot-os.org/group__drivers__periph__gpio__ll.html) seems to fit the bill so for
- many MCUs still need an implementation
- add a high level API that unifies external and internal GPIOs on top
## ADC
(contact/steering: [benpicco](https://github.com/benpicco), [kfessel](https://github.com/kfessel), [gschorcht](https://github.com/gschorcht), [maribu](https://github.com/maribu))
- extend / replace the ADC API to allow advanced use cases
- selecting reference voltages (think: multimeter app)
- differential inputs
- fast (ideally DMA supported) sampling (think: a digital oscilloscope app)
- unify external and internal ADCs
- see https://github.com/RIOT-OS/RIOT/pull/13247 for one proposal
# Software Updates
(contact/steering: [Emmanuel](https://github.com/emmanuelsearch))
- Modularize to provide toolbox supporting other image storing (e.g. support external flash), transport (other than CoAP), crypto (e.g. secure element).
- riotboot support for architectures other than Cortex-M
# Documentation
(contact/steering: [Emmanuel](https://github.com/emmanuelsearch))
- Write and publish more RDMs
# Low-level Hardware Support
(contact/steering: [Alex](https://github.com/aabadie))
- radio support for TI SensorTag
- radio support for Silab Thunderboard
# Testing
(contact/steering: [Kaspar](https://github.com/kaspar030))
- automated network functionality tests (e.g. RPL + UDP/PING tests through border router, multi-hop) in IoTLAB dev sites?
# Security
(contact/steering: [Kaspar](https://github.com/kaspar030))
- RNG unified (secure, or basic), seeding
- RIOT default configuration = secure configuration (that's our goal/motto)
## 802.15.4 link layer security
(contact/steering: [chrysn](https://github.com/chrysn))
Current status: RIOT supports application provided keys,
with no guidance on how to (and no practical ways to) use that securely
(see [CVE-2021-41061](https://nvd.nist.gov/vuln/detail/CVE-2021-41061)).
Goal: Usably secure defaults.
- Figure out applicability of [RFC9031](https://www.rfc-editor.org/rfc/rfc9031) ("CoJP") to non-6TiSCH scenarios.
- Implement RFC9031 with any extensions needed for the MACs RIOT has.
- Provide tools to set up a recommended JRC, and to provision keys between it and the device at flash time.
This may entail extensions to the build process, as CoJP requires per-device secrets.
@deprecated Roadmap has moved to the [Guide Site](https://guide.riot-os.org/misc/roadmap/).
This page will be removed after release 2026.04.

View File

@ -1,55 +1,5 @@
Terminal programs configuration {#terminal-programs}
Terminal programs configuration (Deprecated) {#terminal-programs}
===========================================================
[TOC]
Background {#background}
==========
This page explains how to configure some popular terminal programs for correct
display of newlines when using the serial interface of a RIOT powered device.
When printing something using *stdio* (e.g., `printf("Hello World!\n");`, RIOT
sends a line feed character (`0xA`) as `\n` (newline).
Some terminals need more, for example, a carriage return and a line feed
character (0xD, 0xA). See https://en.wikipedia.org/wiki/Newline for background.
This page tries to collect needed settings for common terminal programs that
will make them correctly display newlines.
gtkterm {#gtkterm}
======
- Graphical method:
- Open the configuration menu.
- Click on ***CR LF auto***.
- Manual method:
- Edit the file `~/.gtktermrc`.
- Change value of ***crlfauto*** option to `True`.
minicom {#minicom}
=======
- Interactive method:
- Press ***Ctrl+A u***.
- Manual method:
- Edit the configuration file (`~/.minirc.dfl` per default).
- Add the following line:
pu addcarreturn Yes
miniterm {#miniterm}
========
- Generic method:
- Start with `--eol CR`parameter.
- Via RIOT build system:
- `RIOT_TERMINAL=miniterm make term`
picocom {#picocom}
=======
- Generic method:
- Start with `--imap lfcrlf` parameter.
- Via RIOT build system:
- `RIOT_TERMINAL=picocom make term`
putty {#putty}
=====
- Graphical method:
- Go to configuration tree and choose `Terminal` branch.
- Enable option `Implicit CR in every LF`.
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/misc/terminal_config/).
This page will be removed after release 2026.04.

View File

@ -1,4 +1,4 @@
Using C++ in RIOT {#using-cpp}
Using C++ in RIOT (Deprecated) {#using-cpp}
==================
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/c_tutorials/using_cpp/).

View File

@ -1,4 +1,4 @@
Using Rust in RIOT {#using-rust}
Using Rust in RIOT (Deprecated) {#using-rust}
==================
@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/).

View File

@ -1,3 +1,3 @@
# RIOT Vision {#vision}
# RIOT Vision (Deprecated) {#vision}
@deprecated See [Vision](https://guide.riot-os.org/general/vision/) on the RIOT Guide Site for the latest information. This page will be removed after release 2025.11.

View File

@ -0,0 +1,293 @@
---
title: Creating an application
description: How to create your own application for RIOT-OS
---
To create your own application you need to create a directory containing one or
multiple C file(s) with your source code and a Makefile. A template Makefile is
available in the `dist` folder of the
[RIOT repository](https://github.com/RIOT-OS/RIOT).
## The main() Function
After the board is initialized, RIOT starts two threads: the idle thread and
the main thread. The idle thread has the lowest priority and will run whenever
no other thread is ready to run. It will automatically use the lowest possible
power mode for the device. The main thread - configured with a default priority
that is right in the middle between the lowest and the highest available
priorities - is the first thread that runs and calls the `main()` function.
This function needs to be defined in the source code of the application
(typically located in `main.c`).
```c
#include <stdio.h>
int main(void)
{
puts("Hello World!");
return 0;
}
```
## The Application's Makefile
### The Minimal Makefile
At minimum the Makefile of an application (see
[Creating a Project](/c_tutorials/create_project/)) needs to
define the following macros:
* `APPLICATION`: should contain the name of your application
* `RIOTBASE`: specifies the path to your copy of the RIOT repository (note
that you may want to use `$(CURDIR)` here, to give a relative path)
The `BOARD` macro is also required and recommended to be set to `native` by
default, but is recommended to be overridable with the `?=` operator.
Additionally, it is required to include the `Makefile.include` from the
`RIOTBASE`.
```makefile
# Set the name of your application:
APPLICATION = foobar
# If no BOARD is found in the environment, use this default:
BOARD ?= native
# This has to be the absolute path to the RIOT base directory:
RIOTBASE ?= $(CURDIR)/../../RIOT
include $(RIOTBASE)/Makefile.include
```
### How to handle unsupported boards?
Sometimes it is necessary to exclude boards because they don't provide a
required functionality or don't have sufficient memory. RIOT's build system
looks for the macros `BOARD_BLACKLIST`, `BOARD_WHITELIST`, and
`BOARD_INSUFFICIENT_MEMORY`. Any board name that is not included in
`BOARD_WHITELIST` will issue a message that one has to expect errors if they
build the application for the board referred by that name. The list can also be
used by a CI system to not build the application for this board at all. A board
that is included in `BOARD_BLACKLIST` will show the same behavior. The build
system evaluates `BOARD_WHITELIST` first and then `BOARD_BLACKLIST`. The
`BOARD_INSUFFICIENT_MEMORY` macro is similar to `BOARD_BLACKLIST` but will
build in any case. A CI system can use the information provided by the
`BOARD_INSUFFICIENT_MEMORY` macro to skip the linking step in the build
process, since some linkers will issue an error if the code won't fit the
target board's flash memory or RAM.
### Including Modules
By default a RIOT application comprises only of the applications' code itself,
the kernel, and platform specific code. In order to use additional modules,
such as a particular [device driver](https://doc.riot-os.org/group__drivers.html)
or [a system library](https://doc.riot-os.org/group__sys.html)
(including [networking capabilities](https://doc.riot-os.org/group__net.html)),
you have to append the modules' names to the USEMODULE variable.
For example, to build an application using the
SHT11 temperature sensor and UDP/IPv6 functionalities of the GNRC network stack,
your Makefile needs to contain these lines:
```makefile
USEMODULE += sht11
USEMODULE += gnrc_ipv6_default
USEMODULE += gnrc_udp
```
Modules typically pull in all required dependencies themselves.
## Including Source Files in Subfolders
By default, all source files in an application's (or any RIOT module's) directory
are automatically compiled as part of the application. In order to organize source
code in a directory structure, two different approaches can be used:
1. Make each subdirectory a separate RIOT module with a unique name inside its
Makefile, either by adding the directory's path to `DIRS` or with the [out-of-tree
module support](#external-modules).
2. Add the source files within subdirectories to `SRC`, either explicitly or with
Makefile wildcards.
Both approaches are illustrated and explained in `examples/basic/subfolders`.
## Setting Board-specific Dependencies
Required dependencies of applications may change depending on the
target board or architecture. This is especially
relevant for networking applications where multiple hardware implementations
exist and the appropriate implementation has to be chosen for the given board
or architecture.
To achieve this task elegantly, a `Makefile.board.dep` file can be
created in the application folder, which is automatically included and
evaluated by RIOT build system during the dependency resolution phase.
This ensures that all the relevant variables such as `FEATURES_USED` or the
`USEMODULE` list are fully populated.
```makefile
ifneq (,$(filter arch_esp,$(FEATURES_USED)))
USEMODULE += esp_wifi
endif
ifneq (,$(filter native native32 native64,$(BOARD)))
USEMODULE += netdev_default
endif
```
# Helper Tools
To help you start writing an application within RIOT, the build system provides
the `generate-example` and `generate-test` make targets. These targets are wrappers
around the [riotgen](https://pypi.org/project/riotgen/) command line tool and
are helpful when starting to implement an application: all required files are
generated with copyright headers, doxygen groups, etc, so you can concentrate
on the module implementation.
For applications, the `Makefile` is generated with the dependencies (modules,
packages, required features) included.
## Usage:
To generate an example application, e.g in the `examples` directory, from the
RIOT base directory, run:
```sh
make generate-example
```
To generate a test application, e.g in the `tests` directory, from the
RIOT base directory, run:
```sh
make generate-test
```
Then answer a few questions about the application:
- Application name: enter a name for your application. It will be used as both
the name of the application directory under `examples` or `tests` and by
the build system module (set in the `APPLICATION` variable).
- Application brief description: Describe in one line what is this application
about.
- Target board: select the default target board. The value is set to `native`
by default.
- Modules: give the list of dependency modules, separated by commas. For
example: `ztimer,fmt`
- Packages: give the list of dependency packages, separated by commas.
- Features required: give the list of CPU features (`periph_*`, etc) required
by the application, all separated by commas.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
Once completed, the application files are either located in
`examples/<application name>` or `tests/<application name>` depending on the
target used.
**Testrunner:** when using the `make generate-test`, you can also automatically
add a testrunner Python script. Just answer 'y' when prompted.
# Creating an Out of Tree Application Structure
Applications written for RIOT do not have to reside in the RIOT tree. Out of
tree applications, modules and boards are supported.
For a full application with custom board and modules, the following directory
tree can be used:
```
├── apps
│ └── my_app
│ └── Makefile
├── boards
│ └── my_board
├── modules
│ └── my_module
│ ├── include
│ │ └── my_module.h
│ ├── Makefile
│ ├── Makefile.include
│ └── my_module.c
└── RIOT
```
In this example tree, the `apps` directory contains a collection of applications
for the project. The modules directory could contain extra modules for the
applications.
The Makefile inside the application needs at least the following as bare minimum:
```makefile
APPLICATION = my_app
PROJECT_BASE ?= $(CURDIR)/../..
RIOTBASE ?= $(PROJECT_BASE)/RIOT
# Optionally, provide paths to where external boards and/or modules
# reside, so that they can be included in the app
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
include $(RIOTBASE)/Makefile.include
```
The `RIOTBASE` variable tells the build system where to find the RIOT source
tree and to need to point to the RIOT source tree used for the application for
the application to work.
The RIOT directory contains the sources of RIOT here. This can be either a
direct checkout of the sources or a git submodule, whichever has your
preference.
If your project has separate modules or separate boards, these can be contained
inside a modules os boards directory. The RIOT build system has both
`EXTERNAL_MODULE_DIRS` and `EXTERNAL_BOARD_DIRS` variables to specify
directories that contain extra modules and extra boards.
## External Boards
External boards can be ported in an identical way as porting a regular board to
RIOT, see [Porting Boards](/advanced_tutorials/porting_boards/).
One approach can be to copy over an existing board and modify it to suit the
needs. Boards in the RIOT tree can be included and used as dependency in the
custom boards. In case you connect additional hardware to an upstream board
(such as e.g. an Arduino shield) or you require a different hardware
configuration (e.g. configuring some of the pins configured as ADC as
additional PWM outputs instead) a copy of the upstream board that is then
customized to the application needs is the best course of action.
## External Modules
Similar to the external boards, external modules can be written in a similar way
as regular in-tree modules.
One modification is the include directory inside the module directory. For this
include directory to be added to the include path during compilation, the
following snippet is required in the modules `Makefile.include`:
```makefile
USEMODULE_INCLUDES_my_module := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_my_module)
```
Note that the make variable (here `USEMODULE_INCLUDES_my_module`) must be unique
for every module to make this work. Including the module name here is usually
sufficient.
## Extra Makefile Scaffolding
A bit of extra, but optional, Makefile scaffolding can help to keep the project
easy to maintain. An extra `Makefile.include` in the root directory of the
project that sets the necessary variables can help to deduplicate settings.
This includes the `RIOTBASE` variable and the include to the RIOT
`Makefile.include`:
```makefile
EXTERNAL_MODULE_DIRS += $(PROJECT_BASE)/modules
EXTERNAL_BOARD_DIRS += $(PROJECT_BASE)/boards
RIOTBASE ?= $(PROJECT_BASE)/RIOT
include $(RIOTBASE)/Makefile.include
```
Applications then just have to set the `PROJECT_BASE` variable and include this
makefile and don't have to each add the external board and module directories.
The application makefile would then look like this:
```makefile
APPLICATION = my_app
PROJECT_BASE ?= $(CURDIR)/../..
include $(PROJECT_BASE)/Makefile.include
```

View File

@ -0,0 +1,201 @@
---
title: Creating modules
description: Guide on how to create modules in RIOT-OS
---
Modules in RIOT are well-defined units of code that provide a set of features
to your application. This includes also drivers and to a certain extent ports
for CPUs and boards (with some exceptions, see the
[porting guide](/advanced_tutorials/porting_boards/) for further information).
## The General Structure
Like [applications](/advanced_tutorials/creating_application/), modules are directories
containing source files and a Makefile. Additionally their API can be defined
in one or more header files, residing in the include path of their
super-module.
E.g. the [Shell](https://doc.riot-os.org/group__sys__shell.html) module
is implemented in `sys/shell` and defines its
API in `sys/include/shell.h` and the
[ISL29020 light sensor](https://doc.riot-os.org/group__drivers__isl29020.html)
driver is implemented in `drivers/isl29020`
and defines its API in `drivers/include/isl29020.h`.
A module's Makefile just needs to include `Makefile.base` in the RIOT
repository:
```makefile
include $(RIOTBASE)/Makefile.base
```
If your module's name differs from the name of the directory it resides in you
need to set the `MODULE` macro in addition.
When compiled a module always provides a `MODULE_<MODULENAME>` macro to the
system. This way, other modules can check if the module is available in the
current configuration or not.
Modules can be used by adding their name to the `USEMODULE` macro of your
application's Makefile.
### Pitfalls
The `MODULE` name should be unique or build breaks as modules overwrite the
same output file. This might for example lead to `undefined reference to` errors
in the linker which can be hard to track down.
This problem happened in the past for:
* Packages root directory (libfixmath/u8g2)
* boards/cpu/periph and their common boards/cpu/periph
Note: even if all boards and cpus implement the `board` and `cpu` modules, only
one is used in an application so there is no conflict.
## Module Dependencies
Your module may depend on other modules to minimize code duplication. These
dependencies are defined in `Makefile.dep` with the following syntax:
```makefile
ifneq (,$(filter your_module,$(USEMODULE))) # if module in USEMODULE
USEMODULE += dep1 # add dependencies to USEMODULE
USEMODULE += dep2
endif
```
Note, that `Makefile.dep` is processed only once so you have to take care to
add the dependency block for your module *before* your dependencies pull in
their dependencies.
## Modules Outside of RIOTBASE
Modules can be defined outside of `RIOTBASE`. In addition to adding it to `USEMODULE`
the user needs to add the directory (or directories) containing external modules
to `EXTERNAL_MODULE_DIRS`.
External modules can optionally define the following files:
* `Makefile.include` file to set global build configuration like `CFLAGS` or add
API headers include paths to the `USEMODULE_INCLUDES` variable.
* `Makefile.dep` file to set module dependencies
:::note
The name of an external module must be unique (both in regard to other
external modules, as well to native RIOT modules). Additionally, the
directory containing the module must match the module name, e.g.
module `foo` must be located in `<PATH_IN_EXTERNAL_MODULE_DIRS>/foo`.
:::
An example can be found in
[`tests/build_system/external_module_dirs`](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/external_module_dirs)
## Pseudomodules
Pseudomodules are modules that are not static libraries, i.e. do not generate a
`<module name>.a` file.
To create a pseudomodule just add its name to `makefiles/pseudomodules.inc.mk`
with `PSEUDOMODULES += <modulename>` in alphabetical order.
A Pseudomodule may or may not have a source file associated with it. To make the
distinction between them we will refer to those that don't as true-Pseudomodules.
The main use case for true-Pseudomodules is to provide base information for
dependencies to other modules or information to the code base via the
`MODULE_<MODULENAME>` macro.
Pseudomodules with source code exist under a "real" `MODULE` since they will
generate a `<pseudomodule_name>.o` file grouped under that `MODULE`s
`<module_name>.a` file.
These modules appear in RIOT under two forms:
1. Conditionally included source files:
```
foo/
|----foo_bar.c
|----foo.c
|----Makefile
```
In `foo/Makefile` you add the source file to the `SRC` variable, conditioned on
the Pseudomodule inclusion
```makefile
ifneq (,$(filter foo_bar,$(USEMODULE)))
SRC += foo_bar.c
endif
```
See `sys/net/ble/skald` for an example in code.
2. Using the `SUBMODULES` mechanism:
```
foo/
|----spam.c
|----ham.c
|----eggs.c
|----Makefile
```
```makefile
# make all code end up in "foo_bar.a", this can be any name
MODULE := foo_bar
# ensure that "foo_ham" or "bar_foo_ham" builds "foo_ham.c".
BASE_MODULE := foo
# list of source files that are not SUBMODULES
SRC := spam.c
# enable submodules by setting SUBMODULES = 1
SUBMODULES = 1
```
When using `SUBMODULES` in a `MODULE` all `SRC` file excluded from `foo/Makefile`
will be considered `SUBMODULES`. In the example above `ham.c` and `eggs.c`.
These source files will be conditionally included depending if the modules have
been added, i.e. `USEMODULE += foo_ham foo_eggs` (it's the same as case 1 but
handled automatically in `Makefile.base`).
The `SUBMODULES` mechanism is more flexible since `BASE_MODULE` allows matching
the only parts of compounded module names and only match against part of that name.
See `sys/ztimer/Makefile` for an example in code.
`SUBMODULES` can also be true-pseudomodules, or become one by conditionally excluding
the source files by adding them to `SUBMODULES_NO_SRC`.
# Helper Tools
To help you start writing a module, the RIOT build system provides the
`generate-module` make target. It is a wrapper around the
[riotgen](https://pypi.org/project/riotgen/) command line tool that is helpful
when starting to implement a module: all required files are generated with
copyright headers, doxygen groups, etc, so you can concentrate on the module
implementation.
The module source files are created in the `sys` directory.
## Usage
From the RIOT base directory, run:
```sh
make generate-module
```
Then answer a few questions about the driver:
- Module name: enter a name for your module. It will be used as both the name
of the module directory under sys, where the source files are created, and
the build system module (used with `USEMODULE`).
- Module doxygen name: Enter the name of module, as displayed in the
Doxygen documentation.
- Brief doxygen description: Describe in one line what is this module about.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
Once completed, the module files are located in
`sys/<module name>/<module name>.c` and `sys/include/<module name>.h`.

View File

@ -0,0 +1,501 @@
---
title: Writing a Device Driver in RIOT
description: Guidelines and best practices for writing device drivers in RIOT-OS
---
This document describes the requirement, design objectives, and some
non-function details when writing device drivers in/for RIOT. The term device
driver in this context includes all 'CPU-external' devices connected to the CPU
typically via peripherals like SPI, I2C, UART, GPIO, and similar. CPU
peripherals itself are in RIOT not considered to be device drivers, but
peripheral or low-level drivers. Typical devices are network devices like
radios, Ethernet adapters, sensors, and actuators.
# General Design Objectives
Device drivers should be as easy to use as possible. This implies an
'initialize->ready' paradigm, meaning, that device drivers should be ready to use
and in operation right after they have been initialized. On top, devices should
work with physical values wherever possible. So e.g. sensors should return
already converted values in some physical unit instead of RAW data, so that
users can work directly with data from different devices directly without having
to care about device specific conversion.
However, please avoid the use of `float` or `double`. Instead, multiply to the
next SI (or appropriate) unit. E.g. if an ADC would return values like `1.23 V`,
choose to return `1230 mV` instead.
Additionally, towards ease of use, all device drivers in RIOT should provide a
similar 'look and feel'. They should behave similarly in terms of their state
after initialization, like their used data representation and so on.
Secondly, all device drivers should be optimized for minimal RAM/ROM usage, as
RIOT targets (very) constrained devices. This implies that instead of exposing
all thinkable functionality, the drivers should focus on exporting and
implementing a device's core functionality, thus covering ~95% of the use cases.
Third, it should always be possible to handle more than a single device of the
same kind. Drivers and their interfaces are thus designed to keep their state
information in a parameterized location instead of driver defined global
variables.
Fourth, RIOT defines high-level interfaces for certain groups of devices (i.e.
netdev for network devices, SAUL for sensors and actuators), which enable users
to work with a wide variety of devices without having to know much about the
actual device that is mapped.
Fifth, during initialization, we make sure that we can communicate with a device.
Other functions should check the dev pointer is not void, and should also handle
error return values from the lower layer peripheral driver implementations,
where there are some.
Sixth, device drivers SHOULD be implemented independent of any CPU/board code.
To achieve this, the driver implementations should strictly be based on
platform independent interfaces as the peripheral drivers, xtimer, etc.
# General
## Documentation
Document what your driver does! Most devices come with a very large number of
features, while the corresponding device driver only supports a subset of them.
This should be clearly stated in the device driver's documentation so that
anyone wanting to use the driver can find out the supported features without
having to scan through the code.
## Device descriptor and parameter configuration
Each device MUST supply a data structure, holding the devices state and
configuration, using the naming scheme of `DEVNAME_t` (e.g. `dht_t`, or
`at86rf2xx_t`). In the context of RIOT, we call this data structure the device
descriptor.
This device descriptor MUST contain all the state data of a device. By this, we
are not limited to the number of instances of the driver we can run
concurrently. The descriptor is hereby used for identifying the device we want
to interact with, and SHOULD always be the first parameter for all device driver
related functions.
Typical things found in these descriptors are e.g. used peripherals (e.g. SPI or
I2C bus used, interfacing GPIO pins), data buffers (e.g. RX/TX buffers where
needed), or state machine information.
On top of the device descriptor, each device driver MUST also define a data
structure holding the needed configuration data. The naming scheme for this type
is `DEVNAME_params_t`. In contrary to the device descriptor, this data structure
should only contain static information, that is needed for the device
initialization as it is preferably allocated in ROM.
A simple I2C temperature sensors' device descriptor could look like this:
```c
typedef struct {
tmpabc_params_t p; /**< device configuration parameter like I2C bus and bus addr */
int scale; /**< some custom scaling factor for converting the results */
} tmpabc_t;
/* with params being */
typedef struct {
i2c_t bus; /**< I2C bus the device is connected to */
uint8_t addr; /**< the device's address on the bus */
} tmpabc_params_t;
```
**NOTE:** In many cases it makes sense, to copy the `xxx_params` data into the
device descriptor during initialization. In some cases, it is, however, better
to just link the `params` data via pointer and only copy selected data. This way,
configuration data that is only used once can be read directly from ROM, while
often used fields (e.g. used peripherals) are stored directly in the device
descriptor and one saves hereby one de-referencing step when accessing them.
## Default device configuration
Each device driver in RIOT MUST supply a default configuration file, named
`DEVNAME_params.h`. This file should be located in the `RIOT/drivers/...`. The
idea is that this file can be overridden by an application or a board, by
simply putting a file with the same name in the application's or the board's
include folders, while RIOT's build system takes care of preferring those files
instead of the default params file.
A default parameter header file for the example temperature sensor above would
look like this (`tmpabc_params.h`):
```c
/* ... */
#include "board.h" /* THIS INCLUDE IS MANDATORY */
#include "tmpabc.h"
/* ... */
/**
* @brief Default configuration parameters for TMPABC sensors
* @{
*/
#ifndef TMPABC_PARAM_I2C
#define TMPABC_PARAM_I2C (I2C_DEV(0))
#endif
#ifndef TMPABC_PARAM_ADDR
#define TMPABC_PARAM_ADDR (0xab)
#endif
#ifndef TMPABC_PARAMS
#define TMPABC_PARAMS { .i2c = TMPABC_PARAM_I2C \
.addr = TMPABC_PARAM_ADDR }
#endif
/** @} */
/**
* @brief Allocation of TMPABC configuration
*/
static const tmpabc_params_t tmpabc_params[] = {
TMPABC_PARAMS
}
/* ... */
```
Now to influence the default configuration parameters, we have these options:
First, we can override one or more of the parameter from the makesystem, e.g.
```sh
CFLAGS="-DTMPABC_PARAM_ADDR=0x23" make all
```
Second, we can override selected parameters from the board configuration
(`board.h`):
```c
/* ... */
/**
* @brief TMPABC sensor configuration
* @{
*/
#define TMPABC_PARAM_I2C (I2C_DEV(1))
#define TMPABC_PARAM_ADDR (0x17)
/** @} */
/* ... */
```
Third, we can define more than a single device in the board configuration
(`board.h`):
```c
/* ... */
/**
* @brief Configure the on-board temperature sensors
* @{
*/
#define TMPABC_PARAMS { \
.i2c = I2C_DEV(1), \
.addr = 0x31 \
}, \
{ \
.i2c = I2C_DEV(1), \
.addr = 0x21 \
}
/** @} */
/* ... */
```
And finally, we can simply override the `tmpabc_params.h` file as described
above.
## Compile-time configuration documentation
The macros that configure the driver during compilation is added to the listing
for [Compile time configurations](https://doc.riot-os.org/group__config.html). Refer to the following example
that exposes
[TMP00x sensor](https://github.com/RIOT-OS/RIOT/blob/2025.07-branch/drivers/include/tmp00x.h#L96-L157)
to [sensors group](https://doc.riot-os.org/group__config__drivers__sensors.htmls).
```c
/**
* @defgroup drivers_tmp00x_config TMP006/TMP007 Infrared Thermopile
* Sensor driver compile configuration
* @ingroup config_drivers_sensors
* @{
*/
/**
* @brief Default Address
* ....
*/
#ifndef TMP00X_I2C_ADDRESS
#define TMP00X_I2C_ADDRESS (0x40)
#endif
....
/** @} */
```
Sub-groups defined for different types of drivers can be found in
[drivers/doc.txt](https://github.com/RIOT-OS/RIOT/blob/master/drivers/doc.txt)
## Initialization
In general, the initialization functions should do the following:
- initialize the device descriptor
- initialize non-shared peripherals they use, e.g. GPIO pins
- test for device connectivity, e.g. does an SPI/I2C slave react
- reset the device to a well-defined state, e.g. use external reset lines or do
a software rest
- do the actual device initialization
For testing a device's connectivity, it is recommended to read certain
configuration data with a defined value from the device. Some devices offer
`WHO_AM_I` or `DEVICE_ID` registers for this purpose. Writing and reading back
some data to the device is another valid option for testing its responsiveness.
For more detailed information on how the signature of the init functions should
look like, please refer below to the specific requirements for network devices
and sensors.
## Return Values
As stated above, we check communication of a device during initialization and
handle error return values from the lower layers, where they exist. To prevent
subsequent misuse by passing NULL pointers and similar to the subsequent
functions, the recommended way is to check the parameter using `assert`, e.g.:
```c
int16_t tmpabc_read(const tmpabc_t *dev)
{
assert(dev);
/* ... */
return value;
}
```
Whenever you implement status/error return values in your driver, magic numbers
MUST ***NOT*** be used. Instead, use negative `errno` codes (such as `-EIO` for
an input/output error) and *document* every single error code that can be
return for each function using the `reval` Doxygen command. E.g. like this:
```c
/**
* @brief Initialize the foo device and its descriptor
* @param[out] dev Device descriptor to initialized
* @param[in] params Device initialization parameters
*
* @retval 0 Success
* @retval -ENXIO No foo device connected to the I2C bus
* @retval -ENODEV Device using the foo I2C address is not a foo device
* etc.
*/
int foo_init(foo_t *dev, const foo_params_t *params);
```
You can multiplex this information whenever this is reasonable, as long as a
negative return value indicates an error without exceptions. E.g. like this:
```c
/**
* @brief Perform a relative humidity measurement
* @param[in] dev Humidity sensor to perform the measurement on
*
* @return The relative humidity in percent
* @retval -EIO Communication with the sensor failed
*/
int foo_humidity(const foo_t *dev);
```
### Documenting Return Values
With the exception of functions returning `void`, all return values have to be
documented. Use the `return` Doxygen command to describe what is returned. In
order to document special return value (such as error codes), use the `retval`
command. The `retval` command expects the specific value to document as first
argument (no spaces in the value allowed!), and a description (spaces allowed
here) as second. It is safe to use both `return` and `retval` commands, or just
one of them - whatever makes most sense for a given function.
## General Device Driver Checklist
- *MUST*: the supported feature set and any custom behavior is clearly
documented
- *MUST*: device descriptor is defined: `devab_t`
- *MUST*: device parameter `struct` is defined: `devab_params_t`
- *MUST*: a default parameter configuration file is present, e.g.
`RIOT/drivers/devab/include/devab_params.h`
- *MUST*: all error and status return codes are named, e.g.
`DEVAB_OK, DEVAB_NOSPI, DEVAB_OVERFLOW, ...`
- *MUST*: use `const devab_t *dev` when the device descriptor can be access
read-only
## Build system integration
### Internal include files
If the driver contains internal include files, a `Makefile.include` must be
added in the driver implementation directory, with the following content
(adapted to the name of the driver module):
```
USEMODULE_INCLUDES_<driver name> := $(LAST_MAKEFILEDIR)/include
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_<driver name>)
```
### External dependencies
If the driver has other module or CPU features dependencies (like `xtimer` or
`periph_i2c`), they must be added in the `$(RIOTBASE)/drivers/Makefile.dep`
file in a block like below (this is an example, you'll have to adapt to the
driver requirements):
```
ifneq (,$(filter <driver name>,$(USEMODULE)))
FEATURES_REQUIRED += periph_i2c
USEMODULE += xtimer
endif
```
**Warning:** Please be careful with alphabetical order when modifying this file.
## Helper tools
To help you start writing a device driver, the RIOT build system provides the
`generate-driver` make target. It is a wrapper around the
[riotgen](https://pypi.org/project/riotgen/) command line tool that is helpful
when starting to implement a driver: all minimum files are generated with
copyright headers, doxygen groups, etc, so you can concentrate on the driver
implementation.
**Usage:**
From the RIOT base directory, run:
```
make generate-driver
```
Then answer a few questions about the driver:
- Driver name: enter a name for your driver. It will be used as both the name
of the driver directory where the source files are created and the build
system module.
- Driver doxygen group name: Enter the name of the driver, as displayed in the
Doxygen documentation.
- Brief doxygen description: Describe in one line what is this driver about.
- Parent driver Doxygen group: Enter the Doxygen group the driver belongs to.
It can be `actuators`, `display`, `misc`, `netdev`, `sensors`, `storage`.
Other global information (author name, email, organization) should be retrieved
automatically from your git configuration.
# Sensors
## SAUL
All sensor drivers SHOULD implement the SAUL interface. It is however
recommended, that the drivers are written in a way, that the drivers do not
solely export the SAUL interface, but map the SAUL interface upon a driver
specific one.
For example, a temperature driver provides the following function (`tmpabc.c`):
```c
int16_t tmpabc_read(tmpabc_t *dev);
```
which then can easily be mapped to SAUL (`tmpabc_saul.c`):
```c
int saul_read(saul_t *dev, phydat_t *data)
{
memset(data, 0, sizeof(phydat_t));
data->x = tmpabc_read((tmpabc_t *)dev);
data->unit = UNIT_TEMP_C;
data->scale = -2;
return 1;
}
```
This ensures the versatility of the device driver, having in mind that one might
want to use the driver without SAUL or maybe in a context without RIOT.
## Initialization
Sensor device drivers are expected to implement a single initialization
function, `DEVNAME_init`, taking the device descriptor and the device's
parameter struct as argument:
```c
int tmpabc_init(tmpabc_t *dev, const tmpabc_params_t *params);
```
After this function is called, the device MUST be running and usable.
## Value handling
### Value semantics
All sensors in RIOT MUST return their reading results as real physical values.
When working with sensor data, these are the values of interest, and the
overhead of the conversion is normally neglectable.
### Typing
All values SHOULD be returned using integer types, with `int16_t` being the
preferred type where applicable.
In many situations, the physical values cannot be mapped directly to integer
values. For example, we do not want to map temperature values to integers
directly while using their fraction. The recommended way to solve this is by
scaling the result value using decimal fixed point arithmetic, in other words,
just return centi-degree instead of degree (e.g. 2372c°C instead of 23.72°C).
## Additional Sensor Driver Checklist
- *MUST*: mandatory device parameters are configurable through this file, e.g.
sampling rate, resolution, sensitivity
- *MUST*: an init function in the style of
`int devab_init(devab_t *dev, const devab_params_t *params);` exists
- *MUST*: after initialization, the device must be operational
- *MUST*: all error and return values are named, e.g.
`DEVAB_OK, DEVAB_NODEV, ...`
- *MUST*: all 'read' functions return values in their physical representation,
e.g. `centi-degree, Pa, lux, mili-G`
- *MUST*: all 'read' functions return integer values, preferably `int16_t`
- *SHOULD*: if multiple dimensions are read, they SHOULD be combined into a
data structure
- *SHOULD*: the driver implements the SAUL interface
- *SHOULD*: the driver exports functions for putting it to sleep and waking up
the device
# Network devices
## Initialization
The initialization process MUST be split into 2 steps: first, initialize the
device descriptor and if applicable the used peripherals, and secondly do the
actual device initialization. The reason for this is, that before a device is
actually activated and can start to process data, the network stack for the
device needs to be initialized. By supplying a second init function, that does
the actual initialization, we can hand the control over when this is done to the
actual network stacks.
The initialization functions SHOULD follow this naming scheme:
```c
void netabc_setup(netabc_t *dev, const netabc_params_t *params);
int netabs_init(netabc_t *dev);
```
## netdev
Device driver for network device SHOULD implement the `netdev` interface. It is
up to the implementer, if the device driver also offers a device specific
interface which is then mapped to the `netdev` interface, or if the device
driver can be purely interfaced using `netdev`. While the second option is
recommended for efficiency reasons, this is not mandatory.
## Additional Network Device Driver Checklist
- *MUST*: a setup function in the style of
`int devab_setup(devab_t *dev, const devab_params_t *params);` exists
- *MUST*: an init function in the style of `int devnet_init(devnet_t *dev)`
exists
- *SHOULD*: the driver implements 'netdev' [if applicable]
# TODO
Add some information about how to handle multiple threads, when to use mutexes,
and how to deal with interrupts? And especially patterns for being nice from
other threads and power consumption point of view...

View File

@ -0,0 +1,199 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Generated by graphviz version 13.1.2 (0)
-->
<!-- Pages: 1 -->
<svg width="635pt" height="682pt"
viewBox="0.00 0.00 635.00 682.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 678)">
<polygon fill="white" stroke="none" points="-4,4 -4,-678 631.2,-678 631.2,4 -4,4"/>
<!-- Start -->
<g id="node1" class="node">
<title>Start</title>
<path fill="#275a4b" stroke="#3fa687" stroke-width="2" d="M132.6,-637.5C132.6,-637.5 162.6,-637.5 162.6,-637.5 168.6,-637.5 174.6,-643.5 174.6,-649.5 174.6,-649.5 174.6,-661.5 174.6,-661.5 174.6,-667.5 168.6,-673.5 162.6,-673.5 162.6,-673.5 132.6,-673.5 132.6,-673.5 126.6,-673.5 120.6,-667.5 120.6,-661.5 120.6,-661.5 120.6,-649.5 120.6,-649.5 120.6,-643.5 126.6,-637.5 132.6,-637.5"/>
<text xml:space="preserve" text-anchor="middle" x="147.35" y="-651.95" font-family="sans-serif" font-size="14.00" fill="white">Start</text>
</g>
<!-- IfCPU -->
<g id="node3" class="node">
<title>IfCPU</title>
<g id="a_node3"><a xlink:title="CPU/MCU already ported?">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="147.6,-600 0,-553 147.6,-506 295.2,-553 147.6,-600"/>
<text xml:space="preserve" text-anchor="start" x="114.97" y="-559.2" font-family="sans-serif" font-size="14.00" fill="white">CPU/MCU</text>
<text xml:space="preserve" text-anchor="start" x="96.6" y="-539.7" font-family="sans-serif" font-size="14.00" fill="white">already ported?</text>
</a>
</g>
</g>
<!-- Start&#45;&gt;IfCPU -->
<g id="edge1" class="edge">
<title>Start&#45;&gt;IfCPU</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M147.6,-636.53C147.6,-629.86 147.6,-621.87 147.6,-613.52"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="151.1,-613.74 147.6,-603.74 144.1,-613.74 151.1,-613.74"/>
</g>
<!-- End -->
<g id="node2" class="node">
<title>End</title>
<g id="a_node2"><a xlink:href="https://github.com/RIOT-OS/RIOT/tree/master/tests/leds" xlink:title="Blink the LEDs">
<path fill="#275a4b" stroke="#3fa687" stroke-width="2" d="M178,-0.5C178,-0.5 449.2,-0.5 449.2,-0.5 455.2,-0.5 461.2,-6.5 461.2,-12.5 461.2,-12.5 461.2,-24.5 461.2,-24.5 461.2,-30.5 455.2,-36.5 449.2,-36.5 449.2,-36.5 178,-36.5 178,-36.5 172,-36.5 166,-30.5 166,-24.5 166,-24.5 166,-12.5 166,-12.5 166,-6.5 172,-0.5 178,-0.5"/>
<text xml:space="preserve" text-anchor="middle" x="313.12" y="-14.95" font-family="sans-serif" font-size="14.00" fill="white">Blink the LEDs</text>
</a>
</g>
</g>
<!-- IfBoard -->
<g id="node4" class="node">
<title>IfBoard</title>
<g id="a_node4"><a xlink:title="Board definitions already provided?">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="147.6,-469 0,-422 147.6,-375 295.2,-422 147.6,-469"/>
<text xml:space="preserve" text-anchor="start" x="91.35" y="-428.2" font-family="sans-serif" font-size="14.00" fill="white">Board definitions</text>
<text xml:space="preserve" text-anchor="start" x="90.22" y="-408.7" font-family="sans-serif" font-size="14.00" fill="white">already provided?</text>
</a>
</g>
</g>
<!-- IfCPU&#45;&gt;IfBoard -->
<g id="edge2" class="edge">
<title>IfCPU&#45;&gt;IfBoard</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M147.6,-505.06C147.6,-497.77 147.6,-490.15 147.6,-482.62"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="151.1,-482.71 147.6,-472.71 144.1,-482.71 151.1,-482.71"/>
<text xml:space="preserve" text-anchor="middle" x="158.85" y="-483.95" font-family="sans-serif" font-size="14.00" fill="#275a4b">Yes</text>
</g>
<!-- PortCPU -->
<g id="node7" class="node">
<title>PortCPU</title>
<g id="a_node7"><a xlink:title="Port CPU">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="627.2,-571 332,-571 332,-535 627.2,-535 627.2,-571"/>
<text xml:space="preserve" text-anchor="start" x="449.6" y="-554.7" font-family="sans-serif" font-size="14.00" fill="white">Port </text>
<text xml:space="preserve" text-anchor="start" x="481.1" y="-554.7" font-family="sans-serif" font-weight="bold" font-size="14.00" fill="white">CPU</text>
<text xml:space="preserve" text-anchor="start" x="412.85" y="-540.7" font-family="sans-serif" font-size="14.00" fill="white">(TBD: provide guide)</text>
</a>
</g>
</g>
<!-- IfCPU&#45;&gt;PortCPU -->
<g id="edge6" class="edge">
<title>IfCPU&#45;&gt;PortCPU</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M298.06,-553C304.75,-553 311.47,-553 318.19,-553"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="318.05,-556.5 328.05,-553 318.05,-549.5 318.05,-556.5"/>
<text xml:space="preserve" text-anchor="middle" x="313.6" y="-562.2" font-family="sans-serif" font-size="14.00" fill="#275a4b">No</text>
</g>
<!-- IfDrivers -->
<g id="node5" class="node">
<title>IfDrivers</title>
<g id="a_node5"><a xlink:title="All on&#45;board devices supported?">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="147.6,-338 0,-291 147.6,-244 295.2,-291 147.6,-338"/>
<text xml:space="preserve" text-anchor="start" x="107.85" y="-297.2" font-family="sans-serif" font-size="14.00" fill="white">All on&#45;board</text>
<text xml:space="preserve" text-anchor="start" x="84.6" y="-277.7" font-family="sans-serif" font-size="14.00" fill="white">devices supported?</text>
</a>
</g>
</g>
<!-- IfBoard&#45;&gt;IfDrivers -->
<g id="edge3" class="edge">
<title>IfBoard&#45;&gt;IfDrivers</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M147.6,-374.06C147.6,-366.77 147.6,-359.15 147.6,-351.62"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="151.1,-351.71 147.6,-341.71 144.1,-351.71 151.1,-351.71"/>
<text xml:space="preserve" text-anchor="middle" x="158.85" y="-352.95" font-family="sans-serif" font-size="14.00" fill="#275a4b">Yes</text>
</g>
<!-- PortBoard -->
<g id="node8" class="node">
<title>PortBoard</title>
<g id="a_node8"><a xlink:href="@ref porting-boards" xlink:title="Provide board definitions">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="627.2,-440 332,-440 332,-404 627.2,-404 627.2,-440"/>
<text xml:space="preserve" text-anchor="start" x="455.23" y="-423.7" font-family="sans-serif" font-size="14.00" fill="white">Provide</text>
<text xml:space="preserve" text-anchor="start" x="419.23" y="-409.7" font-family="sans-serif" font-weight="bold" font-size="14.00" fill="white">board definitions</text>
</a>
</g>
</g>
<!-- IfBoard&#45;&gt;PortBoard -->
<g id="edge7" class="edge">
<title>IfBoard&#45;&gt;PortBoard</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M298.06,-422C304.75,-422 311.47,-422 318.19,-422"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="318.05,-425.5 328.05,-422 318.05,-418.5 318.05,-425.5"/>
<text xml:space="preserve" text-anchor="middle" x="313.6" y="-431.2" font-family="sans-serif" font-size="14.00" fill="#275a4b">No</text>
</g>
<!-- IfNetdev -->
<g id="node6" class="node">
<title>IfNetdev</title>
<g id="a_node6"><a xlink:title="Network device supported by network stack?">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="147.6,-207 0,-140.5 147.6,-74 295.2,-140.5 147.6,-207"/>
<text xml:space="preserve" text-anchor="start" x="96.6" y="-156.45" font-family="sans-serif" font-size="14.00" fill="white">Network device</text>
<text xml:space="preserve" text-anchor="start" x="103.72" y="-136.95" font-family="sans-serif" font-size="14.00" fill="white">supported by</text>
<text xml:space="preserve" text-anchor="start" x="98.1" y="-117.45" font-family="sans-serif" font-size="14.00" fill="white">network stack?</text>
</a>
</g>
</g>
<!-- IfDrivers&#45;&gt;IfNetdev -->
<g id="edge4" class="edge">
<title>IfDrivers&#45;&gt;IfNetdev</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M147.6,-243.01C147.6,-235.88 147.6,-228.36 147.6,-220.77"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="151.1,-221.01 147.6,-211.01 144.1,-221.01 151.1,-221.01"/>
<text xml:space="preserve" text-anchor="middle" x="158.85" y="-221.95" font-family="sans-serif" font-size="14.00" fill="#275a4b">Yes</text>
</g>
<!-- PortDrivers -->
<g id="node9" class="node">
<title>PortDrivers</title>
<g id="a_node9"><a xlink:href="@ref driver-guide" xlink:title="Provide device drivers">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="627.2,-309 332,-309 332,-273 627.2,-273 627.2,-309"/>
<text xml:space="preserve" text-anchor="start" x="455.23" y="-292.7" font-family="sans-serif" font-size="14.00" fill="white">Provide</text>
<text xml:space="preserve" text-anchor="start" x="430.48" y="-278.7" font-family="sans-serif" font-weight="bold" font-size="14.00" fill="white">device drivers</text>
</a>
</g>
</g>
<!-- IfDrivers&#45;&gt;PortDrivers -->
<g id="edge8" class="edge">
<title>IfDrivers&#45;&gt;PortDrivers</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M298.06,-291C304.75,-291 311.47,-291 318.19,-291"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="318.05,-294.5 328.05,-291 318.05,-287.5 318.05,-294.5"/>
<text xml:space="preserve" text-anchor="middle" x="313.6" y="-300.2" font-family="sans-serif" font-size="14.00" fill="#275a4b">No</text>
</g>
<!-- IfNetdev&#45;&gt;End -->
<g id="edge5" class="edge">
<title>IfNetdev&#45;&gt;End</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M204.26,-98.54C228.85,-80.76 256.88,-60.5 278.4,-44.95"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="280.19,-47.97 286.25,-39.27 276.09,-42.29 280.19,-47.97"/>
<text xml:space="preserve" text-anchor="middle" x="274.65" y="-51.95" font-family="sans-serif" font-size="14.00" fill="#275a4b">Yes</text>
</g>
<!-- PortNetdev -->
<g id="node10" class="node">
<title>PortNetdev</title>
<g id="a_node10"><a xlink:href="@ref drivers_netdev" xlink:title="Provide network device support for network stack">
<polygon fill="#275a4b" stroke="#3fa687" stroke-width="2" points="627.2,-158.5 332,-158.5 332,-122.5 627.2,-122.5 627.2,-158.5"/>
<text xml:space="preserve" text-anchor="start" x="369.73" y="-142.2" font-family="sans-serif" font-size="14.00" fill="white">Provide </text>
<text xml:space="preserve" text-anchor="start" x="422.23" y="-142.2" font-family="sans-serif" font-weight="bold" font-size="14.00" fill="white">network device support</text>
<text xml:space="preserve" text-anchor="start" x="421.85" y="-128.2" font-family="sans-serif" font-size="14.00" fill="white">for network stack</text>
</a>
</g>
</g>
<!-- IfNetdev&#45;&gt;PortNetdev -->
<g id="edge9" class="edge">
<title>IfNetdev&#45;&gt;PortNetdev</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M297.57,-140.5C304.47,-140.5 311.4,-140.5 318.32,-140.5"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="318.14,-144 328.14,-140.5 318.14,-137 318.14,-144"/>
<text xml:space="preserve" text-anchor="middle" x="313.6" y="-149.7" font-family="sans-serif" font-size="14.00" fill="#275a4b">No</text>
</g>
<!-- PortCPU&#45;&gt;IfBoard -->
<g id="edge10" class="edge">
<title>PortCPU&#45;&gt;IfBoard</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M433.44,-534.06C379.76,-513.21 290.3,-478.45 225.74,-453.36"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="227.4,-450.25 216.81,-449.89 224.86,-456.78 227.4,-450.25"/>
</g>
<!-- PortCPU&#45;&gt;PortBoard -->
<!-- PortBoard&#45;&gt;IfDrivers -->
<g id="edge11" class="edge">
<title>PortBoard&#45;&gt;IfDrivers</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M433.44,-403.06C379.76,-382.21 290.3,-347.45 225.74,-322.36"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="227.4,-319.25 216.81,-318.89 224.86,-325.78 227.4,-319.25"/>
</g>
<!-- PortBoard&#45;&gt;PortDrivers -->
<!-- PortDrivers&#45;&gt;IfNetdev -->
<g id="edge12" class="edge">
<title>PortDrivers&#45;&gt;IfNetdev</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M439.55,-272.09C388.71,-249.35 299.63,-209.5 233.19,-179.79"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="234.81,-176.67 224.25,-175.78 231.95,-183.06 234.81,-176.67"/>
</g>
<!-- PortDrivers&#45;&gt;PortNetdev -->
<!-- PortNetdev&#45;&gt;End -->
<g id="edge13" class="edge">
<title>PortNetdev&#45;&gt;End</title>
<path fill="none" stroke="#3fa687" stroke-width="2" d="M454.75,-121.53C426.55,-101.15 380.36,-67.76 348.54,-44.76"/>
<polygon fill="#3fa687" stroke="#3fa687" stroke-width="2" points="350.96,-42.19 340.8,-39.17 346.86,-47.86 350.96,-42.19"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,435 @@
---
title: Porting Boards
description: Guide on how to port new boards to RIOT-OS
---
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.
:::
# Porting Flowchart
![Porting flowchart](img/porting-boards.svg)
# General Structure
Like [applications](/advanced_tutorials/creating_applications/) or
[modules](/advanced_tutorials/creating_modules),
boards consist of a directory containing source files and
Makefiles. Usually a `BOARD` directory has the following structure,
although not all of the subdirectories or Makefiles have to be present for
a board implementation to work.
```
board-foo/
|----dist/
|----scripts
|----board.c
|----doc.md
|----include/
|----periph_conf.h
|----board.h
|----gpio_params.h
|----Makefile
|----Makefile.dep
|----Makefile.features
|----Makefile.include
```
## 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.).
- `gpio_params.h`: if the board supports
[SAUL](https://doc.riot-os.org/group__drivers__saul.html) then its
[saul_gpio_params_t](https://doc.riot-os.org/structsaul__gpio__params__t.html)
is defined here. (Analogously, an `adc_params.h` can
contain a [saul_adc_params_t](https://doc.riot-os.org/structsaul__adc__params__t.html)
and `pwm_params.h` a
[saul_pwm_rgb_params_t](https://doc.riot-os.org/structsaul__pwm__rgb__params__t.html)
and a [saul_pwm_dimmer_params_t](https://doc.riot-os.org/structsaul__pwm__dimmer__params__t.html)).
- 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 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).
```c
void board_init(void)
{
/* initialize GPIO or others... */
...
}
```
## Makefiles
### Makefile
A board's Makefile just needs to include `Makefile.base` in the RIOT
repository and define the `MODULE` as `board` (see
[modules](/advanced_tutorials/creating_modules) for more details)
```makefile
MODULE = board
include $(RIOTBASE)/Makefile.base
```
### 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:
```makefile
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.
:::
#### 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 radio driver](https://doc.riot-os.org/group__drivers__sx127x.html)
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](https://doc.riot-os.org/group__drivers__saul.html)
interface. This is usually done as following:
```makefile
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += saul_gpio
USEMODULE += apds9960
USEMODULE += bmp280_i2c
USEMODULE += lis3mdl
USEMODULE += sht3x
endif
```
### 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 [build system basics](/build-system/build_system_basics/)
for more details on these variables).
e.g.:
```makefile
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
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 defines the following values for the serial
port (depending on the host OS):
```
PORT_LINUX ?= /dev/ttyACM0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbmodem*)))
```
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 `Makefile.include`:
```makefile
# Define the default port depending on the host OS
PORT_LINUX ?= /dev/ttyUSB0
PORT_DARWIN ?= $(firstword $(sort $(wildcard /dev/tty.usbserial*)))
# this board uses OpenOCD
PROGRAMMER ?= openocd
```
## Timer Configurations
When using the high level timer `ztimer` there is an overhead in calling the
[ztimer_sleep](https://doc.riot-os.org/group__sys__ztimer.html#gade98636e198f2d571c8acd861d29d360)
and [ztimer_set](https://doc.riot-os.org/group__sys__ztimer.html#ga8934a79a89e35d58673418a1e4a2e69c)
functions. This offset can be compensated for.
It can be measured by running `tests/sys/ztimer_overhead` on your board, i.e:
```bash
$ BOARD=my-new-board make -C tests/sys/ztimer_overhead flash term
main(): This is RIOT!
ZTIMER_USEC auto_adjust params:
ZTIMER_USEC->adjust_set = xx
ZTIMER_USEC->adjust_sleep = xx
ZTIMER_USEC auto_adjust params cleared
zitmer_overhead_set...
min=6 max=7 avg_diff=6
zitmer_overhead_sleep...
min=21 max=21 avg_diff=21
ZTIMER_USEC adjust params for my-new-board:
CONFIG_ZTIMER_USEC_ADJUST_SET 6
CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21
```
The last two lines can be added as defines to the new board `board.h`:
```c
/**
* @name ztimer configuration values
* @{
*/
#define CONFIG_ZTIMER_USEC_ADJUST_SET 6
#define CONFIG_ZTIMER_USEC_ADJUST_SLEEP 21
/** @} */
```
Alternatively, the pseudomodule [ztimer_auto_adjust](https://doc.riot-os.org/group__pseudomodule__ztimer__auto__adjust.html)
can be used in an application to enable automatic timer offset compensation at board startup.
This however incurs overhead both in the text segment and at bootup time.
## doc.md
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.
```markdown
@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
...
```
Previously documentation was contained in `doc.txt` files with C-style comment
blocks. This style has been deprecated in favor of using `doc.md` files in
Markdown format, which eliminates formatting and interpretation issues.
Old style files will continually be replaced by the new format.
Up to version `0.9.2` the [riotgen](https://pypi.org/project/riotgen/) tool
will generate `doc.txt` files instead of `doc.md` files. You can upgrade it to
the latest version with
```bash
pip install --upgrade riotgen
```
# 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:
```bash
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
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, for example in the `cfg_timer_tim5.h`:
```c
/**
* @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)
/** @} */
```
# 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.md
|----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):
```makefile
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
[Using Common Code](#using-common-code)). e.g:
`include $(RIOTBOARD)/foo-parent/Makefile.*include*`
An example can be found in
[`tests/build_system/external_board_native`](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/external_board_native).
# Board Names and Aliases
New boards should be named according to
[RDM0003](https://github.com/RIOT-OS/RIOT/blob/master/doc/memos/rdm0003.md).
Historically, some board names have not followed this structure.
For backwards compatibility, RIOT supports board aliases that can be used
in place of the actual board name in the environment or Make variable `BOARD`.
A list of all existing board aliases can be found in
[`makefiles/board_alias.inc.mk`](https://github.com/RIOT-OS/RIOT/blob/master/makefiles/board_alias.inc.mk).
[`BOARD=native`](https://doc.riot-os.org/group__boards__common__native.html)
is a special alias in that it
resolves to either [`native32`](https://doc.riot-os.org/group__boards__native32.html)
or [`native64`](https://doc.riot-os.org/group__boards__native64.html)
depending on the host architecture.
# 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.
# Further Reference
- [In her blog](https://blog.martine-lenders.eu/riot-board-en.html), Martine Lenders documented her approach of
porting the [Adafruit Feather nRF52840 Express](https://doc.riot-os.org/group__boards__adafruit-feather-nrf52840-express.html)
in February 2020.
- [Over at HackMD][https://hackmd.io/njFHwQ33SNS3sQKAkLkNtQ], Akshai M documented his approach of
porting the [Silicon Labs SLSTK3400A starter kit](https://doc.riot-os.org/group__boards__slstk3400a.html) in July 2020.

View File

@ -0,0 +1,51 @@
---
title: Debugging Tools
description: Overview of debugging tools supported in RIOT-OS
---
## Undefined Behavior Sanitizer (ubsan)
RIOT contains Makefile convenience support for gcc/clang's undefined
behaviour sanitizer.
### Overview
Both gcc and clang allow generation of code that does runtime checks for
undefined behavior (UB).
E.g., the following code might trigger UB for some parameters:
```c
void test(int foo) {
return (foo << 24);
}
```
In this case, the signed shift would be alright unless:
- it would "push out" all bits to the left, with undefined runtime result. Here,
that happens on architectures with 16-bit integers.
- `foo` is negative, with implementation-specific runtime results.
Using ubsan, these can be caught at runtime.
There are three modes for ubsan that define what happens when the sanitizer
observed undefined behaviour:
1. `trap` -> cause a trap
2. `msg_exit` -> print a message and exit
3. `msg_recover` -> print a message and continue
`trap` is available on all RIOT platforms, whereas `msg_exit` and `msg_recover`
are currently only available on `native` when building with gcc, as they require runtime support in
the form of `libubsan`.
The default is `trap`, or `msg_exit` if available (currently, on native:gnu only).
### How to Use
1. build with `make all-ubsan`.
2. build with `UBSAN_MODE=[trap|msg_exit|msg_recover] make all-ubsan` to
override the ubsan mode.

View File

@ -0,0 +1,506 @@
---
title: Flashing via RIOT's Build System
description: Guide on how to flash boards using RIOT's build system
---
# General Approach
In general, flashing a board from RIOT is as straight forward as typing in a
shell (with the application directory as current working directory):
```sh
make BOARD=<BOARD-TO-FLASH> flash
```
This will **rebuild** ***AND*** **flash** the application in the current working
directory for board `<BOARD-TO-FLASH>`, using its default programming tool. If
you want to use an alternative programming tool, say `stm32flash`, use:
```sh
make BOARD=<BOARD-TO-FLASH> PROGRAMMER=stm32flash flash
```
To flash without rebuilding use `flash-only` as target instead of `flash`.
# Supported Tools
RIOT supports plenty of flashing tools, that are below grouped into general
flashing tools that support multiple MCU families, and specialized tools that
only support one platform.
Note that some programmers require additional configuration on a per board
level or rely on features only available on some boards. Hence, a given board
may not be supported by a programmer listed as supported for the platform of
the board due to a missing board feature, bootloader, or similar.
To ease use the programmers are given by the value to pass via
`PROGRAMMER=<value>`, rather than the official spelling of the programmer.
## Compatibility Matrix of Generic Tools
<!-- Note: Add flashers that theoretically support multiple platforms here,
even if RIOT does only have integration for one platform. The missing
integration may be added later on. -->
MCU Family | `bmp` | `dfu-util` | `jlink` | `openocd` | `pyocd` | `uf2conv`
---------------|--------|------------|---------|-----------|---------|----------
ATmega | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ATXmega | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
CC13xx / C26xx | ✗ | ✗ | ✓ | ✓ (1) | ✗ | ✗
CC2538 | ✗ | ✗ | ✓ | ✗ | ✗ | ✗
EFM32 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
ESP8266 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ESP32 (Xtensa) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
ESP32 (RISC-V) | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
FE310 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
GD32V | ✗ | ✗ | ✗ | ✓ (1) | ✗ | ✗
Kinetis | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
LPC1768 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
LPC23xx | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
MIPS32r2 | ✗ | ✗ | ✓ | ✗ | ✗ | ✗
MSP430 | ✗ | ✗ | ✗ | ✗ | ✗ | ✗
nRF51 | ✗ | ✗ | ✓ | ✓ | ✓ | ✗
nRF52 | ✓ | ✗ | ✓ | ✓ | ✓ | ✓
RP2040 | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
SAM | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
Stellaris | ✗ | ✗ | ✓ | ✓ | ✗ | ✗
STM32 | ✓ | ✓ | ✓ | ✓ | ✗ | ✗
Remarks:
1. Requires a patched version of the programmer tool
## Specialized Flashing Tools Per Platform
The following list only contains single-platform flashing tools. Tools that
support multiple platforms are given in section above.
### AVR
- `avrdude`
### CC13xx / CC26xx
- `uniflash`
### CC2538
- `cc2538-bsl`
### ESP8266 / ESP32 (Xtensa) / ESP32 (RISC-V)
- `esptool`
### LPC23xx
- `lpc2k_pgm`
### MSP430
- `mspdebug`
- `goodfet`
### nRF52
- `adafruit-nrfutil`, `uf2conv` (requires Adafruit bootloader),
see [Adafruit nRF52 Bootloader Common](https://doc.riot-os.org/group__boards__common__adafruit-nrf52-bootloader.html)
- `nrfutil` (required nRF bootloader)
- `nrfjprog` (requires a separate J-Link debugger)
### RP2040 / RP2350
- `picotool`
### SAM
- `bossa`
- `edbg`
### STM32
- `stm32flash`
- `stm32loader`
- `cpy2remed` (requires integrated ST-Link programmer, e.g. Nucleo boards)
- `robotis-loader` (requires robotis bootloader, only one board supported)
# Programmer Configuration
This section will list additional configuration options to control the behavior
of a programming tool, such as selecting the hardware adapter used for
programming.
## OpenOCD Configuration
### OPENOCD_DEBUG_ADAPTER
`OPENOCD_DEBUG_ADAPTER` can be set via command line or as environment variable
to use non-default flashing hardware.
### OPENOCD_RESET_USE_CONNECT_ASSERT_SRST
`OPENOCD_RESET_USE_CONNECT_ASSERT_SRST` can be set via command line or as
environment variable to `0` to disable resetting the board via the `SRST` line.
This is useful when the `SRST` signal is not connected to the debug adapter or
when using cheap ST-Link V2 clones with broken `SRST` output. Note that it may
not be possible to attach the debugger while the MCU is in deep sleeping mode.
If this is set to `0` by the user, the user may need a carefully timed reset
button press to be able to flash the board.
### OPENOCD_PRE_FLASH_CMDS
`OPENOCD_PRE_FLASH_CMDS` can be set as environment variable to pass additional
commands to OpenOCD prior to flashing, e.g. to disable flash write protection.
### OPENOCD_PRE_VERIFY_CMDS
`OPENOCD_PRE_VERIFY_CMDS` can be set as environment variable to pass additional
flags to OpenOCD prior to verifying the flashed firmware. E.g. this is used
in the `pba-d-01-kw2x` to disable the watchdog to prevent it from disrupting
the verification process.
### OPENOCD_PRE_FLASH_CHECK_SCRIPT
`OPENOCD_PRE_FLASH_CHECK_SCRIPT` can be set via command line or as
environment variable to execute a script before OpenOCD starts flashing. It is
used for Kinetis boards to prevent bricking a board by locking the flash via
magic value in the flash configuration field protection bits.
The script is expected to exit with code `0` if flashing should resume, or with
exit code `1` if flashing should be aborted.
### OPENOCD_CONFIG
`OPENOCD_DEBUG_ADAPTER` can be set via command line or as environment variable
to use non-default OpenOCD configuration file.
### OPENOCD_TRANSPORT
`OPENOCD_TRANSPORT` can be set via command line or as environment variable to
select a non-default transport protocol. E.g. to use JTAG rather than SWD for a
board that defaults to SWD use:
```sh
make PROGRAMMER=openocd OPENOCD_TRANSPORT=jtag
```
Note that the OpenOCD configuration file of a given board may only support SWD or
JTAG. Also JTAG requires more signal lines to be connected compared to SWD and
some internal programmers only have the SWD signal lines connected, so that
JTAG will not be possible.
## stm32flash Configuration
It is possible to automatically boot the STM32 board into the in-ROM bootloader
that `stm32flash` communicates with for flashing by connecting the RST pin to
DTR and the BOOT pin (or BOOT0 for STM32 MCU families with BOOT0 and BOOT1 pins)
to RTS of the TTL adapter. In addition, set `STM32FLASH_RESET` to `1` via
environment or command line to actually issue a reset with BOOT (or BOOT0)
pulled high prior flashing to enter the bootloader, and a second reset with BOOT
(or BOOT0) pulled low to reboot into the application. `STM32FLASH_RESET`
defaults to `0` as of know, as with `PROGRAMMER=stm32flash STM32FLASH_RESET=1`
additional terminal flags are set, so that `make term` doesn't accidentally
keeps the reset signal pulled low or boot the board into the bootloader.
The TTL adapter this was tested with had inverted RTS and DTR signal. By setting
`STM32FLASH_RESET_INVERT` to `1` RIOT will assume RTS and DTR signals to be
inverted, by setting it to `0` non-inverted signals will be generated. As of
now, `STM32FLASH_RESET_INVERT` is by default `1`. This may change if it
becomes evident that non-inverted TTL adapters are in fact more common than
inverted adapters.
## MSPDEBUG Configuration
All options can be passed as environment variables or as make arguments.
All options except for `DEBUGSERVER_PORT` apply to both debugging and flashing
alike.
`MSPDEBUG_PROGRAMMER` is used to set the hardware programmer/debugger to use
for programming and debugging. See `mspdebug --help` or `man mspdebug` for a
list of programmers.
`MSPDEBUG_PROTOCOL` is used to specify the debugger protocol. It is typically
set by the board used. Only JTAG and Spi-Bi-Wire are supported.
`MSPDEBUG_TTY` is used to connect via TTY interface instead of directly via
USB to the debugger. Usually, this is not required.
`DEBUG_ADAPTER_ID` is used to select the debugger/programmer by its serial. If
not set, `mspdebug` will select the first device with matching vendor and
product ID. Unless multiple debuggers of the same type are connected, this
options is typically not needed.
`DEBUGSERVER_PORT` is used to specify the TCP port to listen for GDB to
connect to. It defaults to 2000.
## Handling Multiple Boards with UDEV-Rules
When developing and working with multiple boards the default `PORT`
configuration for a particular board might not apply anymore, so `PORT` will need
to be specified whenever calling `make term/test`. This can also happen if
multiple `DEBUGGERS/PROGRAMMERS` are present so `DEBUG_ADAPTER_ID` will also
need to be passed. Keeping track of this will become annoying.
One way of handling this is to use `udev` rules to define `SYMLINKS` between the
boards serial port (`riot/tty-<board-name>`) and the actual serial port
(dev/ttyACM* or other). With this we can query the rest of the boards serial
`dev` information (`DEBUG_ADAPTER_ID`, `PORT`, etc.) to always flash and open a
terminal on the correct port.
### Procedure
- use `udevadm info /dev/ttyACM0` to query the udev database for information on
device on port `/dev/ttyACM0`.
- or: use `udevadm info --attribute-walk --name /dev/ttyACM0` for more detailed
output when the first level of information isn't enough
- create a udev rule with information of the device and one parent to create a
matching rule in `/etc/udev/rules.d/70-riotboards.rules`.
```
# samr21-xpro
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", \
ATTRS{idProduct}=="2111", ATTRS{manufacturer}=="Atmel Corp.", \
ATTRS{serial}=="ATML2127031800004957", SYMLINK+="riot/tty-samr21-xpro"
```
- reload rules: `udevadm control --reload-rules`
- Boards `PORT` are symlinked to /dev/riot/tty-`board-name`.
- Create a `makefile.pre` that will query the real `PORT` and the
`DEBUG_ADAPTER_ID` from the `SYMLINK` info
```makefile
PORT = /dev/riot/tty-$(BOARD)
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n '/ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p}')
```
- You can now add `makefile.pre` to `RIOT_MAKEFILES_GLOBAL_PRE` as an environment
variable or on each `make` call:
```sh
$ RIOT_MAKEFILES_GLOBAL_PRE=/path/to/makefile.pre make -C examples/basic/hello-world flash term
```
:::note
If set as an environment variable it would be a good idea to add a
variable to enable/disable it, e.g:
```makefile
ifeq (1,$(ENABLE_LOCAL_BOARDS))
PORT = /dev/riot/tty-$(BOARD)
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n '/ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p}')
endif
```
:::
## Handling Multiple Versions of the same BOARD
The above procedure works fine when handling different boards, but not
multiple times the same board, e.g: multiple `samr21-xpro`.
An option for this would be to add an identifier of that board to the mapped
`riot/tty-*`, there are multiple ways of handling this but in the end it means
having a way to identify every copy.
Another way would be to map the `DEBUG_ADAPTER_ID` in the name:
```makefile
SYMLINK+="riot/node-$attr{serial}
```
But it will require to know in advance the serial number of each board you want
to use. Another option would be to add some kind of numbering and defining
multiple symlinks for each board. e.g. for `samr21-xpro` number `n`:
```
# samr21-xpro
SUBSYSTEM=="tty", SUBSYSTEMS=="usb", ATTRS{idVendor}=="03eb", \
ATTRS{idProduct}=="2111", ATTRS{manufacturer}=="Atmel Corp.", \
ATTRS{serial}=="ATML2127031800004957", SYMLINK+="riot/tty-samr21-xpro", \
SYMLINK+="riot/tty-samr21-xpro-n"
```
Then, when flashing, the number can be specified and the parsing adapted:
```makefile
ifneq(,$(BOARD_NUM))
PORT = /dev/riot/tty-$(BOARD)-$(BOARD_NUM)
else
PORT = /dev/riot/tty-$(BOARD)
endif
DEBUG_ADAPTER_ID = $(\
shell udevadm info -q property $(PORT) |\
sed -n '/ID_SERIAL_SHORT/ {s/ID_SERIAL_SHORT=//p}')
```
```sh
BOARD=samr21-xpro BOARD_NUM=n make flash term
```
In the end, this would be the same as using the serial, but a simple number might
be easier to handle.
## Notes
Udev only parses SUBSYSTEM and one parent. For others, we will rely on ENV
variables defined by 60-serial.rules
So the current filename should be higher than 60-serial.rules
If for some reason re-writing the serial is needed there is a windows tool:
https://remoteqth.com/wiki/index.php?page=How+to+set+usb+device+SerialNumber
## Documentation:
* The whole documentation
http://reactivated.net/writing_udev_rules.html#udevinfo
* Udev manpage
http://manpages.ubuntu.com/manpages/eoan/en/man7/udev.7.html
# Handling Multiple Boards without UDEV-Rules
This is a simpler approach than the above mentioned issue. The solution here only
uses a Makefile for selecting the debugger and serial port. No
administrative privileges (e.g. to configure Udev) are required.
One of the limitations of the solution described here is that it currently
doesn't work with multiple boards of the same type. This is a
limitation of the script and not of the mechanism used, it is possible to adapt
the script to support multiple boards of the same type. This modification is
left as an exercise to the reader.
The following Make snippet is used:
```makefile
LOCAL_BOARD_MAP ?= 1
# Adapt this list to your board collection
SERIAL_nucleo-f103rb ?= 066BFF343633464257254156
SERIAL_same54-xpro ?= ATML2748051800005053
SERIAL_samr21-xpro ?= ATML2127031800008360
SERIAL_nrf52dk ?= 000682223007
ifeq (1,$(LOCAL_BOARD_MAP))
# Retrieve the serial of the selected board
BOARD_SERIAL = $(SERIAL_$(BOARD))
# Check if there is a serial for the board
ifneq (,$(BOARD_SERIAL))
# Set the variables used by various debug tools to the selected serial
SERIAL ?= $(BOARD_SERIAL)
DEBUG_ADAPTER_ID ?= $(BOARD_SERIAL)
JLINK_SERIAL ?= $(BOARD_SERIAL)
# Use the existing script to grab the matching /dev/ttyACM* device
PORT ?= $(shell $(RIOTTOOLS)/usb-serial/ttys.py --most-recent --format path --serial $(SERIAL))
endif
endif
```
The array of board serial numbers has to be edited to match your local boards.
The serial numbers used here is the USB device serial number as reported by
the debugger hardware. With the `make list-ttys` it is reported as the 'serial':
```sh
$ make list-ttys
path | driver | vendor | model | model_db | serial | ctime
-------------|---------|--------------------------|--------------------------------------|-----------------------|--------------------------|---------
/dev/ttyUSB0 | cp210x | Silicon Labs | CP2102 USB to UART Bridge Controller | CP210x UART Bridge | 0001 | 15:58:13
/dev/ttyACM1 | cdc_acm | STMicroelectronics | STM32 STLink | ST-LINK/V2.1 | 0671FF535155878281151932 | 15:58:04
/dev/ttyACM3 | cdc_acm | Arduino (www.arduino.cc) | EOS High Power | Mega ADK R3 (CDC ACM) | 75230313733351110120 | 15:59:57
/dev/ttyACM2 | cdc_acm | SEGGER | J-Link | J-Link | 000683475134 | 12:41:36
```
When the above make snippet is included as `RIOT_MAKEFILES_GLOBAL_PRE`, the
serial number of the USB device is automatically set if the used board is
included in the script. This will then ensure that the board debugger is used
for flashing and the board serial device is used when starting the serial
console.
It supports command line parameters to filter by vendor name, model name, serial
number, or driver. In addition, the `--most-recent` argument will only print the
most recently added interface (out of those matching the filtering by vendor,
model, etc.). The `--format path` argument will result in only the device path
being printed for convenient use in scripts.
# Handling Multiple Boards: Simplest Approach
Passing `MOST_RECENT_PORT=1` as environment variable or as parameter to
make will result in the most recently connected board being preferred over the
default PORT for the selected board.
For some boards `TTY_BOARD_FILTER` is provided, which filters TTYs e.g. by
vendor or model to only considered TTYs that actually may belong to the selected
board. E.g. for Nucleo boards this is `--model 'STM32 STLink'`, as they all use
an integrated STLink as programmer. As long as only one TTY is provided from an
STLink, this will reliably select the correct TTY for an Nucleo regardless of
which TTY was most recently connected. Some boards even provide info that
allows to always reliably identify them correctly (e.g. the firmware on the
ATmega16U2 used as USB to UART converter on Arduino Mega2560 will provide
identification data unique to that board).
## Adding Board Filters
After connecting as many variants of the board you target (and maybe some others
to test that the filter actually filters out non-matching boards). Then first
run `./dist/tools/usb-serial/ttys.py` without arguments and study the output.
When a genuine Arduino Mega 2560, a genuine Arduino Mega ADK (a variant of the
Mega 2560), a cheap Arduino Mega 2560 clone, a BBC micro:bit v2 and a
Nucleo F767-ZI are connected, the following output is shown:
path | driver | vendor | model | model_db | serial | ctime | iface_num
-------------|---------|--------------------------|--------------------------------------|------------------------------------------------------|--------------------------------------------------|----------|----------
/dev/ttyACM0 | cdc_acm | Arduino (www.arduino.cc) | 0042 | Mega 2560 R3 (CDC ACM) | 857353134333519002C1 | 12:13:55 | 0
/dev/ttyACM1 | cdc_acm | Arduino (www.arduino.cc) | EOS High Power | Mega ADK R3 (CDC ACM) | 75230313733351110120 | 15:59:57 | 0
/dev/ttyACM2 | cdc_acm | STMicroelectronics | STM32 STLink | ST-LINK/V2.1 | 0670FF535155878281123912 | 10:00:39 | 2
/dev/ttyACM3 | cdc_acm | Arm | BBC micro:bit CMSIS-DAP | ARM mbed | 99053602000528334c41b84da1f2f09d000000006e052820 | 12:21:03 | 1
/dev/ttyUSB0 | cp210x | Silicon Labs | CP2102 USB to UART Bridge Controller | CP2102/CP2109 UART Bridge Controller [CP210x family] | 0001 | 16:57:27 | 0
Now we add arguments to the invocation of `ttys.py` to filter the list e.g.
by model, vendor etc. (note: as regex!) ideally until only the target boards
are listed. Some boards do not provide enough information to e.g. tell them
apart from other boards using the same USB to UART bridge or the same debugger.
In that case we have to live with some "bycatch".
In the case of the Arduino Mega 2560 the parameters
`--vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'` will narrow down the
list to only show the genuine Arduino Mega versions. Se we add to the
`Makefile.include` in `boards/arduino-mega2560`:
```makefile
TTY_BOARD_FILTER := --vendor 'Arduino' --model-db 'Mega 2560|Mega ADK'
```
Note that also matching the `R3` in `Mega 2560 R3` would prevent matching older
or newer revisions than R3, so we don't add that to the regex.
## Advances Board Filters
In most cases, just adding a simple `TTY_BOARD_FILTER` is sufficient. If we
however have wildly different flavors of the same board (e.g. genuine Arduino
Mega 2560 with an ATmega16U2 and clones with a cheap USB to UART bridge) that we
all want to support, we have to instead provide a `TTY_SELECT_CMD` that prints
the path to and the serial of the TTY (separated by a space) and exists with
`0` if a TTY was found, or that exists with `1` and prints nothing when no TTY
was found. We can still use the `ttys.py` script to detect all Arduino Mega
2560 versions: We first try to detect a genuine Arduino Mega and fall back to
selecting cheap USB UART bridges when that fails using the `||` shell operator:
```makefile
TTY_SELECT_CMD := $(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path serial \
--vendor 'Arduino' \
--model-db 'Mega 2560|Mega ADK' || \
$(RIOTTOOLS)/usb-serial/ttys.py \
--most-recent \
--format path serial \
--driver 'cp210x'
```

View File

@ -0,0 +1,637 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="245.79939mm"
height="24.209375mm"
viewBox="0 0 245.79939 24.209375"
version="1.1"
id="svg1"
inkscape:version="1.4.2 (ebf0e940d0, 2025-05-08)"
sodipodi:docname="kconfig_integration.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns:xhtml="http://www.w3.org/1999/xhtml">
<sodipodi:namedview
id="namedview1"
pagecolor="#ffffff"
bordercolor="#000000"
borderopacity="0.25"
inkscape:showpageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#d1d1d1"
inkscape:document-units="mm"
inkscape:zoom="0.99508277"
inkscape:cx="397.95684"
inkscape:cy="551.21043"
inkscape:window-width="2560"
inkscape:window-height="1368"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
inkscape:current-layer="layer1" />
<defs
id="defs1" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0.23629884,-2.7317763)">
<g
id="g16"
transform="matrix(0.26458333,0,0,0.26458333,1.4849785,2.864068)">
<rect
x="1"
y="1"
width="120"
height="60"
rx="9"
ry="9"
fill="#275a4b"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="rect1" />
<g
transform="translate(-0.5,-0.5)"
id="g1">
<switch
id="switch1">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 2px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 15px; font-family: Courier New; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:font
color="#ffffff"
style="font-size: 15px">
<xhtml:span
style="font-size: 15px">$(USEMODULE)<xhtml:br
style="font-size: 15px" />
$(USEPKG)<xhtml:br
style="font-size: 15px" />
</xhtml:span>
</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="61"
y="36"
fill="#000000"
font-family="'Courier New'"
font-size="15px"
text-anchor="middle"
font-weight="bold"
id="text1">$(USEMODULE)...</text>
</switch>
</g>
<rect
x="201"
y="1"
width="120"
height="60"
rx="9"
ry="9"
fill="#275a4b"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="rect2" />
<g
transform="translate(-0.5,-0.5)"
id="g2">
<switch
id="switch2">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 202px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 15px; font-family: Courier New; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:font
color="#ffffff"
style="font-size: 15px">
<xhtml:span
style="font-size: 15px">Kconfig.dep</xhtml:span>
</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="261"
y="36"
fill="#000000"
font-family="'Courier New'"
font-size="15px"
text-anchor="middle"
font-weight="bold"
id="text2">Kconfig.dep</text>
</switch>
</g>
<rect
x="401"
y="1"
width="120"
height="60"
rx="9"
ry="9"
fill="#275a4b"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="rect3" />
<g
transform="translate(-0.5,-0.5)"
id="g3">
<switch
id="switch3">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 402px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 15px; font-family: Courier New; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:font
color="#ffffff"
style="font-size: 15px">
<xhtml:span
style="font-size: 15px">out.config</xhtml:span>
</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="461"
y="36"
fill="#000000"
font-family="'Courier New'"
font-size="15px"
text-anchor="middle"
font-weight="bold"
id="text3">out.config</text>
</switch>
</g>
<rect
x="601"
y="1"
width="120"
height="60"
rx="9"
ry="9"
fill="#3f9179"
stroke="#3fa687"
stroke-width="3"
stroke-dasharray="3, 3"
pointer-events="all"
id="rect4" />
<g
transform="translate(-0.5,-0.5)"
id="g4">
<switch
id="switch4">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 602px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 15px; font-family: Courier New; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:font
color="#ffffff"
style="font-size: 15px">
<xhtml:span
style="font-size: 15px">menuconfig<xhtml:br
style="font-size: 15px" />
</xhtml:span>
</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="661"
y="36"
fill="#000000"
font-family="'Courier New'"
font-size="15px"
text-anchor="middle"
font-weight="bold"
id="text4">menuconfig</text>
</switch>
</g>
<path
d="m 124,31 h 64.65"
fill="none"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="stroke"
id="path4" />
<circle
cx="121"
cy="31"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="ellipse4"
r="3" />
<path
d="m 197.65,31 -9,4.5 v -9 z"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="all"
id="path5" />
<path
d="m 324,30.72 64.65,0.24"
fill="none"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="stroke"
id="path6" />
<circle
cx="321"
cy="30.709999"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="ellipse6"
r="3" />
<path
d="m 397.65,30.99 -9.02,4.47 0.03,-9 z"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="all"
id="path7" />
<path
d="m 524,30.72 64.65,0.24"
fill="none"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="stroke"
id="path8" />
<circle
cx="521"
cy="30.709999"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="ellipse8"
r="3" />
<path
d="m 597.65,30.99 -9.02,4.47 0.03,-9 z"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="all"
id="path9" />
<rect
x="801"
y="1"
width="120"
height="60"
rx="9"
ry="9"
fill="#275a4b"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="rect9" />
<g
transform="translate(-0.5,-0.5)"
id="g9">
<switch
id="switch9">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 31px; margin-left: 802px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 15px; font-family: Courier New; color: #000000; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:font
color="#ffffff"
style="font-size: 15px">
<xhtml:span
style="font-size: 15px">autoconf.h<xhtml:br
style="font-size: 15px" />
</xhtml:span>
</xhtml:font>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="861"
y="36"
fill="#000000"
font-family="'Courier New'"
font-size="15px"
text-anchor="middle"
font-weight="bold"
id="text9">autoconf.h</text>
</switch>
</g>
<path
d="m 724,30.72 64.65,0.24"
fill="none"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="stroke"
id="path10" />
<circle
cx="721"
cy="30.709999"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
pointer-events="all"
id="ellipse10"
r="3" />
<path
d="m 797.65,30.99 -9.02,4.47 0.03,-9 z"
fill="#3fa687"
stroke="#3fa687"
stroke-width="3"
stroke-miterlimit="10"
pointer-events="all"
id="path11" />
<rect
x="41"
y="71"
width="40"
height="20"
fill="none"
stroke="none"
pointer-events="all"
id="rect11" />
<g
transform="translate(-0.5,-0.5)"
id="g11">
<switch
id="switch11">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 81px; margin-left: 42px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 12px; font-family: Courier New; color: #333333; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:span>
<xhtml:font
style="font-size: 15px"
color="#666666">0</xhtml:font>
</xhtml:span>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="61"
y="85"
fill="#333333"
font-family="'Courier New'"
font-size="12px"
text-anchor="middle"
font-weight="bold"
id="text11">0</text>
</switch>
</g>
<rect
x="241"
y="71"
width="40"
height="20"
fill="none"
stroke="none"
pointer-events="all"
id="rect12" />
<g
transform="translate(-0.5,-0.5)"
id="g12">
<switch
id="switch12">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 81px; margin-left: 242px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 12px; font-family: Courier New; color: #333333; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:span>
<xhtml:font
style="font-size: 15px"
color="#666666">1</xhtml:font>
</xhtml:span>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="261"
y="85"
fill="#333333"
font-family="'Courier New'"
font-size="12px"
text-anchor="middle"
font-weight="bold"
id="text12">1</text>
</switch>
</g>
<rect
x="441"
y="71"
width="40"
height="20"
fill="none"
stroke="none"
pointer-events="all"
id="rect13" />
<g
transform="translate(-0.5,-0.5)"
id="g13">
<switch
id="switch13">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 81px; margin-left: 442px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 12px; font-family: Courier New; color: #333333; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:span>
<xhtml:font
style="font-size: 15px"
color="#666666">2</xhtml:font>
</xhtml:span>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="461"
y="85"
fill="#333333"
font-family="'Courier New'"
font-size="12px"
text-anchor="middle"
font-weight="bold"
id="text13">2</text>
</switch>
</g>
<rect
x="641"
y="71"
width="40"
height="20"
fill="none"
stroke="none"
pointer-events="all"
id="rect14" />
<g
transform="translate(-0.5,-0.5)"
id="g14">
<switch
id="switch14">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 81px; margin-left: 642px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 12px; font-family: Courier New; color: #333333; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:span>
<xhtml:font
style="font-size: 15px"
color="#666666">3</xhtml:font>
</xhtml:span>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="661"
y="85"
fill="#333333"
font-family="'Courier New'"
font-size="12px"
text-anchor="middle"
font-weight="bold"
id="text14">3</text>
</switch>
</g>
<rect
x="841"
y="71"
width="40"
height="20"
fill="none"
stroke="none"
pointer-events="all"
id="rect15" />
<g
transform="translate(-0.5,-0.5)"
id="g15">
<switch
id="switch15">
<foreignObject
style="overflow: visible; text-align: left;"
pointer-events="none"
width="100%"
height="100%"
requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility">
<xhtml:div
style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 38px; height: 1px; padding-top: 81px; margin-left: 842px;">
<xhtml:div
style="box-sizing: border-box; font-size: 0; text-align: center; ">
<xhtml:div
style="display: inline-block; font-size: 12px; font-family: Courier New; color: #333333; line-height: 1.2; pointer-events: all; font-weight: bold; white-space: normal; word-wrap: normal; ">
<xhtml:span>
<xhtml:font
style="font-size: 15px"
color="#666666">4</xhtml:font>
</xhtml:span>
</xhtml:div>
</xhtml:div>
</xhtml:div>
</foreignObject>
<text
x="861"
y="85"
fill="#333333"
font-family="'Courier New'"
font-size="12px"
text-anchor="middle"
font-weight="bold"
id="text15">4</text>
</switch>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

View File

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 9.5 KiB

View File

@ -0,0 +1,568 @@
---
title: Kconfig in RIOT
description: Using Kconfig to configure RIOT modules at compile-time
---
The objective of using Kconfig in RIOT is to configure software modules at
compile-time. This means having a standard way of:
- Exposing configurable parameters
- Assigning application and user-specific configurations
- Verifying these parameters
- Check possible values
- Check valid configuration considering inter-dependencies
- Applying the selected configuration
# Overview
## Exposure
Modules in RIOT expose their configurable parameters via
Kconfig files (for more information on Kconfig syntax check
[the specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html)).
In these files documentation, restrictions, default values and dependencies can
be expressed.
Kconfig files are structured through the file system mirroring the current
module distribution. In time, all modules will have Kconfig files to make
themselves configurable through this system.
## Assignment
The user can assign values to the exposed parameters, either by manually writing
'.config' files or using an interface such as Menuconfig. Parameters with no
assigned values will take the default ones. For a detailed distinction between
Kconfig and '.config' files see [Appendix B](#appendix-b-difference-between-kconfig-and-config-files).
## Verification and Application
Using '.config' and Kconfig files the build system takes care of doing the
necessary checks on the values according to the parameter definition. After
that, the `autoconf.h` header file is generated, it contains all the
configurations in the form of (`CONFIG_` prefixed) macros.
# User Guide to Configure with Kconfig
## Configure using menuconfig
In order to use the graphical interface menuconfig to configure the
application, run `make menuconfig` in the application's folder. All available
configurations (based on the used modules) for the particular platform will be
presented. By default, the configuration of a module via Kconfig is not enabled.
In order to activate the configuration via Kconfig, the corresponding option
should be selected. That will enable the configuration of all inner options, if
available.
Once the desired configuration is achieved, save the configuration to the
default proposed path and exit. The saved configuration will be applied when
the code is compiled (`make all`).
If the current configuration should be used in the future, it can be saved in the
application's folder as `user.config`, using the 'Save' option in menuconfig.
This way it will be persistent after cleaning the application directory
(`make clean`).
## Configure using '.config' Files
The second way to configure the application is by directly writing '.config'
files. Two files will be sources of configuration during the generation of the
final header file: `app.config` and `user.config`, which should be placed
inside the application's folder. `app.config` sets default configuration
values for the particular application, the user can override them by setting
them in `user.config`. Additionally, further `.config` files can be added to
the variable `KCONFIG_ADD_CONFIG`, which will be applied _after_ default CPU and
board configurations, `app.config` and `user.config`. This means that they will
have priority.
Let's say that the `SOCK_UTIL_SCHEME_MAXLEN` symbol in `sock_util` module needs
to be configured. The `user.config` file could look like:
```makefile
# activate configuration of sock_util using Kconfig
CONFIG_KCONFIG_MODULE_SOCK_UTIL=y
# change scheme part length
CONFIG_SOCK_UTIL_SCHEME_MAXLEN=24
```
In this case, there is no need for using menuconfig. It's enough just to call
`make all` in the application folder, as this configuration will be read and
applied. Note that if any dependency issue occurs, warnings will be generated
(e.g. not enabling the configuration of a module via Kconfig).
## Application Configuration with Kconfig
To expose application-specific configuration options a `Kconfig` file can
be placed in the application's folder. For an example of this you can check
the [tests/build_system/kconfig](https://github.com/RIOT-OS/RIOT/tree/master/tests/build_system/kconfig)
application.
## Configuration via Environment Variables
For easy debugging of configurations or testing new modules by compiling them
into existing applications, one can also use environment variables prefixed by
`RIOT_CONFIG_`. To achieve the same configuration exemplified in
[Configure using '.config' files](#configure-using-config-files), e.g., you could also use
```sh
RIOT_CONFIG_KCONFIG_MODULE_SOCK_UTIL=1 \
RIOT_CONFIG_SOCK_UTIL_SCHEME_MAXLEN=24 \
make
```
All the checks that apply for `.config` files also are done with this approach.
Mind that this is only meant to be used during development. In production,
please set the configuration via `.config` files.
## A Note on the Usage of CFLAGS
When a certain module is being configured via Kconfig, the configuration macro
will no longer be overridable by means of CFLAGS (e.g. set on the
compilation command or on a Makefile). Consider this if you are getting a
'redefined warning'.
---
# Integration into the Build System
The integration of Kconfig into the build system is mainly done in
`makefiles/kconfig.mk`.
## Steps during the Build Process
![Output of every step of the build process](img/kconfig_integration.svg)
### 0. Module Dependency Resolution
The resolution of module dependencies is performed by the build
system where all the used modules and packages end up listed in the `USEMODULE`
or `USEPKG` make variables.
#### Input
- Makefiles.
#### Output
- `USEMODULE` and `USEPKG` variables.
### 1. Module Listing
The list of modules needed for the particular build is dumped into the
`$ (GENERATED_DIR)/Kconfig.dep` file, where each module is translated into a
Kconfig symbol as documented in [Appendix A](#appendix-a-check-if-a-module-or-package-is-used).
#### Input
- `USEMODULE` and `USEPKG` variables
#### Output
- `$ (GENERATED_DIR)/Kconfig.dep` file
### 2. Merging all Configuration Sources
In this step configuration values are taken from multiple sources and merged
into a single `out.config` configuration file. This file is temporary and is
removed on cleanup. If the user needs to save a particular configuration
set, a backup has to be saved (this can be done using the menuconfig interface)
so it can be loaded later in this step.
To accomplish merging of multiple input files, the `genconfig` script is
used. Note that **the order matters**: existing configuration values are
merged in the order expressed in the input section, where the last value
assigned to a parameter has the highest priority. If no configuration files are
available, all default values will be applied.
`out.config` is the only configuration input for the `autoconf.h` in the
[generation step](#4-generation-of-the-autoconfh-header).
Additionally this step generates a file `out.config.d` which holds the
information of all the used Kconfig files in Makefile format. This file is
included by the build system and allows to re-trigger the generation of
`out.conf` whenever a Kconfig file is modified.
#### Input
- Optional:
- `$ (APPDIR)/app.config`: Application specific default configurations.
- `$ (APPDIR)/user.config`: Configurations saved by user.
#### Output
- `$ (GENERATED_DIR)/out.config` file.
### 3. Menuconfig Execution (optional)
Menuconfig is a graphical interface for software configuration. It is, for example, used for
the configuration of the Linux kernel. This section explains the process
that occurs when RIOT is being configured using the menuconfig interface.
The main `Kconfig` file is used in this step to show the configurable
parameters of the system. Kconfig will filter inapplicable parameters (i.e.
parameters exposed by modules that are not being used) based on the file
`$ (GENERATED_DIR)/Kconfig.dep` generated in step 1.
Note that if Kconfig is not used to configure a module, the corresponding
header files default values will be used.
`out.config` is one of the inputs for menuconfig. This means that any
configuration that the application defines in the `app.config` or a backup
configuration from the user in `user.config` are taken into account on the
first run (see [Appendix C](#appendix-c-pitfall-when-using-different-configuration-interfaces)).
In this step the user chooses configuration values (or selects the minimal
configuration) and saves it to the `out.config` file. Here the user can
choose to save a backup configuration file for later at a different location
(e.g. a `user.config` file in the application folder).
If any changes occur to `out.config`, the
[generation of autoconf.h](#4-generation-of-the-autoconfh-header) is executed automatically.
#### Input
- `/Kconfig` file.
- Optional:
- `$ (APPDIR)/app.config`
- `$ (APPDIR)/user.config`
- `$ (GENERATED_DIR)/out.config`
#### Output
- Updated `$ (GENERATED_DIR)/out.config` file.
- `$ (GENERATED_DIR)/out.config.old` backup file.
### 4. Generation of the autoconf.h Header
With the addition of Kconfig, a dependency has been added to the build
process: the `$ (GENERATED_DIR)/autoconf.h` header file. This header file is
the main output from the Kconfig configuration system. It holds all the macros
that should be used to configure modules in RIOT:
`CONFIG_<module>_<parameter>`.
In order to generate the `autoconf.h` file, the `genconfig` script is used.
Inputs for this script are the main `Kconfig` file and `out.config`
configuration file, which holds the selected values for the exposed parameters.
#### Input:
- `$ (GENERATED_DIR)/out.config` file.
- Main `Kconfig` file exposing configuration of modules.
#### Output:
- `$ (GENERATED_DIR)/autoconf.h` configuration header file.
- Optional:
- `$ (GENERATED_DIR)/deps/*/*.h` header files that allow incremental builds
### Summary of Files
These files are defined in `kconfig.mk`.
| File | Description |
| ---------------| ----------- |
| `Kconfig` | Defines configuration options of modules. |
| `Kconfig.dep` | Holds a list of the modules that are being compiled. |
| `app.config` | Holds default application configuration values. |
| `user.config` | Holds configuration values applied by the user. |
| `out.config` | Configuration file containing all the symbols defined in `autoconf.h`. |
| `out.config.d` | Dependency file of `out.config` containing the list of Kconfig files used to generate it. |
| `autoconf.h` | Header file containing the macros that applied the selected configuration. |
## Kconfig Symbols in Makefiles
As `.config` files have Makefile syntax, they can be included when building,
which allows to access the applied configuration from the build system.
During migration this is also useful, as it gives the ability to check whether a
parameter is being configured via Kconfig or a default value via `CFLAGS` could
be injected. For example:
```makefile
ifndef CONFIG_USB_VID
CFLAGS += -DCONFIG_USB_VID=0x1209
endif
```
Symbols will have the same name as the configuration macros (thus will always
have the `CONFIG_` prefix). As the configuration file is loaded in
`Makefile.include`, care should be taken when performing checks in the
application's Makefile. The symbols will not be defined until after including
`Makefile.include`.
---
# Transition Phase
## Making Configuration via Kconfig optional
During transition to the usage of Kconfig as the main configuration tool for
RIOT, the default behavior will be the traditional one: expose configuration
options in header files and use CFLAGS as inputs. To allow optional
configuration via Kconfig, a convention will be used when writing Kconfig files.
Modules should be contained in their own `menu` entries, this way the user
can choose to enable the configuration via Kconfig for an specific module.
These entries should define a dependency on the module they configure (see
[Appendix A](#appendix-a-check-if-a-module-or-package-is-used) to see how to
check if a module is being used).
The module configuration must be enabled via make dependency modelling.
## Modelling CPUs and Boards
CPUs and boards are being modelled in Kconfig. The following part is a guide on how to
organize and name the symbols.
### CPUs
The proposed hierarchy for the classification of CPUs is as follows:
```
+------------+
More Specific | CPU_MODEL |
+ +------------+
|
|
| +------------+
| | CPU_FAM |
| +------------+
|
|
| +------------+
| | CPU_CORE |
| +------------+
|
|
v +------------+
Less Specific | CPU_ARCH |
+------------+
```
Where each hierarchy is defined as:
- `CPU_MODEL`: The specific identifier of the used CPU, used for some CPU
implementations to differentiate between different memory
layouts.
- `CPU_FAM`: An intermediate identifier between CPU and CPU_MODEL that
represents a sub-group of a manufacturers CPUs.
- `CPU_CORE`: The specific identifier of the core present in the CPU.
- `CPU_ARCH`: The specific identifier of the architecture of the core defined
in `CPU_CORE`.
In order to model the hierarchies, a hidden boolean symbol must be declared for
each. The name of the symbol must begin with the correspondent prefix and must
be followed by the specific value. For instance, the 'samd21' family symbol is
named `CPU_FAM_SAMD21`.
In addition, a default value to the corresponding common symbol must be defined.
The default value must be guarded by the boolean symbol corresponding to the
hierarchy.
Features may be provided by any hierarchy symbol. Usually symbols are selected
from more specific to less specific. This means that a `CPU_MODEL_<model>`
symbol usually would select the corresponding `CPU_FAM_<family>` symbol,
which would in turn select the `CPU_CORE_<core>`. This may change in some cases
where `CPU_COMMON_` symbols are defined to avoid repetition. For convenience and
if it makes sense within a CPU vendor family, it's also allowed to use
intermediate grouping levels, like `CPU_LINE_<xxx>` used for STM32.
In addition to the symbols of the hierarchy described above, a default value
to the `CPU` symbol should be assigned, which will match the value of the `CPU`
Makefile variable in the build system.
The declaration of the symbols should be placed in a `Kconfig` file in the
folder that corresponds to the hierarchy. When the symbols are scattered into
multiple files, it is responsibility of file containing the most specific
symbols to `source` the less specific. Keep in mind that only the file located
in `/cpu/<CPU>/Kconfig` will be included by the root `/Kconfig` file.
#### Example
```
# This is the most specific symbol (selected by the board)
# The CPU model selects the family it belongs to
config CPU_MODEL_SAMR21G18A
bool
select CPU_FAM_SAMD21
# In this case the family selects a common 'sam0' symbol (which provides some
# features), and the core it has (cortex-m0+)
config CPU_FAM_SAMD21
bool
select CPU_COMMON_SAM0
select CPU_CORE_CORTEX_M0PLUS
# The value of the common value depends on the selected model
config CPU_MODEL
default "samd21e18a" if CPU_MODEL_SAMD21E18A
default "samd21g18a" if CPU_MODEL_SAMD21G18A
default "samd21j18a" if CPU_MODEL_SAMD21J18A
default "samr21e18a" if CPU_MODEL_SAMR21E18A
default "samr21g18a" if CPU_MODEL_SAMR21G18A
config CPU_FAM
default "samd21" if CPU_FAM_SAMD21
```
### Boards
Boards must be modelled as hidden boolean symbols with the prefix `BOARD_` which
default to `y` and are placed in `/boards/<BOARD>/Kconfig`. This file will be
`source`d from the main `/Kconfig` file. The board symbol must select the
`CPU_MODEL_<model>` symbol that corresponds to the CPU model present on the
board. The board symbol must also select the symbols that correspond to the
features it provides.
In the same `Kconfig` file a default value must be assigned to the
common `BOARD` symbol. It must be guarded by the board's symbol, so it only
applies in that case.
There are cases when grouping common code for multiple boards helps to avoid
unnecessary repetition. In the case features are provided in a common board
folder (e.g. `/boards/common/arduino-atmega`) a symbol should be declared to
model this in Kconfig. Symbols for common boards must have the `BOARD_COMMON_`
prefix, and must select the common provided features.
#### Example
The samr21-xpro has a `samr21g18a` CPU and provides multiple features. Its
symbol is modelled as following:
```
# /boards/samr21-xpro/Kconfig
config BOARD
default "samr21-xpro" if BOARD_SAMR21_XPRO
config BOARD_SAMR21_XPRO
bool
default y
select CPU_MODEL_SAMR21G18A
```
### Default Configurations
Boards, common board directories, CPUs and common CPU directories may need to
override default configuration values. Visible configuration symbols are
configurable by the user and show on the menuconfig interface. `.config` files
are used to set their values. To allow multiple sources of `.config` files,
there are two Makefile variables developers should use: `KCONFIG_CPU_CONFIG` for
sources added by the CPU or common CPU directories, and `KCONFIG_BOARD_CONFIG`
for sources added by the board or common board directories. This ensures the
correct priority of the configurations.
The `Makefile.features` infrastructure is used to populate the
configuration sources. As the order in which `.config` files are merged matters,
configuration sources should be ordered from more generic to more specific.
Because the board's `Makefile.features` is included before the CPU's `Makefile.features`
it is important to utilize two different lists of configuration sources. For
instance, if `cpu/cortexm_common` adds its configuration, `cpu/stm32` should add
its configuration after it, and `boards/stm32f769i-disco` after it.
```makefile
include $(RIOTCPU)/cortexm_common/Makefile.features
# Add stm32 configs after including cortexm_common so stm32 takes precedence
KCONFIG_CPU_CONFIG += $(RIOTCPU)/stm32/stm32.config
```
## Summary of Reserved Kconfig Prefixes
The following symbol prefixes have been assigned particular semantics and are
reserved for the cases described below:
<!-- Keep the table in alphabetical order -->
| Prefix | Description |
| :----- | :---------- |
| `BOARD_` | Models a board |
| `BOARD_COMMON_` | Used for common symbols used by multiple boards |
| `CPU_ARCH_` | Models a CPU architecture |
| `CPU_COMMON_` | Used for common symbols used by multiple CPUs |
| `CPU_CORE_` | Models a CPU core |
| `CPU_FAM_` | Models a family of CPUs |
| `CPU_MODEL_` | Models a particular model of CPU |
| `USEMODULE_` | Models a [RIOT module](https://doc.riot-os.org/creating-modules.html#creating-modules). Generated from `USEMODULE` variable |
| `USEPKG_` | Models an [external package](https://doc.riot-os.org/group__pkg.html). Generated from `USEPKG` variable |
---
# Appendices
## Appendix A: Check if a Module or Package is used
In order to show only the relevant configuration parameters to the user with
respect to a given application and board selection, Kconfig needs knowledge
about all modules and packages to be used for a compilation. The dependency
handling among modules is performed by the build system (via
`Makefile.dep` files). The interface defined to declare the used modules and
packages is the `$ (GENERATED_DIR)/Kconfig.dep` file.
There will be a symbol for every used module (i.e. every module in
`USEMODULE` make variable) and package. The names in the symbols will be
uppercase and separated by `_`. Based on these symbols, configurability is
decided.
The following is an example of how to use these symbols in Kconfig files to
configure compile-time configurations with `USEMODULE` dependencies:
```
menu "Configure Sock Utilities"
depends on USEMODULE_SOCK_UTIL
config SOCK_UTIL_SCHEME_MAXLEN
int "Maximum length of the scheme part for sock_urlsplit"
default 16
...
endmenu # Configure Sock Utilities
```
## Appendix B: Difference between 'Kconfig' and '.config' Files
Kconfig files describe a configuration database, which is a collection of
configuration options organized in a tree structure. Configuration options may
have dependencies (among other attributes), which are used to determine their
visibility.
Kconfig files are written in
[Kconfig language](https://www.kernel.org/doc/Documentation/kbuild/kconfig-language.txt)
defined in the Linux kernel. Configuration options have attributes such as
types, prompts and default values.
#### Kconfig File
```
menu "Buffer Sizes"
config GCOAP_PDU_BUF_SIZE
int "Request or response buffer size"
default 128
endmenu
```
On the other hand configuration files contain assignment of values to
configuration options and use Makefile syntax. They can also be used to save a
set of configuration values as backup.
#### '.config' File
```makefile
# enable Kconfig configuration for gcoap
CONFIG_KCONFIG_MODULE_GCOAP=y
# set the value
CONFIG_GCOAP_PDU_BUF_SIZE=12345
```
In other words: Kconfig files describe configuration options and '.config' files
assign their values.
## Appendix C: Pitfall when using Different Configuration Interfaces
In the current configuration flow the user can choose to configure RIOT using
the menuconfig graphical interface or writing '.config' files by hand.
As explained in the
['Configuration sources merging step'](#2-merging-all-configuration-sources)
of the configuration process, configuration from multiple sources are loaded to
create a single `out.config` file, and the order of merging matters: last
file has priority.
While editing values directly via '.config' files, `out.config` will be
re-built. The user can also use the menuconfig interface to modify the configuration
file (this is the recommended way, as it gives access to much more information
regarding dependencies and default values of the symbols). Menuconfig will
change `out.config` directly (a backup file `out.config.old` will be kept).
**It is recommended to save backups of the configurations, as any change on the
configuration sources would re-trigger the merging process and overwrite
`out.config`.**
## Appendix D: A few Key Aspects while Exposing a Macro to Kconfig
A macro that holds a 0 or 1 is modelled in Kconfig as a `bool` symbol. References to this macro
can then make use of IS_ACTIVE macro from kernel_defines.h with C conditionals
for conditional compilation.
[FXOS8700 driver exposure to Kconfig](https://github.com/RIOT-OS/RIOT/pull/13914)
can be considered as an example. If the macro is defined as `TRUE` by default,
a new symbol gets introduced to invert the semantics. The recommended
practice is to add a new symbol and expose it to Kconfig while the old one is
tagged to be deprecated. The process is documented in this
[commit](https://github.com/RIOT-OS/RIOT/pull/13129/commits/c7b6dc587cf20f3177abe0417a408b6ab90d0ff8)
There may be cases where a macro is expected to hold only specific values, e.g.
'GNRC_IPV6_MSG_QUEUE_SIZE' expressed as the power of two. These may be modelled
in such a way that a new macro is introduced to hold the restricted figures
while operators are added to arrive at the desired value. The process is
documented in this [pull request.](https://github.com/RIOT-OS/RIOT/pull/14086)
# Useful references
- [Kconfig language specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-language.html)
- [Kconfig macro language specification](https://www.kernel.org/doc/html/latest/kbuild/kconfig-macro-language.html)
- [Kconfig - Tips and Best Practices](https://docs.zephyrproject.org/latest/guides/kconfig/tips.html)

View File

@ -0,0 +1,76 @@
---
title: FAQ
description: Frequently Asked Questions about the RIOT Code of Conduct
---
This FAQ attempts to address common questions and concerns around the RIOT
community's [Code of Conduct](/general/code_of_conduct/).
If you still have questions after reading it,
please feel free to [contact us](mailto:riot@riot-os.org).
--------------------------------------------------------------------------------
### Why have you adopted a Code of Conduct?
If you're familiar with the RIOT
community, you'll probably notice that the Code basically matches what we
already do. Think of this as documentation: we're taking implicit expectations
about behavior and making them explicit.
We're doing this because the RIOT community is growing faster than any of us
could have anticipated. This is on balance a very positive thing, but as we've
grown past the point where it's possible to know the whole community we think
it's very important to be clear about our values.
We know that the RIOT community is open, friendly, and welcoming. We want to
make sure everyone else knows it too.
### What does it mean to "adopt" a Code of Conduct?
For the most part, we don't think it means large changes. We think that the text
does a really good job describing the way the RIOT community already conducts
itself. We expect that most people will simply continue to behave in the awesome
way they have for years.
However, we do expect that people will abide by the spirit and words of the CoC
when in "official" RIOT spaces. This code has been adopted by the RIOT community
as a whole. That means that it'll apply in all community spaces.
In practice, this means the [RIOT forum](https://forum.riot-os.org), the Matrix
chats (e.g., [`#riot-os`](https://matrix.to/#/#riot-os:matrix.org) or
[`#riot-os-off-topic`](https://matrix.to/#/#riot-os-off-topic:matrix.org)),
mailing lists (e.g., security@riot-os.org), bug tracking and code review tools,
and "official" RIOT events such as Hack'n'ACKs or RIOT summits. In addition,
violations of this code outside these spaces may affect a person's ability to
participate within them.
### What happens if someone violates the Code of Conduct?
Our intent is that anyone in the community can stand up for this code, and
direct people who're unaware to this document. If that doesn't work, or if you
need more help, you can contact <conduct@riot-os.org>. For more details please see
our [Reporting Guidelines](/general/code_of_conduct/reporting/).
### Why do we need a Code of Conduct? Everyone knows not to be a jerk.
Sadly, not everyone knows this.
However, even if everyone was kind, everyone was compassionate, and everyone was
familiar with codes of conduct it would still be incumbent upon our community to
publish our own. Maintaining a code of conduct forces us to consider and
articulate what kind of community we want to be, and serves as a constant
reminder to put our best foot forward. But most importantly, it serves as a
signpost to people looking to join our community that we feel these values are
important.
### This is censorship! I have the right to say whatever I want!
You do -- in *your* space. If you'd like to hang out in *our* spaces (as
clarified above), we have some simple guidelines to follow. If you want to, for
example, form a group where RIOT is discussed using language inappropriate for
general channels then nobody's stopping you. We respect your right to establish
whatever codes of conduct you want in the spaces that belong to you. Please
honor this Code of Conduct in our spaces.
#### References
This FAQ was adapted from the [Django Code of Conduct FAQ](https://www.djangoproject.com/conduct/faq/)

View File

@ -0,0 +1,82 @@
---
title: Reporting Guidelines
description: How to report violations of the RIOT Code of Conduct
---
If you believe someone is violating the [code of conduct](/general/code_of_conduct/)
we ask that you report it to us by emailing <conduct@riot-os.org>.
Currently, the recipients of
this email address are [\@OlegHahm](https://github.com/OlegHahm) (Oleg Hahm) and
[\@miri64](https://github.com/miri64) (Martine Lenders).
**All reports will be kept confidential.** In some cases we may determine that a
public statement will need to be made. If that's the case, the identities of all
victims and reporters will remain confidential unless those individuals instruct
us otherwise.
**If you believe anyone is in physical danger, please notify appropriate law
enforcement first.** If you are unsure what law enforcement agency is
appropriate, please include this in your report and we will attempt to notify
them.
If you are unsure whether the incident is a violation, or whether the space
where it happened is covered by this Code of Conduct, we encourage you to still
report it. We would much rather have a few extra reports where we decide to take
no action, rather than miss a report of an actual violation. We do not look
negatively on you if we find the incident is not a violation. And knowing about
incidents that are not violations, or happen outside our spaces, can also help
us to improve the Code of Conduct or the processes surrounding it.
In your report please include:
- Your contact info (so we can get in touch with you if we need to follow up)
- Names (real, nicknames, or pseudonyms) of any individuals involved. If there
were other witnesses besides you, please try to include them as well.
- When and where the incident occurred. Please be as specific as possible.
- Your account of what occurred. If there is a publicly available record (e.g.
forum post, a mailing list archive, or a public Matrix chat link) please include a link.
- Any extra context you believe existed for the incident.
- If you believe this incident is ongoing.
- Any other information you believe we should have.
### What happens after you file a report?
You will receive an email from one of the core community members as soon as
possible. We promise to acknowledge receipt within 24 hours (and will aim for
much quicker than that).
They will review the incident and determine:
- What happened.
- Whether this event constitutes a code of conduct violation.
- Who the bad actor was.
- Whether this is an ongoing situation, or if there is a threat to anyone's
physical safety.
If this is determined to be an ongoing incident or a threat to physical safety,
their immediate priority will be to protect everyone involved.
This means we may delay an "official" response until we believe that the
situation has ended and that everyone is physically safe.
Once the working group has a complete account of the events they will make a
decision as to how to response. Responses may include:
- Nothing (if we determine no violation occurred).
- A private reprimand from us to the individual(s) involved.
- A public reprimand.
- An imposed vacation (i.e. asking someone to "take a week off" from the forum,
the Matrix chats, or a mailing list).
- A permanent or temporary ban from some or all RIOT spaces (forum, Matrix chats, mailing lists,
etc.)
- A request for a public or private apology.
We'll respond within one week to the person who filed the report with either a
resolution or an explanation of why the situation is not yet resolved.
Once we've determined our final action, we'll contact the original reporter to
let them know what action (if any) we'll be taking. We'll take into account
feedback from the reporter on the appropriateness of our response, but we don't
guarantee we'll act on it.
#### Reference
These reporting guidelines were adapted from the [Django reporting guidelines](https://www.djangoproject.com/conduct/reporting/)

View File

@ -0,0 +1,149 @@
---
title: Hints for quicker & better RIOT development
description: Best practices and recommended tools for RIOT development
---
* Use the [methodology](#methodology-emulator-first-target-iot-hardware-last) described below.
* Use [`ccache`](/build-system/advanced_build_system_tricks/#speed-up-builds-with-ccache) to speedup compilation
## Coding "Dos" and "Don'ts"
### Dos
* Use static memory. See also [Static vs. Dynamic Memory](#static-vs-dynamic-memory).
* Select the priorities carefully.
* Minimize stack usage with `DEVELHELP` and `CREATE_STACKTEST`.
* Use threads to increase flexibility, modularity and robustness by leveraging IPC.
* Use unsigned or signed integer (`unsigned`, `int`, `size_t` or `ssize_t`) for loop variables wherever possible,
but keep in mind that on some platforms an `int` has a width of only 16-bit. In general, you should avoid types
like `uint8_t` for loop iterators as they will probably make it more expensive on some platforms.
* Join and factor out parts of the code with existing code in RIOT, where it makes sense.
* Check all `size/length` parameters when passing memory, e.g. using `sizeof(x)` or `strlen(x)` as appropriate.
Make sure you don't use the wrong one with a pointer.
* Make sure all code paths can be reached. Make sure there are no always `true/false` conditions.
* Make sure all critical sections (`lock/unlock`, `acquire/release`, ...) are always closed on every code path.
* Make sure return values are consistent with our API documentation.
* Use `assert()` statements to check parameters rather than returning an error code at run-time,
to keep the code size down.
* Use the `DEBUG(...)` macro rather than `log_x(...)`
* Declare all internal module variables and functions `static`
* Make sure variables are reduced in scope as much as possible
* Use an appropriate signedness in your variables
* Make sure the variables are big enough to prevent overflow. Be aware that the code may run on platforms with
different sizes of variables. For example, `int/unsigned` is only 16-bit on msp430 and avr8. If in doubt,
use portable types.
* Reduce the number of function calls as far as possible without duplicating code.
* Use good judgement when using `static inline` functions and macros. If they are used in multiple places,
is the increase in performance worth the penalty in code size?
* Use memory judiciously in general. For example:
```c
typedef enum {
A,
B,
...
} foo_t;
int bar(foo_t v)
{
int abc;
...
switch(v) {
case A:
abc = 23;
break;
case B:
abc = 42;
break;
...
}
...
}
/* VS */
typedef enum {
A = 23,
B = 42,
...
} foo_t;
int bar(foo_t v) {
int abc = v;
...
}
```
### Don'ts
* Don't use too many threads. Try not to use more than one thread per module. Don't create threads for one-time tasks.
* Don't use the POSIX wrapper if implementing something from scratch.
* Don't allocate big chunks of memory (for instance the IPC message queue) on the stack,
but use rather static memory for that.
* Don't over-provision memory.
* Don't pass stack memory between different contexts unless you can prove conclusively that it won't be a problem.
* Don't use enums for flags, because flags have a width in memory that is in most cases smaller than `sizeof(enum)`
(most bitfields are 16 bits max, on most of our newer platforms, `sizeof(enum)` is however 32 bits).
This results in every assignment needed to be cast to either `uint8_t` or `uint16_t`. With macros you don't need to
cast since they are typeless. Making the enum packed makes its width unpredictable in terms of alignment issues,
when used in struct.
* Don't duplicate code from elsewhere in the RIOT code base, unless there is a very good reason to do so.
* Don't duplicate code within your own code, unless there is a very good reason to do so.
Use internal functions to this end.
* Don't mix up logical and bitwise operations (`!` vs `~`, or `&&` vs `&`)
## Methodology: emulator first, target IoT hardware last!
The below methodology is recommended, using well-known de facto standard tools from the FLOSS community that are
compatible with RIOT. Using the below workflow improves time-to-running-code compared to typical IoT software
workflows (which can be as retro as "LED-driven" debugging).
0. For newbies, preliminaries are typically faster with the provisioned virtual environment setup, e.g. with **Vagrant**.
1. To check your code, first use available **static analysis** as much as possible initially, which means
(i) enable all compiler warnings and fix all problems found, then (ii) use a supported linter such as **cppcheck**
to find bad coding patterns (i.e. code smells) and identify misuse of standard APIs.
2. Next, use available **dynamic analysis** tools to find further defects while running the code on **RIOT native**,
which means (i) running unit tests and integration tests on RIOT native emulator, and (ii) using **Valgrind** memcheck,
as well as the **GCC stack smashing detection**, to detect and avoid undefined behavior due to invalid memory access.
3. In case of networked applications or protocols, test **several instances of native** communicating via a virtual
network mimicking the targeted scenario, which means (i) either using the default virtual full-mesh or other
topologies configured via DESvirt, and (ii) using **Wireshark** to capture and analyze virtual network traffic,
e.g. to ensure protocol packets are syntactically correct, and to observe network communication patterns.
4. In case of incorrect behavior at this stage, analyze the system state for semantic errors on native using the
standard debugger **gdb**, which allows virtually unlimited conditional breakpoints, record and replay,
catchpoints, tracepoints and watchpoints.
5. In case of suspected performance bottleneck, use performance profilers **gprof**, or else cachegrind,
to identify precisely the bottlenecks.
6. At this stage the implementation has proven bug-free on the native emulator. One can thus finally move on to
hardware-in-the-loop, which means (i) flashing the binary on the targeted IoT hardware, typically using
standard flasher **OpenOCD** or **edbg**, and (ii) using the **RIOT shell** running on the target IoT device(s)
for easier debugging on the target hardware.
7. In case the hardware is not available on-site, one can consider remotely flashing and testing the binary on
supported open-access testbeds, e.g. [IoT-LAB](https://www.iot-lab.info) hardware is fully supported by RIOT.
8. In case of failure, after analyzing the failure and attempting to fix the defect, go back to step 1 to make sure
the fix did not itself introduce a new defect.
## Static vs. Dynamic Memory
In your C program you have to decide where the memory you want to use comes from.
There are two ways to get memory in your C code:
1. Define static memory.
2. Use dynamic memory (call `malloc()`/`free()` to get memory from the heap).
Both ways have some drawbacks which are listed here.
If you want to analyze the static memory consumption of your code you can use
[otm](https://github.com/LudwigOrtmann/otm) or `make cosy`.
### Static memory
* Access the memory in one operation O(1) ⇒ real time condition
* Programmer needs to know the amount of memory on compile time
* Leads to over and undersized buffers
* Forces the programmer to think about the amount of need memory at compile time
### Dynamic memory
* `malloc()` and `free()` are implemented in your `libc` (RIOT on ARM: `newlib`/`picolib`)
* Runtime behavior is not predictable
* Code can request the amount of memory it needs on runtime
* On most platforms: the size of the heap is `sizeof(<RAM>)-sizeof(<static memory>)`
* If you reduce your usage of static memory your heap gets bigger
* Programmer needs to handle failed memory allocation calls at runtime
* Static code analysis is unable to find errors regarding memory management

View File

@ -0,0 +1,155 @@
---
title: Emulators
description: Overview of emulators supported in RIOT-OS
---
RIOT supports the [Qemu](https://www.qemu.org/) and [Renode](https://renode.io/)
emulation tools. The emulation offers a hardware-free development environment
for quickly testing applications.
From the build system point of view, the emulation support in RIOT is
transparent compared to the usual workflow: simply add `EMULATE=1` to the
command line and the emulator supported by the board will be called instead of
the board flashing/debugging tool.
Targets compatible with `EMULATE=1` are `term`, `cleanterm`, `debug`,
`debugserver` and `test`.
If a board supports multiple emulators, the emulator backend can be selected
with the `RIOT_EMULATOR` variable. Possible values are `qemu` and `renode`.
If no emulator is specified by the board configuration (e.g. in its
`Makefile.include`), the default emulator is `renode`.
The boards with emulator supported can be listed using the
`info-emulated-boards` target:
```shell
$ make info-emulated-boards
```
## Features
Be aware that not all hardware features provided by a board - and described as
such in the build system by `FEATURES_PROVIDED` - are implemented in emulators.
For example, the `hifive1b` provides the RTC peripheral feature but this is not
implemented by the renode driver.
So you may expect some failures when running advanced applications on the
emulator.
## Usage
All emulators can be used the same way. Just add `EMULATE=1` to the command
line.
To start an emulator and connect to the serial port of the emulated board, run:
```shell
$ EMULATE=1 make BOARD=<board> -C <application directory> all term
```
To start an emulator with a GDB server and connect a GDB client to it, run:
```shell
$ EMULATE=1 make BOARD=<board> -C <application directory> all debug
```
To start an automatic test script with the emulated board, run:
```shell
$ EMULATE=1 make BOARD=<board> -C <test application directory> all test
```
The `EMULATOR_SERIAL_PORT` variable can be used to specify a custom serial port
on the host running the emulator.
The default value is built based on a random temporary directory:
`$(EMULATOR_TMP_DIR)/uart`.
The randomness of this variable allows several emulated sessions of the same
application with the same board to run in parallel.
# Qemu
## Overview
[Qemu](https://www.qemu.org/) is a machine emulator and virtualizer. It can
be used to emulate regular computer architectures but also some microcontroller
based boards such as the [BBC micro:bit](https://doc.riot-os.org/group__boards__microbit.html).
## Installation
Qemu is usually available via the package manager of common Linux distributions.
Depending on your local system, the installation procedure is described on the
[qemu website](https://www.qemu.org/download/).
## Boards supported
So far, in RIOT, only the
[BBC micro:bit](https://doc.riot-os.org/group__boards__microbit.html)
board is supported with qemu.
## Configuration
The QEMU emulated serial port is exposed on a local Unix socket, redirected to a
local PTY file (using [socat](http://www.dest-unreach.org/socat/)). This makes
it possible to open the PTY file in a regular serial port.
# Renode
## Overview
[Renode](http://renode.io) is a virtual development tool for multinode embedded
networks (both wired and wireless) enabling a scalable workflow for building
effective, tested and secure IoT systems, created by
Antmicro](http://antmicro.com/blog/2017/08/renode-press-release/).
It can easily be used to run applications on a broad range of embedded platforms
without any changes in the code itself, as if you were running on real
hardware - but with more possibilities.
## Installation
### From package
Packages for macOS, deb-based and rpm-based systems, for Windows and for Arch
Linux are available on [GitHub](https://github.com/renode/renode/releases/latest).
### From Source
Follow the installation instructions on Renode's
[GitHub](https://github.com/renode/renode#installation) page.
If you choose to build renode from source, after the compilation is successful,
ensure that `renode` is available on your `PATH`.
One way to do so, is via symlink:
```shell
sudo ln -s path/to/renode/repository/renode /usr/local/bin/renode
```
### Testing
After installation, verify that Renode is working using `renode --help`. You
should be presented with a help screen.
## Documentation
Documentation for Renode can be found on [Read The Docs](https://renode.readthedocs.io).
## Usage
From within RIOT-OS, add `EMULATE=1` to start the emulation. The emulation
expects a board definition file in `boards/<BOARD>/dist/board.resc`.
The board definition file will tell Renode how to setup an emulation session.
The application binary file (`*.elf`) is available using the variable
`$image_file`.
For an example, refer to `boards/cc2538dk/dist/board.resc`.
The renode logging level can be configured from the command line using the
following variables:
- `RENODE_SHOW_LOG`: set it to 1 to show the logs in the standard output
- `RENODE_LOG_LEVEL`: set it to the desired log level, default is 2 (warning)
The renode monitor and serial console GUI windows are hidden by default but
they can be displayed by setting `RENODE_SHOW_GUI` to 1 in the command line.
If uart0 is not the default serial port used for stdio, use `RENODE_SYSBUS_UART`
to specify a custom one in the board `Makefile.include`.

View File

@ -0,0 +1,172 @@
---
title: IO-Mapping and Shields
description: How to use Arduino compatible pin mappings and shields in RIOT-OS
---
## Introduction
Arduino has popularized the concept of adding an abstraction layer over the
MCU GPIOs and ADC multiplexer as "Digital Pins" and "Analog Pins". For historic
reasons as well as to express appreciation for the introduction of concept, we
prefix features and macros that map board pins to MCU pins with `ARDUINO`.
:::note
This means, we also explicitly use the Arduino feature for boards that
are neither official Arduino products nor compatible.
:::
## I/O Mappings
All I/O mappings are provided by the `arduino_iomap.h` header file. This is
provided either by the board directly (e.g. in
`<RIOT git repo>/board/<board>/include/arduino_iomap.h`) or by the board
family (e.g. in `board/common/<board family>/include/arduino_iomap.h`).
To add support to new boards, start by copy-pasting the `arduino_iomap.h` from
an existing board and adapt/extend the macros as needed. Finally, add the
features to the `Makefile.features` and `KConfig` files of the board that
indicate the presence of the added mappings.
### Digital Pins
The feature `arduino_pins` is provided by boards that do have a mapping to
digital pins. The GPIO for e.g. `D3` is provided as `ARDUINO_PIN_3`. The
number of the highest digital pin is provided as `ARDUINO_PIN_LAST`. E.g. if
`ARDUINO_PIN_LAST` is 42, digital pins `D0` to `D42` are typically provided.
:::warn
Some boards do have "gaps" in the pin mapping. It could be that
e.g. `ARDUINO_PIN_5` is defined, but `ARDUINO_PIN_4` is not.
:::
:::note
Often aliases are provided for analog pins in digital mode. E.g.
to use the pin `A3` as digital pin, `ARDUINO_PIN_A3` can be used
to avoid looking up what digital number that pin has.
:::
### Analog Pins
The feature `arduino_analog` is provided by boards that do have a mapping of
ADC lines to analog pins. E.g. the ADC line corresponding to pin `A5` would
be `ARDUINO_A5`. The number of the highest analog pin is provided as
`ARDUINO_ANALOG_PIN_LAST`. The macro `ARDUINO_ANALOG_PIN_LAST` is defined if
and only if a mapping is provided (so it can be used to test for this feature).
:::warn
Some boards do have "gaps" in the analog pin mapping. It could be
that e.g. `ARDUINO_A3` is defined, but `ARDUINO_A2` is not.
:::
### DAC Pins
The feature `arduino_dac` is provided by boards that do have a mapping of
DAC pins to DAC lines. E.g. the DAC line for the pin DAC1 would be
`ARDUINO_DAC1`. The number of the highest DAC pin is provided as
`ARDUINO_DAC_PIN_LAST`. The macro `ARDUINO_DAC_PIN_LAST` is defined if
and only if a mapping is provided (so it can be used to test for this feature).
:::warn
Some boards do have "gaps" in the analog pin mapping. It could be
that e.g. `ARDUINO_DAC4` is defined, but `ARDUINO_DAC3` is not.
:::
### PWM Pins
The feature `arduino_pwm` is provided by boards that do have a mapping of
digital pins to PWM settings. E.g. the PWM device connected to the digital pin
`D11` would be `ARDUINO_PIN_11_PWM_DEV` and the channel would be
`ARDUINO_PIN_11_PWM_CHAN`. A PWM frequency for all PWM pins is defined as
`ARDUINO_PWM_FREQU`.
:::warn
Typically only few digital pins support PWM. For pins without PWM
output, no `ARDUINO_PIN_<NUM>_PWM_DEV` macro and no
`ARDUINO_PIN_<NUM>_PWM_DEV` is defined.
:::
### UART Device
The feature `arduino_uart` is provided by boards that do provide an UART device
mapping. For the official Arduino boards and compatible boards, the
`ARDUINO_UART_D0D1` macro refers to the UART device that uses the digital pins
`D0` and `D1`.
Please extend the table below to keep naming among boards of the same form
factor consistent:
| Form Factor | Macro Name | Description |
|:---------------- |:--------------------- |:--------------------------------- |
| Arduino Nano | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Arduino Uno | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Arduino Mega | `ARDUINO_UART_D0D1` | UART on D0 (RXD) and D1 (TXD) |
| Seeedstudio XIAO | `ARDUINO_UART_DEV` | UART on D7 (RXD) and D6 (TXD) |
### I²C Buses
The feature `arduino_i2c` is provided by boards that do provide an I²C bus
mapping.
| Form Factor | Macro Name | Description |
|:---------------- |:--------------------- |:--------------------------------- |
| Arduino Nano | `ARDUINO_I2C_NANO` | D18 (SDA) / D19 (SCL) |
| Arduino Uno | `ARDUINO_I2C_UNO` | D18 (SDA) / D19 (SCL) |
| Arduino Mega | `ARDUINO_I2C_UNO` | D20 (SDA) / D21 (SCL) |
| Arduino Zero | `ARDUINO_I2C_UNO` | D20 (SDA) / D21 (SCL) |
| Arduino Due | `ARDUINO_I2C_UNO` | D70 (SDA) / D71 (SCL) |
| Seeedstudio XIAO | `ARDUINO_I2C_DEV` | D4 (SDA) / D5 (SCL) |
The `ARDUINO_I2C_UNO` refers to the I²C bus next to the AREF pin (the topmost
pins on header on the top right) of an Arduino Uno compatible board, e.g.
such as the Arduino Mega2560. Even though the Arduino UNO, the Arduino MEGA2560,
the Arduino Zero and the Arduino Zero all having the I²C bus at the exact same
mechanical positions, the digital pin number of the I²C bus next to the AREF
differs between the versions.
### SPI Buses
The feature `arduino_spi` is provided by boards that do provide an SPI bus
mapping.
| Form Factor | Macro Name | Description |
|:---------------- |:------------------------- |:------------------------------------- |
| Arduino Nano | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Nano | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Arduino Uno | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Uno | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Arduino Mega | `ARDUINO_SPI_ISP` | The SPI on the ISP header |
| Arduino Mega | `ARDUINO_SPI_D11D12D13` | D11 (MOSI) / D12 (MISO) / D13 (SCK) |
| Seeedstudio XIAO | `ARDUINO_SPI_DEV` | D10 (MOSI) / D9 (MISO) / D8 (SCK) |
:::note
The original AVR based Arduinos only have a single hard SPI bus which
is only provided via the ISP header. Many modern Arduino compatible
boards do not provide the ISP header and only have SPI on D11/D12/D13
provided.
:::
## Mechanical and Electrical Compatibility
Modules implementing drivers for extension boards, a.k.a. shields, can express
their mechanical and electrical requirements by depending on `arduino_shield_...`
features. The following list of features currently exists:
| Feature Name | Compatibility Claim |
|:--------------------- |:------------------------------------------------------------- |
| `arduino_shield_nano` | Board has side headers compatible with the Arduino Nano |
| `arduino_shield_uno` | Board has side headers compatible with the Arduino UNO |
| `arduino_shield_mega` | Board has side headers compatible with the Arduino MEGA |
| `feather_shield` | Board has headers compatible with the Adafruit Feather boards |
| `xiao_shield` | Board has headers compatible with the Seeedstudio XIAO boards |
:::note
A board providing `arduino_shield_mega` **MUST** also provide
`arduino_shield_uno`, as Arduino MEGA boards are backward compatible to
shields for the Arduino UNO.
:::
E.g. a module that implements the W5100 based Ethernet shield would depend on
both `arduino_shield_uno` and `arduino_shield_isp` for electrical compatibility
as well as on `arduino_spi` for SPI bus mapping and `arduino_pins` for the CS
pin mapping. This module could reuse the existing `w5100` driver and just
supply the correct `w5100_params_t` using the I/O mappings.

139
doc/guides/misc/roadmap.md Normal file
View File

@ -0,0 +1,139 @@
---
title: Roadmap
description: Overview of priority areas of RIOT development & enhancements
---
The aim of the roadmap is to identify priority areas of RIOT development and enhancements.
For each area, some near-future plans and concrete next steps are indicated.
The text and items below are tentative, up for discussion, to be updated by regular pull requests.
# Network Stack High Layers
(contact/steering: [Martine](https://github.com/miri64))
- ICN stack support clean-up
- discuss mid- and long-term plans for network stack maintenance & development (GNRC vs other supported stacks)
- revisit network time synchronization
- Provide a border router into 6LoWPANs (a 6LBR) that works out of the box in common scenarios:
- [x] in IPv6 networks with working Prefix Delegation (PD)
- [ ] in IPv6 networks without working Prefix Delegation (eg. by means of ND Proxying) <!-- 6man-variable-slaac also sounds nice but is at best a step between PD and just-a-single-v6-address -->
- [ ] in legacy networks (eg. by means of tunneling)
- [ ] with configurable on-by-default fallbacks
# Network Stack Low Layers
(contact/steering: [Peter](https://github.com/PeterKietzmann))
- Point-to-Point Protocol (PPP): finalize and merge `gnrc_ppp`
# Integrations
(contact/steering: [Teufelchen](https://github.com/teufelchen1))
- [Home-Assistant](https://www.home-assistant.io/) BTHome integration
- [Home-Assistant](https://www.home-assistant.io/) integration via [MQTT Discovery](https://www.home-assistant.io/integrations/mqtt#mqtt-discovery)
# Power Modes
(contact/steering: [benpicco](https://github.com/benpicco))
- concept to fix shell usage issue while LPM activated
- integrate generic power management functions in device driver APIs (netdev, SAUL, ...)
- more advanced LPM concepts:
- sleeping for short periods (in cases where it is not feasible to switch to the idle thread and back) -> mitigate active waiting
# Peripheral Drivers
(contact/steering: [maribu](https://github.com/maribu))
## Timers
(contact/steering: [kaspar030](https://github.com/kaspar030), [benpicco](https://github.com/benpicco), [maribu](https://github.com/maribu))
- cleanup and unification of low-level timer interfaces (`timer`, `rtt`, `rtc`)
- implement capture mode
## SPI
- introduction of `spi_slave` interface
- transition to `spi_clk_t` being the frequency in Hz, not an `enum` constant, to allow arbitrary frequencies
- most implementations have been ported
- allow a way to detect the actual frequency an SPI bus is running at
- see https://github.com/RIOT-OS/RIOT/pull/16727 for one proposal
## I2C
- introduction of `i2c_slave` interface
- see https://github.com/RIOT-OS/RIOT/issues/19560 for a discussion
## GPIO
(contact/steering: [gschorcht](https://github.com/gschorcht), [maribu](https://github.com/maribu))
- add a port-based, feature-rich, thread-safe GPIO API
- [GPIO LL](https://doc.riot-os.org/group__drivers__periph__gpio__ll.html) seems to fit the bill so for
- many MCUs still need an implementation
- add a high level API that unifies external and internal GPIOs on top
## ADC
(contact/steering: [benpicco](https://github.com/benpicco), [kfessel](https://github.com/kfessel), [gschorcht](https://github.com/gschorcht), [maribu](https://github.com/maribu))
- extend / replace the ADC API to allow advanced use cases
- selecting reference voltages (think: multimeter app)
- differential inputs
- fast (ideally DMA supported) sampling (think: a digital oscilloscope app)
- unify external and internal ADCs
- see https://github.com/RIOT-OS/RIOT/pull/13247 for one proposal
# Software Updates
(contact/steering: [Emmanuel](https://github.com/emmanuelsearch))
- Modularize to provide toolbox supporting other image storing (e.g. support external flash), transport (other than CoAP), crypto (e.g. secure element).
- riotboot support for architectures other than Cortex-M
# Documentation
(contact/steering: [Emmanuel](https://github.com/emmanuelsearch))
- Write and publish more RDMs
# Low-Level Hardware Support
(contact/steering: [Alex](https://github.com/aabadie))
- radio support for TI SensorTag
- radio support for Silab Thunderboard
# Testing
(contact/steering: [Kaspar](https://github.com/kaspar030))
- automated network functionality tests (e.g. RPL + UDP/PING tests through border router, multi-hop) in IoTLAB dev sites?
# Security
(contact/steering: [Kaspar](https://github.com/kaspar030))
- RNG unified (secure, or basic), seeding
- RIOT default configuration = secure configuration (that's our goal/motto)
## 802.15.4 Link Layer Security
(contact/steering: [chrysn](https://github.com/chrysn))
Current status: RIOT supports application provided keys,
with no guidance on how to (and no practical ways to) use that securely
(see [CVE-2021-41061](https://nvd.nist.gov/vuln/detail/CVE-2021-41061)).
Goal: Usably secure defaults.
- Figure out applicability of [RFC9031](https://www.rfc-editor.org/rfc/rfc9031) ("CoJP") to non-6TiSCH scenarios.
- Implement RFC9031 with any extensions needed for the MACs RIOT has.
- Provide tools to set up a recommended JRC, and to provision keys between it and the device at flash time.
This may entail extensions to the build process, as CoJP requires per-device secrets.

View File

@ -0,0 +1,55 @@
---
title: Terminal programs configuration
description: How to configure popular terminal programs for correct display of newlines
---
## Background
This page explains how to configure some popular terminal programs for correct
display of newlines when using the serial interface of a RIOT powered device.
When printing something using *stdio* (e.g., `printf("Hello World!\n");`, RIOT
sends a line feed character (`0xA`) as `\n` (newline).
Some terminals need more, for example, a carriage return and a line feed
character (0x0D, 0x0A). See https://en.wikipedia.org/wiki/Newline for background.
This page tries to collect the necessary settings for common terminal programs
that will make them correctly display newlines.
## gtkterm
- Graphical method:
- Open the configuration menu.
- Click on ***CR LF auto***.
- Manual method:
- Edit the file `~/.gtktermrc`.
- Change value of ***crlfauto*** option to `True`.
## minicom
- Interactive method:
- Press ***Ctrl+A u***.
- Manual method:
- Edit the configuration file (`~/.minirc.dfl` per default).
- Add the following line:
`pu addcarreturn Yes`
## miniterm
- Generic method:
- Start with `--eol CR` parameter.
- Via RIOT build system:
- `RIOT_TERMINAL=miniterm make term`
## picocom
- Generic method:
- Start with `--imap lfcrlf` parameter.
- Via RIOT build system:
- `RIOT_TERMINAL=picocom make term`
## putty
- Graphical method:
- Go to configuration tree and choose `Terminal` branch.
- Enable option `Implicit CR in every LF`.

View File

@ -56,6 +56,15 @@ export default defineConfig({
},
],
},
{
label: "Code of Conduct",
collapsed: true,
items: [
"general/code_of_conduct",
"general/code_of_conduct/faq",
"general/code_of_conduct/reporting",
],
},
{
label: "RIOT in a Nutshell",
items: [
@ -63,7 +72,6 @@ export default defineConfig({
"general/structure",
"general/vision",
"general/governance",
"general/code_of_conduct",
],
},
{
@ -98,6 +106,15 @@ export default defineConfig({
"rust_tutorials/create_project",
],
},
{
label: "Advanced",
items: [
"advanced_tutorials/creating_application",
"advanced_tutorials/creating_modules",
"advanced_tutorials/device_drivers",
"advanced_tutorials/porting_boards",
],
},
],
},
{
@ -105,13 +122,24 @@ export default defineConfig({
items: [
"build-system/build_system",
"build-system/build_system_basics",
"build-system/kconfig",
"build-system/flashing",
"build-system/build-in-docker",
"build-system/advanced_build_system_tricks",
"build-system/debugging_aids",
],
},
{
label: "Miscellaneous",
items: ["misc/release_cycle", "misc/how_to_doc"],
items: [
"misc/dev_best_practices",
"misc/io_mapping_and_shields",
"misc/roadmap",
"misc/release_cycle",
"misc/emulators",
"misc/terminal_config",
"misc/how_to_doc",
],
},
],
customCss: ["./src/styles/custom.css", "./src/fonts/font-face.css"],

View File

@ -79,8 +79,8 @@
* if one is working on new packages that aren't ready to be committed to
* upstream or if an application needs its own unique packages. For this, one
* can use the `EXTERNAL_PKG_DIRS` make variable. It works similar to the way
* [external modules](@ref modules-outside-of-riotbase) are
* handled. In your application's Makefile, in addition to adding the package
* [external modules](https://guide.riot-os.org/advanced_tutorials/creating_modules/#modules-outside-of-riotbase)
* are handled. In your application's Makefile, in addition to adding the package
* name to `USEPKG` as shown above, add the path to a folder that contains your
* external packages:
*

View File

@ -13,8 +13,8 @@
*
* How To Use
* ----------
* First you need to @ref including-modules "include" a module that implements
* this API in your application's Makefile.
* First you need to [include][include-link]
* a module that implements this API in your application's Makefile.
*
* The `sock_tls` module requires the `wolfssl` package.
*
@ -107,8 +107,8 @@
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple DTLS echo server. It is important to at least include
* @ref including-modules "include" the IPv6 module of your networking
* Above you see a simple DTLS echo server. It is important to at least
* [include][include-link] the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
* one network device.
* A separate file should define the buffers used as certificate and private key,
@ -218,6 +218,7 @@
* return 0;
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* [include-link]: https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules
*/
#include <string.h>

View File

@ -93,10 +93,14 @@
* the standard C++ lib (feature `libstdcpp`) is not required.
*
* As a minimum requirement, the features `arduino_pins` is a hard dependency.
* See @ref iomaps-mapping-gpio what a board needs to provide this.
* See [Digital Pins](https://guide.riot-os.org/misc/io_mapping_and_shields/#digital-pins
* what a board needs to provide this.
*
* Additional mappings for analog pins (see @ref iomaps-mapping-adc) and PWM
* pins (see @ref iomaps-mapping-pwm) is required to be able to use
* Additional mappings for analog pins
* (see [Analog Pins](https://guide.riot-os.org/misc/io_mapping_and_shields/#analog-pins))
* and PWM pins
* (see [PWM Pins](https://guide.riot-os.org/misc/io_mapping_and_shields/#pwm-pins))
* is required to be able to use
* `analogRead()` and `analogWrite()`.
*
* See also @ref iomaps on how a board can provide more I/O mappings and even

View File

@ -19,7 +19,7 @@
* How To Use
* ----------
*
* You need to [include](@ref including-modules) at least one module that
* You need to [include][include-link] at least one module that
* implements a [`sock` API](@ref net_sock) (e.g. `gnrc_sock_udp` and
* `gnrc_sock_async` for the [GNRC](@ref net_gnrc) implementation using UDP) and
* the module `sock_async_event` in your application's Makefile.
@ -82,7 +82,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple UDP echo server using @ref sys_event. Don't forget to
* also @ref including-modules "include" the IPv6 module of your networking
* also [include][include-link] the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
* one network device.
*
@ -159,6 +159,8 @@
* event_loop(&queue);
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* [include-link]: https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules
*
* @{
*
* @file

View File

@ -55,7 +55,9 @@
*
* ## Makefile Includes
*
* First, we need to [include](@ref including-modules) a module that implements
* First, we need to
* [include](https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules)
* a module that implements
* this API in our applications Makefile. For example the module that
* implements this API for [tinydtls](@ref pkg_tinydtls) is called
* `tinydtls_sock_dtls'.

View File

@ -18,7 +18,7 @@
*
* How To Use
* ----------
* First you need to @ref including-modules "include" a module that implements
* First you need to [include][include-link] a module that implements
* this API in your application's Makefile. For example the implementation for
* @ref net_gnrc "GNRC" is called `gnrc_sock_ip`.
*
@ -60,7 +60,8 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple IPv6 server. Don't forget to also
* @ref including-modules "include" the IPv6 module of your networking
* [include][include-link]
* the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc "GNRC") and at
* least one network device.
*
@ -195,7 +196,7 @@
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Again: Don't forget to also @ref including-modules "include" the IPv6 module
* Again: Don't forget to also [include][include-link] the IPv6 module
* of your networking implementation (e.g. `gnrc_ipv6_default` for
* @ref net_gnrc "GNRC") and at least one network device.
*
@ -255,6 +256,8 @@
* Finally, we wait a second before sending out the next "Hello!" with
* `xtimer_sleep(1)`.
*
* [include-link]: https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules
*
* @{
*
* @file

View File

@ -18,7 +18,7 @@
*
* How To Use
* ----------
* First you need to @ref including-modules "include" a module that implements
* First you need to [include][include-link] a module that implements
* this API in your application's Makefile. For example the implementation for
* @ref net_gnrc "GNRC" is called `gnrc_sock_tcp`.
*
@ -84,7 +84,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple TCP echo server. Don't forget to also
* @ref including-modules "include" the IPv6 module of your networking
* [include][include-link] the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
* one network device.
*
@ -233,7 +233,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple TCP echo client. Again: Don't forget to also
* @ref including-modules "include" the IPv6 module of your networking
* [include][include-link] the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc "GNRC") and at
* least one network device. Ad0)ditionally, for the IPv6 address parsing you need
* the @ref net_ipv6_addr "IPv6 address module".
@ -286,6 +286,8 @@
* return res;
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* [include-link]: https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules
*
* @{
*
* @file

View File

@ -18,7 +18,7 @@
*
* How To Use
* ----------
* First you need to @ref including-modules "include" a module that implements
* First you need to [include][include-link] a module that implements
* this API in your application's Makefile. For example the implementation for
* @ref net_gnrc "GNRC" is called `gnrc_sock_udp`.
*
@ -61,7 +61,7 @@
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Above you see a simple UDP echo server. Don't forget to also
* @ref including-modules "include" the IPv6 module of your networking
* [include][include-link] the IPv6 module of your networking
* implementation (e.g. `gnrc_ipv6_default` for @ref net_gnrc GNRC) and at least
* one network device.
*
@ -193,7 +193,7 @@
* }
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* Again: Don't forget to also @ref including-modules "include" the IPv6 module
* Again: Don't forget to also [include][include-link] the IPv6 module
* of your networking implementation (e.g. `gnrc_ipv6_default` for
* @ref net_gnrc "GNRC") and at least one network device.
*
@ -255,6 +255,8 @@
* Finally, we wait a second before sending out the next "Hello!" with
* `xtimer_sleep(1)`.
*
* [include-link]: https://guide.riot-os.org/advanced_tutorials/creating_application/#including-modules
*
* @{
*
* @file