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/codegen/src/codegen/gpio.rs b/codegen/src/codegen/gpio.rs index 107b15190..1e9cdca64 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(); @@ -50,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 }); @@ -60,94 +62,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/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/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; } } diff --git a/examples/gpio_erased.rs b/examples/gpio_erased.rs index 658a26331..14eff22dc 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::ErasedPin; 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..3171d8985 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,241 +62,143 @@ //! //! [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 + +use core::marker::PhantomData; + +use crate::rcc::AHB; -use core::{convert::Infallible, marker::PhantomData}; +mod convert; +pub use convert::PinMode; +mod partially_erased; +pub use partially_erased::PartiallyErasedPin; +mod erased; +pub use erased::ErasedPin; +mod dynamic; +mod exti; +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); - } +/// Id, port and mode for any pin +pub trait PinExt { + /// Current pin mode + type Mode; + /// Pin number + fn pin_id(&self) -> u8; + /// Port number starting from 0 + 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; +/// JTAG/SWD mote (type state) +pub type Debugger = Alternate<0, PushPull>; + +mod marker { + /// 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 all pin modes except alternate + pub trait NotAlt {} /// 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, + pub trait IntoAf: super::HL {} } -#[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 - } -} - -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::Interruptable for Output {} +impl marker::Interruptable for Input {} 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::OutputSpeed for Output {} +impl marker::OutputSpeed for Alternate {} impl marker::Active for Output {} -impl marker::Active for Alternate {} +impl marker::Active for Alternate {} +impl marker::NotAlt for Input {} +impl marker::NotAlt for Output {} +impl marker::NotAlt for Analog {} -/// Slew rate configuration -#[derive(Copy, Clone, PartialEq, Eq)] +/// GPIO Pin speed selection #[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { /// Low speed - Low, + Low = 0, /// Medium speed - Medium, + Medium = 1, /// 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, + 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, @@ -302,604 +208,319 @@ pub enum Edge { 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, -} +/// Opaque MODER register +pub struct MODER(()); -// Make all GPIO peripheral trait extensions sealable. -impl crate::private::Sealed for Pin {} +/// Opaque OTYPER register +pub struct OTYPER(()); -/// 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; +/// Opaque OSPEEDR register +pub struct OSPEEDR(()); -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, - } - } +/// Opaque PUPDR register +pub struct PUPDR(()); + +/// Opaque AFR register +pub struct Afr(()); + +/// Represents high or low configuration register +pub trait HL { + /// Configuration register associated to pin + type Afr; } -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, - } +macro_rules! cr { + ($high:literal: [$($i:literal),+]) => { + $( + impl HL for Pin { + type Afr = Afr; + } + )+ } } -impl Pin { - fn into_mode(self) -> Pin { - Pin { - gpio: self.gpio, - index: self.index, - _mode: PhantomData, +cr!(false: [0, 1, 2, 3, 4, 5, 6, 7]); +cr!(true: [8, 9, 10, 11, 12, 13, 14, 15]); + +macro_rules! af { + ($i:literal, $AFi:ident) => { + #[doc = concat!("Alternate function ", $i, " (type state)" )] + pub type $AFi = Alternate<$i, Otype>; + }; + + ([$($i:literal),+ $(,)?]) => { + paste::paste! { + $( + af!($i, []); + )+ } - } + }; } -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() - } +af!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); - /// 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() +/// 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 } } +} - /// 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() +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::() + )) } +} - /// 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() +#[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 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() - } +impl PinExt for Pin { + type Mode = 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() + #[inline(always)] + fn pin_id(&self) -> u8 { + N } - - /// 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() + #[inline(always)] + fn port_id(&self) -> u8 { + P as u8 - b'A' } } -impl Pin +impl Pin where - Gpio: marker::GpioStatic, - Index: marker::Index, - Mode: marker::OutputSpeed, + 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()), + /// Set pin speed + pub fn set_speed(&mut self, _ospeedr: &mut OSPEEDR

, speed: Speed) { + let offset = 2 * { N }; + + unsafe { + (*Gpio::

::ptr()) + .ospeedr + .modify(|r, w| w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset))); } } + + /// Set pin speed + pub fn speed(mut self, ospeedr: &mut OSPEEDR

, speed: Speed) -> Self { + self.set_speed(ospeedr, speed); + self + } } -impl Pin +impl Pin where - Gpio: marker::GpioStatic, - Index: marker::Index, - Mode: marker::Active, + 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()), + 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))) + }; + } + + /// 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 + } + + /// 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) } } - /// 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) { + /// Enables / disables the internal pull down + pub fn internal_pull_down(self, pupdr: &mut PUPDR

, on: bool) -> Self { if on { - pupdr.pull_up(self.index.index()); + self.internal_resistor(pupdr, Pull::Down) } else { - pupdr.floating(self.index.index()); + self.internal_resistor(pupdr, Pull::None) } } } -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(()) +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) -> PartiallyErasedPin { + PartiallyErasedPin::new(N) } - 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(()) + /// 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) -> ErasedPin { + ErasedPin::new(P as u8 - b'A', N) } } -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()?) +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(), + } } - - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*self.gpio.ptr()).is_low(self.index.index()) }) + #[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)) } } -} - -impl StatefulOutputPin for Pin> -where - Gpio: marker::Gpio, - Index: marker::Index, -{ - fn is_set_high(&self) -> Result { - Ok(!self.is_set_low()?) + #[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))) } } - - fn is_set_low(&self) -> Result { + #[inline(always)] + fn _is_set_low(&self) -> bool { // NOTE(unsafe) atomic read with no side effects - Ok(unsafe { (*self.gpio.ptr()).is_set_low(self.index.index()) }) + 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 toggleable::Default for Pin> -where - Gpio: marker::Gpio, - Index: marker::Index, -{ -} - -/// 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 - Gpio: marker::Gpio, - Index: marker::Index, - Mode: marker::Active, -{ - /// 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 self.index.index() { - 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!(), - } +impl Pin> { + /// Drives the pin high + #[inline(always)] + pub fn set_high(&mut self) { + self._set_high() } - /// 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), - 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, index, rise); - crate::modify_at!(reg_for_cpu!(exti, ftsr), BITWIDTH, index, fall); - } + /// Drives the pin low + #[inline(always)] + pub fn set_low(&mut self) { + self._set_low() } - /// 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 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) }; + /// Is the pin in drive high or low mode? + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } } - /// 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) + /// Drives the pin high or low depending on the provided value + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } } - /// Disable external interrupts from this pin - pub fn disable_interrupt(&mut self, exti: &mut EXTI) { - self.configure_interrupt(exti, Switch::Off) + /// Is the pin in drive high mode? + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() } - /// 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())) }; + /// Is the pin in drive low mode? + #[inline(always)] + pub fn is_set_low(&self) -> bool { + self._is_set_low() } - /// 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 } + /// Toggle pin output + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } } } -impl Pin +impl Pin where - Gpio: marker::GpioStatic, - Index: marker::Index, + MODE: marker::Readable, { - /// 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() + /// Is the input pin high? + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() } - /// 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() + /// Is the input pin low? + #[inline(always)] + pub fn is_low(&self) -> bool { + self._is_low() } } -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) - } - - /// 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) - } - } - }; - - ([$($i:literal),+ $(,)?]) => { - paste::paste! { - $( - af!($i, [], [], []); - )+ - } - }; -} - -af!([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]); - -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 - } - - #[inline(always)] - fn is_set_low(&self, i: u8) -> bool { - self.odr.read().bits() & (1 << i) == 0 - } - - #[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)) }; - } - - #[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))) }; - } - } - )+ - }; -} - -/// 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 } - )+ - } - ) => { - 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) }; - } - )+ - } - }; -} - 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() - } - - #[inline(always)] - fn port_index(&self) -> u8 { - $port_index - } - } - - impl marker::Gpio for $Gpiox {} - - impl marker::GpioStatic for $Gpiox { - type MODER = $gpiox::MODER; - type OTYPER = $gpiox::OTYPER; - type OSPEEDR = $gpiox::OSPEEDR; - type PUPDR = $gpiox::PUPDR; - } - - $( - #[doc = concat!("Pin ", stringify!($PXi))] - pub type $PXi = Pin<$Gpiox, U<$i>, Mode>; - - $( - impl marker::IntoAf<$af> for $PXi { - type AFR = $gpiox::$AFR; - } - )* - )+ - - #[doc = concat!("Partially erased pin for ", stringify!($GPIOX))] - pub type $PXx = Pin<$Gpiox, Ux, Mode>; - - #[doc = concat!("All Pins and associated registers for GPIO port ", stringify!($GPIOX))] + ($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 core::marker::PhantomData; - - use crate::{ - pac::{$gpioy, $GPIOX}, - rcc::{AHB, Enable, Reset}, - }; - - use super::{Afr, $Gpiox, GpioExt, Moder, Ospeedr, Otyper, Pupdr, U}; - - #[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, - }; - - pub use super::{ - $PXx, - $( - $PXi, - )+ - }; + use crate::pac::$GPIOX; + use crate::rcc::{Enable, Reset, AHB}; + use super::{Afr, MODER, OTYPER, OSPEEDR, PUPDR}; /// 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 +528,568 @@ 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(()); + #[doc="Common type for "] + #[doc=stringify!($GPIOX)] + #[doc=" related pins"] + pub type $PXn = super::PartiallyErasedPin<$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) }; - } - } + $( + #[doc=stringify!($PXi)] + #[doc=" pin"] + pub type $PXi = super::Pin<$port_id, $i, MODE>; - /// Opaque AFRL register - pub struct AFRL(()); + $( + impl super::marker::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), + PA14: (pa14, 14, [0, 3, 4, 6, 7, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 3, 4, 6, 7, 9, 15], super::Debugger), +]); - /// 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), + 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]), + 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), + 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), +]); - 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), + 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]), + 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!(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!({ - 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!(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), + 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")] +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), + 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]), + 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!(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!({ - 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!(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!({ - 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!(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), + 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")] +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), + 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]), + 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!(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), + 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")] +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), + 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]), + 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!({ - 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!(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!(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 _, + _ => panic!("Unknown GPIO port"), + } + } +} + +// 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..f7b17c607 --- /dev/null +++ b/src/gpio/convert.rs @@ -0,0 +1,254 @@ +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: super::marker::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: super::marker::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) { + 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 { + $block + .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 }; + $block.afrl.modify(|r, w| { + w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) + }); + } else { + let offset2 = 4 * { $N - 8 }; + $block.afrh.modify(|r, w| { + w.bits((r.bits() & !(0b1111 << offset2)) | (afr << offset2)) + }); + } + } + } + + if MODE::MODER != M::MODER { + $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 fn into_mode(mut self) -> ErasedPin { + self.mode::(); + 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) + } +} + +/// 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..51e5e3184 --- /dev/null +++ b/src/gpio/dynamic.rs @@ -0,0 +1,157 @@ +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 { + /// 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 { + InputFloating | InputPullUp | InputPullDown | OutputOpenDrain => true, + OutputPushPull => false, + } + } + + /// Is pin in writable mode + 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(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, + 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; + } + /// 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, + 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; + } + + /// Drives the pin high + pub fn set_high(&mut self) -> Result<(), PinModeError> { + if self.mode.is_output() { + Pin::::new()._set_state(PinState::High); + Ok(()) + } else { + 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); + Ok(()) + } else { + Err(PinModeError::IncorrectMode) + } + } + + /// 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()) + } else { + Err(PinModeError::IncorrectMode) + } + } +} diff --git a/src/gpio/erased.rs b/src/gpio/erased.rs new file mode 100644 index 000000000..dede8ed64 --- /dev/null +++ b/src/gpio/erased.rs @@ -0,0 +1,163 @@ +use super::*; + +/// 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 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, + _mode: PhantomData, + } + } + + #[inline] + 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: + // - 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> { + /// 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 + unsafe { + self.block() + .bsrr + .write(|w| w.bits(1 << (self.pin_id() + 16))) + }; + } + + /// Is the pin in drive high or low mode? + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + /// Drives the pin high or low depending on the provided value + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + /// 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() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl ErasedPin +where + MODE: super::marker::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/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 } + } +} diff --git a/src/gpio/hal_02.rs b/src/gpio/hal_02.rs new file mode 100644 index 000000000..11e4dfc7a --- /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::marker::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::marker::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::marker::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..c23054253 --- /dev/null +++ b/src/gpio/partially_erased.rs @@ -0,0 +1,136 @@ +use super::*; + +/// 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 { + pub(crate) 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> { + /// 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 + unsafe { + (*Gpio::

::ptr()) + .bsrr + .write(|w| w.bits(1 << (self.i + 16))) + } + } + + /// Is the pin in drive high or low mode? + #[inline(always)] + pub fn get_state(&self) -> PinState { + if self.is_set_low() { + PinState::Low + } else { + PinState::High + } + } + + /// Drives the pin high or low depending on the provided value + #[inline(always)] + pub fn set_state(&mut self, state: PinState) { + match state { + PinState::Low => self.set_low(), + PinState::High => self.set_high(), + } + } + + /// 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() { + self.set_high() + } else { + self.set_low() + } + } +} + +impl PartiallyErasedPin +where + MODE: super::marker::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 + unsafe { (*Gpio::

::ptr()).idr.read().bits() & (1 << self.i) == 0 } + } +} diff --git a/src/lib.rs b/src/lib.rs index 1c70cac91..99ca630f7 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_or(s) +} 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..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::{Input, PXx}; +use hal::gpio::{ErasedPin, Input}; struct State { - input_ground: PXx, - input_vdd: PXx, + input_ground: ErasedPin, + input_vdd: ErasedPin, } #[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..72392e25e 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, ErasedPin, Input, Pull}; use hal::{pac, prelude::*}; struct State { - observer: PXx, - puller: gpioc::PC1, - pupdr: gpioc::PUPDR, + observer: ErasedPin, + 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..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::{Input, OpenDrain, Output, PXx}; +use hal::gpio::{ErasedPin, Input, OpenDrain, Output}; struct State { - input_pin: PXx, - output_pin: PXx>, + input_pin: ErasedPin, + output_pin: ErasedPin>, } #[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..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::{Input, Output, PXx, PushPull}; +use hal::gpio::{ErasedPin, Input, Output, PushPull}; struct State { - input_pin: PXx, - output_pin: PXx>, + input_pin: ErasedPin, + output_pin: ErasedPin>, } #[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(