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:
parent
a542735847
commit
ac206af656
@ -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"]
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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,
|
||||||
|
|||||||
@ -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)]
|
||||||
|
|||||||
243
esp-hal-common/src/pcnt/channel.rs
Normal file
243
esp-hal-common/src/pcnt/channel.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
30
esp-hal-common/src/pcnt/mod.rs
Normal file
30
esp-hal-common/src/pcnt/mod.rs
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
392
esp-hal-common/src/pcnt/unit.rs
Normal file
392
esp-hal-common/src/pcnt/unit.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -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());
|
||||||
|
|||||||
144
esp32-hal/examples/pcnt_encoder.rs
Normal file
144
esp32-hal/examples/pcnt_encoder.rs
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -19,6 +19,7 @@ pub use esp_hal_common::{
|
|||||||
ledc,
|
ledc,
|
||||||
macros,
|
macros,
|
||||||
mcpwm,
|
mcpwm,
|
||||||
|
pcnt,
|
||||||
peripherals,
|
peripherals,
|
||||||
prelude,
|
prelude,
|
||||||
pulse_control,
|
pulse_control,
|
||||||
|
|||||||
144
esp32s2-hal/examples/pcnt_encoder.rs
Normal file
144
esp32s2-hal/examples/pcnt_encoder.rs
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -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,
|
||||||
|
|||||||
144
esp32s3-hal/examples/pcnt_encoder.rs
Normal file
144
esp32s3-hal/examples/pcnt_encoder.rs
Normal 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();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -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,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user