diff --git a/doc/doxygen/src/using-rust.md b/doc/doxygen/src/using-rust.md
index 50e68fd31b..563932a31d 100644
--- a/doc/doxygen/src/using-rust.md
+++ b/doc/doxygen/src/using-rust.md
@@ -1,258 +1,5 @@
Using Rust in RIOT {#using-rust}
==================
-[TOC]
-
-On supported CPUs, Rust can be used to develop RIOT applications.
-Support is indicated in the `has_rust_target` feature,
-and tested for in applications using the Makefile line
-`FEATURES_REQUIRED += rust_target`.
-
-In addition to the regular RIOT build toolchain
-and a recent nightly Rust toolchain for the given target,
-using this also requires C2Rust with some patches applied to be installed;
-see toolchain for installation instructions.
-All these are readily available in the [official RIOT docker image],
-which gets used by default if `BUILD_IN_DOCKER=1` is set.
-
-[official RIOT docker image]: https://hub.docker.com/r/riot/riotbuild
-
-Examples
---------
-
-Two examples are provided:
-
-* ``rust-hello-world`` is minimal in the sense of setup and code complexity; it is the typical Hello World example.
-
- (Note that it is not necessarily minimal in terms of built size,
- as Rust's regular printing infrastructure is more powerful and a bit heavier than your off-the-shelf ``printf``,
- which embedded libcs already often trim down).
-
-* ``rust-gcoap`` is a set of demo CoAP resources
- both from the [coap-message-demos] crate (containing platform and library independent examples)
- and from the [riot-module-examples] crate (containing RIOT specific examples).
-
-There are [additional examples] available on GitLab,
-maintained in coordination with the riot-wrappers crate.
-
-[coap-message-demos]: https://gitlab.com/chrysn/coap-message-demos
-[riot-module-examples]: https://gitlab.com/etonomy/riot-module-examples
-[additional examples]: https://gitlab.com/etonomy/riot-examples/
-
-IDE / editor setup
-------------------
-
-Users of Rust often take advantage of autocompletion or inline help.
-To use this on RIOT projects,
-some flags and environment variables have to be set,
-which are listed by `make info-rust`.
-These can be configured in the IDE's project setup
-or exported as environment variables.
-
-How it works
-------------
-
-The easy part of the story is that Rust code gets compiled into a static library
-which is then linked together with the rest of the RIOT code;
-if the main function happens to be implemented in Rust, so it is.
-
-The **RIOT build system** contains rules and metadata to facilitate building and linking:
-it calls `cargo` (Rust's own build system),
-sets up paths to work well with out-of-tree builds,
-configures the Rust target depending on the board's CPU,
-and unpacks the static library into object files to facilitate interaction with XFA.
-
-The [**riot-sys**] crate translates a selected subset of RIOT's header files for use in Rust;
-this happens both using the [bindgen] crate (working from API information in header files)
-and [C2Rust] \(translating static inline functions, and with some help from riot-sys, constant preprocessor initializers).
-Functions exported by riot-sys are inherently unsafe to use (in Rust's sense of unsafe),
-and may be somewhat volatile in their API due to mismatches between RIOT's / C's and Rust's API stability concepts.
-
-The [**riot-wrappers**] crate creates safe and idiomatic wrappers around the types and functions provided by riot-sys.
-Thanks to Rust's strong zero-cost abstractions, these often come at no increased runtime cost.
-For example, locking a [riot_wrappers::mutex::Mutex] can rely on it having been properly initialized at creation;
-furthermore, the mutex is freed when it goes out of scope.
-
-Where practical, the wrappers are not accessed through own methods
-but through established platform independent traits.
-For example, the main API surface of an [I2CDevice]
-is its implementation of the [corresponding embedded-hal I2C traits] for reading and writing.
-
-The wrappers are [documented together with riot-sys and some of the examples].
-
-[**riot-sys**]: https://crates.io/crates/riot-sys
-[**riot-wrappers**]: https://crates.io/crates/riot-wrappers
-[bindgen]: https://crates.io/crates/bindgen
-[C2Rust]: https://c2rust.com/
-[riot_wrappers::mutex::Mutex]: https://rustdoc.etonomy.org/riot_wrappers/mutex/struct.Mutex.html
-[documented together with riot-sys and some of the examples]: https://rustdoc.etonomy.org/
-[I2CDevice]: https://rustdoc.etonomy.org/riot_wrappers/i2c/struct.I2CDevice.html
-[corresponding embedded-hal I2C traits]: https://rustdoc.etonomy.org/embedded_hal/blocking/i2c/index.html
-
-Library components in Rust
---------------------------
-
-It is possible to use Rust in different modules than the application itself.
-
-Such modules are usually pseudomodules (although they may be mixed with C in regular modules as well).
-They always depend on the `rust_riotmodules` module / crate,
-which collects all enabled modules into a single crate by means of optional features.
-
-If the application is not written in Rust,
-that then depends on `rust_riotmodules_standalone`,
-which adds a panic handler and serves as a root crate.
-
-If the application is written in Rust,
-`rust_riotmodules` needs to be added as a dependency of the application.
-(This helps deduplicate between application and library code,
-and also avoids symbol name clashes).
-This is done by adding a dependency on the local `rust_riotmodules` crate (which is a no-op when no such modules are enabled),
-and placing an `extern crate rust_riotmodules;` statement in the code.
-(The latter is needed even after most `extern crate` was abolished in 2018,
-because crates depended on but not used otherwise are usually not linked in).
-
-Toolchain {#toolchain}
----------
-
-To install the necessary Rust components, it is easiest use [**rustup**, installed as described on its website].
-
-Using Rust on RIOT needs the latest stable version of Rust.
-
-Make sure you have the core library for the CPU (**target**) of your choice available:
-
-```
-$ rustup target add thumbv7m-none-eabi
-```
-
-Substitute thumbv7m-none-eabi with the value of `RUST_TARGET`
-in the output of `make info-build` of an application that has your current board selected
-(or just add it later whenever the Rust compiler complains about not finding the core library for a given target).
-Using the beta or nightly toolchains will work just as well
-if they are selected through rustup's override mechanism.
-
-
-While Rust comes with its own [cargo] dependency tracker for any Rust code,
-it does not attempt to install **system components**.
-To avoid playing the whack-a-mole of installing components whenever an install step fails,
-consider installing this list of packages on Debian
-(or an equivalent list on the distribution of your choice):
-
-```
-# apt install libclang-dev llvm llvm-dev cmake libssl-dev pkg-config
-```
-
-This encompass both components needed for riot-sys and for the later installation of C2Rust.
-
-
-In addition to the Rust compiler you'll need to install the C2Rust transpiler;
-as this is using some recent fixes, it is best installed as:
-
-
-```shell
-$ cargo install c2rust --git https://github.com/immunant/c2rust --tag v0.19.0 --locked
-```
-
-If multiple versions of LLVM are installed locally, it may be necessary to prefix it with the selected LLVM version:
-
-```
-$ LLVM_CONFIG_PATH=/usr/bin/llvm-config-16 cargo install …
-```
-
-[cargo]: https://doc.rust-lang.org/cargo/
-[**rustup**, installed as described on its website]: https://rustup.rs/
-
-Maintenance
------------
-
-The [riot-sys] and [riot-wrappers] crates are currently maintained as parts of the RIOT project.
-While being released via crates.io on demand, usually RIOT uses a fixed version from the git repositories that are [easily updated].
-
-The autogenerated bindings of the C API are slightly stricter than C's API,
-and thus occasionally require additional work when C APIs change subtly.
-The riot-sys crate takes the brunt of these changes --
-it changes automatically, and no attempt is currently made to reflect these changes in a SemVer compatible manner.
-The riot-wrappers crate smooths this out,
-and provides an API that aims to be more stable than the C API.
-It does that by generously converting types that changed,
-and [introspecting generated bindings] or using [information provided by riot-sys].
-
-The typical workflow of (C-nonbreaking, Rust-breaking) API changes is as follows:
-
-* A PR subtly alters a type (eg. `uint8_t *` to `void *` in [#17990]).
-
- Consequently, builds of Rust examples break.
-
-* A PR is opened on riot-wrappers to smooth over the change, like [aab605f4] .
-
- The PR is tested against current master in its CI (albeit not for the full set of boards).
- To test whether it also works for the changed API,
- a commit titled "REMOVEME Test with updated riot-wrappes" can be added to the original PR;
- it alters `.cargo/config.toml` to point to the changed branch,
- and removes any Cargo.lock files in the RIOT tree.
-
- That PR is then merged.
-
-* The version of riot-wrappers that works both with the previous and the new code
- is pulled into the RIOT master branch by updating the Cargo.lock files.
- The PR can look like [#18181], and verifies that the new riot-wrappers works on all boards.
-
- That PR is then merged.
-
-* For the next builds (up to the merging of) the original PR,
- the REMOVEME commit can be removed.
-
- It is good practice to rebase it onto the latest master after the update to riot-wrappers has been merged,
- as this helps keeping bisectability up.
-
- The PR now contains no Rust specific changes, and can be merged.
-
-There are a few variations that can occur:
-
-* Sometimes casting is not enough, and a type must be extracted from a signature.
- [See the phydat callback type change] for an example.
-
-* When neither casting nor type detection is sufficient,
- a marker can be introduced through riot-sys;
- it detects a keyword's presence in the source and passes it as [information provided by riot-sys] to riot-wrappers.
- [See the coap_request_ctx_t change] for an example.
-
- In that case, a riot-sys PR is opened in parallel to the riot-wrappers PR.
-
- This method helps keeping changes backportable easily:
- riot-sys and riot-wrappers are expected to work with the latest released version of RIOT all the time,
- and avoid flag-day changes.
- (Keeping riot-sys and riot-wrappers compatible with the latest release is also important to retain the ability to backport fixes).
-
-* When functions are moved from being static and not being static,
- their names go from `riot_sys::inline::name` to `riot_sys::name` (or vice versa).
-
- riot-sys [has a list] of items that are always publicly exported directly as `riot_sys::name`;
- just add the function there.
-
- If non-generic types are referenced in them, they go from `riot_sys::inline::my_type_t` to `riot_sys::my_type_t`.
- The [inline_cast] function family helps making that cast a bit safer.
-
-* Things fail around atomics.
-
- Until [C2Rust's support for atomics has improved],
- riot-sys requires all exported headers to use the better supported `atomic_utils.h`.
-
- If it is unavoidable that atomics are part of header files
- (and not actually used in any static inline functions),
- riot-sys's [atomics workarounds] can be extended as a last resort.
-
-
-[riot-wrappers]: https://github.com/RIOT-OS/rust-riot-wrappers/
-[riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/
-[easily updated]: https://github.com/RIOT-OS/RIOT/pull/17491#issuecomment-1143209437
-[introspecting generated bindings]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/helpers.rs#L3
-[information provided by riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L591
-[#17990]: https://github.com/RIOT-OS/RIOT/pull/17990
-[aab605f4]: https://github.com/RIOT-OS/rust-riot-wrappers/commit/aab605f464a279608ef0a8ad2afd5ae43179e330
-[#18181]: https://github.com/RIOT-OS/RIOT/pull/18181
-[See the phydat callback type change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/6/files#diff-ccb7946e3b4122ea3ce23fa9bc54eba63d75f7a6142fd4afdd9908b1bead50e0
-[See the coap_request_ctx_t change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/4/files
-[has a list]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L533
-[inline_cast]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/lib.rs#L68
-[C2Rust's support for atomics has improved]: https://github.com/immunant/c2rust/issues/436
-[atomics workarounds]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/riot-c2rust.h#L79
+@deprecated Guides have moved to the [Guide Site](https://guide.riot-os.org/).
+This page will be removed after release 2025.11.
diff --git a/doc/guides/rust_tutorials/create_project.mdx b/doc/guides/rust_tutorials/create_project.mdx
new file mode 100644
index 0000000000..926a2d3a95
--- /dev/null
+++ b/doc/guides/rust_tutorials/create_project.mdx
@@ -0,0 +1,274 @@
+---
+title: "Creating a Project"
+description: "Create a new project with a simple hello world program"
+---
+
+import GitSetup from '@components/gitsetup.mdx';
+import Contact from '@components/contact.astro';
+
+## Step 1: Create a new project
+
+
+
+#### Open VS Code
+
+Now that we have added RIOT as a submodule to our project,
+we can start writing our hello world program.
+You can use any text editor to create this file.
+We will use Visual Studio Code in this example.
+To open Visual Studio Code in the directory, you can use the following command:
+
+```bash title="Open Visual Studio Code"
+code .
+```
+
+## Step 2: Initialize Rust
+
+Now that Visual Studio Code is open,
+we need to tell Rust what kind of project we want to create.
+We do this by running the following command in the terminal:
+
+```bash title="Create a new Rust project"
+cargo new hello_world --lib
+```
+
+This command creates a new project called `hello_world` with a library crate type.
+The `--lib` flag tells Rust that we want to create a library crate instead of a binary crate.
+A library crate is a collection of functions and types that can be used by other programs,
+while a binary crate is an executable program.
+RIOT then calls our `main` function when the program starts.
+
+You should now have 3 new files within your project directory:
+
+- `Cargo.toml`: This file contains metadata about your project and its dependencies.
+- `src/lib.rs`: This file contains the source code for your library crate.
+- `Cargo.lock`: This file contains information about the exact versions of your dependencies.
+ - This file is automatically generated by Cargo and should not be edited manually
+ so don't worry about it for now.
+
+
+
+## Step 3: Creating the Makefile
+
+Now that we have created our hello world program,
+we need to create a Makefile to build our program.
+The Makefile is a build automation tool
+that allows us to define how our program should be built.
+We create a new file called `Makefile` in the root directory of our project
+and add the following code:
+
+```makefile title="Makefile"
+# name of your application
+APPLICATION = hello-world
+
+# The name of crate (as per Cargo.toml package name, but with '-' replaced with '_')
+#
+# The presence of this triggers building Rust code contained in this
+# application in addition to any C code.
+APPLICATION_RUST_MODULE = rust_hello_world
+
+# If no BOARD is found in the environment, use this default:
+BOARD ?= native
+
+# If you want to build in a Docker container, set this to 1.
+# This is useful if you want to build on a system that does not have the
+# RIOT toolchain installed, or if you want to ensure that the build is
+# reproducible.
+BUILD_IN_DOCKER ?= 1
+
+# This has to be the absolute path to the RIOT base directory:
+RIOTBASE ?= $(CURDIR)/../../../..
+
+# Comment this out to disable code in RIOT that does safety checking
+# which is not needed in a production environment but helps in the
+# development process:
+DEVELHELP ?= 1
+
+# Change this to 0 show compiler invocation lines by default:
+QUIET ?= 1
+
+include $(RIOTBASE)/Makefile.include
+```
+
+:::note
+The `BUILD_IN_DOCKER=1` flag tells the build system to use the docker image
+provided by RIOT to build our program.
+This ensures that we have all the necessary dependencies to build our program.
+If you have already built RIOT on your system,
+you can omit this flag and the build system will use the toolchain installed on your system.
+If you want to build your program on a different board,
+you can change the `BOARD` variable to the name of the board you want to build for.
+:::
+
+Now RIOT knows that you want to build a Rust application
+and will use the `hello_world` crate as the main module.
+
+
+
+## Step 3: Adjusting the Cargo.toml
+
+Next, we need to adjust the `Cargo.toml` file to tell Cargo that we want to build for RIOT.
+Open the `Cargo.toml` file and replace its contents with the following:
+
+```toml title="Cargo.toml"
+[package]
+name = "hello-world"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+crate-type = ["staticlib"]
+
+[profile.release]
+# Setting the panic mode has little effect on the built code (as Rust on RIOT
+# supports no unwinding), but setting it allows builds on native without using
+# the nightly-only lang_items feature.
+panic = "abort"
+
+[dependencies]
+riot-wrappers = { version = "0.9.1", features = [ "set_panic_handler", "panic_handler_format" ] }
+
+rust_riotmodules = { path = "./RIOT/sys/rust_riotmodules/" }
+```
+
+The most important part here are the dependencies.
+As mentioned in [Rust in Riot](/rust_tutorials/rust_in_riot/),
+`riot-wrappers` is a crate that provides a set of wrappers around
+RIOT's C functions to make them usable from Rust in a safe way.
+
+The other configuration options are not that important for now,
+but you can read more about them in the
+[Cargo documentation](https://doc.rust-lang.org/cargo/reference/manifest.html).
+
+### IDE Setup
+
+Due to the way the RIOT Rust integration works, you need to amend your
+normal Rust setup in your IDE to make it work with RIOT. Luckily RIOT
+provides a small makefile command that will help you with that.
+Run the following command in your terminal:
+
+```bash
+make info-rust
+```
+
+The output will look something like this:
+
+```bash title="Output of make info-rust"
+[ann@ann-laptop13 rust01-hello-world]$ make info-rust
+cargo version
+cargo 1.81.0 (2dbb1af80 2024-08-20)
+c2rust --version
+C2Rust 0.19.0
+To use this setup of Rust in an IDE, add these command line arguments to the `cargo check` or `rust-analyzer`:
+ --profile release
+and export these environment variables:
+ CARGO_BUILD_TARGET="thumbv7em-none-eabihf"
+ RIOT_COMPILE_COMMANDS_JSON="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/cargo-compile-commands.json"
+ RIOTBUILD_CONFIG_HEADER_C="/home/ann/projects/exercises/rust01-hello-world/bin/feather-nrf52840-sense/riotbuild/riotbuild.h"
+You can also call cargo related commands with `make cargo-command CARGO_COMMAND="cargo check"`.
+Beware that the way command line arguments are passed in is not consistent across cargo commands, so adding `--profile release` or other flags from above as part of CARGO_COMMAND may be necessary.
+```
+
+Add the environment variables to your shell configuration file for this project
+or use the `make cargo-command` command to run cargo commands with the correct arguments.
+
+In VSCode you can now go to the workspace settings `.vscode/settings.json`
+and add the following settings:
+
+```json title=".vscode/settings.json"
+{
+ "rust-analyzer.cargo.extraArgs": [
+ "--profile",
+ "release"
+ ],
+ "rust-analyzer.cargo.target": "thumbv7em-none-eabihf",
+}
+```
+
+
+## Step 4: Writing the Hello World Program
+
+We are nearly done with setting up our project. The last thing we need to do is
+to write the actual hello world program.
+Open the `src/lib.rs` file and replace its contents with the following code:
+
+```rust title="src/lib.rs"
+#![no_std]
+
+use riot_wrappers::riot_main;
+use riot_wrappers::println;
+
+extern crate rust_riotmodules;
+```
+
+`#![no_std]` tells the Rust compiler that we are building a program
+that does not depend on the standard library,
+which is not available on the hardware we are targeting.
+This does mean that we can't use some of the standard library features
+like `std::io` or `std::collections`, however,
+there are a lot of `no_std` compatible crates available that provide similar functionality,
+including `riot-wrappers` 😉
+
+After that we import the functions that we will soon use to print to the console.
+The `riot_main` macro helps RIOT figure out what our main function is
+and `println` is a macro that we can use to print to the console,
+this replaces the `println!` macro from the standard library,
+since, as mentioned before, we can't use it on embedded systems.
+
+Now we need to actually write the `main` function.
+Add the following code to the `src/lib.rs` file:
+
+```rust title="src/lib.rs"
+riot_main!(main);
+
+fn main() {
+ println!(
+ "You are running RIOT using Rust on a(n) {} board.",
+ riot_wrappers::BOARD
+ );
+}
+```
+
+
+
+Congratulations! You have now created your first Rust program for RIOT. 🎉
+
+## Step 5: Building the Program
+
+
+
+To build our program, we use the following command:
+
+```bash title="Build and flash the program"
+make flash
+```
+
+After building the program,
+we can run it using the following command to start the RIOT shell:
+
+```bash title="Connect to the RIOT shell"
+make term
+```
+
+You should see the following output:
+
+```txt title="Output in the terminal"
+You are running RIOT using Rust on a(n) native board.
+```
+
+
+
+## Conclusion
+
+In this tutorial,
+you have learned how to create a new Rust project for RIOT and how to build and run it.
+You have also learned how to write a simple hello world program in Rust
+and how to use the `riot-wrappers` crate to interact with RIOT's C functions.
+
+:::note
+The source code for this tutorial can be found
+[HERE](https://github.com/RIOT-OS/RIOT/tree/master/examples/lang_support/official/rust-hello-world).
+
+If your project is not working as expected,
+you can compare your code with the code in this repository to see if you missed anything.
+:::
diff --git a/doc/guides/rust_tutorials/img/create_project/01_project_structure.png b/doc/guides/rust_tutorials/img/create_project/01_project_structure.png
new file mode 100644
index 0000000000..a357b2fc08
Binary files /dev/null and b/doc/guides/rust_tutorials/img/create_project/01_project_structure.png differ
diff --git a/doc/guides/rust_tutorials/img/create_project/02_makefile.png b/doc/guides/rust_tutorials/img/create_project/02_makefile.png
new file mode 100644
index 0000000000..bf687eb7a3
Binary files /dev/null and b/doc/guides/rust_tutorials/img/create_project/02_makefile.png differ
diff --git a/doc/guides/rust_tutorials/img/create_project/03_lib.png b/doc/guides/rust_tutorials/img/create_project/03_lib.png
new file mode 100644
index 0000000000..f3c9c0f860
Binary files /dev/null and b/doc/guides/rust_tutorials/img/create_project/03_lib.png differ
diff --git a/doc/guides/rust_tutorials/img/create_project/04_terminal_output.png b/doc/guides/rust_tutorials/img/create_project/04_terminal_output.png
new file mode 100644
index 0000000000..336673ca6c
Binary files /dev/null and b/doc/guides/rust_tutorials/img/create_project/04_terminal_output.png differ
diff --git a/doc/guides/rust_tutorials/rust_in_riot.md b/doc/guides/rust_tutorials/rust_in_riot.md
new file mode 100644
index 0000000000..1f2873eb83
--- /dev/null
+++ b/doc/guides/rust_tutorials/rust_in_riot.md
@@ -0,0 +1,273 @@
+---
+title: Rust in RIOT
+description: Using Rust in RIOT
+---
+
+:::tip
+This document describes the general setup and usage of Rust in RIOT.
+If you want to create a new application using Rust, you can start with the
+[Creating a Rust application tutorial](/rust_tutorials/create_project/).
+:::
+
+On supported CPUs, Rust can be used to develop RIOT applications.
+Support is indicated in the `has_rust_target` feature.
+
+In addition to the regular RIOT build toolchain
+and a recent nightly Rust toolchain for the given target,
+using this also requires C2Rust with some patches applied to be installed,
+see toolchain for installation instructions.
+All these are readily available in the [official RIOT docker image],
+which gets used by default if `BUILD_IN_DOCKER=1` is set.
+
+[official RIOT docker image]: https://hub.docker.com/r/riot/riotbuild
+
+## Examples
+
+Two examples are provided:
+
+- `rust-hello-world` is minimal in the sense of setup and code complexity,
+ it is the typical Hello World example.
+
+ (Note that it is not necessarily minimal in terms of build size,
+ as Rust's regular printing infrastructure is more powerful and a bit heavier
+ than your off-the-shelf `printf`,
+ which embedded libcs already often trim down).
+
+- `rust-gcoap` is a set of demo CoAP resources
+ both from the [coap-message-demos] crate (containing platform and library independent examples)
+ and from the [riot-module-examples] crate (containing RIOT specific examples).
+
+There are [additional examples] available on GitLab,
+maintained in coordination with the riot-wrappers crate.
+
+[coap-message-demos]: https://gitlab.com/chrysn/coap-message-demos
+[riot-module-examples]: https://gitlab.com/etonomy/riot-module-examples
+[additional examples]: https://gitlab.com/etonomy/riot-examples/
+
+## IDE / editor setup
+
+Users of Rust often take advantage of autocompletion or inline help.
+To use this on RIOT projects,
+some flags and environment variables have to be set,
+which are listed by `make info-rust`.
+These can be configured in the IDE's project setup
+or exported as environment variables.
+
+## How it works
+
+The easy part of the story is that Rust code gets compiled into a static library
+which is then linked together with the rest of the RIOT code,
+if the main function happens to be implemented in Rust, so it is.
+
+The **RIOT build system** contains rules and metadata to facilitate building and linking:
+it calls `cargo` (Rust's own build system),
+sets up paths to work well with out-of-tree builds,
+configures the Rust target depending on the board's CPU,
+and unpacks the static library into object files to facilitate interaction with XFA.
+
+The [**riot-sys**] crate translates a selected subset of RIOT's header files for use in Rust,
+this happens both using the [bindgen] crate (working from API information in header files)
+and [C2Rust] \(translating static inline functions, and with some help from riot-sys,
+constant preprocessor initializers).
+Functions exported by riot-sys are inherently unsafe to use (in Rust's sense of unsafe),
+and may be somewhat volatile in their API due to mismatches between RIOT's / C's
+and Rust's API stability concepts.
+
+The [**riot-wrappers**] crate creates safe and idiomatic wrappers around the types and functions provided by riot-sys.
+Thanks to Rust's strong zero-cost abstractions, these often come at no increased runtime cost.
+For example, locking a [riot_wrappers::mutex::Mutex]
+can rely on it having been properly initialized at creation,
+furthermore, the mutex is freed when it goes out of scope.
+
+Where practical, the wrappers are not accessed through own methods
+but through established platform independent traits.
+For example, the main API surface of an [I2CDevice]
+is its implementation of the [corresponding embedded-hal I2C traits] for reading and writing.
+
+The wrappers are [documented together with riot-sys and some of the examples].
+
+[**riot-sys**]: https://crates.io/crates/riot-sys
+[**riot-wrappers**]: https://crates.io/crates/riot-wrappers
+[bindgen]: https://crates.io/crates/bindgen
+[C2Rust]: https://c2rust.com/
+[riot_wrappers::mutex::Mutex]: https://rustdoc.etonomy.org/riot_wrappers/mutex/struct.Mutex.html
+[documented together with riot-sys and some of the examples]: https://rustdoc.etonomy.org/
+[I2CDevice]: https://rustdoc.etonomy.org/riot_wrappers/i2c/struct.I2CDevice.html
+[corresponding embedded-hal I2C traits]: https://rustdoc.etonomy.org/embedded_hal/blocking/i2c/index.html
+
+## Library components in Rust
+
+It is possible to use Rust in different modules than the application itself.
+
+Such modules are usually pseudomodules
+(although they may be mixed with C in regular modules as well).
+They always depend on the `rust_riotmodules` module / crate,
+which collects all enabled modules into a single crate by means of optional features.
+
+If the application is not written in Rust,
+that then depends on `rust_riotmodules_standalone`,
+which adds a panic handler and serves as a root crate.
+
+If the application is written in Rust,
+`rust_riotmodules` needs to be added as a dependency of the application.
+(This helps deduplicate between application and library code,
+and also avoids symbol name clashes).
+This is done by adding a dependency on the local `rust_riotmodules` crate
+(which is a no-op when no such modules are enabled),
+and placing an `extern crate rust_riotmodules,` statement in the code.
+(The latter is needed even after most `extern crate` was abolished in 2018,
+because crates depended on but not used otherwise are usually not linked in).
+
+## Toolchain
+
+Using Rust on RIOT needs the latest stable version of Rust. Please note that
+many popular Linux distributions provide very old versions in their
+repositories. Therefore to install the necessary Rust components, it is
+recommended and easiest to use [**rustup**, installed as described
+on its project website].
+
+Make sure you have the core library for the CPU (**target**) of your choice available:
+
+```shell
+rustup target add thumbv7m-none-eabi
+```
+
+Substitute `thumbv7m-none-eabi` with the value of `RUST_TARGET`
+in the output of `make info-build` of an application that has your current board selected
+(or just add it later whenever the Rust compiler complains about not finding
+the core library for a given target).
+Using the beta or nightly toolchains will work just as well
+if they are selected through rustup's override mechanism.
+
+While Rust comes with its own [cargo] dependency tracker for any Rust code,
+it does not attempt to install **system components**.
+To avoid playing the whack-a-mole of installing components whenever an install step fails,
+consider installing this list of packages on Debian
+(or an equivalent list on the distribution of your choice):
+
+```shell
+apt install libclang-dev llvm llvm-dev cmake libssl-dev pkg-config
+```
+
+This encompasses both components needed for riot-sys and for the later installation of C2Rust.
+
+In addition to the Rust compiler you'll need to install the C2Rust transpiler,
+as this is using some recent fixes, it is best installed as:
+
+
+
+```shell
+cargo install c2rust --git https://github.com/immunant/c2rust --tag v0.19.0 --locked
+```
+
+If multiple versions of LLVM are installed locally,
+it may be necessary to prefix it with the selected LLVM version:
+
+```shell
+LLVM_CONFIG_PATH=/usr/bin/llvm-config-16 cargo install …
+```
+
+[cargo]: https://doc.rust-lang.org/cargo/
+[**rustup**, installed as described on its project website]: https://rustup.rs/
+
+## Maintenance
+
+The [riot-sys] and [riot-wrappers] crates are currently maintained as parts of the RIOT project.
+While being released via crates.io on demand,
+usually RIOT uses a fixed version from the git repositories that are [easily updated].
+
+The autogenerated bindings of the C API are slightly stricter than C's API,
+and thus occasionally require additional work when C APIs change subtly.
+The riot-sys crate takes the brunt of these changes --
+it changes automatically, and no attempt is currently made
+to reflect these changes in a SemVer compatible manner.
+The riot-wrappers crate smooths this out,
+and provides an API that aims to be more stable than the C API.
+It does that by generously converting types that changed,
+and [introspecting generated bindings] or using [information provided by riot-sys].
+
+The typical workflow of (C-nonbreaking, Rust-breaking) API changes is as follows:
+
+- A PR subtly alters a type (eg. `uint8_t *` to `void *` in [#17990]).
+
+ Consequently, builds of Rust examples break.
+
+
+- A PR is opened on riot-wrappers to smooth over the change, like [aab605f4]
+
+ The PR is tested against current master in its CI (albeit not for the full set of boards).
+ To test whether it also works for the changed API,
+ a commit titled "REMOVEME Test with updated riot-wrappes" can be added to the original PR,
+ it alters `.cargo/config.toml` to point to the changed branch,
+ and removes any Cargo.lock files in the RIOT tree.
+
+ That PR is then merged.
+
+- The version of riot-wrappers that works both with the previous and the new code
+ is pulled into the RIOT master branch by updating the Cargo.lock files.
+ The PR can look like [#18181], and verifies that the new riot-wrappers works on all boards.
+
+ That PR is then merged.
+
+- For the next builds (up to the merging of) the original PR,
+ the REMOVEME commit can be removed.
+
+ It is good practice to rebase it onto the latest master after
+ the update to riot-wrappers has been merged,
+ as this helps keeping bisectability up.
+
+ The PR now contains no Rust specific changes, and can be merged.
+
+There are a few variations that can occur:
+
+- Sometimes casting is not enough, and a type must be extracted from a signature.
+ [See the phydat callback type change] for an example.
+
+- When neither casting nor type detection is sufficient,
+ a marker can be introduced through riot-sys,
+ it detects a keyword's presence in the source and passes it as
+ [information provided by riot-sys] to riot-wrappers.
+ [See the coap_request_ctx_t change] for an example.
+
+ In that case, a riot-sys PR is opened in parallel to the riot-wrappers PR.
+
+ This method helps keeping changes backportable easily:
+ riot-sys and riot-wrappers are expected to work with the latest released
+ version of RIOT all the time,
+ and avoid flag-day changes.
+ (Keeping riot-sys and riot-wrappers compatible with the latest release
+ is also important to retain the ability to backport fixes).
+
+- When functions are moved from being static and not being static,
+ their names go from `riot_sys::inline::name` to `riot_sys::name` (or vice versa).
+
+ riot-sys [has a list] of items that are always publicly exported directly as `riot_sys::name`,
+ just add the function there.
+
+ If non-generic types are referenced in them,
+ they go from `riot_sys::inline::my_type_t` to `riot_sys::my_type_t`.
+ The [inline_cast] function family helps making that cast a bit safer.
+
+- Things fail around atomics.
+
+ Until [C2Rust's support for atomics has improved],
+ riot-sys requires all exported headers to use the better supported `atomic_utils.h`.
+
+ If it is unavoidable that atomics are part of header files
+ (and not actually used in any static inline functions),
+ riot-sys's [atomics workarounds] can be extended as a last resort.
+
+[riot-wrappers]: https://github.com/RIOT-OS/rust-riot-wrappers/
+[riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/
+[easily updated]: https://github.com/RIOT-OS/RIOT/pull/17491#issuecomment-1143209437
+[introspecting generated bindings]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/helpers.rs#L3
+[information provided by riot-sys]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L591
+[#17990]: https://github.com/RIOT-OS/RIOT/pull/17990
+[aab605f4]: https://github.com/RIOT-OS/rust-riot-wrappers/commit/aab605f464a279608ef0a8ad2afd5ae43179e330
+[#18181]: https://github.com/RIOT-OS/RIOT/pull/18181
+[See the phydat callback type change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/6/files#diff-ccb7946e3b4122ea3ce23fa9bc54eba63d75f7a6142fd4afdd9908b1bead50e0
+[See the coap_request_ctx_t change]: https://github.com/RIOT-OS/rust-riot-wrappers/pull/4/files
+[has a list]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/build.rs#L533
+[inline_cast]: https://github.com/RIOT-OS/rust-riot-wrappers/blob/db9d163e3eddcb7154edcf25db7207e4123964ee/src/lib.rs#L68
+[C2Rust's support for atomics has improved]: https://github.com/immunant/c2rust/issues/436
+[atomics workarounds]: https://github.com/RIOT-OS/rust-riot-sys/blob/525b2384a3541d4879a5f3845ee6241243c29a78/riot-c2rust.h#L79
diff --git a/doc/starlight/astro.config.mjs b/doc/starlight/astro.config.mjs
index bac0e62d36..914a5f4d6b 100644
--- a/doc/starlight/astro.config.mjs
+++ b/doc/starlight/astro.config.mjs
@@ -73,6 +73,13 @@ export default defineConfig({
"c_tutorials/saul",
],
},
+ {
+ label: "Rust Basics",
+ items: [
+ "rust_tutorials/rust_in_riot",
+ "rust_tutorials/create_project",
+ ],
+ },
],
},
{