aboutsummaryrefslogtreecommitdiff
path: root/examples/rp235x/src/bin/sharing.rs
diff options
context:
space:
mode:
authorCurly <[email protected]>2025-02-23 07:33:58 -0800
committerCurly <[email protected]>2025-02-23 07:33:58 -0800
commit3932835998802fc3abf7cce4f736e072858ebfd1 (patch)
tree5dd714b99bc74a03556c58809237c88691c293bb /examples/rp235x/src/bin/sharing.rs
parentc3c67db93e627a4fafe5e1a1123e5cbb4abafe47 (diff)
rename `rp23` (?) folder to `rp235x`; fix `ci.sh` to use `rp235x` folder
Diffstat (limited to 'examples/rp235x/src/bin/sharing.rs')
-rw-r--r--examples/rp235x/src/bin/sharing.rs150
1 files changed, 150 insertions, 0 deletions
diff --git a/examples/rp235x/src/bin/sharing.rs b/examples/rp235x/src/bin/sharing.rs
new file mode 100644
index 000000000..5416e20ce
--- /dev/null
+++ b/examples/rp235x/src/bin/sharing.rs
@@ -0,0 +1,150 @@
1//! This example shows some common strategies for sharing resources between tasks.
2//!
3//! We demonstrate five different ways of sharing, covering different use cases:
4//! - Atomics: This method is used for simple values, such as bool and u8..u32
5//! - Blocking Mutex: This is used for sharing non-async things, using Cell/RefCell for interior mutability.
6//! - Async Mutex: This is used for sharing async resources, where you need to hold the lock across await points.
7//! The async Mutex has interior mutability built-in, so no RefCell is needed.
8//! - Cell: For sharing Copy types between tasks running on the same executor.
9//! - RefCell: When you want &mut access to a value shared between tasks running on the same executor.
10//!
11//! More information: https://embassy.dev/book/#_sharing_peripherals_between_tasks
12
13#![no_std]
14#![no_main]
15
16use core::cell::{Cell, RefCell};
17use core::sync::atomic::{AtomicU32, Ordering};
18
19use cortex_m_rt::entry;
20use defmt::info;
21use embassy_executor::{Executor, InterruptExecutor};
22use embassy_rp::clocks::RoscRng;
23use embassy_rp::interrupt::{InterruptExt, Priority};
24use embassy_rp::peripherals::UART0;
25use embassy_rp::uart::{self, InterruptHandler, UartTx};
26use embassy_rp::{bind_interrupts, interrupt};
27use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
28use embassy_sync::{blocking_mutex, mutex};
29use embassy_time::{Duration, Ticker};
30use rand::RngCore;
31use static_cell::{ConstStaticCell, StaticCell};
32use {defmt_rtt as _, panic_probe as _};
33
34type UartAsyncMutex = mutex::Mutex<CriticalSectionRawMutex, UartTx<'static, UART0, uart::Async>>;
35
36struct MyType {
37 inner: u32,
38}
39
40static EXECUTOR_HI: InterruptExecutor = InterruptExecutor::new();
41static EXECUTOR_LOW: StaticCell<Executor> = StaticCell::new();
42
43// Use Atomics for simple values
44static ATOMIC: AtomicU32 = AtomicU32::new(0);
45
46// Use blocking Mutex with Cell/RefCell for sharing non-async things
47static MUTEX_BLOCKING: blocking_mutex::Mutex<CriticalSectionRawMutex, RefCell<MyType>> =
48 blocking_mutex::Mutex::new(RefCell::new(MyType { inner: 0 }));
49
50bind_interrupts!(struct Irqs {
51 UART0_IRQ => InterruptHandler<UART0>;
52});
53
54#[interrupt]
55unsafe fn SWI_IRQ_0() {
56 EXECUTOR_HI.on_interrupt()
57}
58
59#[entry]
60fn main() -> ! {
61 let p = embassy_rp::init(Default::default());
62 info!("Here we go!");
63
64 let uart = UartTx::new(p.UART0, p.PIN_0, p.DMA_CH0, uart::Config::default());
65 // Use the async Mutex for sharing async things (built-in interior mutability)
66 static UART: StaticCell<UartAsyncMutex> = StaticCell::new();
67 let uart = UART.init(mutex::Mutex::new(uart));
68
69 // High-priority executor: runs in interrupt mode
70 interrupt::SWI_IRQ_0.set_priority(Priority::P3);
71 let spawner = EXECUTOR_HI.start(interrupt::SWI_IRQ_0);
72 spawner.must_spawn(task_a(uart));
73
74 // Low priority executor: runs in thread mode
75 let executor = EXECUTOR_LOW.init(Executor::new());
76 executor.run(|spawner| {
77 // No Mutex needed when sharing between tasks running on the same executor
78
79 // Use Cell for Copy-types
80 static CELL: ConstStaticCell<Cell<[u8; 4]>> = ConstStaticCell::new(Cell::new([0; 4]));
81 let cell = CELL.take();
82
83 // Use RefCell for &mut access
84 static REF_CELL: ConstStaticCell<RefCell<MyType>> = ConstStaticCell::new(RefCell::new(MyType { inner: 0 }));
85 let ref_cell = REF_CELL.take();
86
87 spawner.must_spawn(task_b(uart, cell, ref_cell));
88 spawner.must_spawn(task_c(cell, ref_cell));
89 });
90}
91
92#[embassy_executor::task]
93async fn task_a(uart: &'static UartAsyncMutex) {
94 let mut ticker = Ticker::every(Duration::from_secs(1));
95 loop {
96 let random = RoscRng.next_u32();
97
98 {
99 let mut uart = uart.lock().await;
100 uart.write(b"task a").await.unwrap();
101 // The uart lock is released when it goes out of scope
102 }
103
104 ATOMIC.store(random, Ordering::Relaxed);
105
106 MUTEX_BLOCKING.lock(|x| x.borrow_mut().inner = random);
107
108 ticker.next().await;
109 }
110}
111
112#[embassy_executor::task]
113async fn task_b(uart: &'static UartAsyncMutex, cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
114 let mut ticker = Ticker::every(Duration::from_secs(1));
115 loop {
116 let random = RoscRng.next_u32();
117
118 uart.lock().await.write(b"task b").await.unwrap();
119
120 cell.set(random.to_be_bytes());
121
122 ref_cell.borrow_mut().inner = random;
123
124 ticker.next().await;
125 }
126}
127
128#[embassy_executor::task]
129async fn task_c(cell: &'static Cell<[u8; 4]>, ref_cell: &'static RefCell<MyType>) {
130 let mut ticker = Ticker::every(Duration::from_secs(1));
131 loop {
132 info!("=======================");
133
134 let atomic_val = ATOMIC.load(Ordering::Relaxed);
135 info!("atomic: {}", atomic_val);
136
137 MUTEX_BLOCKING.lock(|x| {
138 let val = x.borrow().inner;
139 info!("blocking mutex: {}", val);
140 });
141
142 let cell_val = cell.get();
143 info!("cell: {:?}", cell_val);
144
145 let ref_cell_val = ref_cell.borrow().inner;
146 info!("ref_cell: {:?}", ref_cell_val);
147
148 ticker.next().await;
149 }
150}