pulse counter implementation (#328)

* start of pulse counter implementation

* implement interrupts
implement pcnt for esp32, esp32s2, and esp32s3

* implement pcnt for esp32s2

* fix esp32 PCNT signal names

* update PCNT register/fields for cleaned up PAC

* implement events/get_events (choosing what events interrupt)

* added pcnt example: simple encoder configuration

* restrict pcnt::channel::Channel::new() to super

* PcntPin -> PcntSignal
added range checks for thresholds and limits

* PcntSource is a better name I think

* handle error for PCNT Unit configure() in example

* update pac versions for status register change

* cargo fmt

* cargo fmt (examples)

* PcntSource now only stores the source id.
add a critical section to protect the ctrl & isr_en registers

* cargo fmt
This commit is contained in:
liebman 2023-01-17 09:04:22 -08:00 committed by GitHub
parent a542735847
commit ac206af656
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 1177 additions and 36 deletions

View File

@ -51,11 +51,11 @@ ufmt-write = { version = "0.1.0", optional = true }
# Each supported device MUST have its PAC included below along with a # Each supported device MUST have its PAC included below along with a
# corresponding feature. We rename the PAC packages because we cannot # corresponding feature. We rename the PAC packages because we cannot
# have dependencies and features with the same names. # have dependencies and features with the same names.
esp32 = { version = "0.18.0", features = ["critical-section"], optional = true } esp32 = { version = "0.19.0", features = ["critical-section"], optional = true }
esp32c2 = { version = "0.5.1", features = ["critical-section"], optional = true } esp32c2 = { version = "0.6.0", features = ["critical-section"], optional = true }
esp32c3 = { version = "0.9.0", features = ["critical-section"], optional = true } esp32c3 = { version = "0.9.0", features = ["critical-section"], optional = true }
esp32s2 = { version = "0.8.0", features = ["critical-section"], optional = true } esp32s2 = { version = "0.9.0", features = ["critical-section"], optional = true }
esp32s3 = { version = "0.12.0", features = ["critical-section"], optional = true } esp32s3 = { version = "0.13.0", features = ["critical-section"], optional = true }
[features] [features]
esp32 = ["esp32/rt" , "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api"] esp32 = ["esp32/rt" , "xtensa", "xtensa-lx/esp32", "xtensa-lx-rt/esp32", "lock_api"]

View File

@ -116,26 +116,26 @@ pub enum InputSignal {
PWM0_F2 = 36, PWM0_F2 = 36,
GPIO_BT_ACTIVE = 37, GPIO_BT_ACTIVE = 37,
GPIO_BT_PRIORITY = 38, GPIO_BT_PRIORITY = 38,
PCNT_SIG_CH0_0 = 39, PCNT0_SIG_CH0 = 39,
PCNT_SIG_CH1_0 = 40, PCNT0_SIG_CH1 = 40,
PCNT_CTRL_CH0_0 = 41, PCNT0_CTRL_CH0 = 41,
PCNT_CTRL_CH1_0 = 42, PCNT0_CTRL_CH1 = 42,
PCNT_SIG_CH0_1 = 43, PCNT1_SIG_CH0 = 43,
PCNT_SIG_CH1_1 = 44, PCNT1_SIG_CH1 = 44,
PCNT_CTRL_CH0_1 = 45, PCNT1_CTRL_CH0 = 45,
PCNT_CTRL_CH1_1 = 46, PCNT1_CTRL_CH1 = 46,
PCNT_SIG_CH0_2 = 47, PCNT2_SIG_CH0 = 47,
PCNT_SIG_CH1_2 = 48, PCNT2_SIG_CH1 = 48,
PCNT_CTRL_CH0_2 = 49, PCNT2_CTRL_CH0 = 49,
PCNT_CTRL_CH1_2 = 50, PCNT2_CTRL_CH1 = 50,
PCNT_SIG_CH0_3 = 51, PCNT3_SIG_CH0 = 51,
PCNT_SIG_CH1_3 = 52, PCNT3_SIG_CH1 = 52,
PCNT_CTRL_CH0_3 = 53, PCNT3_CTRL_CH0 = 53,
PCNT_CTRL_CH1_3 = 54, PCNT3_CTRL_CH1 = 54,
PCNT_SIG_CH0_4 = 55, PCNT4_SIG_CH0 = 55,
PCNT_SIG_CH1_4 = 56, PCNT4_SIG_CH1 = 56,
PCNT_CTRL_CH0_4 = 57, PCNT4_CTRL_CH0 = 57,
PCNT_CTRL_CH1_4 = 58, PCNT4_CTRL_CH1 = 58,
HSPICS1 = 61, HSPICS1 = 61,
HSPICS2 = 62, HSPICS2 = 62,
VSPICLK = 63, VSPICLK = 63,
@ -146,18 +146,18 @@ pub enum InputSignal {
VSPICS0 = 68, VSPICS0 = 68,
VSPICS1 = 69, VSPICS1 = 69,
VSPICS2 = 70, VSPICS2 = 70,
PCNT_SIG_CH0_5 = 71, PCNT5_SIG_CH0 = 71,
PCNT_SIG_CH1_5 = 72, PCNT5_SIG_CH1 = 72,
PCNT_CTRL_CH0_5 = 73, PCNT5_CTRL_CH0 = 73,
PCNT_CTRL_CH1_5 = 74, PCNT5_CTRL_CH1 = 74,
PCNT_SIG_CH0_6 = 75, PCNT6_SIG_CH0 = 75,
PCNT_SIG_CH1_6 = 76, PCNT6_SIG_CH1 = 76,
PCNT_CTRL_CH0_6 = 77, PCNT6_CTRL_CH0 = 77,
PCNT_CTRL_CH1_6 = 78, PCNT6_CTRL_CH1 = 78,
PCNT_SIG_CH0_7 = 79, PCNT7_SIG_CH0 = 79,
PCNT_SIG_CH1_7 = 80, PCNT7_SIG_CH1 = 80,
PCNT_CTRL_CH0_7 = 81, PCNT7_CTRL_CH0 = 81,
PCNT_CTRL_CH1_7 = 82, PCNT7_CTRL_CH1 = 82,
RMT_SIG_0 = 83, RMT_SIG_0 = 83,
RMT_SIG_1 = 84, RMT_SIG_1 = 84,
RMT_SIG_2 = 85, RMT_SIG_2 = 85,

View File

@ -102,6 +102,22 @@ pub enum InputSignal {
I2S0I_WS = 28, I2S0I_WS = 28,
I2CEXT0_SCL = 29, I2CEXT0_SCL = 29,
I2CEXT0_SDA = 30, I2CEXT0_SDA = 30,
PCNT0_SIG_CH0 = 39,
PCNT0_SIG_CH1 = 40,
PCNT0_CTRL_CH0 = 41,
PCNT0_CTRL_CH1 = 42,
PCNT1_SIG_CH0 = 43,
PCNT1_SIG_CH1 = 44,
PCNT1_CTRL_CH0 = 45,
PCNT1_CTRL_CH1 = 46,
PCNT2_SIG_CH0 = 47,
PCNT2_SIG_CH1 = 48,
PCNT2_CTRL_CH0 = 49,
PCNT2_CTRL_CH1 = 50,
PCNT3_SIG_CH0 = 51,
PCNT3_SIG_CH1 = 52,
PCNT3_CTRL_CH0 = 53,
PCNT3_CTRL_CH1 = 54,
USB_OTG_IDDIG = 64, USB_OTG_IDDIG = 64,
USB_OTG_AVALID = 65, USB_OTG_AVALID = 65,
USB_SRP_BVALID = 66, USB_SRP_BVALID = 66,

View File

@ -63,6 +63,22 @@ pub enum InputSignal {
I2S1I_SD = 30, I2S1I_SD = 30,
I2S1I_BCK = 31, I2S1I_BCK = 31,
I2S1I_WS = 32, I2S1I_WS = 32,
PCNT0_SIG_CH0 = 33,
PCNT0_SIG_CH1 = 34,
PCNT0_CTRL_CH0 = 35,
PCNT0_CTRL_CH1 = 36,
PCNT1_SIG_CH0 = 37,
PCNT1_SIG_CH1 = 38,
PCNT1_CTRL_CH0 = 39,
PCNT1_CTRL_CH1 = 40,
PCNT2_SIG_CH0 = 41,
PCNT2_SIG_CH1 = 42,
PCNT2_CTRL_CH0 = 43,
PCNT2_CTRL_CH1 = 44,
PCNT3_SIG_CH0 = 45,
PCNT3_SIG_CH1 = 46,
PCNT3_CTRL_CH0 = 47,
PCNT3_CTRL_CH1 = 48,
I2S0I_SD1 = 51, I2S0I_SD1 = 51,
I2S0I_SD2 = 52, I2S0I_SD2 = 52,
I2S0I_SD3 = 53, I2S0I_SD3 = 53,

View File

@ -60,6 +60,8 @@ pub mod ledc;
pub mod mcpwm; pub mod mcpwm;
#[cfg(usb_otg)] #[cfg(usb_otg)]
pub mod otg_fs; pub mod otg_fs;
#[cfg(any(esp32, esp32s2, esp32s3))]
pub mod pcnt;
pub mod peripheral; pub mod peripheral;
pub mod prelude; pub mod prelude;
#[cfg(rmt)] #[cfg(rmt)]

View File

@ -0,0 +1,243 @@
use super::unit;
use crate::{
gpio::{
types::{InputSignal, ONE_INPUT, ZERO_INPUT},
InputPin,
},
peripheral::Peripheral,
peripherals::GPIO,
};
/// Channel number
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Number {
Channel0,
Channel1,
}
/// PCNT channel action on signal edge
#[derive(Debug, Copy, Clone, Default)]
pub enum EdgeMode {
/// Hold current count value
Hold = 0,
/// Increase count value
#[default]
Increment = 1,
/// Decrease count value
Decrement = 2,
}
/// PCNT channel action on control level
#[derive(Debug, Copy, Clone, Default)]
pub enum CtrlMode {
/// Keep current count mode
Keep = 0,
/// Invert current count mode (increase -> decrease, decrease -> increase)
#[default]
Reverse = 1,
/// Hold current count value
Disable = 2,
}
/// Pulse Counter configuration for a single channel
#[derive(Debug, Copy, Clone, Default)]
pub struct Config {
/// PCNT low control mode
pub lctrl_mode: CtrlMode,
/// PCNT high control mode
pub hctrl_mode: CtrlMode,
/// PCNT signal positive edge count mode
pub pos_edge: EdgeMode,
/// PCNT signal negative edge count mode
pub neg_edge: EdgeMode,
pub invert_ctrl: bool,
pub invert_sig: bool,
}
/// PcntPin can be always high, always low, or an actual pin
#[derive(Clone, Copy)]
pub struct PcntSource {
source: u8,
}
impl PcntSource {
pub fn from_pin<'a, P: InputPin>(pin: impl Peripheral<P = P> + 'a) -> Self {
crate::into_ref!(pin);
Self {
source: pin.number(),
}
}
pub fn always_high() -> Self {
Self { source: ONE_INPUT }
}
pub fn always_low() -> Self {
Self { source: ZERO_INPUT }
}
}
pub struct Channel {
unit: unit::Number,
channel: Number,
}
impl Channel {
/// return a new Channel
pub(super) fn new(unit: unit::Number, channel: Number) -> Self {
Self { unit, channel }
}
/// Configure the channel
pub fn configure(&mut self, ctrl_signal: PcntSource, edge_signal: PcntSource, config: Config) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
let conf0 = match self.unit {
unit::Number::Unit0 => &pcnt.u0_conf0,
unit::Number::Unit1 => &pcnt.u1_conf0,
unit::Number::Unit2 => &pcnt.u2_conf0,
unit::Number::Unit3 => &pcnt.u3_conf0,
#[cfg(esp32)]
unit::Number::Unit4 => &pcnt.u4_conf0,
#[cfg(esp32)]
unit::Number::Unit5 => &pcnt.u5_conf0,
#[cfg(esp32)]
unit::Number::Unit6 => &pcnt.u6_conf0,
#[cfg(esp32)]
unit::Number::Unit7 => &pcnt.u7_conf0,
};
match self.channel {
Number::Channel0 => {
conf0.modify(|_, w| unsafe {
w.ch0_hctrl_mode()
.bits(config.hctrl_mode as u8)
.ch0_lctrl_mode()
.bits(config.lctrl_mode as u8)
.ch0_neg_mode()
.bits(config.neg_edge as u8)
.ch0_pos_mode()
.bits(config.pos_edge as u8)
});
}
Number::Channel1 => {
conf0.modify(|_, w| unsafe {
w.ch1_hctrl_mode()
.bits(config.hctrl_mode as u8)
.ch1_lctrl_mode()
.bits(config.lctrl_mode as u8)
.ch1_neg_mode()
.bits(config.neg_edge as u8)
.ch1_pos_mode()
.bits(config.pos_edge as u8)
});
}
}
self.set_ctrl_signal(ctrl_signal, config.invert_ctrl);
self.set_edge_signal(edge_signal, config.invert_sig);
}
/// Set the control signal (pin/high/low) for this channel
pub fn set_ctrl_signal(&self, source: PcntSource, invert: bool) -> &Self {
let signal = match self.unit {
unit::Number::Unit0 => match self.channel {
Number::Channel0 => InputSignal::PCNT0_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT0_CTRL_CH1,
},
unit::Number::Unit1 => match self.channel {
Number::Channel0 => InputSignal::PCNT1_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT1_CTRL_CH1,
},
unit::Number::Unit2 => match self.channel {
Number::Channel0 => InputSignal::PCNT2_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT2_CTRL_CH1,
},
unit::Number::Unit3 => match self.channel {
Number::Channel0 => InputSignal::PCNT3_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT3_CTRL_CH1,
},
#[cfg(esp32)]
unit::Number::Unit4 => match self.channel {
Number::Channel0 => InputSignal::PCNT4_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT4_CTRL_CH1,
},
#[cfg(esp32)]
unit::Number::Unit5 => match self.channel {
Number::Channel0 => InputSignal::PCNT5_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT5_CTRL_CH1,
},
#[cfg(esp32)]
unit::Number::Unit6 => match self.channel {
Number::Channel0 => InputSignal::PCNT6_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT6_CTRL_CH1,
},
#[cfg(esp32)]
unit::Number::Unit7 => match self.channel {
Number::Channel0 => InputSignal::PCNT7_CTRL_CH0,
Number::Channel1 => InputSignal::PCNT7_CTRL_CH1,
},
};
if (signal as usize) <= crate::types::INPUT_SIGNAL_MAX as usize {
unsafe { &*GPIO::PTR }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sel()
.set_bit()
.in_inv_sel()
.bit(invert)
.in_sel()
.bits(source.source)
});
}
self
}
/// Set the edge signal (pin/high/low) for this channel
pub fn set_edge_signal(&self, source: PcntSource, invert: bool) -> &Self {
let signal = match self.unit {
unit::Number::Unit0 => match self.channel {
Number::Channel0 => InputSignal::PCNT0_SIG_CH0,
Number::Channel1 => InputSignal::PCNT0_SIG_CH1,
},
unit::Number::Unit1 => match self.channel {
Number::Channel0 => InputSignal::PCNT1_SIG_CH0,
Number::Channel1 => InputSignal::PCNT1_SIG_CH1,
},
unit::Number::Unit2 => match self.channel {
Number::Channel0 => InputSignal::PCNT2_SIG_CH0,
Number::Channel1 => InputSignal::PCNT2_SIG_CH1,
},
unit::Number::Unit3 => match self.channel {
Number::Channel0 => InputSignal::PCNT3_SIG_CH0,
Number::Channel1 => InputSignal::PCNT3_SIG_CH1,
},
#[cfg(esp32)]
unit::Number::Unit4 => match self.channel {
Number::Channel0 => InputSignal::PCNT4_SIG_CH0,
Number::Channel1 => InputSignal::PCNT4_SIG_CH1,
},
#[cfg(esp32)]
unit::Number::Unit5 => match self.channel {
Number::Channel0 => InputSignal::PCNT5_SIG_CH0,
Number::Channel1 => InputSignal::PCNT5_SIG_CH1,
},
#[cfg(esp32)]
unit::Number::Unit6 => match self.channel {
Number::Channel0 => InputSignal::PCNT6_SIG_CH0,
Number::Channel1 => InputSignal::PCNT6_SIG_CH1,
},
#[cfg(esp32)]
unit::Number::Unit7 => match self.channel {
Number::Channel0 => InputSignal::PCNT7_SIG_CH0,
Number::Channel1 => InputSignal::PCNT7_SIG_CH1,
},
};
if (signal as usize) <= crate::types::INPUT_SIGNAL_MAX as usize {
unsafe { &*GPIO::PTR }.func_in_sel_cfg[signal as usize].modify(|_, w| unsafe {
w.sel()
.set_bit()
.in_inv_sel()
.bit(invert)
.in_sel()
.bits(source.source)
});
}
self
}
}

View File

@ -0,0 +1,30 @@
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,
peripheral_clock_control: &mut PeripheralClockControl,
) -> Self {
crate::into_ref!(_instance);
// Enable the PCNT peripherals clock in the system peripheral
peripheral_clock_control.enable(crate::system::Peripheral::Pcnt);
PCNT { _instance }
}
/// Return a unit
pub fn get_unit(&self, number: unit::Number) -> Unit {
Unit::new(number)
}
}

View File

@ -0,0 +1,392 @@
use critical_section::CriticalSection;
use super::channel;
/// Unit number
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub enum Number {
Unit0,
Unit1,
Unit2,
Unit3,
#[cfg(esp32)]
Unit4,
#[cfg(esp32)]
Unit5,
#[cfg(esp32)]
Unit6,
#[cfg(esp32)]
Unit7,
}
/// Unit errors
#[derive(Debug)]
pub enum Error {
/// Invalid filter threshold value
InvalidFilterThresh,
/// Invalid low limit - must be < 0
InvalidLowLimit,
/// Invalid high limit - must be > 0
InvalidHighLimit,
}
/// the current status of the counter.
#[derive(Copy, Clone, Debug, Default)]
pub enum ZeroMode {
/// pulse counter decreases from positive to 0.
#[default]
PosZero = 0,
/// pulse counter increases from negative to 0
NegZero = 1,
/// pulse counter is negative (not implemented?)
Negitive = 2,
/// pulse counter is positive (not implemented?)
Positive = 3,
}
impl From<u8> for ZeroMode {
fn from(value: u8) -> Self {
match value {
0 => Self::PosZero,
1 => Self::NegZero,
2 => Self::Negitive,
3 => Self::Positive,
_ => unreachable!(), // TODO: is this good enoough? should we use some default?
}
}
}
// Events
#[derive(Copy, Clone, Debug, Default)]
pub struct Events {
pub low_limit: bool,
pub high_limit: bool,
pub thresh0: bool,
pub thresh1: bool,
pub zero: bool,
}
/// Unit configuration
#[derive(Copy, Clone, Default)]
pub struct Config {
pub low_limit: i16,
pub high_limit: i16,
pub thresh0: i16,
pub thresh1: i16,
pub filter: Option<u16>,
}
pub struct Unit {
number: Number,
}
impl Unit {
/// return a new Unit
pub(super) fn new(number: Number) -> Self {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
let conf0 = match number {
Number::Unit0 => &pcnt.u0_conf0,
Number::Unit1 => &pcnt.u1_conf0,
Number::Unit2 => &pcnt.u2_conf0,
Number::Unit3 => &pcnt.u3_conf0,
#[cfg(esp32)]
Number::Unit4 => &pcnt.u4_conf0,
#[cfg(esp32)]
Number::Unit5 => &pcnt.u5_conf0,
#[cfg(esp32)]
Number::Unit6 => &pcnt.u6_conf0,
#[cfg(esp32)]
Number::Unit7 => &pcnt.u7_conf0,
};
// disable filter and all events
conf0.modify(|_, w| unsafe {
w.filter_en()
.clear_bit()
.filter_thres()
.bits(0)
.thr_l_lim_en()
.clear_bit()
.thr_h_lim_en()
.clear_bit()
.thr_thres0_en()
.clear_bit()
.thr_thres1_en()
.clear_bit()
.thr_zero_en()
.clear_bit()
});
Self { number }
}
pub fn configure(&mut self, config: Config) -> Result<(), Error> {
// low limit must be >= or the limit is -32768 and when thats
// hit the event status claims it was the high limit.
// tested on an esp32s3
if config.low_limit >= 0 {
return Err(Error::InvalidLowLimit);
}
if config.high_limit <= 0 {
return Err(Error::InvalidHighLimit);
}
let (filter_en, filter) = match config.filter {
Some(filter) => (true, filter),
None => (false, 0),
};
// filter must be less than 1024
if filter > 1023 {
return Err(Error::InvalidFilterThresh);
}
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
let (conf0, conf1, conf2) = match self.number {
Number::Unit0 => (&pcnt.u0_conf0, &pcnt.u0_conf1, &pcnt.u0_conf2),
Number::Unit1 => (&pcnt.u1_conf0, &pcnt.u1_conf1, &pcnt.u1_conf2),
Number::Unit2 => (&pcnt.u2_conf0, &pcnt.u2_conf1, &pcnt.u2_conf2),
Number::Unit3 => (&pcnt.u3_conf0, &pcnt.u3_conf1, &pcnt.u3_conf2),
#[cfg(esp32)]
Number::Unit4 => (&pcnt.u4_conf0, &pcnt.u4_conf1, &pcnt.u4_conf2),
#[cfg(esp32)]
Number::Unit5 => (&pcnt.u5_conf0, &pcnt.u5_conf1, &pcnt.u5_conf2),
#[cfg(esp32)]
Number::Unit6 => (&pcnt.u6_conf0, &pcnt.u6_conf1, &pcnt.u6_conf2),
#[cfg(esp32)]
Number::Unit7 => (&pcnt.u7_conf0, &pcnt.u7_conf1, &pcnt.u7_conf2),
};
conf2.write(|w| unsafe {
w.cnt_l_lim()
.bits(config.low_limit as u16)
.cnt_h_lim()
.bits(config.high_limit as u16)
});
conf1.write(|w| unsafe {
w.cnt_thres0()
.bits(config.thresh0 as u16)
.cnt_thres1()
.bits(config.thresh1 as u16)
});
conf0.modify(|_, w| unsafe { w.filter_thres().bits(filter).filter_en().bit(filter_en) });
self.pause();
self.clear();
Ok(())
}
pub fn get_channel(&self, number: channel::Number) -> super::channel::Channel {
super::channel::Channel::new(self.number, number)
}
pub fn clear(&self) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| {
match self.number {
Number::Unit0 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u0().set_bit()),
Number::Unit1 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u1().set_bit()),
Number::Unit2 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u2().set_bit()),
Number::Unit3 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u3().set_bit()),
#[cfg(esp32)]
Number::Unit4 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u4().set_bit()),
#[cfg(esp32)]
Number::Unit5 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u5().set_bit()),
#[cfg(esp32)]
Number::Unit6 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u6().set_bit()),
#[cfg(esp32)]
Number::Unit7 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u7().set_bit()),
}
// TODO: does this need a delay? (liebman / Jan 2 2023)
match self.number {
Number::Unit0 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u0().clear_bit()),
Number::Unit1 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u1().clear_bit()),
Number::Unit2 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u2().clear_bit()),
Number::Unit3 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u3().clear_bit()),
#[cfg(esp32)]
Number::Unit4 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u4().clear_bit()),
#[cfg(esp32)]
Number::Unit5 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u5().clear_bit()),
#[cfg(esp32)]
Number::Unit6 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u6().clear_bit()),
#[cfg(esp32)]
Number::Unit7 => pcnt.ctrl.modify(|_, w| w.cnt_rst_u7().clear_bit()),
}
});
}
/// Pause the counter
pub fn pause(&self) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| match self.number {
Number::Unit0 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u0().set_bit()),
Number::Unit1 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u1().set_bit()),
Number::Unit2 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u2().set_bit()),
Number::Unit3 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u3().set_bit()),
#[cfg(esp32)]
Number::Unit4 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u4().set_bit()),
#[cfg(esp32)]
Number::Unit5 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u5().set_bit()),
#[cfg(esp32)]
Number::Unit6 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u6().set_bit()),
#[cfg(esp32)]
Number::Unit7 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u7().set_bit()),
});
}
/// Resume the counter
pub fn resume(&self) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| match self.number {
Number::Unit0 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u0().clear_bit()),
Number::Unit1 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u1().clear_bit()),
Number::Unit2 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u2().clear_bit()),
Number::Unit3 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u3().clear_bit()),
#[cfg(esp32)]
Number::Unit4 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u4().clear_bit()),
#[cfg(esp32)]
Number::Unit5 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u5().clear_bit()),
#[cfg(esp32)]
Number::Unit6 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u6().clear_bit()),
#[cfg(esp32)]
Number::Unit7 => pcnt.ctrl.modify(|_, w| w.cnt_pause_u7().clear_bit()),
});
}
/// Enable which events generate interrupts on this unit.
pub fn events(&self, events: Events) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
let conf0 = match self.number {
Number::Unit0 => &pcnt.u0_conf0,
Number::Unit1 => &pcnt.u1_conf0,
Number::Unit2 => &pcnt.u2_conf0,
Number::Unit3 => &pcnt.u3_conf0,
#[cfg(esp32)]
Number::Unit4 => &pcnt.u4_conf0,
#[cfg(esp32)]
Number::Unit5 => &pcnt.u5_conf0,
#[cfg(esp32)]
Number::Unit6 => &pcnt.u6_conf0,
#[cfg(esp32)]
Number::Unit7 => &pcnt.u7_conf0,
};
conf0.modify(|_, w| {
w.thr_l_lim_en()
.bit(events.low_limit)
.thr_h_lim_en()
.bit(events.high_limit)
.thr_thres0_en()
.bit(events.thresh0)
.thr_thres1_en()
.bit(events.thresh1)
.thr_zero_en()
.bit(events.zero)
});
}
/// Get the latest events for this unit.
pub fn get_events(&self) -> Events {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
let status = pcnt.u_status[self.number as usize].read();
Events {
low_limit: status.l_lim().bit(),
high_limit: status.h_lim().bit(),
thresh0: status.thres0().bit(),
thresh1: status.thres1().bit(),
zero: status.zero().bit(),
}
}
/// Get the mode of the last zero crossing
pub fn get_zero_mode(&self) -> ZeroMode {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
pcnt.u_status[self.number as usize]
.read()
.zero_mode()
.bits()
.into()
}
/// Enable interrupts for this unit.
pub fn listen(&self) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| {
pcnt.int_ena.modify(|_, w| match self.number {
Number::Unit0 => w.cnt_thr_event_u0().set_bit(),
Number::Unit1 => w.cnt_thr_event_u1().set_bit(),
Number::Unit2 => w.cnt_thr_event_u2().set_bit(),
Number::Unit3 => w.cnt_thr_event_u3().set_bit(),
#[cfg(esp32)]
Number::Unit4 => w.cnt_thr_event_u4().set_bit(),
#[cfg(esp32)]
Number::Unit5 => w.cnt_thr_event_u5().set_bit(),
#[cfg(esp32)]
Number::Unit6 => w.cnt_thr_event_u6().set_bit(),
#[cfg(esp32)]
Number::Unit7 => w.cnt_thr_event_u7().set_bit(),
})
});
}
/// Disable interrupts for this unit.
pub fn unlisten(&self, _cs: CriticalSection) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| {
pcnt.int_ena.write(|w| match self.number {
Number::Unit0 => w.cnt_thr_event_u0().clear_bit(),
Number::Unit1 => w.cnt_thr_event_u1().clear_bit(),
Number::Unit2 => w.cnt_thr_event_u2().clear_bit(),
Number::Unit3 => w.cnt_thr_event_u3().clear_bit(),
#[cfg(esp32)]
Number::Unit4 => w.cnt_thr_event_u4().clear_bit(),
#[cfg(esp32)]
Number::Unit5 => w.cnt_thr_event_u5().clear_bit(),
#[cfg(esp32)]
Number::Unit6 => w.cnt_thr_event_u6().clear_bit(),
#[cfg(esp32)]
Number::Unit7 => w.cnt_thr_event_u7().clear_bit(),
})
});
}
/// Returns true if an interrupt is active for this unit.
pub fn interrupt_set(&self) -> bool {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
match self.number {
Number::Unit0 => pcnt.int_st.read().cnt_thr_event_u0().bit(),
Number::Unit1 => pcnt.int_st.read().cnt_thr_event_u1().bit(),
Number::Unit2 => pcnt.int_st.read().cnt_thr_event_u2().bit(),
Number::Unit3 => pcnt.int_st.read().cnt_thr_event_u3().bit(),
#[cfg(esp32)]
Number::Unit4 => pcnt.int_st.read().cnt_thr_event_u4().bit(),
#[cfg(esp32)]
Number::Unit5 => pcnt.int_st.read().cnt_thr_event_u5().bit(),
#[cfg(esp32)]
Number::Unit6 => pcnt.int_st.read().cnt_thr_event_u6().bit(),
#[cfg(esp32)]
Number::Unit7 => pcnt.int_st.read().cnt_thr_event_u7().bit(),
}
}
/// Clear the interrupt bit for this unit.
pub fn reset_interrupt(&self) {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
critical_section::with(|_cs| {
pcnt.int_clr.write(|w| match self.number {
Number::Unit0 => w.cnt_thr_event_u0().set_bit(),
Number::Unit1 => w.cnt_thr_event_u1().set_bit(),
Number::Unit2 => w.cnt_thr_event_u2().set_bit(),
Number::Unit3 => w.cnt_thr_event_u3().set_bit(),
#[cfg(esp32)]
Number::Unit4 => w.cnt_thr_event_u4().set_bit(),
#[cfg(esp32)]
Number::Unit5 => w.cnt_thr_event_u5().set_bit(),
#[cfg(esp32)]
Number::Unit6 => w.cnt_thr_event_u6().set_bit(),
#[cfg(esp32)]
Number::Unit7 => w.cnt_thr_event_u7().set_bit(),
})
});
}
/// Get the current counter value.
pub fn get_value(&self) -> i16 {
let pcnt = unsafe { &*crate::peripherals::PCNT::ptr() };
pcnt.u_cnt[self.number as usize].read().cnt().bits() as i16
}
}

View File

@ -30,6 +30,8 @@ pub enum Peripheral {
Mcpwm0, Mcpwm0,
#[cfg(any(esp32, esp32s3))] #[cfg(any(esp32, esp32s3))]
Mcpwm1, Mcpwm1,
#[cfg(any(esp32, esp32s2, esp32s3))]
Pcnt,
#[cfg(any(esp32c2, esp32c3))] #[cfg(any(esp32c2, esp32c3))]
ApbSarAdc, ApbSarAdc,
#[cfg(gdma)] #[cfg(gdma)]
@ -108,6 +110,11 @@ impl PeripheralClockControl {
perip_clk_en0.modify(|_, w| w.pwm1_clk_en().set_bit()); perip_clk_en0.modify(|_, w| w.pwm1_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.pwm1_rst().clear_bit()); perip_rst_en0.modify(|_, w| w.pwm1_rst().clear_bit());
} }
#[cfg(any(esp32, esp32s2, esp32s3))]
Peripheral::Pcnt => {
perip_clk_en0.modify(|_, w| w.pcnt_clk_en().set_bit());
perip_rst_en0.modify(|_, w| w.pcnt_rst().clear_bit());
}
#[cfg(any(esp32c2, esp32c3))] #[cfg(any(esp32c2, esp32c3))]
Peripheral::ApbSarAdc => { Peripheral::ApbSarAdc => {
perip_clk_en0.modify(|_, w| w.apb_saradc_clk_en().set_bit()); perip_clk_en0.modify(|_, w| w.apb_saradc_clk_en().set_bit());

View File

@ -0,0 +1,144 @@
//! 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
#![no_std]
#![no_main]
use core::{
cell::RefCell,
cmp::min,
sync::atomic::{AtomicI32, Ordering},
};
use critical_section::Mutex;
use esp32_hal as esp_hal;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
interrupt,
pcnt::{channel, channel::PcntSource, unit, PCNT},
peripherals::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_println::println;
use xtensa_lx_rt::entry;
static UNIT0: Mutex<RefCell<Option<unit::Unit>>> = Mutex::new(RefCell::new(None));
static VALUE: AtomicI32 = AtomicI32::new(0);
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.DPORT.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let unit_number = unit::Number::Unit1;
// setup a pulse couter
println!("setup pulse counter unit 0");
let pcnt = PCNT::new(peripherals.PCNT, &mut system.peripheral_clock_control);
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 mut pin_a = io.pins.gpio22.into_pull_up_input();
let mut pin_b = io.pins.gpio23.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;
}
});
}
}
#[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();
}
});
}

View File

@ -19,6 +19,7 @@ pub use esp_hal_common::{
ledc, ledc,
macros, macros,
mcpwm, mcpwm,
pcnt,
peripherals, peripherals,
prelude, prelude,
pulse_control, pulse_control,

View File

@ -0,0 +1,144 @@
//! 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
#![no_std]
#![no_main]
use core::{
cell::RefCell,
cmp::min,
sync::atomic::{AtomicI32, Ordering},
};
use critical_section::Mutex;
use esp32s2_hal as esp_hal;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
interrupt,
pcnt::{channel, channel::PcntSource, unit, PCNT},
peripherals::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_println::println;
use xtensa_lx_rt::entry;
static UNIT0: Mutex<RefCell<Option<unit::Unit>>> = Mutex::new(RefCell::new(None));
static VALUE: AtomicI32 = AtomicI32::new(0);
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let unit_number = unit::Number::Unit1;
// setup a pulse couter
println!("setup pulse counter unit 0");
let pcnt = PCNT::new(peripherals.PCNT, &mut system.peripheral_clock_control);
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 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;
}
});
}
}
#[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.store(VALUE.load(Ordering::SeqCst) + 100, Ordering::SeqCst);
} else if events.low_limit {
VALUE.store(VALUE.load(Ordering::SeqCst) - 100, Ordering::SeqCst);
}
u0.reset_interrupt();
}
});
}

View File

@ -18,6 +18,7 @@ pub use esp_hal_common::{
ledc, ledc,
macros, macros,
otg_fs, otg_fs,
pcnt,
peripherals, peripherals,
prelude, prelude,
pulse_control, pulse_control,

View File

@ -0,0 +1,144 @@
//! 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
#![no_std]
#![no_main]
use core::{
cell::RefCell,
cmp::min,
sync::atomic::{AtomicI32, Ordering},
};
use critical_section::Mutex;
use esp32s3_hal as esp_hal;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
interrupt,
pcnt::{channel, channel::PcntSource, unit, PCNT},
peripherals::{self, Peripherals},
prelude::*,
timer::TimerGroup,
Rtc,
IO,
};
use esp_println::println;
use xtensa_lx_rt::entry;
static UNIT0: Mutex<RefCell<Option<unit::Unit>>> = Mutex::new(RefCell::new(None));
static VALUE: AtomicI32 = AtomicI32::new(0);
#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let mut system = peripherals.SYSTEM.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
let mut rtc = Rtc::new(peripherals.RTC_CNTL);
let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut wdt = timer_group0.wdt;
let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
// Disable MWDT and RWDT (Watchdog) flash boot protection
wdt.disable();
rtc.rwdt.disable();
let unit_number = unit::Number::Unit1;
// setup a pulse couter
println!("setup pulse counter unit 0");
let pcnt = PCNT::new(peripherals.PCNT, &mut system.peripheral_clock_control);
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 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;
}
});
}
}
#[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();
}
});
}

View File

@ -20,6 +20,7 @@ pub use esp_hal_common::{
macros, macros,
mcpwm, mcpwm,
otg_fs, otg_fs,
pcnt,
peripherals, peripherals,
prelude, prelude,
pulse_control, pulse_control,