aboutsummaryrefslogtreecommitdiff
path: root/examples/nrf/src/bin/multiprio.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/nrf/src/bin/multiprio.rs')
-rw-r--r--examples/nrf/src/bin/multiprio.rs162
1 files changed, 162 insertions, 0 deletions
diff --git a/examples/nrf/src/bin/multiprio.rs b/examples/nrf/src/bin/multiprio.rs
new file mode 100644
index 000000000..79fa029b3
--- /dev/null
+++ b/examples/nrf/src/bin/multiprio.rs
@@ -0,0 +1,162 @@
1//! This example showcases how to create multiple Executor instances to run tasks at
2//! different priority levels.
3//!
4//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
5//! there's work in the queue, and `wfe` for waiting for work.
6//!
7//! Medium and high priority executors run in two interrupts with different priorities.
8//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
9//! when there's work the interrupt will trigger and run the executor.
10//!
11//! Sample output below. Note that high priority ticks can interrupt everything else, and
12//! medium priority computations can interrupt low priority computations, making them to appear
13//! to take significantly longer time.
14//!
15//! ```not_rust
16//! [med] Starting long computation
17//! [med] done in 992 ms
18//! [high] tick!
19//! [low] Starting long computation
20//! [med] Starting long computation
21//! [high] tick!
22//! [high] tick!
23//! [med] done in 993 ms
24//! [med] Starting long computation
25//! [high] tick!
26//! [high] tick!
27//! [med] done in 993 ms
28//! [low] done in 3972 ms
29//! [med] Starting long computation
30//! [high] tick!
31//! [high] tick!
32//! [med] done in 993 ms
33//! ```
34//!
35//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
36//! You will get an output like the following. Note that no computation is ever interrupted.
37//!
38//! ```not_rust
39//! [high] tick!
40//! [med] Starting long computation
41//! [med] done in 496 ms
42//! [low] Starting long computation
43//! [low] done in 992 ms
44//! [med] Starting long computation
45//! [med] done in 496 ms
46//! [high] tick!
47//! [low] Starting long computation
48//! [low] done in 992 ms
49//! [high] tick!
50//! [med] Starting long computation
51//! [med] done in 496 ms
52//! [high] tick!
53//! ```
54//!
55
56#![no_std]
57#![no_main]
58#![feature(min_type_alias_impl_trait)]
59#![feature(impl_trait_in_bindings)]
60#![feature(type_alias_impl_trait)]
61#![allow(incomplete_features)]
62
63#[path = "../example_common.rs"]
64mod example_common;
65use example_common::*;
66
67use cortex_m_rt::entry;
68use defmt::panic;
69use embassy::executor::{Executor, InterruptExecutor};
70use embassy::interrupt::InterruptExt;
71use embassy::time::{Duration, Instant, Timer};
72use embassy::util::Forever;
73use embassy_nrf::{interrupt, peripherals, rtc};
74
75#[embassy::task]
76async fn run_high() {
77 loop {
78 info!(" [high] tick!");
79 Timer::after(Duration::from_ticks(27374)).await;
80 }
81}
82
83#[embassy::task]
84async fn run_med() {
85 loop {
86 let start = Instant::now();
87 info!(" [med] Starting long computation");
88
89 // Spin-wait to simulate a long CPU computation
90 cortex_m::asm::delay(32_000_000); // ~1 second
91
92 let end = Instant::now();
93 let ms = end.duration_since(start).as_ticks() / 33;
94 info!(" [med] done in {} ms", ms);
95
96 Timer::after(Duration::from_ticks(23421)).await;
97 }
98}
99
100#[embassy::task]
101async fn run_low() {
102 loop {
103 let start = Instant::now();
104 info!("[low] Starting long computation");
105
106 // Spin-wait to simulate a long CPU computation
107 cortex_m::asm::delay(64_000_000); // ~2 seconds
108
109 let end = Instant::now();
110 let ms = end.duration_since(start).as_ticks() / 33;
111 info!("[low] done in {} ms", ms);
112
113 Timer::after(Duration::from_ticks(32983)).await;
114 }
115}
116
117static RTC: Forever<rtc::RTC<peripherals::RTC1>> = Forever::new();
118static ALARM_HIGH: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
119static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::SWI1_EGU1>> = Forever::new();
120static ALARM_MED: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
121static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::SWI0_EGU0>> = Forever::new();
122static ALARM_LOW: Forever<rtc::Alarm<peripherals::RTC1>> = Forever::new();
123static EXECUTOR_LOW: Forever<Executor> = Forever::new();
124
125#[entry]
126fn main() -> ! {
127 info!("Hello World!");
128
129 let p = embassy_nrf::init(Default::default());
130
131 let rtc = RTC.put(rtc::RTC::new(p.RTC1, interrupt::take!(RTC1)));
132 rtc.start();
133 unsafe { embassy::time::set_clock(rtc) };
134
135 // High-priority executor: SWI1_EGU1, priority level 6
136 let irq = interrupt::take!(SWI1_EGU1);
137 irq.set_priority(interrupt::Priority::P6);
138 let alarm = ALARM_HIGH.put(rtc.alarm2());
139 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
140 executor.set_alarm(alarm);
141 executor.start(|spawner| {
142 unwrap!(spawner.spawn(run_high()));
143 });
144
145 // Medium-priority executor: SWI0_EGU0, priority level 7
146 let irq = interrupt::take!(SWI0_EGU0);
147 irq.set_priority(interrupt::Priority::P7);
148 let alarm = ALARM_MED.put(rtc.alarm1());
149 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
150 executor.set_alarm(alarm);
151 executor.start(|spawner| {
152 unwrap!(spawner.spawn(run_med()));
153 });
154
155 // Low priority executor: runs in thread mode, using WFE/SEV
156 let alarm = ALARM_LOW.put(rtc.alarm0());
157 let executor = EXECUTOR_LOW.put(Executor::new());
158 executor.set_alarm(alarm);
159 executor.run(|spawner| {
160 unwrap!(spawner.spawn(run_low()));
161 });
162}