aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBen Gamari <[email protected]>2021-09-29 10:10:20 -0400
committerDario Nieuwenhuis <[email protected]>2021-11-27 02:50:30 +0100
commit8211d58ee29362edc7f210e6b6d692881254f6da (patch)
tree7886921766a78062fb2194954c77ec1ec8ed2e3d
parent88d4b0c00d5164f2fe6307bacce74887b3f8d4da (diff)
stm32/pwm: initial commit
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/pwm/mod.rs195
2 files changed, 197 insertions, 0 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 424b1c994..a7b8b3224 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -51,6 +51,8 @@ pub mod sdmmc;
51pub mod spi; 51pub mod spi;
52#[cfg(usart)] 52#[cfg(usart)]
53pub mod usart; 53pub mod usart;
54//#[cfg(pwm)]
55pub mod pwm;
54 56
55#[cfg(feature = "subghz")] 57#[cfg(feature = "subghz")]
56pub mod subghz; 58pub mod subghz;
diff --git a/embassy-stm32/src/pwm/mod.rs b/embassy-stm32/src/pwm/mod.rs
new file mode 100644
index 000000000..f1ef1f1dd
--- /dev/null
+++ b/embassy-stm32/src/pwm/mod.rs
@@ -0,0 +1,195 @@
1use crate::gpio;
2use crate::rcc::RccPeripheral;
3use crate::time::Hertz;
4use core::marker::PhantomData;
5use embassy::util::Unborrow;
6use embassy_hal_common::unborrow;
7use stm32_metapac::timer::vals::Ocm;
8
9pub struct Pwm<'d, T: Instance> {
10 phantom: PhantomData<&'d mut T>,
11}
12
13// TIM2
14
15pub struct Ch1 {}
16pub struct Ch2 {}
17pub struct Ch3 {}
18pub struct Ch4 {}
19
20#[derive(Clone, Copy)]
21pub enum Channel {
22 Ch1,
23 Ch2,
24 Ch3,
25 Ch4,
26}
27
28impl<'d, T: Instance> Pwm<'d, T> {
29 pub fn new<F: Into<Hertz>>(
30 _tim: impl Unborrow<Target = T> + 'd,
31 ch1: impl Unborrow<Target = impl PwmPin<T, Ch1>> + 'd,
32 ch2: impl Unborrow<Target = impl PwmPin<T, Ch2>> + 'd,
33 ch3: impl Unborrow<Target = impl PwmPin<T, Ch3>> + 'd,
34 ch4: impl Unborrow<Target = impl PwmPin<T, Ch4>> + 'd,
35 freq: F,
36 ) -> Self {
37 unborrow!(ch1, ch2, ch3, ch4);
38
39 T::enable();
40 T::reset();
41 let r = T::regs();
42
43 let mut this = Pwm {
44 phantom: PhantomData,
45 };
46 unsafe {
47 ch1.configure();
48 ch2.configure();
49 ch3.configure();
50 ch4.configure();
51 }
52
53 unsafe {
54 use stm32_metapac::timer::vals::Dir;
55 this.set_freq(freq);
56 r.cr1().write(|w| {
57 w.set_cen(true);
58 w.set_dir(Dir::UP)
59 });
60
61 this.set_ocm(Channel::Ch1, Ocm::PWMMODE1);
62 this.set_ocm(Channel::Ch2, Ocm::PWMMODE1);
63 this.set_ocm(Channel::Ch3, Ocm::PWMMODE1);
64 this.set_ocm(Channel::Ch4, Ocm::PWMMODE1);
65 }
66 this
67 }
68
69 unsafe fn set_ocm(&mut self, channel: Channel, mode: Ocm) {
70 let r = T::regs();
71 match channel {
72 Channel::Ch1 => r.ccmr_output(0).modify(|w| w.set_ocm(0, mode)),
73 Channel::Ch2 => r.ccmr_output(0).modify(|w| w.set_ocm(1, mode)),
74 Channel::Ch3 => r.ccmr_output(1).modify(|w| w.set_ocm(0, mode)),
75 Channel::Ch4 => r.ccmr_output(1).modify(|w| w.set_ocm(1, mode)),
76 }
77 }
78
79 unsafe fn set_enable(&mut self, channel: Channel, enable: bool) {
80 let r = T::regs();
81 match channel {
82 Channel::Ch1 => r.ccer().modify(|w| w.set_cce(0, enable)),
83 Channel::Ch2 => r.ccer().modify(|w| w.set_cce(1, enable)),
84 Channel::Ch3 => r.ccer().modify(|w| w.set_cce(2, enable)),
85 Channel::Ch4 => r.ccer().modify(|w| w.set_cce(3, enable)),
86 }
87 }
88
89 pub fn enable(&mut self, channel: Channel) {
90 unsafe {
91 self.set_enable(channel, true);
92 }
93 }
94
95 pub fn disable(&mut self, channel: Channel) {
96 unsafe {
97 self.set_enable(channel, false);
98 }
99 }
100
101 pub fn set_freq<F: Into<Hertz>>(&mut self, freq: F) {
102 use core::convert::TryInto;
103 let clk = T::frequency();
104 let r = T::regs();
105 let freq: Hertz = freq.into();
106 let ticks: u32 = clk.0 / freq.0;
107 let psc: u16 = (ticks / (1 << 16)).try_into().unwrap();
108 let arr: u16 = (ticks / (u32::from(psc) + 1)).try_into().unwrap();
109 unsafe {
110 r.psc().write(|w| w.set_psc(psc));
111 r.arr().write(|w| w.set_arr(arr));
112 }
113 }
114
115 pub fn get_max_duty(&self) -> u32 {
116 let r = T::regs();
117 unsafe { r.arr().read().arr() as u32 }
118 }
119
120 pub fn set_duty(&mut self, channel: Channel, duty: u32) {
121 use core::convert::TryInto;
122 assert!(duty < self.get_max_duty());
123 let duty: u16 = duty.try_into().unwrap();
124 let r = T::regs();
125 unsafe {
126 match channel {
127 Channel::Ch1 => r.ccr(0).modify(|w| w.set_ccr(duty)),
128 Channel::Ch2 => r.ccr(1).modify(|w| w.set_ccr(duty)),
129 Channel::Ch3 => r.ccr(2).modify(|w| w.set_ccr(duty)),
130 Channel::Ch4 => r.ccr(3).modify(|w| w.set_ccr(duty)),
131 }
132 }
133 }
134}
135
136pub(crate) mod sealed {
137 pub trait Instance {
138 fn regs() -> crate::pac::timer::TimGp16;
139 }
140}
141
142pub trait Instance: sealed::Instance + Sized + RccPeripheral + 'static {}
143
144#[allow(unused)]
145macro_rules! impl_timer {
146 ($inst:ident) => {
147 impl crate::pwm::sealed::Instance for crate::peripherals::$inst {
148 fn regs() -> crate::pac::timer::TimGp16 {
149 crate::pac::$inst
150 }
151 }
152
153 impl crate::pwm::Instance for crate::peripherals::$inst {}
154 };
155}
156
157pub trait PwmPin<Timer, Channel>: gpio::OptionalPin {
158 unsafe fn configure(&mut self);
159}
160
161impl<Timer, Channel> PwmPin<Timer, Channel> for gpio::NoPin {
162 unsafe fn configure(&mut self) {}
163}
164
165#[allow(unused)]
166macro_rules! impl_pwm_pin {
167 ($timer:ident, $channel:ident, $pin:ident, $af:expr) => {
168 impl crate::pwm::PwmPin<crate::peripherals::$timer, crate::pwm::$channel>
169 for crate::peripherals::$pin
170 {
171 unsafe fn configure(&mut self) {
172 use crate::gpio::sealed::{AFType, Pin};
173 use crate::gpio::Speed;
174 self.set_low();
175 self.set_speed(Speed::VeryHigh);
176 self.set_as_af($af, AFType::OutputPushPull);
177 }
178 }
179 };
180}
181
182#[cfg(rcc_g0)]
183mod impls {
184 crate::pac::peripherals!(
185 (timer, TIM2) => { impl_timer!(TIM2); };
186 (timer, TIM3) => { impl_timer!(TIM3); };
187 (timer, TIM4) => { impl_timer!(TIM4); };
188 (timer, TIM5) => { impl_timer!(TIM5); };
189 );
190
191 impl_pwm_pin!(TIM2, Ch1, PA0, 2);
192 impl_pwm_pin!(TIM2, Ch2, PA1, 2);
193 impl_pwm_pin!(TIM2, Ch3, PA2, 2);
194 impl_pwm_pin!(TIM2, Ch4, PA3, 2);
195}