//! PCNT Encoder Demo //! //! This example decodes a quadrature encoder //! //! Since the PCNT units reset to zero when they reach their limits //! we enable an interrupt on the upper and lower limits and //! track the overflow in an AtomicI32 #![no_std] #![no_main] use core::{ cell::RefCell, cmp::min, sync::atomic::{AtomicI32, Ordering}, }; use critical_section::Mutex; use esp32h2_hal as esp_hal; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, interrupt, pcnt::{channel, channel::PcntSource, unit, PCNT}, peripherals::{self, Peripherals}, prelude::*, IO, }; use esp_println::println; static UNIT0: Mutex>> = Mutex::new(RefCell::new(None)); static VALUE: AtomicI32 = AtomicI32::new(0); #[entry] fn main() -> ! { let peripherals = Peripherals::take(); let system = peripherals.SYSTEM.split(); let _clocks = ClockControl::boot_defaults(system.clock_control).freeze(); let unit_number = unit::Number::Unit1; // setup a pulse couter println!("setup pulse counter unit 0"); let pcnt = PCNT::new(peripherals.PCNT); let mut u0 = pcnt.get_unit(unit_number); u0.configure(unit::Config { low_limit: -100, high_limit: 100, filter: Some(min(10u16 * 80, 1023u16)), ..Default::default() }) .unwrap(); println!("setup channel 0"); let mut ch0 = u0.get_channel(channel::Number::Channel0); let io = IO::new(peripherals.GPIO, peripherals.IO_MUX); let mut pin_a = io.pins.gpio4.into_pull_up_input(); let mut pin_b = io.pins.gpio5.into_pull_up_input(); ch0.configure( PcntSource::from_pin(&mut pin_a), PcntSource::from_pin(&mut pin_b), channel::Config { lctrl_mode: channel::CtrlMode::Reverse, hctrl_mode: channel::CtrlMode::Keep, pos_edge: channel::EdgeMode::Decrement, neg_edge: channel::EdgeMode::Increment, invert_ctrl: false, invert_sig: false, }, ); println!("setup channel 1"); let mut ch1 = u0.get_channel(channel::Number::Channel1); ch1.configure( PcntSource::from_pin(&mut pin_b), PcntSource::from_pin(&mut pin_a), channel::Config { lctrl_mode: channel::CtrlMode::Reverse, hctrl_mode: channel::CtrlMode::Keep, pos_edge: channel::EdgeMode::Increment, neg_edge: channel::EdgeMode::Decrement, invert_ctrl: false, invert_sig: false, }, ); println!("subscribing to events"); u0.events(unit::Events { low_limit: true, high_limit: true, thresh0: false, thresh1: false, zero: false, }); println!("enabling interrupts"); u0.listen(); println!("resume pulse counter unit 0"); u0.resume(); critical_section::with(|cs| UNIT0.borrow_ref_mut(cs).replace(u0)); interrupt::enable(peripherals::Interrupt::PCNT, interrupt::Priority::Priority2).unwrap(); let mut last_value: i32 = 0; loop { critical_section::with(|cs| { let mut u0 = UNIT0.borrow_ref_mut(cs); let u0 = u0.as_mut().unwrap(); let value: i32 = u0.get_value() as i32 + VALUE.load(Ordering::SeqCst); if value != last_value { println!("value: {value}"); last_value = value; } }); } } #[interrupt] fn PCNT() { critical_section::with(|cs| { let mut u0 = UNIT0.borrow_ref_mut(cs); let u0 = u0.as_mut().unwrap(); if u0.interrupt_set() { let events = u0.get_events(); if events.high_limit { VALUE.fetch_add(100, Ordering::SeqCst); } else if events.low_limit { VALUE.fetch_add(-100, Ordering::SeqCst); } u0.reset_interrupt(); } }); }