Framework
rtic-rs/rtic avatar
rtic-rs/rtic

RTIC: A Hardware-Accelerated Rust RTOS for Cortex-M

Real-Time Interrupt-driven Concurrency (RTIC) framework for ARM Cortex-M microcontrollers

2,411 stars267 forksRustApache-2.0

At a glance

What is it?
RTIC turns Cortex-M interrupt priorities into a compile-time scheduler. Here is what it does well, where the documentation leaves gaps, and how it compares with Embassy.
Who is it for?
RTIC suits teams shipping fixed-workload firmware on Cortex-M who want hardware preemption and a compile-time deadlock guarantee without an RTOS kernel or a heap. It is the wrong tool for runtime-configurable task sets, for RISC-V targets whose backend limitations you have not read, and for anyone expecting an async executor.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 2 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

What RTIC Solves for Bare-Metal Rust Developers

Writing interrupt handlers on a Cortex-M means sharing data between an ISR and the main loop while keeping the compiler happy. The usual answer is a critical section that disables interrupts, or a mutex that can deadlock. RTIC takes a different route: it treats the NVIC (the nested vectored interrupt controller built into every Cortex-M core) as the scheduler, and generates the resource locking code from a declarative macro at compile time.

RTIC stands for Real-Time Interrupt-driven Concurrency. The README describes it as "a concurrency framework for building real-time systems" and calls it "the hardware accelerated Rust RTOS". The audience is embedded engineers who already write Rust for microcontrollers and want preemptive multitasking without pulling in a full RTOS kernel, a heap allocator, or a dynamic task table.

The claim that matters most is this one: "Deadlock free execution guaranteed at compile time." That is a stronger statement than what the standard library Mutex provides, because the guarantee comes from static analysis of priorities rather than from runtime behaviour. The README also notes that all tasks share a single call stack and that there is no hard dependency on a dynamic memory allocator. On a part with 20 KB of RAM, that distinction decides whether a framework is usable at all.

How the Priority-Based Scheduler Works

The mechanism is priority-based critical sections. Each task in an RTIC application is bound to an interrupt source or spawned by software, and each carries a priority. When a task touches a shared resource, the framework computes the ceiling priority for that resource and raises the running task's priority to it for the duration of the access. On Cortex-M this maps onto the hardware BASEPRI register, so the lock is enforced by masking interrupts at or below a threshold rather than by a software flag.

The README lists the consequences directly: "The task scheduler has minimal software footprint; the hardware does the bulk of the scheduling." That is why RTIC can promise deadlock freedom. Priority ceiling protocols cannot deadlock, and no runtime bookkeeping is needed to detect one.

Beyond tasks and resources, the framework provides message passing to software tasks at spawn time, and a timer queue. The timer queue lets software tasks be delayed or scheduled to resume at a future time, which the README suggests for periodic work. The underlying design comes from the RTFM language created by the Embedded Systems group at Luleå University of Technology; the README cites two papers, one on static priority SRP kernel primitives and one on abstract timers for the Cortex-M family.

The repository is a workspace, not a single crate. Top-level entries include rtic, rtic-macros, rtic-sync, rtic-common, rtic-monotonics, and rtic-time. The macro crate is where the code generation lives; rtic-monotonics and rtic-time handle the time base that the timer queue depends on. That split matters when you read the changelog for a breaking change, because the crate you depend on may not be the crate that changed.

Getting RTIC and Running a First Task

The README does not contain an install section. It points to the book at rtic.rs for user documentation, to rtic.rs/stable/api/ for the API reference, and to the rtic-examples repository for community examples. The crate itself is published on crates.io, as the badge in the README indicates, so adding it to a project means a normal Cargo dependency. The examples directory in the repository holds per-board projects such as stm32f411_rtc_interrupt and rp2040_local_i2c_init that are the closest thing to a starting template.

What the README does document is how the project checks itself. It states that to check all tests locally you need QEMU, and ESP32 QEMU if you want that target, then run:

console
$ cargo xtask ci

The README says this is the command that checks all `tests` locally. To format code before a pull request, which the README notes is already included in `ci` above:

console
$ cargo xtask fmt

For lints:

console
$ cargo xtask clippy

The README adds "and so on" and directs readers to `cargo xtask --help` for all options. Running these in a clone is the project's own definition of a working checkout, and it is also the fastest way to see the macro expansion behaviour on your host before you touch hardware. Beyond that, the README gives no application-level code sample, so the first real task definition has to come from the book or from the examples repository rather than from this page.

Where RTIC Is the Wrong Choice

RTIC is a static framework, and static means you decide the task set at compile time. There is no runtime task creation, no dynamic priority assignment, and no scheduler you can reconfigure after boot. If your application needs to load behaviour at runtime, or if task priorities depend on data that only arrives after startup, RTIC's model fights you.

The single shared call stack is the other constraint. The README presents it as an efficiency win, and it is: no per-task stack allocation means RAM use stays flat as you add tasks. But a shared stack means the worst case stack depth is the sum of the deepest path through any chain of preemptions, not the maximum of independent tasks. On a device with a small RAM budget you have to reason about that sum, and the README does not describe a stack analysis tool. The claim that the model is "amenable to known WCET analysis and scheduling analysis techniques" points at the academic papers, not at a tool shipped in this repository.

RISC-V support comes with a caveat the README states plainly: "Most RISC-V devices are supported", and it directs readers to the book to learn about the backends, "their particularities, and their limitations". If you are targeting a RISC-V part, read that chapter before committing, because the support is not described as uniform across devices the way Cortex-M support is.

Finally, the README documents no rollback or migration path for the macro syntax. When the app macro changes between versions, that is a source-level migration you perform by hand. The RFC repository exists precisely because "New features and big changes should go through the RFC process", which tells you the project expects its own surface to move.

RTIC vs Embassy and vs a Conventional RTOS

The comparison people reach for is RTIC vs Embassy, and the difference is architectural rather than cosmetic. Embassy is built around async/await and an executor that polls futures; tasks are futures, and yielding is cooperative. RTIC has no executor and no futures in its task model. Tasks are functions bound to interrupt vectors, and preemption is done by the NVIC. RTIC's README describes the task model as "event triggered (fired in response to asynchronous stimuli) or spawned by the application on demand", with "prioritization of tasks and, thus, preemptive multitasking".

That changes what you can prove. Cooperative scheduling in Embassy means a task that does not await blocks everything at its priority level. RTIC's hardware preemption means a higher-priority interrupt runs regardless of what a lower-priority task is doing, and the priority ceiling protocol keeps shared data consistent. If your reasoning is built on interrupt latency and WCET, RTIC's model maps onto it more directly.

The other comparison is RTIC vs a traditional RTOS such as FreeRTOS or Zephyr. A conventional RTOS gives you dynamic tasks, a heap, and a scheduler running on a tick. RTIC gives you none of those by default. The README's framing is that the hardware does the scheduling and the software footprint is minimal. For a device with a fixed, known workload, that trade is favourable. For a device that runs a filesystem, a network stack and an application, it is not.

Both comparisons come with a shared cost: RTIC is a Rust framework. There is no C API and no path to reuse an existing C driver stack inside a task without writing bindings.

Maintenance, Licensing and Upgrade Cost

The repository is not archived, and the last push was on 2026-09-28. The README links to a Matrix room and to weekly meeting minutes on HackMD, and the project runs an RFC process for new features and big changes. That is a project with governance, not a single-maintainer experiment.

Upgrade cost concentrates in the proc macro. Because the app macro generates the resource locking and the interrupt bindings, a change in macro syntax touches every task declaration in your codebase. The workspace split means a bump to rtic-monotonics or rtic-time can land separately from a bump to rtic itself, so read each crate's release notes rather than assuming a single version number covers the whole framework. The repository metadata retrieved for this review contains no release notes, so check crates.io and the changelog before upgrading a production firmware image.

Licensing is dual. The README states that all source code, including code snippets, is licensed under either Apache License 2.0 or the MIT license, at your option. The written prose in the book is separate and falls under Creative Commons CC-BY-SA v4.0. Contributions are accepted under the Apache-2.0 terms unless stated otherwise. The practical implication for a commercial product is that the source code path is permissive; the book's CC-BY-SA terms apply to the documentation text, not to your firmware. This is a description of what the files say, not legal advice.

Who Should Adopt RTIC

Adopt RTIC if your target is a Cortex-M part, your task set is known at compile time, and you want preemptive priorities without an RTOS kernel, a heap, or a per-task stack. The compile-time deadlock guarantee is the reason to pick it over hand-rolled critical sections, and the single shared stack is the reason it fits on small parts.

Do not adopt it if you need runtime task creation, if you are targeting a RISC-V device and have not read the backend limitations in the book, or if you expect to reuse a large C driver stack. Do not adopt it expecting an async executor; that is a different framework with a different execution model.

Before committing, verify three things against the version you actually pull. First, open the API reference at rtic.rs/stable/api/ and confirm the current app macro syntax, since the README shows none. Second, check the book's RISC-V chapter if that is your target. Third, run `cargo xtask ci` in a clone of the repository with QEMU installed to confirm the test suite passes on your host, because that is the project's own definition of a working checkout.

Editorial conclusion

RTIC suits teams shipping fixed-workload firmware on Cortex-M who want hardware preemption and a compile-time deadlock guarantee without an RTOS kernel or a heap. It is the wrong tool for runtime-configurable task sets, for RISC-V targets whose backend limitations you have not read, and for anyone expecting an async executor. Before adopting, verify the app macro syntax in the API reference at rtic.rs/stable/api/ for the exact crate version you pull, read the RISC-V chapter of the book if that is your target, and run cargo xtask ci in a clone with QEMU installed.

Frequently asked questions

What does RTIC stand for?

RTIC stands for Real-Time Interrupt-driven Concurrency. The README uses that expansion as the project's full name and describes the framework as a concurrency framework for building real-time systems.

What is RTIC in Rust?

RTIC is a Rust concurrency framework for real-time systems, described in the README as the hardware accelerated Rust RTOS. It provides tasks as the unit of concurrency, message passing, a timer queue, and priority-based critical sections, and it supports all Cortex-M devices and most RISC-V devices.

How do you install RTIC?

The README does not give install steps. It points to the book at rtic.rs for user documentation and to the rtic-examples repository for community examples, and the crate is published on crates.io, so it is added as a Cargo dependency.

Does RTIC work on RISC-V microcontrollers?

The README states that most RISC-V devices are supported and directs readers to the RTIC book to learn about the RISC-V backends, their particularities, and their limitations. Cortex-M support is described as full.

How does RTIC guarantee deadlock-free execution?

The README states that deadlock-free execution is guaranteed at compile time, a stronger guarantee than the standard Mutex abstraction provides. It also states that memory sharing uses fine-grained priority-based critical sections, which is the mechanism behind that guarantee.

Official sources

  1. Issues
  2. License: Apache-2.0
  3. Project website
  4. README
  5. rtic-rs/rtic on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/rtic-rs-rtic.svg)](https://hysenlabs.com/projects/rtic-rs-rtic)