aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/gpio.rs108
1 files changed, 85 insertions, 23 deletions
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index e562dcab7..5c2b0f6fc 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -18,7 +18,19 @@ pub enum Pull {
18 Down, 18 Down,
19} 19}
20 20
21/// Pull setting for an input. 21impl From<Pull> for vals::Pupdr {
22 fn from(pull: Pull) -> Self {
23 use Pull::*;
24
25 match pull {
26 None => vals::Pupdr::FLOATING,
27 Up => vals::Pupdr::PULLUP,
28 Down => vals::Pupdr::PULLDOWN,
29 }
30 }
31}
32
33/// Speed settings
22#[derive(Debug)] 34#[derive(Debug)]
23#[cfg_attr(feature = "defmt", derive(defmt::Format))] 35#[cfg_attr(feature = "defmt", derive(defmt::Format))]
24pub enum Speed { 36pub enum Speed {
@@ -56,12 +68,7 @@ impl<'d, T: Pin> Input<'d, T> {
56 cortex_m::interrupt::free(|_| unsafe { 68 cortex_m::interrupt::free(|_| unsafe {
57 let r = pin.block(); 69 let r = pin.block();
58 let n = pin.pin() as usize; 70 let n = pin.pin() as usize;
59 let val = match pull { 71 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
60 Pull::None => vals::Pupdr::FLOATING,
61 Pull::Up => vals::Pupdr::PULLUP,
62 Pull::Down => vals::Pupdr::PULLDOWN,
63 };
64 r.pupdr().modify(|w| w.set_pupdr(n, val));
65 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL)); 72 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL));
66 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); 73 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
67 }); 74 });
@@ -111,12 +118,7 @@ pub struct Output<'d, T: Pin> {
111} 118}
112 119
113impl<'d, T: Pin> Output<'d, T> { 120impl<'d, T: Pin> Output<'d, T> {
114 pub fn new( 121 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level, speed: Speed) -> Self {
115 pin: impl Unborrow<Target = T> + 'd,
116 initial_output: Level,
117 speed: Speed,
118 open_drain: bool,
119 ) -> Self {
120 unborrow!(pin); 122 unborrow!(pin);
121 123
122 match initial_output { 124 match initial_output {
@@ -129,9 +131,6 @@ impl<'d, T: Pin> Output<'d, T> {
129 let n = pin.pin() as usize; 131 let n = pin.pin() as usize;
130 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); 132 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
131 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); 133 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
132 if open_drain {
133 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN));
134 }
135 pin.set_speed(speed); 134 pin.set_speed(speed);
136 }); 135 });
137 136
@@ -149,8 +148,6 @@ impl<'d, T: Pin> Drop for Output<'d, T> {
149 let n = self.pin.pin() as usize; 148 let n = self.pin.pin() as usize;
150 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); 149 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
151 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); 150 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
152 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL));
153 self.pin.set_speed(Speed::LowSpeed);
154 }); 151 });
155 } 152 }
156} 153}
@@ -184,20 +181,85 @@ impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
184 } 181 }
185} 182}
186 183
187impl<'d, T: Pin> InputPin for Output<'d, T> { 184impl<'d, T: Pin> toggleable::Default for Output<'d, T> {}
185
186/// GPIO output open-drain driver.
187pub struct OutputOpenDrain<'d, T: Pin> {
188 pub(crate) pin: T,
189 phantom: PhantomData<&'d mut T>,
190}
191
192impl<'d, T: Pin> OutputOpenDrain<'d, T> {
193 pub fn new(
194 pin: impl Unborrow<Target = T> + 'd,
195 initial_output: Level,
196 speed: Speed,
197 pull: Pull,
198 ) -> Self {
199 unborrow!(pin);
200
201 match initial_output {
202 Level::High => pin.set_high(),
203 Level::Low => pin.set_low(),
204 }
205
206 cortex_m::interrupt::free(|_| unsafe {
207 let r = pin.block();
208 let n = pin.pin() as usize;
209 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
210 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
211 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN));
212 pin.set_speed(speed);
213 });
214
215 Self {
216 pin,
217 phantom: PhantomData,
218 }
219 }
220}
221
222impl<'d, T: Pin> Drop for OutputOpenDrain<'d, T> {
223 fn drop(&mut self) {
224 cortex_m::interrupt::free(|_| unsafe {
225 let r = self.pin.block();
226 let n = self.pin.pin() as usize;
227 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
228 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
229 });
230 }
231}
232
233impl<'d, T: Pin> OutputPin for OutputOpenDrain<'d, T> {
234 type Error = Infallible;
235
236 /// Set the output as high.
237 fn set_high(&mut self) -> Result<(), Self::Error> {
238 self.pin.set_high();
239 Ok(())
240 }
241
242 /// Set the output as low.
243 fn set_low(&mut self) -> Result<(), Self::Error> {
244 self.pin.set_low();
245 Ok(())
246 }
247}
248
249impl<'d, T: Pin> InputPin for Input<'d, T> {
188 type Error = Infallible; 250 type Error = Infallible;
189 251
190 fn is_high(&self) -> Result<bool, Self::Error> { 252 fn is_high(&self) -> Result<bool, Self::Error> {
191 self.is_set_high() 253 self.is_low().map(|v| !v)
192 } 254 }
193 255
194 fn is_low(&self) -> Result<bool, Self::Error> { 256 fn is_low(&self) -> Result<bool, Self::Error> {
195 self.is_set_low() 257 // NOTE(safety) Atomic read
258 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as usize) };
259 Ok(state == vals::Idr::LOW)
196 } 260 }
197} 261}
198 262
199impl<'d, T: Pin> toggleable::Default for Output<'d, T> {}
200
201pub(crate) mod sealed { 263pub(crate) mod sealed {
202 use super::*; 264 use super::*;
203 265