esp-hal/examples/src/bin/pcnt_encoder.rs
Dániel Buga 7a733a75db
GPIO interconnect (#2128)
* Allow accessing signal list via ErasedPin

* Replace AnyPin with more flexible signal config

* Update tests and examples

* Fix enable_from_gpio value

* Access signals from pin drivers

* DummyPin is not a pin

* Remove redundant public fns

* Various fixes, rename ErasedPin

* Changelog

* rustfmt

* Update i8080

* Typos and endless recursion

* Drop Pin suffix from traits

* Extract AF conversion

* Touch up changelog

* Clean up spi tests

* Refactor pull resistor handling

* Don't disable configured output functionality

* Clean up TODO

* Tweak docs

* Clean up examples
2024-09-11 15:15:55 +00:00

118 lines
3.4 KiB
Rust

//! 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
//!
//! The following wiring is assumed:
//! - Control signal => GPIO4
//! - Edge signal => GPIO5
//% CHIPS: esp32 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::{cell::RefCell, cmp::min, sync::atomic::Ordering};
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
gpio::{Io, Pull},
interrupt::Priority,
pcnt::{
channel::{self, PcntInputConfig, PcntSource},
unit,
Pcnt,
},
prelude::*,
};
use esp_println::println;
use portable_atomic::AtomicI32;
static UNIT0: Mutex<RefCell<Option<unit::Unit<'static, 1>>>> = Mutex::new(RefCell::new(None));
static VALUE: AtomicI32 = AtomicI32::new(0);
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
// Set up a pulse counter:
println!("setup pulse counter unit 0");
let mut pcnt = Pcnt::new(peripherals.PCNT);
pcnt.set_interrupt_handler(interrupt_handler);
let u0 = pcnt.unit1;
u0.set_low_limit(Some(-100)).unwrap();
u0.set_high_limit(Some(100)).unwrap();
u0.set_filter(Some(min(10u16 * 80, 1023u16))).unwrap();
u0.clear();
println!("setup channel 0");
let ch0 = &u0.channel0;
let pin_a = io.pins.gpio4;
let pin_b = io.pins.gpio5;
ch0.set_ctrl_signal(PcntSource::from(
pin_a.peripheral_input(),
PcntInputConfig { pull: Pull::Up },
));
ch0.set_edge_signal(PcntSource::from(
pin_b.peripheral_input(),
PcntInputConfig { pull: Pull::Up },
));
ch0.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
ch0.set_input_mode(channel::EdgeMode::Increment, channel::EdgeMode::Decrement);
println!("setup channel 1");
let ch1 = &u0.channel1;
ch1.set_ctrl_signal(PcntSource::from(
pin_b.peripheral_input(),
PcntInputConfig { pull: Pull::Up },
));
ch1.set_edge_signal(PcntSource::from(
pin_a.peripheral_input(),
PcntInputConfig { pull: Pull::Up },
));
ch1.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
ch1.set_input_mode(channel::EdgeMode::Decrement, channel::EdgeMode::Increment);
println!("enabling interrupts");
u0.listen();
println!("resume pulse counter unit 0");
u0.resume();
let counter = u0.counter.clone();
critical_section::with(|cs| UNIT0.borrow_ref_mut(cs).replace(u0));
let mut last_value: i32 = 0;
loop {
let value: i32 = counter.get() as i32 + VALUE.load(Ordering::SeqCst);
if value != last_value {
println!("value: {value}");
last_value = value;
}
}
}
#[handler(priority = Priority::Priority2)]
fn interrupt_handler() {
critical_section::with(|cs| {
let mut u0 = UNIT0.borrow_ref_mut(cs);
let u0 = u0.as_mut().unwrap();
if u0.interrupt_is_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();
}
});
}