[esp32c3] SYSTIMER peripheral (#76)
* initial systimer impl * Add systimer example * Make Alarms real singletons * Remove runtime Option, turn into compile error * Make Systimer::now() not take self * refactor shared alarm methods * Implement esp32c3 delay with monotonic SystemTimer::now() * Add extend systimer support to esp32s3 and add example * systimer: esp32s2 support
This commit is contained in:
parent
0c61e7eeef
commit
4acdf2516c
@ -32,60 +32,33 @@ where
|
||||
mod delay {
|
||||
use fugit::HertzU64;
|
||||
|
||||
use crate::{clock::Clocks, pac::SYSTIMER};
|
||||
use crate::{clock::Clocks, systimer::SystemTimer};
|
||||
|
||||
/// Uses the `SYSTIMER` peripheral for counting clock cycles, as
|
||||
/// unfortunately the ESP32-C3 does NOT implement the `mcycle` CSR, which is
|
||||
/// how we would normally do this.
|
||||
pub struct Delay {
|
||||
systimer: SYSTIMER,
|
||||
freq: HertzU64,
|
||||
}
|
||||
|
||||
impl Delay {
|
||||
/// Create a new Delay instance
|
||||
pub fn new(systimer: SYSTIMER, clocks: &Clocks) -> Self {
|
||||
pub fn new(clocks: &Clocks) -> Self {
|
||||
// The counters and comparators are driven using `XTAL_CLK`. The average clock
|
||||
// frequency is fXTAL_CLK/2.5, which is 16 MHz. The timer counting is
|
||||
// incremented by 1/16 μs on each `CNT_CLK` cycle.
|
||||
|
||||
Self {
|
||||
systimer,
|
||||
freq: HertzU64::MHz((clocks.xtal_clock.to_MHz() * 10 / 25) as u64),
|
||||
}
|
||||
}
|
||||
|
||||
/// Return the raw interface to the underlying SYSTIMER instance
|
||||
pub fn free(self) -> SYSTIMER {
|
||||
self.systimer
|
||||
}
|
||||
|
||||
/// Delay for the specified number of microseconds
|
||||
pub fn delay(&self, us: u32) {
|
||||
let t0 = self.unit0_value();
|
||||
let t0 = SystemTimer::now();
|
||||
let clocks = (us as u64 * self.freq.raw()) / HertzU64::MHz(1).raw();
|
||||
|
||||
while self.unit0_value().wrapping_sub(t0) <= clocks {}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn unit0_value(&self) -> u64 {
|
||||
self.systimer
|
||||
.unit0_op
|
||||
.write(|w| w.timer_unit0_update().set_bit());
|
||||
|
||||
while !self
|
||||
.systimer
|
||||
.unit0_op
|
||||
.read()
|
||||
.timer_unit0_value_valid()
|
||||
.bit_is_set()
|
||||
{}
|
||||
|
||||
let value_lo = self.systimer.unit0_value_lo.read().bits();
|
||||
let value_hi = self.systimer.unit0_value_hi.read().bits();
|
||||
|
||||
((value_hi as u64) << 32) | value_lo as u64
|
||||
while SystemTimer::now().wrapping_sub(t0) <= clocks {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -58,6 +58,8 @@ pub use spi::Spi;
|
||||
pub use timer::Timer;
|
||||
#[cfg(any(feature = "esp32c3", feature = "esp32s3"))]
|
||||
pub use usb_serial_jtag::UsbSerialJtag;
|
||||
#[cfg(any(feature = "esp32c3", feature = "esp32s3", feature = "esp32s2"))]
|
||||
pub mod systimer;
|
||||
|
||||
pub mod clock;
|
||||
pub mod system;
|
||||
|
||||
175
esp-hal-common/src/systimer.rs
Normal file
175
esp-hal-common/src/systimer.rs
Normal file
@ -0,0 +1,175 @@
|
||||
use core::{intrinsics::transmute, marker::PhantomData};
|
||||
|
||||
use crate::pac::{
|
||||
generic::Reg,
|
||||
systimer::{
|
||||
target0_conf::TARGET0_CONF_SPEC,
|
||||
target0_hi::TARGET0_HI_SPEC,
|
||||
target0_lo::TARGET0_LO_SPEC,
|
||||
},
|
||||
SYSTIMER,
|
||||
};
|
||||
|
||||
// TODO this only handles unit0 of the systimer
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct SystemTimer {
|
||||
_inner: SYSTIMER,
|
||||
pub alarm0: Alarm<Target, 0>,
|
||||
pub alarm1: Alarm<Target, 1>,
|
||||
pub alarm2: Alarm<Target, 2>,
|
||||
}
|
||||
|
||||
impl SystemTimer {
|
||||
pub fn new(p: SYSTIMER) -> Self {
|
||||
Self {
|
||||
_inner: p,
|
||||
alarm0: Alarm::new(),
|
||||
alarm1: Alarm::new(),
|
||||
alarm2: Alarm::new(),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO use fugit types
|
||||
pub fn now() -> u64 {
|
||||
// This should be safe to access from multiple contexts
|
||||
// worst case scenario the second accesor ends up reading
|
||||
// an older time stamp
|
||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||
systimer
|
||||
.unit0_op
|
||||
.modify(|_, w| w.timer_unit0_update().set_bit());
|
||||
|
||||
while !systimer
|
||||
.unit0_op
|
||||
.read()
|
||||
.timer_unit0_value_valid()
|
||||
.bit_is_set()
|
||||
{}
|
||||
|
||||
let value_lo = systimer.unit0_value_lo.read().bits();
|
||||
let value_hi = systimer.unit0_value_hi.read().bits();
|
||||
|
||||
((value_hi as u64) << 32) | value_lo as u64
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Target;
|
||||
// pub struct Periodic; // TODO, also impl e-h timer traits
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Alarm<MODE, const CHANNEL: u8> {
|
||||
_pd: PhantomData<MODE>,
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> Alarm<T, CHANNEL> {
|
||||
// private constructor
|
||||
fn new() -> Self {
|
||||
Self { _pd: PhantomData }
|
||||
}
|
||||
|
||||
pub fn enable_interrupt(&self) {
|
||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||
match CHANNEL {
|
||||
0 => systimer
|
||||
.int_ena
|
||||
.modify(|_, w| w.target0_int_ena().set_bit()),
|
||||
1 => systimer
|
||||
.int_ena
|
||||
.modify(|_, w| w.target1_int_ena().set_bit()),
|
||||
2 => systimer
|
||||
.int_ena
|
||||
.modify(|_, w| w.target2_int_ena().set_bit()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clear_interrupt(&self) {
|
||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||
match CHANNEL {
|
||||
0 => systimer.int_clr.write(|w| w.target0_int_clr().set_bit()),
|
||||
1 => systimer.int_clr.write(|w| w.target1_int_clr().set_bit()),
|
||||
2 => systimer.int_clr.write(|w| w.target2_int_clr().set_bit()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const CHANNEL: u8> Alarm<Target, CHANNEL> {
|
||||
pub fn set_target(&self, timestamp: u64) {
|
||||
unsafe {
|
||||
let systimer = &*SYSTIMER::ptr();
|
||||
let (tconf, hi, lo): (
|
||||
&Reg<TARGET0_CONF_SPEC>,
|
||||
&Reg<TARGET0_HI_SPEC>,
|
||||
&Reg<TARGET0_LO_SPEC>,
|
||||
) = match CHANNEL {
|
||||
0 => (
|
||||
&systimer.target0_conf,
|
||||
&systimer.target0_hi,
|
||||
&systimer.target0_lo,
|
||||
),
|
||||
1 => (
|
||||
transmute(&systimer.target1_conf),
|
||||
transmute(&systimer.target1_hi),
|
||||
transmute(&systimer.target1_lo),
|
||||
),
|
||||
2 => (
|
||||
transmute(&systimer.target2_conf),
|
||||
transmute(&systimer.target2_hi),
|
||||
transmute(&systimer.target2_lo),
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
#[cfg(feature = "esp32s2")]
|
||||
systimer.step.write(|w| w.timer_xtal_step().bits(0x1)); // run at XTAL freq, not 80 * XTAL freq
|
||||
|
||||
#[cfg(any(feature = "esp32c3", feature = "esp32s3"))]
|
||||
{
|
||||
tconf.write(|w| w.target0_timer_unit_sel().clear_bit()); // default, use unit 0
|
||||
systimer
|
||||
.conf
|
||||
.modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit());
|
||||
}
|
||||
|
||||
tconf.write(|w| w.target0_period_mode().clear_bit()); // target mode
|
||||
hi.write(|w| w.timer_target0_hi().bits((timestamp >> 32) as u32));
|
||||
lo.write(|w| w.timer_target0_lo().bits((timestamp & 0xFFFF_FFFF) as u32));
|
||||
|
||||
#[cfg(any(feature = "esp32c3", feature = "esp32s3"))]
|
||||
{
|
||||
match CHANNEL {
|
||||
0 => {
|
||||
systimer
|
||||
.comp0_load
|
||||
.write(|w| w.timer_comp0_load().set_bit());
|
||||
}
|
||||
1 => systimer
|
||||
.comp1_load
|
||||
.write(|w| w.timer_comp1_load().set_bit()),
|
||||
2 => systimer
|
||||
.comp2_load
|
||||
.write(|w| w.timer_comp2_load().set_bit()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
systimer.conf.modify(|_r, w| match CHANNEL {
|
||||
0 => w.target0_work_en().set_bit(),
|
||||
1 => w.target1_work_en().set_bit(),
|
||||
2 => w.target2_work_en().set_bit(),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "esp32s2")]
|
||||
tconf.modify(|_r, w| match CHANNEL {
|
||||
0 => w.target0_work_en().set_bit(),
|
||||
1 => w.target0_work_en().set_bit(),
|
||||
2 => w.target0_work_en().set_bit(),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -39,7 +39,7 @@ fn main() -> ! {
|
||||
|
||||
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||
// loop.
|
||||
let mut delay = Delay::new(peripherals.SYSTIMER, &clocks);
|
||||
let mut delay = Delay::new(&clocks);
|
||||
|
||||
loop {
|
||||
led.toggle().unwrap();
|
||||
|
||||
@ -79,7 +79,7 @@ fn main() -> ! {
|
||||
riscv::interrupt::enable();
|
||||
}
|
||||
|
||||
let mut delay = Delay::new(peripherals.SYSTIMER, &clocks);
|
||||
let mut delay = Delay::new(&clocks);
|
||||
loop {
|
||||
led.toggle().unwrap();
|
||||
delay.delay_ms(500u32);
|
||||
|
||||
@ -65,7 +65,7 @@ fn main() -> ! {
|
||||
|
||||
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||
// loop.
|
||||
let mut delay = Delay::new(peripherals.SYSTIMER, &clocks);
|
||||
let mut delay = Delay::new(&clocks);
|
||||
|
||||
let mut color = Hsv {
|
||||
hue: 0,
|
||||
|
||||
@ -67,7 +67,7 @@ fn main() -> ! {
|
||||
&clocks,
|
||||
);
|
||||
|
||||
let mut delay = Delay::new(peripherals.SYSTIMER, &clocks);
|
||||
let mut delay = Delay::new(&clocks);
|
||||
|
||||
loop {
|
||||
let mut data = [0xde, 0xca, 0xfb, 0xad];
|
||||
|
||||
164
esp32c3-hal/examples/systimer.rs
Normal file
164
esp32c3-hal/examples/systimer.rs
Normal file
@ -0,0 +1,164 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
|
||||
use bare_metal::Mutex;
|
||||
use esp32c3_hal::{
|
||||
pac::{self, Peripherals, UART0},
|
||||
prelude::*,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
Timer,
|
||||
};
|
||||
use esp_hal_common::{
|
||||
interrupt::{self},
|
||||
systimer::{Alarm, SystemTimer, Target},
|
||||
Cpu,
|
||||
};
|
||||
use panic_halt as _;
|
||||
use riscv_rt::entry;
|
||||
|
||||
static mut SERIAL: Mutex<RefCell<Option<Serial<UART0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM0: Mutex<RefCell<Option<Alarm<Target, 0>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM1: Mutex<RefCell<Option<Alarm<Target, 1>>>> = Mutex::new(RefCell::new(None));
|
||||
static mut ALARM2: Mutex<RefCell<Option<Alarm<Target, 2>>>> = Mutex::new(RefCell::new(None));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
|
||||
// Disable the watchdog timers. For the ESP32-C3, this includes the Super WDT,
|
||||
// the RTC WDT, and the TIMG WDTs.
|
||||
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut timer1 = Timer::new(peripherals.TIMG1);
|
||||
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||
|
||||
rtc_cntl.set_super_wdt_enable(false);
|
||||
rtc_cntl.set_wdt_enable(false);
|
||||
timer0.disable();
|
||||
timer1.disable();
|
||||
|
||||
writeln!(serial0, "SYSTIMER Demo start!").ok();
|
||||
|
||||
let syst = SystemTimer::new(peripherals.SYSTIMER);
|
||||
|
||||
writeln!(serial0, "SYSTIMER Current value = {}", SystemTimer::now()).ok();
|
||||
|
||||
let alarm0 = syst.alarm0;
|
||||
alarm0.set_target(40_000_000);
|
||||
alarm0.enable_interrupt();
|
||||
|
||||
let alarm1 = syst.alarm1;
|
||||
alarm1.set_target(41_111_111);
|
||||
alarm1.enable_interrupt();
|
||||
|
||||
let alarm2 = syst.alarm2;
|
||||
alarm2.set_target(42_222_222 * 2);
|
||||
alarm2.enable_interrupt();
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET0,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
);
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET1,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
);
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET2,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_kind(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::InterruptKind::Level,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt1,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt2,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
interrupt::set_priority(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt3,
|
||||
interrupt::Priority::Priority1,
|
||||
);
|
||||
|
||||
riscv::interrupt::free(|_cs| unsafe {
|
||||
SERIAL.get_mut().replace(Some(serial0));
|
||||
ALARM0.get_mut().replace(Some(alarm0));
|
||||
ALARM1.get_mut().replace(Some(alarm1));
|
||||
ALARM2.get_mut().replace(Some(alarm2));
|
||||
});
|
||||
|
||||
unsafe {
|
||||
riscv::interrupt::enable();
|
||||
}
|
||||
|
||||
loop {}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt1() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 1 = {}", SystemTimer::now()).ok();
|
||||
|
||||
let mut alarm = ALARM0.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt1);
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt2() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 2 = {}", SystemTimer::now()).ok();
|
||||
|
||||
let mut alarm = ALARM1.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt2);
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn interrupt3() {
|
||||
riscv::interrupt::free(|cs| unsafe {
|
||||
let mut serial = SERIAL.borrow(*cs).borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt 3 = {}", SystemTimer::now()).ok();
|
||||
|
||||
let mut alarm = ALARM2.borrow(*cs).borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
|
||||
interrupt::clear(Cpu::ProCpu, interrupt::CpuInterrupt::Interrupt3);
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
@ -21,7 +21,7 @@ fn main() -> ! {
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let mut delay = Delay::new(peripherals.SYSTIMER, &clocks);
|
||||
let mut delay = Delay::new(&clocks);
|
||||
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut timer1 = Timer::new(peripherals.TIMG1);
|
||||
|
||||
@ -13,6 +13,7 @@ pub use esp_hal_common::{
|
||||
ram,
|
||||
spi,
|
||||
system,
|
||||
systimer,
|
||||
utils,
|
||||
Cpu,
|
||||
Delay,
|
||||
|
||||
173
esp32s2-hal/examples/systimer.rs
Normal file
173
esp32s2-hal/examples/systimer.rs
Normal file
@ -0,0 +1,173 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
|
||||
use esp32s2_hal::{
|
||||
clock::ClockControl,
|
||||
pac::{self, Peripherals, UART0},
|
||||
prelude::*,
|
||||
Delay,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
Timer,
|
||||
};
|
||||
use esp_hal_common::{
|
||||
interrupt,
|
||||
Cpu,
|
||||
systimer::{SystemTimer, Alarm, Target}
|
||||
};
|
||||
use panic_halt as _;
|
||||
use xtensa_lx::mutex::{Mutex, CriticalSectionMutex};
|
||||
use xtensa_lx_rt::entry;
|
||||
|
||||
static mut SERIAL: CriticalSectionMutex<RefCell<Option<Serial<UART0>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
static mut ALARM0: CriticalSectionMutex<RefCell<Option<Alarm<Target, 0>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
static mut ALARM1: CriticalSectionMutex<RefCell<Option<Alarm<Target, 1>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
static mut ALARM2: CriticalSectionMutex<RefCell<Option<Alarm<Target, 2>>>> =
|
||||
CriticalSectionMutex::new(RefCell::new(None));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
|
||||
let mut serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||
|
||||
// Disable MWDT and RWDT (Watchdog) flash boot protection
|
||||
timer0.disable();
|
||||
rtc_cntl.set_wdt_global_enable(false);
|
||||
|
||||
let syst = SystemTimer::new(peripherals.SYSTIMER);
|
||||
|
||||
let now = SystemTimer::now();
|
||||
|
||||
writeln!(serial0, "Now: {}", now).ok();
|
||||
|
||||
let alarm0 = syst.alarm0;
|
||||
alarm0.set_target(40_000_0000);
|
||||
alarm0.enable_interrupt();
|
||||
|
||||
let alarm1 = syst.alarm1;
|
||||
alarm1.set_target(41_111_1110);
|
||||
alarm1.enable_interrupt();
|
||||
|
||||
let alarm2 = syst.alarm2;
|
||||
alarm2.set_target(42_222_2220 * 2);
|
||||
alarm2.enable_interrupt();
|
||||
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
|
||||
(&ALARM0).lock(|data| (*data).replace(Some(alarm0)));
|
||||
(&ALARM1).lock(|data| (*data).replace(Some(alarm1)));
|
||||
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
|
||||
}
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET0,
|
||||
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
|
||||
);
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET1,
|
||||
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
|
||||
);
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET2,
|
||||
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
|
||||
);
|
||||
|
||||
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||
// loop.
|
||||
let mut delay = Delay::new(&clocks);
|
||||
|
||||
unsafe {
|
||||
xtensa_lx::interrupt::enable_mask(1 << 19 | 1 << 0 | 1 << 23 );
|
||||
}
|
||||
|
||||
loop {
|
||||
delay.delay_ms(500u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level1_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl1 (alarm0)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM0).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level2_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl2 (alarm1)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM1).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level3_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl3 (alarm2)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM2).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
169
esp32s3-hal/examples/systimer.rs
Normal file
169
esp32s3-hal/examples/systimer.rs
Normal file
@ -0,0 +1,169 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
use core::{cell::RefCell, fmt::Write};
|
||||
|
||||
use esp32s3_hal::{
|
||||
clock::ClockControl,
|
||||
pac::{self, Peripherals, UART0},
|
||||
prelude::*,
|
||||
Delay,
|
||||
RtcCntl,
|
||||
Serial,
|
||||
Timer,
|
||||
};
|
||||
use esp_hal_common::{
|
||||
interrupt,
|
||||
Cpu,
|
||||
systimer::{SystemTimer, Alarm, Target}
|
||||
};
|
||||
use panic_halt as _;
|
||||
use xtensa_lx::mutex::{Mutex, SpinLockMutex};
|
||||
use xtensa_lx_rt::entry;
|
||||
|
||||
static mut SERIAL: SpinLockMutex<RefCell<Option<Serial<UART0>>>> =
|
||||
SpinLockMutex::new(RefCell::new(None));
|
||||
static mut ALARM0: SpinLockMutex<RefCell<Option<Alarm<Target, 0>>>> =
|
||||
SpinLockMutex::new(RefCell::new(None));
|
||||
static mut ALARM1: SpinLockMutex<RefCell<Option<Alarm<Target, 1>>>> =
|
||||
SpinLockMutex::new(RefCell::new(None));
|
||||
static mut ALARM2: SpinLockMutex<RefCell<Option<Alarm<Target, 2>>>> =
|
||||
SpinLockMutex::new(RefCell::new(None));
|
||||
|
||||
#[entry]
|
||||
fn main() -> ! {
|
||||
let peripherals = Peripherals::take().unwrap();
|
||||
let system = peripherals.SYSTEM.split();
|
||||
let clocks = ClockControl::boot_defaults(system.clock_control).freeze();
|
||||
|
||||
let mut timer0 = Timer::new(peripherals.TIMG0);
|
||||
let mut rtc_cntl = RtcCntl::new(peripherals.RTC_CNTL);
|
||||
let serial0 = Serial::new(peripherals.UART0).unwrap();
|
||||
|
||||
// Disable MWDT and RWDT (Watchdog) flash boot protection
|
||||
timer0.disable();
|
||||
rtc_cntl.set_wdt_global_enable(false);
|
||||
|
||||
let syst = SystemTimer::new(peripherals.SYSTIMER);
|
||||
|
||||
let alarm0 = syst.alarm0;
|
||||
alarm0.set_target(40_000_000);
|
||||
alarm0.enable_interrupt();
|
||||
|
||||
let alarm1 = syst.alarm1;
|
||||
alarm1.set_target(41_111_111);
|
||||
alarm1.enable_interrupt();
|
||||
|
||||
let alarm2 = syst.alarm2;
|
||||
alarm2.set_target(42_222_222 * 2);
|
||||
alarm2.enable_interrupt();
|
||||
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| (*data).replace(Some(serial0)));
|
||||
(&ALARM0).lock(|data| (*data).replace(Some(alarm0)));
|
||||
(&ALARM1).lock(|data| (*data).replace(Some(alarm1)));
|
||||
(&ALARM2).lock(|data| (*data).replace(Some(alarm2)));
|
||||
}
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET0,
|
||||
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
|
||||
);
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET1,
|
||||
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
|
||||
);
|
||||
|
||||
interrupt::enable(
|
||||
Cpu::ProCpu,
|
||||
pac::Interrupt::SYSTIMER_TARGET2,
|
||||
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
|
||||
);
|
||||
|
||||
// Initialize the Delay peripheral, and use it to toggle the LED state in a
|
||||
// loop.
|
||||
let mut delay = Delay::new(&clocks);
|
||||
|
||||
unsafe {
|
||||
xtensa_lx::interrupt::enable_mask(1 << 19 | 1 << 0 | 1 << 23 );
|
||||
}
|
||||
|
||||
loop {
|
||||
delay.delay_ms(500u32);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level1_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl1 (alarm0)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt0LevelPriority1,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM0).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level2_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl2 (alarm1)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt19LevelPriority2,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM1).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn level3_interrupt() {
|
||||
unsafe {
|
||||
(&SERIAL).lock(|data| {
|
||||
let mut serial = data.borrow_mut();
|
||||
let serial = serial.as_mut().unwrap();
|
||||
writeln!(serial, "Interrupt lvl3 (alarm2)").ok();
|
||||
});
|
||||
}
|
||||
|
||||
interrupt::clear(
|
||||
Cpu::ProCpu,
|
||||
interrupt::CpuInterrupt::Interrupt23LevelPriority3,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
(&ALARM2).lock(|data| {
|
||||
let mut alarm = data.borrow_mut();
|
||||
let alarm = alarm.as_mut().unwrap();
|
||||
alarm.clear_interrupt();
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,7 @@ pub use esp_hal_common::{
|
||||
pulse_control,
|
||||
ram,
|
||||
spi,
|
||||
systimer,
|
||||
usb_serial_jtag,
|
||||
utils,
|
||||
Cpu,
|
||||
|
||||
Loading…
Reference in New Issue
Block a user