Skip to content

Commit b23e2eb

Browse files
kyp44Dan Whitman
andauthored
feat: Implement DelayNs trait for TimerCounter
#880 * feat(timer): Implements the `ehal::delay::DelayNs` trait for `timer::TimerCounter` and refactors it a bit to pull out common code and reduce code duplication between chip variants. * feat(timer): Addresses an overlooked issue with the `pwm` driver caused by a refactor of `timer_params::TimerParams` when implementing the `ehal::delay::DelayNs` trait for `timer::TimerCounter`. * feat(timer): As it is public, restores the behavior of the `timer_params::TimerParams` constructors such that they panic if a 16-bit timer cannot count the specific time. --------- Co-authored-by: Dan Whitman <[email protected]>
1 parent e9d120d commit b23e2eb

File tree

4 files changed

+164
-155
lines changed

4 files changed

+164
-155
lines changed

hal/src/peripherals/timer/common.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//! Common items for timer hardware for all chips.
2+
use core::convert::Infallible;
3+
use fugit::NanosDurationU32;
4+
5+
use crate::ehal::delay::DelayNs;
6+
use crate::ehal_02::timer::{CountDown, Periodic};
7+
use crate::time::Nanoseconds;
8+
use crate::timer_params::TimerParams;
9+
use crate::timer_traits::InterruptDrivenTimer;
10+
11+
use super::{Count16Reg, TimerCounter};
12+
13+
/// This is a helper trait to make it easier to make most of the
14+
/// TimerCounter impl generic. It doesn't make too much sense to
15+
/// to try to implement this trait outside of this module.
16+
pub trait Count16 {
17+
fn count_16(&self) -> &Count16Reg;
18+
}
19+
20+
impl<TC> InterruptDrivenTimer for TimerCounter<TC>
21+
where
22+
TC: Count16,
23+
{
24+
/// Enable the interrupt generation for this hardware timer.
25+
/// This method only sets the clock configuration to trigger
26+
/// the interrupt; it does not configure the interrupt controller
27+
/// or define an interrupt handler.
28+
fn enable_interrupt(&mut self) {
29+
self.tc.count_16().intenset().write(|w| w.ovf().set_bit());
30+
}
31+
32+
fn start<T>(&mut self, timeout: T)
33+
where
34+
T: Into<NanosDurationU32>,
35+
{
36+
let params = TimerParams::new_ns(timeout.into(), self.freq);
37+
self.start_timer(params.divider, params.check_cycles_u16());
38+
}
39+
40+
fn wait(&mut self) -> nb::Result<(), Infallible> {
41+
let count = self.tc.count_16();
42+
if count.intflag().read().ovf().bit_is_set() {
43+
// Writing a 1 clears the flag
44+
count.intflag().modify(|_, w| w.ovf().set_bit());
45+
Ok(())
46+
} else {
47+
Err(nb::Error::WouldBlock)
48+
}
49+
}
50+
51+
/// Disables interrupt generation for this hardware timer.
52+
/// This method only sets the clock configuration to prevent
53+
/// triggering the interrupt; it does not configure the interrupt
54+
/// controller.
55+
fn disable_interrupt(&mut self) {
56+
self.tc.count_16().intenclr().write(|w| w.ovf().set_bit());
57+
}
58+
}
59+
60+
impl<TC> Periodic for TimerCounter<TC> {}
61+
impl<TC> CountDown for TimerCounter<TC>
62+
where
63+
TC: Count16,
64+
{
65+
type Time = Nanoseconds;
66+
67+
fn start<T>(&mut self, timeout: T)
68+
where
69+
T: Into<Self::Time>,
70+
{
71+
<Self as InterruptDrivenTimer>::start(self, timeout);
72+
}
73+
74+
fn wait(&mut self) -> nb::Result<(), void::Void> {
75+
nb::block! {
76+
<Self as InterruptDrivenTimer>::wait(self)
77+
}
78+
.unwrap(); // wait() is Infallible
79+
Ok(())
80+
}
81+
}
82+
83+
impl<TC> DelayNs for TimerCounter<TC>
84+
where
85+
TC: Count16,
86+
{
87+
fn delay_ns(&mut self, ns: u32) {
88+
let ticks: u32 = (ns as u64 * self.freq.to_Hz() as u64 / 1_000_000_000_u64) as u32;
89+
let params = TimerParams::new_from_ticks(ticks);
90+
91+
// The timer is is only 16 bits, so we may need to run it multiple times.
92+
let mut cycles = params.cycles;
93+
if cycles > u16::MAX as u32 {
94+
self.start_timer(params.divider, u16::MAX);
95+
while cycles > u16::MAX as u32 {
96+
let _ = nb::block!(InterruptDrivenTimer::wait(self));
97+
cycles -= u16::MAX as u32;
98+
}
99+
}
100+
101+
// Wait more if there are any leftover cycles
102+
if cycles > 0 {
103+
self.start_timer(params.divider, cycles as u16);
104+
let _ = nb::block!(InterruptDrivenTimer::wait(self));
105+
}
106+
107+
self.disable();
108+
}
109+
}

hal/src/peripherals/timer/d11.rs

Lines changed: 14 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,17 @@
11
//! Working with timer counter hardware
2-
use core::convert::Infallible;
3-
42
use atsamd_hal_macros::hal_cfg;
5-
use fugit::NanosDurationU32;
63

7-
use crate::ehal_02::timer::{CountDown, Periodic};
84
use crate::pac::Pm;
95
#[hal_cfg("tc1-d11")]
106
use crate::pac::{tc1::Count16 as Count16Reg, Tc1};
117
#[hal_cfg("tc3-d21")]
128
use crate::pac::{tc3::Count16 as Count16Reg, Tc3, Tc4, Tc5};
13-
use crate::timer_params::TimerParams;
149

1510
use crate::clock;
16-
use crate::time::{Hertz, Nanoseconds};
17-
use crate::timer_traits::InterruptDrivenTimer;
11+
use crate::time::Hertz;
12+
13+
mod common;
14+
pub use common::Count16;
1815

1916
#[cfg(feature = "async")]
2017
mod async_api;
@@ -41,62 +38,17 @@ pub struct TimerCounter<TC> {
4138
freq: Hertz,
4239
tc: TC,
4340
}
44-
45-
impl<TC: Count16> TimerCounter<TC> {}
46-
47-
/// This is a helper trait to make it easier to make most of the
48-
/// TimerCounter impl generic. It doesn't make too much sense to
49-
/// to try to implement this trait outside of this module.
50-
pub trait Count16 {
51-
fn count_16(&self) -> &Count16Reg;
52-
}
53-
54-
impl<TC> Periodic for TimerCounter<TC> {}
55-
impl<TC> CountDown for TimerCounter<TC>
41+
impl<TC> TimerCounter<TC>
5642
where
5743
TC: Count16,
5844
{
59-
type Time = Nanoseconds;
60-
61-
fn start<T>(&mut self, timeout: T)
62-
where
63-
T: Into<Self::Time>,
64-
{
65-
<Self as InterruptDrivenTimer>::start(self, timeout);
66-
}
67-
68-
fn wait(&mut self) -> nb::Result<(), void::Void> {
69-
nb::block! {
70-
<Self as InterruptDrivenTimer>::wait(self)
71-
}
72-
.unwrap(); // wait() is Infallible
73-
Ok(())
74-
}
75-
}
76-
77-
impl<TC> InterruptDrivenTimer for TimerCounter<TC>
78-
where
79-
TC: Count16,
80-
{
81-
/// Enable the interrupt generation for this hardware timer.
82-
/// This method only sets the clock configuration to trigger
83-
/// the interrupt; it does not configure the interrupt controller
84-
/// or define an interrupt handler.
85-
fn enable_interrupt(&mut self) {
86-
self.tc.count_16().intenset().write(|w| w.ovf().set_bit());
87-
}
88-
89-
fn start<T: Into<NanosDurationU32>>(&mut self, timeout: T) {
90-
let params = TimerParams::new_ns(timeout.into(), self.freq);
91-
let divider = params.divider;
92-
let cycles = params.cycles;
45+
/// Starts the 16-bit timer, counting up in periodic mode.
46+
fn start_timer(&mut self, divider: u16, cycles: u16) {
47+
// Disable the timer while we reconfigure it
48+
self.disable();
9349

9450
let count = self.tc.count_16();
9551

96-
// Disable the timer while we reconfigure it
97-
count.ctrla().modify(|_, w| w.enable().clear_bit());
98-
while count.status().read().syncbusy().bit_is_set() {}
99-
10052
// Now that we have a clock routed to the peripheral, we
10153
// can ask it to perform a reset.
10254
count.ctrla().write(|w| w.swrst().set_bit());
@@ -113,7 +65,7 @@ where
11365
});
11466

11567
// Set TOP value for mfrq mode
116-
count.cc(0).write(|w| unsafe { w.cc().bits(cycles as u16) });
68+
count.cc(0).write(|w| unsafe { w.cc().bits(cycles) });
11769

11870
count.ctrla().modify(|_, w| {
11971
match divider {
@@ -134,23 +86,12 @@ where
13486
});
13587
}
13688

137-
fn wait(&mut self) -> nb::Result<(), Infallible> {
89+
/// Disable the timer
90+
fn disable(&mut self) {
13891
let count = self.tc.count_16();
139-
if count.intflag().read().ovf().bit_is_set() {
140-
// Writing a 1 clears the flag
141-
count.intflag().modify(|_, w| w.ovf().set_bit());
142-
Ok(())
143-
} else {
144-
Err(nb::Error::WouldBlock)
145-
}
146-
}
14792

148-
/// Disables interrupt generation for this hardware timer.
149-
/// This method only sets the clock configuration to prevent
150-
/// triggering the interrupt; it does not configure the interrupt
151-
/// controller.
152-
fn disable_interrupt(&mut self) {
153-
self.tc.count_16().intenclr().write(|w| w.ovf().set_bit());
93+
count.ctrla().modify(|_, w| w.enable().clear_bit());
94+
while count.status().read().syncbusy().bit_is_set() {}
15495
}
15596
}
15697

hal/src/peripherals/timer/d5x.rs

Lines changed: 14 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,18 @@
11
//! Working with timer counter hardware
2-
use core::convert::Infallible;
3-
42
use atsamd_hal_macros::hal_cfg;
5-
use fugit::NanosDurationU32;
63

7-
use crate::ehal_02::timer::{CountDown, Periodic};
84
use crate::pac::tc0::Count16 as Count16Reg;
95
use crate::pac::{Mclk, Tc2, Tc3};
106
#[hal_cfg(all("tc4", "tc5"))]
117
use crate::pac::{Tc4, Tc5};
128
#[hal_cfg(all("tc6", "tc7"))]
139
use crate::pac::{Tc6, Tc7};
14-
use crate::timer_params::TimerParams;
15-
use crate::timer_traits::InterruptDrivenTimer;
1610

1711
use crate::clock;
18-
use crate::time::{Hertz, Nanoseconds};
12+
use crate::time::Hertz;
13+
14+
mod common;
15+
pub use common::Count16;
1916

2017
#[cfg(feature = "async")]
2118
mod async_api;
@@ -42,62 +39,17 @@ pub struct TimerCounter<TC> {
4239
freq: Hertz,
4340
tc: TC,
4441
}
45-
46-
/// This is a helper trait to make it easier to make most of the
47-
/// TimerCounter impl generic. It doesn't make too much sense to
48-
/// to try to implement this trait outside of this module.
49-
pub trait Count16 {
50-
fn count_16(&self) -> &Count16Reg;
51-
}
52-
53-
impl<TC> Periodic for TimerCounter<TC> {}
54-
impl<TC> CountDown for TimerCounter<TC>
42+
impl<TC> TimerCounter<TC>
5543
where
5644
TC: Count16,
5745
{
58-
type Time = Nanoseconds;
59-
60-
fn start<T>(&mut self, timeout: T)
61-
where
62-
T: Into<Self::Time>,
63-
{
64-
<Self as InterruptDrivenTimer>::start(self, timeout);
65-
}
66-
67-
fn wait(&mut self) -> nb::Result<(), void::Void> {
68-
nb::block! {
69-
<Self as InterruptDrivenTimer>::wait(self)
70-
}
71-
.unwrap(); // wait() is Infallible
72-
Ok(())
73-
}
74-
}
75-
76-
impl<TC> InterruptDrivenTimer for TimerCounter<TC>
77-
where
78-
TC: Count16,
79-
{
80-
/// Enable the interrupt generation for this hardware timer.
81-
/// This method only sets the clock configuration to trigger
82-
/// the interrupt; it does not configure the interrupt controller
83-
/// or define an interrupt handler.
84-
fn enable_interrupt(&mut self) {
85-
self.tc.count_16().intenset().write(|w| w.ovf().set_bit());
86-
}
46+
/// Starts the 16-bit timer, counting up in periodic mode.
47+
fn start_timer(&mut self, divider: u16, cycles: u16) {
48+
// Disable the timer while we reconfigure it
49+
self.disable();
8750

88-
fn start<T>(&mut self, timeout: T)
89-
where
90-
T: Into<NanosDurationU32>,
91-
{
92-
let params = TimerParams::new_ns(timeout.into(), self.freq);
93-
let divider = params.divider;
94-
let cycles = params.cycles;
9551
let count = self.tc.count_16();
9652

97-
// Disable the timer while we reconfigure it
98-
count.ctrla().modify(|_, w| w.enable().clear_bit());
99-
while count.syncbusy().read().enable().bit_is_set() {}
100-
10153
// Now that we have a clock routed to the peripheral, we
10254
// can ask it to perform a reset.
10355
count.ctrla().write(|w| w.swrst().set_bit());
@@ -111,7 +63,7 @@ where
11163
});
11264

11365
// Set TOP value for mfrq mode
114-
count.cc(0).write(|w| unsafe { w.cc().bits(cycles as u16) });
66+
count.cc(0).write(|w| unsafe { w.cc().bits(cycles) });
11567

11668
// Enable Match Frequency Waveform generation
11769
count.wave().modify(|_, w| w.wavegen().mfrq());
@@ -133,23 +85,12 @@ where
13385
});
13486
}
13587

136-
fn wait(&mut self) -> nb::Result<(), Infallible> {
88+
/// Disable the timer
89+
fn disable(&mut self) {
13790
let count = self.tc.count_16();
138-
if count.intflag().read().ovf().bit_is_set() {
139-
// Writing a 1 clears the flag
140-
count.intflag().modify(|_, w| w.ovf().set_bit());
141-
Ok(())
142-
} else {
143-
Err(nb::Error::WouldBlock)
144-
}
145-
}
14691

147-
/// Disables interrupt generation for this hardware timer.
148-
/// This method only sets the clock configuration to prevent
149-
/// triggering the interrupt; it does not configure the interrupt
150-
/// controller.
151-
fn disable_interrupt(&mut self) {
152-
self.tc.count_16().intenclr().write(|w| w.ovf().set_bit());
92+
count.ctrla().modify(|_, w| w.enable().clear_bit());
93+
while count.syncbusy().read().enable().bit_is_set() {}
15394
}
15495
}
15596

0 commit comments

Comments
 (0)