Skip to content

Commit 983aa93

Browse files
committed
Add documentation for GPIO pins
1 parent f7204fc commit 983aa93

File tree

3 files changed

+75
-11
lines changed

3 files changed

+75
-11
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Add runtime-reconfigurable GPIO pins
13+
1014
### Fixed
1115

1216
- Fix period retrieval for timers

examples/dynamic_gpio.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use nb::block;
99
use cortex_m_rt::entry;
1010
use cortex_m_semihosting::hprintln;
1111
use embedded_hal::digital::v2::{InputPin, OutputPin};
12-
use stm32f1xx_hal::{gpio::State, pac, prelude::*, timer::Timer};
12+
use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
1313

1414
#[entry]
1515
fn main() -> ! {

src/gpio.rs

Lines changed: 70 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,75 @@
11
//! # General Purpose I/Os
22
//!
3+
//! The GPIO pins are organised into groups of 16 pins which can be accessed through the
4+
//! `gpioa`, `gpiob`... modules. To get access to the pins, you first need to convert them into a
5+
//! HAL designed struct from the `pac` struct using the `spilit` function.
6+
//! ```rust
7+
//! // Acquire the GPIOC peripheral
8+
//! // NOTE: `dp` is the device peripherals from the `PAC` crate
9+
//! let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
10+
//! ```
11+
//!
12+
//! This gives you a struct containing two control registers `crl` and `crh`, and all the pins
13+
//! `px0..px15`. These structs are what you use to interract with the pins to change their modes,
14+
//! or their inputs or outputs. For example, to set `pa5` high, you would call
15+
//!
16+
//! ```rust
17+
//! let output = gpioa.pa5.into_push_pull_output(&mut gpioa.crl);
18+
//! output.set_high();
19+
//! ```
20+
//!
21+
//! Each GPIO pin can be set to various modes:
22+
//!
23+
//! - **Alternate**: Pin mode required when the pin is driven by other peripherals
24+
//! - **Dynamic**: Pin mode is selected at runtime. See changing configurations for more details
25+
//! - Input
26+
//! - **PullUp**: Input connected to high with a weak pull up resistor. Will be high when nothing
27+
//! is connected
28+
//! - **PullDown**: Input connected to high with a weak pull up resistor. Will be low when nothing
29+
//! is connected
30+
//! - **Floating**: Input not pulled to high or low. Will be undefined when nothing is connected
31+
//! - Output
32+
//! - **PushPull**: Output which either drives the pin high or low
33+
//! - **OpenDrain**: Output which leaves the gate floating, or pulls it do ground in drain
34+
//! mode. Can be used as an input in the `open` configuration
35+
//! - **Debugger**: Some pins start out being used by the debugger. A pin in this mode can only be
36+
//! used if the [JTAG peripheral has been turned off](#accessing-pa15-pb3-and-pb14).
37+
//!
38+
//! ## Changing modes
39+
//! The simplest way to change the pin mode is to use the `into_<mode>` functions. These return a
40+
//! new struct with the correct mode that you can use the input or output functions on.
41+
//!
42+
//! If you need a more temporary mode change, and can not use the `into_<mode>` functions for
43+
//! ownership reasons, you can use the `as_<mode>` functions to temporarily change the pin type, do
44+
//! some output or input, and then have it change back once done.
45+
//!
46+
//! ### Dynamic Mode Change
47+
//! The above mode change methods guarantee that you can only call input functions when the pin is
48+
//! in input mode, and output when in output modes, but can lead to some issues. Therefore, there
49+
//! is also a mode where the state is kept track of at runtime, allowing you to change the mode
50+
//! often, and without problems with ownership, or references, at the cost of some performance and
51+
//! the risk of runtime errors.
52+
//!
53+
//! To make a pin dynamic, use the `into_dynamic` function, and then use the `make_<mode>` functions to
54+
//! change the mode
55+
//!
56+
//! ## Accessing PA15, PB3, and PB14
57+
//!
58+
//! These pins are used by the JTAG peripheral by default. To use them in your program, you need to
59+
//! disable that peripheral. This is done using the [afio::MAPR::disable_jtag](../afio/struct.MAPR.html#method.disable_jtag) function
60+
//!
361
//! # Interfacing with v1 traits
462
//!
5-
//! `embedded-hal` has two versions of the digital traits, `v2` which is used
6-
//! by this crate and `v1` which is deprecated but still used by a lot of drivers.
7-
//! If you want to use such a driver with this crate, you need to convert the digital pins to the `v1` type.
63+
//! `embedded-hal` has two versions of the digital traits, `v2` which is used by this crate and
64+
//! `v1` which is deprecated but still used by a lot of drivers. If you want to use such a driver
65+
//! with this crate, you need to convert the digital pins to the `v1` type.
866
//!
967
//! This is done using `embedded-hal::digital::v1_compat::OldOutputPin`. For example:
1068
//!
1169
//! ```rust
1270
//! let nss = gpioa.pa4.into_push_pull_output(&mut gpioa.crl);
1371
//! let mut mfrc522 = Mfrc522::new(spi, OldOutputPin::from(nss)).unwrap();
1472
//! ```
15-
//!
1673
1774
use core::marker::PhantomData;
1875

@@ -96,6 +153,7 @@ pub trait ExtiPin {
96153
fn check_interrupt(&mut self) -> bool;
97154
}
98155

156+
/// Tracks the current pin state for dynamic pins
99157
pub enum Dynamic {
100158
InputFloating,
101159
InputPullUp,
@@ -104,6 +162,8 @@ pub enum Dynamic {
104162
OutputOpenDrain,
105163
}
106164

165+
impl Active for Dynamic {}
166+
107167
#[derive(Debug, PartialEq)]
108168
pub enum PinModeError {
109169
IncorrectMode,
@@ -134,22 +194,22 @@ pub trait PinMode<CR> {
134194

135195
// These impls are needed because a macro can not brace initialise a ty token
136196
impl<MODE> Input<MODE> {
137-
fn _new() -> Self {
197+
const fn _new() -> Self {
138198
Self { _mode: PhantomData }
139199
}
140200
}
141201
impl<MODE> Output<MODE> {
142-
fn _new() -> Self {
202+
const fn _new() -> Self {
143203
Self { _mode: PhantomData }
144204
}
145205
}
146206
impl<MODE> Alternate<MODE> {
147-
fn _new() -> Self {
207+
const fn _new() -> Self {
148208
Self { _mode: PhantomData }
149209
}
150210
}
151211
impl Debugger {
152-
fn _new() -> Self {
212+
const fn _new() -> Self {
153213
Self {}
154214
}
155215
}
@@ -516,7 +576,6 @@ macro_rules! gpio {
516576
}
517577
}
518578

519-
520579
/// Configures the pin to operate as an analog input pin
521580
pub fn into_analog(self, cr: &mut $CR) -> $PXi<Analog> {
522581
unsafe {
@@ -533,6 +592,8 @@ macro_rules! gpio {
533592
}
534593
}
535594

595+
// These macros are defined here instead of at the top level in order
596+
// to be able to refer to macro variables from the outer layers.
536597
macro_rules! impl_temp_output {
537598
(
538599
$fn_name:ident,
@@ -626,7 +687,6 @@ macro_rules! gpio {
626687
);
627688
}
628689

629-
630690
impl<MODE> $PXi<MODE> where MODE: Active {
631691
/// Erases the pin number from the type
632692
fn into_generic(self) -> Generic<MODE> {

0 commit comments

Comments
 (0)