From f946323901d5929be1a37403d9024138d705ff20 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 22 Mar 2022 22:25:39 +0300 Subject: [PATCH 1/9] f4xx-hal like gpio --- CHANGELOG.md | 2 + Cargo.toml | 2 +- examples/can.rs | 4 +- examples/gpio_erased.rs | 16 +- examples/gpio_interrupts.rs | 9 +- examples/i2c_scanner.rs | 18 +- examples/pwm.rs | 20 +- examples/serial_dma.rs | 4 +- examples/serial_echo_rtic.rs | 16 +- examples/spi.rs | 6 +- examples/toggle.rs | 10 +- examples/usb_serial.rs | 12 +- src/gpio.rs | 2203 +++++++++------------ src/gpio/convert.rs | 215 ++ src/gpio/dynamic.rs | 134 ++ src/gpio/erased.rs | 147 ++ src/gpio/hal_02.rs | 242 +++ src/gpio/partially_erased.rs | 129 ++ src/lib.rs | 6 + src/prelude.rs | 6 - src/syscfg.rs | 14 +- testsuite/tests/adc.rs | 4 +- testsuite/tests/gpio_input.rs | 14 +- testsuite/tests/gpio_input_puller.rs | 27 +- testsuite/tests/gpio_output_open_drain.rs | 25 +- testsuite/tests/gpio_output_push_pull.rs | 22 +- testsuite/tests/spi.rs | 6 +- testsuite/tests/uart.rs | 24 +- 28 files changed, 1883 insertions(+), 1454 deletions(-) create mode 100644 src/gpio/convert.rs create mode 100644 src/gpio/dynamic.rs create mode 100644 src/gpio/erased.rs create mode 100644 src/gpio/hal_02.rs create mode 100644 src/gpio/partially_erased.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 32d6df1fc..2164cc410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - Missing `MosiPin` impl for `PB5` ([#322]) - Read valid data from data register even if reception of next character has started ([#317]) +- Use const generics for pins. The MSRV was bumped to 1.59 ([#316]) ## [v0.9.0] - 2022-03-06 @@ -603,6 +604,7 @@ let clocks = rcc [#322]: https://github.com/stm32-rs/stm32f3xx-hal/pull/322 [#318]: https://github.com/stm32-rs/stm32f3xx-hal/pull/318 [#317]: https://github.com/stm32-rs/stm32f3xx-hal/pull/317 +[#316]: https://github.com/stm32-rs/stm32f3xx-hal/pull/316 [#314]: https://github.com/stm32-rs/stm32f3xx-hal/pull/314 [#309]: https://github.com/stm32-rs/stm32f3xx-hal/pull/309 [#308]: https://github.com/stm32-rs/stm32f3xx-hal/pull/308 diff --git a/Cargo.toml b/Cargo.toml index 849ad150f..fab412ab8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ cortex-m = "0.7.4" cortex-m-rt = "0.7.3" defmt = { version = ">=0.2.3, <0.4.0", optional = true } embedded-dma = "0.2.0" -embedded-hal = { version = "0.2.5", features = ["unproven"] } +embedded-hal = { version = "0.2.7", features = ["unproven"] } embedded-time = "0.12.0" enumset = { version = "1.0.6", optional = true } nb = "1.0.0" diff --git a/examples/can.rs b/examples/can.rs index 73e5990f4..80d08afa3 100644 --- a/examples/can.rs +++ b/examples/can.rs @@ -43,10 +43,10 @@ fn main() -> ! { // Configure CAN RX and TX pins (AF9) let rx = gpioa .pa11 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); let tx = gpioa .pa12 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); // Initialize the CAN peripheral // Use loopback mode: No pins need to be assigned to peripheral. diff --git a/examples/gpio_erased.rs b/examples/gpio_erased.rs index 658a26331..a77798da9 100644 --- a/examples/gpio_erased.rs +++ b/examples/gpio_erased.rs @@ -23,33 +23,29 @@ fn main() -> ! { let mut gpioc = dp.GPIOC.split(&mut rcc.ahb); let mut gpiod = dp.GPIOD.split(&mut rcc.ahb); - let mut pin_array: [gpio::PXx; 4] = [ + let mut pin_array: [gpio::EPin; 4] = [ gpiob .pb11 .into_floating_input(&mut gpiob.moder, &mut gpiob.pupdr) - .downgrade() - .downgrade(), + .erase(), gpioc .pc4 .into_floating_input(&mut gpioc.moder, &mut gpioc.pupdr) - .downgrade() - .downgrade(), + .erase(), gpiod .pd3 .into_floating_input(&mut gpiod.moder, &mut gpiod.pupdr) - .downgrade() - .downgrade(), + .erase(), gpiod .pd2 .into_floating_input(&mut gpiod.moder, &mut gpiod.pupdr) - .downgrade() - .downgrade(), + .erase(), ]; hprintln!("Start scanning pin array"); loop { for pin in pin_array.iter_mut() { - hprintln!("Value is {}", pin.is_high().unwrap()); + hprintln!("Value is {}", pin.is_high()); asm::delay(1_000_000); } } diff --git a/examples/gpio_interrupts.rs b/examples/gpio_interrupts.rs index c835ec5f1..25a7f8aed 100644 --- a/examples/gpio_interrupts.rs +++ b/examples/gpio_interrupts.rs @@ -35,7 +35,7 @@ fn main() -> ! { .pe9 .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper); // Turn the led on so we know the configuration step occurred. - led.toggle().expect("unable to toggle led in configuration"); + led.toggle(); // Move the ownership of the led to the global LED cortex_m::interrupt::free(|cs| *LED.borrow(cs).borrow_mut() = Some(led)); @@ -69,12 +69,7 @@ fn main() -> ! { fn EXTI0() { cortex_m::interrupt::free(|cs| { // Toggle the LED - LED.borrow(cs) - .borrow_mut() - .as_mut() - .unwrap() - .toggle() - .unwrap(); + LED.borrow(cs).borrow_mut().as_mut().unwrap().toggle(); // Clear the interrupt pending bit so we don't infinitely call this routine BUTTON diff --git a/examples/i2c_scanner.rs b/examples/i2c_scanner.rs index ff9a1f452..3a3283e36 100644 --- a/examples/i2c_scanner.rs +++ b/examples/i2c_scanner.rs @@ -28,16 +28,14 @@ fn main() -> ! { let mut gpiob = dp.GPIOB.split(&mut rcc.ahb); // Configure I2C1 - let mut scl = - gpiob - .pb6 - .into_af_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - let mut sda = - gpiob - .pb7 - .into_af_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); - scl.internal_pull_up(&mut gpiob.pupdr, true); - sda.internal_pull_up(&mut gpiob.pupdr, true); + let scl = gpiob + .pb6 + .into_alternate_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl) + .internal_pull_up(&mut gpiob.pupdr, true); + let sda = gpiob + .pb7 + .into_alternate_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl) + .internal_pull_up(&mut gpiob.pupdr, true); let mut i2c = hal::i2c::I2c::new( dp.I2C1, (scl, sda), diff --git a/examples/pwm.rs b/examples/pwm.rs index 3a00c49d7..be1485185 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -34,38 +34,38 @@ fn main() -> ! { let mut gpioa = dp.GPIOA.split(&mut rcc.ahb); let pa4 = gpioa .pa4 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); let pa6 = gpioa .pa6 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); let pa7 = gpioa .pa7 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl); let mut gpiob = dp.GPIOB.split(&mut rcc.ahb); let pb0 = gpiob .pb0 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let pb1 = gpiob .pb1 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let pb4 = gpiob .pb4 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let pb5 = gpiob .pb5 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrl); let pb8 = gpiob .pb8 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh); let pb10 = gpiob .pb10 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh); + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh); let mut gpioc = dp.GPIOC.split(&mut rcc.ahb); let pc10 = gpioc .pc10 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); // TIM3 // diff --git a/examples/serial_dma.rs b/examples/serial_dma.rs index bf580dbce..430cf919d 100644 --- a/examples/serial_dma.rs +++ b/examples/serial_dma.rs @@ -35,10 +35,10 @@ fn main() -> ! { let pins = ( gpioa .pa9 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), gpioa .pa10 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), ); let serial = Serial::new(dp.USART1, pins, 9600.Bd(), clocks, &mut rcc.apb2); let (tx, rx) = serial.split(); diff --git a/examples/serial_echo_rtic.rs b/examples/serial_echo_rtic.rs index 3b2cf71ec..05f597779 100644 --- a/examples/serial_echo_rtic.rs +++ b/examples/serial_echo_rtic.rs @@ -58,30 +58,30 @@ mod app { let mut dir: DirType = gpioe .pe13 .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper); - dir.set_low().unwrap(); + dir.set_low(); // SERIAL let mut gpioa = cx.device.GPIOA.split(&mut rcc.ahb); - let mut pins = ( + let pins = ( gpioa // Tx pin .pa9 // configure this pin to make use of its `USART1_TX` alternative function // (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at // https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html) - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), gpioa // Rx pin .pa10 // configure this pin to make use of its `USART1_RX` alternative function // (AF mapping taken from table 14 "Alternate functions for port A" of the datasheet at // https://www.st.com/en/microcontrollers-microprocessors/stm32f303vc.html) - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh) + .internal_pull_up(&mut gpioa.pupdr, true), ); - pins.1.internal_pull_up(&mut gpioa.pupdr, true); let mut serial: SerialType = Serial::new(cx.device.USART1, pins, 19200.Bd(), clocks, &mut rcc.apb2); - serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Switch::On); + serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Toggle::On); rprintln!("post init"); @@ -99,7 +99,7 @@ mod app { let dir = cx.local.dir; if serial.is_event_triggered(Event::ReceiveDataRegisterNotEmpty) { - dir.set_high().unwrap(); + dir.set_high(); serial.configure_interrupt(Event::ReceiveDataRegisterNotEmpty, Switch::Off); match serial.read() { Ok(byte) => { @@ -116,7 +116,7 @@ mod app { // and other functions enabled by the "enumset" feature. let events = serial.triggered_events(); if events.contains(Event::TransmissionComplete) { - dir.set_low().unwrap(); + dir.set_low(); let interrupts = { let mut interrupts = enumset::EnumSet::new(); interrupts.insert(Event::ReceiveDataRegisterNotEmpty); diff --git a/examples/spi.rs b/examples/spi.rs index 63727ea72..cd3a90b88 100644 --- a/examples/spi.rs +++ b/examples/spi.rs @@ -32,13 +32,13 @@ fn main() -> ! { // Configure pins for SPI let sck = gpioc .pc10 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); let miso = gpioc .pc11 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); let mosi = gpioc .pc12 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh); let mut spi = Spi::new(dp.SPI3, (sck, miso, mosi), 3.MHz(), clocks, &mut rcc.apb1); diff --git a/examples/toggle.rs b/examples/toggle.rs index a466ed14b..a294e13bb 100644 --- a/examples/toggle.rs +++ b/examples/toggle.rs @@ -25,18 +25,18 @@ fn main() -> ! { .pe13 .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper); - led.set_low().unwrap(); + led.set_low(); loop { - led.toggle().unwrap(); + led.toggle(); cortex_m::asm::delay(8_000_000); // Toggle by hand. // Uses `StatefulOutputPin` instead of `ToggleableOutputPin`. // Logically it is the same. - if led.is_set_low().unwrap() { - led.set_high().unwrap(); + if led.is_set_low() { + led.set_high(); } else { - led.set_low().unwrap(); + led.set_low(); } cortex_m::asm::delay(8_000_000); } diff --git a/examples/usb_serial.rs b/examples/usb_serial.rs index 749bbeadd..56d7fabd0 100644 --- a/examples/usb_serial.rs +++ b/examples/usb_serial.rs @@ -39,7 +39,7 @@ fn main() -> ! { let mut led = gpioe .pe13 .into_push_pull_output(&mut gpioe.moder, &mut gpioe.otyper); - led.set_low().ok(); // Turn off + led.set_low(); // Turn off let mut gpioa = dp.GPIOA.split(&mut rcc.ahb); @@ -50,13 +50,13 @@ fn main() -> ! { let mut usb_dp = gpioa .pa12 .into_push_pull_output(&mut gpioa.moder, &mut gpioa.otyper); - usb_dp.set_low().ok(); + usb_dp.set_low(); delay(clocks.sysclk().0 / 100); let usb_dm = gpioa .pa11 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); - let usb_dp = usb_dp.into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); + let usb_dp = usb_dp.into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh); let usb = Peripheral { usb: dp.USB, @@ -83,7 +83,7 @@ fn main() -> ! { match serial.read(&mut buf) { Ok(count) if count > 0 => { - led.set_high().ok(); // Turn on + led.set_high(); // Turn on // Echo back in upper case for c in buf[0..count].iter_mut() { @@ -105,6 +105,6 @@ fn main() -> ! { _ => {} } - led.set_low().ok(); // Turn off + led.set_low(); // Turn off } } diff --git a/src/gpio.rs b/src/gpio.rs index 1ff27c063..4f7920c11 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -44,6 +44,10 @@ //! - **Analog**: Pin mode required for ADC, DAC, OPAMP, and COMP peripherals. It is also suitable //! for minimize energy consumption as the output buffer and the schmitt trigger input is disabled //! +//! ## Changing modes +//! The simplest way to change the pin mode is to use the `into_` functions. These return a +//! new struct with the correct mode that you can use the input or output functions on. +//! //! ### Output Speed //! //! Output speed (slew rate) for each pin is selectable from low, medium, and high by calling @@ -58,499 +62,198 @@ //! //! [InputPin]: embedded_hal::digital::v2::InputPin //! [OutputPin]: embedded_hal::digital::v2::OutputPin -//! [examples/toggle.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.9.1/examples/toggle.rs +//! [examples/toggle.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.9.0/examples/toggle.rs +//! +//! If you need a more temporary mode change, and can not use the `into_` functions for +//! ownership reasons, you can use the closure based `with_` 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_` functions to +//! change the mode + +#![allow(missing_docs)] + +use core::marker::PhantomData; + +use crate::pac::{Interrupt, EXTI}; +use crate::rcc::AHB; +use crate::Switch; -use core::{convert::Infallible, marker::PhantomData}; +mod convert; +use convert::PinMode; +mod partially_erased; +pub use partially_erased::{PEPin, PartiallyErasedPin}; +mod erased; +pub use erased::{EPin, ErasedPin}; +mod dynamic; +pub use dynamic::{Dynamic, DynamicPin}; +mod hal_02; -use crate::{ - hal::digital::v2::OutputPin, - pac::{Interrupt, EXTI}, - rcc::AHB, - Switch, -}; +pub use embedded_hal::digital::v2::PinState; -use crate::hal::digital::v2::{toggleable, InputPin, StatefulOutputPin}; +use core::fmt; + +/// A filler pin type +#[derive(Debug)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct NoPin; /// Extension trait to split a GPIO peripheral in independent pins and registers pub trait GpioExt { - /// The Parts to split the GPIO peripheral into + /// The parts to split the GPIO into type Parts; /// Splits the GPIO block into independent pins and registers fn split(self, ahb: &mut AHB) -> Self::Parts; } -/// GPIO Register interface traits private to this module -mod private { - pub trait GpioRegExt { - fn is_low(&self, i: u8) -> bool; - fn is_set_low(&self, i: u8) -> bool; - fn set_high(&self, i: u8); - fn set_low(&self, i: u8); - } - - pub trait Moder { - fn input(&mut self, i: u8); - fn output(&mut self, i: u8); - fn alternate(&mut self, i: u8); - fn analog(&mut self, i: u8); - } - - pub trait Otyper { - fn push_pull(&mut self, i: u8); - fn open_drain(&mut self, i: u8); - } +pub trait PinExt { + type Mode; + /// Return pin number + fn pin_id(&self) -> u8; + /// Return port number + fn port_id(&self) -> u8; +} - pub trait Ospeedr { - fn low(&mut self, i: u8); - fn medium(&mut self, i: u8); - fn high(&mut self, i: u8); - } +/// Some alternate mode (type state) +pub struct Alternate(PhantomData); - pub trait Pupdr { - fn floating(&mut self, i: u8); - fn pull_up(&mut self, i: u8); - fn pull_down(&mut self, i: u8); - } +/// Input mode (type state) +pub struct Input; - pub trait Afr { - fn afx(&mut self, i: u8, x: u8); - } +/// Pull setting for an input. +#[derive(Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Pull { + /// Floating + None = 0, + /// Pulled up + Up = 1, + /// Pulled down + Down = 2, +} - pub trait Gpio { - type Reg: GpioRegExt + ?Sized; +/// Open drain input or output (type state) +pub struct OpenDrain; - fn ptr(&self) -> *const Self::Reg; - fn port_index(&self) -> u8; - } +/// Output mode (type state) +pub struct Output { + _mode: PhantomData, } -use private::{Afr, GpioRegExt, Moder, Ospeedr, Otyper, Pupdr}; - -/// Marker traits used in this module -pub mod marker { - /// Marker trait for GPIO ports - pub trait Gpio: super::private::Gpio {} - - /// Marker trait for compile time defined GPIO ports - pub trait GpioStatic: Gpio { - /// Associated MODER register - type MODER: super::Moder; - /// Associated OTYPER register - type OTYPER: super::Otyper; - /// Associated OSPEEDR register - type OSPEEDR: super::Ospeedr; - /// Associated PUPDR register - type PUPDR: super::Pupdr; - } +/// Push pull output (type state) +pub struct PushPull; - /// Marker trait for pin number - pub trait Index { - #[doc(hidden)] - fn index(&self) -> u8; - } +/// Analog mode (type state) +pub struct Analog; + +pub type Debugger = Alternate<0, PushPull>; +mod sealed { + /// Marker trait that show if `ExtiPin` can be implemented + pub trait Interruptable {} /// Marker trait for readable pin modes pub trait Readable {} - /// Marker trait for slew rate configurable pin modes pub trait OutputSpeed {} - /// Marker trait for active pin modes pub trait Active {} - - /// Marker trait for pins with alternate function `A` mapping - pub trait IntoAf { - /// Associated AFR register - type AFR: super::Afr; - } -} - -/// Runtime defined GPIO port (type state) -#[derive(Debug)] -pub struct Gpiox { - ptr: *const dyn GpioRegExt, - index: u8, -} - -#[cfg(feature = "defmt")] -impl defmt::Format for Gpiox { - fn format(&self, f: defmt::Formatter) { - defmt::write!(f, "Gpiox {{ ptr: GpioRegExt , index: {:?} }}", self.index); - } -} - -// # SAFETY -// As Gpiox uses `dyn GpioRegExt` pointer internally, `Send` is not auto-implemented. -// But since GpioExt does only do atomic operations without side-effects we can assume -// that it safe to `Send` this type. -unsafe impl Send for Gpiox {} - -// # SAFETY -// As Gpiox uses `dyn GpioRegExt` pointer internally, `Sync` is not auto-implemented. -// But since GpioExt does only do atomic operations without side-effects we can assume -// that it safe to `Send` this type. -unsafe impl Sync for Gpiox {} - -impl private::Gpio for Gpiox { - type Reg = dyn GpioRegExt; - - fn ptr(&self) -> *const Self::Reg { - self.ptr - } - - fn port_index(&self) -> u8 { - self.index - } + /// Marker trait for all pin modes except alternate + pub trait NotAlt {} } -impl marker::Gpio for Gpiox {} - -/// Runtime defined pin number (type state) -// TODO(Sh3Rm4n): If the pin number wouldn't be runtime defined, the implementation for all -// statically defined pins would be much easier (and withless overhead). What could be the -// solution? -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Ux(u8); - -impl marker::Index for Ux { - fn index(&self) -> u8 { - self.0 - } -} - -/// Compile time defined pin number (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct U; - -impl marker::Index for U { - #[inline(always)] - fn index(&self) -> u8 { - X - } -} - -/// Input mode (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Input; -/// Output mode (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Output(PhantomData); -/// Alternate function (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Alternate(PhantomData); -/// Analog mode (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Analog; - -/// Push-pull output (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct PushPull; -/// Open-drain output (type state) -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct OpenDrain; - -impl marker::Readable for Input {} -impl marker::Readable for Output {} -impl marker::OutputSpeed for Output {} -impl marker::OutputSpeed for Alternate {} -impl marker::Active for Input {} -impl marker::Active for Output {} -impl marker::Active for Alternate {} - -/// Slew rate configuration -#[derive(Copy, Clone, PartialEq, Eq)] +impl sealed::Readable for Input {} +impl sealed::Readable for Output {} +impl sealed::Active for Input {} +impl sealed::OutputSpeed for Output {} +impl sealed::OutputSpeed for Alternate {} +impl sealed::Active for Output {} +impl sealed::Active for Alternate {} +impl sealed::NotAlt for Input {} +impl sealed::NotAlt for Output {} +impl sealed::NotAlt for Analog {} + +/// GPIO Pin speed selection #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { - /// Low speed - Low, - /// Medium speed - Medium, - /// High speed - High, -} - -/// Internal pull-up and pull-down resistor configuration -#[derive(Copy, Clone, PartialEq, Eq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum Resistor { - /// Floating - Floating, - /// Pulled up - PullUp, - /// Pulled down - PullDown, + Low = 0, + Medium = 1, + High = 3, } -/// GPIO interrupt trigger edge selection -#[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Edge { - /// Rising edge of voltage Rising, - /// Falling edge of voltage Falling, - /// Rising and falling edge of voltage RisingFalling, } -/// Generic pin -#[derive(Debug)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub struct Pin { - pub(crate) gpio: Gpio, - pub(crate) index: Index, - _mode: PhantomData, -} +use sealed::Interruptable; +impl Interruptable for Output {} +impl Interruptable for Input {} -// Make all GPIO peripheral trait extensions sealable. -impl crate::private::Sealed for Pin {} - -/// Fully erased pin -/// -/// This moves the pin type information to be known -/// at runtime, and erases the specific compile time type of the GPIO. -/// The only compile time information of the GPIO pin is it's Mode. -/// -/// See [examples/gpio_erased.rs] as an example. -/// -/// [examples/gpio_erased.rs]: https://github.com/stm32-rs/stm32f3xx-hal/blob/v0.9.1/examples/gpio_erased.rs -pub type PXx = Pin; - -impl Pin, Mode> { - /// Erases the pin number from the type - /// - /// This is useful when you want to collect the pins into an array where you - /// need all the elements to have the same type - pub fn downgrade(self) -> Pin { - Pin { - gpio: self.gpio, - index: Ux(X), - _mode: self._mode, - } - } -} - -impl Pin -where - Gpio: marker::GpioStatic, - Gpio::Reg: 'static + Sized, -{ - /// Erases the port letter from the type - /// - /// This is useful when you want to collect the pins into an array where you - /// need all the elements to have the same type - pub fn downgrade(self) -> PXx { - PXx { - gpio: Gpiox { - ptr: self.gpio.ptr(), - index: self.gpio.port_index(), - }, - index: self.index, - _mode: self._mode, - } - } -} - -impl Pin { - fn into_mode(self) -> Pin { - Pin { - gpio: self.gpio, - index: self.index, - _mode: PhantomData, - } - } -} +/// Opaque MODER register +pub struct MODER(()); -impl Pin -where - Gpio: marker::GpioStatic, - Index: marker::Index, -{ - /// Configures the pin to operate as an input pin - pub fn into_input(self, moder: &mut Gpio::MODER) -> Pin { - moder.input(self.index.index()); - self.into_mode() - } +/// Opaque OTYPER register +pub struct OTYPER(()); - /// Convenience method to configure the pin to operate as an input pin - /// and set the internal resistor floating - pub fn into_floating_input( - self, - moder: &mut Gpio::MODER, - pupdr: &mut Gpio::PUPDR, - ) -> Pin { - moder.input(self.index.index()); - pupdr.floating(self.index.index()); - self.into_mode() - } +/// Opaque OSPEEDR register +pub struct OSPEEDR(()); - /// Convenience method to configure the pin to operate as an input pin - /// and set the internal resistor pull-up - pub fn into_pull_up_input( - self, - moder: &mut Gpio::MODER, - pupdr: &mut Gpio::PUPDR, - ) -> Pin { - moder.input(self.index.index()); - pupdr.pull_up(self.index.index()); - self.into_mode() - } +/// Opaque PUPDR register +pub struct PUPDR(()); - /// Convenience method to configure the pin to operate as an input pin - /// and set the internal resistor pull-down - pub fn into_pull_down_input( - self, - moder: &mut Gpio::MODER, - pupdr: &mut Gpio::PUPDR, - ) -> Pin { - moder.input(self.index.index()); - pupdr.pull_down(self.index.index()); - self.into_mode() - } +/// Opaque AFR register +pub struct Afr(()); - /// Configures the pin to operate as a push-pull output pin - pub fn into_push_pull_output( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - ) -> Pin> { - moder.output(self.index.index()); - otyper.push_pull(self.index.index()); - self.into_mode() - } - - /// Configures the pin to operate as an open-drain output pin - pub fn into_open_drain_output( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - ) -> Pin> { - moder.output(self.index.index()); - otyper.open_drain(self.index.index()); - self.into_mode() - } - - /// Configures the pin to operate as an analog pin, with disabled schmitt trigger. - pub fn into_analog( - self, - moder: &mut Gpio::MODER, - pupdr: &mut Gpio::PUPDR, - ) -> Pin { - moder.analog(self.index.index()); - pupdr.floating(self.index.index()); - self.into_mode() - } +/// Represents high or low configuration register +pub trait HL { + /// Configuration register associated to pin + type Afr; } -impl Pin -where - Gpio: marker::GpioStatic, - Index: marker::Index, - Mode: marker::OutputSpeed, -{ - /// Set pin output slew rate - pub fn set_speed(&mut self, ospeedr: &mut Gpio::OSPEEDR, speed: Speed) { - match speed { - Speed::Low => ospeedr.low(self.index.index()), - Speed::Medium => ospeedr.medium(self.index.index()), - Speed::High => ospeedr.high(self.index.index()), - } - } -} - -impl Pin -where - Gpio: marker::GpioStatic, - Index: marker::Index, - Mode: marker::Active, -{ - /// Set the internal pull-up and pull-down resistor - pub fn set_internal_resistor(&mut self, pupdr: &mut Gpio::PUPDR, resistor: Resistor) { - match resistor { - Resistor::Floating => pupdr.floating(self.index.index()), - Resistor::PullUp => pupdr.pull_up(self.index.index()), - Resistor::PullDown => pupdr.pull_down(self.index.index()), - } - } +/// Marker trait for pins with alternate function `A` mapping +pub trait IntoAf: HL {} - /// Enables / disables the internal pull up (Provided for compatibility with other stm32 HALs) - pub fn internal_pull_up(&mut self, pupdr: &mut Gpio::PUPDR, on: bool) { - if on { - pupdr.pull_up(self.index.index()); - } else { - pupdr.floating(self.index.index()); - } - } -} - -impl OutputPin for Pin> -where - Gpio: marker::Gpio, - Index: marker::Index, -{ - type Error = Infallible; - - fn set_high(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*self.gpio.ptr()).set_high(self.index.index()) }; - Ok(()) - } - - fn set_low(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*self.gpio.ptr()).set_low(self.index.index()) }; - Ok(()) +macro_rules! cr { + ($high:literal: [$($i:literal),+]) => { + $( + impl HL for Pin { + type Afr = Afr; + } + )+ } } -impl InputPin for Pin -where - Gpio: marker::Gpio, - Index: marker::Index, - Mode: marker::Readable, -{ - type Error = Infallible; - - fn is_high(&self) -> Result { - Ok(!self.is_low()?) - } - - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*self.gpio.ptr()).is_low(self.index.index()) }) - } -} +cr!(false: [0, 1, 2, 3, 4, 5, 6, 7]); +cr!(true: [8, 9, 10, 11, 12, 13, 14, 15]); -impl StatefulOutputPin for Pin> -where - Gpio: marker::Gpio, - Index: marker::Index, -{ - fn is_set_high(&self) -> Result { - Ok(!self.is_set_low()?) - } +macro_rules! af { + ($i:literal, $AFi:ident) => { + #[doc = concat!("Alternate function ", $i, " (type state)" )] + pub type $AFi = Alternate<$i, Otype>; + }; - fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*self.gpio.ptr()).is_set_low(self.index.index()) }) - } + ([$($i:literal),+ $(,)?]) => { + paste::paste! { + $( + af!($i, []); + )+ + } + }; } -impl toggleable::Default for Pin> -where - Gpio: marker::Gpio, - Index: marker::Index, -{ -} +af!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); /// Return an EXTI register for the current CPU #[cfg(feature = "svd-f373")] @@ -570,11 +273,9 @@ macro_rules! reg_for_cpu { }; } -impl Pin +impl Pin where - Gpio: marker::Gpio, - Index: marker::Index, - Mode: marker::Active, + MODE: Interruptable, { /// NVIC interrupt number of interrupt from this pin /// @@ -583,7 +284,7 @@ where // TODO(Sh3rm4n): It would be cool to have this either const or have a const function. // But this is currenlty not possible, because index() is runtime defined. pub fn interrupt(&self) -> Interrupt { - match self.index.index() { + match N { 0 => Interrupt::EXTI0, 1 => Interrupt::EXTI1, #[cfg(feature = "svd-f373")] @@ -604,7 +305,6 @@ where /// Generate interrupt on rising edge, falling edge, or both pub fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) { const BITWIDTH: u8 = 1; - let index = self.index.index(); let (rise, fall) = match edge { Edge::Rising => (true as u32, false as u32), Edge::Falling => (false as u32, true as u32), @@ -612,8 +312,8 @@ where }; // SAFETY: Unguarded write to the register, but behind a &mut unsafe { - crate::modify_at!(reg_for_cpu!(exti, rtsr), BITWIDTH, index, rise); - crate::modify_at!(reg_for_cpu!(exti, ftsr), BITWIDTH, index, fall); + crate::modify_at!(reg_for_cpu!(exti, rtsr), BITWIDTH, N, rise); + crate::modify_at!(reg_for_cpu!(exti, ftsr), BITWIDTH, N, fall); } } @@ -629,10 +329,9 @@ where let enable: Switch = enable.into(); let enable: bool = enable.into(); - let index = self.index.index(); let value = u32::from(enable); // SAFETY: Unguarded write to the register, but behind a &mut - unsafe { crate::modify_at!(reg_for_cpu!(exti, imr), BITWIDTH, index, value) }; + unsafe { crate::modify_at!(reg_for_cpu!(exti, imr), BITWIDTH, N, value) }; } /// Enable external interrupts from this pin @@ -653,253 +352,269 @@ where /// Clear the interrupt pending bit for this pin pub fn clear_interrupt(&mut self) { // SAFETY: Atomic write to register without side-effects. - unsafe { reg_for_cpu!((*EXTI::ptr()), pr).write(|w| w.bits(1 << self.index.index())) }; + unsafe { reg_for_cpu!((*EXTI::ptr()), pr).write(|w| w.bits(1 << N)) }; } /// Reads the interrupt pending bit for this pin pub fn is_interrupt_pending(&self) -> bool { // SAFETY: Atomic write to register without side-effects. - unsafe { reg_for_cpu!((*EXTI::ptr()), pr).read().bits() & (1 << self.index.index()) != 0 } + unsafe { reg_for_cpu!((*EXTI::ptr()), pr).read().bits() & (1 << N) != 0 } } } -impl Pin -where - Gpio: marker::GpioStatic, - Index: marker::Index, -{ - /// Configures the pin to operate as an alternate function push-pull output pin - pub fn into_af_push_pull( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - afr: &mut >::AFR, - ) -> Pin> - where - Self: marker::IntoAf, - { - moder.alternate(self.index.index()); - otyper.push_pull(self.index.index()); - afr.afx(self.index.index(), A); - self.into_mode() +/// Generic pin type +/// +/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). +/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. +/// - `N` is pin number: from `0` to `15`. +pub struct Pin { + _mode: PhantomData, +} +impl Pin { + const fn new() -> Self { + Self { _mode: PhantomData } } +} - /// Configures the pin to operate as an alternate function open-drain output pin - pub fn into_af_open_drain( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - afr: &mut >::AFR, - ) -> Pin> - where - Self: marker::IntoAf, - { - moder.alternate(self.index.index()); - otyper.open_drain(self.index.index()); - afr.afx(self.index.index(), A); - self.into_mode() +impl fmt::Debug for Pin { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_fmt(format_args!( + "P{}{}<{}>", + P, + N, + crate::stripped_type_name::() + )) } } -macro_rules! af { - ($i:literal, $AFi:ident, $into_afi_push_pull:ident, $into_afi_open_drain:ident) => { - #[doc = concat!("Alternate function ", $i, " (type state)" )] - pub type $AFi = Alternate; - - impl Pin - where - Self: marker::IntoAf<$i>, - Gpio: marker::GpioStatic, - Index: marker::Index, - { - /// Configures the pin to operate as an alternate function push-pull output pin - #[deprecated(since = "0.9.0", note = "Will be removed with the next version. Use `into_af_push_pull()` instead")] - pub fn $into_afi_push_pull( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - afr: &mut >::AFR, - ) -> Pin> { - self.into_af_push_pull::<$i>(moder, otyper, afr) - } +#[cfg(feature = "defmt")] +impl defmt::Format for Pin { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "P{}{}<{}>", P, N, crate::stripped_type_name::()); + } +} - /// Configures the pin to operate as an alternate function open-drain output pin - #[deprecated(since = "0.9.0", note = "Will be removed with the next version. Use `into_af_open_drain()` instead")] - pub fn $into_afi_open_drain( - self, - moder: &mut Gpio::MODER, - otyper: &mut Gpio::OTYPER, - afr: &mut >::AFR, - ) -> Pin> { - self.into_af_open_drain::<$i>(moder, otyper, afr) - } - } - }; +impl PinExt for Pin { + type Mode = MODE; - ([$($i:literal),+ $(,)?]) => { - paste::paste! { - $( - af!($i, [], [], []); - )+ - } - }; + #[inline(always)] + fn pin_id(&self) -> u8 { + N + } + #[inline(always)] + fn port_id(&self) -> u8 { + P as u8 - b'A' + } } -af!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); +impl Pin +where + MODE: sealed::OutputSpeed, +{ + /// Set pin speed + pub fn set_speed(&mut self, _ospeedr: &mut OSPEEDR

, speed: Speed) { + let offset = 2 * { N }; -macro_rules! gpio_trait { - ([$($gpioy:ident),+ $(,)?]) => { - $( - impl GpioRegExt for crate::pac::$gpioy::RegisterBlock { - #[inline(always)] - fn is_low(&self, i: u8) -> bool { - self.idr.read().bits() & (1 << i) == 0 - } + unsafe { + (*Gpio::

::ptr()) + .ospeedr + .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset))); + } + } - #[inline(always)] - fn is_set_low(&self, i: u8) -> bool { - self.odr.read().bits() & (1 << i) == 0 - } + /// Set pin speed + pub fn speed(mut self, ospeedr: &mut OSPEEDR

, speed: Speed) -> Self { + self.set_speed(ospeedr, speed); + self + } +} - #[inline(always)] - fn set_high(&self, i: u8) { - // NOTE(unsafe, write) atomic write to a stateless register - unsafe { self.bsrr.write(|w| w.bits(1 << i)) }; - } +impl Pin +where + MODE: sealed::Active, +{ + /// Set the internal pull-up and pull-down resistor + pub fn set_internal_resistor(&mut self, _pupdr: &mut PUPDR

, resistor: Pull) { + let offset = 2 * { N }; + let value = resistor as u32; + unsafe { + (*Gpio::

::ptr()) + .pupdr + .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (value << offset))) + }; + } - #[inline(always)] - fn set_low(&self, i: u8) { - // NOTE(unsafe, write) atomic write to a stateless register - unsafe { self.bsrr.write(|w| w.bits(1 << (16 + i))) }; - } - } - )+ - }; -} + /// Set the internal pull-up and pull-down resistor + pub fn internal_resistor(mut self, pupdr: &mut PUPDR

, resistor: Pull) -> Self { + self.set_internal_resistor(pupdr, resistor); + self + } -/// Implement private::{Moder, Ospeedr, Otyper, Pupdr} traits for each opaque register structs -macro_rules! r_trait { - ( - ($GPIOX:ident, $gpioy:ident::$xr:ident::$enum:ident, $bitwidth:expr); - impl $Xr:ident for $XR:ty { - $( - fn $fn:ident { $VARIANT:ident } - )+ + /// Enables / disables the internal pull up + pub fn internal_pull_up(self, pupdr: &mut PUPDR

, on: bool) -> Self { + if on { + self.internal_resistor(pupdr, Pull::Up) + } else { + self.internal_resistor(pupdr, Pull::None) } - ) => { - impl $Xr for $XR { - $( - #[inline] - fn $fn(&mut self, i: u8) { - let value = $gpioy::$xr::$enum::$VARIANT as u32; - unsafe { crate::modify_at!((*$GPIOX::ptr()).$xr, $bitwidth, i, value) }; - } - )+ + } + + /// Enables / disables the internal pull down + pub fn internal_pull_down(self, pupdr: &mut PUPDR

, on: bool) -> Self { + if on { + self.internal_resistor(pupdr, Pull::Down) + } else { + self.internal_resistor(pupdr, Pull::None) } - }; + } } -macro_rules! gpio { - ({ - GPIO: $GPIOX:ident, - gpio: $gpiox:ident, - Gpio: $Gpiox:ident, - port_index: $port_index:literal, - gpio_mapped: $gpioy:ident, - partially_erased_pin: $PXx:ident, - pins: [$( - $i:literal => ( - $PXi:ident, $pxi:ident, $MODE:ty, $AFR:ident, [$($af:literal),*], - ), - )+], - }) => { - #[doc = concat!("GPIO port ", stringify!($GPIOX), " (type state)")] - #[derive(Debug)] - #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub struct $Gpiox; - - impl private::Gpio for $Gpiox { - type Reg = crate::pac::$gpioy::RegisterBlock; - - #[inline(always)] - fn ptr(&self) -> *const Self::Reg { - crate::pac::$GPIOX::ptr() - } +impl Pin { + /// Erases the pin number from the type + /// + /// This is useful when you want to collect the pins into an array where you + /// need all the elements to have the same type + pub fn erase_number(self) -> PEPin { + PEPin::new(N) + } - #[inline(always)] - fn port_index(&self) -> u8 { - $port_index - } + /// Erases the pin number and the port from the type + /// + /// This is useful when you want to collect the pins into an array where you + /// need all the elements to have the same type + pub fn erase(self) -> EPin { + EPin::new(P as u8 - b'A', N) + } +} + +impl Pin { + /// Set the output of the pin regardless of its mode. + /// Primarily used to set the output value of the pin + /// before changing its mode to an output to avoid + /// a short spike of an incorrect value + #[inline(always)] + fn _set_state(&mut self, state: PinState) { + match state { + PinState::High => self._set_high(), + PinState::Low => self._set_low(), } + } + #[inline(always)] + fn _set_high(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << N)) } + } + #[inline(always)] + fn _set_low(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << (16 + N))) } + } + #[inline(always)] + fn _is_set_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << N) == 0 } + } + #[inline(always)] + fn _is_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << N) == 0 } + } +} - impl marker::Gpio for $Gpiox {} +impl Pin> { + #[inline(always)] + pub fn set_high(&mut self) { + self._set_high() + } - impl marker::GpioStatic for $Gpiox { - type MODER = $gpiox::MODER; - type OTYPER = $gpiox::OTYPER; - type OSPEEDR = $gpiox::OSPEEDR; - type PUPDR = $gpiox::PUPDR; - } + #[inline(always)] + pub fn set_low(&mut self) { + self._set_low() + } - $( - #[doc = concat!("Pin ", stringify!($PXi))] - pub type $PXi = Pin<$Gpiox, U<$i>, Mode>; + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } - $( - impl marker::IntoAf<$af> for $PXi { - type AFR = $gpiox::$AFR; - } - )* - )+ + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } - #[doc = concat!("Partially erased pin for ", stringify!($GPIOX))] - pub type $PXx = Pin<$Gpiox, Ux, Mode>; + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } - #[doc = concat!("All Pins and associated registers for GPIO port ", stringify!($GPIOX))] - pub mod $gpiox { - use core::marker::PhantomData; + #[inline(always)] + pub fn is_set_low(&self) -> bool { + self._is_set_low() + } - use crate::{ - pac::{$gpioy, $GPIOX}, - rcc::{AHB, Enable, Reset}, - }; + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} - use super::{Afr, $Gpiox, GpioExt, Moder, Ospeedr, Otyper, Pupdr, U}; +impl Pin +where + MODE: sealed::Readable, +{ + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } - #[allow(unused_imports)] - use super::{ - Input, Output, Analog, PushPull, OpenDrain, - AF0, AF1, AF2, AF3, AF4, AF5, AF6, AF7, AF8, AF9, AF10, AF11, AF12, AF13, AF14, AF15, - }; + #[inline(always)] + pub fn is_low(&self) -> bool { + self._is_low() + } +} - pub use super::{ - $PXx, - $( - $PXi, - )+ - }; +macro_rules! gpio { + ($GPIOX:ident, $gpiox:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [ + $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+ + ]) => { + /// GPIO + pub mod $gpiox { + use crate::pac::$GPIOX; + use crate::rcc::{Enable, Reset, AHB}; + use super::{Afr, Input, MODER, OTYPER, OSPEEDR, PUPDR, IntoAf}; /// GPIO parts pub struct Parts { /// Opaque AFRH register - pub afrh: AFRH, + pub afrh: Afr<$port_id, true>, /// Opaque AFRL register - pub afrl: AFRL, + pub afrl: Afr<$port_id, false>, /// Opaque MODER register - pub moder: MODER, - /// Opaque OSPEEDR register - pub ospeedr: OSPEEDR, + pub moder: MODER<$port_id>, /// Opaque OTYPER register - pub otyper: OTYPER, + pub otyper: OTYPER<$port_id>, + /// Opaque OSPEEDR register + pub ospeedr: OSPEEDR<$port_id>, /// Opaque PUPDR register - pub pupdr: PUPDR, + pub pupdr: PUPDR<$port_id>, $( - #[doc = concat!("Pin ", stringify!($PXi))] - pub $pxi: $PXi<$MODE>, + /// Pin + pub $pxi: $PXi $(<$MODE>)?, )+ } - impl GpioExt for $GPIOX { + impl super::GpioExt for $GPIOX { type Parts = Parts; fn split(self, ahb: &mut AHB) -> Parts { @@ -907,703 +622,563 @@ macro_rules! gpio { <$GPIOX>::reset(ahb); Parts { - afrh: AFRH(()), - afrl: AFRL(()), + afrh: Afr(()), + afrl: Afr(()), moder: MODER(()), - ospeedr: OSPEEDR(()), otyper: OTYPER(()), + ospeedr: OSPEEDR(()), pupdr: PUPDR(()), $( - $pxi: $PXi { - gpio: $Gpiox, - index: U::<$i>, - _mode: PhantomData, - }, + $pxi: $PXi::new(), )+ } } } - /// Opaque AFRH register - pub struct AFRH(()); + pub type $PXn = super::PEPin<$port_id, MODE>; - impl Afr for AFRH { - #[inline] - fn afx(&mut self, i: u8, x: u8) { - const BITWIDTH: u8 = 4; - unsafe { crate::modify_at!((*$GPIOX::ptr()).afrh, BITWIDTH, i - 8, x as u32) }; - } - } + $( + pub type $PXi = super::Pin<$port_id, $i, MODE>; - /// Opaque AFRL register - pub struct AFRL(()); + $( + impl IntoAf<$A> for $PXi { } + )* + )+ - impl Afr for AFRL { - #[inline] - fn afx(&mut self, i: u8, x: u8) { - const BITWIDTH: u8 = 4; - unsafe { crate::modify_at!((*$GPIOX::ptr()).afrl, BITWIDTH, i, x as u32) }; - } - } + } - /// Opaque MODER register - pub struct MODER(()); + pub use $gpiox::{ $($PXi,)+ }; + } +} - r_trait! { - ($GPIOX, $gpioy::moder::MODER15_A, 2); - impl Moder for MODER { - fn input { Input } - fn output { Output } - fn alternate { Alternate } - fn analog { Analog } - } - } +#[cfg(feature = "gpio-f302")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 3, 7, 15]), + PA1: (pa1, 1, [0, 1, 3, 7, 9, 15]), + PA2: (pa2, 2, [1, 3, 7, 8, 9, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 15]), + PA4: (pa4, 4, [3, 6, 7, 15]), + PA5: (pa5, 5, [1, 3, 15]), + PA6: (pa6, 6, [1, 3, 6, 15]), + PA7: (pa7, 7, [1, 3, 6, 15]), + PA8: (pa8, 8, [0, 3, 4, 5, 6, 7, 15]), + PA9: (pa9, 9, [2, 3, 4, 5, 6, 7, 9, 10, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 8, 10, 15]), + PA11: (pa11, 11, [5, 6, 7, 9, 11, 12, 15]), + PA12: (pa12, 12, [1, 5, 6, 7, 8, 9, 11, 15]), + PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 3, 4, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp +]); - /// Opaque OSPEEDR register - pub struct OSPEEDR(()); +#[cfg(feature = "gpio-f302")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [3, 6, 15]), + PB1: (pb1, 1, [3, 6, 8, 15]), + PB2: (pb2, 2, [3, 15]), + PB3: (pb3, 3, [0, 1, 3, 6, 7, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 3, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 4, 6, 7, 8, 10, 15]), + PB6: (pb6, 6, [1, 3, 4, 7, 15]), + PB7: (pb7, 7, [1, 3, 4, 7, 15]), + PB8: (pb8, 8, [1, 3, 4, 7, 9, 12, 15]), + PB9: (pb9, 9, [1, 4, 6, 7, 8, 9, 15]), + PB10: (pb10, 10, [1, 3, 7, 15]), + PB11: (pb11, 11, [1, 3, 7, 15]), + PB12: (pb12, 12, [3, 4, 5, 6, 7, 15]), + PB13: (pb13, 13, [3, 5, 6, 7, 15]), + PB14: (pb14, 14, [1, 3, 5, 6, 7, 15]), + PB15: (pb15, 15, [0, 1, 2, 4, 5, 15]), +]); - r_trait! { - ($GPIOX, $gpioy::ospeedr::OSPEEDR15_A, 2); - impl Ospeedr for OSPEEDR { - fn low { LowSpeed } - fn medium { MediumSpeed } - fn high { HighSpeed } - } - } +#[cfg(feature = "gpio-f302")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2]), + PC1: (pc1, 1, [1, 2]), + PC2: (pc2, 2, [1, 2]), + PC3: (pc3, 3, [1, 2, 6]), + PC4: (pc4, 4, [1, 2, 7]), + PC5: (pc5, 5, [1, 2, 3, 7]), + PC6: (pc6, 6, [1, 6, 7]), + PC7: (pc7, 7, [1, 6]), + PC8: (pc8, 8, [1]), + PC9: (pc9, 9, [1, 3, 5]), + PC10: (pc10, 10, [1, 6, 7]), + PC11: (pc11, 11, [1, 6, 7]), + PC12: (pc12, 12, [1, 6, 7]), + PC13: (pc13, 13, [4]), + PC14: (pc14, 14, []), + PC15: (pc15, 15, []), +]); - /// Opaque OTYPER register - pub struct OTYPER(()); +#[cfg(feature = "gpio-f302")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD2: (pd2, 2, [1]), +]); - r_trait! { - ($GPIOX, $gpioy::otyper::OT15_A, 1); - impl Otyper for OTYPER { - fn push_pull { PushPull } - fn open_drain { OpenDrain } - } - } +#[cfg(feature = "gpio-f302")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 5, 6]), + PF1: (pf1, 1, [4, 5]), +]); - /// Opaque PUPDR register - pub struct PUPDR(()); +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), + PA1: (pa1, 1, [0, 1, 3, 7, 9, 15]), + PA2: (pa2, 2, [1, 3, 7, 8, 9, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 15]), + PA4: (pa4, 4, [2, 3, 5, 6, 7, 15]), + PA5: (pa5, 5, [1, 3, 5, 15]), + PA6: (pa6, 6, [1, 2, 3, 4, 5, 6, 8, 15]), + PA7: (pa7, 7, [1, 2, 3, 4, 5, 6, 15]), + PA8: (pa8, 8, [0, 3, 4, 5, 6, 7, 8, 10, 15]), + PA9: (pa9, 9, [2, 3, 4, 5, 6, 7, 8, 9, 10, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 8, 10, 11, 15]), + PA11: (pa11, 11, [5, 6, 7, 8, 9, 10, 11, 12, 15]), + PA12: (pa12, 12, [1, 5, 6, 7, 8, 9, 10, 11, 15]), + PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 2, 3, 4, 5, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp +]); - r_trait! { - ($GPIOX, $gpioy::pupdr::PUPDR15_A, 2); - impl Pupdr for PUPDR { - fn floating { Floating } - fn pull_up { PullUp } - fn pull_down { PullDown } - } - } - } - }; +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 3, 4, 6, 15]), + PB1: (pb1, 1, [2, 3, 4, 6, 8, 15]), + PB2: (pb2, 2, [3, 15]), + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 10, 15]), + PB6: (pb6, 6, [1, 2, 3, 4, 5, 6, 7, 10, 15]), + PB7: (pb7, 7, [1, 2, 3, 4, 5, 7, 10, 12, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 7, 8, 9, 10, 12, 15]), + PB9: (pb9, 9, [1, 2, 4, 6, 7, 8, 9, 10, 15]), + PB10: (pb10, 10, [1, 3, 7, 15]), + PB11: (pb11, 11, [1, 3, 7, 15]), + PB12: (pb12, 12, [3, 4, 5, 6, 7, 15]), + PB13: (pb13, 13, [3, 5, 6, 7, 15]), + PB14: (pb14, 14, [1, 3, 5, 6, 7, 15]), + PB15: (pb15, 15, [0, 1, 2, 4, 5, 15]), +]); - ({ - pacs: $pacs:tt, - ports: [$( - { - port: ($X:ident/$x:ident, $port_index:literal, $gpioy:ident), - pins: [$( - $i:literal => { - reset: $MODE:ty, - afr: $LH:ident, - af: [$($af:literal),*] - }, - )+], - }, - )+], - }) => { - paste::paste! { - gpio_trait!($pacs); - $( - gpio!({ - GPIO: [], - gpio: [], - Gpio: [], - port_index: $port_index, - gpio_mapped: $gpioy, - partially_erased_pin: [

], - pins: [$( - $i => ( - [

], [

], $MODE, [], [$($af),*], - ), - )+], - }); - )+ - } - }; -} -// auto-generated using codegen -// STM32CubeMX DB release: DB.6.0.10 +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2]), + PC1: (pc1, 1, [1, 2]), + PC2: (pc2, 2, [1, 2, 3]), + PC3: (pc3, 3, [1, 2, 6]), + PC4: (pc4, 4, [1, 2, 7]), + PC5: (pc5, 5, [1, 2, 3, 7]), + PC6: (pc6, 6, [1, 2, 4, 6, 7]), + PC7: (pc7, 7, [1, 2, 4, 6, 7]), + PC8: (pc8, 8, [1, 2, 4, 7]), + PC9: (pc9, 9, [1, 2, 3, 4, 5, 6]), + PC10: (pc10, 10, [1, 4, 5, 6, 7]), + PC11: (pc11, 11, [1, 4, 5, 6, 7]), + PC12: (pc12, 12, [1, 4, 5, 6, 7]), + PC13: (pc13, 13, [1, 4]), + PC14: (pc14, 14, [1]), + PC15: (pc15, 15, [1]), +]); -#[cfg(feature = "gpio-f302")] -gpio!({ - pacs: [gpioa, gpiob, gpioc], - ports: [ - { - port: (A/a, 0, gpioa), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 3, 7, 15] }, - 1 => { reset: Input, afr: L, af: [0, 1, 3, 7, 9, 15] }, - 2 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 15] }, - 3 => { reset: Input, afr: L, af: [1, 3, 7, 9, 15] }, - 4 => { reset: Input, afr: L, af: [3, 6, 7, 15] }, - 5 => { reset: Input, afr: L, af: [1, 3, 15] }, - 6 => { reset: Input, afr: L, af: [1, 3, 6, 15] }, - 7 => { reset: Input, afr: L, af: [1, 3, 6, 15] }, - 8 => { reset: Input, afr: H, af: [0, 3, 4, 5, 6, 7, 15] }, - 9 => { reset: Input, afr: H, af: [2, 3, 4, 5, 6, 7, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 4, 5, 6, 7, 8, 10, 15] }, - 11 => { reset: Input, afr: H, af: [5, 6, 7, 9, 11, 12, 15] }, - 12 => { reset: Input, afr: H, af: [1, 5, 6, 7, 8, 9, 11, 15] }, - 13 => { reset: AF0, afr: H, af: [0, 1, 3, 5, 7, 15] }, - 14 => { reset: AF0, afr: H, af: [0, 3, 4, 6, 7, 15] }, - 15 => { reset: AF0, afr: H, af: [0, 1, 3, 4, 6, 7, 9, 15] }, - ], - }, - { - port: (B/b, 1, gpiob), - pins: [ - 0 => { reset: Input, afr: L, af: [3, 6, 15] }, - 1 => { reset: Input, afr: L, af: [3, 6, 8, 15] }, - 2 => { reset: Input, afr: L, af: [3, 15] }, - 3 => { reset: AF0, afr: L, af: [0, 1, 3, 6, 7, 15] }, - 4 => { reset: AF0, afr: L, af: [0, 1, 3, 6, 7, 10, 15] }, - 5 => { reset: Input, afr: L, af: [1, 4, 6, 7, 8, 10, 15] }, - 6 => { reset: Input, afr: L, af: [1, 3, 4, 7, 15] }, - 7 => { reset: Input, afr: L, af: [1, 3, 4, 7, 15] }, - 8 => { reset: Input, afr: H, af: [1, 3, 4, 7, 9, 12, 15] }, - 9 => { reset: Input, afr: H, af: [1, 4, 6, 7, 8, 9, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 11 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 12 => { reset: Input, afr: H, af: [3, 4, 5, 6, 7, 15] }, - 13 => { reset: Input, afr: H, af: [3, 5, 6, 7, 15] }, - 14 => { reset: Input, afr: H, af: [1, 3, 5, 6, 7, 15] }, - 15 => { reset: Input, afr: H, af: [0, 1, 2, 4, 5, 15] }, - ], - }, - { - port: (C/c, 2, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2] }, - 1 => { reset: Input, afr: L, af: [1, 2] }, - 2 => { reset: Input, afr: L, af: [1, 2] }, - 3 => { reset: Input, afr: L, af: [1, 2, 6] }, - 4 => { reset: Input, afr: L, af: [1, 2, 7] }, - 5 => { reset: Input, afr: L, af: [1, 2, 3, 7] }, - 6 => { reset: Input, afr: L, af: [1, 6, 7] }, - 7 => { reset: Input, afr: L, af: [1, 6] }, - 8 => { reset: Input, afr: H, af: [1] }, - 9 => { reset: Input, afr: H, af: [1, 3, 5] }, - 10 => { reset: Input, afr: H, af: [1, 6, 7] }, - 11 => { reset: Input, afr: H, af: [1, 6, 7] }, - 12 => { reset: Input, afr: H, af: [1, 6, 7] }, - 13 => { reset: Input, afr: H, af: [4] }, - 14 => { reset: Input, afr: H, af: [] }, - 15 => { reset: Input, afr: H, af: [] }, - ], - }, - { - port: (D/d, 3, gpioc), - pins: [ - 2 => { reset: Input, afr: L, af: [1] }, - ], - }, - { - port: (F/f, 5, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [4, 5, 6] }, - 1 => { reset: Input, afr: L, af: [4, 5] }, - ], - }, - ], -}); +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [1, 7, 12]), + PD1: (pd1, 1, [1, 4, 6, 7, 12]), + PD2: (pd2, 2, [1, 2, 4, 5]), + PD3: (pd3, 3, [1, 2, 7, 12]), + PD4: (pd4, 4, [1, 2, 7, 12]), + PD5: (pd5, 5, [1, 7, 12]), + PD6: (pd6, 6, [1, 2, 7, 12]), + PD7: (pd7, 7, [1, 2, 7, 12]), + PD8: (pd8, 8, [1, 7, 12]), + PD9: (pd9, 9, [1, 7, 12]), + PD10: (pd10, 10, [1, 7, 12]), + PD11: (pd11, 11, [1, 7, 12]), + PD12: (pd12, 12, [1, 2, 3, 7, 12]), + PD13: (pd13, 13, [1, 2, 3, 12]), + PD14: (pd14, 14, [1, 2, 3, 12]), + PD15: (pd15, 15, [1, 2, 3, 6, 12]), +]); #[cfg(feature = "gpio-f303e")] -gpio!({ - pacs: [gpioa, gpiob, gpioc], - ports: [ - { - port: (A/a, 0, gpioa), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 10, 15] }, - 1 => { reset: Input, afr: L, af: [0, 1, 3, 7, 9, 15] }, - 2 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 15] }, - 3 => { reset: Input, afr: L, af: [1, 3, 7, 9, 15] }, - 4 => { reset: Input, afr: L, af: [2, 3, 5, 6, 7, 15] }, - 5 => { reset: Input, afr: L, af: [1, 3, 5, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 8, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 15] }, - 8 => { reset: Input, afr: H, af: [0, 3, 4, 5, 6, 7, 8, 10, 15] }, - 9 => { reset: Input, afr: H, af: [2, 3, 4, 5, 6, 7, 8, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 4, 5, 6, 7, 8, 10, 11, 15] }, - 11 => { reset: Input, afr: H, af: [5, 6, 7, 8, 9, 10, 11, 12, 15] }, - 12 => { reset: Input, afr: H, af: [1, 5, 6, 7, 8, 9, 10, 11, 15] }, - 13 => { reset: AF0, afr: H, af: [0, 1, 3, 5, 7, 10, 15] }, - 14 => { reset: AF0, afr: H, af: [0, 3, 4, 5, 6, 7, 15] }, - 15 => { reset: AF0, afr: H, af: [0, 1, 2, 3, 4, 5, 6, 7, 9, 15] }, - ], - }, - { - port: (B/b, 1, gpiob), - pins: [ - 0 => { reset: Input, afr: L, af: [2, 3, 4, 6, 15] }, - 1 => { reset: Input, afr: L, af: [2, 3, 4, 6, 8, 15] }, - 2 => { reset: Input, afr: L, af: [3, 15] }, - 3 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 4 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 5 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 7, 8, 10, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 7, 10, 12, 15] }, - 8 => { reset: Input, afr: H, af: [1, 2, 3, 4, 7, 8, 9, 10, 12, 15] }, - 9 => { reset: Input, afr: H, af: [1, 2, 4, 6, 7, 8, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 11 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 12 => { reset: Input, afr: H, af: [3, 4, 5, 6, 7, 15] }, - 13 => { reset: Input, afr: H, af: [3, 5, 6, 7, 15] }, - 14 => { reset: Input, afr: H, af: [1, 3, 5, 6, 7, 15] }, - 15 => { reset: Input, afr: H, af: [0, 1, 2, 4, 5, 15] }, - ], - }, - { - port: (C/c, 2, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2] }, - 1 => { reset: Input, afr: L, af: [1, 2] }, - 2 => { reset: Input, afr: L, af: [1, 2, 3] }, - 3 => { reset: Input, afr: L, af: [1, 2, 6] }, - 4 => { reset: Input, afr: L, af: [1, 2, 7] }, - 5 => { reset: Input, afr: L, af: [1, 2, 3, 7] }, - 6 => { reset: Input, afr: L, af: [1, 2, 4, 6, 7] }, - 7 => { reset: Input, afr: L, af: [1, 2, 4, 6, 7] }, - 8 => { reset: Input, afr: H, af: [1, 2, 4, 7] }, - 9 => { reset: Input, afr: H, af: [1, 2, 3, 4, 5, 6] }, - 10 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 11 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 12 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 13 => { reset: Input, afr: H, af: [1, 4] }, - 14 => { reset: Input, afr: H, af: [1] }, - 15 => { reset: Input, afr: H, af: [1] }, - ], - }, - { - port: (D/d, 3, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 7, 12] }, - 1 => { reset: Input, afr: L, af: [1, 4, 6, 7, 12] }, - 2 => { reset: Input, afr: L, af: [1, 2, 4, 5] }, - 3 => { reset: Input, afr: L, af: [1, 2, 7, 12] }, - 4 => { reset: Input, afr: L, af: [1, 2, 7, 12] }, - 5 => { reset: Input, afr: L, af: [1, 7, 12] }, - 6 => { reset: Input, afr: L, af: [1, 2, 7, 12] }, - 7 => { reset: Input, afr: L, af: [1, 2, 7, 12] }, - 8 => { reset: Input, afr: H, af: [1, 7, 12] }, - 9 => { reset: Input, afr: H, af: [1, 7, 12] }, - 10 => { reset: Input, afr: H, af: [1, 7, 12] }, - 11 => { reset: Input, afr: H, af: [1, 7, 12] }, - 12 => { reset: Input, afr: H, af: [1, 2, 3, 7, 12] }, - 13 => { reset: Input, afr: H, af: [1, 2, 3, 12] }, - 14 => { reset: Input, afr: H, af: [1, 2, 3, 12] }, - 15 => { reset: Input, afr: H, af: [1, 2, 3, 6, 12] }, - ], - }, - { - port: (E/e, 4, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 4, 6, 7, 12] }, - 1 => { reset: Input, afr: L, af: [1, 4, 6, 7, 12] }, - 2 => { reset: Input, afr: L, af: [0, 1, 2, 3, 5, 6, 12] }, - 3 => { reset: Input, afr: L, af: [0, 1, 2, 3, 5, 6, 12] }, - 4 => { reset: Input, afr: L, af: [0, 1, 2, 3, 5, 6, 12] }, - 5 => { reset: Input, afr: L, af: [0, 1, 2, 3, 5, 6, 12] }, - 6 => { reset: Input, afr: L, af: [0, 1, 5, 6, 12] }, - 7 => { reset: Input, afr: L, af: [1, 2, 12] }, - 8 => { reset: Input, afr: H, af: [1, 2, 12] }, - 9 => { reset: Input, afr: H, af: [1, 2, 12] }, - 10 => { reset: Input, afr: H, af: [1, 2, 12] }, - 11 => { reset: Input, afr: H, af: [1, 2, 5, 12] }, - 12 => { reset: Input, afr: H, af: [1, 2, 5, 12] }, - 13 => { reset: Input, afr: H, af: [1, 2, 5, 12] }, - 14 => { reset: Input, afr: H, af: [1, 2, 5, 6, 12] }, - 15 => { reset: Input, afr: H, af: [1, 2, 7, 12] }, - ], - }, - { - port: (F/f, 5, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 4, 5, 6] }, - 1 => { reset: Input, afr: L, af: [1, 4, 5] }, - 2 => { reset: Input, afr: L, af: [1, 2, 12] }, - 3 => { reset: Input, afr: L, af: [1, 2, 12] }, - 4 => { reset: Input, afr: L, af: [1, 2, 3, 12] }, - 5 => { reset: Input, afr: L, af: [1, 2, 12] }, - 6 => { reset: Input, afr: L, af: [1, 2, 4, 7, 12] }, - 7 => { reset: Input, afr: L, af: [1, 2, 12] }, - 8 => { reset: Input, afr: H, af: [1, 2, 12] }, - 9 => { reset: Input, afr: H, af: [1, 2, 3, 5, 12] }, - 10 => { reset: Input, afr: H, af: [1, 2, 3, 5, 12] }, - 11 => { reset: Input, afr: H, af: [1, 2] }, - 12 => { reset: Input, afr: H, af: [1, 2, 12] }, - 13 => { reset: Input, afr: H, af: [1, 2, 12] }, - 14 => { reset: Input, afr: H, af: [1, 2, 12] }, - 15 => { reset: Input, afr: H, af: [1, 2, 12] }, - ], - }, - { - port: (G/g, 6, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 12] }, - 1 => { reset: Input, afr: L, af: [1, 2, 12] }, - 2 => { reset: Input, afr: L, af: [1, 2, 12] }, - 3 => { reset: Input, afr: L, af: [1, 2, 12] }, - 4 => { reset: Input, afr: L, af: [1, 2, 12] }, - 5 => { reset: Input, afr: L, af: [1, 2, 12] }, - 6 => { reset: Input, afr: L, af: [1, 12] }, - 7 => { reset: Input, afr: L, af: [1, 12] }, - 8 => { reset: Input, afr: H, af: [1] }, - 9 => { reset: Input, afr: H, af: [1, 12] }, - 10 => { reset: Input, afr: H, af: [1, 12] }, - 11 => { reset: Input, afr: H, af: [1, 12] }, - 12 => { reset: Input, afr: H, af: [1, 12] }, - 13 => { reset: Input, afr: H, af: [1, 12] }, - 14 => { reset: Input, afr: H, af: [1, 12] }, - 15 => { reset: Input, afr: H, af: [1] }, - ], - }, - { - port: (H/h, 7, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 12] }, - 1 => { reset: Input, afr: L, af: [1, 2, 12] }, - 2 => { reset: Input, afr: L, af: [1] }, - ], - }, - ], -}); +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [1, 2, 4, 6, 7, 12]), + PE1: (pe1, 1, [1, 4, 6, 7, 12]), + PE2: (pe2, 2, [0, 1, 2, 3, 5, 6, 12]), + PE3: (pe3, 3, [0, 1, 2, 3, 5, 6, 12]), + PE4: (pe4, 4, [0, 1, 2, 3, 5, 6, 12]), + PE5: (pe5, 5, [0, 1, 2, 3, 5, 6, 12]), + PE6: (pe6, 6, [0, 1, 5, 6, 12]), + PE7: (pe7, 7, [1, 2, 12]), + PE8: (pe8, 8, [1, 2, 12]), + PE9: (pe9, 9, [1, 2, 12]), + PE10: (pe10, 10, [1, 2, 12]), + PE11: (pe11, 11, [1, 2, 5, 12]), + PE12: (pe12, 12, [1, 2, 5, 12]), + PE13: (pe13, 13, [1, 2, 5, 12]), + PE14: (pe14, 14, [1, 2, 5, 6, 12]), + PE15: (pe15, 15, [1, 2, 7, 12]), +]); + +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [1, 4, 5, 6]), + PF1: (pf1, 1, [1, 4, 5]), + PF2: (pf2, 2, [1, 2, 12]), + PF3: (pf3, 3, [1, 2, 12]), + PF4: (pf4, 4, [1, 2, 3, 12]), + PF5: (pf5, 5, [1, 2, 12]), + PF6: (pf6, 6, [1, 2, 4, 7, 12]), + PF7: (pf7, 7, [1, 2, 12]), + PF8: (pf8, 8, [1, 2, 12]), + PF9: (pf9, 9, [1, 2, 3, 5, 12]), + PF10: (pf10, 10, [1, 2, 3, 5, 12]), + PF11: (pf11, 11, [1, 2]), + PF12: (pf12, 12, [1, 2, 12]), + PF13: (pf13, 13, [1, 2, 12]), + PF14: (pf14, 14, [1, 2, 12]), + PF15: (pf15, 15, [1, 2, 12]), +]); + +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOG, gpiog, PG, 'G', PGn, [ + PG0: (pg0, 0, [1, 2, 12]), + PG1: (pg1, 1, [1, 2, 12]), + PG2: (pg2, 2, [1, 2, 12]), + PG3: (pg3, 3, [1, 2, 12]), + PG4: (pg4, 4, [1, 2, 12]), + PG5: (pg5, 5, [1, 2, 12]), + PG6: (pg6, 6, [1, 12]), + PG7: (pg7, 7, [1, 12]), + PG8: (pg8, 8, [1]), + PG9: (pg9, 9, [1, 12]), + PG10: (pg10, 10, [1, 12]), + PG11: (pg11, 11, [1, 12]), + PG12: (pg12, 12, [1, 12]), + PG13: (pg13, 13, [1, 12]), + PG14: (pg14, 14, [1, 12]), + PG15: (pg15, 15, [1]), +]); + +#[cfg(feature = "gpio-f303e")] +gpio!(GPIOH, gpioh, PH, 'H', PHn, [ + PH0: (ph0, 0, [1, 2, 12]), + PH1: (ph1, 1, [1, 2, 12]), + PH2: (ph2, 2, [1]), +]); + +#[cfg(feature = "gpio-f303")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), + PA1: (pa1, 1, [0, 1, 3, 7, 9, 15]), + PA2: (pa2, 2, [1, 3, 7, 8, 9, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 15]), + PA4: (pa4, 4, [2, 3, 5, 6, 7, 15]), + PA5: (pa5, 5, [1, 3, 5, 15]), + PA6: (pa6, 6, [1, 2, 3, 4, 5, 6, 8, 15]), + PA7: (pa7, 7, [1, 2, 3, 4, 5, 6, 8, 15]), + PA8: (pa8, 8, [0, 4, 5, 6, 7, 8, 10, 15]), + PA9: (pa9, 9, [3, 4, 5, 6, 7, 8, 9, 10, 15]), + PA10: (pa10, 10, [1, 3, 4, 6, 7, 8, 10, 11, 15]), + PA11: (pa11, 11, [6, 7, 8, 9, 10, 11, 12, 14, 15]), + PA12: (pa12, 12, [1, 6, 7, 8, 9, 10, 11, 14, 15]), + PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp +]); + +#[cfg(feature = "gpio-f303")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 3, 4, 6, 15]), + PB1: (pb1, 1, [2, 3, 4, 6, 8, 15]), + PB2: (pb2, 2, [3, 15]), + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 10, 15]), + PB6: (pb6, 6, [1, 2, 3, 4, 5, 6, 7, 10, 15]), + PB7: (pb7, 7, [1, 2, 3, 4, 5, 7, 10, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 8, 9, 10, 12, 15]), + PB9: (pb9, 9, [1, 2, 4, 6, 8, 9, 10, 15]), + PB10: (pb10, 10, [1, 3, 7, 15]), + PB11: (pb11, 11, [1, 3, 7, 15]), + PB12: (pb12, 12, [3, 4, 5, 6, 7, 15]), + PB13: (pb13, 13, [3, 5, 6, 7, 15]), + PB14: (pb14, 14, [1, 3, 5, 6, 7, 15]), + PB15: (pb15, 15, [0, 1, 2, 4, 5, 15]), +]); + +#[cfg(feature = "gpio-f303")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1]), + PC1: (pc1, 1, [1]), + PC2: (pc2, 2, [1, 3]), + PC3: (pc3, 3, [1, 6]), + PC4: (pc4, 4, [1, 7]), + PC5: (pc5, 5, [1, 3, 7]), + PC6: (pc6, 6, [1, 2, 4, 6, 7]), + PC7: (pc7, 7, [1, 2, 4, 6, 7]), + PC8: (pc8, 8, [1, 2, 4, 7]), + PC9: (pc9, 9, [1, 2, 4, 5, 6]), + PC10: (pc10, 10, [1, 4, 5, 6, 7]), + PC11: (pc11, 11, [1, 4, 5, 6, 7]), + PC12: (pc12, 12, [1, 4, 5, 6, 7]), + PC13: (pc13, 13, [4]), + PC14: (pc14, 14, []), + PC15: (pc15, 15, []), +]); #[cfg(feature = "gpio-f303")] -gpio!({ - pacs: [gpioa, gpiob, gpioc], - ports: [ - { - port: (A/a, 0, gpioa), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 10, 15] }, - 1 => { reset: Input, afr: L, af: [0, 1, 3, 7, 9, 15] }, - 2 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 15] }, - 3 => { reset: Input, afr: L, af: [1, 3, 7, 9, 15] }, - 4 => { reset: Input, afr: L, af: [2, 3, 5, 6, 7, 15] }, - 5 => { reset: Input, afr: L, af: [1, 3, 5, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 8, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 8, 15] }, - 8 => { reset: Input, afr: H, af: [0, 4, 5, 6, 7, 8, 10, 15] }, - 9 => { reset: Input, afr: H, af: [3, 4, 5, 6, 7, 8, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 4, 6, 7, 8, 10, 11, 15] }, - 11 => { reset: Input, afr: H, af: [6, 7, 8, 9, 10, 11, 12, 14, 15] }, - 12 => { reset: Input, afr: H, af: [1, 6, 7, 8, 9, 10, 11, 14, 15] }, - 13 => { reset: AF0, afr: H, af: [0, 1, 3, 5, 7, 10, 15] }, - 14 => { reset: AF0, afr: H, af: [0, 3, 4, 5, 6, 7, 15] }, - 15 => { reset: AF0, afr: H, af: [0, 1, 2, 4, 5, 6, 7, 9, 15] }, - ], - }, - { - port: (B/b, 1, gpiob), - pins: [ - 0 => { reset: Input, afr: L, af: [2, 3, 4, 6, 15] }, - 1 => { reset: Input, afr: L, af: [2, 3, 4, 6, 8, 15] }, - 2 => { reset: Input, afr: L, af: [3, 15] }, - 3 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 4 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 5 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 6, 7, 10, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 4, 5, 7, 10, 15] }, - 8 => { reset: Input, afr: H, af: [1, 2, 3, 4, 8, 9, 10, 12, 15] }, - 9 => { reset: Input, afr: H, af: [1, 2, 4, 6, 8, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 11 => { reset: Input, afr: H, af: [1, 3, 7, 15] }, - 12 => { reset: Input, afr: H, af: [3, 4, 5, 6, 7, 15] }, - 13 => { reset: Input, afr: H, af: [3, 5, 6, 7, 15] }, - 14 => { reset: Input, afr: H, af: [1, 3, 5, 6, 7, 15] }, - 15 => { reset: Input, afr: H, af: [0, 1, 2, 4, 5, 15] }, - ], - }, - { - port: (C/c, 2, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1] }, - 1 => { reset: Input, afr: L, af: [1] }, - 2 => { reset: Input, afr: L, af: [1, 3] }, - 3 => { reset: Input, afr: L, af: [1, 6] }, - 4 => { reset: Input, afr: L, af: [1, 7] }, - 5 => { reset: Input, afr: L, af: [1, 3, 7] }, - 6 => { reset: Input, afr: L, af: [1, 2, 4, 6, 7] }, - 7 => { reset: Input, afr: L, af: [1, 2, 4, 6, 7] }, - 8 => { reset: Input, afr: H, af: [1, 2, 4, 7] }, - 9 => { reset: Input, afr: H, af: [1, 2, 4, 5, 6] }, - 10 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 11 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 12 => { reset: Input, afr: H, af: [1, 4, 5, 6, 7] }, - 13 => { reset: Input, afr: H, af: [4] }, - 14 => { reset: Input, afr: H, af: [] }, - 15 => { reset: Input, afr: H, af: [] }, - ], - }, - { - port: (D/d, 3, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 7] }, - 1 => { reset: Input, afr: L, af: [1, 4, 6, 7] }, - 2 => { reset: Input, afr: L, af: [1, 2, 4, 5] }, - 3 => { reset: Input, afr: L, af: [1, 2, 7] }, - 4 => { reset: Input, afr: L, af: [1, 2, 7] }, - 5 => { reset: Input, afr: L, af: [1, 7] }, - 6 => { reset: Input, afr: L, af: [1, 2, 7] }, - 7 => { reset: Input, afr: L, af: [1, 2, 7] }, - 8 => { reset: Input, afr: H, af: [1, 7] }, - 9 => { reset: Input, afr: H, af: [1, 7] }, - 10 => { reset: Input, afr: H, af: [1, 7] }, - 11 => { reset: Input, afr: H, af: [1, 7] }, - 12 => { reset: Input, afr: H, af: [1, 2, 3, 7] }, - 13 => { reset: Input, afr: H, af: [1, 2, 3] }, - 14 => { reset: Input, afr: H, af: [1, 2, 3] }, - 15 => { reset: Input, afr: H, af: [1, 2, 3, 6] }, - ], - }, - { - port: (E/e, 4, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 4, 7] }, - 1 => { reset: Input, afr: L, af: [1, 4, 7] }, - 2 => { reset: Input, afr: L, af: [0, 1, 2, 3] }, - 3 => { reset: Input, afr: L, af: [0, 1, 2, 3] }, - 4 => { reset: Input, afr: L, af: [0, 1, 2, 3] }, - 5 => { reset: Input, afr: L, af: [0, 1, 2, 3] }, - 6 => { reset: Input, afr: L, af: [0, 1] }, - 7 => { reset: Input, afr: L, af: [1, 2] }, - 8 => { reset: Input, afr: H, af: [1, 2] }, - 9 => { reset: Input, afr: H, af: [1, 2] }, - 10 => { reset: Input, afr: H, af: [1, 2] }, - 11 => { reset: Input, afr: H, af: [1, 2] }, - 12 => { reset: Input, afr: H, af: [1, 2] }, - 13 => { reset: Input, afr: H, af: [1, 2] }, - 14 => { reset: Input, afr: H, af: [1, 2, 6] }, - 15 => { reset: Input, afr: H, af: [1, 2, 7] }, - ], - }, - { - port: (F/f, 5, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [4, 6] }, - 1 => { reset: Input, afr: L, af: [4] }, - 2 => { reset: Input, afr: L, af: [1] }, - 4 => { reset: Input, afr: L, af: [1, 2] }, - 6 => { reset: Input, afr: L, af: [1, 2, 4, 7] }, - 9 => { reset: Input, afr: H, af: [1, 3, 5] }, - 10 => { reset: Input, afr: H, af: [1, 3, 5] }, - ], - }, - ], -}); +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [1, 7]), + PD1: (pd1, 1, [1, 4, 6, 7]), + PD2: (pd2, 2, [1, 2, 4, 5]), + PD3: (pd3, 3, [1, 2, 7]), + PD4: (pd4, 4, [1, 2, 7]), + PD5: (pd5, 5, [1, 7]), + PD6: (pd6, 6, [1, 2, 7]), + PD7: (pd7, 7, [1, 2, 7]), + PD8: (pd8, 8, [1, 7]), + PD9: (pd9, 9, [1, 7]), + PD10: (pd10, 10, [1, 7]), + PD11: (pd11, 11, [1, 7]), + PD12: (pd12, 12, [1, 2, 3, 7]), + PD13: (pd13, 13, [1, 2, 3]), + PD14: (pd14, 14, [1, 2, 3]), + PD15: (pd15, 15, [1, 2, 3, 6]), +]); + +#[cfg(feature = "gpio-f303")] +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [1, 2, 4, 7]), + PE1: (pe1, 1, [1, 4, 7]), + PE2: (pe2, 2, [0, 1, 2, 3]), + PE3: (pe3, 3, [0, 1, 2, 3]), + PE4: (pe4, 4, [0, 1, 2, 3]), + PE5: (pe5, 5, [0, 1, 2, 3]), + PE6: (pe6, 6, [0, 1]), + PE7: (pe7, 7, [1, 2]), + PE8: (pe8, 8, [1, 2]), + PE9: (pe9, 9, [1, 2]), + PE10: (pe10, 10, [1, 2]), + PE11: (pe11, 11, [1, 2]), + PE12: (pe12, 12, [1, 2]), + PE13: (pe13, 13, [1, 2]), + PE14: (pe14, 14, [1, 2, 6]), + PE15: (pe15, 15, [1, 2, 7]), +]); + +#[cfg(feature = "gpio-f303")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 6]), + PF1: (pf1, 1, [4]), + PF2: (pf2, 2, [1]), + PF4: (pf4, 4, [1, 2]), + PF6: (pf6, 6, [1, 2, 4, 7]), + PF9: (pf9, 9, [1, 3, 5]), + PF10: (pf10, 10, [1, 3, 5]), +]); + +#[cfg(feature = "gpio-f333")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 3, 7, 15]), + PA1: (pa1, 1, [1, 3, 7, 9, 15]), + PA2: (pa2, 2, [1, 3, 7, 8, 9, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 15]), + PA4: (pa4, 4, [2, 3, 5, 7, 15]), + PA5: (pa5, 5, [1, 3, 5, 15]), + PA6: (pa6, 6, [1, 2, 3, 5, 6, 13, 15]), + PA7: (pa7, 7, [1, 2, 3, 5, 6, 15]), + PA8: (pa8, 8, [0, 6, 7, 13, 15]), + PA9: (pa9, 9, [3, 6, 7, 9, 10, 13, 15]), + PA10: (pa10, 10, [1, 3, 6, 7, 8, 10, 13, 15]), + PA11: (pa11, 11, [6, 7, 9, 11, 12, 13, 15]), + PA12: (pa12, 12, [1, 6, 7, 8, 9, 11, 13, 15]), + PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 3, 4, 5, 7, 9, 13, 15], super::Debugger), // JTDI, PullUp +]); + +#[cfg(feature = "gpio-f333")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 3, 6, 15]), + PB1: (pb1, 1, [2, 3, 6, 8, 13, 15]), + PB2: (pb2, 2, [3, 13, 15]), + PB3: (pb3, 3, [0, 1, 3, 5, 7, 10, 12, 13, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 2, 3, 5, 7, 10, 13, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 2, 4, 5, 7, 10, 13, 15]), + PB6: (pb6, 6, [1, 3, 4, 7, 12, 13, 15]), + PB7: (pb7, 7, [1, 3, 4, 7, 10, 13, 15]), + PB8: (pb8, 8, [1, 3, 4, 7, 9, 12, 13, 15]), + PB9: (pb9, 9, [1, 4, 6, 7, 8, 9, 13, 15]), + PB10: (pb10, 10, [1, 3, 7, 13, 15]), + PB11: (pb11, 11, [1, 3, 7, 13, 15]), + PB12: (pb12, 12, [3, 6, 7, 13, 15]), + PB13: (pb13, 13, [3, 6, 7, 13, 15]), + PB14: (pb14, 14, [1, 3, 6, 7, 13, 15]), + PB15: (pb15, 15, [1, 2, 4, 13, 15]), +]); + +#[cfg(feature = "gpio-f333")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2]), + PC1: (pc1, 1, [1, 2]), + PC2: (pc2, 2, [1, 2]), + PC3: (pc3, 3, [1, 2, 6]), + PC4: (pc4, 4, [1, 2, 7]), + PC5: (pc5, 5, [1, 2, 3, 7]), + PC6: (pc6, 6, [1, 2, 3, 7]), + PC7: (pc7, 7, [1, 2, 3]), + PC8: (pc8, 8, [1, 2, 3]), + PC9: (pc9, 9, [1, 2, 3]), + PC10: (pc10, 10, [1, 7]), + PC11: (pc11, 11, [1, 3, 7]), + PC12: (pc12, 12, [1, 3, 7]), + PC13: (pc13, 13, [4]), + PC14: (pc14, 14, []), + PC15: (pc15, 15, []), +]); + +#[cfg(feature = "gpio-f333")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD2: (pd2, 2, [1, 2]), +]); #[cfg(feature = "gpio-f333")] -gpio!({ - pacs: [gpioa, gpiob, gpioc], - ports: [ - { - port: (A/a, 0, gpioa), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 3, 7, 15] }, - 1 => { reset: Input, afr: L, af: [1, 3, 7, 9, 15] }, - 2 => { reset: Input, afr: L, af: [1, 3, 7, 8, 9, 15] }, - 3 => { reset: Input, afr: L, af: [1, 3, 7, 9, 15] }, - 4 => { reset: Input, afr: L, af: [2, 3, 5, 7, 15] }, - 5 => { reset: Input, afr: L, af: [1, 3, 5, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 5, 6, 13, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 5, 6, 15] }, - 8 => { reset: Input, afr: H, af: [0, 6, 7, 13, 15] }, - 9 => { reset: Input, afr: H, af: [3, 6, 7, 9, 10, 13, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 6, 7, 8, 10, 13, 15] }, - 11 => { reset: Input, afr: H, af: [6, 7, 9, 11, 12, 13, 15] }, - 12 => { reset: Input, afr: H, af: [1, 6, 7, 8, 9, 11, 13, 15] }, - 13 => { reset: AF0, afr: H, af: [0, 1, 3, 5, 7, 15] }, - 14 => { reset: AF0, afr: H, af: [0, 3, 4, 6, 7, 15] }, - 15 => { reset: AF0, afr: H, af: [0, 1, 3, 4, 5, 7, 9, 13, 15] }, - ], - }, - { - port: (B/b, 1, gpiob), - pins: [ - 0 => { reset: Input, afr: L, af: [2, 3, 6, 15] }, - 1 => { reset: Input, afr: L, af: [2, 3, 6, 8, 13, 15] }, - 2 => { reset: Input, afr: L, af: [3, 13, 15] }, - 3 => { reset: AF0, afr: L, af: [0, 1, 3, 5, 7, 10, 12, 13, 15] }, - 4 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 5, 7, 10, 13, 15] }, - 5 => { reset: Input, afr: L, af: [1, 2, 4, 5, 7, 10, 13, 15] }, - 6 => { reset: Input, afr: L, af: [1, 3, 4, 7, 12, 13, 15] }, - 7 => { reset: Input, afr: L, af: [1, 3, 4, 7, 10, 13, 15] }, - 8 => { reset: Input, afr: H, af: [1, 3, 4, 7, 9, 12, 13, 15] }, - 9 => { reset: Input, afr: H, af: [1, 4, 6, 7, 8, 9, 13, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 7, 13, 15] }, - 11 => { reset: Input, afr: H, af: [1, 3, 7, 13, 15] }, - 12 => { reset: Input, afr: H, af: [3, 6, 7, 13, 15] }, - 13 => { reset: Input, afr: H, af: [3, 6, 7, 13, 15] }, - 14 => { reset: Input, afr: H, af: [1, 3, 6, 7, 13, 15] }, - 15 => { reset: Input, afr: H, af: [1, 2, 4, 13, 15] }, - ], - }, - { - port: (C/c, 2, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2] }, - 1 => { reset: Input, afr: L, af: [1, 2] }, - 2 => { reset: Input, afr: L, af: [1, 2] }, - 3 => { reset: Input, afr: L, af: [1, 2, 6] }, - 4 => { reset: Input, afr: L, af: [1, 2, 7] }, - 5 => { reset: Input, afr: L, af: [1, 2, 3, 7] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 7] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3] }, - 8 => { reset: Input, afr: H, af: [1, 2, 3] }, - 9 => { reset: Input, afr: H, af: [1, 2, 3] }, - 10 => { reset: Input, afr: H, af: [1, 7] }, - 11 => { reset: Input, afr: H, af: [1, 3, 7] }, - 12 => { reset: Input, afr: H, af: [1, 3, 7] }, - 13 => { reset: Input, afr: H, af: [4] }, - 14 => { reset: Input, afr: H, af: [] }, - 15 => { reset: Input, afr: H, af: [] }, - ], - }, - { - port: (D/d, 3, gpioc), - pins: [ - 2 => { reset: Input, afr: L, af: [1, 2] }, - ], - }, - { - port: (F/f, 5, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [6] }, - 1 => { reset: Input, afr: L, af: [] }, - ], - }, - ], -}); +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [6]), + PF1: (pf1, 1, []), +]); + +#[cfg(feature = "gpio-f373")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 2, 3, 7, 8, 11, 15]), + PA1: (pa1, 1, [0, 1, 2, 3, 6, 7, 9, 11, 15]), + PA2: (pa2, 2, [1, 2, 3, 6, 7, 8, 9, 11, 15]), + PA3: (pa3, 3, [1, 2, 3, 6, 7, 9, 11, 15]), + PA4: (pa4, 4, [2, 3, 5, 6, 7, 10, 15]), + PA5: (pa5, 5, [1, 3, 5, 7, 9, 10, 15]), + PA6: (pa6, 6, [1, 2, 3, 5, 8, 9, 15]), + PA7: (pa7, 7, [1, 2, 3, 5, 8, 9, 15]), + PA8: (pa8, 8, [0, 2, 4, 5, 7, 10, 15]), + PA9: (pa9, 9, [2, 3, 4, 5, 7, 9, 10, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 7, 9, 10, 15]), + PA11: (pa11, 11, [2, 5, 6, 7, 8, 9, 10, 14, 15]), + PA12: (pa12, 12, [1, 2, 6, 7, 8, 9, 10, 14, 15]), + PA13: (pa13, 13, [0, 1, 2, 3, 5, 6, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed + PA14: (pa14, 14, [0, 3, 4, 10, 15], super::Debugger), // SWCLK, PullDown + PA15: (pa15, 15, [0, 1, 3, 4, 5, 6, 10, 15], super::Debugger), // JTDI, PullUp +]); + +#[cfg(feature = "gpio-f373")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 3, 5, 10, 15]), + PB1: (pb1, 1, [2, 3, 15]), + PB2: (pb2, 2, [15]), + PB3: (pb3, 3, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), // SWO, VeryHigh speed + PB4: (pb4, 4, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), // JTRST, PullUp + PB5: (pb5, 5, [1, 2, 4, 5, 6, 7, 10, 11, 15]), + PB6: (pb6, 6, [1, 2, 3, 4, 7, 9, 10, 11, 15]), + PB7: (pb7, 7, [1, 2, 3, 4, 7, 9, 10, 11, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15]), + PB9: (pb9, 9, [1, 2, 4, 5, 6, 7, 8, 9, 11, 15]), + PB10: (pb10, 10, [1, 3, 5, 6, 7, 15]), + PB14: (pb14, 14, [1, 3, 5, 7, 9, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 5, 9, 15]), +]); + +#[cfg(feature = "gpio-f373")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2]), + PC1: (pc1, 1, [1, 2]), + PC2: (pc2, 2, [1, 2, 5]), + PC3: (pc3, 3, [1, 2, 5]), + PC4: (pc4, 4, [1, 2, 3, 7]), + PC5: (pc5, 5, [1, 3, 7]), + PC6: (pc6, 6, [1, 2, 5]), + PC7: (pc7, 7, [1, 2, 5]), + PC8: (pc8, 8, [1, 2, 5]), + PC9: (pc9, 9, [1, 2, 5]), + PC10: (pc10, 10, [1, 2, 6, 7]), + PC11: (pc11, 11, [1, 2, 6, 7]), + PC12: (pc12, 12, [1, 2, 6, 7]), + PC13: (pc13, 13, []), + PC14: (pc14, 14, []), + PC15: (pc15, 15, []), +]); + +#[cfg(feature = "gpio-f373")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [1, 2, 7]), + PD1: (pd1, 1, [1, 2, 7]), + PD2: (pd2, 2, [1, 2]), + PD3: (pd3, 3, [1, 5, 7]), + PD4: (pd4, 4, [1, 5, 7]), + PD5: (pd5, 5, [1, 7]), + PD6: (pd6, 6, [1, 5, 7]), + PD7: (pd7, 7, [1, 5, 7]), + PD8: (pd8, 8, [1, 3, 5, 7]), + PD9: (pd9, 9, [1, 3, 7]), + PD10: (pd10, 10, [1, 7]), + PD11: (pd11, 11, [1, 7]), + PD12: (pd12, 12, [1, 2, 3, 7]), + PD13: (pd13, 13, [1, 2, 3]), + PD14: (pd14, 14, [1, 2, 3]), + PD15: (pd15, 15, [1, 2, 3]), +]); + +#[cfg(feature = "gpio-f373")] +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [1, 2, 7]), + PE1: (pe1, 1, [1, 7]), + PE2: (pe2, 2, [0, 1, 3]), + PE3: (pe3, 3, [0, 1, 3]), + PE4: (pe4, 4, [0, 1, 3]), + PE5: (pe5, 5, [0, 1, 3]), + PE6: (pe6, 6, [0, 1]), + PE7: (pe7, 7, [1]), + PE8: (pe8, 8, [1]), + PE9: (pe9, 9, [1]), + PE10: (pe10, 10, [1]), + PE11: (pe11, 11, [1]), + PE12: (pe12, 12, [1]), + PE13: (pe13, 13, [1]), + PE14: (pe14, 14, [1]), + PE15: (pe15, 15, [1, 7]), +]); #[cfg(feature = "gpio-f373")] -gpio!({ - pacs: [gpioa, gpiob, gpioc, gpiod], - ports: [ - { - port: (A/a, 0, gpioa), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 3, 7, 8, 11, 15] }, - 1 => { reset: Input, afr: L, af: [0, 1, 2, 3, 6, 7, 9, 11, 15] }, - 2 => { reset: Input, afr: L, af: [1, 2, 3, 6, 7, 8, 9, 11, 15] }, - 3 => { reset: Input, afr: L, af: [1, 2, 3, 6, 7, 9, 11, 15] }, - 4 => { reset: Input, afr: L, af: [2, 3, 5, 6, 7, 10, 15] }, - 5 => { reset: Input, afr: L, af: [1, 3, 5, 7, 9, 10, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 5, 8, 9, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 5, 8, 9, 15] }, - 8 => { reset: Input, afr: H, af: [0, 2, 4, 5, 7, 10, 15] }, - 9 => { reset: Input, afr: H, af: [2, 3, 4, 5, 7, 9, 10, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 4, 5, 7, 9, 10, 15] }, - 11 => { reset: Input, afr: H, af: [2, 5, 6, 7, 8, 9, 10, 14, 15] }, - 12 => { reset: Input, afr: H, af: [1, 2, 6, 7, 8, 9, 10, 14, 15] }, - 13 => { reset: AF0, afr: H, af: [0, 1, 2, 3, 5, 6, 7, 10, 15] }, - 14 => { reset: AF0, afr: H, af: [0, 3, 4, 10, 15] }, - 15 => { reset: AF0, afr: H, af: [0, 1, 3, 4, 5, 6, 10, 15] }, - ], - }, - { - port: (B/b, 1, gpiob), - pins: [ - 0 => { reset: Input, afr: L, af: [2, 3, 5, 10, 15] }, - 1 => { reset: Input, afr: L, af: [2, 3, 15] }, - 2 => { reset: Input, afr: L, af: [15] }, - 3 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 5, 6, 7, 9, 10, 15] }, - 4 => { reset: AF0, afr: L, af: [0, 1, 2, 3, 5, 6, 7, 9, 10, 15] }, - 5 => { reset: Input, afr: L, af: [1, 2, 4, 5, 6, 7, 10, 11, 15] }, - 6 => { reset: Input, afr: L, af: [1, 2, 3, 4, 7, 9, 10, 11, 15] }, - 7 => { reset: Input, afr: L, af: [1, 2, 3, 4, 7, 9, 10, 11, 15] }, - 8 => { reset: Input, afr: H, af: [1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 15] }, - 9 => { reset: Input, afr: H, af: [1, 2, 4, 5, 6, 7, 8, 9, 11, 15] }, - 10 => { reset: Input, afr: H, af: [1, 3, 5, 6, 7, 15] }, - 14 => { reset: Input, afr: H, af: [1, 3, 5, 7, 9, 15] }, - 15 => { reset: Input, afr: H, af: [0, 1, 2, 3, 5, 9, 15] }, - ], - }, - { - port: (C/c, 2, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2] }, - 1 => { reset: Input, afr: L, af: [1, 2] }, - 2 => { reset: Input, afr: L, af: [1, 2, 5] }, - 3 => { reset: Input, afr: L, af: [1, 2, 5] }, - 4 => { reset: Input, afr: L, af: [1, 2, 3, 7] }, - 5 => { reset: Input, afr: L, af: [1, 3, 7] }, - 6 => { reset: Input, afr: L, af: [1, 2, 5] }, - 7 => { reset: Input, afr: L, af: [1, 2, 5] }, - 8 => { reset: Input, afr: H, af: [1, 2, 5] }, - 9 => { reset: Input, afr: H, af: [1, 2, 5] }, - 10 => { reset: Input, afr: H, af: [1, 2, 6, 7] }, - 11 => { reset: Input, afr: H, af: [1, 2, 6, 7] }, - 12 => { reset: Input, afr: H, af: [1, 2, 6, 7] }, - 13 => { reset: Input, afr: H, af: [] }, - 14 => { reset: Input, afr: H, af: [] }, - 15 => { reset: Input, afr: H, af: [] }, - ], - }, - { - port: (D/d, 3, gpiod), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 7] }, - 1 => { reset: Input, afr: L, af: [1, 2, 7] }, - 2 => { reset: Input, afr: L, af: [1, 2] }, - 3 => { reset: Input, afr: L, af: [1, 5, 7] }, - 4 => { reset: Input, afr: L, af: [1, 5, 7] }, - 5 => { reset: Input, afr: L, af: [1, 7] }, - 6 => { reset: Input, afr: L, af: [1, 5, 7] }, - 7 => { reset: Input, afr: L, af: [1, 5, 7] }, - 8 => { reset: Input, afr: H, af: [1, 3, 5, 7] }, - 9 => { reset: Input, afr: H, af: [1, 3, 7] }, - 10 => { reset: Input, afr: H, af: [1, 7] }, - 11 => { reset: Input, afr: H, af: [1, 7] }, - 12 => { reset: Input, afr: H, af: [1, 2, 3, 7] }, - 13 => { reset: Input, afr: H, af: [1, 2, 3] }, - 14 => { reset: Input, afr: H, af: [1, 2, 3] }, - 15 => { reset: Input, afr: H, af: [1, 2, 3] }, - ], - }, - { - port: (E/e, 4, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [1, 2, 7] }, - 1 => { reset: Input, afr: L, af: [1, 7] }, - 2 => { reset: Input, afr: L, af: [0, 1, 3] }, - 3 => { reset: Input, afr: L, af: [0, 1, 3] }, - 4 => { reset: Input, afr: L, af: [0, 1, 3] }, - 5 => { reset: Input, afr: L, af: [0, 1, 3] }, - 6 => { reset: Input, afr: L, af: [0, 1] }, - 7 => { reset: Input, afr: L, af: [1] }, - 8 => { reset: Input, afr: H, af: [1] }, - 9 => { reset: Input, afr: H, af: [1] }, - 10 => { reset: Input, afr: H, af: [1] }, - 11 => { reset: Input, afr: H, af: [1] }, - 12 => { reset: Input, afr: H, af: [1] }, - 13 => { reset: Input, afr: H, af: [1] }, - 14 => { reset: Input, afr: H, af: [1] }, - 15 => { reset: Input, afr: H, af: [1, 7] }, - ], - }, - { - port: (F/f, 5, gpioc), - pins: [ - 0 => { reset: Input, afr: L, af: [4] }, - 1 => { reset: Input, afr: L, af: [4] }, - 2 => { reset: Input, afr: L, af: [1, 4] }, - 4 => { reset: Input, afr: L, af: [1] }, - 6 => { reset: Input, afr: L, af: [1, 2, 4, 5, 7] }, - 7 => { reset: Input, afr: L, af: [1, 4, 7] }, - 9 => { reset: Input, afr: H, af: [1, 2] }, - 10 => { reset: Input, afr: H, af: [1] }, - ], - }, - ], -}); +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4]), + PF1: (pf1, 1, [4]), + PF2: (pf2, 2, [1, 4]), + PF4: (pf4, 4, [1]), + PF6: (pf6, 6, [1, 2, 4, 5, 7]), + PF7: (pf7, 7, [1, 4, 7]), + PF9: (pf9, 9, [1, 2]), + PF10: (pf10, 10, [1]), +]); + +struct Gpio; +impl Gpio

{ + const fn ptr() -> *const crate::pac::gpioa::RegisterBlock { + match P { + 'A' => crate::pac::GPIOA::ptr(), + 'B' => crate::pac::GPIOB::ptr() as _, + 'C' => crate::pac::GPIOC::ptr() as _, + 'D' => crate::pac::GPIOD::ptr() as _, + #[cfg(any(feature = "gpio-f303e", feature = "gpio-f303", feature = "gpio-f373"))] + 'E' => crate::pac::GPIOE::ptr() as _, + 'F' => crate::pac::GPIOF::ptr() as _, + #[cfg(feature = "gpio-f303e")] + 'G' => crate::pac::GPIOG::ptr() as _, + #[cfg(feature = "gpio-f303e")] + 'H' => crate::pac::GPIOH::ptr() as _, + _ => crate::pac::GPIOA::ptr(), + } + } +} + +// Make all GPIO peripheral trait extensions sealable. +impl crate::private::Sealed for Pin {} diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs new file mode 100644 index 000000000..a58016440 --- /dev/null +++ b/src/gpio/convert.rs @@ -0,0 +1,215 @@ +use super::*; + +impl Pin { + /// Configures the pin to operate alternate mode + pub fn into_alternate( + self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + _afr: &mut ::Afr, + ) -> Pin> + where + Self: IntoAf, + { + self.into_mode() + } + + /// Configures the pin to operate in alternate open drain mode + pub fn into_alternate_open_drain( + self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + _afr: &mut ::Afr, + ) -> Pin> + where + Self: IntoAf, + { + self.into_mode() + } + + /// Configures the pin to operate as a input pin + pub fn into_input(self) -> Pin { + self.into_mode() + } + + /// Configures the pin to operate as a floating input pin + pub fn into_floating_input( + self, + _moder: &mut MODER

, + pupdr: &mut PUPDR

, + ) -> Pin { + self.into_mode().internal_resistor(pupdr, Pull::None) + } + + /// Configures the pin to operate as a pulled down input pin + pub fn into_pull_down_input( + self, + _moder: &mut MODER

, + pupdr: &mut PUPDR

, + ) -> Pin { + self.into_mode().internal_resistor(pupdr, Pull::Down) + } + + /// Configures the pin to operate as a pulled up input pin + pub fn into_pull_up_input( + self, + _moder: &mut MODER

, + pupdr: &mut PUPDR

, + ) -> Pin { + self.into_mode().internal_resistor(pupdr, Pull::Up) + } + + /// Configures the pin to operate as an open drain output pin + /// Initial state will be low. + pub fn into_open_drain_output( + self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + ) -> Pin> { + self.into_mode() + } + + /// Configures the pin to operate as an open-drain output pin. + /// `initial_state` specifies whether the pin should be initially high or low. + pub fn into_open_drain_output_in_state( + mut self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + initial_state: PinState, + ) -> Pin> { + self._set_state(initial_state); + self.into_mode() + } + + /// Configures the pin to operate as an push pull output pin + /// Initial state will be low. + pub fn into_push_pull_output( + mut self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + ) -> Pin> { + self._set_low(); + self.into_mode() + } + + /// Configures the pin to operate as an push-pull output pin. + /// `initial_state` specifies whether the pin should be initially high or low. + pub fn into_push_pull_output_in_state( + mut self, + _moder: &mut MODER

, + _otyper: &mut OTYPER

, + initial_state: PinState, + ) -> Pin> { + self._set_state(initial_state); + self.into_mode() + } + + /// Configures the pin to operate as an analog input pin + pub fn into_analog(self, _moder: &mut MODER

, _pupdr: &mut PUPDR

) -> Pin { + self.into_mode() + } + + /// Configures the pin as a pin that can change between input + /// and output without changing the type. It starts out + /// as a floating input + pub fn into_dynamic(self, moder: &mut MODER

, pupdr: &mut PUPDR

) -> DynamicPin { + self.into_floating_input(moder, pupdr); + DynamicPin::new(Dynamic::InputFloating) + } + + /// Puts `self` into mode `M`. + /// + /// This violates the type state constraints from `MODE`, so callers must + /// ensure they use this properly. + #[inline(always)] + pub(super) fn mode(&mut self) { + let offset = 2 * N; + unsafe { + if MODE::OTYPER != M::OTYPER { + if let Some(otyper) = M::OTYPER { + (*Gpio::

::ptr()) + .otyper + .modify(|r, w| w.bits(r.bits() & !(0b1 << N) | (otyper << N))); + } + } + + if MODE::AFR != M::AFR { + if let Some(afr) = M::AFR { + if N < 8 { + let offset2 = 4 * { N }; + (*Gpio::

::ptr()).afrl.modify(|r, w| { + w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) + }); + } else { + let offset2 = 4 * { N - 8 }; + (*Gpio::

::ptr()).afrh.modify(|r, w| { + w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) + }); + } + } + } + + if MODE::MODER != M::MODER { + (*Gpio::

::ptr()) + .moder + .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (M::MODER << offset))); + } + } + } + + #[inline(always)] + /// Converts pin into specified mode + pub(super) fn into_mode(mut self) -> Pin { + self.mode::(); + Pin::new() + } +} + +/// Marker trait for valid pin modes (type state). +/// +/// It can not be implemented by outside types. +pub trait PinMode: crate::Sealed { + // These constants are used to implement the pin configuration code. + // They are not part of public API. + + #[doc(hidden)] + const MODER: u32 = u32::MAX; + #[doc(hidden)] + const OTYPER: Option = None; + #[doc(hidden)] + const AFR: Option = None; +} + +impl crate::Sealed for Input {} +impl PinMode for Input { + const MODER: u32 = 0b00; +} + +impl crate::Sealed for Analog {} +impl PinMode for Analog { + const MODER: u32 = 0b11; +} + +impl crate::Sealed for Output {} +impl PinMode for Output { + const MODER: u32 = 0b01; + const OTYPER: Option = Some(0b1); +} + +impl PinMode for Output { + const MODER: u32 = 0b01; + const OTYPER: Option = Some(0b0); +} + +impl crate::Sealed for Alternate {} +impl PinMode for Alternate { + const MODER: u32 = 0b10; + const OTYPER: Option = Some(0b1); + const AFR: Option = Some(A as _); +} + +impl PinMode for Alternate { + const MODER: u32 = 0b10; + const OTYPER: Option = Some(0b0); + const AFR: Option = Some(A as _); +} diff --git a/src/gpio/dynamic.rs b/src/gpio/dynamic.rs new file mode 100644 index 000000000..24a153fa6 --- /dev/null +++ b/src/gpio/dynamic.rs @@ -0,0 +1,134 @@ +use super::*; + +/// Pin type with dynamic mode +/// +/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. +/// - `N` is pin number: from `0` to `15`. +pub struct DynamicPin { + /// Current pin mode + pub(crate) mode: Dynamic, +} + +/// Tracks the current pin state for dynamic pins +pub enum Dynamic { + InputFloating, + InputPullUp, + InputPullDown, + OutputPushPull, + OutputOpenDrain, +} + +#[derive(Debug, PartialEq)] +pub enum PinModeError { + IncorrectMode, +} + +impl Dynamic { + pub fn is_input(&self) -> bool { + use Dynamic::*; + match self { + InputFloating | InputPullUp | InputPullDown | OutputOpenDrain => true, + OutputPushPull => false, + } + } + pub fn is_output(&self) -> bool { + use Dynamic::*; + match self { + InputFloating | InputPullUp | InputPullDown => false, + OutputPushPull | OutputOpenDrain => true, + } + } +} + +// For convertion simplify +struct Unknown; + +impl crate::Sealed for Unknown {} +impl PinMode for Unknown {} + +impl DynamicPin { + pub const fn new(mode: Dynamic) -> Self { + Self { mode } + } + + #[inline] + pub fn make_pull_up_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_pull_up_input(moder, pupdr); + self.mode = Dynamic::InputPullUp; + } + #[inline] + pub fn make_pull_down_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_pull_down_input(moder, pupdr); + self.mode = Dynamic::InputPullDown; + } + #[inline] + pub fn make_floating_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_floating_input(moder, pupdr); + self.mode = Dynamic::InputFloating; + } + #[inline] + pub fn make_push_pull_output(&mut self, moder: &mut MODER

, otyper: &mut OTYPER

) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_push_pull_output(moder, otyper); + self.mode = Dynamic::OutputPushPull; + } + #[inline] + pub fn make_push_pull_output_in_state( + &mut self, + moder: &mut MODER

, + otyper: &mut OTYPER

, + state: PinState, + ) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_push_pull_output_in_state(moder, otyper, state); + self.mode = Dynamic::OutputPushPull; + } + #[inline] + pub fn make_open_drain_output(&mut self, moder: &mut MODER

, otyper: &mut OTYPER

) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_open_drain_output(moder, otyper); + self.mode = Dynamic::OutputOpenDrain; + } + #[inline] + pub fn make_open_drain_output_in_state( + &mut self, + moder: &mut MODER

, + otyper: &mut OTYPER

, + state: PinState, + ) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_open_drain_output_in_state(moder, otyper, state); + self.mode = Dynamic::OutputOpenDrain; + } + + pub fn set_high(&mut self) -> Result<(), PinModeError> { + if self.mode.is_output() { + Pin::::new()._set_state(PinState::High); + Ok(()) + } else { + Err(PinModeError::IncorrectMode) + } + } + pub fn set_low(&mut self) -> Result<(), PinModeError> { + if self.mode.is_output() { + Pin::::new()._set_state(PinState::Low); + Ok(()) + } else { + Err(PinModeError::IncorrectMode) + } + } + + pub fn is_high(&self) -> Result { + self.is_low().map(|b| !b) + } + pub fn is_low(&self) -> Result { + if self.mode.is_input() { + Ok(Pin::::new()._is_low()) + } else { + Err(PinModeError::IncorrectMode) + } + } +} diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs new file mode 100644 index 000000000..098ea4fae --- /dev/null +++ b/src/gpio/erased.rs @@ -0,0 +1,147 @@ +use super::*; + +pub type EPin = ErasedPin; + +/// Fully erased pin +/// +/// `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). +pub struct ErasedPin { + // Bits 0-3: Pin, Bits 4-7: Port + pin_port: u8, + _mode: PhantomData, +} + +impl fmt::Debug for ErasedPin { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_fmt(format_args!( + "P({}{})<{}>", + self.port_id(), + self.pin_id(), + crate::stripped_type_name::() + )) + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for ErasedPin { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "P({}{})<{}>", + self.port_id(), + self.pin_id(), + crate::stripped_type_name::() + ); + } +} + +impl PinExt for ErasedPin { + type Mode = MODE; + + #[inline(always)] + fn pin_id(&self) -> u8 { + self.pin_port & 0x0f + } + #[inline(always)] + fn port_id(&self) -> u8 { + self.pin_port >> 4 + } +} + +impl ErasedPin { + pub(crate) fn new(port: u8, pin: u8) -> Self { + Self { + pin_port: port << 4 | pin, + _mode: PhantomData, + } + } + + #[inline] + fn block(&self) -> &crate::pac::gpioa::RegisterBlock { + // This function uses pointer arithmetic instead of branching to be more efficient + + // The logic relies on the following assumptions: + // - GPIOA register is available on all chips + // - all gpio register blocks have the same layout + // - consecutive gpio register blocks have the same offset between them, namely 0x0400 + // - ErasedPin::new was called with a valid port + + // FIXME could be calculated after const_raw_ptr_to_usize_cast stabilization #51910 + const GPIO_REGISTER_OFFSET: usize = 0x0400; + + let offset = GPIO_REGISTER_OFFSET * self.port_id() as usize; + let block_ptr = + (crate::pac::GPIOA::ptr() as usize + offset) as *const crate::pac::gpioa::RegisterBlock; + + unsafe { &*block_ptr } + } +} + +impl ErasedPin> { + #[inline(always)] + pub fn set_high(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) }; + } + + #[inline(always)] + pub fn set_low(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { + self.block() + .bsrr + .write(|w| w.bits(1 << (self.pin_id() + 16))) + }; + } + + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + pub fn is_set_low(&self) -> bool { + self.block().odr.read().bits() & (1 << self.pin_id()) == 0 + } + + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl ErasedPin +where + MODE: super::sealed::Readable, +{ + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + pub fn is_low(&self) -> bool { + self.block().idr.read().bits() & (1 << self.pin_id()) == 0 + } +} diff --git a/src/gpio/hal_02.rs b/src/gpio/hal_02.rs new file mode 100644 index 000000000..f1cd0824b --- /dev/null +++ b/src/gpio/hal_02.rs @@ -0,0 +1,242 @@ +use core::convert::Infallible; + +use super::{ + dynamic::PinModeError, DynamicPin, ErasedPin, Input, OpenDrain, Output, PartiallyErasedPin, + Pin, PinMode, PinState, +}; + +use embedded_hal::digital::v2::{ + InputPin, IoPin, OutputPin, StatefulOutputPin, ToggleableOutputPin, +}; + +// Implementations for `Pin` + +impl OutputPin for Pin> { + type Error = Infallible; + + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin for Pin> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for Pin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for Pin +where + MODE: super::sealed::Readable, +{ + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +impl IoPin for Pin> { + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(state); + Ok(self) + } +} + +impl IoPin, Self> for Pin> +where + Output: PinMode, +{ + type Error = Infallible; + fn into_input_pin(self) -> Result, Self::Error> { + Ok(self.into_input()) + } + fn into_output_pin(mut self, state: PinState) -> Result { + self.set_state(state); + Ok(self) + } +} + +impl IoPin>> for Pin +where + Output: PinMode, +{ + type Error = Infallible; + fn into_input_pin(self) -> Result { + Ok(self) + } + fn into_output_pin(mut self, state: PinState) -> Result>, Self::Error> { + self._set_state(state); + Ok(self.into_mode()) + } +} + +// Implementations for `ErasedPin` + +impl OutputPin for ErasedPin> { + type Error = core::convert::Infallible; + + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin for ErasedPin> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for ErasedPin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for ErasedPin +where + MODE: super::sealed::Readable, +{ + type Error = core::convert::Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +// Implementations for `PartiallyErasedPin` + +impl OutputPin for PartiallyErasedPin> { + type Error = Infallible; + + #[inline(always)] + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high(); + Ok(()) + } + + #[inline(always)] + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low(); + Ok(()) + } +} + +impl StatefulOutputPin for PartiallyErasedPin> { + #[inline(always)] + fn is_set_high(&self) -> Result { + Ok(self.is_set_high()) + } + + #[inline(always)] + fn is_set_low(&self) -> Result { + Ok(self.is_set_low()) + } +} + +impl ToggleableOutputPin for PartiallyErasedPin> { + type Error = Infallible; + + #[inline(always)] + fn toggle(&mut self) -> Result<(), Self::Error> { + self.toggle(); + Ok(()) + } +} + +impl InputPin for PartiallyErasedPin +where + MODE: super::sealed::Readable, +{ + type Error = Infallible; + + #[inline(always)] + fn is_high(&self) -> Result { + Ok(self.is_high()) + } + + #[inline(always)] + fn is_low(&self) -> Result { + Ok(self.is_low()) + } +} + +// Implementations for `DynamicPin` + +impl OutputPin for DynamicPin { + type Error = PinModeError; + fn set_high(&mut self) -> Result<(), Self::Error> { + self.set_high() + } + fn set_low(&mut self) -> Result<(), Self::Error> { + self.set_low() + } +} + +impl InputPin for DynamicPin { + type Error = PinModeError; + fn is_high(&self) -> Result { + self.is_high() + } + fn is_low(&self) -> Result { + self.is_low() + } +} diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs new file mode 100644 index 000000000..1fba20853 --- /dev/null +++ b/src/gpio/partially_erased.rs @@ -0,0 +1,129 @@ +use super::*; + +pub type PEPin = PartiallyErasedPin; + +/// Partially erased pin +/// +/// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). +/// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. +pub struct PartiallyErasedPin { + i: u8, + _mode: PhantomData, +} + +impl PartiallyErasedPin { + pub(crate) fn new(i: u8) -> Self { + Self { + i, + _mode: PhantomData, + } + } +} + +impl fmt::Debug for PartiallyErasedPin { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_fmt(format_args!( + "P{}({})<{}>", + P, + self.i, + crate::stripped_type_name::() + )) + } +} + +#[cfg(feature = "defmt")] +impl defmt::Format for PartiallyErasedPin { + fn format(&self, f: defmt::Formatter) { + defmt::write!( + f, + "P{}({})<{}>", + P, + self.i, + crate::stripped_type_name::() + ); + } +} + +impl PinExt for PartiallyErasedPin { + type Mode = MODE; + + #[inline(always)] + fn pin_id(&self) -> u8 { + self.i + } + #[inline(always)] + fn port_id(&self) -> u8 { + P as u8 - b'A' + } +} + +impl PartiallyErasedPin> { + #[inline(always)] + pub fn set_high(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << self.i)) } + } + + #[inline(always)] + pub fn set_low(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(1 << (self.i + 16))) + } + } + + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } + + #[inline(always)] + pub fn is_set_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << self.i) == 0 } + } + + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl PartiallyErasedPin +where + MODE: super::sealed::Readable, +{ + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } + + #[inline(always)] + pub fn is_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 } + } +} diff --git a/src/lib.rs b/src/lib.rs index 1c70cac91..88ae626cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -327,3 +327,9 @@ impl From for Switch { #[derive(Debug, Copy, Clone, PartialEq, Eq)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct TryFromIntError; + +fn stripped_type_name() -> &'static str { + let s = core::any::type_name::(); + let p = s.split("::"); + p.last().unwrap() +} diff --git a/src/prelude.rs b/src/prelude.rs index 4d38766a0..5fad981f3 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -16,9 +16,3 @@ pub use crate::rcc::RccExt as _stm32f3xx_hal_rcc_RccExt; pub use crate::syscfg::SysCfgExt as _stm32f3xx_hal_syscfg_SysCfgExt; pub use crate::time::duration::Extensions as _stm32f3xx_hal_time_time_Extensions; pub use crate::time::rate::Extensions as _stm32f3xx_hal_time_rate_Extensions; -pub use crate::{ - hal::digital::v2::InputPin as _embedded_hal_digital_InputPin, - hal::digital::v2::OutputPin as _embedded_hal_digital_OutputPin, - hal::digital::v2::StatefulOutputPin as _embedded_hal_digital_StatefulOutputPin, - hal::digital::v2::ToggleableOutputPin as _embedded_hal_digital_ToggleableOutputPin, -}; diff --git a/src/syscfg.rs b/src/syscfg.rs index 1b14906ee..385ca7509 100644 --- a/src/syscfg.rs +++ b/src/syscfg.rs @@ -3,7 +3,7 @@ use core::fmt; use core::ops::Deref; -use crate::gpio::{marker, Pin}; +use crate::gpio::PinExt; use crate::{ pac::SYSCFG, rcc::{Enable, APB2}, @@ -73,15 +73,11 @@ impl SysCfg { /// /// But configuring `PA1` and and `PB2` works! #[doc(alias = "enable_interrupt")] - pub fn select_exti_interrupt_source(&mut self, pin: &Pin) - where - Gpio: marker::Gpio, - Index: marker::Index, - { + pub fn select_exti_interrupt_source(&mut self, pin: &PIN) { const BITWIDTH: u8 = 4; - let index = pin.index.index() % 4; - let extigpionr = pin.gpio.port_index() as u32; - match pin.index.index() { + let index = pin.pin_id() % 4; + let extigpionr = pin.port_id() as u32; + match pin.pin_id() { // SAFETY: These are all unguarded writes directly to the register, // without leveraging the safety of stm32f3 generated values. 0..=3 => unsafe { crate::modify_at!(self.exticr1, BITWIDTH, index, extigpionr) }, diff --git a/testsuite/tests/adc.rs b/testsuite/tests/adc.rs index 87c17d518..cc4852098 100644 --- a/testsuite/tests/adc.rs +++ b/testsuite/tests/adc.rs @@ -126,11 +126,11 @@ mod tests { let mut adc = defmt::unwrap!(state.adc.take()); adc.set_sample_time(&state.analog, config::SampleTime::Cycles61C5); for _ in 0..10 { - defmt::unwrap!(state.output.set_high()); + state.output.set_high(); asm::delay(100); let adc_level: u16 = defmt::unwrap!(adc.read(&mut state.analog).ok()); defmt::debug!("{}", adc_level); - defmt::unwrap!(state.output.set_low()); + state.output.set_low(); asm::delay(100); // Vref is 3V so output should reach the maximum. assert!((3500..4100).contains(&adc_level)); diff --git a/testsuite/tests/gpio_input.rs b/testsuite/tests/gpio_input.rs index e9f50f575..3c5c47922 100644 --- a/testsuite/tests/gpio_input.rs +++ b/testsuite/tests/gpio_input.rs @@ -5,11 +5,11 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::{Input, PXx}; +use hal::gpio::{EPin, Input}; struct State { - input_ground: PXx, - input_vdd: PXx, + input_ground: EPin, + input_vdd: EPin, } #[defmt_test::tests] @@ -33,18 +33,18 @@ mod tests { .into_floating_input(&mut gpioc.moder, &mut gpioc.pupdr); super::State { - input_ground: input_ground.downgrade().downgrade(), - input_vdd: input_vdd.downgrade().downgrade(), + input_ground: input_ground.erase(), + input_vdd: input_vdd.erase(), } } #[test] fn ground_is_low(state: &mut super::State) { - assert!(unwrap!(state.input_ground.is_low())); + assert!(state.input_ground.is_low()); } #[test] fn vdd_is_high(state: &mut super::State) { - assert!(unwrap!(state.input_vdd.is_high())); + assert!(state.input_vdd.is_high()); } } diff --git a/testsuite/tests/gpio_input_puller.rs b/testsuite/tests/gpio_input_puller.rs index 079f1aa2a..488be5d2f 100644 --- a/testsuite/tests/gpio_input_puller.rs +++ b/testsuite/tests/gpio_input_puller.rs @@ -5,15 +5,13 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::gpioc; -use hal::gpio::Resistor; -use hal::gpio::{Input, PXx}; +use hal::gpio::{self, EPin, Input, Pull}; use hal::{pac, prelude::*}; struct State { - observer: PXx, - puller: gpioc::PC1, - pupdr: gpioc::PUPDR, + observer: EPin, + puller: gpio::PC1, + pupdr: gpio::PUPDR<'C'>, } #[defmt_test::tests] @@ -37,14 +35,13 @@ mod tests { .pc1 .into_floating_input(&mut gpioc.moder, &mut gpioc.pupdr), }; - let mut observer = pair.0; + let observer = pair.0.internal_resistor(&mut gpioc.pupdr, Pull::None); let puller = pair.1; - observer.set_internal_resistor(&mut gpioc.pupdr, Resistor::Floating); let pupdr = gpioc.pupdr; super::State { - observer: observer.downgrade().downgrade(), + observer: observer.erase(), puller, pupdr, } @@ -54,19 +51,19 @@ mod tests { fn pulldown_is_low(state: &mut super::State) { state .puller - .set_internal_resistor(&mut state.pupdr, Resistor::PullDown); + .set_internal_resistor(&mut state.pupdr, Pull::None); cortex_m::asm::delay(10); - assert!(unwrap!(state.puller.is_low())); - assert!(unwrap!(state.observer.is_low())); + assert!(state.puller.is_low()); + assert!(state.observer.is_low()); } #[test] fn set_high_is_high(state: &mut super::State) { state .puller - .set_internal_resistor(&mut state.pupdr, Resistor::PullUp); + .set_internal_resistor(&mut state.pupdr, Pull::Up); cortex_m::asm::delay(10); - assert!(unwrap!(state.puller.is_high())); - assert!(unwrap!(state.observer.is_high())); + assert!(state.puller.is_high()); + assert!(state.observer.is_high()); } } diff --git a/testsuite/tests/gpio_output_open_drain.rs b/testsuite/tests/gpio_output_open_drain.rs index 7736f5cf1..a9d5bcee0 100644 --- a/testsuite/tests/gpio_output_open_drain.rs +++ b/testsuite/tests/gpio_output_open_drain.rs @@ -5,11 +5,11 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::{Input, OpenDrain, Output, PXx}; +use hal::gpio::{EPin, Input, OpenDrain, Output}; struct State { - input_pin: PXx, - output_pin: PXx>, + input_pin: EPin, + output_pin: EPin>, } #[defmt_test::tests] @@ -33,27 +33,26 @@ mod tests { .pc1 .into_open_drain_output(&mut gpioc.moder, &mut gpioc.otyper), }; - let mut input_pin = pair.0; - input_pin.internal_pull_up(&mut gpioc.pupdr, true); + let input_pin = pair.0.internal_pull_up(&mut gpioc.pupdr, true); let output_pin = pair.1; super::State { - input_pin: input_pin.downgrade().downgrade(), - output_pin: output_pin.downgrade().downgrade(), + input_pin: input_pin.erase(), + output_pin: output_pin.erase(), } } #[test] fn set_low_is_low(state: &mut super::State) { - unwrap!(state.output_pin.set_low()); - assert!(unwrap!(state.output_pin.is_set_low())); - assert!(unwrap!(state.input_pin.is_low())); + state.output_pin.set_low(); + assert!(state.output_pin.is_set_low()); + assert!(state.input_pin.is_low()); } #[test] fn set_high_is_high(state: &mut super::State) { - unwrap!(state.output_pin.set_high()); - assert!(unwrap!(state.output_pin.is_set_high())); - assert!(unwrap!(state.input_pin.is_high())); + state.output_pin.set_high(); + assert!(state.output_pin.is_set_high()); + assert!(state.input_pin.is_high()); } } diff --git a/testsuite/tests/gpio_output_push_pull.rs b/testsuite/tests/gpio_output_push_pull.rs index 2239af343..67f7abd49 100644 --- a/testsuite/tests/gpio_output_push_pull.rs +++ b/testsuite/tests/gpio_output_push_pull.rs @@ -7,11 +7,11 @@ use panic_probe as _; use hal::prelude::*; use stm32f3xx_hal as hal; -use hal::gpio::{Input, Output, PXx, PushPull}; +use hal::gpio::{EPin, Input, Output, PushPull}; struct State { - input_pin: PXx, - output_pin: PXx>, + input_pin: EPin, + output_pin: EPin>, } #[defmt_test::tests] @@ -37,22 +37,22 @@ mod tests { }; super::State { - input_pin: pair.0.downgrade().downgrade(), - output_pin: pair.1.downgrade().downgrade(), + input_pin: pair.0.erase(), + output_pin: pair.1.erase(), } } #[test] fn set_low_is_low(state: &mut super::State) { - unwrap!(state.output_pin.set_low()); - assert!(unwrap!(state.output_pin.is_set_low())); - assert!(unwrap!(state.input_pin.is_low())); + state.output_pin.set_low(); + assert!(state.output_pin.is_set_low()); + assert!(state.input_pin.is_low()); } #[test] fn set_high_is_high(state: &mut super::State) { - unwrap!(state.output_pin.set_high()); - assert!(unwrap!(state.output_pin.is_set_high())); - assert!(unwrap!(state.input_pin.is_high())); + state.output_pin.set_high(); + assert!(state.output_pin.is_set_high()); + assert!(state.input_pin.is_high()); } } diff --git a/testsuite/tests/spi.rs b/testsuite/tests/spi.rs index 5419a648c..fa9335a96 100644 --- a/testsuite/tests/spi.rs +++ b/testsuite/tests/spi.rs @@ -52,13 +52,13 @@ mod tests { let spi_pins = SpiPair { 0: gpioc .pc10 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), 1: gpioc .pc11 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), 2: gpioc .pc12 - .into_af_push_pull(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), + .into_alternate(&mut gpioc.moder, &mut gpioc.otyper, &mut gpioc.afrh), }; let spi = Spi::new( diff --git a/testsuite/tests/uart.rs b/testsuite/tests/uart.rs index 31fe5c219..d002da423 100644 --- a/testsuite/tests/uart.rs +++ b/testsuite/tests/uart.rs @@ -124,26 +124,30 @@ mod tests { let serial_pair = SerialPair { 0: gpioa .pa9 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), 1: gpioa .pa10 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrh), }; let cs_pair_1 = CrossSerialPair1 { 0: gpioa .pa2 - .into_af_push_pull(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl), - 1: gpiob - .pb11 - .into_af_open_drain(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh), + .into_alternate(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl), + 1: gpiob.pb11.into_alternate_open_drain( + &mut gpiob.moder, + &mut gpiob.otyper, + &mut gpiob.afrh, + ), }; let cs_pair_2 = CrossSerialPair2 { 0: gpiob .pb10 - .into_af_push_pull(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh), - 1: gpioa - .pa3 - .into_af_open_drain(&mut gpioa.moder, &mut gpioa.otyper, &mut gpioa.afrl), + .into_alternate(&mut gpiob.moder, &mut gpiob.otyper, &mut gpiob.afrh), + 1: gpioa.pa3.into_alternate_open_drain( + &mut gpioa.moder, + &mut gpioa.otyper, + &mut gpioa.afrl, + ), }; let serial1 = Serial::new( From 597f50b7fab7e67df57ac203e19f72e09001da83 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 1 Apr 2022 18:19:40 +0300 Subject: [PATCH 2/9] codegen update --- codegen/src/codegen/gpio.rs | 89 +++++++++++-------------------------- codegen/src/main.rs | 2 +- src/gpio.rs | 54 +++++++++++----------- 3 files changed, 56 insertions(+), 89 deletions(-) diff --git a/codegen/src/codegen/gpio.rs b/codegen/src/codegen/gpio.rs index 107b15190..381a5f03a 100644 --- a/codegen/src/codegen/gpio.rs +++ b/codegen/src/codegen/gpio.rs @@ -21,7 +21,6 @@ fn gen_gpio_ip(ip: &gpio::Ip) -> Result<()> { let feature = ip_version_to_feature(&ip.version)?; let ports = merge_pins_by_port(&ip.pins)?; - println!(r#"#[cfg(feature = "{}")]"#, feature); gen_gpio_macro_call(&ports, &feature)?; Ok(()) } @@ -31,7 +30,7 @@ fn ip_version_to_feature(ip_version: &str) -> Result { Lazy::new(|| Regex::new(r"^STM32(?P\w+)_gpio_v1_0$").unwrap()); let captures = VERSION - .captures(&ip_version) + .captures(ip_version) .with_context(|| format!("invalid GPIO IP version: {}", ip_version))?; let version = captures.name("version").unwrap().as_str(); @@ -60,94 +59,58 @@ fn merge_pins_by_port(pins: &[gpio::Pin]) -> Result> { } fn gen_gpio_macro_call(ports: &[Port], feature: &str) -> Result<()> { - println!("gpio!({{"); - - gen_pac_list(ports, feature); - - println!(" ports: ["); for port in ports { - gen_port(port, feature)?; + println!(r#"#[cfg(feature = "{}")]"#, feature); + gen_port(port)?; + println!(); } - println!(" ],"); - println!("}});"); Ok(()) } -fn gen_pac_list(ports: &[Port], feature: &str) { - let mut pac_modules: Vec<_> = ports - .iter() - .map(|port| get_port_pac_module(port, feature)) - .collect(); - pac_modules.sort_unstable(); - pac_modules.dedup(); - println!(" pacs: [{}],", pac_modules.join(", ")); -} - -fn gen_port(port: &Port, feature: &str) -> Result<()> { - let pac_module = get_port_pac_module(port, feature); - let port_index = match port.id { - 'A' => 0, - 'B' => 1, - 'C' => 2, - 'D' => 3, - 'E' => 4, - 'F' => 5, - 'G' => 6, - 'H' => 7, - _ => unreachable!(), - }; - - println!(" {{"); +fn gen_port(port: &Port) -> Result<()> { + let port_upper = port.id; + let port_lower = port.id.to_ascii_lowercase(); println!( - " port: ({}/{}, {}, {}),", - port.id, - port.id.to_lowercase(), - port_index, - pac_module, + "gpio!(GPIO{0}, gpio{1}, P{0}, '{0}', P{0}n, [", + port_upper, port_lower ); - println!(" pins: ["); for pin in &port.pins { - gen_pin(pin)?; + gen_pin(port_upper, port_lower, pin)?; } - println!(" ],"); - println!(" }},"); + println!("]);"); Ok(()) } -fn get_port_pac_module(port: &Port, feature: &str) -> &'static str { - // The registers in ports A and B have different reset values due to the - // presence of debug pins, so they get dedicated PAC modules. - match port.id { - 'A' => "gpioa", - 'B' => "gpiob", - 'D' if feature == "gpio-f373" => "gpiod", - _ => "gpioc", - } -} - -fn gen_pin(pin: &gpio::Pin) -> Result<()> { +fn gen_pin(port_upper: char, port_lower: char, pin: &gpio::Pin) -> Result<()> { let nr = pin.number()?; let reset_mode = get_pin_reset_mode(pin)?; - let afr = if nr < 8 { 'L' } else { 'H' }; let af_numbers = get_pin_af_numbers(pin)?; println!( - " {} => {{ reset: {}, afr: {}, af: {:?} }},", - nr, reset_mode, afr, af_numbers, + " P{0}{2}: (p{1}{2}, {2}, {3:?}{4}),", + port_upper, + port_lower, + nr, + af_numbers, + if let Some(rst) = reset_mode { + format!(", {}", rst) + } else { + String::new() + } ); Ok(()) } -fn get_pin_reset_mode(pin: &gpio::Pin) -> Result<&'static str> { +fn get_pin_reset_mode(pin: &gpio::Pin) -> Result> { // Debug pins default to their debug function (AF0), everything else - // defaults to input. + // defaults to floating input or analog. let mode = match (pin.port()?, pin.number()?) { - ('A', 13) | ('A', 14) | ('A', 15) | ('B', 3) | ('B', 4) => "AF0", - _ => "Input", + ('A', 13) | ('A', 14) | ('A', 15) | ('B', 3) | ('B', 4) => Some("super::Debugger"), + _ => None, }; Ok(mode) } diff --git a/codegen/src/main.rs b/codegen/src/main.rs index 5c1dabecb..d3a7b9600 100644 --- a/codegen/src/main.rs +++ b/codegen/src/main.rs @@ -34,7 +34,7 @@ fn handle_gpio(db_path: PathBuf) -> Result<()> { } fn emit_autogen_comment(db: &Db) -> Result<()> { - let package = cubemx::package::load(&db)?; + let package = cubemx::package::load(db)?; codegen::gen_autogen_comment(&package); Ok(()) diff --git a/src/gpio.rs b/src/gpio.rs index 4f7920c11..86dc8229e 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -666,9 +666,9 @@ gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 8, 10, 15]), PA11: (pa11, 11, [5, 6, 7, 9, 11, 12, 15]), PA12: (pa12, 12, [1, 5, 6, 7, 8, 9, 11, 15]), - PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, [0, 1, 3, 4, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp + PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), + PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 3, 4, 6, 7, 9, 15], super::Debugger), ]); #[cfg(feature = "gpio-f302")] @@ -676,8 +676,8 @@ gpio!(GPIOB, gpiob, PB, 'B', PBn, [ PB0: (pb0, 0, [3, 6, 15]), PB1: (pb1, 1, [3, 6, 8, 15]), PB2: (pb2, 2, [3, 15]), - PB3: (pb3, 3, [0, 1, 3, 6, 7, 15], super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, [0, 1, 3, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB3: (pb3, 3, [0, 1, 3, 6, 7, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 3, 6, 7, 10, 15], super::Debugger), PB5: (pb5, 5, [1, 4, 6, 7, 8, 10, 15]), PB6: (pb6, 6, [1, 3, 4, 7, 15]), PB7: (pb7, 7, [1, 3, 4, 7, 15]), @@ -722,6 +722,7 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF1: (pf1, 1, [4, 5]), ]); + #[cfg(feature = "gpio-f303e")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), @@ -737,9 +738,9 @@ gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 8, 10, 11, 15]), PA11: (pa11, 11, [5, 6, 7, 8, 9, 10, 11, 12, 15]), PA12: (pa12, 12, [1, 5, 6, 7, 8, 9, 10, 11, 15]), - PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, [0, 1, 2, 3, 4, 5, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp + PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), + PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 3, 4, 5, 6, 7, 9, 15], super::Debugger), ]); #[cfg(feature = "gpio-f303e")] @@ -747,8 +748,8 @@ gpio!(GPIOB, gpiob, PB, 'B', PBn, [ PB0: (pb0, 0, [2, 3, 4, 6, 15]), PB1: (pb1, 1, [2, 3, 4, 6, 8, 15]), PB2: (pb2, 2, [3, 15]), - PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 10, 15]), PB6: (pb6, 6, [1, 2, 3, 4, 5, 6, 7, 10, 15]), PB7: (pb7, 7, [1, 2, 3, 4, 5, 7, 10, 12, 15]), @@ -869,6 +870,7 @@ gpio!(GPIOH, gpioh, PH, 'H', PHn, [ PH2: (ph2, 2, [1]), ]); + #[cfg(feature = "gpio-f303")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), @@ -884,9 +886,9 @@ gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA10: (pa10, 10, [1, 3, 4, 6, 7, 8, 10, 11, 15]), PA11: (pa11, 11, [6, 7, 8, 9, 10, 11, 12, 14, 15]), PA12: (pa12, 12, [1, 6, 7, 8, 9, 10, 11, 14, 15]), - PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 9, 15], super::Debugger), // JTDI, PullUp + PA13: (pa13, 13, [0, 1, 3, 5, 7, 10, 15], super::Debugger), + PA14: (pa14, 14, [0, 3, 4, 5, 6, 7, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 9, 15], super::Debugger), ]); #[cfg(feature = "gpio-f303")] @@ -894,8 +896,8 @@ gpio!(GPIOB, gpiob, PB, 'B', PBn, [ PB0: (pb0, 0, [2, 3, 4, 6, 15]), PB1: (pb1, 1, [2, 3, 4, 6, 8, 15]), PB2: (pb2, 2, [3, 15]), - PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), // JTRST, PullUp + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 3, 4, 5, 6, 7, 10, 15], super::Debugger), PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 10, 15]), PB6: (pb6, 6, [1, 2, 3, 4, 5, 6, 7, 10, 15]), PB7: (pb7, 7, [1, 2, 3, 4, 5, 7, 10, 15]), @@ -980,6 +982,7 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF10: (pf10, 10, [1, 3, 5]), ]); + #[cfg(feature = "gpio-f333")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 15]), @@ -995,9 +998,9 @@ gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA10: (pa10, 10, [1, 3, 6, 7, 8, 10, 13, 15]), PA11: (pa11, 11, [6, 7, 9, 11, 12, 13, 15]), PA12: (pa12, 12, [1, 6, 7, 8, 9, 11, 13, 15]), - PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, [0, 1, 3, 4, 5, 7, 9, 13, 15], super::Debugger), // JTDI, PullUp + PA13: (pa13, 13, [0, 1, 3, 5, 7, 15], super::Debugger), + PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 3, 4, 5, 7, 9, 13, 15], super::Debugger), ]); #[cfg(feature = "gpio-f333")] @@ -1005,8 +1008,8 @@ gpio!(GPIOB, gpiob, PB, 'B', PBn, [ PB0: (pb0, 0, [2, 3, 6, 15]), PB1: (pb1, 1, [2, 3, 6, 8, 13, 15]), PB2: (pb2, 2, [3, 13, 15]), - PB3: (pb3, 3, [0, 1, 3, 5, 7, 10, 12, 13, 15], super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, [0, 1, 2, 3, 5, 7, 10, 13, 15], super::Debugger), // JTRST, PullUp + PB3: (pb3, 3, [0, 1, 3, 5, 7, 10, 12, 13, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 3, 5, 7, 10, 13, 15], super::Debugger), PB5: (pb5, 5, [1, 2, 4, 5, 7, 10, 13, 15]), PB6: (pb6, 6, [1, 3, 4, 7, 12, 13, 15]), PB7: (pb7, 7, [1, 3, 4, 7, 10, 13, 15]), @@ -1051,6 +1054,7 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF1: (pf1, 1, []), ]); + #[cfg(feature = "gpio-f373")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 2, 3, 7, 8, 11, 15]), @@ -1066,9 +1070,9 @@ gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA10: (pa10, 10, [1, 3, 4, 5, 7, 9, 10, 15]), PA11: (pa11, 11, [2, 5, 6, 7, 8, 9, 10, 14, 15]), PA12: (pa12, 12, [1, 2, 6, 7, 8, 9, 10, 14, 15]), - PA13: (pa13, 13, [0, 1, 2, 3, 5, 6, 7, 10, 15], super::Debugger), // SWDIO, PullUp VeryHigh speed - PA14: (pa14, 14, [0, 3, 4, 10, 15], super::Debugger), // SWCLK, PullDown - PA15: (pa15, 15, [0, 1, 3, 4, 5, 6, 10, 15], super::Debugger), // JTDI, PullUp + PA13: (pa13, 13, [0, 1, 2, 3, 5, 6, 7, 10, 15], super::Debugger), + PA14: (pa14, 14, [0, 3, 4, 10, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 3, 4, 5, 6, 10, 15], super::Debugger), ]); #[cfg(feature = "gpio-f373")] @@ -1076,8 +1080,8 @@ gpio!(GPIOB, gpiob, PB, 'B', PBn, [ PB0: (pb0, 0, [2, 3, 5, 10, 15]), PB1: (pb1, 1, [2, 3, 15]), PB2: (pb2, 2, [15]), - PB3: (pb3, 3, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), // SWO, VeryHigh speed - PB4: (pb4, 4, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), // JTRST, PullUp + PB3: (pb3, 3, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 3, 5, 6, 7, 9, 10, 15], super::Debugger), PB5: (pb5, 5, [1, 2, 4, 5, 6, 7, 10, 11, 15]), PB6: (pb6, 6, [1, 2, 3, 4, 7, 9, 10, 11, 15]), PB7: (pb7, 7, [1, 2, 3, 4, 7, 9, 10, 11, 15]), From f634c339091b80c9cb9370310d3aa5b28f0ffc6b Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 1 Apr 2022 19:55:23 +0300 Subject: [PATCH 3/9] add docs --- examples/gpio_erased.rs | 2 +- src/gpio.rs | 48 ++++++++++++++++------- src/gpio/dynamic.rs | 25 +++++++++++- src/gpio/erased.rs | 11 +++++- src/gpio/partially_erased.rs | 11 +++++- src/lib.rs | 2 +- testsuite/tests/gpio_input.rs | 6 +-- testsuite/tests/gpio_input_puller.rs | 4 +- testsuite/tests/gpio_output_open_drain.rs | 6 +-- testsuite/tests/gpio_output_push_pull.rs | 6 +-- 10 files changed, 88 insertions(+), 33 deletions(-) diff --git a/examples/gpio_erased.rs b/examples/gpio_erased.rs index a77798da9..14eff22dc 100644 --- a/examples/gpio_erased.rs +++ b/examples/gpio_erased.rs @@ -23,7 +23,7 @@ fn main() -> ! { let mut gpioc = dp.GPIOC.split(&mut rcc.ahb); let mut gpiod = dp.GPIOD.split(&mut rcc.ahb); - let mut pin_array: [gpio::EPin; 4] = [ + let mut pin_array: [gpio::ErasedPin; 4] = [ gpiob .pb11 .into_floating_input(&mut gpiob.moder, &mut gpiob.pupdr) diff --git a/src/gpio.rs b/src/gpio.rs index 86dc8229e..8d81b6c5f 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -78,8 +78,6 @@ //! To make a pin dynamic, use the `into_dynamic` function, and then use the `make_` functions to //! change the mode -#![allow(missing_docs)] - use core::marker::PhantomData; use crate::pac::{Interrupt, EXTI}; @@ -89,9 +87,9 @@ use crate::Switch; mod convert; use convert::PinMode; mod partially_erased; -pub use partially_erased::{PEPin, PartiallyErasedPin}; +pub use partially_erased::PartiallyErasedPin; mod erased; -pub use erased::{EPin, ErasedPin}; +pub use erased::ErasedPin; mod dynamic; pub use dynamic::{Dynamic, DynamicPin}; mod hal_02; @@ -114,11 +112,13 @@ pub trait GpioExt { fn split(self, ahb: &mut AHB) -> Self::Parts; } +/// Id, port and mode for any pin pub trait PinExt { + /// Current pin mode type Mode; - /// Return pin number + /// Pin number fn pin_id(&self) -> u8; - /// Return port number + /// Port number starting from 0 fn port_id(&self) -> u8; } @@ -154,6 +154,7 @@ pub struct PushPull; /// Analog mode (type state) pub struct Analog; +/// JTAG/SWD mote (type state) pub type Debugger = Alternate<0, PushPull>; mod sealed { @@ -184,16 +185,23 @@ impl sealed::NotAlt for Analog {} #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { + /// Low speed Low = 0, + /// Medium speed Medium = 1, + /// High speed High = 3, } +/// GPIO interrupt trigger edge selection #[cfg_attr(feature = "defmt", derive(defmt::Format))] #[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Edge { + /// Rising edge of voltage Rising, + /// Falling edge of voltage Falling, + /// Rising and falling edge of voltage RisingFalling, } @@ -474,16 +482,16 @@ impl Pin { /// /// This is useful when you want to collect the pins into an array where you /// need all the elements to have the same type - pub fn erase_number(self) -> PEPin { - PEPin::new(N) + pub fn erase_number(self) -> PartiallyErasedPin { + PartiallyErasedPin::new(N) } /// Erases the pin number and the port from the type /// /// This is useful when you want to collect the pins into an array where you /// need all the elements to have the same type - pub fn erase(self) -> EPin { - EPin::new(P as u8 - b'A', N) + pub fn erase(self) -> ErasedPin { + ErasedPin::new(P as u8 - b'A', N) } } @@ -522,16 +530,19 @@ impl Pin { } impl Pin> { + /// Drives the pin high #[inline(always)] pub fn set_high(&mut self) { self._set_high() } + /// Drives the pin low #[inline(always)] pub fn set_low(&mut self) { self._set_low() } + /// Is the pin in drive high or low mode? #[inline(always)] pub fn get_state(&self) -> PinState { if self.is_set_low() { @@ -541,6 +552,7 @@ impl Pin> { } } + /// Drives the pin high or low depending on the provided value #[inline(always)] pub fn set_state(&mut self, state: PinState) { match state { @@ -549,16 +561,19 @@ impl Pin> { } } + /// Is the pin in drive high mode? #[inline(always)] pub fn is_set_high(&self) -> bool { !self.is_set_low() } + /// Is the pin in drive low mode? #[inline(always)] pub fn is_set_low(&self) -> bool { self._is_set_low() } + /// Toggle pin output #[inline(always)] pub fn toggle(&mut self) { if self.is_set_low() { @@ -573,11 +588,13 @@ impl Pin where MODE: sealed::Readable, { + /// Is the input pin high? #[inline(always)] pub fn is_high(&self) -> bool { !self.is_low() } + /// Is the input pin low? #[inline(always)] pub fn is_low(&self) -> bool { self._is_low() @@ -635,9 +652,14 @@ macro_rules! gpio { } } - pub type $PXn = super::PEPin<$port_id, MODE>; + #[doc="Common type for "] + #[doc=stringify!($GPIOX)] + #[doc=" related pins"] + pub type $PXn = super::PartiallyErasedPin<$port_id, MODE>; $( + #[doc=stringify!($PXi)] + #[doc=" pin"] pub type $PXi = super::Pin<$port_id, $i, MODE>; $( @@ -722,7 +744,6 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF1: (pf1, 1, [4, 5]), ]); - #[cfg(feature = "gpio-f303e")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), @@ -870,7 +891,6 @@ gpio!(GPIOH, gpioh, PH, 'H', PHn, [ PH2: (ph2, 2, [1]), ]); - #[cfg(feature = "gpio-f303")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 8, 9, 10, 15]), @@ -982,7 +1002,6 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF10: (pf10, 10, [1, 3, 5]), ]); - #[cfg(feature = "gpio-f333")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 3, 7, 15]), @@ -1054,7 +1073,6 @@ gpio!(GPIOF, gpiof, PF, 'F', PFn, [ PF1: (pf1, 1, []), ]); - #[cfg(feature = "gpio-f373")] gpio!(GPIOA, gpioa, PA, 'A', PAn, [ PA0: (pa0, 0, [1, 2, 3, 7, 8, 11, 15]), diff --git a/src/gpio/dynamic.rs b/src/gpio/dynamic.rs index 24a153fa6..51e5e3184 100644 --- a/src/gpio/dynamic.rs +++ b/src/gpio/dynamic.rs @@ -11,19 +11,27 @@ pub struct DynamicPin { /// Tracks the current pin state for dynamic pins pub enum Dynamic { + /// Floating input mode InputFloating, + /// Pull-up input mode InputPullUp, + /// Pull-down input mode InputPullDown, + /// Push-pull output mode OutputPushPull, + /// Open-drain output mode OutputOpenDrain, } +/// Error for [DynamicPin] #[derive(Debug, PartialEq)] pub enum PinModeError { + /// For operations unsupported in current mode IncorrectMode, } impl Dynamic { + /// Is pin in readable mode pub fn is_input(&self) -> bool { use Dynamic::*; match self { @@ -31,6 +39,8 @@ impl Dynamic { OutputPushPull => false, } } + + /// Is pin in writable mode pub fn is_output(&self) -> bool { use Dynamic::*; match self { @@ -47,34 +57,39 @@ impl crate::Sealed for Unknown {} impl PinMode for Unknown {} impl DynamicPin { - pub const fn new(mode: Dynamic) -> Self { + pub(super) const fn new(mode: Dynamic) -> Self { Self { mode } } + /// Switch pin into pull-up input #[inline] pub fn make_pull_up_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { // NOTE(unsafe), we have a mutable reference to the current pin Pin::::new().into_pull_up_input(moder, pupdr); self.mode = Dynamic::InputPullUp; } + /// Switch pin into pull-down input #[inline] pub fn make_pull_down_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { // NOTE(unsafe), we have a mutable reference to the current pin Pin::::new().into_pull_down_input(moder, pupdr); self.mode = Dynamic::InputPullDown; } + /// Switch pin into floating input #[inline] pub fn make_floating_input(&mut self, moder: &mut MODER

, pupdr: &mut PUPDR

) { // NOTE(unsafe), we have a mutable reference to the current pin Pin::::new().into_floating_input(moder, pupdr); self.mode = Dynamic::InputFloating; } + /// Switch pin into push-pull output #[inline] pub fn make_push_pull_output(&mut self, moder: &mut MODER

, otyper: &mut OTYPER

) { // NOTE(unsafe), we have a mutable reference to the current pin Pin::::new().into_push_pull_output(moder, otyper); self.mode = Dynamic::OutputPushPull; } + /// Switch pin into push-pull output with required voltage state #[inline] pub fn make_push_pull_output_in_state( &mut self, @@ -86,12 +101,14 @@ impl DynamicPin { Pin::::new().into_push_pull_output_in_state(moder, otyper, state); self.mode = Dynamic::OutputPushPull; } + /// Switch pin into open-drain output #[inline] pub fn make_open_drain_output(&mut self, moder: &mut MODER

, otyper: &mut OTYPER

) { // NOTE(unsafe), we have a mutable reference to the current pin Pin::::new().into_open_drain_output(moder, otyper); self.mode = Dynamic::OutputOpenDrain; } + /// Switch pin into open-drain output with required voltage state #[inline] pub fn make_open_drain_output_in_state( &mut self, @@ -104,6 +121,7 @@ impl DynamicPin { self.mode = Dynamic::OutputOpenDrain; } + /// Drives the pin high pub fn set_high(&mut self) -> Result<(), PinModeError> { if self.mode.is_output() { Pin::::new()._set_state(PinState::High); @@ -112,6 +130,8 @@ impl DynamicPin { Err(PinModeError::IncorrectMode) } } + + /// Drives the pin low pub fn set_low(&mut self) -> Result<(), PinModeError> { if self.mode.is_output() { Pin::::new()._set_state(PinState::Low); @@ -121,9 +141,12 @@ impl DynamicPin { } } + /// Is the input pin high? pub fn is_high(&self) -> Result { self.is_low().map(|b| !b) } + + /// Is the input pin low? pub fn is_low(&self) -> Result { if self.mode.is_input() { Ok(Pin::::new()._is_low()) diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs index 098ea4fae..9c4d6b607 100644 --- a/src/gpio/erased.rs +++ b/src/gpio/erased.rs @@ -1,7 +1,5 @@ use super::*; -pub type EPin = ErasedPin; - /// Fully erased pin /// /// `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). @@ -78,12 +76,14 @@ impl ErasedPin { } impl ErasedPin> { + /// Drives the pin high #[inline(always)] pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { self.block().bsrr.write(|w| w.bits(1 << self.pin_id())) }; } + /// Drives the pin low #[inline(always)] pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register @@ -94,6 +94,7 @@ impl ErasedPin> { }; } + /// Is the pin in drive high or low mode? #[inline(always)] pub fn get_state(&self) -> PinState { if self.is_set_low() { @@ -103,6 +104,7 @@ impl ErasedPin> { } } + /// Drives the pin high or low depending on the provided value #[inline(always)] pub fn set_state(&mut self, state: PinState) { match state { @@ -111,16 +113,19 @@ impl ErasedPin> { } } + /// Is the pin in drive high mode? #[inline(always)] pub fn is_set_high(&self) -> bool { !self.is_set_low() } + /// Is the pin in drive low mode? #[inline(always)] pub fn is_set_low(&self) -> bool { self.block().odr.read().bits() & (1 << self.pin_id()) == 0 } + /// Toggle pin output #[inline(always)] pub fn toggle(&mut self) { if self.is_set_low() { @@ -135,11 +140,13 @@ impl ErasedPin where MODE: super::sealed::Readable, { + /// Is the input pin high? #[inline(always)] pub fn is_high(&self) -> bool { !self.is_low() } + /// Is the input pin low? #[inline(always)] pub fn is_low(&self) -> bool { self.block().idr.read().bits() & (1 << self.pin_id()) == 0 diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index 1fba20853..3459d65c8 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -1,7 +1,5 @@ use super::*; -pub type PEPin = PartiallyErasedPin; - /// Partially erased pin /// /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). @@ -58,12 +56,14 @@ impl PinExt for PartiallyErasedPin { } impl PartiallyErasedPin> { + /// Drives the pin high #[inline(always)] pub fn set_high(&mut self) { // NOTE(unsafe) atomic write to a stateless register unsafe { (*Gpio::

::ptr()).bsrr.write(|w| w.bits(1 << self.i)) } } + /// Drives the pin low #[inline(always)] pub fn set_low(&mut self) { // NOTE(unsafe) atomic write to a stateless register @@ -74,6 +74,7 @@ impl PartiallyErasedPin> { } } + /// Is the pin in drive high or low mode? #[inline(always)] pub fn get_state(&self) -> PinState { if self.is_set_low() { @@ -83,6 +84,7 @@ impl PartiallyErasedPin> { } } + /// Drives the pin high or low depending on the provided value #[inline(always)] pub fn set_state(&mut self, state: PinState) { match state { @@ -91,17 +93,20 @@ impl PartiallyErasedPin> { } } + /// Is the pin in drive high mode? #[inline(always)] pub fn is_set_high(&self) -> bool { !self.is_set_low() } + /// Is the pin in drive low mode? #[inline(always)] pub fn is_set_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects unsafe { (*Gpio::

::ptr()).odr.read().bits() & (1 << self.i) == 0 } } + /// Toggle pin output #[inline(always)] pub fn toggle(&mut self) { if self.is_set_low() { @@ -116,11 +121,13 @@ impl PartiallyErasedPin where MODE: super::sealed::Readable, { + /// Is the input pin high? #[inline(always)] pub fn is_high(&self) -> bool { !self.is_low() } + /// Is the input pin low? #[inline(always)] pub fn is_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects diff --git a/src/lib.rs b/src/lib.rs index 88ae626cf..99ca630f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -331,5 +331,5 @@ pub struct TryFromIntError; fn stripped_type_name() -> &'static str { let s = core::any::type_name::(); let p = s.split("::"); - p.last().unwrap() + p.last().unwrap_or(s) } diff --git a/testsuite/tests/gpio_input.rs b/testsuite/tests/gpio_input.rs index 3c5c47922..77a3208a0 100644 --- a/testsuite/tests/gpio_input.rs +++ b/testsuite/tests/gpio_input.rs @@ -5,11 +5,11 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::{EPin, Input}; +use hal::gpio::{ErasedPin, Input}; struct State { - input_ground: EPin, - input_vdd: EPin, + input_ground: ErasedPin, + input_vdd: ErasedPin, } #[defmt_test::tests] diff --git a/testsuite/tests/gpio_input_puller.rs b/testsuite/tests/gpio_input_puller.rs index 488be5d2f..72392e25e 100644 --- a/testsuite/tests/gpio_input_puller.rs +++ b/testsuite/tests/gpio_input_puller.rs @@ -5,11 +5,11 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::{self, EPin, Input, Pull}; +use hal::gpio::{self, ErasedPin, Input, Pull}; use hal::{pac, prelude::*}; struct State { - observer: EPin, + observer: ErasedPin, puller: gpio::PC1, pupdr: gpio::PUPDR<'C'>, } diff --git a/testsuite/tests/gpio_output_open_drain.rs b/testsuite/tests/gpio_output_open_drain.rs index a9d5bcee0..179201f10 100644 --- a/testsuite/tests/gpio_output_open_drain.rs +++ b/testsuite/tests/gpio_output_open_drain.rs @@ -5,11 +5,11 @@ use testsuite as _; use stm32f3xx_hal as hal; -use hal::gpio::{EPin, Input, OpenDrain, Output}; +use hal::gpio::{ErasedPin, Input, OpenDrain, Output}; struct State { - input_pin: EPin, - output_pin: EPin>, + input_pin: ErasedPin, + output_pin: ErasedPin>, } #[defmt_test::tests] diff --git a/testsuite/tests/gpio_output_push_pull.rs b/testsuite/tests/gpio_output_push_pull.rs index 67f7abd49..89d079015 100644 --- a/testsuite/tests/gpio_output_push_pull.rs +++ b/testsuite/tests/gpio_output_push_pull.rs @@ -7,11 +7,11 @@ use panic_probe as _; use hal::prelude::*; use stm32f3xx_hal as hal; -use hal::gpio::{EPin, Input, Output, PushPull}; +use hal::gpio::{ErasedPin, Input, Output, PushPull}; struct State { - input_pin: EPin, - output_pin: EPin>, + input_pin: ErasedPin, + output_pin: ErasedPin>, } #[defmt_test::tests] From ae9bbc72717a363774706da248ec840ae7151be2 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Fri, 1 Apr 2022 19:57:02 +0300 Subject: [PATCH 4/9] sealed -> marker --- src/gpio.rs | 30 +++++++++++++++--------------- src/gpio/erased.rs | 2 +- src/gpio/hal_02.rs | 6 +++--- src/gpio/partially_erased.rs | 2 +- 4 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/gpio.rs b/src/gpio.rs index 8d81b6c5f..a9a3dbb18 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -157,7 +157,7 @@ pub struct Analog; /// JTAG/SWD mote (type state) pub type Debugger = Alternate<0, PushPull>; -mod sealed { +mod marker { /// Marker trait that show if `ExtiPin` can be implemented pub trait Interruptable {} /// Marker trait for readable pin modes @@ -170,16 +170,16 @@ mod sealed { pub trait NotAlt {} } -impl sealed::Readable for Input {} -impl sealed::Readable for Output {} -impl sealed::Active for Input {} -impl sealed::OutputSpeed for Output {} -impl sealed::OutputSpeed for Alternate {} -impl sealed::Active for Output {} -impl sealed::Active for Alternate {} -impl sealed::NotAlt for Input {} -impl sealed::NotAlt for Output {} -impl sealed::NotAlt for Analog {} +impl marker::Readable for Input {} +impl marker::Readable for Output {} +impl marker::Active for Input {} +impl marker::OutputSpeed for Output {} +impl marker::OutputSpeed for Alternate {} +impl marker::Active for Output {} +impl marker::Active for Alternate {} +impl marker::NotAlt for Input {} +impl marker::NotAlt for Output {} +impl marker::NotAlt for Analog {} /// GPIO Pin speed selection #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -205,7 +205,7 @@ pub enum Edge { RisingFalling, } -use sealed::Interruptable; +use marker::Interruptable; impl Interruptable for Output {} impl Interruptable for Input {} @@ -417,7 +417,7 @@ impl PinExt for Pin { impl Pin where - MODE: sealed::OutputSpeed, + MODE: marker::OutputSpeed, { /// Set pin speed pub fn set_speed(&mut self, _ospeedr: &mut OSPEEDR

, speed: Speed) { @@ -439,7 +439,7 @@ where impl Pin where - MODE: sealed::Active, + MODE: marker::Active, { /// Set the internal pull-up and pull-down resistor pub fn set_internal_resistor(&mut self, _pupdr: &mut PUPDR

, resistor: Pull) { @@ -586,7 +586,7 @@ impl Pin> { impl Pin where - MODE: sealed::Readable, + MODE: marker::Readable, { /// Is the input pin high? #[inline(always)] diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs index 9c4d6b607..0f3f67551 100644 --- a/src/gpio/erased.rs +++ b/src/gpio/erased.rs @@ -138,7 +138,7 @@ impl ErasedPin> { impl ErasedPin where - MODE: super::sealed::Readable, + MODE: super::marker::Readable, { /// Is the input pin high? #[inline(always)] diff --git a/src/gpio/hal_02.rs b/src/gpio/hal_02.rs index f1cd0824b..11e4dfc7a 100644 --- a/src/gpio/hal_02.rs +++ b/src/gpio/hal_02.rs @@ -51,7 +51,7 @@ impl ToggleableOutputPin for Pin InputPin for Pin where - MODE: super::sealed::Readable, + MODE: super::marker::Readable, { type Error = Infallible; @@ -147,7 +147,7 @@ impl ToggleableOutputPin for ErasedPin> { impl InputPin for ErasedPin where - MODE: super::sealed::Readable, + MODE: super::marker::Readable, { type Error = core::convert::Infallible; @@ -204,7 +204,7 @@ impl ToggleableOutputPin for PartiallyErasedPin InputPin for PartiallyErasedPin where - MODE: super::sealed::Readable, + MODE: super::marker::Readable, { type Error = Infallible; diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index 3459d65c8..563fcdb7b 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -119,7 +119,7 @@ impl PartiallyErasedPin> { impl PartiallyErasedPin where - MODE: super::sealed::Readable, + MODE: super::marker::Readable, { /// Is the input pin high? #[inline(always)] From 6607f5d124854a69b88040c06fce749b6835418f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 3 Apr 2022 07:59:08 +0300 Subject: [PATCH 5/9] move IntoAf to markers --- codegen/src/codegen/gpio.rs | 3 +++ src/gpio.rs | 13 ++++++------- src/gpio/convert.rs | 4 ++-- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/codegen/src/codegen/gpio.rs b/codegen/src/codegen/gpio.rs index 381a5f03a..1e9cdca64 100644 --- a/codegen/src/codegen/gpio.rs +++ b/codegen/src/codegen/gpio.rs @@ -49,6 +49,9 @@ fn merge_pins_by_port(pins: &[gpio::Pin]) -> Result> { let mut ports = Vec::new(); for (id, mut pins) in pins_by_port { + pins.retain(|p| { + p.name != "PDR_ON" && p.name != "PC14OSC32_IN" && p.name != "PC15OSC32_OUT" + }); pins.sort_by_key(|p| p.number().unwrap_or_default()); pins.dedup_by_key(|p| p.number().unwrap_or_default()); ports.push(Port { id, pins }); diff --git a/src/gpio.rs b/src/gpio.rs index a9a3dbb18..f378e66e5 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -168,6 +168,8 @@ mod marker { pub trait Active {} /// Marker trait for all pin modes except alternate pub trait NotAlt {} + /// Marker trait for pins with alternate function `A` mapping + pub trait IntoAf: super::HL {} } impl marker::Readable for Input {} @@ -230,9 +232,6 @@ pub trait HL { type Afr; } -/// Marker trait for pins with alternate function `A` mapping -pub trait IntoAf: HL {} - macro_rules! cr { ($high:literal: [$($i:literal),+]) => { $( @@ -609,7 +608,7 @@ macro_rules! gpio { pub mod $gpiox { use crate::pac::$GPIOX; use crate::rcc::{Enable, Reset, AHB}; - use super::{Afr, Input, MODER, OTYPER, OSPEEDR, PUPDR, IntoAf}; + use super::{Afr, MODER, OTYPER, OSPEEDR, PUPDR}; /// GPIO parts pub struct Parts { @@ -660,10 +659,10 @@ macro_rules! gpio { $( #[doc=stringify!($PXi)] #[doc=" pin"] - pub type $PXi = super::Pin<$port_id, $i, MODE>; + pub type $PXi = super::Pin<$port_id, $i, MODE>; $( - impl IntoAf<$A> for $PXi { } + impl super::marker::IntoAf<$A> for $PXi { } )* )+ @@ -1197,7 +1196,7 @@ impl Gpio

{ 'G' => crate::pac::GPIOG::ptr() as _, #[cfg(feature = "gpio-f303e")] 'H' => crate::pac::GPIOH::ptr() as _, - _ => crate::pac::GPIOA::ptr(), + _ => panic!("Unknown GPIO port"), } } } diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs index a58016440..054d11761 100644 --- a/src/gpio/convert.rs +++ b/src/gpio/convert.rs @@ -9,7 +9,7 @@ impl Pin { _afr: &mut ::Afr, ) -> Pin> where - Self: IntoAf, + Self: super::marker::IntoAf, { self.into_mode() } @@ -22,7 +22,7 @@ impl Pin { _afr: &mut ::Afr, ) -> Pin> where - Self: IntoAf, + Self: super::marker::IntoAf, { self.into_mode() } From 73323d4ada5ba5d94cd1cbda7fbd5075a4c75d23 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 3 Apr 2022 10:45:30 +0300 Subject: [PATCH 6/9] move Exti impl to submodule --- src/gpio.rs | 116 ++--------------------------------------------- src/gpio/exti.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 113 insertions(+), 113 deletions(-) create mode 100644 src/gpio/exti.rs diff --git a/src/gpio.rs b/src/gpio.rs index f378e66e5..093e92bc8 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -80,9 +80,7 @@ use core::marker::PhantomData; -use crate::pac::{Interrupt, EXTI}; use crate::rcc::AHB; -use crate::Switch; mod convert; use convert::PinMode; @@ -91,6 +89,7 @@ pub use partially_erased::PartiallyErasedPin; mod erased; pub use erased::ErasedPin; mod dynamic; +mod exti; pub use dynamic::{Dynamic, DynamicPin}; mod hal_02; @@ -172,6 +171,8 @@ mod marker { pub trait IntoAf: super::HL {} } +impl marker::Interruptable for Output {} +impl marker::Interruptable for Input {} impl marker::Readable for Input {} impl marker::Readable for Output {} impl marker::Active for Input {} @@ -207,10 +208,6 @@ pub enum Edge { RisingFalling, } -use marker::Interruptable; -impl Interruptable for Output {} -impl Interruptable for Input {} - /// Opaque MODER register pub struct MODER(()); @@ -262,113 +259,6 @@ macro_rules! af { af!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); -/// Return an EXTI register for the current CPU -#[cfg(feature = "svd-f373")] -macro_rules! reg_for_cpu { - ($exti:expr, $xr:ident) => { - $exti.$xr - }; -} - -/// Return an EXTI register for the current CPU -#[cfg(not(feature = "svd-f373"))] -macro_rules! reg_for_cpu { - ($exti:expr, $xr:ident) => { - paste::paste! { - $exti.[<$xr 1>] - } - }; -} - -impl Pin -where - MODE: Interruptable, -{ - /// NVIC interrupt number of interrupt from this pin - /// - /// Used to unmask / enable the interrupt with [`cortex_m::peripheral::NVIC::unmask()`]. - /// This is also useful for all other [`cortex_m::peripheral::NVIC`] functions. - // TODO(Sh3rm4n): It would be cool to have this either const or have a const function. - // But this is currenlty not possible, because index() is runtime defined. - pub fn interrupt(&self) -> Interrupt { - match N { - 0 => Interrupt::EXTI0, - 1 => Interrupt::EXTI1, - #[cfg(feature = "svd-f373")] - 2 => Interrupt::EXTI2_TS, - #[cfg(not(feature = "svd-f373"))] - 2 => Interrupt::EXTI2_TSC, - 3 => Interrupt::EXTI3, - 4 => Interrupt::EXTI4, - #[cfg(feature = "svd-f373")] - 5..=9 => Interrupt::EXTI5_9, - #[cfg(not(feature = "svd-f373"))] - 5..=9 => Interrupt::EXTI9_5, - 10..=15 => Interrupt::EXTI15_10, - _ => crate::unreachable!(), - } - } - - /// Generate interrupt on rising edge, falling edge, or both - pub fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) { - const BITWIDTH: u8 = 1; - let (rise, fall) = match edge { - Edge::Rising => (true as u32, false as u32), - Edge::Falling => (false as u32, true as u32), - Edge::RisingFalling => (true as u32, true as u32), - }; - // SAFETY: Unguarded write to the register, but behind a &mut - unsafe { - crate::modify_at!(reg_for_cpu!(exti, rtsr), BITWIDTH, N, rise); - crate::modify_at!(reg_for_cpu!(exti, ftsr), BITWIDTH, N, fall); - } - } - - /// Configure external interrupts from this pin - /// - /// # Note - /// - /// Remeber to also configure the interrupt pin on - /// the SysCfg site, with [`crate::syscfg::SysCfg::select_exti_interrupt_source()`] - pub fn configure_interrupt(&mut self, exti: &mut EXTI, enable: impl Into) { - const BITWIDTH: u8 = 1; - - let enable: Switch = enable.into(); - let enable: bool = enable.into(); - - let value = u32::from(enable); - // SAFETY: Unguarded write to the register, but behind a &mut - unsafe { crate::modify_at!(reg_for_cpu!(exti, imr), BITWIDTH, N, value) }; - } - - /// Enable external interrupts from this pin - /// - /// # Note - /// - /// Remeber to also configure the interrupt pin on - /// the SysCfg site, with [`crate::syscfg::SysCfg::select_exti_interrupt_source()`] - pub fn enable_interrupt(&mut self, exti: &mut EXTI) { - self.configure_interrupt(exti, Switch::On) - } - - /// Disable external interrupts from this pin - pub fn disable_interrupt(&mut self, exti: &mut EXTI) { - self.configure_interrupt(exti, Switch::Off) - } - - /// Clear the interrupt pending bit for this pin - pub fn clear_interrupt(&mut self) { - // SAFETY: Atomic write to register without side-effects. - unsafe { reg_for_cpu!((*EXTI::ptr()), pr).write(|w| w.bits(1 << N)) }; - } - - /// Reads the interrupt pending bit for this pin - pub fn is_interrupt_pending(&self) -> bool { - // SAFETY: Atomic write to register without side-effects. - unsafe { reg_for_cpu!((*EXTI::ptr()), pr).read().bits() & (1 << N) != 0 } - } -} - /// Generic pin type /// /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). diff --git a/src/gpio/exti.rs b/src/gpio/exti.rs new file mode 100644 index 000000000..16f064ce6 --- /dev/null +++ b/src/gpio/exti.rs @@ -0,0 +1,110 @@ +use super::{marker, Edge, Pin}; +use crate::pac::{Interrupt, EXTI}; +use crate::Switch; + +/// Return an EXTI register for the current CPU +#[cfg(feature = "svd-f373")] +macro_rules! reg_for_cpu { + ($exti:expr, $xr:ident) => { + $exti.$xr + }; +} + +/// Return an EXTI register for the current CPU +#[cfg(not(feature = "svd-f373"))] +macro_rules! reg_for_cpu { + ($exti:expr, $xr:ident) => { + paste::paste! { + $exti.[<$xr 1>] + } + }; +} + +impl Pin { + /// NVIC interrupt number of interrupt from this pin + /// + /// Used to unmask / enable the interrupt with [`cortex_m::peripheral::NVIC::unmask()`]. + /// This is also useful for all other [`cortex_m::peripheral::NVIC`] functions. + pub const fn interrupt(&self) -> Interrupt { + match N { + 0 => Interrupt::EXTI0, + 1 => Interrupt::EXTI1, + #[cfg(feature = "svd-f373")] + 2 => Interrupt::EXTI2_TS, + #[cfg(not(feature = "svd-f373"))] + 2 => Interrupt::EXTI2_TSC, + 3 => Interrupt::EXTI3, + 4 => Interrupt::EXTI4, + #[cfg(feature = "svd-f373")] + 5..=9 => Interrupt::EXTI5_9, + #[cfg(not(feature = "svd-f373"))] + 5..=9 => Interrupt::EXTI9_5, + 10..=15 => Interrupt::EXTI15_10, + _ => panic!("Unsupported pin number"), + } + } +} + +impl Pin +where + MODE: marker::Interruptable, +{ + /// Generate interrupt on rising edge, falling edge, or both + pub fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: Edge) { + const BITWIDTH: u8 = 1; + let (rise, fall) = match edge { + Edge::Rising => (true as u32, false as u32), + Edge::Falling => (false as u32, true as u32), + Edge::RisingFalling => (true as u32, true as u32), + }; + // SAFETY: Unguarded write to the register, but behind a &mut + unsafe { + crate::modify_at!(reg_for_cpu!(exti, rtsr), BITWIDTH, N, rise); + crate::modify_at!(reg_for_cpu!(exti, ftsr), BITWIDTH, N, fall); + } + } + + /// Configure external interrupts from this pin + /// + /// # Note + /// + /// Remeber to also configure the interrupt pin on + /// the SysCfg site, with [`crate::syscfg::SysCfg::select_exti_interrupt_source()`] + pub fn configure_interrupt(&mut self, exti: &mut EXTI, enable: impl Into) { + const BITWIDTH: u8 = 1; + + let enable: Switch = enable.into(); + let enable: bool = enable.into(); + + let value = u32::from(enable); + // SAFETY: Unguarded write to the register, but behind a &mut + unsafe { crate::modify_at!(reg_for_cpu!(exti, imr), BITWIDTH, N, value) }; + } + + /// Enable external interrupts from this pin + /// + /// # Note + /// + /// Remeber to also configure the interrupt pin on + /// the SysCfg site, with [`crate::syscfg::SysCfg::select_exti_interrupt_source()`] + pub fn enable_interrupt(&mut self, exti: &mut EXTI) { + self.configure_interrupt(exti, Switch::On) + } + + /// Disable external interrupts from this pin + pub fn disable_interrupt(&mut self, exti: &mut EXTI) { + self.configure_interrupt(exti, Switch::Off) + } + + /// Clear the interrupt pending bit for this pin + pub fn clear_interrupt(&mut self) { + // SAFETY: Atomic write to register without side-effects. + unsafe { reg_for_cpu!((*EXTI::ptr()), pr).write(|w| w.bits(1 << N)) }; + } + + /// Reads the interrupt pending bit for this pin + pub fn is_interrupt_pending(&self) -> bool { + // SAFETY: Atomic write to register without side-effects. + unsafe { reg_for_cpu!((*EXTI::ptr()), pr).read().bits() & (1 << N) != 0 } + } +} From 23fff038e465c1dab52a5e5fca792326c5b19fa6 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 26 Apr 2022 17:25:41 +0300 Subject: [PATCH 7/9] pub PinMode --- src/gpio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gpio.rs b/src/gpio.rs index 093e92bc8..3171d8985 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -83,7 +83,7 @@ use core::marker::PhantomData; use crate::rcc::AHB; mod convert; -use convert::PinMode; +pub use convert::PinMode; mod partially_erased; pub use partially_erased::PartiallyErasedPin; mod erased; From 3ae4cc35ea137da5e91dc9b83e3253398b2d559f Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 4 Jul 2023 12:06:09 +0300 Subject: [PATCH 8/9] fix --- examples/dac_sine.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/dac_sine.rs b/examples/dac_sine.rs index 58c7ede77..35e113056 100644 --- a/examples/dac_sine.rs +++ b/examples/dac_sine.rs @@ -38,10 +38,10 @@ fn main() -> ! { cortex_m::asm::delay(8_000); } if led { - ok_led.set_low().unwrap(); + ok_led.set_low(); led = false; } else { - ok_led.set_high().unwrap(); + ok_led.set_high(); led = true; } } From 7e0bad83d9784ae642b49267f03ad20a5d0de7c3 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 4 Jul 2023 12:19:25 +0300 Subject: [PATCH 9/9] into_mode for Erased pins --- src/gpio/convert.rs | 61 +++++++++++++++++++++++++++++------- src/gpio/erased.rs | 11 ++++++- src/gpio/partially_erased.rs | 2 +- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs index 054d11761..f7b17c607 100644 --- a/src/gpio/convert.rs +++ b/src/gpio/convert.rs @@ -123,26 +123,39 @@ impl Pin { /// ensure they use this properly. #[inline(always)] pub(super) fn mode(&mut self) { - let offset = 2 * N; + change_mode!((*Gpio::

::ptr()), N); + } + + #[inline(always)] + /// Converts pin into specified mode + pub fn into_mode(mut self) -> Pin { + self.mode::(); + Pin::new() + } +} + +macro_rules! change_mode { + ($block:expr, $N:ident) => { + let offset = 2 * $N; unsafe { if MODE::OTYPER != M::OTYPER { if let Some(otyper) = M::OTYPER { - (*Gpio::

::ptr()) + $block .otyper - .modify(|r, w| w.bits(r.bits() & !(0b1 << N) | (otyper << N))); + .modify(|r, w| w.bits(r.bits() & !(0b1 << $N) | (otyper << $N))); } } if MODE::AFR != M::AFR { if let Some(afr) = M::AFR { - if N < 8 { - let offset2 = 4 * { N }; - (*Gpio::

::ptr()).afrl.modify(|r, w| { + if $N < 8 { + let offset2 = 4 * { $N }; + $block.afrl.modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) }); } else { - let offset2 = 4 * { N - 8 }; - (*Gpio::

::ptr()).afrh.modify(|r, w| { + let offset2 = 4 * { $N - 8 }; + $block.afrh.modify(|r, w| { w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) }); } @@ -150,18 +163,44 @@ impl Pin { } if MODE::MODER != M::MODER { - (*Gpio::

::ptr()) + $block .moder .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | (M::MODER << offset))); } } + }; +} +use change_mode; + +use super::ErasedPin; +impl ErasedPin { + #[inline(always)] + pub(super) fn mode(&mut self) { + let n = self.pin_id(); + change_mode!(self.block(), n); } #[inline(always)] /// Converts pin into specified mode - pub(super) fn into_mode(mut self) -> Pin { + pub fn into_mode(mut self) -> ErasedPin { self.mode::(); - Pin::new() + ErasedPin::from_pin_port(self.into_pin_port()) + } +} + +use super::PartiallyErasedPin; +impl PartiallyErasedPin { + #[inline(always)] + pub(super) fn mode(&mut self) { + let n = self.pin_id(); + change_mode!((*Gpio::

::ptr()), n); + } + + #[inline(always)] + /// Converts pin into specified mode + pub fn into_mode(mut self) -> PartiallyErasedPin { + self.mode::(); + PartiallyErasedPin::new(self.i) } } diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs index 0f3f67551..dede8ed64 100644 --- a/src/gpio/erased.rs +++ b/src/gpio/erased.rs @@ -47,6 +47,15 @@ impl PinExt for ErasedPin { } impl ErasedPin { + pub(crate) fn from_pin_port(pin_port: u8) -> Self { + Self { + pin_port, + _mode: PhantomData, + } + } + pub(crate) fn into_pin_port(self) -> u8 { + self.pin_port + } pub(crate) fn new(port: u8, pin: u8) -> Self { Self { pin_port: port << 4 | pin, @@ -55,7 +64,7 @@ impl ErasedPin { } #[inline] - fn block(&self) -> &crate::pac::gpioa::RegisterBlock { + pub(crate) fn block(&self) -> &crate::pac::gpioa::RegisterBlock { // This function uses pointer arithmetic instead of branching to be more efficient // The logic relies on the following assumptions: diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs index 563fcdb7b..c23054253 100644 --- a/src/gpio/partially_erased.rs +++ b/src/gpio/partially_erased.rs @@ -5,7 +5,7 @@ use super::*; /// - `MODE` is one of the pin modes (see [Modes](crate::gpio#modes) section). /// - `P` is port name: `A` for GPIOA, `B` for GPIOB, etc. pub struct PartiallyErasedPin { - i: u8, + pub(crate) i: u8, _mode: PhantomData, }