aboutsummaryrefslogtreecommitdiff
path: root/examples/src/bin/multiprio.rs
diff options
context:
space:
mode:
Diffstat (limited to 'examples/src/bin/multiprio.rs')
-rw-r--r--examples/src/bin/multiprio.rs185
1 files changed, 185 insertions, 0 deletions
diff --git a/examples/src/bin/multiprio.rs b/examples/src/bin/multiprio.rs
new file mode 100644
index 000000000..ed170c581
--- /dev/null
+++ b/examples/src/bin/multiprio.rs
@@ -0,0 +1,185 @@
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(type_alias_impl_trait)]
59
60#[path = "../example_common.rs"]
61mod example_common;
62use example_common::*;
63
64use core::mem::MaybeUninit;
65use cortex_m_rt::entry;
66use embassy::executor::{task, Executor};
67use embassy::time::{Duration, Instant, Timer};
68use embassy_nrf::{interrupt, pac, rtc};
69use nrf52840_hal::clocks;
70
71#[task]
72async fn run_high() {
73 loop {
74 info!(" [high] tick!");
75 Timer::after(Duration::from_ticks(27374)).await;
76 }
77}
78
79#[task]
80async fn run_med() {
81 loop {
82 let start = Instant::now();
83 info!(" [med] Starting long computation");
84
85 // Spin-wait to simulate a long CPU computation
86 cortex_m::asm::delay(32_000_000); // ~1 second
87
88 let end = Instant::now();
89 let ms = end.duration_since(start).into_ticks() / 33;
90 info!(" [med] done in {:u32} ms", ms);
91
92 Timer::after(Duration::from_ticks(23421)).await;
93 }
94}
95
96#[task]
97async fn run_low() {
98 loop {
99 let start = Instant::now();
100 info!("[low] Starting long computation");
101
102 // Spin-wait to simulate a long CPU computation
103 cortex_m::asm::delay(64_000_000); // ~2 seconds
104
105 let end = Instant::now();
106 let ms = end.duration_since(start).into_ticks() / 33;
107 info!("[low] done in {:u32} ms", ms);
108
109 Timer::after(Duration::from_ticks(32983)).await;
110 }
111}
112
113static mut RTC: MaybeUninit<rtc::RTC<pac::RTC1>> = MaybeUninit::uninit();
114static mut EXECUTOR_LOW: MaybeUninit<Executor<rtc::Alarm<pac::RTC1>>> = MaybeUninit::uninit();
115static mut EXECUTOR_MED: MaybeUninit<Executor<rtc::Alarm<pac::RTC1>>> = MaybeUninit::uninit();
116static mut EXECUTOR_HIGH: MaybeUninit<Executor<rtc::Alarm<pac::RTC1>>> = MaybeUninit::uninit();
117
118#[entry]
119fn main() -> ! {
120 info!("Hello World!");
121
122 let p = embassy_nrf::pac::Peripherals::take().dewrap();
123
124 clocks::Clocks::new(p.CLOCK)
125 .enable_ext_hfosc()
126 .set_lfclk_src_external(clocks::LfOscConfiguration::NoExternalNoBypass)
127 .start_lfclk();
128
129 let rtc: &'static _ = unsafe {
130 let ptr = RTC.as_mut_ptr();
131 ptr.write(rtc::RTC::new(p.RTC1));
132 &*ptr
133 };
134
135 rtc.start();
136 unsafe { embassy::time::set_clock(rtc) };
137
138 let executor_low: &'static _ = unsafe {
139 let ptr = EXECUTOR_LOW.as_mut_ptr();
140 ptr.write(Executor::new(rtc.alarm0(), cortex_m::asm::sev));
141 &*ptr
142 };
143
144 let executor_med: &'static _ = unsafe {
145 let ptr = EXECUTOR_MED.as_mut_ptr();
146 ptr.write(Executor::new(rtc.alarm1(), || {
147 interrupt::pend(interrupt::SWI0_EGU0)
148 }));
149 &*ptr
150 };
151
152 let executor_high: &'static _ = unsafe {
153 let ptr = EXECUTOR_HIGH.as_mut_ptr();
154 ptr.write(Executor::new(rtc.alarm2(), || {
155 interrupt::pend(interrupt::SWI1_EGU1)
156 }));
157 &*ptr
158 };
159
160 interrupt::set_priority(interrupt::SWI0_EGU0, interrupt::Priority::Level7);
161 interrupt::set_priority(interrupt::SWI1_EGU1, interrupt::Priority::Level6);
162 interrupt::enable(interrupt::SWI0_EGU0);
163 interrupt::enable(interrupt::SWI1_EGU1);
164
165 unsafe {
166 executor_low.spawn(run_low()).dewrap();
167 executor_med.spawn(run_med()).dewrap();
168 executor_high.spawn(run_high()).dewrap();
169
170 loop {
171 executor_low.run();
172 cortex_m::asm::wfe();
173 }
174 }
175}
176
177#[interrupt]
178unsafe fn SWI0_EGU0() {
179 EXECUTOR_MED.as_ptr().as_ref().unwrap().run()
180}
181
182#[interrupt]
183unsafe fn SWI1_EGU1() {
184 EXECUTOR_HIGH.as_ptr().as_ref().unwrap().run()
185}