Expand description
§Pulse Counter peripheral driver
§Overview
The PCNT (Pulse Counter)
driver for ESP
chips is a software component
that provides an interface for controlling and utilizing the PCNT
peripheral. The PCNT
peripheral is a hardware module available in ESP
chips, which functions as a pulse counter and encoder. It is capable of
counting pulses and monitoring changes in signal levels from external
sources.
The PCNT
driver is designed to offer convenient and efficient access to
the functionalities of the PCNT
peripheral. It consists of two main
modules:
The channel
module allows users to configure and manage individual
channels of the PCNT
peripheral. It provides methods to set various
parameters for each channel, such as control modes for signal edges, action
on control level, and configurations for positive and negative edge count
modes.
The unit
module is responsible for configuring and handling individual
units of the PCNT
peripheral. Each unit represents a separate instance of
the PCNT
module, identified by unit numbers like Unit0
, Unit1
, and so
on. Users can interact with these units to configure settings such as low
and high limits, thresholds, and optional filtering. The unit module also
enables users to pause, resume, and clear the counter, as well as enable or
disable interrupts for specific events associated with the unit.
§Example
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.gpio5.into_pull_up_input();
let mut pin_b = io.pins.gpio6.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;
}
});
}
Where the PCNT
interrupt handler is defined as:
#[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();
}
});
}