diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-20 01:36:00 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 00:58:57 +0200 |
| commit | 3d3e770b8dca9adb50b02f14d0087fe40ee1ce35 (patch) | |
| tree | 60cf926885bbdbc4a2d43488e9570977a9a6e586 | |
| parent | fcf6a63b5cf1d1505ec01ea42a1a75f33794b038 (diff) | |
nrf/gpio: add output drive config.
| -rw-r--r-- | embassy-nrf/src/gpio.rs | 84 |
1 files changed, 65 insertions, 19 deletions
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 9f4604b0a..52cb57319 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs | |||
| @@ -2,26 +2,12 @@ use core::convert::Infallible; | |||
| 2 | use core::hint::unreachable_unchecked; | 2 | use core::hint::unreachable_unchecked; |
| 3 | 3 | ||
| 4 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; | 4 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; |
| 5 | use gpio::pin_cnf::DRIVE_A; | ||
| 5 | 6 | ||
| 6 | use crate::pac; | 7 | use crate::pac; |
| 7 | use crate::pac::p0 as gpio; | 8 | use crate::pac::p0 as gpio; |
| 8 | use crate::peripherals; | 9 | use crate::peripherals; |
| 9 | 10 | ||
| 10 | /// Represents a digital input or output level. | ||
| 11 | #[derive(Debug, Eq, PartialEq)] | ||
| 12 | pub enum Level { | ||
| 13 | Low, | ||
| 14 | High, | ||
| 15 | } | ||
| 16 | |||
| 17 | /// Represents a pull setting for an input. | ||
| 18 | #[derive(Debug, Eq, PartialEq)] | ||
| 19 | pub enum Pull { | ||
| 20 | None, | ||
| 21 | Up, | ||
| 22 | Down, | ||
| 23 | } | ||
| 24 | |||
| 25 | /// A GPIO port with up to 32 pins. | 11 | /// A GPIO port with up to 32 pins. |
| 26 | #[derive(Debug, Eq, PartialEq)] | 12 | #[derive(Debug, Eq, PartialEq)] |
| 27 | pub enum Port { | 13 | pub enum Port { |
| @@ -33,6 +19,16 @@ pub enum Port { | |||
| 33 | Port1, | 19 | Port1, |
| 34 | } | 20 | } |
| 35 | 21 | ||
| 22 | /// Pull setting for an input. | ||
| 23 | #[derive(Debug, Eq, PartialEq)] | ||
| 24 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 25 | pub enum Pull { | ||
| 26 | None, | ||
| 27 | Up, | ||
| 28 | Down, | ||
| 29 | } | ||
| 30 | |||
| 31 | /// GPIO input driver. | ||
| 36 | pub struct Input<T: Pin> { | 32 | pub struct Input<T: Pin> { |
| 37 | pin: T, | 33 | pin: T, |
| 38 | } | 34 | } |
| @@ -80,18 +76,64 @@ impl<T: Pin> InputPin for Input<T> { | |||
| 80 | } | 76 | } |
| 81 | } | 77 | } |
| 82 | 78 | ||
| 79 | /// Digital input or output level. | ||
| 80 | #[derive(Debug, Eq, PartialEq)] | ||
| 81 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 82 | pub enum Level { | ||
| 83 | Low, | ||
| 84 | High, | ||
| 85 | } | ||
| 86 | |||
| 87 | #[derive(Clone, Copy, Debug, PartialEq)] | ||
| 88 | #[cfg_attr(feature = "defmt", derive(defmt::Format))] | ||
| 89 | #[repr(u8)] | ||
| 90 | pub enum OutputDrive { | ||
| 91 | /// Standard '0', standard '1' | ||
| 92 | Standard = 0, | ||
| 93 | /// High drive '0', standard '1' | ||
| 94 | HighDrive0Standard1 = 1, | ||
| 95 | /// Standard '0', high drive '1' | ||
| 96 | Standard0HighDrive1 = 2, | ||
| 97 | /// High drive '0', high 'drive '1' | ||
| 98 | HighDrive = 3, | ||
| 99 | /// Disconnect '0' standard '1' (normally used for wired-or connections) | ||
| 100 | Disconnect0Standard1 = 4, | ||
| 101 | /// Disconnect '0', high drive '1' (normally used for wired-or connections) | ||
| 102 | Disconnect0HighDrive1 = 5, | ||
| 103 | /// Standard '0'. disconnect '1' (also known as "open drain", normally used for wired-and connections) | ||
| 104 | Standard0Disconnect1 = 6, | ||
| 105 | /// High drive '0', disconnect '1' (also known as "open drain", normally used for wired-and connections) | ||
| 106 | HighDrive0Disconnect1 = 7, | ||
| 107 | } | ||
| 108 | |||
| 109 | /// GPIO output driver. | ||
| 83 | pub struct Output<T: Pin> { | 110 | pub struct Output<T: Pin> { |
| 84 | pin: T, | 111 | pin: T, |
| 85 | } | 112 | } |
| 86 | 113 | ||
| 87 | impl<T: Pin> Output<T> { | 114 | impl<T: Pin> Output<T> { |
| 88 | // TODO opendrain | 115 | pub fn new(pin: T, initial_output: Level, drive: OutputDrive) -> Self { |
| 89 | pub fn new(pin: T, initial_output: Level) -> Self { | 116 | match initial_output { |
| 117 | Level::High => pin.set_high(), | ||
| 118 | Level::Low => pin.set_low(), | ||
| 119 | } | ||
| 120 | |||
| 121 | let drive = match drive { | ||
| 122 | OutputDrive::Standard => DRIVE_A::S0S1, | ||
| 123 | OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1, | ||
| 124 | OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1, | ||
| 125 | OutputDrive::HighDrive => DRIVE_A::H0H1, | ||
| 126 | OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1, | ||
| 127 | OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1, | ||
| 128 | OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1, | ||
| 129 | OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1, | ||
| 130 | }; | ||
| 131 | |||
| 90 | pin.conf().write(|w| { | 132 | pin.conf().write(|w| { |
| 91 | w.dir().output(); | 133 | w.dir().output(); |
| 92 | w.input().disconnect(); | 134 | w.input().disconnect(); |
| 93 | w.pull().disabled(); | 135 | w.pull().disabled(); |
| 94 | w.drive().s0s1(); | 136 | w.drive().variant(drive); |
| 95 | w.sense().disabled(); | 137 | w.sense().disabled(); |
| 96 | w | 138 | w |
| 97 | }); | 139 | }); |
| @@ -195,11 +237,13 @@ pub(crate) mod sealed { | |||
| 195 | } | 237 | } |
| 196 | 238 | ||
| 197 | pub trait Pin: sealed::Pin + Sized { | 239 | pub trait Pin: sealed::Pin + Sized { |
| 240 | /// Number of the pin within the port (0..31) | ||
| 198 | #[inline] | 241 | #[inline] |
| 199 | fn pin(&self) -> u8 { | 242 | fn pin(&self) -> u8 { |
| 200 | self._pin() | 243 | self._pin() |
| 201 | } | 244 | } |
| 202 | 245 | ||
| 246 | /// Port of the pin | ||
| 203 | #[inline] | 247 | #[inline] |
| 204 | fn port(&self) -> Port { | 248 | fn port(&self) -> Port { |
| 205 | match self.pin_port() / 32 { | 249 | match self.pin_port() / 32 { |
| @@ -215,6 +259,7 @@ pub trait Pin: sealed::Pin + Sized { | |||
| 215 | self.pin_port() as u32 | 259 | self.pin_port() as u32 |
| 216 | } | 260 | } |
| 217 | 261 | ||
| 262 | /// Convert from concrete pin type PX_XX to type erased `AnyPin`. | ||
| 218 | fn degrade(self) -> AnyPin { | 263 | fn degrade(self) -> AnyPin { |
| 219 | AnyPin { | 264 | AnyPin { |
| 220 | pin_port: self.pin_port(), | 265 | pin_port: self.pin_port(), |
| @@ -222,12 +267,13 @@ pub trait Pin: sealed::Pin + Sized { | |||
| 222 | } | 267 | } |
| 223 | } | 268 | } |
| 224 | 269 | ||
| 270 | // Type-erased GPIO pin | ||
| 225 | pub struct AnyPin { | 271 | pub struct AnyPin { |
| 226 | pin_port: u8, | 272 | pin_port: u8, |
| 227 | } | 273 | } |
| 228 | 274 | ||
| 229 | impl AnyPin { | 275 | impl AnyPin { |
| 230 | pub unsafe fn from_psel_bits(psel_bits: u32) -> Self { | 276 | pub unsafe fn steal_from_psel_bits(psel_bits: u32) -> Self { |
| 231 | Self { | 277 | Self { |
| 232 | pin_port: psel_bits as u8, | 278 | pin_port: psel_bits as u8, |
| 233 | } | 279 | } |
