Skip to content

Commit 11c726f

Browse files
authored
Implement more general GPIO pins (#115)
* Implement more general GPIO pins * Add changelog entry * Downgrade directly to Pxx * Make downgrade function downgrade to Pxx and make into_generic private * Add example of generic pin usage
1 parent 22dcce5 commit 11c726f

File tree

3 files changed

+148
-12
lines changed

3 files changed

+148
-12
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2828
### Changed
2929

3030
- DMA traits now require AsSlice instead of AsRef
31+
- GPIO `downgrade` function now returns a `Pxx` instead of a type specific to a
32+
GPIO port
3133

3234
## [v0.4.0] - 2019-08-09
3335

examples/blinky_generic.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//! Blinks several LEDs stored in an array
2+
3+
#![deny(unsafe_code)]
4+
#![no_std]
5+
#![no_main]
6+
7+
use panic_halt as _;
8+
9+
use nb::block;
10+
11+
use stm32f1xx_hal::{
12+
prelude::*,
13+
pac,
14+
timer::Timer,
15+
};
16+
use cortex_m_rt::entry;
17+
use embedded_hal::digital::v2::OutputPin;
18+
19+
#[entry]
20+
fn main() -> ! {
21+
let cp = cortex_m::Peripherals::take().unwrap();
22+
let dp = pac::Peripherals::take().unwrap();
23+
24+
let mut flash = dp.FLASH.constrain();
25+
let mut rcc = dp.RCC.constrain();
26+
27+
let clocks = rcc.cfgr.freeze(&mut flash.acr);
28+
29+
// Acquire the GPIO peripherals
30+
let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
31+
let mut gpioc = dp.GPIOC.split(&mut rcc.apb2);
32+
33+
// Configure the syst timer to trigger an update every second
34+
let mut timer = Timer::syst(cp.SYST, &clocks).start_count_down(1.hz());
35+
36+
// Create an array of LEDS to blink
37+
let mut leds = [
38+
gpioc.pc13.into_push_pull_output(&mut gpioc.crh).downgrade(),
39+
gpioa.pa1.into_push_pull_output(&mut gpioa.crl).downgrade()
40+
];
41+
42+
// Wait for the timer to trigger an update and change the state of the LED
43+
loop {
44+
block!(timer.wait()).unwrap();
45+
for led in leds.iter_mut() {
46+
led.set_high().unwrap();
47+
}
48+
block!(timer.wait()).unwrap();
49+
for led in leds.iter_mut() {
50+
led.set_low().unwrap();
51+
}
52+
}
53+
}

src/gpio.rs

Lines changed: 93 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ macro_rules! gpio {
9595
State,
9696
Active,
9797
Debugger,
98+
Pxx
9899
};
99100

100101
/// GPIO parts
@@ -150,13 +151,19 @@ macro_rules! gpio {
150151
}
151152
}
152153

153-
/// Partially erased pin
154-
pub struct $PXx<MODE> {
154+
/// Partially erased pin. Only used in the Pxx enum
155+
pub struct Generic<MODE> {
155156
i: u8,
156157
_mode: PhantomData<MODE>,
157158
}
158159

159-
impl<MODE> OutputPin for $PXx<Output<MODE>> {
160+
impl<MODE> Generic<MODE> {
161+
pub fn downgrade(self) -> Pxx<MODE> {
162+
Pxx::$PXx(self)
163+
}
164+
}
165+
166+
impl<MODE> OutputPin for Generic<Output<MODE>> {
160167
type Error = Void;
161168
fn set_high(&mut self) -> Result<(), Self::Error> {
162169
// NOTE(unsafe) atomic write to a stateless register
@@ -169,7 +176,7 @@ macro_rules! gpio {
169176
}
170177
}
171178

172-
impl<MODE> InputPin for $PXx<Input<MODE>> {
179+
impl<MODE> InputPin for Generic<Input<MODE>> {
173180
type Error = Void;
174181
fn is_high(&self) -> Result<bool, Self::Error> {
175182
self.is_low().map(|b| !b)
@@ -181,7 +188,7 @@ macro_rules! gpio {
181188
}
182189
}
183190

184-
impl <MODE> StatefulOutputPin for $PXx<Output<MODE>> {
191+
impl <MODE> StatefulOutputPin for Generic<Output<MODE>> {
185192
fn is_set_high(&self) -> Result<bool, Self::Error> {
186193
self.is_set_low().map(|b| !b)
187194
}
@@ -192,9 +199,9 @@ macro_rules! gpio {
192199
}
193200
}
194201

195-
impl <MODE> toggleable::Default for $PXx<Output<MODE>> {}
202+
impl <MODE> toggleable::Default for Generic<Output<MODE>> {}
196203

197-
impl InputPin for $PXx<Output<OpenDrain>> {
204+
impl InputPin for Generic<Output<OpenDrain>> {
198205
type Error = Void;
199206
fn is_high(&self) -> Result<bool, Self::Error> {
200207
self.is_low().map(|b| !b)
@@ -206,6 +213,10 @@ macro_rules! gpio {
206213
}
207214
}
208215

216+
pub type $PXx<MODE> = Pxx<MODE>;
217+
218+
219+
209220
$(
210221
/// Pin
211222
pub struct $PXi<MODE> {
@@ -442,15 +453,20 @@ macro_rules! gpio {
442453

443454
impl<MODE> $PXi<MODE> where MODE: Active {
444455
/// Erases the pin number from the type
445-
///
446-
/// This is useful when you want to collect the pins into an array where you
447-
/// need all the elements to have the same type
448-
pub fn downgrade(self) -> $PXx<MODE> {
449-
$PXx {
456+
fn into_generic(self) -> Generic<MODE> {
457+
Generic {
450458
i: $i,
451459
_mode: self._mode,
452460
}
453461
}
462+
463+
/// Erases the pin number and port from the type
464+
///
465+
/// This is useful when you want to collect the pins into an array where you
466+
/// need all the elements to have the same type
467+
pub fn downgrade(self) -> Pxx<MODE> {
468+
self.into_generic().downgrade()
469+
}
454470
}
455471

456472
impl<MODE> OutputPin for $PXi<Output<MODE>> {
@@ -507,6 +523,71 @@ macro_rules! gpio {
507523
}
508524
}
509525

526+
macro_rules! impl_pxx {
527+
($(($port:ident :: $pin:ident)),*) => {
528+
use void::Void;
529+
use embedded_hal::digital::v2::{InputPin, StatefulOutputPin, OutputPin};
530+
531+
pub enum Pxx<MODE> {
532+
$(
533+
$pin($port::Generic<MODE>)
534+
),*
535+
}
536+
537+
impl<MODE> OutputPin for Pxx<Output<MODE>> {
538+
type Error = Void;
539+
fn set_high(&mut self) -> Result<(), Void> {
540+
match self {
541+
$(Pxx::$pin(pin) => pin.set_high()),*
542+
}
543+
}
544+
545+
fn set_low(&mut self) -> Result<(), Void> {
546+
match self {
547+
$(Pxx::$pin(pin) => pin.set_low()),*
548+
}
549+
}
550+
}
551+
552+
impl<MODE> StatefulOutputPin for Pxx<Output<MODE>> {
553+
fn is_set_high(&self) -> Result<bool, Self::Error> {
554+
match self {
555+
$(Pxx::$pin(pin) => pin.is_set_high()),*
556+
}
557+
}
558+
559+
fn is_set_low(&self) -> Result<bool, Self::Error> {
560+
match self {
561+
$(Pxx::$pin(pin) => pin.is_set_low()),*
562+
}
563+
}
564+
}
565+
566+
impl<MODE> InputPin for Pxx<Input<MODE>> {
567+
type Error = Void;
568+
fn is_high(&self) -> Result<bool, Void> {
569+
match self {
570+
$(Pxx::$pin(pin) => pin.is_high()),*
571+
}
572+
}
573+
574+
fn is_low(&self) -> Result<bool, Void> {
575+
match self {
576+
$(Pxx::$pin(pin) => pin.is_low()),*
577+
}
578+
}
579+
}
580+
}
581+
}
582+
583+
impl_pxx!{
584+
(gpioa::PAx),
585+
(gpiob::PBx),
586+
(gpioc::PCx),
587+
(gpiod::PDx),
588+
(gpioe::PEx)
589+
}
590+
510591
gpio!(GPIOA, gpioa, gpioa, PAx, [
511592
PA0: (pa0, 0, Input<Floating>, CRL),
512593
PA1: (pa1, 1, Input<Floating>, CRL),

0 commit comments

Comments
 (0)