Forráskód Böngészése

Add documentation for GPIO pins

TheZoq2 4 éve
szülő
commit
983aa938a0
3 módosított fájl, 75 hozzáadás és 11 törlés
  1. 4 0
      CHANGELOG.md
  2. 1 1
      examples/dynamic_gpio.rs
  3. 70 10
      src/gpio.rs

+ 4 - 0
CHANGELOG.md

@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
 
 ## [Unreleased]
 
+### Added
+
+- Add runtime-reconfigurable GPIO pins
+
 ### Fixed
 
 - Fix period retrieval for timers

+ 1 - 1
examples/dynamic_gpio.rs

@@ -9,7 +9,7 @@ use nb::block;
 use cortex_m_rt::entry;
 use cortex_m_semihosting::hprintln;
 use embedded_hal::digital::v2::{InputPin, OutputPin};
-use stm32f1xx_hal::{gpio::State, pac, prelude::*, timer::Timer};
+use stm32f1xx_hal::{pac, prelude::*, timer::Timer};
 
 #[entry]
 fn main() -> ! {

+ 70 - 10
src/gpio.rs

@@ -1,10 +1,68 @@
 //! # General Purpose I/Os
 //!
+//! The GPIO pins are organised into groups of 16 pins which can be accessed through the
+//! `gpioa`, `gpiob`... modules. To get access to the pins, you first need to convert them into a
+//! HAL designed struct from the `pac` struct using the `spilit` function.
+//! ```rust
+//! // Acquire the GPIOC peripheral
+//! // NOTE: `dp` is the device peripherals from the `PAC` crate
+//! let mut gpioa = dp.GPIOA.split(&mut rcc.apb2);
+//! ```
+//!
+//! This gives you a struct containing two control registers `crl` and `crh`, and all the pins
+//! `px0..px15`. These structs are what you use to interract with the pins to change their modes,
+//! or their inputs or outputs. For example, to set `pa5` high, you would call
+//!
+//! ```rust
+//! let output = gpioa.pa5.into_push_pull_output(&mut gpioa.crl);
+//! output.set_high();
+//! ```
+//!
+//! Each GPIO pin can be set to various modes:
+//!
+//! - **Alternate**: Pin mode required when the pin is driven by other peripherals
+//! - **Dynamic**: Pin mode is selected at runtime. See changing configurations for more details
+//! - Input
+//!     - **PullUp**: Input connected to high with a weak pull up resistor. Will be high when nothing
+//!     is connected
+//!     - **PullDown**: Input connected to high with a weak pull up resistor. Will be low when nothing
+//!     is connected
+//!     - **Floating**: Input not pulled to high or low. Will be undefined when nothing is connected
+//! - Output
+//!     - **PushPull**: Output which either drives the pin high or low
+//!     - **OpenDrain**: Output which leaves the gate floating, or pulls it do ground in drain
+//!     mode. Can be used as an input in the `open` configuration
+//! - **Debugger**: Some pins start out being used by the debugger. A pin in this mode can only be
+//! used if the [JTAG peripheral has been turned off](#accessing-pa15-pb3-and-pb14).
+//!
+//! ## Changing modes
+//! The simplest way to change the pin mode is to use the `into_<mode>` functions. These return a
+//! new struct with the correct mode that you can use the input or output functions on.
+//!
+//! If you need a more temporary mode change, and can not use the `into_<mode>` functions for
+//! ownership reasons, you can use the `as_<mode>` functions to temporarily change the pin type, do
+//! some output or input, and then have it change back once done.
+//!
+//! ### Dynamic Mode Change
+//! The above mode change methods guarantee that you can only call input functions when the pin is
+//! in input mode, and output when in output modes, but can lead to some issues. Therefore, there
+//! is also a mode where the state is kept track of at runtime, allowing you to change the mode
+//! often, and without problems with ownership, or references, at the cost of some performance and
+//! the risk of runtime errors.
+//!
+//! To make a pin dynamic, use the `into_dynamic` function, and then use the `make_<mode>` functions to
+//! change the mode
+//!
+//! ## Accessing PA15, PB3, and PB14
+//!
+//! These pins are used by the JTAG peripheral by default. To use them in your program, you need to
+//! disable that peripheral. This is done using the [afio::MAPR::disable_jtag](../afio/struct.MAPR.html#method.disable_jtag) function
+//!
 //! # Interfacing with v1 traits
 //!
-//! `embedded-hal` has two versions of the digital traits, `v2` which is used
-//! by this crate and `v1` which is deprecated but still used by a lot of drivers.
-//! If you want to use such a driver with this crate, you need to convert the digital pins to the `v1` type.
+//! `embedded-hal` has two versions of the digital traits, `v2` which is used by this crate and
+//! `v1` which is deprecated but still used by a lot of drivers.  If you want to use such a driver
+//! with this crate, you need to convert the digital pins to the `v1` type.
 //!
 //! This is done using `embedded-hal::digital::v1_compat::OldOutputPin`. For example:
 //!
@@ -12,7 +70,6 @@
 //! let nss = gpioa.pa4.into_push_pull_output(&mut gpioa.crl);
 //! let mut mfrc522 = Mfrc522::new(spi, OldOutputPin::from(nss)).unwrap();
 //! ```
-//!
 
 use core::marker::PhantomData;
 
@@ -96,6 +153,7 @@ pub trait ExtiPin {
     fn check_interrupt(&mut self) -> bool;
 }
 
+/// Tracks the current pin state for dynamic pins
 pub enum Dynamic {
     InputFloating,
     InputPullUp,
@@ -104,6 +162,8 @@ pub enum Dynamic {
     OutputOpenDrain,
 }
 
+impl Active for Dynamic {}
+
 #[derive(Debug, PartialEq)]
 pub enum PinModeError {
     IncorrectMode,
@@ -134,22 +194,22 @@ pub trait PinMode<CR> {
 
 // These impls are needed because a macro can not brace initialise a ty token
 impl<MODE> Input<MODE> {
-    fn _new() -> Self {
+    const fn _new() -> Self {
         Self { _mode: PhantomData }
     }
 }
 impl<MODE> Output<MODE> {
-    fn _new() -> Self {
+    const fn _new() -> Self {
         Self { _mode: PhantomData }
     }
 }
 impl<MODE> Alternate<MODE> {
-    fn _new() -> Self {
+    const fn _new() -> Self {
         Self { _mode: PhantomData }
     }
 }
 impl Debugger {
-    fn _new() -> Self {
+    const fn _new() -> Self {
         Self {}
     }
 }
@@ -516,7 +576,6 @@ macro_rules! gpio {
                         }
                     }
 
-
                     /// Configures the pin to operate as an analog input pin
                     pub fn into_analog(self, cr: &mut $CR) -> $PXi<Analog> {
                         unsafe {
@@ -533,6 +592,8 @@ macro_rules! gpio {
                     }
                 }
 
+                // These macros are defined here instead of at the top level in order
+                // to be able to refer to macro variables from the outer layers.
                 macro_rules! impl_temp_output {
                     (
                         $fn_name:ident,
@@ -626,7 +687,6 @@ macro_rules! gpio {
                     );
                 }
 
-
                 impl<MODE> $PXi<MODE> where MODE: Active {
                     /// Erases the pin number from the type
                     fn into_generic(self) -> Generic<MODE> {