aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDominic <[email protected]>2024-03-27 16:30:32 +0100
committerDominic <[email protected]>2024-04-04 13:22:52 +0200
commit8fbd21d2161caaf3d52ad60db1bb2fd0ea91e6f9 (patch)
tree1b6944561bf01d91f09c4238bd51a97f2d59b91c
parenta678b4850c6d5db449378ede28638b86fe2c0d39 (diff)
Add multiprio example for stm32h7 inspired by stm32f4
-rw-r--r--examples/stm32h7/Cargo.toml4
-rw-r--r--examples/stm32h7/src/bin/multiprio.rs145
2 files changed, 147 insertions, 2 deletions
diff --git a/examples/stm32h7/Cargo.toml b/examples/stm32h7/Cargo.toml
index d9ea2626d..84a89b378 100644
--- a/examples/stm32h7/Cargo.toml
+++ b/examples/stm32h7/Cargo.toml
@@ -6,9 +6,9 @@ license = "MIT OR Apache-2.0"
6 6
7[dependencies] 7[dependencies]
8# Change stm32h743bi to your chip name, if necessary. 8# Change stm32h743bi to your chip name, if necessary.
9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-any", "exti", "memory-x", "unstable-pac", "chrono"] } 9embassy-stm32 = { version = "0.1.0", path = "../../embassy-stm32", features = ["defmt", "stm32h743bi", "time-driver-tim2", "exti", "memory-x", "unstable-pac", "chrono"] }
10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] } 10embassy-sync = { version = "0.5.0", path = "../../embassy-sync", features = ["defmt"] }
11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "defmt", "integrated-timers"] } 11embassy-executor = { version = "0.5.0", path = "../../embassy-executor", features = ["task-arena-size-32768", "arch-cortex-m", "executor-thread", "executor-interrupt", "defmt", "integrated-timers"] }
12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] } 12embassy-time = { version = "0.3.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime", "tick-hz-32_768"] }
13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] } 13embassy-net = { version = "0.4.0", path = "../../embassy-net", features = ["defmt", "tcp", "dhcpv4", "medium-ethernet", "proto-ipv6", "dns"] }
14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] } 14embassy-usb = { version = "0.1.0", path = "../../embassy-usb", features = ["defmt"] }
diff --git a/examples/stm32h7/src/bin/multiprio.rs b/examples/stm32h7/src/bin/multiprio.rs
new file mode 100644
index 000000000..73f8dd092
--- /dev/null
+++ b/examples/stm32h7/src/bin/multiprio.rs
@@ -0,0 +1,145 @@
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
59use cortex_m_rt::entry;
60use defmt::*;
61use embassy_executor::{Executor, InterruptExecutor};
62use embassy_stm32::interrupt;
63use embassy_stm32::interrupt::{InterruptExt, Priority};
64use embassy_time::{Instant, Timer};
65use static_cell::StaticCell;
66use {defmt_rtt as _, panic_probe as _};
67
68#[embassy_executor::task]
69async fn run_high() {
70 loop {
71 info!(" [high] tick!");
72 Timer::after_ticks(27374).await;
73 }
74}
75
76#[embassy_executor::task]
77async fn run_med() {
78 loop {
79 let start = Instant::now();
80 info!(" [med] Starting long computation");
81
82 // Spin-wait to simulate a long CPU computation
83 cortex_m::asm::delay(128_000_000); // ~1 second
84
85 let end = Instant::now();
86 let ms = end.duration_since(start).as_ticks() / 33;
87 info!(" [med] done in {} ms", ms);
88
89 Timer::after_ticks(23421).await;
90 }
91}
92
93#[embassy_executor::task]
94async fn run_low() {
95 loop {
96 let start = Instant::now();
97 info!("[low] Starting long computation");
98
99 // Spin-wait to simulate a long CPU computation
100 cortex_m::asm::delay(256_000_000); // ~2 seconds
101
102 let end = Instant::now();
103 let ms = end.duration_since(start).as_ticks() / 33;
104 info!("[low] done in {} ms", ms);
105
106 Timer::after_ticks(32983).await;
107 }
108}
109
110static EXECUTOR_HIGH: InterruptExecutor = InterruptExecutor::new();
111static EXECUTOR_MED: InterruptExecutor = InterruptExecutor::new();
112static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
113
114#[interrupt]
115unsafe fn UART4() {
116 EXECUTOR_HIGH.on_interrupt()
117}
118
119#[interrupt]
120unsafe fn UART5() {
121 EXECUTOR_MED.on_interrupt()
122}
123
124#[entry]
125fn main() -> ! {
126 info!("Hello World!");
127
128 let _p = embassy_stm32::init(Default::default());
129
130 // High-priority executor: UART4, priority level 6
131 interrupt::UART4.set_priority(Priority::P6);
132 let spawner = EXECUTOR_HIGH.start(interrupt::UART4);
133 unwrap!(spawner.spawn(run_high()));
134
135 // Medium-priority executor: UART5, priority level 7
136 interrupt::UART5.set_priority(Priority::P7);
137 let spawner = EXECUTOR_MED.start(interrupt::UART5);
138 unwrap!(spawner.spawn(run_med()));
139
140 // Low priority executor: runs in thread mode, using WFE/SEV
141 let executor = EXECUTOR_LOW.init(Executor::new());
142 executor.run(|spawner| {
143 unwrap!(spawner.spawn(run_low()));
144 });
145}