aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--examples/stm32f3/src/bin/multiprio.rs144
-rw-r--r--examples/stm32f4/src/bin/multiprio.rs144
2 files changed, 288 insertions, 0 deletions
diff --git a/examples/stm32f3/src/bin/multiprio.rs b/examples/stm32f3/src/bin/multiprio.rs
new file mode 100644
index 000000000..9d9754833
--- /dev/null
+++ b/examples/stm32f3/src/bin/multiprio.rs
@@ -0,0 +1,144 @@
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 cortex_m_rt::entry;
65use embassy::executor::{Executor, InterruptExecutor};
66use embassy::interrupt::InterruptExt;
67use embassy::time::{Duration, Instant, Timer};
68use embassy::util::Forever;
69use embassy_stm32::interrupt;
70
71#[embassy::task]
72async fn run_high() {
73 loop {
74 info!(" [high] tick!");
75 Timer::after(Duration::from_ticks(27374)).await;
76 }
77}
78
79#[embassy::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(8_000_000); // ~1 second
87
88 let end = Instant::now();
89 let ms = end.duration_since(start).as_ticks() / 33;
90 info!(" [med] done in {} ms", ms);
91
92 Timer::after(Duration::from_ticks(23421)).await;
93 }
94}
95
96#[embassy::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(16_000_000); // ~2 seconds
104
105 let end = Instant::now();
106 let ms = end.duration_since(start).as_ticks() / 33;
107 info!("[low] done in {} ms", ms);
108
109 Timer::after(Duration::from_ticks(32983)).await;
110 }
111}
112
113static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::UART4>> = Forever::new();
114static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::UART5>> = Forever::new();
115static EXECUTOR_LOW: Forever<Executor> = Forever::new();
116
117#[entry]
118fn main() -> ! {
119 info!("Hello World!");
120
121 let _p = embassy_stm32::init(Default::default());
122
123 // High-priority executor: SWI1_EGU1, priority level 6
124 let irq = interrupt::take!(UART4);
125 irq.set_priority(interrupt::Priority::P6);
126 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
127 executor.start(|spawner| {
128 unwrap!(spawner.spawn(run_high()));
129 });
130
131 // Medium-priority executor: SWI0_EGU0, priority level 7
132 let irq = interrupt::take!(UART5);
133 irq.set_priority(interrupt::Priority::P7);
134 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
135 executor.start(|spawner| {
136 unwrap!(spawner.spawn(run_med()));
137 });
138
139 // Low priority executor: runs in thread mode, using WFE/SEV
140 let executor = EXECUTOR_LOW.put(Executor::new());
141 executor.run(|spawner| {
142 unwrap!(spawner.spawn(run_low()));
143 });
144}
diff --git a/examples/stm32f4/src/bin/multiprio.rs b/examples/stm32f4/src/bin/multiprio.rs
new file mode 100644
index 000000000..9d9754833
--- /dev/null
+++ b/examples/stm32f4/src/bin/multiprio.rs
@@ -0,0 +1,144 @@
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 cortex_m_rt::entry;
65use embassy::executor::{Executor, InterruptExecutor};
66use embassy::interrupt::InterruptExt;
67use embassy::time::{Duration, Instant, Timer};
68use embassy::util::Forever;
69use embassy_stm32::interrupt;
70
71#[embassy::task]
72async fn run_high() {
73 loop {
74 info!(" [high] tick!");
75 Timer::after(Duration::from_ticks(27374)).await;
76 }
77}
78
79#[embassy::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(8_000_000); // ~1 second
87
88 let end = Instant::now();
89 let ms = end.duration_since(start).as_ticks() / 33;
90 info!(" [med] done in {} ms", ms);
91
92 Timer::after(Duration::from_ticks(23421)).await;
93 }
94}
95
96#[embassy::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(16_000_000); // ~2 seconds
104
105 let end = Instant::now();
106 let ms = end.duration_since(start).as_ticks() / 33;
107 info!("[low] done in {} ms", ms);
108
109 Timer::after(Duration::from_ticks(32983)).await;
110 }
111}
112
113static EXECUTOR_HIGH: Forever<InterruptExecutor<interrupt::UART4>> = Forever::new();
114static EXECUTOR_MED: Forever<InterruptExecutor<interrupt::UART5>> = Forever::new();
115static EXECUTOR_LOW: Forever<Executor> = Forever::new();
116
117#[entry]
118fn main() -> ! {
119 info!("Hello World!");
120
121 let _p = embassy_stm32::init(Default::default());
122
123 // High-priority executor: SWI1_EGU1, priority level 6
124 let irq = interrupt::take!(UART4);
125 irq.set_priority(interrupt::Priority::P6);
126 let executor = EXECUTOR_HIGH.put(InterruptExecutor::new(irq));
127 executor.start(|spawner| {
128 unwrap!(spawner.spawn(run_high()));
129 });
130
131 // Medium-priority executor: SWI0_EGU0, priority level 7
132 let irq = interrupt::take!(UART5);
133 irq.set_priority(interrupt::Priority::P7);
134 let executor = EXECUTOR_MED.put(InterruptExecutor::new(irq));
135 executor.start(|spawner| {
136 unwrap!(spawner.spawn(run_med()));
137 });
138
139 // Low priority executor: runs in thread mode, using WFE/SEV
140 let executor = EXECUTOR_LOW.put(Executor::new());
141 executor.run(|spawner| {
142 unwrap!(spawner.spawn(run_low()));
143 });
144}