aboutsummaryrefslogtreecommitdiff
path: root/examples/rp23/src/bin/interrupt.rs
diff options
context:
space:
mode:
authorCaleb Jamison <[email protected]>2024-08-07 23:20:26 -0400
committerCaleb Jamison <[email protected]>2024-08-08 21:35:21 -0400
commitb185e02a42ad751ec6c31ffa6a1b87503f15489d (patch)
tree0f0c66747267d24d95b5957b22db7e5c525cb00e /examples/rp23/src/bin/interrupt.rs
parent891c5ee10584cd990dad529e3506fe1328e4e69d (diff)
Initial rp235x support
Examples have been run, but there is not yet a test suite.
Diffstat (limited to 'examples/rp23/src/bin/interrupt.rs')
-rw-r--r--examples/rp23/src/bin/interrupt.rs110
1 files changed, 110 insertions, 0 deletions
diff --git a/examples/rp23/src/bin/interrupt.rs b/examples/rp23/src/bin/interrupt.rs
new file mode 100644
index 000000000..f46117f95
--- /dev/null
+++ b/examples/rp23/src/bin/interrupt.rs
@@ -0,0 +1,110 @@
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::pwm::{Config, Pwm};
19use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
20use embassy_sync::blocking_mutex::Mutex;
21use embassy_sync::channel::Channel;
22use embassy_time::{Duration, Ticker};
23use portable_atomic::{AtomicU32, Ordering};
24use static_cell::StaticCell;
25use {defmt_rtt as _, panic_probe as _};
26use embassy_rp::block::ImageDef;
27
28#[link_section = ".start_block"]
29#[used]
30pub static IMAGE_DEF: ImageDef = ImageDef::secure_exe();
31
32// Program metadata for `picotool info`
33#[link_section = ".bi_entries"]
34#[used]
35pub static PICOTOOL_ENTRIES: [embassy_rp::binary_info::EntryAddr; 4] = [
36 embassy_rp::binary_info_rp_cargo_bin_name!(),
37 embassy_rp::binary_info_rp_cargo_version!(),
38 embassy_rp::binary_info_rp_program_description!(c"Blinky"),
39 embassy_rp::binary_info_rp_program_build_attribute!(),
40];
41
42
43static COUNTER: AtomicU32 = AtomicU32::new(0);
44static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm>>> = Mutex::new(RefCell::new(None));
45static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> =
46 Mutex::new(RefCell::new(None));
47static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
48
49#[embassy_executor::main]
50async fn main(spawner: Spawner) {
51 embassy_rp::pac::SIO.spinlock(31).write_value(1);
52 let p = embassy_rp::init(Default::default());
53
54 let adc = Adc::new_blocking(p.ADC, Default::default());
55 let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
56 ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
57
58 let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
59 PWM.lock(|p| p.borrow_mut().replace(pwm));
60
61 // Enable the interrupt for pwm slice 4
62 embassy_rp::pac::PWM.irq0_inte().modify(|w| w.set_ch4(true));
63 unsafe {
64 cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP_0);
65 }
66
67 // Tasks require their resources to have 'static lifetime
68 // No Mutex needed when sharing within the same executor/prio level
69 static AVG: StaticCell<Cell<u32>> = StaticCell::new();
70 let avg = AVG.init(Default::default());
71 spawner.must_spawn(processing(avg));
72
73 let mut ticker = Ticker::every(Duration::from_secs(1));
74 loop {
75 ticker.next().await;
76 let freq = COUNTER.swap(0, Ordering::Relaxed);
77 info!("pwm freq: {:?} Hz", freq);
78 info!("adc average: {:?}", avg.get());
79
80 // Update the pwm duty cycle, based on the averaged adc reading
81 let mut config = Config::default();
82 config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
83 PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
84 }
85}
86
87#[embassy_executor::task]
88async fn processing(avg: &'static Cell<u32>) {
89 let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
90 loop {
91 let val = ADC_VALUES.receive().await;
92 buffer.write(val);
93 let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
94 avg.set(sum / buffer.len() as u32);
95 }
96}
97
98#[interrupt]
99fn PWM_IRQ_WRAP_0() {
100 critical_section::with(|cs| {
101 let mut adc = ADC.borrow(cs).borrow_mut();
102 let (adc, p26) = adc.as_mut().unwrap();
103 let val = adc.blocking_read(p26).unwrap();
104 ADC_VALUES.try_send(val).ok();
105
106 // Clear the interrupt, so we don't immediately re-enter this irq handler
107 PWM.borrow(cs).borrow_mut().as_mut().unwrap().clear_wrapped();
108 });
109 COUNTER.fetch_add(1, Ordering::Relaxed);
110}