Skip to content

Commit 2c91060

Browse files
Move pin modes to a trait
1 parent e086879 commit 2c91060

File tree

3 files changed

+104
-77
lines changed

3 files changed

+104
-77
lines changed

src/gpio.rs

Lines changed: 100 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,63 @@ pub struct Output<MODE> {
4141
/// Push pull output (type state)
4242
pub struct PushPull;
4343

44+
mod sealed {
45+
pub trait Sealed {}
46+
}
47+
48+
/// Marker trait for valid pin modes (type state).
49+
///
50+
/// It can not be implemented by outside types.
51+
pub trait PinMode: sealed::Sealed {
52+
// These constants are used to implement the pin configuration code.
53+
// They are not part of public API.
54+
55+
#[doc(hidden)]
56+
const PUPDR: u8;
57+
#[doc(hidden)]
58+
const MODER: u8;
59+
#[doc(hidden)]
60+
const OTYPER: Option<u8> = None;
61+
}
62+
63+
impl sealed::Sealed for Input<Floating> {}
64+
impl PinMode for Input<Floating> {
65+
const PUPDR: u8 = 0b00;
66+
const MODER: u8 = 0b00;
67+
}
68+
69+
impl sealed::Sealed for Input<PullDown> {}
70+
impl PinMode for Input<PullDown> {
71+
const PUPDR: u8 = 0b10;
72+
const MODER: u8 = 0b00;
73+
}
74+
75+
impl sealed::Sealed for Input<PullUp> {}
76+
impl PinMode for Input<PullUp> {
77+
const PUPDR: u8 = 0b01;
78+
const MODER: u8 = 0b00;
79+
}
80+
81+
impl sealed::Sealed for Analog {}
82+
impl PinMode for Analog {
83+
const PUPDR: u8 = 0b00;
84+
const MODER: u8 = 0b11;
85+
}
86+
87+
impl sealed::Sealed for Output<OpenDrain> {}
88+
impl PinMode for Output<OpenDrain> {
89+
const PUPDR: u8 = 0b00;
90+
const MODER: u8 = 0b01;
91+
const OTYPER: Option<u8> = Some(0b1);
92+
}
93+
94+
impl sealed::Sealed for Output<PushPull> {}
95+
impl PinMode for Output<PushPull> {
96+
const PUPDR: u8 = 0b00;
97+
const MODER: u8 = 0b01;
98+
const OTYPER: Option<u8> = Some(0b0);
99+
}
100+
44101
/// GPIO Pin speed selection
45102
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
46103
pub enum Speed {
@@ -85,7 +142,8 @@ macro_rules! gpio {
85142
use crate::rcc::Rcc;
86143
use super::{
87144
Floating, GpioExt, Input, OpenDrain, Output, Speed,
88-
PullDown, PullUp, PushPull, AltMode, Analog, Port
145+
PullDown, PullUp, PushPull, AltMode, Analog, Port,
146+
PinMode,
89147
};
90148

91149
/// GPIO parts
@@ -218,122 +276,91 @@ macro_rules! gpio {
218276
}
219277
}
220278

221-
impl<MODE> $PXi<MODE> {
222-
/// Configures the pin to operate as a floating input pin
223-
pub fn into_floating_input(
224-
self,
225-
) -> $PXi<Input<Floating>> {
279+
impl<MODE: PinMode> $PXi<MODE> {
280+
/// Puts `self` into mode `M`.
281+
///
282+
/// This violates the type state constraints from `MODE`, so callers must
283+
/// ensure they use this properly.
284+
fn mode<M: PinMode>(&mut self) {
226285
let offset = 2 * $i;
227286
unsafe {
228287
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
229-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
288+
w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::PUPDR) << offset))
230289
});
290+
291+
if let Some(otyper) = M::OTYPER {
292+
&(*$GPIOX::ptr()).otyper.modify(|r, w| {
293+
w.bits(r.bits() & !(0b1 << $i) | (u32::from(otyper) << $i))
294+
});
295+
}
296+
231297
&(*$GPIOX::ptr()).moder.modify(|r, w| {
232-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
233-
})
234-
};
298+
w.bits((r.bits() & !(0b11 << offset)) | (u32::from(M::MODER) << offset))
299+
});
300+
}
301+
}
302+
303+
/// Configures the pin to operate as a floating input pin.
304+
pub fn into_floating_input(
305+
mut self,
306+
) -> $PXi<Input<Floating>> {
307+
self.mode::<Input<Floating>>();
235308
$PXi {
236309
_mode: PhantomData
237310
}
238311
}
239312

240-
/// Configures the pin to operate as a pulled down input pin
313+
/// Configures the pin to operate as a pulled down input pin.
241314
pub fn into_pull_down_input(
242-
self,
243-
) -> $PXi<Input<PullDown>> {
244-
let offset = 2 * $i;
245-
unsafe {
246-
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
247-
w.bits((r.bits() & !(0b11 << offset)) | (0b10 << offset))
248-
});
249-
&(*$GPIOX::ptr()).moder.modify(|r, w| {
250-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
251-
})
252-
};
315+
mut self,
316+
) -> $PXi<Input<PullDown>> {
317+
self.mode::<Input<Floating>>();
253318
$PXi {
254319
_mode: PhantomData
255320
}
256321
}
257322

258-
/// Configures the pin to operate as a pulled up input pin
323+
/// Configures the pin to operate as a pulled up input pin.
259324
pub fn into_pull_up_input(
260-
self,
325+
mut self,
261326
) -> $PXi<Input<PullUp>> {
262-
let offset = 2 * $i;
263-
unsafe {
264-
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
265-
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
266-
});
267-
&(*$GPIOX::ptr()).moder.modify(|r, w| {
268-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
269-
})
270-
};
327+
self.mode::<Input<PullUp>>();
271328
$PXi {
272329
_mode: PhantomData
273330
}
274331
}
275332

276-
/// Configures the pin to operate as an analog pin
333+
/// Configures the pin to operate as an analog pin.
277334
pub fn into_analog(
278-
self,
335+
mut self,
279336
) -> $PXi<Analog> {
280-
let offset = 2 * $i;
281-
unsafe {
282-
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
283-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
284-
});
285-
&(*$GPIOX::ptr()).moder.modify(|r, w| {
286-
w.bits((r.bits() & !(0b11 << offset)) | (0b11 << offset))
287-
});
288-
}
337+
self.mode::<Analog>();
289338
$PXi {
290339
_mode: PhantomData
291340
}
292341
}
293342

294-
/// Configures the pin to operate as an open drain output pin
343+
/// Configures the pin to operate as an open drain output pin.
295344
pub fn into_open_drain_output(
296-
self,
345+
mut self,
297346
) -> $PXi<Output<OpenDrain>> {
298-
let offset = 2 * $i;
299-
unsafe {
300-
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
301-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
302-
});
303-
&(*$GPIOX::ptr()).otyper.modify(|r, w| {
304-
w.bits(r.bits() | (0b1 << $i))
305-
});
306-
&(*$GPIOX::ptr()).moder.modify(|r, w| {
307-
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
308-
})
309-
};
347+
self.mode::<Output<OpenDrain>>();
310348
$PXi {
311349
_mode: PhantomData
312350
}
313351
}
314352

315-
/// Configures the pin to operate as an push pull output pin
353+
/// Configures the pin to operate as an push pull output pin.
316354
pub fn into_push_pull_output(
317-
self,
355+
mut self,
318356
) -> $PXi<Output<PushPull>> {
319-
let offset = 2 * $i;
320-
unsafe {
321-
&(*$GPIOX::ptr()).pupdr.modify(|r, w| {
322-
w.bits((r.bits() & !(0b11 << offset)) | (0b00 << offset))
323-
});
324-
&(*$GPIOX::ptr()).otyper.modify(|r, w| {
325-
w.bits(r.bits() & !(0b1 << $i))
326-
});
327-
&(*$GPIOX::ptr()).moder.modify(|r, w| {
328-
w.bits((r.bits() & !(0b11 << offset)) | (0b01 << offset))
329-
})
330-
};
357+
self.mode::<Output<PushPull>>();
331358
$PXi {
332359
_mode: PhantomData
333360
}
334361
}
335362

336-
/// Set pin speed
363+
/// Set pin speed.
337364
pub fn set_speed(self, speed: Speed) -> Self {
338365
let offset = 2 * $i;
339366
unsafe {

src/pwm.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use core::ops::Deref;
44
use cortex_m::interrupt;
55

66
use crate::gpio::gpioa::{PA0, PA1, PA2, PA3};
7-
use crate::gpio::AltMode;
7+
use crate::gpio::{AltMode, PinMode};
88
use crate::hal;
99
use crate::pac::{tim2, TIM2, TIM3};
1010
use crate::rcc::Rcc;
@@ -251,7 +251,7 @@ macro_rules! impl_pin {
251251
) => {
252252
$(
253253
$(
254-
impl<State> Pin<$instance, $channel> for $name<State> {
254+
impl<State: PinMode> Pin<$instance, $channel> for $name<State> {
255255
fn setup(&self) {
256256
self.set_alt_mode(AltMode::$alternate_function);
257257
}

src/serial.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use core::marker::PhantomData;
33
use core::ptr;
44

55
use crate::gpio::gpioa::*;
6-
use crate::gpio::AltMode;
6+
use crate::gpio::{PinMode, AltMode};
77
use crate::hal;
88
use crate::hal::prelude::*;
99
pub use crate::pac::USART2;
@@ -159,7 +159,7 @@ pub trait Pins<USART> {
159159
macro_rules! impl_pins {
160160
($($instance:ty, $tx:ident, $rx:ident, $alt:ident;)*) => {
161161
$(
162-
impl<Tx, Rx> Pins<$instance> for ($tx<Tx>, $rx<Rx>) {
162+
impl<Tx: PinMode, Rx: PinMode> Pins<$instance> for ($tx<Tx>, $rx<Rx>) {
163163
fn setup(&self) {
164164
self.0.set_alt_mode(AltMode::$alt);
165165
self.1.set_alt_mode(AltMode::$alt);

0 commit comments

Comments
 (0)