aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-07-10 21:22:46 +0000
committerGitHub <[email protected]>2022-07-10 21:22:46 +0000
commit93e7d53e393a8f79be1c4a5c0e1fd8497305fc50 (patch)
tree11d9be878c0eb04e7b9b9e7deb766ca4489c8935
parent5f43c1d37e9db847c7861fe0bd821db62edba9f6 (diff)
parent323b0d1a5c430bfcec3288e229179a5b7c86038a (diff)
Merge #851
851: Gpio dynamic flex r=Dirbaio a=AntoineMugnier Add Flex GPIO type for embassy-stm32 as it is the case for embassy-nrf. Co-authored-by: [email protected] <[email protected]>
-rw-r--r--embassy-stm32/src/exti.rs10
-rw-r--r--embassy-stm32/src/gpio.rs491
-rw-r--r--tests/stm32/src/bin/gpio.rs106
3 files changed, 419 insertions, 188 deletions
diff --git a/embassy-stm32/src/exti.rs b/embassy-stm32/src/exti.rs
index 378665b77..94e0e941d 100644
--- a/embassy-stm32/src/exti.rs
+++ b/embassy-stm32/src/exti.rs
@@ -99,7 +99,7 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
99 } 99 }
100 100
101 pub async fn wait_for_high<'a>(&'a mut self) { 101 pub async fn wait_for_high<'a>(&'a mut self) {
102 let fut = ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, false); 102 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false);
103 if self.is_high() { 103 if self.is_high() {
104 return; 104 return;
105 } 105 }
@@ -107,7 +107,7 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
107 } 107 }
108 108
109 pub async fn wait_for_low<'a>(&'a mut self) { 109 pub async fn wait_for_low<'a>(&'a mut self) {
110 let fut = ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), false, true); 110 let fut = ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true);
111 if self.is_low() { 111 if self.is_low() {
112 return; 112 return;
113 } 113 }
@@ -115,15 +115,15 @@ impl<'d, T: GpioPin> ExtiInput<'d, T> {
115 } 115 }
116 116
117 pub async fn wait_for_rising_edge<'a>(&'a mut self) { 117 pub async fn wait_for_rising_edge<'a>(&'a mut self) {
118 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, false).await 118 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, false).await
119 } 119 }
120 120
121 pub async fn wait_for_falling_edge<'a>(&'a mut self) { 121 pub async fn wait_for_falling_edge<'a>(&'a mut self) {
122 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), false, true).await 122 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), false, true).await
123 } 123 }
124 124
125 pub async fn wait_for_any_edge<'a>(&'a mut self) { 125 pub async fn wait_for_any_edge<'a>(&'a mut self) {
126 ExtiInputFuture::new(self.pin.pin.pin(), self.pin.pin.port(), true, true).await 126 ExtiInputFuture::new(self.pin.pin.pin.pin(), self.pin.pin.pin.port(), true, true).await
127 } 127 }
128} 128}
129 129
diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs
index 6e445f8cd..806b5eb68 100644
--- a/embassy-stm32/src/gpio.rs
+++ b/embassy-stm32/src/gpio.rs
@@ -7,6 +7,197 @@ use embassy_hal_common::{unborrow, unsafe_impl_unborrow};
7use crate::pac::gpio::{self, vals}; 7use crate::pac::gpio::{self, vals};
8use crate::{pac, peripherals, Unborrow}; 8use crate::{pac, peripherals, Unborrow};
9 9
10/// GPIO flexible pin.
11///
12/// This pin can either be a disconnected, input, or output pin, or both. The level register bit will remain
13/// set while not in output mode, so the pin's level will be 'remembered' when it is not in output
14/// mode.
15pub struct Flex<'d, T: Pin> {
16 pub(crate) pin: T,
17 phantom: PhantomData<&'d mut T>,
18}
19
20impl<'d, T: Pin> Flex<'d, T> {
21 /// Wrap the pin in a `Flex`.
22 ///
23 /// The pin remains disconnected. The initial output level is unspecified, but can be changed
24 /// before the pin is put into output mode.
25 ///
26 #[inline]
27 pub fn new(pin: impl Unborrow<Target = T> + 'd) -> Self {
28 unborrow!(pin);
29 // Pin will be in disconnected state.
30 Self {
31 pin,
32 phantom: PhantomData,
33 }
34 }
35
36 /// Put the pin into input mode.
37 #[inline]
38 pub fn set_as_input(&mut self, pull: Pull) {
39 critical_section::with(|_| unsafe {
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 let crlh = if n < 8 { 0 } else { 1 };
57 r.cr(crlh).modify(|w| {
58 w.set_mode(n % 8, vals::Mode::INPUT);
59 w.set_cnf_in(n % 8, cnf);
60 });
61 }
62 #[cfg(gpio_v2)]
63 {
64 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
65 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL));
66 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
67 }
68 });
69 }
70
71 /// Put the pin into output mode.
72 ///
73 /// The pin level will be whatever was set before (or low by default). If you want it to begin
74 /// at a specific level, call `set_high`/`set_low` on the pin first.
75 #[inline]
76 pub fn set_as_output(&mut self, speed: Speed) {
77 critical_section::with(|_| unsafe {
78 let r = self.pin.block();
79 let n = self.pin.pin() as usize;
80 #[cfg(gpio_v1)]
81 {
82 let crlh = if n < 8 { 0 } else { 1 };
83 r.cr(crlh).modify(|w| {
84 w.set_mode(n % 8, speed.into());
85 w.set_cnf_out(n % 8, vals::CnfOut::PUSHPULL);
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::PUSHPULL));
92 self.pin.set_speed(speed);
93 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
94 }
95 });
96 }
97
98 /// Put the pin into input + output mode.
99 ///
100 /// This is commonly used for "open drain" mode.
101 /// the hardware will drive the line low if you set it to low, and will leave it floating if you set
102 /// it to high, in which case you can read the input to figure out whether another device
103 /// is driving the line low.
104 ///
105 /// The pin level will be whatever was set before (or low by default). If you want it to begin
106 /// at a specific level, call `set_high`/`set_low` on the pin first.
107 #[inline]
108 pub fn set_as_input_output(&mut self, speed: Speed, pull: Pull) {
109 critical_section::with(|_| unsafe {
110 let r = self.pin.block();
111 let n = self.pin.pin() as usize;
112 #[cfg(gpio_v1)]
113 {
114 let crlh = if n < 8 { 0 } else { 1 };
115 match pull {
116 Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)),
117 Pull::Down => r.bsrr().write(|w| w.set_br(n, true)),
118 Pull::None => {}
119 }
120 r.cr(crlh).modify(|w| w.set_mode(n % 8, speed.into()));
121 r.cr(crlh).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPENDRAIN));
122 }
123 #[cfg(gpio_v2)]
124 {
125 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
126 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN));
127 self.pin.set_speed(speed);
128 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
129 }
130 });
131 }
132
133 #[inline]
134 pub fn is_high(&self) -> bool {
135 !self.is_low()
136 }
137
138 #[inline]
139 pub fn is_low(&self) -> bool {
140 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) };
141 state == vals::Idr::LOW
142 }
143
144 #[inline]
145 pub fn is_set_high(&self) -> bool {
146 !self.is_set_low()
147 }
148
149 /// Is the output pin set as low?
150 #[inline]
151 pub fn is_set_low(&self) -> bool {
152 let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) };
153 state == vals::Odr::LOW
154 }
155
156 #[inline]
157 pub fn set_high(&mut self) {
158 self.pin.set_high();
159 }
160
161 /// Set the output as low.
162 #[inline]
163 pub fn set_low(&mut self) {
164 self.pin.set_low();
165 }
166
167 /// Toggle pin output
168 #[inline]
169 pub fn toggle(&mut self) {
170 if self.is_set_low() {
171 self.set_high()
172 } else {
173 self.set_low()
174 }
175 }
176}
177
178impl<'d, T: Pin> Drop for Flex<'d, T> {
179 #[inline]
180 fn drop(&mut self) {
181 critical_section::with(|_| unsafe {
182 let r = self.pin.block();
183 let n = self.pin.pin() as usize;
184 #[cfg(gpio_v1)]
185 {
186 let crlh = if n < 8 { 0 } else { 1 };
187 r.cr(crlh).modify(|w| {
188 w.set_mode(n % 8, vals::Mode::INPUT);
189 w.set_cnf_in(n % 8, vals::CnfIn::FLOATING);
190 });
191 }
192 #[cfg(gpio_v2)]
193 {
194 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
195 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
196 }
197 });
198 }
199}
200
10/// Pull setting for an input. 201/// Pull setting for an input.
11#[derive(Debug, Eq, PartialEq)] 202#[derive(Debug, Eq, PartialEq)]
12#[cfg_attr(feature = "defmt", derive(defmt::Format))] 203#[cfg_attr(feature = "defmt", derive(defmt::Format))]
@@ -70,78 +261,25 @@ impl From<Speed> for vals::Ospeedr {
70 261
71/// GPIO input driver. 262/// GPIO input driver.
72pub struct Input<'d, T: Pin> { 263pub struct Input<'d, T: Pin> {
73 pub(crate) pin: T, 264 pub(crate) pin: Flex<'d, T>,
74 phantom: PhantomData<&'d mut T>,
75} 265}
76 266
77impl<'d, T: Pin> Input<'d, T> { 267impl<'d, T: Pin> Input<'d, T> {
78 #[inline] 268 #[inline]
79 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self { 269 pub fn new(pin: impl Unborrow<Target = T> + 'd, pull: Pull) -> Self {
80 unborrow!(pin); 270 let mut pin = Flex::new(pin);
81 271 pin.set_as_input(pull);
82 critical_section::with(|_| unsafe { 272 Self { pin }
83 let r = pin.block();
84 let n = pin.pin() as usize;
85 #[cfg(gpio_v1)]
86 {
87 let cnf = match pull {
88 Pull::Up => {
89 r.bsrr().write(|w| w.set_bs(n, true));
90 vals::CnfIn::PULL
91 }
92 Pull::Down => {
93 r.bsrr().write(|w| w.set_br(n, true));
94 vals::CnfIn::PULL
95 }
96 Pull::None => vals::CnfIn::FLOATING,
97 };
98
99 let crlh = if n < 8 { 0 } else { 1 };
100 r.cr(crlh).modify(|w| {
101 w.set_mode(n % 8, vals::Mode::INPUT);
102 w.set_cnf_in(n % 8, cnf);
103 });
104 }
105 #[cfg(gpio_v2)]
106 {
107 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
108 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL));
109 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
110 }
111 });
112
113 Self {
114 pin,
115 phantom: PhantomData,
116 }
117 } 273 }
118 274
119 #[inline] 275 #[inline]
120 pub fn is_high(&self) -> bool { 276 pub fn is_high(&self) -> bool {
121 !self.is_low() 277 self.pin.is_high()
122 } 278 }
123 279
124 #[inline] 280 #[inline]
125 pub fn is_low(&self) -> bool { 281 pub fn is_low(&self) -> bool {
126 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; 282 self.pin.is_low()
127 state == vals::Idr::LOW
128 }
129}
130
131impl<'d, T: Pin> Drop for Input<'d, T> {
132 #[inline]
133 fn drop(&mut self) {
134 critical_section::with(|_| unsafe {
135 let r = self.pin.block();
136 let n = self.pin.pin() as usize;
137 #[cfg(gpio_v1)]
138 {
139 let crlh = if n < 8 { 0 } else { 1 };
140 r.cr(crlh).modify(|w| w.set_cnf_in(n % 8, vals::CnfIn::FLOATING));
141 }
142 #[cfg(gpio_v2)]
143 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
144 });
145 } 283 }
146} 284}
147 285
@@ -155,44 +293,19 @@ pub enum Level {
155 293
156/// GPIO output driver. 294/// GPIO output driver.
157pub struct Output<'d, T: Pin> { 295pub struct Output<'d, T: Pin> {
158 pub(crate) pin: T, 296 pub(crate) pin: Flex<'d, T>,
159 phantom: PhantomData<&'d mut T>,
160} 297}
161 298
162impl<'d, T: Pin> Output<'d, T> { 299impl<'d, T: Pin> Output<'d, T> {
163 #[inline] 300 #[inline]
164 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level, speed: Speed) -> Self { 301 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level, speed: Speed) -> Self {
165 unborrow!(pin); 302 let mut pin = Flex::new(pin);
166
167 match initial_output { 303 match initial_output {
168 Level::High => pin.set_high(), 304 Level::High => pin.set_high(),
169 Level::Low => pin.set_low(), 305 Level::Low => pin.set_low(),
170 } 306 }
171 307 pin.set_as_output(speed);
172 critical_section::with(|_| unsafe { 308 Self { pin }
173 let r = pin.block();
174 let n = pin.pin() as usize;
175 #[cfg(gpio_v1)]
176 {
177 let crlh = if n < 8 { 0 } else { 1 };
178 r.cr(crlh).modify(|w| {
179 w.set_mode(n % 8, speed.into());
180 w.set_cnf_out(n % 8, vals::CnfOut::PUSHPULL);
181 });
182 }
183 #[cfg(gpio_v2)]
184 {
185 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
186 r.otyper().modify(|w| w.set_ot(n, vals::Ot::PUSHPULL));
187 pin.set_speed(speed);
188 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
189 }
190 });
191
192 Self {
193 pin,
194 phantom: PhantomData,
195 }
196 } 309 }
197 310
198 /// Set the output as high. 311 /// Set the output as high.
@@ -210,104 +323,49 @@ impl<'d, T: Pin> Output<'d, T> {
210 /// Is the output pin set as high? 323 /// Is the output pin set as high?
211 #[inline] 324 #[inline]
212 pub fn is_set_high(&self) -> bool { 325 pub fn is_set_high(&self) -> bool {
213 !self.is_set_low() 326 self.pin.is_set_high()
214 } 327 }
215 328
216 /// Is the output pin set as low? 329 /// Is the output pin set as low?
217 #[inline] 330 #[inline]
218 pub fn is_set_low(&self) -> bool { 331 pub fn is_set_low(&self) -> bool {
219 let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; 332 self.pin.is_set_low()
220 state == vals::Odr::LOW
221 } 333 }
222 334
223 /// Toggle pin output 335 /// Toggle pin output
224 #[inline] 336 #[inline]
225 pub fn toggle(&mut self) { 337 pub fn toggle(&mut self) {
226 if self.is_set_low() { 338 self.pin.toggle();
227 self.set_high()
228 } else {
229 self.set_low()
230 }
231 }
232}
233
234impl<'d, T: Pin> Drop for Output<'d, T> {
235 #[inline]
236 fn drop(&mut self) {
237 critical_section::with(|_| unsafe {
238 let r = self.pin.block();
239 let n = self.pin.pin() as usize;
240 #[cfg(gpio_v1)]
241 {
242 let crlh = if n < 8 { 0 } else { 1 };
243 r.cr(crlh).modify(|w| {
244 w.set_mode(n % 8, vals::Mode::INPUT);
245 w.set_cnf_in(n % 8, vals::CnfIn::FLOATING);
246 });
247 }
248 #[cfg(gpio_v2)]
249 {
250 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
251 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
252 }
253 });
254 } 339 }
255} 340}
256 341
257/// GPIO output open-drain driver. 342/// GPIO output open-drain driver.
258pub struct OutputOpenDrain<'d, T: Pin> { 343pub struct OutputOpenDrain<'d, T: Pin> {
259 pub(crate) pin: T, 344 pub(crate) pin: Flex<'d, T>,
260 phantom: PhantomData<&'d mut T>,
261} 345}
262 346
263impl<'d, T: Pin> OutputOpenDrain<'d, T> { 347impl<'d, T: Pin> OutputOpenDrain<'d, T> {
264 #[inline] 348 #[inline]
265 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self { 349 pub fn new(pin: impl Unborrow<Target = T> + 'd, initial_output: Level, speed: Speed, pull: Pull) -> Self {
266 unborrow!(pin); 350 let mut pin = Flex::new(pin);
267 351
268 match initial_output { 352 match initial_output {
269 Level::High => pin.set_high(), 353 Level::High => pin.set_high(),
270 Level::Low => pin.set_low(), 354 Level::Low => pin.set_low(),
271 } 355 }
272 356
273 critical_section::with(|_| unsafe { 357 pin.set_as_input_output(speed, pull);
274 let r = pin.block(); 358 Self { pin }
275 let n = pin.pin() as usize;
276 #[cfg(gpio_v1)]
277 {
278 let crlh = if n < 8 { 0 } else { 1 };
279 match pull {
280 Pull::Up => r.bsrr().write(|w| w.set_bs(n, true)),
281 Pull::Down => r.bsrr().write(|w| w.set_br(n, true)),
282 Pull::None => {}
283 }
284 r.cr(crlh).modify(|w| w.set_mode(n % 8, speed.into()));
285 r.cr(crlh).modify(|w| w.set_cnf_out(n % 8, vals::CnfOut::OPENDRAIN));
286 }
287 #[cfg(gpio_v2)]
288 {
289 r.pupdr().modify(|w| w.set_pupdr(n, pull.into()));
290 r.otyper().modify(|w| w.set_ot(n, vals::Ot::OPENDRAIN));
291 pin.set_speed(speed);
292 r.moder().modify(|w| w.set_moder(n, vals::Moder::OUTPUT));
293 }
294 });
295
296 Self {
297 pin,
298 phantom: PhantomData,
299 }
300 } 359 }
301 360
302 #[inline] 361 #[inline]
303 pub fn is_high(&self) -> bool { 362 pub fn is_high(&self) -> bool {
304 !self.is_low() 363 !self.pin.is_low()
305 } 364 }
306 365
307 #[inline] 366 #[inline]
308 pub fn is_low(&self) -> bool { 367 pub fn is_low(&self) -> bool {
309 let state = unsafe { self.pin.block().idr().read().idr(self.pin.pin() as _) }; 368 self.pin.is_low()
310 state == vals::Idr::LOW
311 } 369 }
312 370
313 /// Set the output as high. 371 /// Set the output as high.
@@ -331,41 +389,13 @@ impl<'d, T: Pin> OutputOpenDrain<'d, T> {
331 /// Is the output pin set as low? 389 /// Is the output pin set as low?
332 #[inline] 390 #[inline]
333 pub fn is_set_low(&self) -> bool { 391 pub fn is_set_low(&self) -> bool {
334 let state = unsafe { self.pin.block().odr().read().odr(self.pin.pin() as _) }; 392 self.pin.is_set_low()
335 state == vals::Odr::LOW
336 } 393 }
337 394
338 /// Toggle pin output 395 /// Toggle pin output
339 #[inline] 396 #[inline]
340 pub fn toggle(&mut self) { 397 pub fn toggle(&mut self) {
341 if self.is_set_low() { 398 self.pin.toggle()
342 self.set_high()
343 } else {
344 self.set_low()
345 }
346 }
347}
348
349impl<'d, T: Pin> Drop for OutputOpenDrain<'d, T> {
350 #[inline]
351 fn drop(&mut self) {
352 critical_section::with(|_| unsafe {
353 let r = self.pin.block();
354 let n = self.pin.pin() as usize;
355 #[cfg(gpio_v1)]
356 {
357 let crlh = if n < 8 { 0 } else { 1 };
358 r.cr(crlh).modify(|w| {
359 w.set_mode(n % 8, vals::Mode::INPUT);
360 w.set_cnf_in(n % 8, vals::CnfIn::FLOATING);
361 });
362 }
363 #[cfg(gpio_v2)]
364 {
365 r.pupdr().modify(|w| w.set_pupdr(n, vals::Pupdr::FLOATING));
366 r.moder().modify(|w| w.set_moder(n, vals::Moder::INPUT));
367 }
368 });
369 } 399 }
370} 400}
371 401
@@ -692,6 +722,55 @@ mod eh02 {
692 Ok(self.toggle()) 722 Ok(self.toggle())
693 } 723 }
694 } 724 }
725
726 impl<'d, T: Pin> InputPin for Flex<'d, T> {
727 type Error = Infallible;
728
729 #[inline]
730 fn is_high(&self) -> Result<bool, Self::Error> {
731 Ok(self.is_high())
732 }
733
734 #[inline]
735 fn is_low(&self) -> Result<bool, Self::Error> {
736 Ok(self.is_low())
737 }
738 }
739
740 impl<'d, T: Pin> OutputPin for Flex<'d, T> {
741 type Error = Infallible;
742
743 #[inline]
744 fn set_high(&mut self) -> Result<(), Self::Error> {
745 Ok(self.set_high())
746 }
747
748 #[inline]
749 fn set_low(&mut self) -> Result<(), Self::Error> {
750 Ok(self.set_low())
751 }
752 }
753
754 impl<'d, T: Pin> StatefulOutputPin for Flex<'d, T> {
755 #[inline]
756 fn is_set_high(&self) -> Result<bool, Self::Error> {
757 Ok(self.is_set_high())
758 }
759
760 /// Is the output pin set as low?
761 #[inline]
762 fn is_set_low(&self) -> Result<bool, Self::Error> {
763 Ok(self.is_set_low())
764 }
765 }
766
767 impl<'d, T: Pin> ToggleableOutputPin for Flex<'d, T> {
768 type Error = Infallible;
769 #[inline]
770 fn toggle(&mut self) -> Result<(), Self::Error> {
771 Ok(self.toggle())
772 }
773 }
695} 774}
696 775
697#[cfg(feature = "unstable-traits")] 776#[cfg(feature = "unstable-traits")]
@@ -788,6 +867,54 @@ mod eh1 {
788 Ok(self.toggle()) 867 Ok(self.toggle())
789 } 868 }
790 } 869 }
870
871 impl<'d, T: Pin> InputPin for Flex<'d, T> {
872 #[inline]
873 fn is_high(&self) -> Result<bool, Self::Error> {
874 Ok(self.is_high())
875 }
876
877 #[inline]
878 fn is_low(&self) -> Result<bool, Self::Error> {
879 Ok(self.is_low())
880 }
881 }
882
883 impl<'d, T: Pin> OutputPin for Flex<'d, T> {
884 #[inline]
885 fn set_high(&mut self) -> Result<(), Self::Error> {
886 Ok(self.set_high())
887 }
888
889 #[inline]
890 fn set_low(&mut self) -> Result<(), Self::Error> {
891 Ok(self.set_low())
892 }
893 }
894
895 impl<'d, T: Pin> ToggleableOutputPin for Flex<'d, T> {
896 #[inline]
897 fn toggle(&mut self) -> Result<(), Self::Error> {
898 Ok(self.toggle())
899 }
900 }
901
902 impl<'d, T: Pin> ErrorType for Flex<'d, T> {
903 type Error = Infallible;
904 }
905
906 impl<'d, T: Pin> StatefulOutputPin for Flex<'d, T> {
907 #[inline]
908 fn is_set_high(&self) -> Result<bool, Self::Error> {
909 Ok(self.is_set_high())
910 }
911
912 /// Is the output pin set as low?
913 #[inline]
914 fn is_set_low(&self) -> Result<bool, Self::Error> {
915 Ok(self.is_set_low())
916 }
917 }
791} 918}
792 919
793#[cfg(feature = "unstable-pac")] 920#[cfg(feature = "unstable-pac")]
diff --git a/tests/stm32/src/bin/gpio.rs b/tests/stm32/src/bin/gpio.rs
index c7991953f..37cfe7cf4 100644
--- a/tests/stm32/src/bin/gpio.rs
+++ b/tests/stm32/src/bin/gpio.rs
@@ -6,7 +6,7 @@
6mod example_common; 6mod example_common;
7use defmt::assert; 7use defmt::assert;
8use embassy::executor::Spawner; 8use embassy::executor::Spawner;
9use embassy_stm32::gpio::{Input, Level, Output, Pull, Speed}; 9use embassy_stm32::gpio::{Flex, Input, Level, Output, OutputOpenDrain, Pull, Speed};
10use embassy_stm32::Peripherals; 10use embassy_stm32::Peripherals;
11use example_common::*; 11use example_common::*;
12 12
@@ -88,6 +88,110 @@ async fn main(_spawner: Spawner, p: Peripherals) {
88 assert!(b.is_high()); 88 assert!(b.is_high());
89 } 89 }
90 90
91 // Test output open drain
92 {
93 let b = Input::new(&mut b, Pull::Down);
94 // no pull, the status is undefined
95
96 let mut a = OutputOpenDrain::new(&mut a, Level::Low, Speed::Low, Pull::None);
97 delay();
98 assert!(b.is_low());
99 a.set_high(); // High-Z output
100 delay();
101 assert!(b.is_low());
102 }
103
104 // FLEX
105 // Test initial output
106 {
107 //Flex pin configured as input
108 let mut b = Flex::new(&mut b);
109 b.set_as_input(Pull::None);
110
111 {
112 //Flex pin configured as output
113 let mut a = Flex::new(&mut a); //Flex pin configured as output
114 a.set_low(); // Pin state must be set before configuring the pin, thus we avoid unknown state
115 a.set_as_output(Speed::Low);
116 delay();
117 assert!(b.is_low());
118 }
119 {
120 //Flex pin configured as output
121 let mut a = Flex::new(&mut a);
122 a.set_high();
123 a.set_as_output(Speed::Low);
124
125 delay();
126 assert!(b.is_high());
127 }
128 }
129
130 // Test input no pull
131 {
132 let mut b = Flex::new(&mut b);
133 b.set_as_input(Pull::None); // no pull, the status is undefined
134
135 let mut a = Flex::new(&mut a);
136 a.set_low();
137 a.set_as_output(Speed::Low);
138
139 delay();
140 assert!(b.is_low());
141 a.set_high();
142 delay();
143 assert!(b.is_high());
144 }
145
146 // Test input pulldown
147 {
148 let mut b = Flex::new(&mut b);
149 b.set_as_input(Pull::Down);
150 delay();
151 assert!(b.is_low());
152
153 let mut a = Flex::new(&mut a);
154 a.set_low();
155 a.set_as_output(Speed::Low);
156 delay();
157 assert!(b.is_low());
158 a.set_high();
159 delay();
160 assert!(b.is_high());
161 }
162
163 // Test input pullup
164 {
165 let mut b = Flex::new(&mut b);
166 b.set_as_input(Pull::Up);
167 delay();
168 assert!(b.is_high());
169
170 let mut a = Flex::new(&mut a);
171 a.set_high();
172 a.set_as_output(Speed::Low);
173 delay();
174 assert!(b.is_high());
175 a.set_low();
176 delay();
177 assert!(b.is_low());
178 }
179
180 // Test output open drain
181 {
182 let mut b = Flex::new(&mut b);
183 b.set_as_input(Pull::Down);
184
185 let mut a = Flex::new(&mut a);
186 a.set_low();
187 a.set_as_input_output(Speed::Low, Pull::None);
188 delay();
189 assert!(b.is_low());
190 a.set_high(); // High-Z output
191 delay();
192 assert!(b.is_low());
193 }
194
91 info!("Test OK"); 195 info!("Test OK");
92 cortex_m::asm::bkpt(); 196 cortex_m::asm::bkpt();
93} 197}