Skip to content

Commit fd4e2a8

Browse files
committed
stm32/timer: add bare type-erased timer driver
1 parent 4f01709 commit fd4e2a8

File tree

3 files changed

+259
-4
lines changed

3 files changed

+259
-4
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ Cargo.lock
55
third_party
66
/Cargo.toml
77
out/
8+
Session.vim

embassy-stm32/src/timer/bare.rs

Lines changed: 234 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,234 @@
1+
//! Bare register-level timer driver.
2+
//!
3+
//! This module provides the core functionality for type-erased drivers for all STM32 timers. It
4+
//! provides integration with the RCC and direct access to the timer registers. It is intended to
5+
//! serve as a building block for higher level drivers.
6+
use core::marker::PhantomData;
7+
8+
use embassy_hal_internal::PeripheralRef;
9+
10+
use super::{AdvancedInstance4Channel, Channel, CoreInstance, GeneralInstance4Channel, Info, TimerBits};
11+
use crate::gpio::{AfType, AnyPin, Pin, SealedPin};
12+
use crate::time::Hertz;
13+
use crate::{into_ref, pac, rcc, Peripheral};
14+
15+
trait TimerPinMarkerSealed {}
16+
17+
/// Trait for marker types that represent all possible timer pins.
18+
#[allow(private_bounds)]
19+
pub trait TimerPinMarker: TimerPinMarkerSealed {}
20+
21+
/// Timer pin trait.
22+
///
23+
/// If a pin peripheral implements `TimerPin<T, M>`, it means that it can be used with timer `T` in
24+
/// the role represented by marker type `M`. For example, `TimerPin<TIM1, Ch2>` is implemented for
25+
/// all pins that can be used as channel 2 for timer TIM1.
26+
///
27+
/// This trait is equivalent to the pin-specific traits defined in the [`timer`][super] module; for
28+
/// example `TimerPin<T, Ch1>` is equivalent to [`timer::Channel1Pin<T>`][super::Channel1Pin].
29+
pub trait TimerPin<T: CoreInstance, M: TimerPinMarker>: Pin {
30+
/// Get the AF number needed to use this pin with timer `T` as pin `M`.
31+
fn af_num(&self) -> u8;
32+
}
33+
34+
/// Marker type for channel 1 pin.
35+
pub enum Ch1 {}
36+
/// Marker type for channel 2 pin.
37+
pub enum Ch2 {}
38+
/// Marker type for channel 3 pin.
39+
pub enum Ch3 {}
40+
/// Marker type for channel 4 pin.
41+
pub enum Ch4 {}
42+
/// Marker type for external trigger pin.
43+
pub enum Etr {}
44+
/// Marker type for channel 1 complementary pin.
45+
pub enum Ch1N {}
46+
/// Marker type for channel 2 complementary pin.
47+
pub enum Ch2N {}
48+
/// Marker type for channel 3 complementary pin.
49+
pub enum Ch3N {}
50+
/// Marker type for channel 4 complementary pin.
51+
pub enum Ch4N {}
52+
/// Marker type for break input pin.
53+
pub enum Bkin {}
54+
/// Marker type for break input comparator 1 pin.
55+
pub enum BkinComp1 {}
56+
/// Marker type for break input comparator 2 pin.
57+
pub enum BkinComp2 {}
58+
/// Marker type for break 2 input pin.
59+
pub enum Bkin2 {}
60+
/// Marker type for break 2 input comparator 1 pin.
61+
pub enum Bkin2Comp1 {}
62+
/// Marker type for break 2 input comparator 2 pin.
63+
pub enum Bkin2Comp2 {}
64+
65+
macro_rules! impl_pin {
66+
($marker_ty:ident, $t:ident, $pin_trait:path, $peri_trait:ident) => {
67+
impl TimerPinMarkerSealed for $marker_ty {}
68+
impl TimerPinMarker for $marker_ty {}
69+
70+
impl<$t: $peri_trait, P> TimerPin<$t, $marker_ty> for P
71+
where
72+
P: $pin_trait,
73+
{
74+
fn af_num(&self) -> u8 {
75+
<P as $pin_trait>::af_num(self)
76+
}
77+
}
78+
};
79+
}
80+
81+
impl_pin!(Ch1, T, super::Channel1Pin<T>, GeneralInstance4Channel);
82+
impl_pin!(Ch2, T, super::Channel2Pin<T>, GeneralInstance4Channel);
83+
impl_pin!(Ch3, T, super::Channel3Pin<T>, GeneralInstance4Channel);
84+
impl_pin!(Ch4, T, super::Channel4Pin<T>, GeneralInstance4Channel);
85+
impl_pin!(Etr, T, super::ExternalTriggerPin<T>, GeneralInstance4Channel);
86+
87+
impl_pin!(Ch1N, T, super::Channel1ComplementaryPin<T>, AdvancedInstance4Channel);
88+
impl_pin!(Ch2N, T, super::Channel2ComplementaryPin<T>, AdvancedInstance4Channel);
89+
impl_pin!(Ch3N, T, super::Channel3ComplementaryPin<T>, AdvancedInstance4Channel);
90+
impl_pin!(Ch4N, T, super::Channel4ComplementaryPin<T>, AdvancedInstance4Channel);
91+
92+
impl_pin!(Bkin, T, super::BreakInputPin<T>, AdvancedInstance4Channel);
93+
impl_pin!(
94+
BkinComp1,
95+
T,
96+
super::BreakInputComparator1Pin<T>,
97+
AdvancedInstance4Channel
98+
);
99+
impl_pin!(
100+
BkinComp2,
101+
T,
102+
super::BreakInputComparator2Pin<T>,
103+
AdvancedInstance4Channel
104+
);
105+
106+
impl_pin!(Bkin2, T, super::BreakInput2Pin<T>, AdvancedInstance4Channel);
107+
impl_pin!(
108+
Bkin2Comp1,
109+
T,
110+
super::BreakInput2Comparator1Pin<T>,
111+
AdvancedInstance4Channel
112+
);
113+
impl_pin!(
114+
Bkin2Comp2,
115+
T,
116+
super::BreakInput2Comparator2Pin<T>,
117+
AdvancedInstance4Channel
118+
);
119+
120+
/// Trait for marker types that represent the four channel pins ([`Ch1`], [`Ch2`], [`Ch3`],
121+
/// [`Ch4`]).
122+
pub trait TimerChannelMarker: TimerPinMarker {
123+
/// Representation of the channel number.
124+
const CHANNEL: Channel;
125+
}
126+
127+
macro_rules! impl_channel {
128+
($marker_ty:ident, $channel:expr) => {
129+
impl TimerChannelMarker for $marker_ty {
130+
const CHANNEL: Channel = $channel;
131+
}
132+
};
133+
}
134+
135+
impl_channel!(Ch1, Channel::Ch1);
136+
impl_channel!(Ch2, Channel::Ch2);
137+
impl_channel!(Ch3, Channel::Ch3);
138+
impl_channel!(Ch4, Channel::Ch4);
139+
140+
/// Type-erased timer pin.
141+
///
142+
/// The only purpose of this struct is to correctly initialize the pin in the constructor and
143+
/// deinitialize it (set it as disconnected) in the constructor. It can be used to implement
144+
/// higher-level pin wrappers, like [`simple_pwm::PwmPin`](super::simple_pwm::PwmPin).
145+
pub struct AnyTimerPin<'d> {
146+
pin: PeripheralRef<'d, AnyPin>,
147+
}
148+
149+
impl<'d> AnyTimerPin<'d> {
150+
/// Initializes a timer pin `M` for timer instance `T`.
151+
pub fn new<T: CoreInstance, M: TimerPinMarker>(
152+
pin: impl Peripheral<P = impl TimerPin<T, M>> + 'd,
153+
af_type: AfType,
154+
) -> Self {
155+
into_ref!(pin);
156+
let af_num = pin.af_num();
157+
let pin = pin.map_into();
158+
pin.set_as_af(af_num, af_type);
159+
Self { pin }
160+
}
161+
}
162+
163+
impl<'d> Drop for AnyTimerPin<'d> {
164+
fn drop(&mut self) {
165+
self.pin.set_as_disconnected();
166+
}
167+
}
168+
169+
/// Type-erased bare driver for timers.
170+
///
171+
/// This driver provides direct access to the timer registers, with the type of the peripheral
172+
/// erased.
173+
pub struct AnyTimer<'d, Regs> {
174+
info: &'d Info,
175+
kernel_clock: Hertz,
176+
_phantom: PhantomData<&'d mut Regs>,
177+
}
178+
179+
macro_rules! impl_regs {
180+
($reg_ty:path, $new:ident, $peri_trait:path) => {
181+
impl<'d> AnyTimer<'d, $reg_ty> {
182+
/// Initializes timer instance `T`.
183+
pub fn $new<T: $peri_trait>(_tim: impl Peripheral<P = T> + 'd) -> Self {
184+
rcc::enable_and_reset::<T>();
185+
Self {
186+
info: T::info(),
187+
kernel_clock: T::frequency(),
188+
_phantom: PhantomData,
189+
}
190+
}
191+
192+
/// Get the registers for this timer.
193+
pub fn regs(&self) -> $reg_ty {
194+
unsafe { <$reg_ty>::from_ptr(self.info.regs) }
195+
}
196+
}
197+
};
198+
}
199+
200+
impl_regs!(pac::timer::TimCore, new_core, CoreInstance);
201+
impl_regs!(pac::timer::TimBasicNoCr2, new_basic_no_cr2, super::BasicNoCr2Instance);
202+
impl_regs!(pac::timer::TimBasic, new_basic, super::BasicInstance);
203+
impl_regs!(pac::timer::Tim1ch, new_1ch, super::GeneralInstance1Channel);
204+
impl_regs!(pac::timer::Tim2ch, new_2ch, super::GeneralInstance2Channel);
205+
impl_regs!(pac::timer::TimGp16, new_gp16, GeneralInstance4Channel);
206+
#[cfg(not(timer_l0))]
207+
impl_regs!(pac::timer::TimGp32, new_gp32, super::GeneralInstance32bit4Channel);
208+
#[cfg(not(timer_l0))]
209+
impl_regs!(pac::timer::Tim1chCmp, new_1ch_cmp, super::AdvancedInstance1Channel);
210+
#[cfg(not(timer_l0))]
211+
impl_regs!(pac::timer::Tim2chCmp, new_2ch_cmp, super::AdvancedInstance2Channel);
212+
#[cfg(not(timer_l0))]
213+
impl_regs!(pac::timer::TimAdv, new_advanced, AdvancedInstance4Channel);
214+
215+
impl<'d, Regs> AnyTimer<'d, Regs> {
216+
/// Get the kernel clock frequency for the timer peripheral.
217+
///
218+
/// Unless you switch the timer to a different clock source, this is the frequency that is fed
219+
/// into the prescaler to drive the timer.
220+
pub fn clock_frequency(&self) -> Hertz {
221+
self.kernel_clock
222+
}
223+
224+
/// Get the number of bits in this timer (16 or 32).
225+
pub fn bits(&self) -> TimerBits {
226+
self.info.bits
227+
}
228+
}
229+
230+
impl<'d, Regs> Drop for AnyTimer<'d, Regs> {
231+
fn drop(&mut self) {
232+
self.info.rcc.disable();
233+
}
234+
}

embassy-stm32/src/timer/mod.rs

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use core::marker::PhantomData;
44

55
use embassy_sync::waitqueue::AtomicWaker;
66

7+
pub mod bare;
78
#[cfg(not(stm32l0))]
89
pub mod complementary_pwm;
910
pub mod input_capture;
@@ -13,7 +14,7 @@ pub mod qei;
1314
pub mod simple_pwm;
1415

1516
use crate::interrupt;
16-
use crate::rcc::RccPeripheral;
17+
use crate::rcc::{RccInfo, RccPeripheral, SealedRccPeripheral};
1718

1819
/// Timer channel.
1920
#[derive(Clone, Copy)]
@@ -66,14 +67,23 @@ impl State {
6667
}
6768
}
6869

69-
trait SealedInstance: RccPeripheral {
70+
struct Info {
71+
regs: *mut (),
72+
rcc: RccInfo,
73+
bits: TimerBits,
74+
}
75+
76+
unsafe impl Sync for Info {}
77+
78+
trait SealedInstance {
79+
fn info() -> &'static Info;
7080
/// Async state for this timer
7181
fn state() -> &'static State;
7282
}
7383

7484
/// Core timer instance.
7585
#[allow(private_bounds)]
76-
pub trait CoreInstance: SealedInstance + 'static {
86+
pub trait CoreInstance: SealedInstance + RccPeripheral + 'static {
7787
/// Update Interrupt for this timer.
7888
type UpdateInterrupt: interrupt::typelevel::Interrupt;
7989

@@ -85,6 +95,7 @@ pub trait CoreInstance: SealedInstance + 'static {
8595
/// This is a raw pointer to the register block. The actual register block layout varies depending on the timer type.
8696
fn regs() -> *mut ();
8797
}
98+
8899
/// Cut-down basic timer instance.
89100
pub trait BasicNoCr2Instance: CoreInstance {}
90101
/// Basic timer instance.
@@ -104,7 +115,7 @@ pub trait GeneralInstance2Channel: GeneralInstance1Channel {
104115

105116
// This trait add *extra* methods to GeneralInstance4Channel,
106117
// that GeneralInstance4Channel doesn't use, but the "AdvancedInstance"s need.
107-
// And it's a private trait, so it's content won't leak to outer namespace.
118+
// And it's a private trait, so its content won't leak to outer namespace.
108119
//
109120
// If you want to add a new method to it, please leave a detail comment to explain it.
110121
trait General4ChBlankSealed {
@@ -171,6 +182,15 @@ dma_trait!(Ch4Dma, GeneralInstance4Channel);
171182
macro_rules! impl_core_timer {
172183
($inst:ident, $bits:expr) => {
173184
impl SealedInstance for crate::peripherals::$inst {
185+
fn info() -> &'static Info {
186+
static INFO: Info = Info {
187+
regs: crate::pac::$inst.as_ptr(),
188+
rcc: crate::peripherals::$inst::RCC_INFO,
189+
bits: $bits,
190+
};
191+
&INFO
192+
}
193+
174194
fn state() -> &'static State {
175195
static STATE: State = State::new();
176196
&STATE

0 commit comments

Comments
 (0)