aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-nrf/src/gpio.rs194
1 files changed, 152 insertions, 42 deletions
diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs
index a06ee6053..4269cbe16 100644
--- a/embassy-nrf/src/gpio.rs
+++ b/embassy-nrf/src/gpio.rs
@@ -41,24 +41,7 @@ impl<'d, T: Pin> Input<'d, T> {
41 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self { 41 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
42 unborrow!(pin); 42 unborrow!(pin);
43 43
44 pin.conf().write(|w| { 44 init_input(&pin, pull);
45 w.dir().input();
46 w.input().connect();
47 match pull {
48 Pull::None => {
49 w.pull().disabled();
50 }
51 Pull::Up => {
52 w.pull().pullup();
53 }
54 Pull::Down => {
55 w.pull().pulldown();
56 }
57 }
58 w.drive().s0s1();
59 w.sense().disabled();
60 w
61 });
62 45
63 Self { 46 Self {
64 pin, 47 pin,
@@ -93,6 +76,7 @@ pub enum Level {
93 High, 76 High,
94} 77}
95 78
79// These numbers match DRIVE_A exactly so hopefully the compiler will unify them.
96#[derive(Clone, Copy, Debug, PartialEq)] 80#[derive(Clone, Copy, Debug, PartialEq)]
97#[cfg_attr(feature = "defmt", derive(defmt::Format))] 81#[cfg_attr(feature = "defmt", derive(defmt::Format))]
98#[repr(u8)] 82#[repr(u8)]
@@ -129,30 +113,7 @@ impl<'d, T: Pin> Output<'d, T> {
129 ) -> Self { 113 ) -> Self {
130 unborrow!(pin); 114 unborrow!(pin);
131 115
132 match initial_output { 116 init_output(&pin, initial_output, drive);
133 Level::High => pin.set_high(),
134 Level::Low => pin.set_low(),
135 }
136
137 let drive = match drive {
138 OutputDrive::Standard => DRIVE_A::S0S1,
139 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
140 OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1,
141 OutputDrive::HighDrive => DRIVE_A::H0H1,
142 OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1,
143 OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1,
144 OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1,
145 OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1,
146 };
147
148 pin.conf().write(|w| {
149 w.dir().output();
150 w.input().disconnect();
151 w.pull().disabled();
152 w.drive().variant(drive);
153 w.sense().disabled();
154 w
155 });
156 117
157 Self { 118 Self {
158 pin, 119 pin,
@@ -205,6 +166,101 @@ impl<'d, T: Pin> StatefulOutputPin for Output<'d, T> {
205 } 166 }
206} 167}
207 168
169/// GPIO flexible pin.
170///
171/// This pin can either be a disconnected, input, or output pin.
172pub struct FlexPin<'d, T: Pin> {
173 pub(crate) pin: T,
174 phantom: PhantomData<&'d mut T>,
175}
176
177impl<'d, T: Pin> FlexPin<'d, T> {
178 /// Wrap the pin in a `FlexPin`.
179 ///
180 /// The pin remains disconnected.
181 pub fn new(pin: impl Unborrow<Target = T> + 'd) -> Self {
182 unborrow!(pin);
183 // Pin will be in disconnected state.
184 Self {
185 pin,
186 phantom: PhantomData,
187 }
188 }
189
190 pub fn to_input(&self, pull: Pull) {
191 self.pin.conf().reset(); // TODO is this necessary?
192 init_input(&self.pin, pull);
193 }
194
195 pub fn to_output(&self, initial_output: Level, drive: OutputDrive) {
196 self.pin.conf().reset(); // TODO is this necessary?
197 init_output(&self.pin, initial_output, drive);
198 }
199
200 pub fn disconnect(&self) {
201 self.pin.conf().reset();
202 }
203}
204
205impl<'d, T: Pin> Drop for FlexPin<'d, T> {
206 fn drop(&mut self) {
207 self.pin.conf().reset();
208 }
209}
210
211/// Implement [`InputPin`] for [`FlexPin`];
212///
213/// If the pin is not in input mode the result is unspecified.
214impl<'d, T: Pin> InputPin for FlexPin<'d, T> {
215 type Error = Infallible;
216
217 fn is_high(&self) -> Result<bool, Self::Error> {
218 self.is_low().map(|v| !v)
219 }
220
221 fn is_low(&self) -> Result<bool, Self::Error> {
222 Ok(self.pin.block().in_.read().bits() & (1 << self.pin.pin()) == 0)
223 }
224}
225
226impl<'d, T: Pin> OutputPin for FlexPin<'d, T> {
227 type Error = Infallible;
228
229 /// Set the output as high.
230 fn set_high(&mut self) -> Result<(), Self::Error> {
231 unsafe {
232 self.pin
233 .block()
234 .outset
235 .write(|w| w.bits(1u32 << self.pin.pin()));
236 }
237 Ok(())
238 }
239
240 /// Set the output as low.
241 fn set_low(&mut self) -> Result<(), Self::Error> {
242 unsafe {
243 self.pin
244 .block()
245 .outclr
246 .write(|w| w.bits(1u32 << self.pin.pin()));
247 }
248 Ok(())
249 }
250}
251
252impl<'d, T: Pin> StatefulOutputPin for FlexPin<'d, T> {
253 /// Is the output pin set as high?
254 fn is_set_high(&self) -> Result<bool, Self::Error> {
255 self.is_set_low().map(|v| !v)
256 }
257
258 /// Is the output pin set as low?
259 fn is_set_low(&self) -> Result<bool, Self::Error> {
260 Ok(self.pin.block().out.read().bits() & (1 << self.pin.pin()) == 0)
261 }
262}
263
208pub(crate) mod sealed { 264pub(crate) mod sealed {
209 use super::*; 265 use super::*;
210 266
@@ -314,6 +370,60 @@ impl sealed::Pin for AnyPin {
314 } 370 }
315} 371}
316 372
373// =====================
374
375/// Set up a pin for input
376#[inline]
377fn init_input<T: Pin>(pin: &T, pull: Pull) {
378 pin.conf().write(|w| {
379 w.dir().input();
380 w.input().connect();
381 match pull {
382 Pull::None => {
383 w.pull().disabled();
384 }
385 Pull::Up => {
386 w.pull().pullup();
387 }
388 Pull::Down => {
389 w.pull().pulldown();
390 }
391 }
392 w.drive().s0s1();
393 w.sense().disabled();
394 w
395 });
396}
397
398/// Set up a pin for output
399#[inline]
400fn init_output<T: Pin>(pin: &T, initial_output: Level, drive: OutputDrive) {
401 match initial_output {
402 Level::High => pin.set_high(),
403 Level::Low => pin.set_low(),
404 }
405
406 let drive = match drive {
407 OutputDrive::Standard => DRIVE_A::S0S1,
408 OutputDrive::HighDrive0Standard1 => DRIVE_A::H0S1,
409 OutputDrive::Standard0HighDrive1 => DRIVE_A::S0H1,
410 OutputDrive::HighDrive => DRIVE_A::H0H1,
411 OutputDrive::Disconnect0Standard1 => DRIVE_A::D0S1,
412 OutputDrive::Disconnect0HighDrive1 => DRIVE_A::D0H1,
413 OutputDrive::Standard0Disconnect1 => DRIVE_A::S0D1,
414 OutputDrive::HighDrive0Disconnect1 => DRIVE_A::H0D1,
415 };
416
417 pin.conf().write(|w| {
418 w.dir().output();
419 w.input().disconnect();
420 w.pull().disabled();
421 w.drive().variant(drive);
422 w.sense().disabled();
423 w
424 });
425}
426
317// ==================== 427// ====================
318 428
319pub trait OptionalPin: sealed::OptionalPin + Sized { 429pub trait OptionalPin: sealed::OptionalPin + Sized {