esp_hal/pcnt/mod.rs
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
//! # Pulse Counter (PCNT)
//!
//! ## Overview
//! The PCNT module is designed to count the number of rising
//! and/or falling edges of input signals. They may contain multiple pulse
//! counter units in the module. Each unit is in effect an independent counter
//! with multiple channels, where each channel can increment/decrement the
//! counter on a rising/falling edge. Furthermore, each channel can be
//! configured separately.
//!
//! It consists of two main modules:
//! * [channel]
//! * [unit]
//!
//! ## Examples
//! ### Decoding a quadrature encoder
//! Visit the [PCNT Encoder] example for an example of using the peripheral.
//!
//! [channel]: channel/index.html
//! [unit]: unit/index.html
//! [PCNT Encoder]: https://github.com/esp-rs/esp-hal/blob/main/examples/src/bin/pcnt_encoder.rs
use self::unit::Unit;
use crate::{
interrupt::{self, InterruptHandler},
peripheral::{Peripheral, PeripheralRef},
peripherals::{self, Interrupt},
system::PeripheralClockControl,
InterruptConfigurable,
};
pub mod channel;
pub mod unit;
/// Pulse Counter (PCNT) peripheral driver.
pub struct Pcnt<'d> {
_instance: PeripheralRef<'d, peripherals::PCNT>,
/// Unit 0
pub unit0: Unit<'d, 0>,
/// Unit 1
pub unit1: Unit<'d, 1>,
/// Unit 2
pub unit2: Unit<'d, 2>,
/// Unit 3
pub unit3: Unit<'d, 3>,
#[cfg(esp32)]
/// Unit 4
pub unit4: Unit<'d, 4>,
#[cfg(esp32)]
/// Unit 5
pub unit5: Unit<'d, 5>,
#[cfg(esp32)]
/// Unit 6
pub unit6: Unit<'d, 6>,
#[cfg(esp32)]
/// Unit 7
pub unit7: Unit<'d, 7>,
}
impl<'d> Pcnt<'d> {
/// Return a new PCNT
pub fn new(_instance: impl Peripheral<P = peripherals::PCNT> + 'd) -> Self {
crate::into_ref!(_instance);
// Enable the PCNT peripherals clock in the system peripheral
PeripheralClockControl::reset(crate::system::Peripheral::Pcnt);
PeripheralClockControl::enable(crate::system::Peripheral::Pcnt);
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
// disable filter, all events, and channel settings
for unit in pcnt.unit_iter() {
unit.conf0().write(|w| unsafe {
// All bits are accounted for in the TRM.
w.bits(0)
});
}
// Remove reset bit from units.
pcnt.ctrl().modify(|_, w| {
#[cfg(not(esp32))]
let unit_count = 4;
#[cfg(esp32)]
let unit_count = 8;
for i in 0..unit_count {
w.cnt_rst_u(i).clear_bit();
}
w.clk_en().set_bit()
});
Pcnt {
_instance,
unit0: Unit::new(),
unit1: Unit::new(),
unit2: Unit::new(),
unit3: Unit::new(),
#[cfg(esp32)]
unit4: Unit::new(),
#[cfg(esp32)]
unit5: Unit::new(),
#[cfg(esp32)]
unit6: Unit::new(),
#[cfg(esp32)]
unit7: Unit::new(),
}
}
}
impl crate::private::Sealed for Pcnt<'_> {}
impl InterruptConfigurable for Pcnt<'_> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
for core in crate::Cpu::other() {
crate::interrupt::disable(core, Interrupt::PCNT);
}
unsafe { interrupt::bind_interrupt(Interrupt::PCNT, handler.handler()) };
unwrap!(interrupt::enable(Interrupt::PCNT, handler.priority()));
}
}