aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDario Nieuwenhuis <[email protected]>2022-07-09 02:12:17 +0200
committerDario Nieuwenhuis <[email protected]>2022-07-09 02:14:30 +0200
commit5cc5961c94568db768c241e8e8bf91a692c1803e (patch)
treec2432690d02b18490d12e4a0a557e3d95325d96f
parentd2a622b3d0ed4dfd2932f9059a70dc82a64d761e (diff)
rp/gpio: add Flex.
-rw-r--r--embassy-rp/src/gpio.rs376
1 files changed, 272 insertions, 104 deletions
diff --git a/embassy-rp/src/gpio.rs b/embassy-rp/src/gpio.rs
index ae771e849..131330e79 100644
--- a/embassy-rp/src/gpio.rs
+++ b/embassy-rp/src/gpio.rs
@@ -30,156 +30,147 @@ pub enum Bank {
30} 30}
31 31
32pub struct Input<'d, T: Pin> { 32pub struct Input<'d, T: Pin> {
33 pin: T, 33 pin: Flex<'d, T>,
34 phantom: PhantomData<&'d mut T>,
35} 34}
36 35
37impl<'d, T: Pin> Input<'d, T> { 36impl<'d, T: Pin> Input<'d, T> {
38 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self { 37 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
39 unborrow!(pin); 38 let mut pin = Flex::new(pin);
40 39 pin.set_as_input();
41 unsafe { 40 pin.set_pull(pull);
42 pin.pad_ctrl().write(|w| { 41 Self { pin }
43 w.set_ie(true);
44 match pull {
45 Pull::Up => w.set_pue(true),
46 Pull::Down => w.set_pde(true),
47 Pull::None => {}
48 }
49 });
50
51 // disable output in SIO, to use it as input
52 pin.sio_oe().value_clr().write_value(1 << pin.pin());
53
54 pin.io().ctrl().write(|w| {
55 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0);
56 });
57 }
58
59 Self {
60 pin,
61 phantom: PhantomData,
62 }
63 } 42 }
64 43
65 pub fn is_high(&self) -> bool { 44 pub fn is_high(&self) -> bool {
66 !self.is_low() 45 self.pin.is_high()
67 } 46 }
68 47
69 pub fn is_low(&self) -> bool { 48 pub fn is_low(&self) -> bool {
70 let val = 1 << self.pin.pin(); 49 self.pin.is_low()
71 unsafe { self.pin.sio_in().read() & val == 0 }
72 }
73}
74
75impl<'d, T: Pin> Drop for Input<'d, T> {
76 fn drop(&mut self) {
77 // todo
78 } 50 }
79} 51}
80 52
81pub struct Output<'d, T: Pin> { 53pub struct Output<'d, T: Pin> {
82 pin: T, 54 pin: Flex<'d, T>,
83 phantom: PhantomData<&'d mut T>,
84} 55}
85 56
86impl<'d, T: Pin> Output<'d, T> { 57impl<'d, T: Pin> Output<'d, T> {
58 #[inline]
87 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level) -> Self { 59 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level) -> Self {
88 unborrow!(pin); 60 let mut pin = Flex::new(pin);
89 61 match initial_output {
90 unsafe { 62 Level::High => pin.set_high(),
91 match initial_output { 63 Level::Low => pin.set_low(),
92 Level::High => pin.sio_out().value_set().write_value(1 << pin.pin()),
93 Level::Low => pin.sio_out().value_clr().write_value(1 << pin.pin()),
94 }
95 pin.sio_oe().value_set().write_value(1 << pin.pin());
96
97 pin.io().ctrl().write(|w| {
98 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0);
99 });
100 } 64 }
101 65
102 Self { 66 pin.set_as_output();
103 pin, 67 Self { pin }
104 phantom: PhantomData,
105 }
106 } 68 }
107 69
108 /// Set the output as high. 70 /// Set the output as high.
71 #[inline]
109 pub fn set_high(&mut self) { 72 pub fn set_high(&mut self) {
110 let val = 1 << self.pin.pin(); 73 self.pin.set_high()
111 unsafe { self.pin.sio_out().value_set().write_value(val) };
112 } 74 }
113 75
114 /// Set the output as low. 76 /// Set the output as low.
77 #[inline]
115 pub fn set_low(&mut self) { 78 pub fn set_low(&mut self) {
116 let val = 1 << self.pin.pin(); 79 self.pin.set_low()
117 unsafe { self.pin.sio_out().value_clr().write_value(val) };
118 } 80 }
119 81
120 /// Is the output pin set as high? 82 /// Is the output pin set as high?
83 #[inline]
121 pub fn is_set_high(&self) -> bool { 84 pub fn is_set_high(&self) -> bool {
122 !self.is_set_low() 85 self.pin.is_set_high()
123 } 86 }
124 87
125 /// Is the output pin set as low? 88 /// Is the output pin set as low?
89 #[inline]
126 pub fn is_set_low(&self) -> bool { 90 pub fn is_set_low(&self) -> bool {
127 // Reading from SIO: GPIO_OUT gives the last value written. 91 self.pin.is_set_low()
128 let val = 1 << self.pin.pin();
129 unsafe { (self.pin.sio_out().value().read() & val) == 0 }
130 } 92 }
131 93
132 /// Toggle pin output 94 /// Toggle pin output
133 #[inline] 95 #[inline]
134 pub fn toggle(&mut self) { 96 pub fn toggle(&mut self) {
135 let val = 1 << self.pin.pin(); 97 self.pin.toggle()
136 unsafe {
137 self.pin.sio_out().value_xor().write_value(val);
138 }
139 } 98 }
140} 99}
141 100
142impl<'d, T: Pin> Drop for Output<'d, T> { 101/// GPIO output open-drain.
143 fn drop(&mut self) { 102pub struct OutputOpenDrain<'d, T: Pin> {
144 let val = 1 << self.pin.pin(); 103 pin: Flex<'d, T>,
145 unsafe { 104}
146 self.pin.sio_out().value_clr().write_value(val); 105
147 self.pin.sio_oe().value_clr().write_value(val); 106impl<'d, T: Pin> OutputOpenDrain<'d, T> {
148 self.pin.io().ctrl().write(|w| { 107 #[inline]
149 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::NULL.0); 108 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level) -> Self {
150 }); 109 let mut pin = Flex::new(pin);
151 }; 110 pin.set_low();
111 match initial_output {
112 Level::High => pin.set_as_input(),
113 Level::Low => pin.set_as_output(),
114 }
115 Self { pin }
116 }
117
118 /// Set the output as high.
119 #[inline]
120 pub fn set_high(&mut self) {
121 // For Open Drain High, disable the output pin.
122 self.pin.set_as_input()
123 }
124
125 /// Set the output as low.
126 #[inline]
127 pub fn set_low(&mut self) {
128 // For Open Drain Low, enable the output pin.
129 self.pin.set_as_output()
130 }
131
132 /// Is the output level high?
133 #[inline]
134 pub fn is_set_high(&self) -> bool {
135 !self.is_set_low()
136 }
137
138 /// Is the output level low?
139 #[inline]
140 pub fn is_set_low(&self) -> bool {
141 self.pin.is_set_as_output()
142 }
143
144 /// Toggle pin output
145 #[inline]
146 pub fn toggle(&mut self) {
147 self.pin.toggle_set_as_output()
152 } 148 }
153} 149}
154 150
155/// GPIO output open-drain. 151/// GPIO flexible pin.
156pub struct OutputOpenDrain<'d, T: Pin> { 152///
153/// This pin can be either an input or output pin. The output level register bit will remain
154/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
155/// mode.
156pub struct Flex<'d, T: Pin> {
157 pin: T, 157 pin: T,
158 phantom: PhantomData<&'d mut T>, 158 phantom: PhantomData<&'d mut T>,
159} 159}
160 160
161impl<'d, T: Pin> OutputOpenDrain<'d, T> { 161impl<'d, T: Pin> Flex<'d, T> {
162 #[inline] 162 #[inline]
163 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level) -> Self { 163 pub fn new(pin: impl Unborrow<Target = T> + 'd) -> Self {
164 unborrow!(pin); 164 unborrow!(pin);
165 165
166 unsafe { 166 unsafe {
167 let val = 1 << pin.pin(); 167 pin.pad_ctrl().write(|w| {
168 w.set_ie(true);
169 });
170
168 pin.io().ctrl().write(|w| { 171 pin.io().ctrl().write(|w| {
169 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0); 172 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::SIO_0.0);
170 }); 173 });
171 pin.sio_out().value_clr().write_value(val);
172
173 match initial_output {
174 Level::High => {
175 // For Open Drain High, disable the output pin.
176 pin.sio_oe().value_clr().write_value(val);
177 }
178 Level::Low => {
179 // For Open Drain Low, enable the output pin.
180 pin.sio_oe().value_set().write_value(val);
181 }
182 }
183 } 174 }
184 175
185 Self { 176 Self {
@@ -188,29 +179,79 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
188 } 179 }
189 } 180 }
190 181
191 /// Set the output as high.
192 #[inline] 182 #[inline]
193 pub fn set_high(&mut self) { 183 fn bit(&self) -> u32 {
194 // For Open Drain High, disable the output pin. 184 1 << self.pin.pin()
185 }
186
187 /// Set the pin's pull.
188 #[inline]
189 pub fn set_pull(&mut self, pull: Pull) {
195 unsafe { 190 unsafe {
196 self.pin.sio_oe().value_clr().write_value(1 << self.pin.pin()); 191 self.pin.pad_ctrl().write(|w| {
192 w.set_ie(true);
193 match pull {
194 Pull::Up => w.set_pue(true),
195 Pull::Down => w.set_pde(true),
196 Pull::None => {}
197 }
198 });
197 } 199 }
198 } 200 }
199 201
202 /// Put the pin into input mode.
203 ///
204 /// The pull setting is left unchanged.
205 #[inline]
206 pub fn set_as_input(&mut self) {
207 unsafe { self.pin.sio_oe().value_clr().write_value(self.bit()) }
208 }
209
210 /// Put the pin into output mode.
211 ///
212 /// The pin level will be whatever was set before (or low by default). If you want it to begin
213 /// at a specific level, call `set_high`/`set_low` on the pin first.
214 #[inline]
215 pub fn set_as_output(&mut self) {
216 unsafe { self.pin.sio_oe().value_set().write_value(self.bit()) }
217 }
218
219 #[inline]
220 fn is_set_as_output(&self) -> bool {
221 unsafe { (self.pin.sio_oe().value().read() & self.bit()) != 0 }
222 }
223
224 #[inline]
225 pub fn toggle_set_as_output(&mut self) {
226 unsafe { self.pin.sio_oe().value_xor().write_value(self.bit()) }
227 }
228
229 #[inline]
230 pub fn is_high(&self) -> bool {
231 !self.is_low()
232 }
233
234 #[inline]
235 pub fn is_low(&self) -> bool {
236 unsafe { self.pin.sio_in().read() & self.bit() == 0 }
237 }
238
239 /// Set the output as high.
240 #[inline]
241 pub fn set_high(&mut self) {
242 unsafe { self.pin.sio_out().value_set().write_value(self.bit()) }
243 }
244
200 /// Set the output as low. 245 /// Set the output as low.
201 #[inline] 246 #[inline]
202 pub fn set_low(&mut self) { 247 pub fn set_low(&mut self) {
203 // For Open Drain Low, enable the output pin. 248 unsafe { self.pin.sio_out().value_clr().write_value(self.bit()) }
204 unsafe {
205 self.pin.sio_oe().value_set().write_value(1 << self.pin.pin());
206 }
207 } 249 }
208 250
209 /// Is the output level high? 251 /// Is the output level high?
210 #[inline] 252 #[inline]
211 pub fn is_set_high(&self) -> bool { 253 pub fn is_set_high(&self) -> bool {
212 let val = 1 << self.pin.pin(); 254 unsafe { (self.pin.sio_out().value().read() & self.bit()) == 0 }
213 unsafe { (self.pin.sio_oe().value().read() & val) == 0 }
214 } 255 }
215 256
216 /// Is the output level low? 257 /// Is the output level low?
@@ -222,9 +263,18 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
222 /// Toggle pin output 263 /// Toggle pin output
223 #[inline] 264 #[inline]
224 pub fn toggle(&mut self) { 265 pub fn toggle(&mut self) {
225 let val = 1 << self.pin.pin(); 266 unsafe { self.pin.sio_out().value_xor().write_value(self.bit()) }
267 }
268}
269
270impl<'d, T: Pin> Drop for Flex<'d, T> {
271 #[inline]
272 fn drop(&mut self) {
226 unsafe { 273 unsafe {
227 self.pin.sio_out().value_xor().write_value(val); 274 self.pin.pad_ctrl().write(|_| {});
275 self.pin.io().ctrl().write(|w| {
276 w.set_funcsel(pac::io::vals::Gpio0CtrlFuncsel::NULL.0);
277 });
228 } 278 }
229 } 279 }
230} 280}
@@ -428,6 +478,48 @@ mod eh02 {
428 Ok(self.toggle()) 478 Ok(self.toggle())
429 } 479 }
430 } 480 }
481
482 impl<'d, T: Pin> embedded_hal_02::digital::v2::InputPin for Flex<'d, T> {
483 type Error = Infallible;
484
485 fn is_high(&self) -> Result<bool, Self::Error> {
486 Ok(self.is_high())
487 }
488
489 fn is_low(&self) -> Result<bool, Self::Error> {
490 Ok(self.is_low())
491 }
492 }
493
494 impl<'d, T: Pin> embedded_hal_02::digital::v2::OutputPin for Flex<'d, T> {
495 type Error = Infallible;
496
497 fn set_high(&mut self) -> Result<(), Self::Error> {
498 Ok(self.set_high())
499 }
500
501 fn set_low(&mut self) -> Result<(), Self::Error> {
502 Ok(self.set_low())
503 }
504 }
505
506 impl<'d, T: Pin> embedded_hal_02::digital::v2::StatefulOutputPin for Flex<'d, T> {
507 fn is_set_high(&self) -> Result<bool, Self::Error> {
508 Ok(self.is_set_high())
509 }
510
511 fn is_set_low(&self) -> Result<bool, Self::Error> {
512 Ok(self.is_set_low())
513 }
514 }
515
516 impl<'d, T: Pin> embedded_hal_02::digital::v2::ToggleableOutputPin for Flex<'d, T> {
517 type Error = Infallible;
518 #[inline]
519 fn toggle(&mut self) -> Result<(), Self::Error> {
520 Ok(self.toggle())
521 }
522 }
431} 523}
432 524
433#[cfg(feature = "unstable-traits")] 525#[cfg(feature = "unstable-traits")]
@@ -471,4 +563,80 @@ mod eh1 {
471 Ok(self.is_set_low()) 563 Ok(self.is_set_low())
472 } 564 }
473 } 565 }
566
567 impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for Output<'d, T> {
568 fn toggle(&mut self) -> Result<(), Self::Error> {
569 Ok(self.toggle())
570 }
571 }
572
573 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for OutputOpenDrain<'d, T> {
574 type Error = Infallible;
575 }
576
577 impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for OutputOpenDrain<'d, T> {
578 fn set_high(&mut self) -> Result<(), Self::Error> {
579 Ok(self.set_high())
580 }
581
582 fn set_low(&mut self) -> Result<(), Self::Error> {
583 Ok(self.set_low())
584 }
585 }
586
587 impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for OutputOpenDrain<'d, T> {
588 fn is_set_high(&self) -> Result<bool, Self::Error> {
589 Ok(self.is_set_high())
590 }
591
592 fn is_set_low(&self) -> Result<bool, Self::Error> {
593 Ok(self.is_set_low())
594 }
595 }
596
597 impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for OutputOpenDrain<'d, T> {
598 fn toggle(&mut self) -> Result<(), Self::Error> {
599 Ok(self.toggle())
600 }
601 }
602
603 impl<'d, T: Pin> embedded_hal_1::digital::ErrorType for Flex<'d, T> {
604 type Error = Infallible;
605 }
606
607 impl<'d, T: Pin> embedded_hal_1::digital::blocking::InputPin for Flex<'d, T> {
608 fn is_high(&self) -> Result<bool, Self::Error> {
609 Ok(self.is_high())
610 }
611
612 fn is_low(&self) -> Result<bool, Self::Error> {
613 Ok(self.is_low())
614 }
615 }
616
617 impl<'d, T: Pin> embedded_hal_1::digital::blocking::OutputPin for Flex<'d, T> {
618 fn set_high(&mut self) -> Result<(), Self::Error> {
619 Ok(self.set_high())
620 }
621
622 fn set_low(&mut self) -> Result<(), Self::Error> {
623 Ok(self.set_low())
624 }
625 }
626
627 impl<'d, T: Pin> embedded_hal_1::digital::blocking::StatefulOutputPin for Flex<'d, T> {
628 fn is_set_high(&self) -> Result<bool, Self::Error> {
629 Ok(self.is_set_high())
630 }
631
632 fn is_set_low(&self) -> Result<bool, Self::Error> {
633 Ok(self.is_set_low())
634 }
635 }
636
637 impl<'d, T: Pin> embedded_hal_1::digital::blocking::ToggleableOutputPin for Flex<'d, T> {
638 fn toggle(&mut self) -> Result<(), Self::Error> {
639 Ok(self.toggle())
640 }
641 }
474} 642}