diff options
| -rw-r--r-- | embassy-stm32/src/gpio.rs | 108 |
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. | 21 | impl 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))] |
| 24 | pub enum Speed { | 36 | pub 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 | ||
| 113 | impl<'d, T: Pin> Output<'d, T> { | 120 | impl<'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 | ||
| 187 | impl<'d, T: Pin> InputPin for Output<'d, T> { | 184 | impl<'d, T: Pin> toggleable::Default for Output<'d, T> {} |
| 185 | |||
| 186 | /// GPIO output open-drain driver. | ||
| 187 | pub struct OutputOpenDrain<'d, T: Pin> { | ||
| 188 | pub(crate) pin: T, | ||
| 189 | phantom: PhantomData<&'d mut T>, | ||
| 190 | } | ||
| 191 | |||
| 192 | impl<'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 | |||
| 222 | impl<'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 | |||
| 233 | impl<'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 | |||
| 249 | impl<'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 | ||
| 199 | impl<'d, T: Pin> toggleable::Default for Output<'d, T> {} | ||
| 200 | |||
| 201 | pub(crate) mod sealed { | 263 | pub(crate) mod sealed { |
| 202 | use super::*; | 264 | use super::*; |
| 203 | 265 | ||
