| 1 | //! General-purpose Input/Output (GPIO) |
| 2 | |
| 3 | #![macro_use ] |
| 4 | use core::convert::Infallible; |
| 5 | |
| 6 | use critical_section::CriticalSection; |
| 7 | use embassy_hal_internal::{impl_peripheral, into_ref, PeripheralRef}; |
| 8 | |
| 9 | use crate::pac::gpio::{self, vals}; |
| 10 | use crate::{peripherals, Peripheral}; |
| 11 | |
| 12 | /// GPIO flexible pin. |
| 13 | /// |
| 14 | /// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain |
| 15 | /// set while not in output mode, so the pin's level will be 'remembered' when it is not in output |
| 16 | /// mode. |
| 17 | pub struct Flex<'d> { |
| 18 | pub(crate) pin: PeripheralRef<'d, AnyPin>, |
| 19 | } |
| 20 | |
| 21 | impl<'d> Flex<'d> { |
| 22 | /// Wrap the pin in a `Flex`. |
| 23 | /// |
| 24 | /// The pin remains disconnected. The initial output level is unspecified, but can be changed |
| 25 | /// before the pin is put into output mode. |
| 26 | /// |
| 27 | #[inline ] |
| 28 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd) -> Self { |
| 29 | into_ref!(pin); |
| 30 | // Pin will be in disconnected state. |
| 31 | Self { pin: pin.map_into() } |
| 32 | } |
| 33 | |
| 34 | /// Put the pin into input mode. |
| 35 | /// |
| 36 | /// The internal weak pull-up and pull-down resistors will be enabled according to `pull`. |
| 37 | #[inline (never)] |
| 38 | pub fn set_as_input(&mut self, pull: Pull) { |
| 39 | critical_section::with(|_| { |
| 40 | let r = self.pin.block(); |
| 41 | let n = self.pin.pin() as usize; |
| 42 | #[cfg (gpio_v1)] |
| 43 | { |
| 44 | let cnf = match pull { |
| 45 | Pull::Up => { |
| 46 | r.bsrr().write(|w| w.set_bs(n, true)); |
| 47 | vals::CnfIn::PULL |
| 48 | } |
| 49 | Pull::Down => { |
| 50 | r.bsrr().write(|w| w.set_br(n, true)); |
| 51 | vals::CnfIn::PULL |
| 52 | } |
| 53 | Pull::None => vals::CnfIn::FLOATING, |
| 54 | }; |
| 55 | |
| 56 | r.cr(n / 8).modify(|w| { |
| 57 | w.set_mode(n % 8, vals::Mode::INPUT); |
| 58 | w.set_cnf_in(n % 8, cnf); |
| 59 | }); |
| 60 | } |
| 61 | #[cfg (gpio_v2)] |
| 62 | { |
| 63 | r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); |
| 64 | r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL)); |
| 65 | r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT)); |
| 66 | } |
| 67 | }); |
| 68 | } |
| 69 | |
| 70 | /// Put the pin into push-pull output mode. |
| 71 | /// |
| 72 | /// The pin level will be whatever was set before (or low by default). If you want it to begin |
| 73 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 74 | /// |
| 75 | /// The internal weak pull-up and pull-down resistors will be disabled. |
| 76 | #[inline (never)] |
| 77 | pub fn set_as_output(&mut self, speed: Speed) { |
| 78 | critical_section::with(|_| { |
| 79 | let r = self.pin.block(); |
| 80 | let n = self.pin.pin() as usize; |
| 81 | #[cfg (gpio_v1)] |
| 82 | { |
| 83 | r.cr(n / 8).modify(|w| { |
| 84 | w.set_mode(n % 8, speed.to_mode()); |
| 85 | w.set_cnf_out(n % 8, vals::CnfOut::PUSH_PULL); |
| 86 | }); |
| 87 | } |
| 88 | #[cfg (gpio_v2)] |
| 89 | { |
| 90 | r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING)); |
| 91 | r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSH_PULL)); |
| 92 | r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); |
| 93 | r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); |
| 94 | } |
| 95 | }); |
| 96 | } |
| 97 | |
| 98 | /// Put the pin into input + open-drain output mode. |
| 99 | /// |
| 100 | /// The hardware will drive the line low if you set it to low, and will leave it floating if you set |
| 101 | /// it to high, in which case you can read the input to figure out whether another device |
| 102 | /// is driving the line low. |
| 103 | /// |
| 104 | /// The pin level will be whatever was set before (or low by default). If you want it to begin |
| 105 | /// at a specific level, call `set_high`/`set_low` on the pin first. |
| 106 | /// |
| 107 | /// The internal weak pull-up and pull-down resistors will be disabled. |
| 108 | #[inline (never)] |
| 109 | pub fn set_as_input_output(&mut self, speed: Speed) { |
| 110 | #[cfg (gpio_v1)] |
| 111 | critical_section::with(|_| { |
| 112 | let r = self.pin.block(); |
| 113 | let n = self.pin.pin() as usize; |
| 114 | r.cr(n / 8).modify(|w| w.set_mode(n % 8, speed.to_mode())); |
| 115 | r.cr(n / 8).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPEN_DRAIN)); |
| 116 | }); |
| 117 | |
| 118 | #[cfg (gpio_v2)] |
| 119 | self.set_as_input_output_pull(speed, Pull::None); |
| 120 | } |
| 121 | |
| 122 | /// Put the pin into input + open-drain output mode with internal pullup or pulldown. |
| 123 | /// |
| 124 | /// This works like [`Self::set_as_input_output()`], but it also allows to enable the internal |
| 125 | /// weak pull-up or pull-down resistors. |
| 126 | #[inline (never)] |
| 127 | #[cfg (gpio_v2)] |
| 128 | pub fn set_as_input_output_pull(&mut self, speed: Speed, pull: Pull) { |
| 129 | critical_section::with(|_| { |
| 130 | let r = self.pin.block(); |
| 131 | let n = self.pin.pin() as usize; |
| 132 | r.pupdr().modify(|w| w.set_pupdr(n, pull.to_pupdr())); |
| 133 | r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPEN_DRAIN)); |
| 134 | r.ospeedr().modify(|w| w.set_ospeedr(n, speed.to_ospeedr())); |
| 135 | r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT)); |
| 136 | }); |
| 137 | } |
| 138 | |
| 139 | /// Put the pin into analog mode |
| 140 | /// |
| 141 | /// This mode is used by ADC and COMP but usually there is no need to set this manually |
| 142 | /// as the mode change is handled by the driver. |
| 143 | #[inline ] |
| 144 | pub fn set_as_analog(&mut self) { |
| 145 | // TODO: does this also need a critical section, like other methods? |
| 146 | self.pin.set_as_analog(); |
| 147 | } |
| 148 | |
| 149 | /// Put the pin into AF mode, unchecked. |
| 150 | /// |
| 151 | /// This puts the pin into the AF mode, with the requested number and AF type. This is |
| 152 | /// completely unchecked, it can attach the pin to literally any peripheral, so use with care. |
| 153 | #[inline ] |
| 154 | pub fn set_as_af_unchecked(&mut self, af_num: u8, af_type: AfType) { |
| 155 | critical_section::with(|_| { |
| 156 | self.pin.set_as_af(af_num, af_type); |
| 157 | }); |
| 158 | } |
| 159 | |
| 160 | /// Get whether the pin input level is high. |
| 161 | #[inline ] |
| 162 | pub fn is_high(&self) -> bool { |
| 163 | !self.is_low() |
| 164 | } |
| 165 | |
| 166 | /// Get whether the pin input level is low. |
| 167 | #[inline ] |
| 168 | pub fn is_low(&self) -> bool { |
| 169 | let state = self.pin.block().idr().read().idr(self.pin.pin() as _); |
| 170 | state == vals::Idr::LOW |
| 171 | } |
| 172 | |
| 173 | /// Get the current pin input level. |
| 174 | #[inline ] |
| 175 | pub fn get_level(&self) -> Level { |
| 176 | self.is_high().into() |
| 177 | } |
| 178 | |
| 179 | /// Get whether the output level is set to high. |
| 180 | #[inline ] |
| 181 | pub fn is_set_high(&self) -> bool { |
| 182 | !self.is_set_low() |
| 183 | } |
| 184 | |
| 185 | /// Get whether the output level is set to low. |
| 186 | #[inline ] |
| 187 | pub fn is_set_low(&self) -> bool { |
| 188 | let state = self.pin.block().odr().read().odr(self.pin.pin() as _); |
| 189 | state == vals::Odr::LOW |
| 190 | } |
| 191 | |
| 192 | /// Get the current output level. |
| 193 | #[inline ] |
| 194 | pub fn get_output_level(&self) -> Level { |
| 195 | self.is_set_high().into() |
| 196 | } |
| 197 | |
| 198 | /// Set the output as high. |
| 199 | #[inline ] |
| 200 | pub fn set_high(&mut self) { |
| 201 | self.pin.set_high(); |
| 202 | } |
| 203 | |
| 204 | /// Set the output as low. |
| 205 | #[inline ] |
| 206 | pub fn set_low(&mut self) { |
| 207 | self.pin.set_low(); |
| 208 | } |
| 209 | |
| 210 | /// Set the output level. |
| 211 | #[inline ] |
| 212 | pub fn set_level(&mut self, level: Level) { |
| 213 | match level { |
| 214 | Level::Low => self.pin.set_low(), |
| 215 | Level::High => self.pin.set_high(), |
| 216 | } |
| 217 | } |
| 218 | |
| 219 | /// Toggle the output level. |
| 220 | #[inline ] |
| 221 | pub fn toggle(&mut self) { |
| 222 | if self.is_set_low() { |
| 223 | self.set_high() |
| 224 | } else { |
| 225 | self.set_low() |
| 226 | } |
| 227 | } |
| 228 | } |
| 229 | |
| 230 | impl<'d> Drop for Flex<'d> { |
| 231 | #[inline ] |
| 232 | fn drop(&mut self) { |
| 233 | critical_section::with(|_| { |
| 234 | self.pin.set_as_disconnected(); |
| 235 | }); |
| 236 | } |
| 237 | } |
| 238 | |
| 239 | /// Pull setting for an input. |
| 240 | #[derive (Debug, Eq, PartialEq, Copy, Clone)] |
| 241 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 242 | pub enum Pull { |
| 243 | /// No pull |
| 244 | None, |
| 245 | /// Pull up |
| 246 | Up, |
| 247 | /// Pull down |
| 248 | Down, |
| 249 | } |
| 250 | |
| 251 | impl Pull { |
| 252 | #[cfg (gpio_v2)] |
| 253 | const fn to_pupdr(self) -> vals::Pupdr { |
| 254 | match self { |
| 255 | Pull::None => vals::Pupdr::FLOATING, |
| 256 | Pull::Up => vals::Pupdr::PULL_UP, |
| 257 | Pull::Down => vals::Pupdr::PULL_DOWN, |
| 258 | } |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | /// Speed setting for an output. |
| 263 | /// |
| 264 | /// These vary depending on the chip, check the reference manual and datasheet ("I/O port |
| 265 | /// characteristics") for details. |
| 266 | #[derive (Debug, Copy, Clone)] |
| 267 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 268 | pub enum Speed { |
| 269 | #[cfg_attr (gpio_v1, doc = "Output speed OUTPUT2MHZ" )] |
| 270 | #[cfg_attr (gpio_v2, doc = "Output speed 00" )] |
| 271 | Low, |
| 272 | #[cfg_attr (gpio_v1, doc = "Output speed OUTPUT10MHZ" )] |
| 273 | #[cfg_attr (gpio_v2, doc = "Output speed 01" )] |
| 274 | Medium, |
| 275 | #[cfg_attr (gpio_v2, doc = "Output speed 10" )] |
| 276 | #[cfg (not(any(gpio_v1, syscfg_f0)))] |
| 277 | High, |
| 278 | #[cfg_attr (gpio_v1, doc = "Output speed OUTPUT50MHZ" )] |
| 279 | #[cfg_attr (gpio_v2, doc = "Output speed 11" )] |
| 280 | VeryHigh, |
| 281 | } |
| 282 | |
| 283 | impl Speed { |
| 284 | #[cfg (gpio_v1)] |
| 285 | const fn to_mode(self) -> vals::Mode { |
| 286 | match self { |
| 287 | Speed::Low => vals::Mode::OUTPUT2MHZ, |
| 288 | Speed::Medium => vals::Mode::OUTPUT10MHZ, |
| 289 | Speed::VeryHigh => vals::Mode::OUTPUT50MHZ, |
| 290 | } |
| 291 | } |
| 292 | |
| 293 | #[cfg (gpio_v2)] |
| 294 | const fn to_ospeedr(self: Speed) -> vals::Ospeedr { |
| 295 | match self { |
| 296 | Speed::Low => vals::Ospeedr::LOW_SPEED, |
| 297 | Speed::Medium => vals::Ospeedr::MEDIUM_SPEED, |
| 298 | #[cfg (not(syscfg_f0))] |
| 299 | Speed::High => vals::Ospeedr::HIGH_SPEED, |
| 300 | Speed::VeryHigh => vals::Ospeedr::VERY_HIGH_SPEED, |
| 301 | } |
| 302 | } |
| 303 | } |
| 304 | |
| 305 | /// GPIO input driver. |
| 306 | pub struct Input<'d> { |
| 307 | pub(crate) pin: Flex<'d>, |
| 308 | } |
| 309 | |
| 310 | impl<'d> Input<'d> { |
| 311 | /// Create GPIO input driver for a [Pin] with the provided [Pull] configuration. |
| 312 | #[inline ] |
| 313 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, pull: Pull) -> Self { |
| 314 | let mut pin = Flex::new(pin); |
| 315 | pin.set_as_input(pull); |
| 316 | Self { pin } |
| 317 | } |
| 318 | |
| 319 | /// Get whether the pin input level is high. |
| 320 | #[inline ] |
| 321 | pub fn is_high(&self) -> bool { |
| 322 | self.pin.is_high() |
| 323 | } |
| 324 | |
| 325 | /// Get whether the pin input level is low. |
| 326 | #[inline ] |
| 327 | pub fn is_low(&self) -> bool { |
| 328 | self.pin.is_low() |
| 329 | } |
| 330 | |
| 331 | /// Get the current pin input level. |
| 332 | #[inline ] |
| 333 | pub fn get_level(&self) -> Level { |
| 334 | self.pin.get_level() |
| 335 | } |
| 336 | } |
| 337 | |
| 338 | /// Digital input or output level. |
| 339 | #[derive (Debug, Eq, PartialEq, Copy, Clone)] |
| 340 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 341 | pub enum Level { |
| 342 | /// Low |
| 343 | Low, |
| 344 | /// High |
| 345 | High, |
| 346 | } |
| 347 | |
| 348 | impl From<bool> for Level { |
| 349 | fn from(val: bool) -> Self { |
| 350 | match val { |
| 351 | true => Self::High, |
| 352 | false => Self::Low, |
| 353 | } |
| 354 | } |
| 355 | } |
| 356 | |
| 357 | impl From<Level> for bool { |
| 358 | fn from(level: Level) -> bool { |
| 359 | match level { |
| 360 | Level::Low => false, |
| 361 | Level::High => true, |
| 362 | } |
| 363 | } |
| 364 | } |
| 365 | |
| 366 | /// GPIO output driver. |
| 367 | /// |
| 368 | /// Note that pins will **return to their floating state** when `Output` is dropped. |
| 369 | /// If pins should retain their state indefinitely, either keep ownership of the |
| 370 | /// `Output`, or pass it to [`core::mem::forget`]. |
| 371 | pub struct Output<'d> { |
| 372 | pub(crate) pin: Flex<'d>, |
| 373 | } |
| 374 | |
| 375 | impl<'d> Output<'d> { |
| 376 | /// Create GPIO output driver for a [Pin] with the provided [Level] and [Speed] configuration. |
| 377 | #[inline ] |
| 378 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self { |
| 379 | let mut pin = Flex::new(pin); |
| 380 | match initial_output { |
| 381 | Level::High => pin.set_high(), |
| 382 | Level::Low => pin.set_low(), |
| 383 | } |
| 384 | pin.set_as_output(speed); |
| 385 | Self { pin } |
| 386 | } |
| 387 | |
| 388 | /// Set the output as high. |
| 389 | #[inline ] |
| 390 | pub fn set_high(&mut self) { |
| 391 | self.pin.set_high(); |
| 392 | } |
| 393 | |
| 394 | /// Set the output as low. |
| 395 | #[inline ] |
| 396 | pub fn set_low(&mut self) { |
| 397 | self.pin.set_low(); |
| 398 | } |
| 399 | |
| 400 | /// Set the output level. |
| 401 | #[inline ] |
| 402 | pub fn set_level(&mut self, level: Level) { |
| 403 | self.pin.set_level(level) |
| 404 | } |
| 405 | |
| 406 | /// Is the output pin set as high? |
| 407 | #[inline ] |
| 408 | pub fn is_set_high(&self) -> bool { |
| 409 | self.pin.is_set_high() |
| 410 | } |
| 411 | |
| 412 | /// Is the output pin set as low? |
| 413 | #[inline ] |
| 414 | pub fn is_set_low(&self) -> bool { |
| 415 | self.pin.is_set_low() |
| 416 | } |
| 417 | |
| 418 | /// What level output is set to |
| 419 | #[inline ] |
| 420 | pub fn get_output_level(&self) -> Level { |
| 421 | self.pin.get_output_level() |
| 422 | } |
| 423 | |
| 424 | /// Toggle pin output |
| 425 | #[inline ] |
| 426 | pub fn toggle(&mut self) { |
| 427 | self.pin.toggle(); |
| 428 | } |
| 429 | } |
| 430 | |
| 431 | /// GPIO output open-drain driver. |
| 432 | /// |
| 433 | /// Note that pins will **return to their floating state** when `OutputOpenDrain` is dropped. |
| 434 | /// If pins should retain their state indefinitely, either keep ownership of the |
| 435 | /// `OutputOpenDrain`, or pass it to [`core::mem::forget`]. |
| 436 | pub struct OutputOpenDrain<'d> { |
| 437 | pub(crate) pin: Flex<'d>, |
| 438 | } |
| 439 | |
| 440 | impl<'d> OutputOpenDrain<'d> { |
| 441 | /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level] and [Speed]. |
| 442 | #[inline ] |
| 443 | pub fn new(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed) -> Self { |
| 444 | let mut pin = Flex::new(pin); |
| 445 | match initial_output { |
| 446 | Level::High => pin.set_high(), |
| 447 | Level::Low => pin.set_low(), |
| 448 | } |
| 449 | pin.set_as_input_output(speed); |
| 450 | Self { pin } |
| 451 | } |
| 452 | |
| 453 | /// Create a new GPIO open drain output driver for a [Pin] with the provided [Level], [Speed] |
| 454 | /// and [Pull]. |
| 455 | #[inline ] |
| 456 | #[cfg (gpio_v2)] |
| 457 | pub fn new_pull(pin: impl Peripheral<P = impl Pin> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { |
| 458 | let mut pin = Flex::new(pin); |
| 459 | match initial_output { |
| 460 | Level::High => pin.set_high(), |
| 461 | Level::Low => pin.set_low(), |
| 462 | } |
| 463 | pin.set_as_input_output_pull(speed, pull); |
| 464 | Self { pin } |
| 465 | } |
| 466 | |
| 467 | /// Get whether the pin input level is high. |
| 468 | #[inline ] |
| 469 | pub fn is_high(&self) -> bool { |
| 470 | !self.pin.is_low() |
| 471 | } |
| 472 | |
| 473 | /// Get whether the pin input level is low. |
| 474 | #[inline ] |
| 475 | pub fn is_low(&self) -> bool { |
| 476 | self.pin.is_low() |
| 477 | } |
| 478 | |
| 479 | /// Get the current pin input level. |
| 480 | #[inline ] |
| 481 | pub fn get_level(&self) -> Level { |
| 482 | self.pin.get_level() |
| 483 | } |
| 484 | |
| 485 | /// Set the output as high. |
| 486 | #[inline ] |
| 487 | pub fn set_high(&mut self) { |
| 488 | self.pin.set_high(); |
| 489 | } |
| 490 | |
| 491 | /// Set the output as low. |
| 492 | #[inline ] |
| 493 | pub fn set_low(&mut self) { |
| 494 | self.pin.set_low(); |
| 495 | } |
| 496 | |
| 497 | /// Set the output level. |
| 498 | #[inline ] |
| 499 | pub fn set_level(&mut self, level: Level) { |
| 500 | self.pin.set_level(level); |
| 501 | } |
| 502 | |
| 503 | /// Get whether the output level is set to high. |
| 504 | #[inline ] |
| 505 | pub fn is_set_high(&self) -> bool { |
| 506 | self.pin.is_set_high() |
| 507 | } |
| 508 | |
| 509 | /// Get whether the output level is set to low. |
| 510 | #[inline ] |
| 511 | pub fn is_set_low(&self) -> bool { |
| 512 | self.pin.is_set_low() |
| 513 | } |
| 514 | |
| 515 | /// Get the current output level. |
| 516 | #[inline ] |
| 517 | pub fn get_output_level(&self) -> Level { |
| 518 | self.pin.get_output_level() |
| 519 | } |
| 520 | |
| 521 | /// Toggle pin output |
| 522 | #[inline ] |
| 523 | pub fn toggle(&mut self) { |
| 524 | self.pin.toggle() |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | /// GPIO output type |
| 529 | #[derive (Debug, Copy, Clone)] |
| 530 | #[cfg_attr (feature = "defmt" , derive(defmt::Format))] |
| 531 | pub enum OutputType { |
| 532 | /// Drive the pin both high or low. |
| 533 | PushPull, |
| 534 | /// Drive the pin low, or don't drive it at all if the output level is high. |
| 535 | OpenDrain, |
| 536 | } |
| 537 | |
| 538 | impl OutputType { |
| 539 | #[cfg (gpio_v1)] |
| 540 | const fn to_cnf_out(self) -> vals::CnfOut { |
| 541 | match self { |
| 542 | OutputType::PushPull => vals::CnfOut::ALT_PUSH_PULL, |
| 543 | OutputType::OpenDrain => vals::CnfOut::ALT_OPEN_DRAIN, |
| 544 | } |
| 545 | } |
| 546 | |
| 547 | #[cfg (gpio_v2)] |
| 548 | const fn to_ot(self) -> vals::Ot { |
| 549 | match self { |
| 550 | OutputType::PushPull => vals::Ot::PUSH_PULL, |
| 551 | OutputType::OpenDrain => vals::Ot::OPEN_DRAIN, |
| 552 | } |
| 553 | } |
| 554 | } |
| 555 | |
| 556 | /// Alternate function type settings. |
| 557 | #[derive (Copy, Clone)] |
| 558 | #[cfg (gpio_v1)] |
| 559 | pub struct AfType { |
| 560 | mode: vals::Mode, |
| 561 | cnf: u8, |
| 562 | pull: Pull, |
| 563 | } |
| 564 | |
| 565 | #[cfg (gpio_v1)] |
| 566 | impl AfType { |
| 567 | /// Input with optional pullup or pulldown. |
| 568 | pub const fn input(pull: Pull) -> Self { |
| 569 | let cnf_in = match pull { |
| 570 | Pull::Up | Pull::Down => vals::CnfIn::PULL, |
| 571 | Pull::None => vals::CnfIn::FLOATING, |
| 572 | }; |
| 573 | Self { |
| 574 | mode: vals::Mode::INPUT, |
| 575 | cnf: cnf_in.to_bits(), |
| 576 | pull, |
| 577 | } |
| 578 | } |
| 579 | |
| 580 | /// Output with output type and speed and no pull-up or pull-down. |
| 581 | pub const fn output(output_type: OutputType, speed: Speed) -> Self { |
| 582 | Self { |
| 583 | mode: speed.to_mode(), |
| 584 | cnf: output_type.to_cnf_out().to_bits(), |
| 585 | pull: Pull::None, |
| 586 | } |
| 587 | } |
| 588 | } |
| 589 | |
| 590 | #[inline (never)] |
| 591 | #[cfg (gpio_v1)] |
| 592 | fn set_as_af(pin_port: u8, _af_num: u8, af_type: AfType) { |
| 593 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 594 | let r = pin.block(); |
| 595 | let n = pin._pin() as usize; |
| 596 | |
| 597 | r.cr(n / 8).modify(|w| { |
| 598 | w.set_mode(n % 8, af_type.mode); |
| 599 | // note that we are writing the CNF field, which is exposed as both `cnf_in` and `cnf_out` |
| 600 | // in the PAC. the choice of `cnf_in` instead of `cnf_out` in this code is arbitrary and |
| 601 | // does not affect the result. |
| 602 | w.set_cnf_in(n % 8, vals::CnfIn::from_bits(af_type.cnf)); |
| 603 | }); |
| 604 | |
| 605 | match af_type.pull { |
| 606 | Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)), |
| 607 | Pull::Down => r.bsrr().write(|w| w.set_br(n, true)), |
| 608 | Pull::None => {} |
| 609 | } |
| 610 | } |
| 611 | |
| 612 | /// Alternate function type settings. |
| 613 | #[derive (Copy, Clone)] |
| 614 | #[cfg (gpio_v2)] |
| 615 | pub struct AfType { |
| 616 | pupdr: vals::Pupdr, |
| 617 | ot: vals::Ot, |
| 618 | ospeedr: vals::Ospeedr, |
| 619 | } |
| 620 | |
| 621 | #[cfg (gpio_v2)] |
| 622 | impl AfType { |
| 623 | /// Input with optional pullup or pulldown. |
| 624 | pub const fn input(pull: Pull) -> Self { |
| 625 | Self { |
| 626 | pupdr: pull.to_pupdr(), |
| 627 | ot: vals::Ot::PUSH_PULL, |
| 628 | ospeedr: vals::Ospeedr::LOW_SPEED, |
| 629 | } |
| 630 | } |
| 631 | |
| 632 | /// Output with output type and speed and no pull-up or pull-down. |
| 633 | pub const fn output(output_type: OutputType, speed: Speed) -> Self { |
| 634 | Self::output_pull(output_type, speed, Pull::None) |
| 635 | } |
| 636 | |
| 637 | /// Output with output type, speed and pull-up or pull-down; |
| 638 | pub const fn output_pull(output_type: OutputType, speed: Speed, pull: Pull) -> Self { |
| 639 | Self { |
| 640 | pupdr: pull.to_pupdr(), |
| 641 | ot: output_type.to_ot(), |
| 642 | ospeedr: speed.to_ospeedr(), |
| 643 | } |
| 644 | } |
| 645 | } |
| 646 | |
| 647 | #[inline (never)] |
| 648 | #[cfg (gpio_v2)] |
| 649 | fn set_as_af(pin_port: u8, af_num: u8, af_type: AfType) { |
| 650 | let pin: AnyPin = unsafe { AnyPin::steal(pin_port) }; |
| 651 | let r: Gpio = pin.block(); |
| 652 | let n: usize = pin._pin() as usize; |
| 653 | |
| 654 | r.afr(n / 8).modify(|w: &mut Afr| w.set_afr(n:n % 8, val:af_num)); |
| 655 | r.pupdr().modify(|w: &mut Pupdr| w.set_pupdr(n, val:af_type.pupdr)); |
| 656 | r.otyper().modify(|w: &mut Otyper| w.set_ot(n, val:af_type.ot)); |
| 657 | r.ospeedr().modify(|w: &mut Ospeedr| w.set_ospeedr(n, val:af_type.ospeedr)); |
| 658 | r.moder().modify(|w: &mut Moder| w.set_moder(n, val:vals::Moder::ALTERNATE)); |
| 659 | } |
| 660 | |
| 661 | #[inline (never)] |
| 662 | #[cfg (gpio_v2)] |
| 663 | fn set_speed(pin_port: u8, speed: Speed) { |
| 664 | let pin: AnyPin = unsafe { AnyPin::steal(pin_port) }; |
| 665 | let r: Gpio = pin.block(); |
| 666 | let n: usize = pin._pin() as usize; |
| 667 | |
| 668 | r.ospeedr().modify(|w: &mut Ospeedr| w.set_ospeedr(n, val:speed.to_ospeedr())); |
| 669 | } |
| 670 | |
| 671 | #[inline (never)] |
| 672 | fn set_as_analog(pin_port: u8) { |
| 673 | let pin: AnyPin = unsafe { AnyPin::steal(pin_port) }; |
| 674 | let r: Gpio = pin.block(); |
| 675 | let n: usize = pin._pin() as usize; |
| 676 | |
| 677 | #[cfg (gpio_v1)] |
| 678 | r.cr(n / 8).modify(|w| { |
| 679 | w.set_mode(n % 8, vals::Mode::INPUT); |
| 680 | w.set_cnf_in(n % 8, vals::CnfIn::ANALOG); |
| 681 | }); |
| 682 | |
| 683 | #[cfg (gpio_v2)] |
| 684 | r.moder().modify(|w: &mut Moder| w.set_moder(n, val:vals::Moder::ANALOG)); |
| 685 | } |
| 686 | |
| 687 | #[inline (never)] |
| 688 | fn get_pull(pin_port: u8) -> Pull { |
| 689 | let pin = unsafe { AnyPin::steal(pin_port) }; |
| 690 | let r = pin.block(); |
| 691 | let n = pin._pin() as usize; |
| 692 | |
| 693 | #[cfg (gpio_v1)] |
| 694 | return match r.cr(n / 8).read().mode(n % 8) { |
| 695 | vals::Mode::INPUT => match r.cr(n / 8).read().cnf_in(n % 8) { |
| 696 | vals::CnfIn::PULL => match r.odr().read().odr(n) { |
| 697 | vals::Odr::LOW => Pull::Down, |
| 698 | vals::Odr::HIGH => Pull::Up, |
| 699 | }, |
| 700 | _ => Pull::None, |
| 701 | }, |
| 702 | _ => Pull::None, |
| 703 | }; |
| 704 | |
| 705 | #[cfg (gpio_v2)] |
| 706 | return match r.pupdr().read().pupdr(n) { |
| 707 | vals::Pupdr::FLOATING => Pull::None, |
| 708 | vals::Pupdr::PULL_DOWN => Pull::Down, |
| 709 | vals::Pupdr::PULL_UP => Pull::Up, |
| 710 | vals::Pupdr::_RESERVED_3 => Pull::None, |
| 711 | }; |
| 712 | } |
| 713 | |
| 714 | pub(crate) trait SealedPin { |
| 715 | fn pin_port(&self) -> u8; |
| 716 | |
| 717 | #[inline ] |
| 718 | fn _pin(&self) -> u8 { |
| 719 | self.pin_port() % 16 |
| 720 | } |
| 721 | |
| 722 | #[inline ] |
| 723 | fn _port(&self) -> u8 { |
| 724 | self.pin_port() / 16 |
| 725 | } |
| 726 | |
| 727 | #[inline ] |
| 728 | fn block(&self) -> gpio::Gpio { |
| 729 | crate::_generated::gpio_block(self._port() as _) |
| 730 | } |
| 731 | |
| 732 | /// Set the output as high. |
| 733 | #[inline ] |
| 734 | fn set_high(&self) { |
| 735 | let n = self._pin() as _; |
| 736 | self.block().bsrr().write(|w| w.set_bs(n, true)); |
| 737 | } |
| 738 | |
| 739 | /// Set the output as low. |
| 740 | #[inline ] |
| 741 | fn set_low(&self) { |
| 742 | let n = self._pin() as _; |
| 743 | self.block().bsrr().write(|w| w.set_br(n, true)); |
| 744 | } |
| 745 | |
| 746 | #[inline ] |
| 747 | fn set_as_af(&self, af_num: u8, af_type: AfType) { |
| 748 | set_as_af(self.pin_port(), af_num, af_type) |
| 749 | } |
| 750 | |
| 751 | #[inline ] |
| 752 | #[cfg (gpio_v2)] |
| 753 | fn set_speed(&self, speed: Speed) { |
| 754 | set_speed(self.pin_port(), speed) |
| 755 | } |
| 756 | |
| 757 | #[inline ] |
| 758 | fn set_as_analog(&self) { |
| 759 | set_as_analog(self.pin_port()); |
| 760 | } |
| 761 | |
| 762 | /// Set the pin as "disconnected", ie doing nothing and consuming the lowest |
| 763 | /// amount of power possible. |
| 764 | /// |
| 765 | /// This is currently the same as [`Self::set_as_analog()`] but is semantically different |
| 766 | /// really. Drivers should `set_as_disconnected()` pins when dropped. |
| 767 | /// |
| 768 | /// Note that this also disables the internal weak pull-up and pull-down resistors. |
| 769 | #[inline ] |
| 770 | fn set_as_disconnected(&self) { |
| 771 | self.set_as_analog(); |
| 772 | } |
| 773 | |
| 774 | /// Get the pull-up configuration. |
| 775 | #[inline ] |
| 776 | fn pull(&self) -> Pull { |
| 777 | critical_section::with(|_| get_pull(self.pin_port())) |
| 778 | } |
| 779 | } |
| 780 | |
| 781 | /// GPIO pin trait. |
| 782 | #[allow (private_bounds)] |
| 783 | pub trait Pin: Peripheral<P = Self> + Into<AnyPin> + SealedPin + Sized + 'static { |
| 784 | /// EXTI channel assigned to this pin. |
| 785 | /// |
| 786 | /// For example, PC4 uses EXTI4. |
| 787 | #[cfg (feature = "exti" )] |
| 788 | type ExtiChannel: crate::exti::Channel; |
| 789 | |
| 790 | /// Number of the pin within the port (0..31) |
| 791 | #[inline ] |
| 792 | fn pin(&self) -> u8 { |
| 793 | self._pin() |
| 794 | } |
| 795 | |
| 796 | /// Port of the pin |
| 797 | #[inline ] |
| 798 | fn port(&self) -> u8 { |
| 799 | self._port() |
| 800 | } |
| 801 | |
| 802 | /// Type-erase (degrade) this pin into an `AnyPin`. |
| 803 | /// |
| 804 | /// This converts pin singletons (`PA5`, `PB6`, ...), which |
| 805 | /// are all different types, into the same type. It is useful for |
| 806 | /// creating arrays of pins, or avoiding generics. |
| 807 | #[inline ] |
| 808 | fn degrade(self) -> AnyPin { |
| 809 | AnyPin { |
| 810 | pin_port: self.pin_port(), |
| 811 | } |
| 812 | } |
| 813 | } |
| 814 | |
| 815 | /// Type-erased GPIO pin |
| 816 | pub struct AnyPin { |
| 817 | pin_port: u8, |
| 818 | } |
| 819 | |
| 820 | impl AnyPin { |
| 821 | /// Unsafely create an `AnyPin` from a pin+port number. |
| 822 | /// |
| 823 | /// `pin_port` is `port_num * 16 + pin_num`, where `port_num` is 0 for port `A`, 1 for port `B`, etc... |
| 824 | #[inline ] |
| 825 | pub unsafe fn steal(pin_port: u8) -> Self { |
| 826 | Self { pin_port } |
| 827 | } |
| 828 | |
| 829 | #[inline ] |
| 830 | fn _port(&self) -> u8 { |
| 831 | self.pin_port / 16 |
| 832 | } |
| 833 | |
| 834 | /// Get the GPIO register block for this pin. |
| 835 | #[cfg (feature = "unstable-pac" )] |
| 836 | #[inline ] |
| 837 | pub fn block(&self) -> gpio::Gpio { |
| 838 | crate::_generated::gpio_block(self._port() as _) |
| 839 | } |
| 840 | } |
| 841 | |
| 842 | impl_peripheral!(AnyPin); |
| 843 | impl Pin for AnyPin { |
| 844 | #[cfg (feature = "exti" )] |
| 845 | type ExtiChannel = crate::exti::AnyChannel; |
| 846 | } |
| 847 | impl SealedPin for AnyPin { |
| 848 | #[inline ] |
| 849 | fn pin_port(&self) -> u8 { |
| 850 | self.pin_port |
| 851 | } |
| 852 | } |
| 853 | |
| 854 | // ==================== |
| 855 | |
| 856 | foreach_pin!( |
| 857 | ($pin_name:ident, $port_name:ident, $port_num:expr, $pin_num:expr, $exti_ch:ident) => { |
| 858 | impl Pin for peripherals::$pin_name { |
| 859 | #[cfg(feature = "exti" )] |
| 860 | type ExtiChannel = peripherals::$exti_ch; |
| 861 | } |
| 862 | impl SealedPin for peripherals::$pin_name { |
| 863 | #[inline] |
| 864 | fn pin_port(&self) -> u8 { |
| 865 | $port_num * 16 + $pin_num |
| 866 | } |
| 867 | } |
| 868 | |
| 869 | impl From<peripherals::$pin_name> for AnyPin { |
| 870 | fn from(x: peripherals::$pin_name) -> Self { |
| 871 | x.degrade() |
| 872 | } |
| 873 | } |
| 874 | }; |
| 875 | ); |
| 876 | |
| 877 | pub(crate) unsafe fn init(_cs: CriticalSection) { |
| 878 | #[cfg (afio)] |
| 879 | crate::rcc::enable_and_reset_with_cs::<crate::peripherals::AFIO>(_cs); |
| 880 | |
| 881 | crate::_generated::init_gpio(); |
| 882 | } |
| 883 | |
| 884 | impl<'d> embedded_hal_02::digital::v2::InputPin for Input<'d> { |
| 885 | type Error = Infallible; |
| 886 | |
| 887 | #[inline ] |
| 888 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 889 | Ok(self.is_high()) |
| 890 | } |
| 891 | |
| 892 | #[inline ] |
| 893 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 894 | Ok(self.is_low()) |
| 895 | } |
| 896 | } |
| 897 | |
| 898 | impl<'d> embedded_hal_02::digital::v2::OutputPin for Output<'d> { |
| 899 | type Error = Infallible; |
| 900 | |
| 901 | #[inline ] |
| 902 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 903 | self.set_high(); |
| 904 | Ok(()) |
| 905 | } |
| 906 | |
| 907 | #[inline ] |
| 908 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 909 | self.set_low(); |
| 910 | Ok(()) |
| 911 | } |
| 912 | } |
| 913 | |
| 914 | impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Output<'d> { |
| 915 | #[inline ] |
| 916 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 917 | Ok(self.is_set_high()) |
| 918 | } |
| 919 | |
| 920 | /// Is the output pin set as low? |
| 921 | #[inline ] |
| 922 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 923 | Ok(self.is_set_low()) |
| 924 | } |
| 925 | } |
| 926 | |
| 927 | impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Output<'d> { |
| 928 | type Error = Infallible; |
| 929 | #[inline ] |
| 930 | fn toggle(&mut self) -> Result<(), Self::Error> { |
| 931 | self.toggle(); |
| 932 | Ok(()) |
| 933 | } |
| 934 | } |
| 935 | |
| 936 | impl<'d> embedded_hal_02::digital::v2::InputPin for OutputOpenDrain<'d> { |
| 937 | type Error = Infallible; |
| 938 | |
| 939 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 940 | Ok(self.is_high()) |
| 941 | } |
| 942 | |
| 943 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 944 | Ok(self.is_low()) |
| 945 | } |
| 946 | } |
| 947 | |
| 948 | impl<'d> embedded_hal_02::digital::v2::OutputPin for OutputOpenDrain<'d> { |
| 949 | type Error = Infallible; |
| 950 | |
| 951 | #[inline ] |
| 952 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 953 | self.set_high(); |
| 954 | Ok(()) |
| 955 | } |
| 956 | |
| 957 | #[inline ] |
| 958 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 959 | self.set_low(); |
| 960 | Ok(()) |
| 961 | } |
| 962 | } |
| 963 | |
| 964 | impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for OutputOpenDrain<'d> { |
| 965 | #[inline ] |
| 966 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 967 | Ok(self.is_set_high()) |
| 968 | } |
| 969 | |
| 970 | /// Is the output pin set as low? |
| 971 | #[inline ] |
| 972 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 973 | Ok(self.is_set_low()) |
| 974 | } |
| 975 | } |
| 976 | |
| 977 | impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for OutputOpenDrain<'d> { |
| 978 | type Error = Infallible; |
| 979 | #[inline ] |
| 980 | fn toggle(&mut self) -> Result<(), Self::Error> { |
| 981 | self.toggle(); |
| 982 | Ok(()) |
| 983 | } |
| 984 | } |
| 985 | |
| 986 | impl<'d> embedded_hal_02::digital::v2::InputPin for Flex<'d> { |
| 987 | type Error = Infallible; |
| 988 | |
| 989 | #[inline ] |
| 990 | fn is_high(&self) -> Result<bool, Self::Error> { |
| 991 | Ok(self.is_high()) |
| 992 | } |
| 993 | |
| 994 | #[inline ] |
| 995 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 996 | Ok(self.is_low()) |
| 997 | } |
| 998 | } |
| 999 | |
| 1000 | impl<'d> embedded_hal_02::digital::v2::OutputPin for Flex<'d> { |
| 1001 | type Error = Infallible; |
| 1002 | |
| 1003 | #[inline ] |
| 1004 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 1005 | self.set_high(); |
| 1006 | Ok(()) |
| 1007 | } |
| 1008 | |
| 1009 | #[inline ] |
| 1010 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 1011 | self.set_low(); |
| 1012 | Ok(()) |
| 1013 | } |
| 1014 | } |
| 1015 | |
| 1016 | impl<'d> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d> { |
| 1017 | #[inline ] |
| 1018 | fn is_set_high(&self) -> Result<bool, Self::Error> { |
| 1019 | Ok(self.is_set_high()) |
| 1020 | } |
| 1021 | |
| 1022 | /// Is the output pin set as low? |
| 1023 | #[inline ] |
| 1024 | fn is_set_low(&self) -> Result<bool, Self::Error> { |
| 1025 | Ok(self.is_set_low()) |
| 1026 | } |
| 1027 | } |
| 1028 | |
| 1029 | impl<'d> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d> { |
| 1030 | type Error = Infallible; |
| 1031 | #[inline ] |
| 1032 | fn toggle(&mut self) -> Result<(), Self::Error> { |
| 1033 | self.toggle(); |
| 1034 | Ok(()) |
| 1035 | } |
| 1036 | } |
| 1037 | |
| 1038 | impl<'d> embedded_hal_1::digital::ErrorType for Input<'d> { |
| 1039 | type Error = Infallible; |
| 1040 | } |
| 1041 | |
| 1042 | impl<'d> embedded_hal_1::digital::InputPin for Input<'d> { |
| 1043 | #[inline ] |
| 1044 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 1045 | Ok((*self).is_high()) |
| 1046 | } |
| 1047 | |
| 1048 | #[inline ] |
| 1049 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 1050 | Ok((*self).is_low()) |
| 1051 | } |
| 1052 | } |
| 1053 | |
| 1054 | impl<'d> embedded_hal_1::digital::ErrorType for Output<'d> { |
| 1055 | type Error = Infallible; |
| 1056 | } |
| 1057 | |
| 1058 | impl<'d> embedded_hal_1::digital::OutputPin for Output<'d> { |
| 1059 | #[inline ] |
| 1060 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 1061 | Ok(self.set_high()) |
| 1062 | } |
| 1063 | |
| 1064 | #[inline ] |
| 1065 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 1066 | Ok(self.set_low()) |
| 1067 | } |
| 1068 | } |
| 1069 | |
| 1070 | impl<'d> embedded_hal_1::digital::StatefulOutputPin for Output<'d> { |
| 1071 | #[inline ] |
| 1072 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 1073 | Ok((*self).is_set_high()) |
| 1074 | } |
| 1075 | |
| 1076 | /// Is the output pin set as low? |
| 1077 | #[inline ] |
| 1078 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 1079 | Ok((*self).is_set_low()) |
| 1080 | } |
| 1081 | } |
| 1082 | |
| 1083 | impl<'d> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d> { |
| 1084 | type Error = Infallible; |
| 1085 | } |
| 1086 | |
| 1087 | impl<'d> embedded_hal_1::digital::InputPin for OutputOpenDrain<'d> { |
| 1088 | #[inline ] |
| 1089 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 1090 | Ok((*self).is_high()) |
| 1091 | } |
| 1092 | |
| 1093 | #[inline ] |
| 1094 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 1095 | Ok((*self).is_low()) |
| 1096 | } |
| 1097 | } |
| 1098 | |
| 1099 | impl<'d> embedded_hal_1::digital::OutputPin for OutputOpenDrain<'d> { |
| 1100 | #[inline ] |
| 1101 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 1102 | Ok(self.set_high()) |
| 1103 | } |
| 1104 | |
| 1105 | #[inline ] |
| 1106 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 1107 | Ok(self.set_low()) |
| 1108 | } |
| 1109 | } |
| 1110 | |
| 1111 | impl<'d> embedded_hal_1::digital::StatefulOutputPin for OutputOpenDrain<'d> { |
| 1112 | #[inline ] |
| 1113 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 1114 | Ok((*self).is_set_high()) |
| 1115 | } |
| 1116 | |
| 1117 | /// Is the output pin set as low? |
| 1118 | #[inline ] |
| 1119 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 1120 | Ok((*self).is_set_low()) |
| 1121 | } |
| 1122 | } |
| 1123 | |
| 1124 | impl<'d> embedded_hal_1::digital::InputPin for Flex<'d> { |
| 1125 | #[inline ] |
| 1126 | fn is_high(&mut self) -> Result<bool, Self::Error> { |
| 1127 | Ok((*self).is_high()) |
| 1128 | } |
| 1129 | |
| 1130 | #[inline ] |
| 1131 | fn is_low(&mut self) -> Result<bool, Self::Error> { |
| 1132 | Ok((*self).is_low()) |
| 1133 | } |
| 1134 | } |
| 1135 | |
| 1136 | impl<'d> embedded_hal_1::digital::OutputPin for Flex<'d> { |
| 1137 | #[inline ] |
| 1138 | fn set_high(&mut self) -> Result<(), Self::Error> { |
| 1139 | Ok(self.set_high()) |
| 1140 | } |
| 1141 | |
| 1142 | #[inline ] |
| 1143 | fn set_low(&mut self) -> Result<(), Self::Error> { |
| 1144 | Ok(self.set_low()) |
| 1145 | } |
| 1146 | } |
| 1147 | |
| 1148 | impl<'d> embedded_hal_1::digital::ErrorType for Flex<'d> { |
| 1149 | type Error = Infallible; |
| 1150 | } |
| 1151 | |
| 1152 | impl<'d> embedded_hal_1::digital::StatefulOutputPin for Flex<'d> { |
| 1153 | #[inline ] |
| 1154 | fn is_set_high(&mut self) -> Result<bool, Self::Error> { |
| 1155 | Ok((*self).is_set_high()) |
| 1156 | } |
| 1157 | |
| 1158 | /// Is the output pin set as low? |
| 1159 | #[inline ] |
| 1160 | fn is_set_low(&mut self) -> Result<bool, Self::Error> { |
| 1161 | Ok((*self).is_set_low()) |
| 1162 | } |
| 1163 | } |
| 1164 | |