mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-10-02 14:44:42 +00:00
[3/3] Timer abstraction: cleanup, simplification, and documentation (#1630)
* Add a new `timg_timer1` symbol to `esp-metadata` definitions * Make `Timer::load_value` fallible (when the value is too large) * Clean up, simplify, and document the `timer` module and its submodules * Fix various issues * Update the timeout value verification for `SYSTIMER` * Clippy * Introduce new `PERIOD_MASK` constant for validating timeout values
This commit is contained in:
parent
7c25750e3a
commit
8aee84f842
@ -5,7 +5,11 @@ use super::AlarmState;
|
|||||||
use crate::{
|
use crate::{
|
||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
peripherals,
|
peripherals,
|
||||||
timer::systimer::{Alarm, SystemTimer, Target},
|
prelude::*,
|
||||||
|
timer::{
|
||||||
|
systimer::{Alarm, SystemTimer, Target},
|
||||||
|
Timer as _,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const ALARM_COUNT: usize = 3;
|
pub const ALARM_COUNT: usize = 3;
|
||||||
@ -43,9 +47,9 @@ impl EmbassyTimer {
|
|||||||
|
|
||||||
pub(super) fn on_alarm_allocated(&self, n: usize) {
|
pub(super) fn on_alarm_allocated(&self, n: usize) {
|
||||||
match n {
|
match n {
|
||||||
0 => self.alarm0.enable_interrupt_internal(true),
|
0 => self.alarm0.enable_interrupt(true),
|
||||||
1 => self.alarm1.enable_interrupt_internal(true),
|
1 => self.alarm1.enable_interrupt(true),
|
||||||
2 => self.alarm2.enable_interrupt_internal(true),
|
2 => self.alarm2.enable_interrupt(true),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,18 +130,18 @@ impl EmbassyTimer {
|
|||||||
|
|
||||||
fn clear_interrupt(&self, id: usize) {
|
fn clear_interrupt(&self, id: usize) {
|
||||||
match id {
|
match id {
|
||||||
0 => self.alarm0.clear_interrupt_internal(),
|
0 => self.alarm0.clear_interrupt(),
|
||||||
1 => self.alarm1.clear_interrupt_internal(),
|
1 => self.alarm1.clear_interrupt(),
|
||||||
2 => self.alarm2.clear_interrupt_internal(),
|
2 => self.alarm2.clear_interrupt(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arm(&self, id: usize, timestamp: u64) {
|
fn arm(&self, id: usize, timestamp: u64) {
|
||||||
match id {
|
match id {
|
||||||
0 => self.alarm0.set_target_internal(timestamp),
|
0 => self.alarm0.load_value(timestamp.micros()).unwrap(),
|
||||||
1 => self.alarm1.set_target_internal(timestamp),
|
1 => self.alarm1.load_value(timestamp.micros()).unwrap(),
|
||||||
2 => self.alarm2.set_target_internal(timestamp),
|
2 => self.alarm2.load_value(timestamp.micros()).unwrap(),
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,14 +43,14 @@ impl EmbassyTimer {
|
|||||||
|
|
||||||
pub(super) fn on_alarm_allocated(&self, _n: usize) {}
|
pub(super) fn on_alarm_allocated(&self, _n: usize) {}
|
||||||
|
|
||||||
fn on_interrupt<Timer: Instance>(&self, id: u8, mut timer: Timer) {
|
fn on_interrupt<Timer: Instance>(&self, id: u8, timer: Timer) {
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
timer.clear_interrupt();
|
timer.clear_interrupt();
|
||||||
self.trigger_alarm(id as usize, cs);
|
self.trigger_alarm(id as usize, cs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn init(clocks: &Clocks, mut timer: TimerType) {
|
pub fn init(clocks: &Clocks, timer: TimerType) {
|
||||||
// set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz...
|
// set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz...
|
||||||
timer.timer0.set_divider(clocks.apb_clock.to_MHz() as u16);
|
timer.timer0.set_divider(clocks.apb_clock.to_MHz() as u16);
|
||||||
timer.timer0.set_counter_active(true);
|
timer.timer0.set_counter_active(true);
|
||||||
|
@ -1,4 +1,34 @@
|
|||||||
//! General-purpose timers.
|
//! # General-purpose Timers
|
||||||
|
//!
|
||||||
|
//! The [OneShotTimer] and [PeriodicTimer] types can be backed by any hardware
|
||||||
|
//! peripheral which implements the [Timer] trait.
|
||||||
|
//!
|
||||||
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! ### Examples
|
||||||
|
//!
|
||||||
|
//! #### One-shot Timer
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None);
|
||||||
|
//! let one_shot = OneShotTimer::new(timg0.timer0);
|
||||||
|
//!
|
||||||
|
//! one_shot.delay_millis(500);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #### Periodic Timer
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None);
|
||||||
|
//! let periodic = PeriodicTimer::new(timg0.timer0);
|
||||||
|
//!
|
||||||
|
//! periodic.start(1.secs());
|
||||||
|
//! loop {
|
||||||
|
//! nb::block!(periodic.wait());
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use fugit::{ExtU64, Instant, MicrosDurationU64};
|
use fugit::{ExtU64, Instant, MicrosDurationU64};
|
||||||
|
|
||||||
@ -17,6 +47,8 @@ pub enum Error {
|
|||||||
TimerInactive,
|
TimerInactive,
|
||||||
/// The alarm is not currently active.
|
/// The alarm is not currently active.
|
||||||
AlarmInactive,
|
AlarmInactive,
|
||||||
|
/// The provided timeout is too large.
|
||||||
|
InvalidTimeout,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Functionality provided by any timer peripheral.
|
/// Functionality provided by any timer peripheral.
|
||||||
@ -37,7 +69,7 @@ pub trait Timer: crate::private::Sealed {
|
|||||||
fn now(&self) -> Instant<u64, 1, 1_000_000>;
|
fn now(&self) -> Instant<u64, 1, 1_000_000>;
|
||||||
|
|
||||||
/// Load a target value into the timer.
|
/// Load a target value into the timer.
|
||||||
fn load_value(&self, value: MicrosDurationU64);
|
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error>;
|
||||||
|
|
||||||
/// Enable auto reload of the loaded value.
|
/// Enable auto reload of the loaded value.
|
||||||
fn enable_auto_reload(&self, auto_reload: bool);
|
fn enable_auto_reload(&self, auto_reload: bool);
|
||||||
@ -51,7 +83,8 @@ pub trait Timer: crate::private::Sealed {
|
|||||||
/// Has the timer triggered?
|
/// Has the timer triggered?
|
||||||
fn is_interrupt_set(&self) -> bool;
|
fn is_interrupt_set(&self) -> bool;
|
||||||
|
|
||||||
/// FIXME: This is (hopefully?) temporary...
|
// NOTE: This is an unfortunate implementation detail of `TIMGx`
|
||||||
|
#[doc(hidden)]
|
||||||
fn set_alarm_active(&self, state: bool);
|
fn set_alarm_active(&self, state: bool);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +126,7 @@ where
|
|||||||
self.inner.reset();
|
self.inner.reset();
|
||||||
|
|
||||||
self.inner.enable_auto_reload(false);
|
self.inner.enable_auto_reload(false);
|
||||||
self.inner.load_value(us);
|
self.inner.load_value(us).unwrap();
|
||||||
self.inner.start();
|
self.inner.start();
|
||||||
|
|
||||||
while !self.inner.is_interrupt_set() {
|
while !self.inner.is_interrupt_set() {
|
||||||
@ -132,9 +165,8 @@ impl<T> embedded_hal::delay::DelayNs for OneShotTimer<T>
|
|||||||
where
|
where
|
||||||
T: Timer,
|
T: Timer,
|
||||||
{
|
{
|
||||||
#[allow(clippy::useless_conversion)]
|
|
||||||
fn delay_ns(&mut self, ns: u32) {
|
fn delay_ns(&mut self, ns: u32) {
|
||||||
self.delay_nanos(ns.into());
|
self.delay_nanos(ns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +185,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Start a new count down.
|
/// Start a new count down.
|
||||||
pub fn start(&mut self, timeout: MicrosDurationU64) {
|
pub fn start(&mut self, timeout: MicrosDurationU64) -> Result<(), Error> {
|
||||||
if self.inner.is_running() {
|
if self.inner.is_running() {
|
||||||
self.inner.stop();
|
self.inner.stop();
|
||||||
}
|
}
|
||||||
@ -162,15 +194,17 @@ where
|
|||||||
self.inner.reset();
|
self.inner.reset();
|
||||||
|
|
||||||
self.inner.enable_auto_reload(true);
|
self.inner.enable_auto_reload(true);
|
||||||
self.inner.load_value(timeout);
|
self.inner.load_value(timeout)?;
|
||||||
self.inner.start();
|
self.inner.start();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// "Wait" until the count down finishes without blocking.
|
/// "Wait" until the count down finishes without blocking.
|
||||||
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
|
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||||
if self.inner.is_interrupt_set() {
|
if self.inner.is_interrupt_set() {
|
||||||
self.inner.clear_interrupt();
|
self.inner.clear_interrupt();
|
||||||
self.inner.set_alarm_active(true); // FIXME: Remove if/when able
|
self.inner.set_alarm_active(true);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
@ -201,7 +235,7 @@ where
|
|||||||
where
|
where
|
||||||
Time: Into<Self::Time>,
|
Time: Into<Self::Time>,
|
||||||
{
|
{
|
||||||
self.start(timeout.into());
|
self.start(timeout.into()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||||
|
@ -1,33 +1,42 @@
|
|||||||
//! # System Timer peripheral driver
|
//! # System Timer (SYSTIMER)
|
||||||
//!
|
//!
|
||||||
//! The System Timer is a
|
//! The System Timer is a
|
||||||
#![cfg_attr(esp32s2, doc = "`64-bit`")]
|
#![cfg_attr(esp32s2, doc = "64-bit")]
|
||||||
#![cfg_attr(not(esp32s2), doc = "`54-bit`")]
|
#![cfg_attr(not(esp32s2), doc = "52-bit")]
|
||||||
//! timer with three comparators capable of raising an alarm interupt on each.
|
//! timer which can be used, for example, to generate tick interrupts for an
|
||||||
|
//! operating system, or simply as a general-purpose timer.
|
||||||
//!
|
//!
|
||||||
//! To obtain the current timer value, call [`SystemTimer::now`].
|
//! The timer consists of two counters, `UNIT0` and `UNIT1`. The counter values
|
||||||
|
//! can be monitored by 3 comparators, `COMP0`, `COMP1`, and `COMP2`.
|
||||||
//!
|
//!
|
||||||
//! [`Alarm`]'s can be configured into two different modes:
|
//! [Alarm]s can be configured in two modes: [Target] (one-shot) and [Periodic].
|
||||||
//!
|
//!
|
||||||
//! - [`Target`], for one-shot timer behaviour.
|
//! ## Usage
|
||||||
//! - [`Periodic`], for alarm triggers at a repeated interval.
|
//!
|
||||||
|
//! ### Examples
|
||||||
|
//!
|
||||||
|
//! #### General-purpose Timer
|
||||||
//!
|
//!
|
||||||
//! ## Example
|
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! let peripherals = Peripherals::take();
|
|
||||||
//!
|
|
||||||
//! let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
//! let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
//! println!("SYSTIMER Current value = {}", SystemTimer::now());
|
|
||||||
//!
|
//!
|
||||||
//! let mut alarm0 = systimer.alarm0;
|
//! // Get the current timestamp, in microseconds:
|
||||||
//! // Block for a second
|
//! let now = systimer.now();
|
||||||
//! alarm0.wait_until(SystemTimer::now().wrapping_add(SystemTimer::TICKS_PER_SECOND));
|
//!
|
||||||
|
//! // Wait for timeout:
|
||||||
|
//! systimer.load_value(1.secs());
|
||||||
|
//! systimer.start();
|
||||||
|
//!
|
||||||
|
//! while !systimer.is_interrupt_set() {
|
||||||
|
//! // Wait
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use fugit::{Instant, MicrosDurationU32, MicrosDurationU64};
|
use fugit::{Instant, MicrosDurationU32, MicrosDurationU64};
|
||||||
|
|
||||||
|
use super::{Error, Timer as _};
|
||||||
use crate::{
|
use crate::{
|
||||||
interrupt::{self, InterruptHandler},
|
interrupt::{self, InterruptHandler},
|
||||||
peripheral::Peripheral,
|
peripheral::Peripheral,
|
||||||
@ -41,18 +50,18 @@ use crate::{
|
|||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// The SystemTimer
|
/// System Timer driver.
|
||||||
pub struct SystemTimer<'d, DM>
|
pub struct SystemTimer<'d, DM>
|
||||||
where
|
where
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
|
_phantom: PhantomData<&'d ()>,
|
||||||
/// Alarm 0.
|
/// Alarm 0.
|
||||||
pub alarm0: Alarm<Target, DM, 0>,
|
pub alarm0: Alarm<Target, DM, 0>,
|
||||||
/// Alarm 1.
|
/// Alarm 1.
|
||||||
pub alarm1: Alarm<Target, DM, 1>,
|
pub alarm1: Alarm<Target, DM, 1>,
|
||||||
/// Alarm 2.
|
/// Alarm 2.
|
||||||
pub alarm2: Alarm<Target, DM, 2>,
|
pub alarm2: Alarm<Target, DM, 2>,
|
||||||
_phantom: PhantomData<&'d ()>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'d> SystemTimer<'d, Blocking> {
|
impl<'d> SystemTimer<'d, Blocking> {
|
||||||
@ -62,11 +71,15 @@ impl<'d> SystemTimer<'d, Blocking> {
|
|||||||
pub const BIT_MASK: u64 = u64::MAX;
|
pub const BIT_MASK: u64 = u64::MAX;
|
||||||
/// The ticks per second the underlying peripheral uses.
|
/// The ticks per second the underlying peripheral uses.
|
||||||
pub const TICKS_PER_SECOND: u64 = 80_000_000;
|
pub const TICKS_PER_SECOND: u64 = 80_000_000;
|
||||||
|
// Bitmask to be applied to the raw period register value.
|
||||||
|
const PERIOD_MASK: u64 = 0x1FFF_FFFF;
|
||||||
} else {
|
} else {
|
||||||
/// Bitmask to be applied to the raw register value.
|
/// Bitmask to be applied to the raw register value.
|
||||||
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
|
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
|
||||||
/// The ticks per second the underlying peripheral uses.
|
/// The ticks per second the underlying peripheral uses.
|
||||||
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
||||||
|
// Bitmask to be applied to the raw period register value.
|
||||||
|
const PERIOD_MASK: u64 = 0x3FF_FFFF;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,14 +89,14 @@ impl<'d> SystemTimer<'d, Blocking> {
|
|||||||
etm::enable_etm();
|
etm::enable_etm();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
_phantom: PhantomData,
|
||||||
alarm0: Alarm::new(),
|
alarm0: Alarm::new(),
|
||||||
alarm1: Alarm::new(),
|
alarm1: Alarm::new(),
|
||||||
alarm2: Alarm::new(),
|
alarm2: Alarm::new(),
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current count of unit 0 in the system timer.
|
/// Get the current count of Unit 0 in the System Timer.
|
||||||
pub fn now() -> u64 {
|
pub fn now() -> u64 {
|
||||||
// This should be safe to access from multiple contexts
|
// This should be safe to access from multiple contexts
|
||||||
// worst case scenario the second accessor ends up reading
|
// worst case scenario the second accessor ends up reading
|
||||||
@ -136,7 +149,6 @@ impl<T, DM, const CHANNEL: u8> Alarm<T, DM, CHANNEL>
|
|||||||
where
|
where
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
// private constructor
|
|
||||||
fn new() -> Self {
|
fn new() -> Self {
|
||||||
Self { _pd: PhantomData }
|
Self { _pd: PhantomData }
|
||||||
}
|
}
|
||||||
@ -178,36 +190,6 @@ where
|
|||||||
tconf.modify(|_r, w| w.work_en().set_bit());
|
tconf.modify(|_r, w| w.work_en().set_bit());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn enable_interrupt_internal(&self, val: bool) {
|
|
||||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
|
||||||
systimer.int_ena().modify(|_, w| w.target(CHANNEL).bit(val));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn clear_interrupt_internal(&self) {
|
|
||||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
|
||||||
systimer
|
|
||||||
.int_clr()
|
|
||||||
.write(|w| w.target(CHANNEL).clear_bit_by_one());
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_target_internal(&self, timestamp: u64) {
|
|
||||||
self.configure(|tconf, target| unsafe {
|
|
||||||
tconf.write(|w| w.period_mode().clear_bit()); // target mode
|
|
||||||
target.hi().write(|w| w.hi().bits((timestamp >> 32) as u32));
|
|
||||||
target
|
|
||||||
.lo()
|
|
||||||
.write(|w| w.lo().set((timestamp & 0xFFFF_FFFF) as u32));
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn set_period_internal(&self, ticks: u32) {
|
|
||||||
self.configure(|tconf, target| {
|
|
||||||
tconf.write(|w| unsafe { w.period_mode().set_bit().period().bits(ticks) });
|
|
||||||
target.hi().write(|w| w.hi().set(0));
|
|
||||||
target.lo().write(|w| w.lo().set(0));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, const CHANNEL: u8> Alarm<T, Blocking, CHANNEL> {
|
impl<T, const CHANNEL: u8> Alarm<T, Blocking, CHANNEL> {
|
||||||
@ -238,16 +220,6 @@ impl<T, const CHANNEL: u8> Alarm<T, Blocking, CHANNEL> {
|
|||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enable the interrupt for this alarm.
|
|
||||||
pub fn enable_interrupt(&mut self, val: bool) {
|
|
||||||
self.enable_interrupt_internal(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enable the interrupt pending status for this alarm.
|
|
||||||
pub fn clear_interrupt(&mut self) {
|
|
||||||
self.clear_interrupt_internal();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<DM, const CHANNEL: u8> Alarm<Target, DM, CHANNEL>
|
impl<DM, const CHANNEL: u8> Alarm<Target, DM, CHANNEL>
|
||||||
@ -256,13 +228,20 @@ where
|
|||||||
{
|
{
|
||||||
/// Set the target value of this [Alarm]
|
/// Set the target value of this [Alarm]
|
||||||
pub fn set_target(&mut self, timestamp: u64) {
|
pub fn set_target(&mut self, timestamp: u64) {
|
||||||
self.set_target_internal(timestamp);
|
self.configure(|tconf, target| unsafe {
|
||||||
|
tconf.write(|w| w.period_mode().clear_bit()); // target mode
|
||||||
|
target.hi().write(|w| w.hi().bits((timestamp >> 32) as u32));
|
||||||
|
target
|
||||||
|
.lo()
|
||||||
|
.write(|w| w.lo().set((timestamp & 0xFFFF_FFFF) as u32));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Block waiting until the timer reaches the `timestamp`
|
/// Block waiting until the timer reaches the `timestamp`
|
||||||
pub fn wait_until(&mut self, timestamp: u64) {
|
pub fn wait_until(&mut self, timestamp: u64) {
|
||||||
self.clear_interrupt_internal();
|
self.clear_interrupt();
|
||||||
self.set_target(timestamp);
|
self.set_target(timestamp);
|
||||||
|
|
||||||
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw();
|
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw();
|
||||||
loop {
|
loop {
|
||||||
if r.read().target(CHANNEL).bit_is_set() {
|
if r.read().target(CHANNEL).bit_is_set() {
|
||||||
@ -286,7 +265,11 @@ where
|
|||||||
let us = period.ticks();
|
let us = period.ticks();
|
||||||
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32;
|
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32;
|
||||||
|
|
||||||
self.set_period_internal(ticks);
|
self.configure(|tconf, target| {
|
||||||
|
tconf.write(|w| unsafe { w.period_mode().set_bit().period().bits(ticks) });
|
||||||
|
target.hi().write(|w| w.hi().set(0));
|
||||||
|
target.lo().write(|w| w.lo().set(0));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Converts this [Alarm] into [Target] mode
|
/// Converts this [Alarm] into [Target] mode
|
||||||
@ -350,12 +333,9 @@ where
|
|||||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(esp32s2)]
|
||||||
match CHANNEL {
|
systimer
|
||||||
0 => systimer.target0_conf().modify(|_, w| w.work_en().set_bit()),
|
.target_conf(CHANNEL as usize)
|
||||||
1 => systimer.target1_conf().modify(|_, w| w.work_en().set_bit()),
|
.modify(|_, w| w.work_en().set_bit());
|
||||||
2 => systimer.target2_conf().modify(|_, w| w.work_en().set_bit()),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
systimer.conf().modify(|_, w| match CHANNEL {
|
systimer.conf().modify(|_, w| match CHANNEL {
|
||||||
@ -370,18 +350,9 @@ where
|
|||||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(esp32s2)]
|
||||||
match CHANNEL {
|
systimer
|
||||||
0 => systimer
|
.target_conf(CHANNEL as usize)
|
||||||
.target0_conf()
|
.modify(|_, w| w.work_en().clear_bit());
|
||||||
.modify(|_, w| w.work_en().clear_bit()),
|
|
||||||
1 => systimer
|
|
||||||
.target1_conf()
|
|
||||||
.modify(|_, w| w.work_en().clear_bit()),
|
|
||||||
2 => systimer
|
|
||||||
.target2_conf()
|
|
||||||
.modify(|_, w| w.work_en().clear_bit()),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
systimer.conf().modify(|_, w| match CHANNEL {
|
systimer.conf().modify(|_, w| match CHANNEL {
|
||||||
@ -416,11 +387,12 @@ where
|
|||||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||||
|
|
||||||
#[cfg(esp32s2)]
|
#[cfg(esp32s2)]
|
||||||
match CHANNEL {
|
{
|
||||||
0 => systimer.target0_conf().read().work_en().bit_is_set(),
|
systimer
|
||||||
1 => systimer.target1_conf().read().work_en().bit_is_set(),
|
.target_conf(CHANNEL as usize)
|
||||||
2 => systimer.target2_conf().read().work_en().bit_is_set(),
|
.read()
|
||||||
_ => unreachable!(),
|
.work_en()
|
||||||
|
.bit_is_set()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
@ -452,8 +424,7 @@ where
|
|||||||
Instant::<u64, 1, 1_000_000>::from_ticks(us)
|
Instant::<u64, 1, 1_000_000>::from_ticks(us)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::unnecessary_cast)]
|
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
|
||||||
fn load_value(&self, value: MicrosDurationU64) {
|
|
||||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||||
|
|
||||||
let auto_reload = systimer
|
let auto_reload = systimer
|
||||||
@ -463,11 +434,18 @@ where
|
|||||||
.bit_is_set();
|
.bit_is_set();
|
||||||
|
|
||||||
let us = value.ticks();
|
let us = value.ticks();
|
||||||
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u64;
|
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000);
|
||||||
|
|
||||||
if auto_reload {
|
if auto_reload {
|
||||||
// Period mode
|
// Period mode
|
||||||
|
|
||||||
|
// The `SYSTIMER_TARGETx_PERIOD` field is 26-bits wide (or
|
||||||
|
// 29-bits on the ESP32-S2), so we must ensure that the provided
|
||||||
|
// value is not too wide:
|
||||||
|
if (ticks & !SystemTimer::PERIOD_MASK) != 0 {
|
||||||
|
return Err(Error::InvalidTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
systimer
|
systimer
|
||||||
.target_conf(CHANNEL as usize)
|
.target_conf(CHANNEL as usize)
|
||||||
.modify(|_, w| unsafe { w.period().bits(ticks as u32) });
|
.modify(|_, w| unsafe { w.period().bits(ticks as u32) });
|
||||||
@ -493,6 +471,14 @@ where
|
|||||||
// Wait for value registers to update
|
// Wait for value registers to update
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The counters/comparators are 52-bits wide (except on ESP32-S2,
|
||||||
|
// which is 64-bits), so we must ensure that the provided value
|
||||||
|
// is not too wide:
|
||||||
|
#[cfg(not(esp32s2))]
|
||||||
|
if (ticks & !SystemTimer::BIT_MASK) != 0 {
|
||||||
|
return Err(Error::InvalidTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
let hi = systimer.unit0_value().hi().read().bits();
|
let hi = systimer.unit0_value().hi().read().bits();
|
||||||
let lo = systimer.unit0_value().lo().read().bits();
|
let lo = systimer.unit0_value().lo().read().bits();
|
||||||
|
|
||||||
@ -513,6 +499,8 @@ where
|
|||||||
.comp_load(CHANNEL as usize)
|
.comp_load(CHANNEL as usize)
|
||||||
.write(|w| w.load().set_bit());
|
.write(|w| w.load().set_bit());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_auto_reload(&self, auto_reload: bool) {
|
fn enable_auto_reload(&self, auto_reload: bool) {
|
||||||
@ -571,7 +559,7 @@ mod asynch {
|
|||||||
|
|
||||||
impl<'a, const N: u8> AlarmFuture<'a, N> {
|
impl<'a, const N: u8> AlarmFuture<'a, N> {
|
||||||
pub(crate) fn new(alarm: &'a Alarm<Periodic, crate::Async, N>) -> Self {
|
pub(crate) fn new(alarm: &'a Alarm<Periodic, crate::Async, N>) -> Self {
|
||||||
alarm.clear_interrupt_internal();
|
alarm.clear_interrupt();
|
||||||
|
|
||||||
let (interrupt, handler) = match N {
|
let (interrupt, handler) = match N {
|
||||||
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
|
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
|
||||||
@ -584,7 +572,7 @@ mod asynch {
|
|||||||
interrupt::enable(interrupt, handler.priority()).unwrap();
|
interrupt::enable(interrupt, handler.priority()).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
alarm.enable_interrupt_internal(true);
|
alarm.enable_interrupt(true);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
|
@ -1,39 +1,53 @@
|
|||||||
//! # General-purpose timers
|
//! # Timer Group (TIMG)
|
||||||
//!
|
//!
|
||||||
//! ## Overview
|
//! The Timer Group (TIMG) peripherals contain one or more general-purpose
|
||||||
//! The `general-purpose timer` peripheral consists of a timer group, which can
|
//! timers, plus one or more watchdog timers.
|
||||||
//! have up to two timers (depending on the chip) and a watchdog timer. The
|
|
||||||
//! timer group allows for the management of multiple timers and synchronization
|
|
||||||
//! between them.
|
|
||||||
//!
|
//!
|
||||||
//! This peripheral can be used to perform a variety of
|
//! The general-purpose timers are based on a 16-bit pre-scaler and a 54-bit
|
||||||
//! tasks, such as triggering an interrupt after a particular interval
|
//! auto-reload-capable up-down counter. The timers have configurable alarms,
|
||||||
//! (periodically and aperiodically), precisely time an interval, act as a
|
//! which are triggered when the internal counter of the timers reaches a
|
||||||
//! hardware clock and so on.
|
//! specific target value. The timers are clocked using the APB clock source.
|
||||||
//!
|
//!
|
||||||
//! Each timer group consists of two general purpose timers and one Main System
|
//! Typically, a general-purpose timer can be used in scenarios such as:
|
||||||
//! Watchdog Timer(MSWDT). All general purpose timers are based on 16-bit
|
|
||||||
//! prescalers and 54-bit auto-reload-capable up-down counters.
|
|
||||||
//!
|
//!
|
||||||
//! The driver uses APB as it's clock source.
|
//! - Generate period alarms; trigger events periodically
|
||||||
|
//! - Generate one-shot alarms; trigger events once
|
||||||
|
//! - Free-running; fetching a high-resolution timestamp on demand
|
||||||
//!
|
//!
|
||||||
//! ## Example
|
//! ## Usage
|
||||||
|
//!
|
||||||
|
//! ### Examples
|
||||||
|
//!
|
||||||
|
//! #### General-purpose Timer
|
||||||
//!
|
//!
|
||||||
//! ```no_run
|
//! ```no_run
|
||||||
//! let mut rtc = Rtc::new(peripherals.LPWR, None);
|
//! let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||||
|
//! let timer0 = timg0.timer0;
|
||||||
//!
|
//!
|
||||||
//! // Create timer groups
|
//! // Get the current timestamp, in microseconds:
|
||||||
//! let timer_group0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
//! let now = timer0.now();
|
||||||
//! // Get watchdog timers of timer groups
|
|
||||||
//! let mut wdt0 = timer_group0.wdt;
|
|
||||||
//! let timer_group1 = TimerGroup::new(peripherals.TIMG1, &clocks);
|
|
||||||
//! let mut wdt1 = timer_group1.wdt;
|
|
||||||
//!
|
//!
|
||||||
//! // Disable watchdog timers
|
//! // Wait for timeout:
|
||||||
//! rtc.swd.disable();
|
//! timer0.load_value(1.secs());
|
||||||
//! rtc.rwdt.disable();
|
//! timer0.start();
|
||||||
//! wdt0.disable();
|
//!
|
||||||
//! wdt1.disable();
|
//! while !timer0.is_interrupt_set() {
|
||||||
|
//! // Wait
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! #### Watchdog Timer
|
||||||
|
//!
|
||||||
|
//! ```no_run
|
||||||
|
//! let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
|
||||||
|
//! let mut wdt = timg0.wdt;
|
||||||
|
//!
|
||||||
|
//! wdt.set_timeout(5_000.millis());
|
||||||
|
//! wdt.enable();
|
||||||
|
//!
|
||||||
|
//! loop {
|
||||||
|
//! wdt.feed();
|
||||||
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use core::{
|
use core::{
|
||||||
@ -43,64 +57,78 @@ use core::{
|
|||||||
|
|
||||||
use fugit::{HertzU32, Instant, MicrosDurationU64};
|
use fugit::{HertzU32, Instant, MicrosDurationU64};
|
||||||
|
|
||||||
|
use super::Error;
|
||||||
#[cfg(timg1)]
|
#[cfg(timg1)]
|
||||||
use crate::peripherals::TIMG1;
|
use crate::peripherals::TIMG1;
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
|
use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
|
||||||
use crate::{
|
use crate::{
|
||||||
clock::Clocks,
|
clock::Clocks,
|
||||||
interrupt::InterruptHandler,
|
interrupt::{self, InterruptHandler},
|
||||||
peripheral::{Peripheral, PeripheralRef},
|
peripheral::{Peripheral, PeripheralRef},
|
||||||
peripherals::{timg0::RegisterBlock, TIMG0},
|
peripherals::{timg0::RegisterBlock, Interrupt, TIMG0},
|
||||||
|
private::Sealed,
|
||||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||||
Async,
|
Async,
|
||||||
Blocking,
|
Blocking,
|
||||||
Mode,
|
Mode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Interrupts which can be registered in [crate::Blocking] mode
|
/// Interrupts which can be registered in [Blocking] mode
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct TimerInterrupts {
|
pub struct TimerInterrupts {
|
||||||
|
/// T0 Interrupt for [`Timer0`]
|
||||||
pub timer0_t0: Option<InterruptHandler>,
|
pub timer0_t0: Option<InterruptHandler>,
|
||||||
|
/// T1 Interrupt for [`Timer0`]
|
||||||
pub timer0_t1: Option<InterruptHandler>,
|
pub timer0_t1: Option<InterruptHandler>,
|
||||||
|
/// WDT Interrupt for [`Timer0`]
|
||||||
pub timer0_wdt: Option<InterruptHandler>,
|
pub timer0_wdt: Option<InterruptHandler>,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
/// T0 Interrupt for [`Timer1`]
|
||||||
|
#[cfg(timg_timer1)]
|
||||||
pub timer1_t0: Option<InterruptHandler>,
|
pub timer1_t0: Option<InterruptHandler>,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
/// T1 Interrupt for [`Timer1`]
|
||||||
|
#[cfg(timg_timer1)]
|
||||||
pub timer1_t1: Option<InterruptHandler>,
|
pub timer1_t1: Option<InterruptHandler>,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
/// WDT Interrupt for [`Timer1`]
|
||||||
|
#[cfg(timg_timer1)]
|
||||||
pub timer1_wdt: Option<InterruptHandler>,
|
pub timer1_wdt: Option<InterruptHandler>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// A timergroup consisting of up to 2 timers (chip dependent) and a watchdog
|
/// A timer group consisting of up to 2 timers (chip dependent) and a watchdog
|
||||||
// timer
|
/// timer.
|
||||||
pub struct TimerGroup<'d, T, DM>
|
pub struct TimerGroup<'d, T, DM>
|
||||||
where
|
where
|
||||||
T: TimerGroupInstance,
|
T: TimerGroupInstance,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
_timer_group: PeripheralRef<'d, T>,
|
_timer_group: PeripheralRef<'d, T>,
|
||||||
|
/// Timer 0
|
||||||
pub timer0: Timer<Timer0<T>, DM>,
|
pub timer0: Timer<Timer0<T>, DM>,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
/// Timer 1
|
||||||
|
#[cfg(timg_timer1)]
|
||||||
pub timer1: Timer<Timer1<T>, DM>,
|
pub timer1: Timer<Timer1<T>, DM>,
|
||||||
|
/// Watchdog timer
|
||||||
pub wdt: Wdt<T, DM>,
|
pub wdt: Wdt<T, DM>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
pub trait TimerGroupInstance {
|
pub trait TimerGroupInstance {
|
||||||
|
fn id() -> u8;
|
||||||
fn register_block() -> *const RegisterBlock;
|
fn register_block() -> *const RegisterBlock;
|
||||||
fn configure_src_clk();
|
fn configure_src_clk();
|
||||||
fn configure_wdt_src_clk();
|
fn configure_wdt_src_clk();
|
||||||
fn id() -> u8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TimerGroupInstance for TIMG0 {
|
impl TimerGroupInstance for TIMG0 {
|
||||||
fn id() -> u8 {
|
fn id() -> u8 {
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn register_block() -> *const RegisterBlock {
|
fn register_block() -> *const RegisterBlock {
|
||||||
crate::peripherals::TIMG0::PTR
|
TIMG0::PTR
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
@ -108,6 +136,7 @@ impl TimerGroupInstance for TIMG0 {
|
|||||||
.timergroup0_timer_clk_conf()
|
.timergroup0_timer_clk_conf()
|
||||||
.modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
|
.modify(|_, w| unsafe { w.tg0_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
|
#[cfg(any(esp32c2, esp32c3, esp32s2, esp32s3))]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
@ -118,11 +147,13 @@ impl TimerGroupInstance for TIMG0 {
|
|||||||
.modify(|_, w| w.use_xtal().clear_bit())
|
.modify(|_, w| w.use_xtal().clear_bit())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(esp32)]
|
#[cfg(esp32)]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
// ESP32 has only APB clock source, do nothing
|
// ESP32 has only APB clock source, do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c2, esp32c3))]
|
#[cfg(any(esp32c2, esp32c3))]
|
||||||
fn configure_wdt_src_clk() {
|
fn configure_wdt_src_clk() {
|
||||||
@ -132,6 +163,7 @@ impl TimerGroupInstance for TIMG0 {
|
|||||||
.modify(|_, w| w.wdt_use_xtal().clear_bit())
|
.modify(|_, w| w.wdt_use_xtal().clear_bit())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
fn configure_wdt_src_clk() {
|
fn configure_wdt_src_clk() {
|
||||||
@ -139,6 +171,7 @@ impl TimerGroupInstance for TIMG0 {
|
|||||||
.timergroup0_wdt_clk_conf()
|
.timergroup0_wdt_clk_conf()
|
||||||
.modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) });
|
.modify(|_, w| unsafe { w.tg0_wdt_clk_sel().bits(1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
fn configure_wdt_src_clk() {
|
fn configure_wdt_src_clk() {
|
||||||
@ -151,10 +184,12 @@ impl TimerGroupInstance for TIMG1 {
|
|||||||
fn id() -> u8 {
|
fn id() -> u8 {
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn register_block() -> *const RegisterBlock {
|
fn register_block() -> *const RegisterBlock {
|
||||||
crate::peripherals::TIMG1::PTR
|
TIMG1::PTR
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
@ -162,6 +197,7 @@ impl TimerGroupInstance for TIMG1 {
|
|||||||
.timergroup1_timer_clk_conf()
|
.timergroup1_timer_clk_conf()
|
||||||
.modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
|
.modify(|_, w| unsafe { w.tg1_timer_clk_sel().bits(TIMG_DEFAULT_CLK_SRC) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32s2, esp32s3))]
|
#[cfg(any(esp32s2, esp32s3))]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
@ -172,12 +208,14 @@ impl TimerGroupInstance for TIMG1 {
|
|||||||
.modify(|_, w| w.use_xtal().clear_bit())
|
.modify(|_, w| w.use_xtal().clear_bit())
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32, esp32c2, esp32c3))]
|
#[cfg(any(esp32, esp32c2, esp32c3))]
|
||||||
fn configure_src_clk() {
|
fn configure_src_clk() {
|
||||||
// ESP32 has only APB clock source, do nothing
|
// ESP32 has only APB clock source, do nothing
|
||||||
// ESP32-C2 and ESP32-C3 don't have t1config only t0config, do nothing
|
// ESP32-C2 and ESP32-C3 don't have t1config only t0config, do nothing
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32c6, esp32h2))]
|
#[cfg(any(esp32c6, esp32h2))]
|
||||||
fn configure_wdt_src_clk() {
|
fn configure_wdt_src_clk() {
|
||||||
@ -185,6 +223,7 @@ impl TimerGroupInstance for TIMG1 {
|
|||||||
.timergroup1_wdt_clk_conf()
|
.timergroup1_wdt_clk_conf()
|
||||||
.modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(1) });
|
.modify(|_, w| unsafe { w.tg1_wdt_clk_sel().bits(1) });
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))]
|
#[cfg(any(esp32, esp32s2, esp32s3, esp32c2, esp32c3))]
|
||||||
fn configure_wdt_src_clk() {
|
fn configure_wdt_src_clk() {
|
||||||
@ -197,12 +236,13 @@ impl<'d, T> TimerGroup<'d, T, Blocking>
|
|||||||
where
|
where
|
||||||
T: TimerGroupInstance,
|
T: TimerGroupInstance,
|
||||||
{
|
{
|
||||||
|
/// Construct a new instance of [`TimerGroup`] in blocking mode
|
||||||
pub fn new(
|
pub fn new(
|
||||||
timer_group: impl Peripheral<P = T> + 'd,
|
_timer_group: impl Peripheral<P = T> + 'd,
|
||||||
clocks: &Clocks,
|
clocks: &Clocks,
|
||||||
isr: Option<TimerInterrupts>,
|
isr: Option<TimerInterrupts>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
crate::into_ref!(timer_group);
|
crate::into_ref!(_timer_group);
|
||||||
|
|
||||||
T::configure_src_clk();
|
T::configure_src_clk();
|
||||||
|
|
||||||
@ -217,7 +257,7 @@ where
|
|||||||
clocks.pll_48m_clock,
|
clocks.pll_48m_clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
let timer1 = Timer::new(
|
let timer1 = Timer::new(
|
||||||
Timer1 {
|
Timer1 {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -228,98 +268,56 @@ where
|
|||||||
if let Some(isr) = isr {
|
if let Some(isr) = isr {
|
||||||
if let Some(handler) = isr.timer0_t0 {
|
if let Some(handler) = isr.timer0_t0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG0_T0_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG0_T0_LEVEL,
|
interrupt::enable(Interrupt::TG0_T0_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG0_T0_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
if let Some(handler) = isr.timer0_t1 {
|
if let Some(handler) = isr.timer0_t1 {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG0_T1_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG0_T1_LEVEL,
|
interrupt::enable(Interrupt::TG0_T1_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG0_T1_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handler) = isr.timer0_wdt {
|
if let Some(handler) = isr.timer0_wdt {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG0_WDT_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG0_WDT_LEVEL,
|
interrupt::enable(Interrupt::TG0_WDT_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG0_WDT_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
{
|
{
|
||||||
if let Some(handler) = isr.timer1_t0 {
|
if let Some(handler) = isr.timer1_t0 {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG1_T0_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG1_T0_LEVEL,
|
interrupt::enable(Interrupt::TG1_T0_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG1_T0_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(esp32, esp32s2, esp32s3))]
|
#[cfg(any(esp32, esp32s2, esp32s3))]
|
||||||
if let Some(handler) = isr.timer1_t1 {
|
if let Some(handler) = isr.timer1_t1 {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG1_T1_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG1_T1_LEVEL,
|
interrupt::enable(Interrupt::TG1_T1_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG1_T1_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(handler) = isr.timer1_wdt {
|
if let Some(handler) = isr.timer1_wdt {
|
||||||
unsafe {
|
unsafe {
|
||||||
crate::interrupt::bind_interrupt(
|
interrupt::bind_interrupt(Interrupt::TG1_WDT_LEVEL, handler.handler());
|
||||||
crate::peripherals::Interrupt::TG1_WDT_LEVEL,
|
interrupt::enable(Interrupt::TG1_WDT_LEVEL, handler.priority()).unwrap();
|
||||||
handler.handler(),
|
|
||||||
);
|
|
||||||
crate::interrupt::enable(
|
|
||||||
crate::peripherals::Interrupt::TG1_WDT_LEVEL,
|
|
||||||
handler.priority(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_timer_group: timer_group,
|
_timer_group,
|
||||||
timer0,
|
timer0,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
timer1,
|
timer1,
|
||||||
wdt: Wdt::new(),
|
wdt: Wdt::new(),
|
||||||
}
|
}
|
||||||
@ -330,8 +328,9 @@ impl<'d, T> TimerGroup<'d, T, Async>
|
|||||||
where
|
where
|
||||||
T: TimerGroupInstance,
|
T: TimerGroupInstance,
|
||||||
{
|
{
|
||||||
pub fn new_async(timer_group: impl Peripheral<P = T> + 'd, clocks: &Clocks) -> Self {
|
/// Construct a new instance of [`TimerGroup`] in asynchronous mode
|
||||||
crate::into_ref!(timer_group);
|
pub fn new_async(_timer_group: impl Peripheral<P = T> + 'd, clocks: &Clocks) -> Self {
|
||||||
|
crate::into_ref!(_timer_group);
|
||||||
|
|
||||||
T::configure_src_clk();
|
T::configure_src_clk();
|
||||||
|
|
||||||
@ -346,7 +345,7 @@ where
|
|||||||
clocks.pll_48m_clock,
|
clocks.pll_48m_clock,
|
||||||
);
|
);
|
||||||
|
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
let timer1 = Timer::new(
|
let timer1 = Timer::new(
|
||||||
Timer1 {
|
Timer1 {
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
@ -355,16 +354,16 @@ where
|
|||||||
);
|
);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
_timer_group: timer_group,
|
_timer_group,
|
||||||
timer0,
|
timer0,
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
timer1,
|
timer1,
|
||||||
wdt: Wdt::new(),
|
wdt: Wdt::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// General-purpose Timer driver
|
/// General-purpose timer.
|
||||||
pub struct Timer<T, DM>
|
pub struct Timer<T, DM>
|
||||||
where
|
where
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
@ -379,7 +378,7 @@ where
|
|||||||
T: Instance,
|
T: Instance,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Create a new timer instance.
|
/// Construct a new instance of [`Timer`]
|
||||||
pub fn new(timg: T, apb_clk_freq: HertzU32) -> Self {
|
pub fn new(timg: T, apb_clk_freq: HertzU32) -> Self {
|
||||||
timg.enable_peripheral();
|
timg.enable_peripheral();
|
||||||
timg.set_counter_active(true);
|
timg.set_counter_active(true);
|
||||||
@ -391,23 +390,6 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start the timer with the given time period.
|
|
||||||
pub fn start(&mut self, timeout: MicrosDurationU64) {
|
|
||||||
self.timg.set_counter_active(false);
|
|
||||||
self.timg.set_alarm_active(false);
|
|
||||||
|
|
||||||
self.timg.reset_counter();
|
|
||||||
|
|
||||||
// TODO: can we cache the divider (only get it on initialization)?
|
|
||||||
let ticks = timeout_to_ticks(timeout, self.apb_clk_freq, self.timg.divider());
|
|
||||||
self.timg.load_alarm_value(ticks);
|
|
||||||
|
|
||||||
self.timg.set_counter_decrementing(false);
|
|
||||||
self.timg.set_auto_reload(true);
|
|
||||||
self.timg.set_counter_active(true);
|
|
||||||
self.timg.set_alarm_active(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Check if the timer has elapsed
|
/// Check if the timer has elapsed
|
||||||
pub fn has_elapsed(&mut self) -> bool {
|
pub fn has_elapsed(&mut self) -> bool {
|
||||||
if !self.timg.is_counter_active() {
|
if !self.timg.is_counter_active() {
|
||||||
@ -452,7 +434,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, DM> crate::private::Sealed for Timer<T, DM>
|
impl<T, DM> Sealed for Timer<T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
@ -514,17 +496,24 @@ where
|
|||||||
Instant::<u64, 1, 1_000_000>::from_ticks(micros)
|
Instant::<u64, 1, 1_000_000>::from_ticks(micros)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_value(&self, value: MicrosDurationU64) {
|
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
|
||||||
let ticks = timeout_to_ticks(value, self.apb_clk_freq, self.timg.divider());
|
let ticks = timeout_to_ticks(value, self.apb_clk_freq, self.timg.divider());
|
||||||
|
|
||||||
let value = ticks & 0x3F_FFFF_FFFF_FFFF;
|
// The counter is 54-bits wide, so we must ensure that the provided
|
||||||
let high = (value >> 32) as u32;
|
// value is not too wide:
|
||||||
let low = (value & 0xFFFF_FFFF) as u32;
|
if (ticks & !0x3F_FFFF_FFFF_FFFF) != 0 {
|
||||||
|
return Err(Error::InvalidTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
let high = (ticks >> 32) as u32;
|
||||||
|
let low = (ticks & 0xFFFF_FFFF) as u32;
|
||||||
|
|
||||||
let t = self.register_block().t(self.timer_number().into());
|
let t = self.register_block().t(self.timer_number().into());
|
||||||
|
|
||||||
t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
|
t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
|
||||||
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
|
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_auto_reload(&self, auto_reload: bool) {
|
fn enable_auto_reload(&self, auto_reload: bool) {
|
||||||
@ -562,8 +551,8 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Timer peripheral instance.
|
#[doc(hidden)]
|
||||||
pub trait Instance: crate::private::Sealed + Enable {
|
pub trait Instance: Sealed + Enable {
|
||||||
fn register_block(&self) -> &RegisterBlock;
|
fn register_block(&self) -> &RegisterBlock;
|
||||||
|
|
||||||
fn timer_number(&self) -> u8;
|
fn timer_number(&self) -> u8;
|
||||||
@ -599,20 +588,24 @@ pub trait Instance: crate::private::Sealed + Enable {
|
|||||||
fn is_interrupt_set(&self) -> bool;
|
fn is_interrupt_set(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Enable: crate::private::Sealed {
|
#[doc(hidden)]
|
||||||
|
pub trait Enable: Sealed {
|
||||||
fn enable_peripheral(&self);
|
fn enable_peripheral(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A timer within a Timer Group.
|
||||||
pub struct TimerX<TG, const T: u8 = 0> {
|
pub struct TimerX<TG, const T: u8 = 0> {
|
||||||
phantom: PhantomData<TG>,
|
phantom: PhantomData<TG>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Timer 0 in the Timer Group.
|
||||||
pub type Timer0<TG> = TimerX<TG, 0>;
|
pub type Timer0<TG> = TimerX<TG, 0>;
|
||||||
|
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
/// Timer 1 in the Timer Group.
|
||||||
|
#[cfg(timg_timer1)]
|
||||||
pub type Timer1<TG> = TimerX<TG, 1>;
|
pub type Timer1<TG> = TimerX<TG, 1>;
|
||||||
|
|
||||||
impl<TG, const T: u8> crate::private::Sealed for TimerX<TG, T> {}
|
impl<TG, const T: u8> Sealed for TimerX<TG, T> {}
|
||||||
|
|
||||||
impl<TG, const T: u8> TimerX<TG, T>
|
impl<TG, const T: u8> TimerX<TG, T>
|
||||||
where
|
where
|
||||||
@ -648,7 +641,6 @@ where
|
|||||||
let t = unsafe { Self::t() };
|
let t = unsafe { Self::t() };
|
||||||
|
|
||||||
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
|
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
|
||||||
|
|
||||||
t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
|
t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
|
||||||
|
|
||||||
t.load().write(|w| unsafe { w.load().bits(1) });
|
t.load().write(|w| unsafe { w.load().bits(1) });
|
||||||
@ -774,7 +766,7 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))]
|
#[cfg(timg_timer1)]
|
||||||
impl<TG> Enable for Timer1<TG>
|
impl<TG> Enable for Timer1<TG>
|
||||||
where
|
where
|
||||||
TG: TimerGroupInstance,
|
TG: TimerGroupInstance,
|
||||||
@ -815,7 +807,7 @@ where
|
|||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<T, DM> embedded_hal_02::timer::CountDown for Timer<T, DM>
|
impl<T, DM> embedded_hal_02::timer::CountDown for Timer<T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance + super::Timer,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
type Time = MicrosDurationU64;
|
type Time = MicrosDurationU64;
|
||||||
@ -824,7 +816,8 @@ where
|
|||||||
where
|
where
|
||||||
Time: Into<Self::Time>,
|
Time: Into<Self::Time>,
|
||||||
{
|
{
|
||||||
(*self).start(timeout.into())
|
self.timg.load_value(timeout.into()).unwrap();
|
||||||
|
self.timg.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||||
@ -839,7 +832,7 @@ where
|
|||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<T, DM> embedded_hal_02::timer::Cancel for Timer<T, DM>
|
impl<T, DM> embedded_hal_02::timer::Cancel for Timer<T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance + super::Timer,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
type Error = super::Error;
|
type Error = super::Error;
|
||||||
@ -860,7 +853,7 @@ where
|
|||||||
#[cfg(feature = "embedded-hal-02")]
|
#[cfg(feature = "embedded-hal-02")]
|
||||||
impl<T, DM> embedded_hal_02::timer::Periodic for Timer<T, DM>
|
impl<T, DM> embedded_hal_02::timer::Periodic for Timer<T, DM>
|
||||||
where
|
where
|
||||||
T: Instance,
|
T: Instance + super::Timer,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -876,10 +869,10 @@ where
|
|||||||
TG: TimerGroupInstance,
|
TG: TimerGroupInstance,
|
||||||
DM: Mode,
|
DM: Mode,
|
||||||
{
|
{
|
||||||
/// Create a new watchdog timer instance
|
/// Construct a new instance of [`Wdt`]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
#[cfg(lp_wdt)]
|
#[cfg(lp_wdt)]
|
||||||
PeripheralClockControl::enable(crate::system::Peripheral::Wdt);
|
PeripheralClockControl::enable(PeripheralEnable::Wdt);
|
||||||
|
|
||||||
TG::configure_wdt_src_clk();
|
TG::configure_wdt_src_clk();
|
||||||
|
|
||||||
@ -927,6 +920,7 @@ where
|
|||||||
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
|
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Feed the watchdog timer
|
||||||
pub fn feed(&mut self) {
|
pub fn feed(&mut self) {
|
||||||
let reg_block = unsafe { &*TG::register_block() };
|
let reg_block = unsafe { &*TG::register_block() };
|
||||||
|
|
||||||
@ -941,6 +935,7 @@ where
|
|||||||
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
|
.write(|w| unsafe { w.wdt_wkey().bits(0u32) });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set the timeout, in microseconds, of the watchdog timer
|
||||||
pub fn set_timeout(&mut self, timeout: MicrosDurationU64) {
|
pub fn set_timeout(&mut self, timeout: MicrosDurationU64) {
|
||||||
let timeout_raw = (timeout.to_nanos() * 10 / 125) as u32;
|
let timeout_raw = (timeout.to_nanos() * 10 / 125) as u32;
|
||||||
|
|
||||||
@ -1036,18 +1031,18 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Event Task Matrix
|
||||||
#[cfg(soc_etm)]
|
#[cfg(soc_etm)]
|
||||||
pub mod etm {
|
pub mod etm {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::etm::{EtmEvent, EtmTask};
|
||||||
etm::{EtmEvent, EtmTask},
|
|
||||||
private::Sealed,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
/// Event Task Matrix event for a timer.
|
||||||
pub struct TimerEtmEvent {
|
pub struct TimerEtmEvent {
|
||||||
id: u8,
|
id: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Event Task Matrix task for a timer.
|
||||||
pub struct TimerEtmTask {
|
pub struct TimerEtmTask {
|
||||||
id: u8,
|
id: u8,
|
||||||
}
|
}
|
||||||
@ -1068,17 +1063,28 @@ pub mod etm {
|
|||||||
|
|
||||||
impl Sealed for TimerEtmTask {}
|
impl Sealed for TimerEtmTask {}
|
||||||
|
|
||||||
/// General purpose timer ETM events
|
/// General purpose timer ETM events.
|
||||||
pub trait TimerEtmEvents<TG> {
|
pub trait TimerEtmEvents<TG> {
|
||||||
|
/// ETM event triggered on alarm
|
||||||
fn on_alarm(&self) -> TimerEtmEvent;
|
fn on_alarm(&self) -> TimerEtmEvent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// General purpose timer ETM tasks
|
/// General purpose timer ETM tasks
|
||||||
pub trait TimerEtmTasks<TG> {
|
pub trait TimerEtmTasks<TG> {
|
||||||
|
/// ETM task to start the counter
|
||||||
fn cnt_start(&self) -> TimerEtmTask;
|
fn cnt_start(&self) -> TimerEtmTask;
|
||||||
|
|
||||||
|
/// ETM task to start the alarm
|
||||||
fn cnt_stop(&self) -> TimerEtmTask;
|
fn cnt_stop(&self) -> TimerEtmTask;
|
||||||
|
|
||||||
|
/// ETM task to stop the counter
|
||||||
fn cnt_reload(&self) -> TimerEtmTask;
|
fn cnt_reload(&self) -> TimerEtmTask;
|
||||||
|
|
||||||
|
/// ETM task to reload the counter
|
||||||
fn cnt_cap(&self) -> TimerEtmTask;
|
fn cnt_cap(&self) -> TimerEtmTask;
|
||||||
|
|
||||||
|
/// ETM task to load the counter with the value stored when the last
|
||||||
|
/// `now()` was called
|
||||||
fn alarm_start(&self) -> TimerEtmTask;
|
fn alarm_start(&self) -> TimerEtmTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1086,7 +1092,6 @@ pub mod etm {
|
|||||||
where
|
where
|
||||||
TG: TimerGroupInstance,
|
TG: TimerGroupInstance,
|
||||||
{
|
{
|
||||||
/// ETM event triggered on alarm
|
|
||||||
fn on_alarm(&self) -> TimerEtmEvent {
|
fn on_alarm(&self) -> TimerEtmEvent {
|
||||||
TimerEtmEvent { id: 48 + TG::id() }
|
TimerEtmEvent { id: 48 + TG::id() }
|
||||||
}
|
}
|
||||||
@ -1096,28 +1101,22 @@ pub mod etm {
|
|||||||
where
|
where
|
||||||
TG: TimerGroupInstance,
|
TG: TimerGroupInstance,
|
||||||
{
|
{
|
||||||
/// ETM task to start the counter
|
|
||||||
fn cnt_start(&self) -> TimerEtmTask {
|
fn cnt_start(&self) -> TimerEtmTask {
|
||||||
TimerEtmTask { id: 88 + TG::id() }
|
TimerEtmTask { id: 88 + TG::id() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ETM task to start the alarm
|
|
||||||
fn alarm_start(&self) -> TimerEtmTask {
|
fn alarm_start(&self) -> TimerEtmTask {
|
||||||
TimerEtmTask { id: 90 + TG::id() }
|
TimerEtmTask { id: 90 + TG::id() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ETM task to stop the counter
|
|
||||||
fn cnt_stop(&self) -> TimerEtmTask {
|
fn cnt_stop(&self) -> TimerEtmTask {
|
||||||
TimerEtmTask { id: 92 + TG::id() }
|
TimerEtmTask { id: 92 + TG::id() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ETM task to reload the counter
|
|
||||||
fn cnt_reload(&self) -> TimerEtmTask {
|
fn cnt_reload(&self) -> TimerEtmTask {
|
||||||
TimerEtmTask { id: 94 + TG::id() }
|
TimerEtmTask { id: 94 + TG::id() }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// ETM task to load the counter with the value stored when the last
|
|
||||||
/// `now()` was called
|
|
||||||
fn cnt_cap(&self) -> TimerEtmTask {
|
fn cnt_cap(&self) -> TimerEtmTask {
|
||||||
TimerEtmTask { id: 96 + TG::id() }
|
TimerEtmTask { id: 96 + TG::id() }
|
||||||
}
|
}
|
||||||
|
@ -59,6 +59,7 @@ symbols = [
|
|||||||
"bt",
|
"bt",
|
||||||
"wifi",
|
"wifi",
|
||||||
"psram",
|
"psram",
|
||||||
|
"timg_timer1",
|
||||||
|
|
||||||
# ROM capabilities
|
# ROM capabilities
|
||||||
"rom_crc_le",
|
"rom_crc_le",
|
||||||
|
@ -57,6 +57,7 @@ symbols = [
|
|||||||
"wifi",
|
"wifi",
|
||||||
"psram",
|
"psram",
|
||||||
"ulp_riscv_core",
|
"ulp_riscv_core",
|
||||||
|
"timg_timer1",
|
||||||
|
|
||||||
# ROM capabilities
|
# ROM capabilities
|
||||||
"rom_crc_le",
|
"rom_crc_le",
|
||||||
|
@ -69,6 +69,7 @@ symbols = [
|
|||||||
"wifi",
|
"wifi",
|
||||||
"psram",
|
"psram",
|
||||||
"ulp_riscv_core",
|
"ulp_riscv_core",
|
||||||
|
"timg_timer1",
|
||||||
|
|
||||||
# ROM capabilities
|
# ROM capabilities
|
||||||
"rom_crc_le",
|
"rom_crc_le",
|
||||||
|
@ -10,6 +10,7 @@ use crate::{
|
|||||||
hal::{
|
hal::{
|
||||||
interrupt::{self, TrapFrame},
|
interrupt::{self, TrapFrame},
|
||||||
peripherals::{self, Interrupt},
|
peripherals::{self, Interrupt},
|
||||||
|
prelude::*,
|
||||||
riscv,
|
riscv,
|
||||||
timer::systimer::{Alarm, Periodic, Target},
|
timer::systimer::{Alarm, Periodic, Target},
|
||||||
},
|
},
|
||||||
|
@ -67,7 +67,10 @@ fn do_task_switch(context: &mut TrapFrame) {
|
|||||||
let mut timer = TIMER1.borrow_ref_mut(cs);
|
let mut timer = TIMER1.borrow_ref_mut(cs);
|
||||||
let timer = unwrap!(timer.as_mut());
|
let timer = unwrap!(timer.as_mut());
|
||||||
timer.clear_interrupt();
|
timer.clear_interrupt();
|
||||||
timer.start(TIMESLICE_FREQUENCY.into_duration());
|
timer
|
||||||
|
.load_value(TIMESLICE_FREQUENCY.into_duration())
|
||||||
|
.unwrap();
|
||||||
|
timer.start();
|
||||||
});
|
});
|
||||||
|
|
||||||
task_switch(context);
|
task_switch(context);
|
||||||
|
@ -40,7 +40,7 @@ fn main() -> ! {
|
|||||||
let timer0 = timg0.timer0;
|
let timer0 = timg0.timer0;
|
||||||
|
|
||||||
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
|
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
|
||||||
timer0.load_value(500u64.millis());
|
timer0.load_value(500u64.millis()).unwrap();
|
||||||
timer0.start();
|
timer0.start();
|
||||||
timer0.listen();
|
timer0.listen();
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ fn tg0_t0_level() {
|
|||||||
let timer0 = timer0.as_mut().unwrap();
|
let timer0 = timer0.as_mut().unwrap();
|
||||||
|
|
||||||
timer0.clear_interrupt();
|
timer0.clear_interrupt();
|
||||||
timer0.start(500u64.millis());
|
timer0.load_value(500u64.millis()).unwrap();
|
||||||
|
timer0.start();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user