Skip to content

Instantly share code, notes, and snippets.

@kalkyl
Last active May 8, 2024 12:45
Show Gist options
  • Save kalkyl/83bbe45be4c8100c0e09db09a6663b97 to your computer and use it in GitHub Desktop.
Save kalkyl/83bbe45be4c8100c0e09db09a6663b97 to your computer and use it in GitHub Desktop.
Raw interrupt handler example
#![no_std]
#![no_main]
use core::cell::{Cell, RefCell};
use defmt::*;
use embassy_executor::Spawner;
use embassy_rp::{gpio::Pull, peripherals::PWM_SLICE4};
use embassy_rp::adc::{self, Adc, Blocking};
use embassy_rp::interrupt;
use embassy_rp::pwm::{Config, Pwm};
use embassy_sync::{blocking_mutex::{raw::CriticalSectionRawMutex, Mutex}, channel::Channel};
use embassy_time::{Duration, Ticker};
use portable_atomic::{AtomicU32, Ordering};
use static_cell::StaticCell;
use {defmt_rtt as _, panic_probe as _};
static COUNTER: AtomicU32 = AtomicU32::new(0);
static PWM: Mutex<CriticalSectionRawMutex, RefCell<Option<Pwm<PWM_SLICE4>>>> = Mutex::new(RefCell::new(None));
static ADC: Mutex<CriticalSectionRawMutex, RefCell<Option<(Adc<Blocking>, adc::Channel)>>> = Mutex::new(RefCell::new(None));
static ADC_VALUES: Channel<CriticalSectionRawMutex, u16, 2048> = Channel::new();
#[embassy_executor::main]
async fn main(spawner: Spawner) {
embassy_rp::pac::SIO.spinlock(31).write_value(1);
let p = embassy_rp::init(Default::default());
let adc = Adc::new_blocking(p.ADC, Default::default());
let p26 = adc::Channel::new_pin(p.PIN_26, Pull::None);
ADC.lock(|a| a.borrow_mut().replace((adc, p26)));
let pwm = Pwm::new_output_b(p.PWM_SLICE4, p.PIN_25, Default::default());
PWM.lock(|p| p.borrow_mut().replace(pwm));
// Enable pwm interrupt
embassy_rp::pac::PWM.inte().modify(|w| w.set_ch4(true));
unsafe { cortex_m::peripheral::NVIC::unmask(interrupt::PWM_IRQ_WRAP); }
static AVG: StaticCell<Cell<u32>> = StaticCell::new();
let avg = AVG.init(Default::default());
spawner.must_spawn(processing(avg));
let mut ticker = Ticker::every(Duration::from_secs(1));
loop {
ticker.next().await;
let freq = COUNTER.swap(0, Ordering::Relaxed);
info!("pwm freq: {:?} Hz", freq);
info!("adc average: {:?}", avg.get());
// Update the pwm duty cycle, based on the adc reading
let mut config = Config::default();
config.compare_b = ((avg.get() as f32 / 4095.0) * config.top as f32) as _;
PWM.lock(|p| p.borrow_mut().as_mut().unwrap().set_config(&config));
}
}
#[embassy_executor::task]
async fn processing(avg: &'static Cell<u32>){
let mut buffer: heapless::HistoryBuffer<u16, 100> = Default::default();
loop {
let val = ADC_VALUES.receive().await;
buffer.write(val);
let sum: u32 = buffer.iter().map(|x| *x as u32).sum();
avg.set(sum/buffer.len() as u32);
}
}
#[interrupt]
fn PWM_IRQ_WRAP() {
critical_section::with(|cs| {
let mut pwm = PWM.borrow(cs).borrow_mut();
pwm.as_mut().unwrap().clear_wrapped();
let mut adc = ADC.borrow(cs).borrow_mut();
let (adc, p26) = adc.as_mut().unwrap();
let val = adc.blocking_read(p26).unwrap();
ADC_VALUES.try_send(val).ok();
});
COUNTER.fetch_add(1, Ordering::Relaxed);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment