1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
//! # 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:
//! * [channel]
//! * [unit]
//!
//! 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
//! ```no_run
//! 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:
//! ```no_run
//! #[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();
//! }
//! });
//! }
//! ```
//!
//! [channel]: channel/index.html
//! [unit]: unit/index.html
use self::unit::Unit;
use crate::{
peripheral::{Peripheral, PeripheralRef},
system::PeripheralClockControl,
};
pub mod channel;
pub mod unit;
pub struct PCNT<'d> {
_instance: PeripheralRef<'d, crate::peripherals::PCNT>,
}
impl<'d> PCNT<'d> {
/// Return a new PCNT
pub fn new(_instance: impl Peripheral<P = crate::peripherals::PCNT> + 'd) -> Self {
crate::into_ref!(_instance);
// Enable the PCNT peripherals clock in the system peripheral
PeripheralClockControl::enable(crate::system::Peripheral::Pcnt);
PCNT { _instance }
}
/// Return a unit
pub fn get_unit(&self, number: unit::Number) -> Unit {
Unit::new(number)
}
}