Skip to main content

Module pcnt

Module pcnt 

Source
Available on crate feature unstable only.
Expand description

§Pulse Counter (PCNT)

§Overview

The PCNT module counts rising and/or falling edges of input signals. Each unit is an independent counter with two channels. Channel edge and control inputs can be configured separately.

Units are peripheral singletons (PCNT0_UNIT0, PCNT0_UNIT1, …, and PCNT1_UNIT0, … when the chip has a second register block). Construct a Unit from a singleton; there is no hub driver.

The hardware raises one interrupt per PCNT register block. Unit emulates per-unit interrupts by installing a shared dispatcher that calls the handler registered on each unit whose status bit is set.

§Examples

§Decoding a quadrature encoder


static UNIT0: Mutex<RefCell<Option<Unit<'static>>>> = Mutex::new(RefCell::new(None));
static VALUE: AtomicI32 = AtomicI32::new(0);

let mut u0 = Unit::new(peripherals.PCNT0_UNIT1);
u0.set_interrupt_handler(interrupt_handler);
u0.set_low_limit(Some(-100))?;
u0.set_high_limit(Some(100))?;
u0.set_filter(Some(min(10u16 * 80, 1023u16)))?;
u0.clear();

let ch0 = &u0.channel0;
let config = InputConfig::default().with_pull(Pull::Up);
let pin_a = Input::new(peripherals.GPIO4, config);
let pin_b = Input::new(peripherals.GPIO5, config);
let input_a = pin_a.peripheral_input();
let input_b = pin_b.peripheral_input();
ch0.set_ctrl_signal(input_a.clone());
ch0.set_edge_signal(input_b.clone());
ch0.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
ch0.set_input_mode(channel::EdgeMode::Increment, channel::EdgeMode::Decrement);

let ch1 = &u0.channel1;
ch1.set_ctrl_signal(input_b);
ch1.set_edge_signal(input_a);
ch1.set_ctrl_mode(channel::CtrlMode::Reverse, channel::CtrlMode::Keep);
ch1.set_input_mode(channel::EdgeMode::Decrement, channel::EdgeMode::Increment);

u0.listen();
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 {
        last_value = value;
    }
}

#[esp_hal::handler]
fn interrupt_handler() {
    critical_section::with(|cs| {
        let mut u0 = UNIT0.borrow_ref_mut(cs);
        if let Some(u0) = u0.as_mut() {
            if u0.interrupt_is_set() {
                let events = u0.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();
            }
        }
    });
}

Re-exports§

pub use unit::Unit;

Modules§

channel
PCNT - Channel Configuration
unit
PCNT - Unit Module

Structs§

AnyPcntUnit
Any PCNT unit.