-
Notifications
You must be signed in to change notification settings - Fork 902
/
Copy pathmultiprio.rs
145 lines (126 loc) · 4.36 KB
/
multiprio.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! This example showcases how to create multiple Executor instances to run tasks at
//! different priority levels.
//!
//! Low priority executor runs in thread mode (not interrupt), and uses `sev` for signaling
//! there's work in the queue, and `wfe` for waiting for work.
//!
//! Medium and high priority executors run in two interrupts with different priorities.
//! Signaling work is done by pending the interrupt. No "waiting" needs to be done explicitly, since
//! when there's work the interrupt will trigger and run the executor.
//!
//! Sample output below. Note that high priority ticks can interrupt everything else, and
//! medium priority computations can interrupt low priority computations, making them to appear
//! to take significantly longer time.
//!
//! ```not_rust
//! [med] Starting long computation
//! [med] done in 992 ms
//! [high] tick!
//! [low] Starting long computation
//! [med] Starting long computation
//! [high] tick!
//! [high] tick!
//! [med] done in 993 ms
//! [med] Starting long computation
//! [high] tick!
//! [high] tick!
//! [med] done in 993 ms
//! [low] done in 3972 ms
//! [med] Starting long computation
//! [high] tick!
//! [high] tick!
//! [med] done in 993 ms
//! ```
//!
//! For comparison, try changing the code so all 3 tasks get spawned on the low priority executor.
//! You will get an output like the following. Note that no computation is ever interrupted.
//!
//! ```not_rust
//! [high] tick!
//! [med] Starting long computation
//! [med] done in 496 ms
//! [low] Starting long computation
//! [low] done in 992 ms
//! [med] Starting long computation
//! [med] done in 496 ms
//! [high] tick!
//! [low] Starting long computation
//! [low] done in 992 ms
//! [high] tick!
//! [med] Starting long computation
//! [med] done in 496 ms
//! [high] tick!
//! ```
//!
#![no_std]
#![no_main]
use cortex_m_rt::entry;
use defmt::{info, unwrap};
use embassy_executor::{Executor, InterruptExecutor};
use embassy_nrf::interrupt;
use embassy_nrf::interrupt::{InterruptExt, Priority};
use embassy_time::{Instant, Timer};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
#[embassy_executor::task]
async fn run_high() {
loop {
info!(" [high] tick!");
Timer::after_ticks(27374).await;
}
}
#[embassy_executor::task]
async fn run_med() {
loop {
let start = Instant::now();
info!(" [med] Starting long computation");
// Spin-wait to simulate a long CPU computation
embassy_time::block_for(embassy_time::Duration::from_secs(1)); // ~1 second
let end = Instant::now();
let ms = end.duration_since(start).as_ticks() / 33;
info!(" [med] done in {} ms", ms);
Timer::after_ticks(23421).await;
}
}
#[embassy_executor::task]
async fn run_low() {
loop {
let start = Instant::now();
info!("[low] Starting long computation");
// Spin-wait to simulate a long CPU computation
embassy_time::block_for(embassy_time::Duration::from_secs(2)); // ~2 seconds
let end = Instant::now();
let ms = end.duration_since(start).as_ticks() / 33;
info!("[low] done in {} ms", ms);
Timer::after_ticks(32983).await;
}
}
static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
#[interrupt]
unsafe fn EGU1_SWI1() {
EXECUTOR_HIGH.on_interrupt()
}
#[interrupt]
unsafe fn EGU0_SWI0() {
EXECUTOR_MED.on_interrupt()
}
#[entry]
fn main() -> ! {
info!("Hello World!");
let _p = embassy_nrf::init(Default::default());
// High-priority executor: EGU1_SWI1, priority level 6
interrupt::EGU1_SWI1.set_priority(Priority::P6);
let spawner = EXECUTOR_HIGH.start(interrupt::EGU1_SWI1);
unwrap!(spawner.spawn(run_high()));
// Medium-priority executor: EGU0_SWI0, priority level 7
interrupt::EGU0_SWI0.set_priority(Priority::P7);
let spawner = EXECUTOR_MED.start(interrupt::EGU0_SWI0);
unwrap!(spawner.spawn(run_med()));
// Low priority executor: runs in thread mode, using WFE/SEV
let executor = EXECUTOR_LOW.init(Executor::new());
executor.run(|spawner| {
unwrap!(spawner.spawn(run_low()));
});
}