Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for multicore async GPIO (#542)
- Add initial support for MCPWM in ESP32-H2 (#544)
- Add some miscellaneous examples for the ESP32-H2 (#548)
- Add initial support for PCNT in ESP32-H2 (#551)

### Fixed

Expand Down
2 changes: 1 addition & 1 deletion esp-hal-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ esp32 = { version = "0.23.0", features = ["critical-section"], optional = true
esp32c2 = { version = "0.11.0", features = ["critical-section"], optional = true }
esp32c3 = { version = "0.14.0", features = ["critical-section"], optional = true }
esp32c6 = { version = "0.4.0", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "ff70333", package = "esp32h2", features = ["critical-section"], optional = true }
esp32h2 = { git = "https://github.com/esp-rs/esp-pacs", rev = "4fe0791", package = "esp32h2", features = ["critical-section"], optional = true }
esp32s2 = { version = "0.14.0", features = ["critical-section"], optional = true }
esp32s3 = { version = "0.18.0", features = ["critical-section"], optional = true }

Expand Down
2 changes: 1 addition & 1 deletion esp-hal-common/devices/esp32h2.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ peripherals = [
# "otp_debug",
# "parl_io",
# "pau",
# "pcnt",
"pcnt",
"pcr",
# "pmu",
# "rmt",
Expand Down
32 changes: 16 additions & 16 deletions esp-hal-common/src/soc/esp32h2/gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,22 +96,22 @@ pub enum InputSignal {
SIG_FUNC_98 = 98,
SIG_FUNC_99 = 99,
SIG_FUNC_100 = 100,
PCNT_SIG_CH00 = 101,
PCNT_SIG_CH10 = 102,
PCNT_CTRL_CH00 = 103,
PCNT_CTRL_CH10 = 104,
PCNT_SIG_CH01 = 105,
PCNT_SIG_CH11 = 106,
PCNT_CTRL_CH01 = 107,
PCNT_CTRL_CH11 = 108,
PCNT_SIG_CH02 = 109,
PCNT_SIG_CH12 = 110,
PCNT_CTRL_CH02 = 111,
PCNT_CTRL_CH12 = 112,
PCNT_SIG_CH03 = 113,
PCNT_SIG_CH13 = 114,
PCNT_CTRL_CH03 = 115,
PCNT_CTRL_CH13 = 116,
PCNT0_SIG_CH0 = 101,
PCNT0_SIG_CH1 = 102,
PCNT0_CTRL_CH0 = 103,
PCNT0_CTRL_CH1 = 104,
PCNT1_SIG_CH0 = 105,
PCNT1_SIG_CH1 = 106,
PCNT1_CTRL_CH0 = 107,
PCNT1_CTRL_CH1 = 108,
PCNT2_SIG_CH0 = 109,
PCNT2_SIG_CH1 = 110,
PCNT2_CTRL_CH0 = 111,
PCNT2_CTRL_CH1 = 112,
PCNT3_SIG_CH0 = 113,
PCNT3_SIG_CH1 = 114,
PCNT3_CTRL_CH0 = 115,
PCNT3_CTRL_CH1 = 116,
SPIQ = 121,
SPID = 122,
SPIHD = 123,
Expand Down
2 changes: 1 addition & 1 deletion esp-hal-common/src/soc/esp32h2/peripherals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ crate::peripherals! {
// OTP_DEBUG => true,
// PARL_IO => true,
// PAU => true,
// PCNT => true,
PCNT => true,
PCR => true,
// PMU => true,
// RMT => true,
Expand Down
157 changes: 157 additions & 0 deletions esp32h2-hal/examples/pcnt_encoder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//! 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 esp32h2_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;

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.PCR.split();
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

// Disable the watchdog timers. For the ESP32-H2, this includes the Super WDT,
// and the TIMG WDTs.
let mut rtc = Rtc::new(peripherals.LP_CLKRST);
let timer_group0 = TimerGroup::new(
peripherals.TIMG0,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt0 = timer_group0.wdt;
let timer_group1 = TimerGroup::new(
peripherals.TIMG1,
&clocks,
&mut system.peripheral_clock_control,
);
let mut wdt1 = timer_group1.wdt;

// Disable watchdog timers
rtc.swd.disable();
rtc.rwdt.disable();
wdt0.disable();
wdt1.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 io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut pin_a = io.pins.gpio4.into_pull_up_input();
let mut pin_b = io.pins.gpio5.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();
}
});
}