aboutsummaryrefslogtreecommitdiff
path: root/examples
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2024-05-09 10:31:15 +0000
committerGitHub <[email protected]>2024-05-09 10:31:15 +0000
commita7eb9bced1daa6e5f9bdf2c888d5920e33786b0b (patch)
tree9a7e48d5acd5e156316daa240a791fa295841c48 /examples
parent4a159453956464b534b7cbf38f5d17b9a3e36bb7 (diff)
parent108bfae30d1857ebeb3764a6a110979efc6cf47e (diff)
Merge pull request #2923 from kalkyl/interrupt
rp: Add raw interrupt handler example
Diffstat (limited to 'examples')
-rw-r--r--examples/rp/Cargo.toml1
-rw-r--r--examples/rp/src/bin/interrupt.rs95
2 files changed, 96 insertions, 0 deletions
diff --git a/examples/rp/Cargo.toml b/examples/rp/Cargo.toml
index ae6746dce..8162e4dcb 100644
--- a/examples/rp/Cargo.toml
+++ b/examples/rp/Cargo.toml
@@ -27,6 +27,7 @@ fixed-macro = "1.2"
27#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] } 27#cortex-m = { version = "0.7.6", features = ["critical-section-single-core"] }
28cortex-m = { version = "0.7.6", features = ["inline-asm"] } 28cortex-m = { version = "0.7.6", features = ["inline-asm"] }
29cortex-m-rt = "0.7.0" 29cortex-m-rt = "0.7.0"
30critical-section = "1.1"
30panic-probe = { version = "0.3", features = ["print-defmt"] } 31panic-probe = { version = "0.3", features = ["print-defmt"] }
31display-interface-spi = "0.4.1" 32display-interface-spi = "0.4.1"
32embedded-graphics = "0.7.1" 33embedded-graphics = "0.7.1"
diff --git a/examples/rp/src/bin/interrupt.rs b/examples/rp/src/bin/interrupt.rs
new file mode 100644
index 000000000..d334d35d7
--- /dev/null
+++ b/examples/rp/src/bin/interrupt.rs
@@ -0,0 +1,95 @@
1//! This example shows how you can use raw interrupt handlers alongside embassy.
2//! The example also showcases some of the options available for sharing resources/data.
3//!
4//! In the example, an ADC reading is triggered every time the PWM wraps around.
5//! The sample data is sent down a channel, to be processed inside a low priority task.
6//! The processed data is then used to adjust the PWM duty cycle, once every second.
7
8#![no_std]
9#![no_main]
10
11use core::cell::{Cell, RefCell};
12
13use defmt::*;
14use embassy_executor::Spawner;
15use embassy_rp::adc::{self, Adc, Blocking};
16use embassy_rp::gpio::Pull;
17use embassy_rp::interrupt;
18use embassy_rp::peripherals::PWM_SLICE4;
19use embassy_rp::pwm::{Config, Pwm};
20use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
21use embassy_sync::blocking_mutex::Mutex;
22use embassy_sync::channel::Channel;
23use embassy_time::{Duration, Ticker};
24use portable_atomic::{AtomicU32, Ordering};
25use static_cell::StaticCell;
26use {defmt_rtt as _, panic_probe as _};
27
28static COUNTER: AtomicU32 = AtomicU32::new(0);
29static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm<PWM_SLICE4>>>> = Mutex::new(RefCell::new(None));
30static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
31 Mutex::new(RefCell::new(None));
32static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
33
34#[embassy_executor::main]
35async fn main(spawner: Spawner) {
36 embassy_rp::pac::SIO.spinlock(31).write_value(1);
37 let p = embassy_rp::init(Default::default());
38
39 let adc = Adc::new_blocking(p.ADC, Default::default());
40 let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
41 ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
42
43 let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
44 PWM.lock(|p| p.borrow_mut().replace(pwm));
45
46 // Enable the interrupt for pwm slice 4
47 embassy_rp::pac::PWM.inte().modify(|w| w.set_ch4(true));
48 unsafe {
49 cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP);
50 }
51
52 // Tasks require their resources to have 'static lifetime
53 // No Mutex needed when sharing within the same executor/prio level
54 static AVG: StaticCell<Cell<u32>> = StaticCell::new();
55 let avg = AVG.init(Default::default());
56 spawner.must_spawn(processing(avg));
57
58 let mut ticker = Ticker::every(Duration::from_secs(1));
59 loop {
60 ticker.next().await;
61 let freq = COUNTER.swap(0, Ordering::Relaxed);
62 info!("pwm freq: {:?} Hz", freq);
63 info!("adc average: {:?}", avg.get());
64
65 // Update the pwm duty cycle, based on the averaged adc reading
66 let mut config = Config::default();
67 config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
68 PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
69 }
70}
71
72#[embassy_executor::task]
73async fn processing(avg: &'static Cell<u32>) {
74 let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
75 loop {
76 let val = ADC_VALUES.receive().await;
77 buffer.write(val);
78 let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
79 avg.set(sum / buffer.len() as u32);
80 }
81}
82
83#[interrupt]
84fn PWM_IRQ_WRAP() {
85 critical_section::with(|cs| {
86 let mut adc = ADC.borrow(cs).borrow_mut();
87 let (adc, p26) = adc.as_mut().unwrap();
88 let val = adc.blocking_read(p26).unwrap();
89 ADC_VALUES.try_send(val).ok();
90
91 // Clear the interrupt, so we don't immediately re-enter this irq handler
92 PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped();
93 });
94 COUNTER.fetch_add(1, Ordering::Relaxed);
95}