@@ -18,7 +18,7 @@ usually consists of:
1818- documentation and tests that make the port maintainable.
1919
2020This document focuses on the CPU side. For the board side, also refer to the
21- existing RIOT guide on [ porting boards] ( https://guide.riot-os.org /advanced_tutorials/porting_boards/) .
21+ existing RIOT guide on [ porting boards] ( /advanced_tutorials/porting_boards/ ) .
2222
2323::: note
2424A CPU port defines what the MCU family can do. A board port defines which of
@@ -32,26 +32,26 @@ A typical CPU port has a file structure similar to the following:
3232Entries marked with ` * ` are optional and depend on the CPU family and reuse
3333strategy. Entries without ` * ` are typically required for a minimal CPU port.
3434
35- ``` text
36- cpu/foo
37- ├── include
38- │ ├── cpu_conf.h
39- │ ├── periph_cpu.h
40- │ └── vendor*
41- ├── ldscripts*
42- ├── periph*
43- │ ├── gpio.c
44- │ ├── i2c.c
45- │ ├── spi.c
46- │ └── ...
47- ├── vectors
48- │ └── vectors_<model>.c
49- ├── Makefile
50- ├── Makefile.dep*
51- ├── Makefile.features*
52- ├── Makefile.include
53- └── cpu.c
54- ```
35+ {% filetree %}
36+ - cpu/foo
37+ - include
38+ - cpu_conf.h
39+ - periph_cpu.h
40+ - vendor*
41+ - ldscripts*
42+ - periph*
43+ - gpio.c
44+ - i2c.c
45+ - spi.c
46+ - …
47+ - vectors
48+ - vectors_ <model >.c
49+ - Makefile
50+ - Makefile.dep*
51+ - Makefile.features*
52+ - Makefile.include
53+ - cpu.c
54+ {% /filetree %}
5555
5656Not every subdirectory is mandatory; use the ` * ` markers above to distinguish
5757optional components.
@@ -61,7 +61,7 @@ optional components.
6161A practical CPU porting workflow usually looks like this:
6262
63631 . create the CPU directory and build-system files,
64- 2 . add startup support and a working ` cpu_init() ` ,
64+ 2 . add startup support and a working ` cpu_init() ` function ,
65653 . provide CPU and peripheral configuration headers,
66664 . add the interrupt vector table,
67675 . implement the required peripherals one by one,
@@ -72,12 +72,13 @@ The following sections describe the individual files and their purpose.
7272
7373## Build System Files
7474
75- ### ` Makefile `
75+ ### Makefile
7676
7777The top-level CPU ` Makefile ` defines the CPU module and may include common
78- subdirectories that are shared with other CPUs.
78+ subdirectories that are shared with other CPUs. ` $(RIOTCPU) ` is the ` cpu/ `
79+ subdirectory of the RIOT basefolder ` $(RIOTBASE) ` .
7980
80- Example:
81+ #### Example:
8182
8283``` makefile
8384MODULE = cpu
@@ -86,13 +87,13 @@ DIRS = $(RIOTCPU)/cortexm_common periph
8687include $(RIOTBASE ) /Makefile.base
8788```
8889
89- # ## ` Makefile.dep`
90+ # ## Makefile.dep
9091
9192This file expresses build-time dependencies for the CPU. It is the right place
9293for conditional module additions that depend on the selected CPU model,
9394`USEMODULE`, or board features.
9495
95- Example :
96+ # ### Example:
9697
9798```makefile
9899include $(RIOTCPU ) /cortexm_common/Makefile.dep
@@ -102,13 +103,13 @@ ifneq (,$(filter periph_uart,$(USEMODULE)))
102103endif
103104```
104105
105- ### ` Makefile.features `
106+ ### Makefile.features
106107
107108This file declares what the CPU provides to the rest of RIOT by defining the
108109CPU architecture, including common family feature files as well as defining
109- the implemented peripherals with ` FEATURES_PROVIDED ` .
110+ the implemented peripherals with ` FEATURES_PROVIDED ` in alphabetical order .
110111
111- Example:
112+ #### Example:
112113
113114``` makefile
114115CPU_CORE = cortex-m4f
@@ -124,27 +125,32 @@ Only advertise features that are actually implemented and usable. Since the
124125availability of some features can depend on the specific ` CPU_MODEL ` ,
125126conditional statements might be required here as well.
126127
127- ### ` Makefile.include `
128+ ### Makefile.include
128129
129- This file contains low-level build configuration for the CPU.
130+ This file contains low-level build configuration and additional compiler and
131+ linker search paths for the CPU.
130132
131- Example:
133+ #### Example:
132134
133135``` makefile
134136INCLUDES += -I$(RIOTCPU ) /foo/include
137+ INCLUDES += -I$(RIOTCPU ) /vendor/include
135138LINKER_SCRIPT = $(RIOTCPU ) /foo/ldscripts/foo.ld
136139VECTORS_O = $(CPU_OBJ ) /vectors/vectors_$(CPU_MODEL ) .o
137140```
138141
139142For Cortex-M devices, this file often also ties the CPU port to the generic
140- ` cortexm_common ` startup and linker support.
143+ ` cortexm_common ` startup and linker support. The same pattern is common on
144+ other architectures as well (for example ` riscv_common ` for RISC-V based
145+ ports).
141146
142147## Core CPU Files
143148
144- ### ` cpu.c `
149+ ### cpu.c
145150
146- ` cpu.c ` contains ` cpu_init() ` , which performs the minimum hardware and runtime
147- initialization needed before RIOT starts normal execution.
151+ The ` cpu.c ` file contains the ` cpu_init() ` function, which performs the
152+ minimum hardware and runtime initialization needed before RIOT starts its
153+ normal operation.
148154
149155A minimal shape often looks like this:
150156
@@ -167,7 +173,7 @@ Refer to the Technical Reference Manual of the target CPU for details on
167173implementing the boot process.
168174:::
169175
170- ### ` vectors/`
176+ ### vectors/
171177
172178This directory contains the interrupt vector table for the supported CPU model.
173179Without a correct vector table, the CPU will usually fault immediately after
@@ -179,9 +185,9 @@ Typical responsibilities:
179185- define the `Reset_Handler`,
180186- provide weak default handlers for all supported interrupts,
181187- match the IRQ numbering expected by
182- `CPU_IRQ_NUMOF`.
188+ `CPU_IRQ_NUMOF` defined in `include/cpu_conf.h` .
183189
184- ### ` ldscripts/`
190+ ### ldscripts/
185191
186192This directory holds CPU-specific linker scripts if the CPU cannot directly use
187193an existing common linker script.
@@ -192,7 +198,7 @@ Typical responsibilities:
192198- place sections such as `.text`, `.data`, `.bss`, interrupt vectors, and stack,
193199- cooperate with RIOT's startup assumptions.
194200
195- ### ` include/cpu_conf.h`
201+ ### include/cpu_conf.h
196202
197203This header provides CPU-wide configuration.
198204
@@ -219,8 +225,10 @@ Example structure:
219225The exact contents depend on the architecture and MCU family, but this file is
220226usually where RIOT learns which vendor header to use and how many interrupts the
221227CPU exposes.
228+ Remember that only vendor headers included in the search paths defined by
229+ the ` Makefile.include ` can be found by the compiler!
222230
223- ### ` include/periph_cpu.h `
231+ ### include/periph_cpu.h
224232
225233This header provides CPU-specific peripheral types and helper macros.
226234
@@ -264,7 +272,7 @@ The exact contents depend on the CPU family, but this file usually contains the
264272CPU-local building blocks that make the generic RIOT peripheral API usable for a
265273specific MCU implementation.
266274
267- ### ` include/vendor/ `
275+ ### include/vendor/
268276
269277Vendor HAL headers can be placed here or integrated via RIOT's package
270278mechanism. Vendor SDKs can range from thousands to millions of lines of code,
@@ -279,7 +287,7 @@ EFM32, which keep vendor content modular and reused across multiple boards.
279287The CPU should be added to ` features.yaml ` so the build system can resolve the
280288feature name consistently.
281289
282- Example:
290+ #### Example:
283291
284292``` yaml
285293- title : Example MCU Grouping
@@ -326,7 +334,8 @@ The GPIO driver provides the basic digital pin interface for RIOT.
326334
327335- ` gpio_init()` for input/output modes,
328336- ` gpio_init_int()` for edge-triggered interrupts,
329- - ` gpio_read()` , `gpio_set()`, `gpio_clear()`, `gpio_toggle()`,
337+ - ` gpio_read()` , `gpio_set()`, `gpio_clear()`, `gpio_toggle()` for discrete
338+ pin state manipulation,
330339- ` gpio_irq_enable()` and `gpio_irq_disable()` if interrupt support is enabled,
331340- pin-to-port decoding helpers if the CPU uses packed GPIO identifiers.
332341
@@ -341,7 +350,8 @@ The GPIO driver provides the basic digital pin interface for RIOT.
341350- preload the output latch if needed before switching a pin to output mode,
342351- configure interrupt trigger type and store callback context for
343352 ` gpio_init_int()` ,
344- - dispatch the registered callback from the ISR.
353+ - dispatch the registered callback from the ISR. Keep the ISR short. It should
354+ typically acknowledge the interrupt and call the registered callback.
345355
346356# ## Example register-level init sketch
347357
@@ -359,25 +369,23 @@ int gpio_init(gpio_t pin, gpio_mode_t mode)
359369}
360370` ` `
361371
362- Keep the ISR short. It should typically acknowledge the interrupt and call the
363- registered callback.
364-
365372# # UART
366373
367374**RIOT API:** `drivers/include/periph/uart.h`
368375
369- UART is used for standard I/O, shell access, and device communication. In RIOT,
370- receive handling is interrupt-driven.
376+ The UART is used for standard I/O, shell access, and device communication.
377+ In RIOT, receive handling is interrupt-driven.
371378
372- As a side note, UART setup usually reuses parts of the GPIO implementation :
373- pin muxing, GPIO direction defaults, and optional RTS/CTS handling all rely on
379+ As a side note, the UART setup usually reuses parts of the GPIO implementation :
380+ Pin muxing, GPIO direction defaults, and optional RTS/CTS handling all rely on
374381the underlying pin configuration support being correct.
375382
376383# ## Typical functionality to implement
377384
378- - ` uart_init()` ,
379- - ` uart_write()` ,
380- - ` uart_poweron()` and `uart_poweroff()`,
385+ - ` uart_init()` for the peripheral initialization,
386+ - ` uart_write()` , `uart_read()` for input and output,
387+ - ` uart_poweron()` and `uart_poweroff()` for enabling and disabling the
388+ peripheral,
381389- optional helpers such as reconfiguration or RX start interrupt support if the
382390 corresponding modules are enabled.
383391
@@ -393,7 +401,7 @@ the underlying pin configuration support being correct.
393401- unmask the peripheral interrupt and connect it to the NVIC if receive support
394402 is enabled,
395403- enable RX/TX and keep `uart_poweroff()` and `uart_poweron()` transparent to
396- upper layers.
404+ the upper layers.
397405
398406# ## Example register-level init sketch
399407
@@ -421,9 +429,17 @@ external RIOT API should remain unchanged.
421429
422430**RIOT API:** `drivers/include/periph/timer.h`
423431
424- Timers are foundational in RIOT because higher layers such as `ztimer` and
425- scheduler services depend on them. A reliable timer driver is therefore one of
426- the most important parts of a CPU port.
432+ Timers are foundational in RIOT because higher level modules such as `ztimer`
433+ and scheduler services depend on them. A reliable timer driver is therefore one
434+ of the most important parts of a CPU port.
435+
436+ Most Cortex-M MCUs expose multiple timer classes : core `SysTick`, general
437+ purpose timers (often 16-bit or 32-bit), and sometimes low-power timers running
438+ from a slower always-on clock. For `periph_timer`, prefer a dedicated general
439+ purpose timer, compare/interrupt support, and enough width for the expected
440+ timing range. `SysTick` is usually better kept for core/system use and is often
441+ too limited (single instance, 24-bit counter, core-clock coupling) for robust
442+ peripheral timing.
427443
428444# ## Typical functionality to implement
429445
@@ -473,8 +489,8 @@ Mistakes here often break `ztimer`, sleeping, or scheduling in subtle ways.
473489**RIOT API:** `drivers/include/periph/spi.h`
474490
475491RIOT's SPI API is transaction-based because an SPI bus is a shared resource.
476- This means the driver is expected to configure and power the peripheral around
477- ` spi_acquire()` / `spi_release()`.
492+ This means the peripheral driver is expected to configure and power the
493+ peripheral within `spi_acquire()` / `spi_release()`.
478494
479495GPIO support is also important here : SPI buses reuse GPIO handling for pin mux
480496setup, optional manual chip-select lines, and some reconfiguration paths.
@@ -500,6 +516,10 @@ setup, optional manual chip-select lines, and some reconfiguration paths.
500516
501517# ## Generic high-level shape
502518
519+ The following snippet is an example of how the SPI API is called from
520+ application or device driver code. It is not CPU-port implementation code
521+ from `cpu/<cpu>/periph/spi.c`.
522+
503523` ` ` c
504524spi_init(bus);
505525spi_init_cs(bus, cs);
@@ -575,16 +595,19 @@ Bring up the CPU with the smallest possible configuration first:
575595- boot to `cpu_init()`,
576596- confirm the vector table works,
577597- get `examples/basic/hello-world` running over UART,
598+ - if UART output is missing, toggle an LED at key checkpoints in startup and
599+ ` cpu_init()` to localize where execution stops,
578600- validate one timer instance so `ztimer` works,
579601- then implement the remaining peripherals incrementally.
580602
581603# ## Reuse common code
582604
583605If the MCU belongs to an already supported architecture or family, reuse the
584- existing common code where possible. For this case, a base directory
606+ existing common code where possible. In this case, a base directory
585607(e.g. `cpu/<CPU_FAM>_common`) should be created that contains all shared/common
586608configurations. This drastically reduces maintenance and lowers the risk of
587- subtle startup or interrupt bugs.
609+ subtle startup or interrupt bugs, as well as code divergation issues in the
610+ future.
588611
589612# ## Refer to the manual of the target CPU
590613
0 commit comments