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:
commit
bd93e286a7
@ -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. It’s 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 we’re 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 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
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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/)
|
||||
|
||||
@ -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/)
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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}
|
||||
----------------------
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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}
|
||||
|
||||

|
||||
|
||||
### 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 |
@ -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.
|
||||
|
||||
@ -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/).
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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/).
|
||||
|
||||
@ -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/).
|
||||
|
||||
@ -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.
|
||||
|
||||
293
doc/guides/advanced_tutorials/creating_application.md
Normal file
293
doc/guides/advanced_tutorials/creating_application.md
Normal 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
|
||||
```
|
||||
201
doc/guides/advanced_tutorials/creating_modules.md
Normal file
201
doc/guides/advanced_tutorials/creating_modules.md
Normal 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`.
|
||||
501
doc/guides/advanced_tutorials/device_drivers.md
Normal file
501
doc/guides/advanced_tutorials/device_drivers.md
Normal 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...
|
||||
199
doc/guides/advanced_tutorials/img/porting-boards.svg
Normal file
199
doc/guides/advanced_tutorials/img/porting-boards.svg
Normal 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->IfCPU -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>Start->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->IfBoard -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>IfCPU->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->PortCPU -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>IfCPU->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-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-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->IfDrivers -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>IfBoard->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->PortBoard -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>IfBoard->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->IfNetdev -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>IfDrivers->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->PortDrivers -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>IfDrivers->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->End -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>IfNetdev->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->PortNetdev -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>IfNetdev->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->IfBoard -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>PortCPU->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->PortBoard -->
|
||||
<!-- PortBoard->IfDrivers -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>PortBoard->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->PortDrivers -->
|
||||
<!-- PortDrivers->IfNetdev -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>PortDrivers->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->PortNetdev -->
|
||||
<!-- PortNetdev->End -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>PortNetdev->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 |
435
doc/guides/advanced_tutorials/porting_boards.md
Normal file
435
doc/guides/advanced_tutorials/porting_boards.md
Normal 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
|
||||

|
||||
|
||||
# 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.
|
||||
51
doc/guides/build-system/debugging_aids.md
Normal file
51
doc/guides/build-system/debugging_aids.md
Normal 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.
|
||||
506
doc/guides/build-system/flashing.md
Normal file
506
doc/guides/build-system/flashing.md
Normal 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'
|
||||
```
|
||||
637
doc/guides/build-system/img/kconfig_integration.svg
Normal file
637
doc/guides/build-system/img/kconfig_integration.svg
Normal 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 |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
568
doc/guides/build-system/kconfig.md
Normal file
568
doc/guides/build-system/kconfig.md
Normal 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
|
||||
|
||||

|
||||
|
||||
### 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)
|
||||
76
doc/guides/general/code_of_conduct/faq.md
Normal file
76
doc/guides/general/code_of_conduct/faq.md
Normal 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/)
|
||||
82
doc/guides/general/code_of_conduct/reporting.md
Normal file
82
doc/guides/general/code_of_conduct/reporting.md
Normal 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/)
|
||||
149
doc/guides/misc/dev_best_practices.md
Normal file
149
doc/guides/misc/dev_best_practices.md
Normal 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
|
||||
155
doc/guides/misc/emulators.md
Normal file
155
doc/guides/misc/emulators.md
Normal 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`.
|
||||
172
doc/guides/misc/io_mapping_and_shields.md
Normal file
172
doc/guides/misc/io_mapping_and_shields.md
Normal 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
139
doc/guides/misc/roadmap.md
Normal 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.
|
||||
55
doc/guides/misc/terminal_config.md
Normal file
55
doc/guides/misc/terminal_config.md
Normal 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`.
|
||||
@ -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"],
|
||||
|
||||
@ -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:
|
||||
*
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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'.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user