Skip to content

Commit 2814d5b

Browse files
authored
Merge pull request #4 from HarkonenBade/gpio-traits
Fully erased pins based on trait implementations
2 parents 84b70c7 + 27b5a9e commit 2814d5b

File tree

2 files changed

+162
-61
lines changed

2 files changed

+162
-61
lines changed

examples/blinky_multiple.rs

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
#![no_main]
2+
#![no_std]
3+
4+
use panic_halt;
5+
6+
use stm32f0xx_hal as hal;
7+
8+
use crate::hal::delay::Delay;
9+
use crate::hal::prelude::*;
10+
use crate::hal::stm32;
11+
12+
use cortex_m::peripheral::Peripherals;
13+
use cortex_m_rt::entry;
14+
15+
#[entry]
16+
fn main() -> ! {
17+
if let (Some(p), Some(cp)) = (stm32::Peripherals::take(), Peripherals::take()) {
18+
let gpioa = p.GPIOA.split();
19+
let gpiob = p.GPIOB.split();
20+
21+
/* (Re-)configure PA1 as output */
22+
let led1 = gpioa.pa1.into_push_pull_output();
23+
24+
/* (Re-)configure PB1 as output */
25+
let led2 = gpiob.pb1.into_push_pull_output();
26+
27+
/* Constrain clocking registers */
28+
let rcc = p.RCC.constrain();
29+
30+
/* Configure clock to 8 MHz (i.e. the default) and freeze it */
31+
let clocks = rcc.cfgr.sysclk(8.mhz()).freeze();
32+
33+
/* Get delay provider */
34+
let mut delay = Delay::new(cp.SYST, clocks);
35+
36+
/* Store them together */
37+
let mut leds = [led1.downgrade(), led2.downgrade()];
38+
loop {
39+
for l in &mut leds {
40+
l.set_high();
41+
}
42+
delay.delay_ms(1_000_u16);
43+
44+
for l in &mut leds {
45+
l.set_low();
46+
}
47+
delay.delay_ms(1_000_u16);
48+
}
49+
}
50+
51+
loop {
52+
continue;
53+
}
54+
}

src/gpio.rs

+108-61
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ pub trait GpioExt {
1111
fn split(self) -> Self::Parts;
1212
}
1313

14+
trait GpioRegExt {
15+
fn is_low(&self, pos: u8) -> bool;
16+
fn is_set_low(&self, pos: u8) -> bool;
17+
fn set_high(&self, pos: u8);
18+
fn set_low(&self, pos: u8);
19+
}
20+
1421
pub struct AF0;
1522
pub struct AF1;
1623
pub struct AF2;
@@ -49,6 +56,86 @@ pub struct Output<MODE> {
4956
/// Push pull output (type state)
5057
pub struct PushPull;
5158

59+
use embedded_hal::digital::{toggleable, InputPin, OutputPin, StatefulOutputPin};
60+
61+
/// Fully erased pin
62+
pub struct Pin<MODE> {
63+
i: u8,
64+
port: *const GpioRegExt,
65+
_mode: PhantomData<MODE>,
66+
}
67+
68+
impl<MODE> StatefulOutputPin for Pin<Output<MODE>> {
69+
fn is_set_high(&self) -> bool {
70+
!self.is_set_low()
71+
}
72+
73+
fn is_set_low(&self) -> bool {
74+
unsafe { (*self.port).is_set_low(self.i) }
75+
}
76+
}
77+
78+
impl<MODE> OutputPin for Pin<Output<MODE>> {
79+
fn set_high(&mut self) {
80+
unsafe { (*self.port).set_high(self.i) }
81+
}
82+
83+
fn set_low(&mut self) {
84+
unsafe { (*self.port).set_low(self.i) }
85+
}
86+
}
87+
88+
impl<MODE> toggleable::Default for Pin<Output<MODE>> {}
89+
90+
impl InputPin for Pin<Output<OpenDrain>> {
91+
fn is_high(&self) -> bool {
92+
!self.is_low()
93+
}
94+
95+
fn is_low(&self) -> bool {
96+
unsafe { (*self.port).is_low(self.i) }
97+
}
98+
}
99+
100+
impl<MODE> InputPin for Pin<Input<MODE>> {
101+
fn is_high(&self) -> bool {
102+
!self.is_low()
103+
}
104+
105+
fn is_low(&self) -> bool {
106+
unsafe { (*self.port).is_low(self.i) }
107+
}
108+
}
109+
110+
macro_rules! gpio_trait {
111+
($gpiox:ident) => {
112+
impl GpioRegExt for crate::stm32::$gpiox::RegisterBlock {
113+
fn is_low(&self, pos: u8) -> bool {
114+
// NOTE(unsafe) atomic read with no side effects
115+
self.idr.read().bits() & (1 << pos) == 0
116+
}
117+
118+
fn is_set_low(&self, pos: u8) -> bool {
119+
// NOTE(unsafe) atomic read with no side effects
120+
self.odr.read().bits() & (1 << pos) == 0
121+
}
122+
123+
fn set_high(&self, pos: u8) {
124+
// NOTE(unsafe) atomic write to a stateless register
125+
unsafe { self.bsrr.write(|w| w.bits(1 << pos)) }
126+
}
127+
128+
fn set_low(&self, pos: u8) {
129+
// NOTE(unsafe) atomic write to a stateless register
130+
unsafe { self.bsrr.write(|w| w.bits(1 << (pos + 16))) }
131+
}
132+
}
133+
};
134+
}
135+
136+
gpio_trait!(gpioa);
137+
gpio_trait!(gpiof);
138+
52139
macro_rules! gpio {
53140
($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, [
54141
$($PXi:ident: ($pxi:ident, $i:expr, $MODE:ty),)+
@@ -64,6 +151,7 @@ macro_rules! gpio {
64151
use super::{
65152
Alternate, Floating, GpioExt, Input, OpenDrain, Output,
66153
PullDown, PullUp, PushPull, AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7,
154+
Pin, GpioRegExt,
67155
};
68156

69157
/// GPIO parts
@@ -90,48 +178,6 @@ macro_rules! gpio {
90178
}
91179
}
92180

93-
/// Partially erased pin
94-
pub struct $PXx<MODE> {
95-
i: u8,
96-
_mode: PhantomData<MODE>,
97-
}
98-
99-
impl<MODE> StatefulOutputPin for $PXx<Output<MODE>> {
100-
fn is_set_high(&self) -> bool {
101-
!self.is_set_low()
102-
}
103-
104-
fn is_set_low(&self) -> bool {
105-
// NOTE(unsafe) atomic read with no side effects
106-
unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << self.i) == 0 }
107-
}
108-
}
109-
110-
impl<MODE> OutputPin for $PXx<Output<MODE>> {
111-
fn set_high(&mut self) {
112-
// NOTE(unsafe) atomic write to a stateless register
113-
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << self.i)) }
114-
}
115-
116-
fn set_low(&mut self) {
117-
// NOTE(unsafe) atomic write to a stateless register
118-
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << (self.i + 16))) }
119-
}
120-
}
121-
122-
impl<MODE> toggleable::Default for $PXx<Output<MODE>> {}
123-
124-
impl<MODE> InputPin for $PXx<Input<MODE>> {
125-
fn is_high(&self) -> bool {
126-
!self.is_low()
127-
}
128-
129-
fn is_low(&self) -> bool {
130-
// NOTE(unsafe) atomic read with no side effects
131-
unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << self.i) == 0 }
132-
}
133-
}
134-
135181
fn _set_alternate_mode (index:usize, mode: u32)
136182
{
137183
let offset = 2 * index;
@@ -382,9 +428,10 @@ macro_rules! gpio {
382428
///
383429
/// This is useful when you want to collect the pins into an array where you
384430
/// need all the elements to have the same type
385-
pub fn downgrade(self) -> $PXx<Output<MODE>> {
386-
$PXx {
431+
pub fn downgrade(self) -> Pin<Output<MODE>> {
432+
Pin {
387433
i: $i,
434+
port: $GPIOX::ptr() as *const GpioRegExt,
388435
_mode: self._mode,
389436
}
390437
}
@@ -396,33 +443,41 @@ macro_rules! gpio {
396443
}
397444

398445
fn is_set_low(&self) -> bool {
399-
// NOTE(unsafe) atomic read with no side effects
400-
unsafe { (*$GPIOX::ptr()).odr.read().bits() & (1 << $i) == 0 }
446+
unsafe { (*$GPIOX::ptr()).is_set_low($i) }
401447
}
402448
}
403449

404450
impl<MODE> OutputPin for $PXi<Output<MODE>> {
405451
fn set_high(&mut self) {
406-
// NOTE(unsafe) atomic write to a stateless register
407-
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << $i)) }
452+
unsafe { (*$GPIOX::ptr()).set_high($i) }
408453
}
409454

410455
fn set_low(&mut self) {
411-
// NOTE(unsafe) atomic write to a stateless register
412-
unsafe { (*$GPIOX::ptr()).bsrr.write(|w| w.bits(1 << ($i + 16))) }
456+
unsafe { (*$GPIOX::ptr()).set_low($i) }
413457
}
414458
}
415459

416460
impl<MODE> toggleable::Default for $PXi<Output<MODE>> {}
417461

462+
impl InputPin for $PXi<Output<OpenDrain>> {
463+
fn is_high(&self) -> bool {
464+
!self.is_low()
465+
}
466+
467+
fn is_low(&self) -> bool {
468+
unsafe { (*$GPIOX::ptr()).is_low($i) }
469+
}
470+
}
471+
418472
impl<MODE> $PXi<Input<MODE>> {
419473
/// Erases the pin number from the type
420474
///
421475
/// This is useful when you want to collect the pins into an array where you
422476
/// need all the elements to have the same type
423-
pub fn downgrade(self) -> $PXx<Input<MODE>> {
424-
$PXx {
477+
pub fn downgrade(self) -> Pin<Input<MODE>> {
478+
Pin {
425479
i: $i,
480+
port: $GPIOX::ptr() as *const GpioRegExt,
426481
_mode: self._mode,
427482
}
428483
}
@@ -434,18 +489,10 @@ macro_rules! gpio {
434489
}
435490

436491
fn is_low(&self) -> bool {
437-
// NOTE(unsafe) atomic read with no side effects
438-
unsafe { (*$GPIOX::ptr()).idr.read().bits() & (1 << $i) == 0 }
492+
unsafe { (*$GPIOX::ptr()).is_low($i) }
439493
}
440494
}
441495
)+
442-
443-
impl<TYPE> $PXx<TYPE> {
444-
pub fn get_id (&self) -> u8
445-
{
446-
self.i
447-
}
448-
}
449496
}
450497
}
451498
}

0 commit comments

Comments
 (0)