mirror of
https://github.com/esp-rs/esp-hal.git
synced 2025-09-28 12:50:53 +00:00
[2/3] Timer abstraction: add OneShotTimer
/PeriodicTimer
drivers, Timer
trait (#1570)
* Add the `Timer` trait, `OneShotTimer` and `PeriodicTimer` types * `PeriodicTimer` now working for `TIMG` * `OneShotTimer` now working for `TIMG` * `OneShotTimer` now working for `SYSTIMER` (plus, some cleanup) * SYSTIMER now mostly working for ESP32-S2 as well * Update `timer_interrupt` example and fix clippy lint to make CI happy again * Update `CHANGELOG.md` * Make `SYSTIMER` work correctly with `PeriodicTimer`, address some review comments * Make `Timer::now()` return a `fugit::Instant`
This commit is contained in:
parent
ec8308058b
commit
5facb759ae
@ -7,17 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- Updated example on i2c to use the new `interrupt_handler` parameter (#1376)
|
||||
|
||||
### Added
|
||||
|
||||
- i2c: implement `I2C:transaction` for `embedded-hal` and `embedded-hal-async`
|
||||
- spi: implement `with_bit_order` - #1537
|
||||
- i2c: implement `I2C:transaction` for `embedded-hal` and `embedded-hal-async` (#1505)
|
||||
- spi: implement `with_bit_order` (#1537)
|
||||
- ESP32-PICO-V3-02: Initial support (#1155)
|
||||
- `time::current_time` API (#1503)
|
||||
- ESP32-S3: Add LCD_CAM Camera driver (#1483)
|
||||
- `embassy-usb` support (#1517)
|
||||
- SPI Slave support for ESP32-S2 (#1562)
|
||||
- Add new generic `OneShotTimer` and `PeriodicTimer` drivers, plus new `Timer` trait which is implemented for `TIMGx` and `SYSTIMER` (#1570)
|
||||
|
||||
### Fixed
|
||||
|
||||
|
@ -36,6 +36,8 @@ pub use crate::timer::timg::{
|
||||
Instance as _esp_hal_timer_timg_Instance,
|
||||
TimerGroupInstance as _esp_hal_timer_timg_TimerGroupInstance,
|
||||
};
|
||||
#[cfg(any(systimer, timg0, timg1))]
|
||||
pub use crate::timer::Timer as _esp_hal_timer_Timer;
|
||||
#[cfg(any(uart0, uart1, uart2))]
|
||||
pub use crate::uart::{Instance as _esp_hal_uart_Instance, UartPins as _esp_hal_uart_UartPins};
|
||||
pub use crate::{entry, macros::*};
|
||||
|
@ -1,6 +1,225 @@
|
||||
//! General-purpose timers.
|
||||
|
||||
use fugit::{ExtU64, Instant, MicrosDurationU64};
|
||||
|
||||
#[cfg(systimer)]
|
||||
pub mod systimer;
|
||||
#[cfg(any(timg0, timg1))]
|
||||
pub mod timg;
|
||||
|
||||
/// Timer errors.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
/// The timer is already active.
|
||||
TimerActive,
|
||||
/// The timer is not currently active.
|
||||
TimerInactive,
|
||||
/// The alarm is not currently active.
|
||||
AlarmInactive,
|
||||
}
|
||||
|
||||
/// Functionality provided by any timer peripheral.
|
||||
pub trait Timer: crate::private::Sealed {
|
||||
/// Start the timer.
|
||||
fn start(&self);
|
||||
|
||||
/// Stop the timer.
|
||||
fn stop(&self);
|
||||
|
||||
/// Reset the timer value to 0.
|
||||
fn reset(&self);
|
||||
|
||||
/// Is the timer running?
|
||||
fn is_running(&self) -> bool;
|
||||
|
||||
/// The current timer value.
|
||||
fn now(&self) -> Instant<u64, 1, 1_000_000>;
|
||||
|
||||
/// Load a target value into the timer.
|
||||
fn load_value(&self, value: MicrosDurationU64);
|
||||
|
||||
/// Enable auto reload of the loaded value.
|
||||
fn enable_auto_reload(&self, auto_reload: bool);
|
||||
|
||||
/// Enable or disable the timer's interrupt.
|
||||
fn enable_interrupt(&self, state: bool);
|
||||
|
||||
/// Clear the timer's interrupt.
|
||||
fn clear_interrupt(&self);
|
||||
|
||||
/// Has the timer triggered?
|
||||
fn is_interrupt_set(&self) -> bool;
|
||||
|
||||
/// FIXME: This is (hopefully?) temporary...
|
||||
fn set_alarm_active(&self, state: bool);
|
||||
}
|
||||
|
||||
/// A one-shot timer.
|
||||
pub struct OneShotTimer<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> OneShotTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
{
|
||||
/// Construct a new instance of [`OneShotTimer`].
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Pauses execution for *at least* `ms` milliseconds.
|
||||
pub fn delay_millis(&self, ms: u32) {
|
||||
self.delay((ms as u64).millis());
|
||||
}
|
||||
|
||||
/// Pauses execution for *at least* `us` microseconds.
|
||||
pub fn delay_micros(&self, us: u32) {
|
||||
self.delay((us as u64).micros());
|
||||
}
|
||||
|
||||
/// Pauses execution for *at least* `ns` nanoseconds.
|
||||
pub fn delay_nanos(&self, ns: u32) {
|
||||
self.delay((ns as u64 / 1000).micros())
|
||||
}
|
||||
|
||||
fn delay(&self, us: MicrosDurationU64) {
|
||||
if self.inner.is_running() {
|
||||
self.inner.stop();
|
||||
}
|
||||
|
||||
self.inner.clear_interrupt();
|
||||
self.inner.reset();
|
||||
|
||||
self.inner.enable_auto_reload(false);
|
||||
self.inner.load_value(us);
|
||||
self.inner.start();
|
||||
|
||||
while !self.inner.is_interrupt_set() {
|
||||
// Wait
|
||||
}
|
||||
|
||||
self.inner.stop();
|
||||
self.inner.clear_interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<T, UXX> embedded_hal_02::blocking::delay::DelayMs<UXX> for OneShotTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
UXX: Into<u32>,
|
||||
{
|
||||
fn delay_ms(&mut self, ms: UXX) {
|
||||
self.delay_millis(ms.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<T, UXX> embedded_hal_02::blocking::delay::DelayUs<UXX> for OneShotTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
UXX: Into<u32>,
|
||||
{
|
||||
fn delay_us(&mut self, us: UXX) {
|
||||
self.delay_micros(us.into());
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal")]
|
||||
impl<T> embedded_hal::delay::DelayNs for OneShotTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
{
|
||||
#[allow(clippy::useless_conversion)]
|
||||
fn delay_ns(&mut self, ns: u32) {
|
||||
self.delay_nanos(ns.into());
|
||||
}
|
||||
}
|
||||
|
||||
/// A periodic timer.
|
||||
pub struct PeriodicTimer<T> {
|
||||
inner: T,
|
||||
}
|
||||
|
||||
impl<T> PeriodicTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
{
|
||||
/// Construct a new instance of [`PeriodicTimer`].
|
||||
pub fn new(inner: T) -> Self {
|
||||
Self { inner }
|
||||
}
|
||||
|
||||
/// Start a new count down.
|
||||
pub fn start(&mut self, timeout: MicrosDurationU64) {
|
||||
if self.inner.is_running() {
|
||||
self.inner.stop();
|
||||
}
|
||||
|
||||
self.inner.clear_interrupt();
|
||||
self.inner.reset();
|
||||
|
||||
self.inner.enable_auto_reload(true);
|
||||
self.inner.load_value(timeout);
|
||||
self.inner.start();
|
||||
}
|
||||
|
||||
/// "Wait" until the count down finishes without blocking.
|
||||
pub fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||
if self.inner.is_interrupt_set() {
|
||||
self.inner.clear_interrupt();
|
||||
self.inner.set_alarm_active(true); // FIXME: Remove if/when able
|
||||
|
||||
Ok(())
|
||||
} else {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
}
|
||||
|
||||
/// Tries to cancel the active count down.
|
||||
pub fn cancel(&mut self) -> Result<(), Error> {
|
||||
if !self.inner.is_running() {
|
||||
return Err(Error::TimerInactive);
|
||||
}
|
||||
|
||||
self.inner.stop();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<T> embedded_hal_02::timer::CountDown for PeriodicTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
{
|
||||
type Time = MicrosDurationU64;
|
||||
|
||||
fn start<Time>(&mut self, timeout: Time)
|
||||
where
|
||||
Time: Into<Self::Time>,
|
||||
{
|
||||
self.start(timeout.into());
|
||||
}
|
||||
|
||||
fn wait(&mut self) -> nb::Result<(), void::Void> {
|
||||
self.wait()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<T> embedded_hal_02::timer::Cancel for PeriodicTimer<T>
|
||||
where
|
||||
T: Timer,
|
||||
{
|
||||
type Error = Error;
|
||||
|
||||
fn cancel(&mut self) -> Result<(), Self::Error> {
|
||||
self.cancel()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "embedded-hal-02")]
|
||||
impl<T> embedded_hal_02::timer::Periodic for PeriodicTimer<T> where T: Timer {}
|
||||
|
@ -26,40 +26,52 @@
|
||||
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use fugit::MicrosDurationU32;
|
||||
use fugit::{Instant, MicrosDurationU32, MicrosDurationU64};
|
||||
|
||||
use crate::{
|
||||
interrupt::InterruptHandler,
|
||||
interrupt::{self, InterruptHandler},
|
||||
peripheral::Peripheral,
|
||||
peripherals::{
|
||||
systimer::{TARGET_CONF, TRGT},
|
||||
Interrupt,
|
||||
SYSTIMER,
|
||||
},
|
||||
Async,
|
||||
Blocking,
|
||||
Mode,
|
||||
};
|
||||
|
||||
/// The SystemTimer
|
||||
pub struct SystemTimer<'d, DM: crate::Mode> {
|
||||
pub struct SystemTimer<'d, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Alarm 0.
|
||||
pub alarm0: Alarm<Target, DM, 0>,
|
||||
/// Alarm 1.
|
||||
pub alarm1: Alarm<Target, DM, 1>,
|
||||
/// Alarm 2.
|
||||
pub alarm2: Alarm<Target, DM, 2>,
|
||||
_phantom: PhantomData<&'d ()>,
|
||||
}
|
||||
|
||||
impl<'d> SystemTimer<'d, crate::Blocking> {
|
||||
/// Bitmask to be applied to the raw register value
|
||||
#[cfg(esp32s2)]
|
||||
pub const BIT_MASK: u64 = u64::MAX;
|
||||
#[cfg(not(esp32s2))]
|
||||
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
|
||||
|
||||
/// The ticks per second the underlying peripheral uses
|
||||
#[cfg(esp32s2)]
|
||||
pub const TICKS_PER_SECOND: u64 = 80_000_000;
|
||||
#[cfg(not(esp32s2))]
|
||||
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
||||
impl<'d> SystemTimer<'d, Blocking> {
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(esp32s2)] {
|
||||
/// Bitmask to be applied to the raw register value.
|
||||
pub const BIT_MASK: u64 = u64::MAX;
|
||||
/// The ticks per second the underlying peripheral uses.
|
||||
pub const TICKS_PER_SECOND: u64 = 80_000_000;
|
||||
} else {
|
||||
/// Bitmask to be applied to the raw register value.
|
||||
pub const BIT_MASK: u64 = 0xF_FFFF_FFFF_FFFF;
|
||||
/// The ticks per second the underlying peripheral uses.
|
||||
pub const TICKS_PER_SECOND: u64 = 16_000_000;
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new instance in [crate::Blocking] mode.
|
||||
pub fn new(_p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
pub fn new(_systimer: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
#[cfg(soc_etm)]
|
||||
etm::enable_etm();
|
||||
|
||||
@ -88,9 +100,9 @@ impl<'d> SystemTimer<'d, crate::Blocking> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d> SystemTimer<'d, crate::Async> {
|
||||
impl<'d> SystemTimer<'d, Async> {
|
||||
/// Create a new instance in [crate::Async] mode.
|
||||
pub fn new_async(_p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
pub fn new_async(_systimer: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
|
||||
#[cfg(soc_etm)]
|
||||
etm::enable_etm();
|
||||
|
||||
@ -113,11 +125,17 @@ pub struct Periodic;
|
||||
|
||||
/// A single alarm.
|
||||
#[derive(Debug)]
|
||||
pub struct Alarm<MODE, DM: crate::Mode, const CHANNEL: u8> {
|
||||
pub struct Alarm<MODE, DM, const CHANNEL: u8>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
_pd: PhantomData<(MODE, DM)>,
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode, const CHANNEL: u8> Alarm<T, DM, CHANNEL> {
|
||||
impl<T, DM, const CHANNEL: u8> Alarm<T, DM, CHANNEL>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
// private constructor
|
||||
fn new() -> Self {
|
||||
Self { _pd: PhantomData }
|
||||
@ -192,37 +210,28 @@ impl<T, DM: crate::Mode, const CHANNEL: u8> Alarm<T, DM, CHANNEL> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, const CHANNEL: u8> Alarm<T, crate::Blocking, CHANNEL> {
|
||||
impl<T, const CHANNEL: u8> Alarm<T, Blocking, CHANNEL> {
|
||||
/// Set the interrupt handler for this alarm.
|
||||
pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
|
||||
match CHANNEL {
|
||||
0 => unsafe {
|
||||
crate::interrupt::bind_interrupt(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
|
||||
handler.handler(),
|
||||
);
|
||||
unwrap!(crate::interrupt::enable(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
|
||||
interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET0, handler.handler());
|
||||
unwrap!(interrupt::enable(
|
||||
Interrupt::SYSTIMER_TARGET0,
|
||||
handler.priority(),
|
||||
));
|
||||
},
|
||||
1 => unsafe {
|
||||
crate::interrupt::bind_interrupt(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
handler.handler(),
|
||||
);
|
||||
unwrap!(crate::interrupt::enable(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET1, handler.handler());
|
||||
unwrap!(interrupt::enable(
|
||||
Interrupt::SYSTIMER_TARGET1,
|
||||
handler.priority(),
|
||||
));
|
||||
},
|
||||
2 => unsafe {
|
||||
crate::interrupt::bind_interrupt(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
|
||||
handler.handler(),
|
||||
);
|
||||
unwrap!(crate::interrupt::enable(
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
|
||||
interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET2, handler.handler());
|
||||
unwrap!(interrupt::enable(
|
||||
Interrupt::SYSTIMER_TARGET2,
|
||||
handler.priority(),
|
||||
));
|
||||
},
|
||||
@ -240,7 +249,11 @@ impl<T, const CHANNEL: u8> Alarm<T, crate::Blocking, CHANNEL> {
|
||||
self.clear_interrupt_internal();
|
||||
}
|
||||
}
|
||||
impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Target, DM, CHANNEL> {
|
||||
|
||||
impl<DM, const CHANNEL: u8> Alarm<Target, DM, CHANNEL>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Set the target value of this [Alarm]
|
||||
pub fn set_target(&mut self, timestamp: u64) {
|
||||
self.set_target_internal(timestamp);
|
||||
@ -264,7 +277,10 @@ impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Target, DM, CHANNEL> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Periodic, DM, CHANNEL> {
|
||||
impl<DM, const CHANNEL: u8> Alarm<Periodic, DM, CHANNEL>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Set the period of this [Alarm]
|
||||
pub fn set_period(&mut self, period: MicrosDurationU32) {
|
||||
let us = period.ticks();
|
||||
@ -279,7 +295,10 @@ impl<DM: crate::Mode, const CHANNEL: u8> Alarm<Periodic, DM, CHANNEL> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> Alarm<T, DM, 0> {
|
||||
impl<T, DM> Alarm<T, DM, 0>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Conjure an alarm out of thin air.
|
||||
///
|
||||
/// # Safety
|
||||
@ -291,7 +310,10 @@ impl<T, DM: crate::Mode> Alarm<T, DM, 0> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> Alarm<T, DM, 1> {
|
||||
impl<T, DM> Alarm<T, DM, 1>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Conjure an alarm out of thin air.
|
||||
///
|
||||
/// # Safety
|
||||
@ -303,7 +325,10 @@ impl<T, DM: crate::Mode> Alarm<T, DM, 1> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> Alarm<T, DM, 2> {
|
||||
impl<T, DM> Alarm<T, DM, 2>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
/// Conjure an alarm out of thin air.
|
||||
///
|
||||
/// # Safety
|
||||
@ -315,6 +340,213 @@ impl<T, DM: crate::Mode> Alarm<T, DM, 2> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM, const CHANNEL: u8> crate::private::Sealed for Alarm<T, DM, CHANNEL> where DM: Mode {}
|
||||
|
||||
impl<T, DM, const CHANNEL: u8> super::Timer for Alarm<T, DM, CHANNEL>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
fn start(&self) {
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
#[cfg(esp32s2)]
|
||||
match CHANNEL {
|
||||
0 => systimer.target0_conf().modify(|_, w| w.work_en().set_bit()),
|
||||
1 => systimer.target1_conf().modify(|_, w| w.work_en().set_bit()),
|
||||
2 => systimer.target2_conf().modify(|_, w| w.work_en().set_bit()),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
#[cfg(not(esp32s2))]
|
||||
systimer.conf().modify(|_, 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!(),
|
||||
});
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
#[cfg(esp32s2)]
|
||||
match CHANNEL {
|
||||
0 => systimer
|
||||
.target0_conf()
|
||||
.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))]
|
||||
systimer.conf().modify(|_, w| match CHANNEL {
|
||||
0 => w.target0_work_en().clear_bit(),
|
||||
1 => w.target1_work_en().clear_bit(),
|
||||
2 => w.target2_work_en().clear_bit(),
|
||||
_ => unreachable!(),
|
||||
});
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
#[cfg(esp32s2)]
|
||||
// Run at XTAL freq, not 80 * XTAL freq:
|
||||
systimer
|
||||
.step()
|
||||
.modify(|_, w| unsafe { w.xtal_step().bits(0x1) });
|
||||
|
||||
#[cfg(not(esp32s2))]
|
||||
{
|
||||
systimer
|
||||
.target_conf(CHANNEL as usize)
|
||||
.modify(|_, w| w.timer_unit_sel().clear_bit()); // default, use unit 0
|
||||
systimer
|
||||
.conf()
|
||||
.modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit());
|
||||
}
|
||||
}
|
||||
|
||||
fn is_running(&self) -> bool {
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
#[cfg(esp32s2)]
|
||||
match CHANNEL {
|
||||
0 => systimer.target0_conf().read().work_en().bit_is_set(),
|
||||
1 => systimer.target1_conf().read().work_en().bit_is_set(),
|
||||
2 => systimer.target2_conf().read().work_en().bit_is_set(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
||||
#[cfg(not(esp32s2))]
|
||||
match CHANNEL {
|
||||
0 => systimer.conf().read().target0_work_en().bit_is_set(),
|
||||
1 => systimer.conf().read().target1_work_en().bit_is_set(),
|
||||
2 => systimer.conf().read().target2_work_en().bit_is_set(),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn now(&self) -> Instant<u64, 1, 1_000_000> {
|
||||
// This should be safe to access from multiple contexts; worst case
|
||||
// scenario the second accessor ends up reading an older time stamp.
|
||||
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
systimer.unit0_op().modify(|_, w| w.update().set_bit());
|
||||
while !systimer.unit0_op().read().value_valid().bit_is_set() {
|
||||
// Wait
|
||||
}
|
||||
|
||||
let value_lo = systimer.unit0_value().lo().read().bits();
|
||||
let value_hi = systimer.unit0_value().hi().read().bits();
|
||||
|
||||
let ticks = ((value_hi as u64) << 32) | value_lo as u64;
|
||||
let us = ticks / (SystemTimer::TICKS_PER_SECOND / 1_000_000);
|
||||
|
||||
Instant::<u64, 1, 1_000_000>::from_ticks(us)
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
fn load_value(&self, value: MicrosDurationU64) {
|
||||
let systimer = unsafe { &*SYSTIMER::PTR };
|
||||
|
||||
let auto_reload = systimer
|
||||
.target_conf(CHANNEL as usize)
|
||||
.read()
|
||||
.period_mode()
|
||||
.bit_is_set();
|
||||
|
||||
let us = value.ticks();
|
||||
let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u64;
|
||||
|
||||
if auto_reload {
|
||||
// Period mode
|
||||
|
||||
systimer
|
||||
.target_conf(CHANNEL as usize)
|
||||
.modify(|_, w| unsafe { w.period().bits(ticks as u32) });
|
||||
|
||||
#[cfg(not(esp32s2))]
|
||||
systimer
|
||||
.comp_load(CHANNEL as usize)
|
||||
.write(|w| w.load().set_bit());
|
||||
|
||||
// Clear and then set SYSTIMER_TARGETx_PERIOD_MODE to configure COMPx into
|
||||
// period mode
|
||||
systimer
|
||||
.target_conf(CHANNEL as usize)
|
||||
.modify(|_, w| w.period_mode().clear_bit());
|
||||
systimer
|
||||
.target_conf(CHANNEL as usize)
|
||||
.modify(|_, w| w.period_mode().set_bit());
|
||||
} else {
|
||||
// Target mode
|
||||
|
||||
systimer.unit0_op().modify(|_, w| w.update().set_bit());
|
||||
while !systimer.unit0_op().read().value_valid().bit_is_set() {
|
||||
// Wait for value registers to update
|
||||
}
|
||||
|
||||
let hi = systimer.unit0_value().hi().read().bits();
|
||||
let lo = systimer.unit0_value().lo().read().bits();
|
||||
|
||||
let v = (((hi & 0xF_FFFF) as u64) << 32) | lo as u64;
|
||||
let t = v + ticks;
|
||||
|
||||
systimer
|
||||
.trgt(CHANNEL as usize)
|
||||
.hi()
|
||||
.write(|w| unsafe { w.hi().bits((t >> 32) as u32) });
|
||||
systimer
|
||||
.trgt(CHANNEL as usize)
|
||||
.lo()
|
||||
.write(|w| unsafe { w.lo().bits(t as u32) });
|
||||
|
||||
#[cfg(not(esp32s2))]
|
||||
systimer
|
||||
.comp_load(CHANNEL as usize)
|
||||
.write(|w| w.load().set_bit());
|
||||
}
|
||||
}
|
||||
|
||||
fn enable_auto_reload(&self, auto_reload: bool) {
|
||||
// If `auto_reload` is true use Period Mode, otherwise use Target Mode:
|
||||
unsafe { &*SYSTIMER::PTR }
|
||||
.target_conf(CHANNEL as usize)
|
||||
.modify(|_, w| w.period_mode().bit(auto_reload));
|
||||
}
|
||||
|
||||
fn enable_interrupt(&self, state: bool) {
|
||||
unsafe { &*SYSTIMER::PTR }
|
||||
.int_ena()
|
||||
.modify(|_, w| w.target(CHANNEL).bit(state));
|
||||
}
|
||||
|
||||
fn clear_interrupt(&self) {
|
||||
unsafe { &*SYSTIMER::PTR }
|
||||
.int_clr()
|
||||
.write(|w| w.target(CHANNEL).clear_bit_by_one());
|
||||
}
|
||||
|
||||
fn is_interrupt_set(&self) -> bool {
|
||||
unsafe { &*SYSTIMER::PTR }
|
||||
.int_raw()
|
||||
.read()
|
||||
.target(CHANNEL)
|
||||
.bit_is_set()
|
||||
}
|
||||
|
||||
fn set_alarm_active(&self, _active: bool) {
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
||||
// Async functionality of the system timer.
|
||||
#[cfg(feature = "async")]
|
||||
mod asynch {
|
||||
@ -342,23 +574,14 @@ mod asynch {
|
||||
alarm.clear_interrupt_internal();
|
||||
|
||||
let (interrupt, handler) = match N {
|
||||
0 => (
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET0,
|
||||
target0_handler,
|
||||
),
|
||||
1 => (
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET1,
|
||||
target1_handler,
|
||||
),
|
||||
_ => (
|
||||
crate::peripherals::Interrupt::SYSTIMER_TARGET2,
|
||||
target2_handler,
|
||||
),
|
||||
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
|
||||
1 => (Interrupt::SYSTIMER_TARGET1, target1_handler),
|
||||
_ => (Interrupt::SYSTIMER_TARGET2, target2_handler),
|
||||
};
|
||||
|
||||
unsafe {
|
||||
crate::interrupt::bind_interrupt(interrupt, handler.handler());
|
||||
crate::interrupt::enable(interrupt, handler.priority()).unwrap();
|
||||
interrupt::bind_interrupt(interrupt, handler.handler());
|
||||
interrupt::enable(interrupt, handler.priority()).unwrap();
|
||||
}
|
||||
|
||||
alarm.enable_interrupt_internal(true);
|
||||
|
@ -41,7 +41,7 @@ use core::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
use fugit::{HertzU32, MicrosDurationU64};
|
||||
use fugit::{HertzU32, Instant, MicrosDurationU64};
|
||||
|
||||
#[cfg(timg1)]
|
||||
use crate::peripherals::TIMG1;
|
||||
@ -52,18 +52,12 @@ use crate::{
|
||||
interrupt::InterruptHandler,
|
||||
peripheral::{Peripheral, PeripheralRef},
|
||||
peripherals::{timg0::RegisterBlock, TIMG0},
|
||||
system::PeripheralClockControl,
|
||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||
Async,
|
||||
Blocking,
|
||||
Mode,
|
||||
};
|
||||
|
||||
/// Custom timer error type
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
|
||||
pub enum Error {
|
||||
TimerActive,
|
||||
TimerInactive,
|
||||
AlarmInactive,
|
||||
}
|
||||
|
||||
/// Interrupts which can be registered in [crate::Blocking] mode
|
||||
#[derive(Debug, Default)]
|
||||
pub struct TimerInterrupts {
|
||||
@ -83,7 +77,7 @@ pub struct TimerInterrupts {
|
||||
pub struct TimerGroup<'d, T, DM>
|
||||
where
|
||||
T: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
_timer_group: PeripheralRef<'d, T>,
|
||||
pub timer0: Timer<Timer0<T>, DM>,
|
||||
@ -199,7 +193,7 @@ impl TimerGroupInstance for TIMG1 {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> TimerGroup<'d, T, crate::Blocking>
|
||||
impl<'d, T> TimerGroup<'d, T, Blocking>
|
||||
where
|
||||
T: TimerGroupInstance,
|
||||
{
|
||||
@ -332,7 +326,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<'d, T> TimerGroup<'d, T, crate::Async>
|
||||
impl<'d, T> TimerGroup<'d, T, Async>
|
||||
where
|
||||
T: TimerGroupInstance,
|
||||
{
|
||||
@ -371,19 +365,24 @@ where
|
||||
}
|
||||
|
||||
/// General-purpose Timer driver
|
||||
pub struct Timer<T, DM: crate::Mode> {
|
||||
pub struct Timer<T, DM>
|
||||
where
|
||||
DM: Mode,
|
||||
{
|
||||
timg: T,
|
||||
apb_clk_freq: HertzU32,
|
||||
phantom: PhantomData<DM>,
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> Timer<T, DM>
|
||||
impl<T, DM> Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
/// Create a new timer instance.
|
||||
pub fn new(timg: T, apb_clk_freq: HertzU32) -> Self {
|
||||
timg.enable_peripheral();
|
||||
timg.set_counter_active(true);
|
||||
|
||||
Self {
|
||||
timg,
|
||||
@ -431,9 +430,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> Deref for Timer<T, DM>
|
||||
impl<T, DM> Deref for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
type Target = T;
|
||||
|
||||
@ -442,44 +442,159 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, DM: crate::Mode> DerefMut for Timer<T, DM>
|
||||
impl<T, DM> DerefMut for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.timg
|
||||
}
|
||||
}
|
||||
|
||||
/// Timer peripheral instance
|
||||
pub trait Instance: crate::private::Sealed + Enable {
|
||||
fn reset_counter(&mut self);
|
||||
impl<T, DM> crate::private::Sealed for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
}
|
||||
|
||||
fn set_counter_active(&mut self, state: bool);
|
||||
impl<T, DM> super::Timer for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: Mode,
|
||||
{
|
||||
fn start(&self) {
|
||||
self.timg.set_counter_active(false);
|
||||
self.timg.set_alarm_active(false);
|
||||
|
||||
self.timg.reset_counter();
|
||||
self.timg.set_counter_decrementing(false);
|
||||
|
||||
self.timg.set_counter_active(true);
|
||||
self.timg.set_alarm_active(true);
|
||||
}
|
||||
|
||||
fn stop(&self) {
|
||||
self.timg.set_counter_active(false);
|
||||
}
|
||||
|
||||
fn reset(&self) {
|
||||
let t = self.register_block().t(self.timer_number().into());
|
||||
|
||||
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
|
||||
t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
|
||||
|
||||
t.load().write(|w| unsafe { w.load().bits(1) });
|
||||
}
|
||||
|
||||
fn is_running(&self) -> bool {
|
||||
self.register_block()
|
||||
.t(self.timer_number().into())
|
||||
.config()
|
||||
.read()
|
||||
.en()
|
||||
.bit_is_set()
|
||||
}
|
||||
|
||||
fn now(&self) -> Instant<u64, 1, 1_000_000> {
|
||||
let t = self.register_block().t(self.timer_number().into());
|
||||
|
||||
t.update().write(|w| w.update().set_bit());
|
||||
while t.update().read().update().bit_is_set() {
|
||||
// Wait for the update to complete
|
||||
}
|
||||
|
||||
let value_lo = t.lo().read().bits() as u64;
|
||||
let value_hi = t.hi().read().bits() as u64;
|
||||
|
||||
let ticks = (value_hi << 32) | value_lo;
|
||||
let micros = ticks_to_timeout(ticks, self.apb_clk_freq, self.timg.divider());
|
||||
|
||||
Instant::<u64, 1, 1_000_000>::from_ticks(micros)
|
||||
}
|
||||
|
||||
fn load_value(&self, value: MicrosDurationU64) {
|
||||
let ticks = timeout_to_ticks(value, self.apb_clk_freq, self.timg.divider());
|
||||
|
||||
let value = ticks & 0x3F_FFFF_FFFF_FFFF;
|
||||
let high = (value >> 32) as u32;
|
||||
let low = (value & 0xFFFF_FFFF) as u32;
|
||||
|
||||
let t = self.register_block().t(self.timer_number().into());
|
||||
|
||||
t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
|
||||
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
|
||||
}
|
||||
|
||||
fn enable_auto_reload(&self, auto_reload: bool) {
|
||||
self.register_block()
|
||||
.t(self.timer_number().into())
|
||||
.config()
|
||||
.modify(|_, w| w.autoreload().bit(auto_reload));
|
||||
}
|
||||
|
||||
fn enable_interrupt(&self, state: bool) {
|
||||
self.register_block()
|
||||
.int_ena_timers()
|
||||
.write(|w| w.t(self.timer_number()).bit(state));
|
||||
}
|
||||
|
||||
fn clear_interrupt(&self) {
|
||||
self.register_block()
|
||||
.int_clr_timers()
|
||||
.write(|w| w.t(self.timer_number()).clear_bit_by_one());
|
||||
}
|
||||
|
||||
fn is_interrupt_set(&self) -> bool {
|
||||
self.register_block()
|
||||
.int_raw_timers()
|
||||
.read()
|
||||
.t(self.timer_number())
|
||||
.bit_is_set()
|
||||
}
|
||||
|
||||
fn set_alarm_active(&self, state: bool) {
|
||||
self.register_block()
|
||||
.t(self.timer_number().into())
|
||||
.config()
|
||||
.modify(|_, w| w.alarm_en().bit(state));
|
||||
}
|
||||
}
|
||||
|
||||
/// Timer peripheral instance.
|
||||
pub trait Instance: crate::private::Sealed + Enable {
|
||||
fn register_block(&self) -> &RegisterBlock;
|
||||
|
||||
fn timer_number(&self) -> u8;
|
||||
|
||||
fn reset_counter(&self);
|
||||
|
||||
fn set_counter_active(&self, state: bool);
|
||||
|
||||
fn is_counter_active(&self) -> bool;
|
||||
|
||||
fn set_counter_decrementing(&mut self, decrementing: bool);
|
||||
fn set_counter_decrementing(&self, decrementing: bool);
|
||||
|
||||
fn set_auto_reload(&mut self, auto_reload: bool);
|
||||
fn set_auto_reload(&self, auto_reload: bool);
|
||||
|
||||
fn set_alarm_active(&mut self, state: bool);
|
||||
fn set_alarm_active(&self, state: bool);
|
||||
|
||||
fn is_alarm_active(&self) -> bool;
|
||||
|
||||
fn load_alarm_value(&mut self, value: u64);
|
||||
fn load_alarm_value(&self, value: u64);
|
||||
|
||||
fn listen(&mut self);
|
||||
fn listen(&self);
|
||||
|
||||
fn unlisten(&mut self);
|
||||
fn unlisten(&self);
|
||||
|
||||
fn clear_interrupt(&mut self);
|
||||
fn clear_interrupt(&self);
|
||||
|
||||
fn now(&self) -> u64;
|
||||
|
||||
fn divider(&self) -> u32;
|
||||
|
||||
fn set_divider(&mut self, divider: u16);
|
||||
fn set_divider(&self, divider: u16);
|
||||
|
||||
fn is_interrupt_set(&self) -> bool;
|
||||
}
|
||||
@ -521,7 +636,15 @@ where
|
||||
TG: TimerGroupInstance,
|
||||
Self: Enable,
|
||||
{
|
||||
fn reset_counter(&mut self) {
|
||||
fn register_block(&self) -> &RegisterBlock {
|
||||
unsafe { &*TG::register_block() }
|
||||
}
|
||||
|
||||
fn timer_number(&self) -> u8 {
|
||||
T
|
||||
}
|
||||
|
||||
fn reset_counter(&self) {
|
||||
let t = unsafe { Self::t() };
|
||||
|
||||
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
|
||||
@ -531,7 +654,7 @@ where
|
||||
t.load().write(|w| unsafe { w.load().bits(1) });
|
||||
}
|
||||
|
||||
fn set_counter_active(&mut self, state: bool) {
|
||||
fn set_counter_active(&self, state: bool) {
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| w.en().bit(state));
|
||||
@ -541,19 +664,19 @@ where
|
||||
unsafe { Self::t() }.config().read().en().bit_is_set()
|
||||
}
|
||||
|
||||
fn set_counter_decrementing(&mut self, decrementing: bool) {
|
||||
fn set_counter_decrementing(&self, decrementing: bool) {
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| w.increase().bit(!decrementing));
|
||||
}
|
||||
|
||||
fn set_auto_reload(&mut self, auto_reload: bool) {
|
||||
fn set_auto_reload(&self, auto_reload: bool) {
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| w.autoreload().bit(auto_reload));
|
||||
}
|
||||
|
||||
fn set_alarm_active(&mut self, state: bool) {
|
||||
fn set_alarm_active(&self, state: bool) {
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| w.alarm_en().bit(state));
|
||||
@ -563,7 +686,7 @@ where
|
||||
unsafe { Self::t() }.config().read().alarm_en().bit_is_set()
|
||||
}
|
||||
|
||||
fn load_alarm_value(&mut self, value: u64) {
|
||||
fn load_alarm_value(&self, value: u64) {
|
||||
let value = value & 0x3F_FFFF_FFFF_FFFF;
|
||||
let high = (value >> 32) as u32;
|
||||
let low = (value & 0xFFFF_FFFF) as u32;
|
||||
@ -575,28 +698,26 @@ where
|
||||
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
|
||||
}
|
||||
|
||||
fn listen(&mut self) {
|
||||
let reg_block = unsafe { &*TG::register_block() };
|
||||
|
||||
fn listen(&self) {
|
||||
// always use level interrupt
|
||||
#[cfg(any(esp32, esp32s2))]
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| w.level_int_en().set_bit());
|
||||
|
||||
reg_block.int_ena_timers().modify(|_, w| w.t(T).set_bit());
|
||||
self.register_block()
|
||||
.int_ena_timers()
|
||||
.modify(|_, w| w.t(T).set_bit());
|
||||
}
|
||||
|
||||
fn unlisten(&mut self) {
|
||||
let reg_block = unsafe { &*TG::register_block() };
|
||||
|
||||
reg_block.int_ena_timers().modify(|_, w| w.t(T).clear_bit());
|
||||
fn unlisten(&self) {
|
||||
self.register_block()
|
||||
.int_ena_timers()
|
||||
.modify(|_, w| w.t(T).clear_bit());
|
||||
}
|
||||
|
||||
fn clear_interrupt(&mut self) {
|
||||
let reg_block = unsafe { &*TG::register_block() };
|
||||
|
||||
reg_block
|
||||
fn clear_interrupt(&self) {
|
||||
self.register_block()
|
||||
.int_clr_timers()
|
||||
.write(|w| w.t(T).clear_bit_by_one());
|
||||
}
|
||||
@ -630,12 +751,14 @@ where
|
||||
}
|
||||
|
||||
fn is_interrupt_set(&self) -> bool {
|
||||
let reg_block = unsafe { &*TG::register_block() };
|
||||
|
||||
reg_block.int_raw_timers().read().t(T).bit_is_set()
|
||||
self.register_block()
|
||||
.int_raw_timers()
|
||||
.read()
|
||||
.t(T)
|
||||
.bit_is_set()
|
||||
}
|
||||
|
||||
fn set_divider(&mut self, divider: u16) {
|
||||
fn set_divider(&self, divider: u16) {
|
||||
unsafe { Self::t() }
|
||||
.config()
|
||||
.modify(|_, w| unsafe { w.divider().bits(divider) })
|
||||
@ -647,7 +770,7 @@ where
|
||||
TG: TimerGroupInstance,
|
||||
{
|
||||
fn enable_peripheral(&self) {
|
||||
PeripheralClockControl::enable(crate::system::Peripheral::Timg0);
|
||||
PeripheralClockControl::enable(PeripheralEnable::Timg0);
|
||||
}
|
||||
}
|
||||
|
||||
@ -657,10 +780,22 @@ where
|
||||
TG: TimerGroupInstance,
|
||||
{
|
||||
fn enable_peripheral(&self) {
|
||||
PeripheralClockControl::enable(crate::system::Peripheral::Timg1);
|
||||
PeripheralClockControl::enable(PeripheralEnable::Timg1);
|
||||
}
|
||||
}
|
||||
|
||||
fn ticks_to_timeout<F>(ticks: u64, clock: F, divider: u32) -> u64
|
||||
where
|
||||
F: Into<HertzU32>,
|
||||
{
|
||||
let clock: HertzU32 = clock.into();
|
||||
|
||||
// 1_000_000 is used to get rid of `float` calculations
|
||||
let period: u64 = 1_000_000 * 1_000_000 / (clock.to_Hz() as u64 / divider as u64);
|
||||
|
||||
ticks * period / 1_000_000
|
||||
}
|
||||
|
||||
fn timeout_to_ticks<T, F>(timeout: T, clock: F, divider: u32) -> u64
|
||||
where
|
||||
T: Into<MicrosDurationU64>,
|
||||
@ -673,6 +808,7 @@ where
|
||||
|
||||
// 1_000_000 is used to get rid of `float` calculations
|
||||
let period: u64 = 1_000_000 * 1_000_000 / (clock.to_Hz() as u64 / divider as u64);
|
||||
|
||||
(1_000_000 * micros / period as u64) as u64
|
||||
}
|
||||
|
||||
@ -680,7 +816,7 @@ where
|
||||
impl<T, DM> embedded_hal_02::timer::CountDown for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
type Time = MicrosDurationU64;
|
||||
|
||||
@ -704,15 +840,15 @@ where
|
||||
impl<T, DM> embedded_hal_02::timer::Cancel for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
type Error = Error;
|
||||
type Error = super::Error;
|
||||
|
||||
fn cancel(&mut self) -> Result<(), Error> {
|
||||
fn cancel(&mut self) -> Result<(), super::Error> {
|
||||
if !self.timg.is_counter_active() {
|
||||
return Err(Error::TimerInactive);
|
||||
return Err(super::Error::TimerInactive);
|
||||
} else if !self.timg.is_alarm_active() {
|
||||
return Err(Error::AlarmInactive);
|
||||
return Err(super::Error::AlarmInactive);
|
||||
}
|
||||
|
||||
self.timg.set_counter_active(false);
|
||||
@ -725,7 +861,7 @@ where
|
||||
impl<T, DM> embedded_hal_02::timer::Periodic for Timer<T, DM>
|
||||
where
|
||||
T: Instance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
}
|
||||
|
||||
@ -738,7 +874,7 @@ pub struct Wdt<TG, DM> {
|
||||
impl<TG, DM> Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
/// Create a new watchdog timer instance
|
||||
pub fn new() -> Self {
|
||||
@ -854,7 +990,7 @@ where
|
||||
impl<TG, DM> Default for Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
@ -865,7 +1001,7 @@ where
|
||||
impl<TG, DM> embedded_hal_02::watchdog::WatchdogDisable for Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
fn disable(&mut self) {
|
||||
self.disable();
|
||||
@ -876,7 +1012,7 @@ where
|
||||
impl<TG, DM> embedded_hal_02::watchdog::WatchdogEnable for Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
type Time = MicrosDurationU64;
|
||||
|
||||
@ -893,7 +1029,7 @@ where
|
||||
impl<TG, DM> embedded_hal_02::watchdog::Watchdog for Wdt<TG, DM>
|
||||
where
|
||||
TG: TimerGroupInstance,
|
||||
DM: crate::Mode,
|
||||
DM: Mode,
|
||||
{
|
||||
fn feed(&mut self) {
|
||||
self.feed();
|
||||
|
@ -37,10 +37,11 @@ fn main() -> ! {
|
||||
..Default::default()
|
||||
}),
|
||||
);
|
||||
let mut timer0 = timg0.timer0;
|
||||
let timer0 = timg0.timer0;
|
||||
|
||||
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
|
||||
timer0.start(500u64.millis());
|
||||
timer0.load_value(500u64.millis());
|
||||
timer0.start();
|
||||
timer0.listen();
|
||||
|
||||
critical_section::with(|cs| {
|
||||
|
Loading…
x
Reference in New Issue
Block a user