diff --git a/.vscode/settings.json b/.vscode/settings.json index 535b9ec0..627c7439 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,11 +1,6 @@ { "rust-analyzer.check.allTargets": false, - "rust-analyzer.check.extraArgs": [ - "--examples", - ], + "rust-analyzer.check.extraArgs": ["--examples"], "rust-analyzer.cargo.target": "thumbv7em-none-eabihf", - "rust-analyzer.cargo.features": [ - "stm32g473", - "defmt", - ] -} \ No newline at end of file + "rust-analyzer.cargo.features": ["stm32g473", "defmt"] +} diff --git a/.zed/settings.json b/.zed/settings.json new file mode 100644 index 00000000..301631d2 --- /dev/null +++ b/.zed/settings.json @@ -0,0 +1,15 @@ +{ + "lsp": { + "rust-analyzer": { + "initialization_options": { + "cargo": { + "features": ["defmt", "stm32g473"] + }, + "check": { + "allTargets": false, + "targets": "thumbv7em-none-eabihf" + } + } + } + } +} diff --git a/Cargo.toml b/Cargo.toml index 9f3dd598..f9bd0b86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ authors = ["Vitaly Domnikov "] categories = ["embedded", "hardware-support", "no-std"] description = "Peripheral access API for STM32G4 series microcontrollers" documentation = "https://docs.rs/stm32g4xx-hal" -edition = "2018" +edition = "2021" keywords = ["arm", "cortex-m", "stm32g4xx", "hal"] license = "MIT/Apache-2.0" name = "stm32g4xx-hal" @@ -86,19 +86,232 @@ usbd-serial = "0.2.2" default = ["rt"] rt = ["stm32g4/rt"] usb = ["dep:stm32-usbd"] -stm32g431 = ["stm32g4/stm32g431"] -stm32g441 = ["stm32g4/stm32g441"] -stm32g471 = ["stm32g4/stm32g471"] -stm32g473 = ["stm32g4/stm32g473"] -stm32g474 = ["stm32g4/stm32g474"] -stm32g483 = ["stm32g4/stm32g483"] -stm32g484 = ["stm32g4/stm32g484"] -stm32g491 = ["stm32g4/stm32g491"] -stm32g4a1 = ["stm32g4/stm32g4a1"] +stm32g431 = ["stm32g4/stm32g431", "gpio-g43x"] +stm32g441 = ["stm32g4/stm32g441", "gpio-g43x"] +stm32g471 = ["stm32g4/stm32g471", "gpio-g47x"] +stm32g473 = ["stm32g4/stm32g473", "gpio-g47x"] +stm32g474 = ["stm32g4/stm32g474", "gpio-g47x"] +stm32g483 = ["stm32g4/stm32g483", "gpio-g47x"] +stm32g484 = ["stm32g4/stm32g484", "gpio-g47x"] +stm32g491 = ["stm32g4/stm32g491", "gpio-g49x"] +stm32g4a1 = ["stm32g4/stm32g4a1", "gpio-g49x"] + +gpio-g43x = [ + "comp1", + "comp2", + "comp3", + "comp4", + "crs", + "fdcan1", + "gpioa", + "gpiob", + "gpioc", + "gpiod", + "gpioe", + "gpiof", + "gpiog", + "i2c1", + "i2c2", + "i2c3", + "i2s", + "i2s2", + "i2s3", + "ir", + "lptim1", + "lpuart1", + "rcc", + "rtc", + "sai1", + "spi1", + "spi2", + "spi3", + "sys", + "tim1", + "tim15", + "tim16", + "tim17", + "tim2", + "tim3", + "tim4", + "tim8", + "uart4", + "ucpd1", + "usart1", + "usart2", + "usart3", +] +gpio-g47x = [ + "comp1", + "comp2", + "comp3", + "comp4", + "comp5", + "comp6", + "comp7", + "crs", + "fdcan1", + "fdcan2", + "fdcan3", + "fmc", + "gpioa", + "gpiob", + "gpioc", + "gpiod", + "gpioe", + "gpiof", + "gpiog", + "hrtim1", + "i2c1", + "i2c2", + "i2c3", + "i2c4", + "i2s", + "i2s2", + "i2s3", + "ir", + "lptim1", + "lpuart1", + "quadspi1", + "rcc", + "rtc", + "sai1", + "spi1", + "spi2", + "spi3", + "spi4", + "sys", + "tim1", + "tim15", + "tim16", + "tim17", + "tim2", + "tim20", + "tim3", + "tim4", + "tim5", + "tim8", + "uart4", + "uart5", + "ucpd1", + "usart1", + "usart2", + "usart3", +] +gpio-g49x = [ + "comp1", + "comp2", + "comp3", + "comp4", + "crs", + "fdcan1", + "fdcan2", + "gpioa", + "gpiob", + "gpioc", + "gpiod", + "gpioe", + "gpiof", + "gpiog", + "i2c1", + "i2c2", + "i2c3", + "i2s", + "i2s2", + "i2s3", + "ir", + "lptim1", + "lpuart1", + "quadspi1", + "rcc", + "rtc", + "sai1", + "spi1", + "spi2", + "spi3", + "sys", + "tim1", + "tim15", + "tim16", + "tim17", + "tim2", + "tim20", + "tim3", + "tim4", + "tim8", + "uart4", + "uart5", + "ucpd1", + "usart1", + "usart2", + "usart3", +] + +comp1 = [] +comp2 = [] +comp3 = [] +comp4 = [] +comp5 = [] +comp6 = [] +comp7 = [] +crs = [] +fdcan1 = [] +fdcan2 = [] +fdcan3 = [] +fmc = [] +gpioa = [] +gpiob = [] +gpioc = [] +gpiod = [] +gpioe = [] +gpiof = [] +gpiog = [] +hrtim1 = [] +i2c1 = [] +i2c2 = [] +i2c3 = [] +i2c4 = [] +i2s = [] +i2s2 = [] +i2s3 = [] +ir = [] +lptim1 = [] +lpuart1 = [] +quadspi1 = [] +rcc = [] +rtc = [] +sai1 = [] +spi1 = [] +spi2 = [] +spi3 = [] +spi4 = [] +sys = [] +tim1 = [] +tim15 = [] +tim16 = [] +tim17 = [] +tim2 = [] +tim20 = [] +tim3 = [] +tim4 = [] +tim5 = [] +tim8 = [] +uart4 = [] +uart5 = [] +ucpd1 = [] +usart1 = [] +usart2 = [] +usart3 = [] + log-itm = ["cortex-m-log/itm"] log-rtt = [] log-semihost = ["cortex-m-log/semihosting"] -defmt = ["dep:defmt", "fugit/defmt", "nb/defmt-0-3", "embedded-hal/defmt-03", "embedded-io/defmt-03"] +defmt = [ + "dep:defmt", + "fugit/defmt", + "nb/defmt-0-3", + "embedded-hal/defmt-03", + "embedded-io/defmt-03", +] cordic = ["dep:fixed"] [profile.dev] diff --git a/examples/blinky.rs b/examples/blinky.rs index 05a0a6fb..35c8caeb 100644 --- a/examples/blinky.rs +++ b/examples/blinky.rs @@ -29,12 +29,12 @@ fn main() -> ! { loop { info!("Set Led low"); for _ in 0..10_000_000 { - led.set_low().unwrap(); + led.set_low(); } info!("Set Led High"); for _ in 0..10_000_000 { - led.set_high().unwrap(); + led.set_high(); } } } diff --git a/examples/blinky_delay.rs b/examples/blinky_delay.rs index 8b55119f..35e9b5ea 100644 --- a/examples/blinky_delay.rs +++ b/examples/blinky_delay.rs @@ -40,11 +40,11 @@ fn main() -> ! { loop { info!("Toggle"); - led.toggle().unwrap(); + led.toggle(); info!("SYST delay"); delay_syst.delay(1000.millis()); info!("Toggle"); - led.toggle().unwrap(); + led.toggle(); info!("TIM2 delay"); delay_tim2.delay_ms(1000); } diff --git a/examples/button.rs b/examples/button.rs index ef7990ec..c3530b90 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -3,7 +3,7 @@ use stm32g4xx_hal::{ //delay::{DelayExt, SYSTDelayExt}, - gpio::{gpioc, ExtiPin, GpioExt, Input, PullDown, SignalEdge}, + gpio::{self, ExtiPin, GpioExt, Input, SignalEdge}, rcc::RccExt, stm32, stm32::{interrupt, Interrupt}, @@ -14,9 +14,8 @@ use core::cell::RefCell; use core::sync::atomic::{AtomicBool, Ordering}; use cortex_m::{asm::wfi, interrupt::Mutex}; use cortex_m_rt::entry; -use embedded_hal::digital::OutputPin; -type ButtonPin = gpioc::PC13>; +type ButtonPin = gpio::PC13; // Make LED pin globally available static G_BUTTON: Mutex>> = Mutex::new(RefCell::new(None)); @@ -86,10 +85,10 @@ fn main() -> ! { if G_LED_ON.load(Ordering::Relaxed) { println!("Turn Led On!"); - led.set_high().unwrap(); + led.set_high(); } else { println!("Turn Led Off!"); - led.set_low().unwrap(); + led.set_low(); } } } diff --git a/examples/can-echo.rs b/examples/can-echo.rs index 3126e0d4..5301ad8a 100644 --- a/examples/can-echo.rs +++ b/examples/can-echo.rs @@ -57,8 +57,8 @@ fn main() -> ! { let can1 = { info!("Init CAN 1"); - let rx = gpiob.pb8.into_alternate().set_speed(Speed::VeryHigh); - let tx = gpiob.pb9.into_alternate().set_speed(Speed::VeryHigh); + let rx = gpiob.pb8.into_alternate().speed(Speed::VeryHigh); + let tx = gpiob.pb9.into_alternate().speed(Speed::VeryHigh); info!("-- Create CAN 1 instance"); let mut can = dp.FDCAN1.fdcan(tx, rx, &rcc); @@ -82,8 +82,8 @@ fn main() -> ! { // let can2 = { // info!("Init CAN 2"); - // let rx = gpiob.pb5.into_alternate().set_speed(Speed::VeryHigh); - // let tx = gpiob.pb13.into_alternate().set_speed(Speed::VeryHigh); + // let rx = gpiob.pb5.into_alternate().speed(Speed::VeryHigh); + // let tx = gpiob.pb13.into_alternate().speed(Speed::VeryHigh); // info!("-- Create CAN 2 instance"); // let mut can = dp.FDCAN2.fdcan(tx, rx, &rcc); diff --git a/examples/comp.rs b/examples/comp.rs index 5893e6d0..f42ea7ae 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -17,7 +17,6 @@ use rt::entry; fn main() -> ! { use hal::comparator::{ComparatorExt, ComparatorSplit, Config, Hysteresis, RefintInput}; use hal::gpio::GpioExt; - use hal::prelude::OutputPin; use hal::rcc::RccExt; use hal::stm32; use stm32g4xx_hal as hal; @@ -55,8 +54,8 @@ fn main() -> ! { loop { // Read comp1 output and update led1 accordingly match comp1.output() { - true => led1.set_high().unwrap(), - false => led1.set_low().unwrap(), + true => led1.set_high(), + false => led1.set_low(), } } } diff --git a/examples/i2c.rs b/examples/i2c.rs index beea9ae2..8dacce08 100644 --- a/examples/i2c.rs +++ b/examples/i2c.rs @@ -3,7 +3,6 @@ #![no_main] #![no_std] -use hal::i2c::Config; use hal::prelude::*; use hal::stm32; use hal::time::RateExtU32; @@ -23,12 +22,13 @@ fn main() -> ! { let mut rcc = dp.RCC.constrain(); let gpiob = dp.GPIOB.split(&mut rcc); - let sda = gpiob.pb9.into_alternate_open_drain(); - let scl = gpiob.pb8.into_alternate_open_drain(); + let sda = gpiob.pb9; + let scl = gpiob.pb8; - let mut i2c = dp.I2C1.i2c(sda, scl, Config::new(40.kHz()), &mut rcc); + let mut i2c = dp.I2C1.i2c(sda, scl, 40.kHz(), &mut rcc); // Alternatively, it is possible to specify the exact timing as follows (see the documentation // of with_timing() for an explanation of the constant): + //use hal::i2c::Config; //let mut i2c = dp // .I2C1 // .i2c(sda, scl, Config::with_timing(0x3042_0f13), &mut rcc); diff --git a/examples/pwm.rs b/examples/pwm.rs index cee8f7d7..9b94f527 100644 --- a/examples/pwm.rs +++ b/examples/pwm.rs @@ -3,9 +3,7 @@ #![no_std] use cortex_m_rt::entry; -use hal::gpio::gpioa::PA8; -use hal::gpio::Alternate; -use hal::gpio::AF6; +use hal::gpio::{AF6, PA8}; use hal::prelude::*; use hal::stm32; use hal::time::RateExtU32; @@ -23,7 +21,7 @@ fn main() -> ! { let dp = stm32::Peripherals::take().expect("cannot take peripherals"); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); - let pin: PA8> = gpioa.pa8.into_alternate(); + let pin: PA8 = gpioa.pa8.into_alternate(); let mut pwm = dp.TIM1.pwm(pin, 100.Hz(), &mut rcc); diff --git a/examples/spi-dma.rs b/examples/spi-dma.rs index 3404f2c0..1cf95769 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -6,11 +6,6 @@ use crate::hal::{ delay::DelayFromCountDownTimer, - gpio::gpioa::PA5, - gpio::gpioa::PA6, - gpio::gpioa::PA7, - gpio::Alternate, - gpio::AF5, prelude::*, pwr::PwrExt, rcc::Config, @@ -44,9 +39,9 @@ fn main() -> ! { let mut delay_tim2 = DelayFromCountDownTimer::new(timer2.start_count_down(100.millis())); let gpioa = dp.GPIOA.split(&mut rcc); - let sclk: PA5> = gpioa.pa5.into_alternate(); - let miso: PA6> = gpioa.pa6.into_alternate(); - let mosi: PA7> = gpioa.pa7.into_alternate(); + let sclk = gpioa.pa5; + let miso = gpioa.pa6; + let mosi = gpioa.pa7; let spi = dp .SPI1 diff --git a/examples/spi-example.rs b/examples/spi-example.rs index a661e248..34194167 100644 --- a/examples/spi-example.rs +++ b/examples/spi-example.rs @@ -7,11 +7,7 @@ use hal::{ delay::DelayFromCountDownTimer, - gpio::gpioa::PA5, - gpio::gpioa::PA6, - gpio::gpioa::PA7, - gpio::Alternate, - gpio::AF5, + gpio::{AF5, PA5, PA6, PA7}, hal_02::spi::FullDuplex, prelude::*, pwr::PwrExt, @@ -41,26 +37,26 @@ fn main() -> ! { let mut delay_tim2 = DelayFromCountDownTimer::new(timer2.start_count_down(100.millis())); let gpioa = dp.GPIOA.split(&mut rcc); - let sclk: PA5> = gpioa.pa5.into_alternate(); - let miso: PA6> = gpioa.pa6.into_alternate(); - let mosi: PA7> = gpioa.pa7.into_alternate(); + let sclk: PA5 = gpioa.pa5.into_alternate(); + let miso: PA6 = gpioa.pa6.into_alternate(); + let mosi: PA7 = gpioa.pa7.into_alternate(); let mut spi = dp .SPI1 .spi((sclk, miso, mosi), spi::MODE_0, 400.kHz(), &mut rcc); let mut cs = gpioa.pa8.into_push_pull_output(); - cs.set_high().unwrap(); + cs.set_high(); // "Hello world!" - let message: [char; 12] = ['H', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd', '!']; + let message = b"Hello world!"; let mut received_byte: u8; loop { - for byte in message.iter() { - cs.set_low().unwrap(); - spi.send(*byte as u8).unwrap(); + for &byte in message { + cs.set_low(); + spi.send(byte).unwrap(); received_byte = nb::block!(FullDuplex::read(&mut spi)).unwrap(); - cs.set_high().unwrap(); + cs.set_high(); info!("{}", received_byte as char); } diff --git a/examples/spi-sd.rs b/examples/spi-sd.rs index 7be0e077..46e10df2 100644 --- a/examples/spi-sd.rs +++ b/examples/spi-sd.rs @@ -6,11 +6,7 @@ extern crate embedded_sdmmc; use fugit::RateExtU32; -use hal::gpio::gpiob::PB14; -use hal::gpio::gpiob::PB15; -use hal::gpio::gpiof::PF9; -use hal::gpio::Alternate; -use hal::gpio::AF5; +use hal::gpio::{AF5, PB14, PB15, PF9}; use hal::prelude::*; use hal::pwr::PwrExt; use hal::rcc::Config; @@ -38,14 +34,14 @@ fn main() -> ! { let gpiof = dp.GPIOF.split(&mut rcc); let cs = { - let mut cs = gpiof.pf8.into_push_pull_output(); - cs.set_high().unwrap(); + let mut cs = gpiof.pf0.into_push_pull_output(); + cs.set_high(); cs }; - let sck: PF9> = gpiof.pf9.into_alternate(); - let miso: PB14> = gpiob.pb14.into_alternate(); - let mosi: PB15> = gpiob.pb15.into_alternate(); + let sck: PF9 = gpiof.pf9.into_alternate(); + let miso: PB14 = gpiob.pb14.into_alternate(); + let mosi: PB15 = gpiob.pb15.into_alternate(); let spi = dp .SPI2 diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index 544e84ec..c52b10e6 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -75,7 +75,7 @@ fn main() -> ! { while !transfer.get_transfer_complete_flag() {} delay_syst.delay(1000.millis()); - led.toggle().unwrap(); + led.toggle(); transfer.restart(|_tx| {}); } } diff --git a/src/adc.rs b/src/adc.rs index ed8c4c6c..1d259402 100644 --- a/src/adc.rs +++ b/src/adc.rs @@ -12,7 +12,7 @@ pub use crate::time::U32Ext as _; use crate::{ dma::{mux::DmaMuxResources, traits::TargetAddress, PeripheralToMemory}, - gpio::*, + gpio::{self, Analog}, opamp::{self, InternalOutput}, rcc::{Enable, Rcc, Reset}, signature::{VtempCal130, VtempCal30, VDDA_CALIB}, @@ -2673,38 +2673,38 @@ adc!(ADC5 => (ExternalTrigger345, configure_clock_source345, DmaMuxResources::AD #[cfg(any(feature = "stm32g431", feature = "stm32g441", feature = "stm32g471",))] adc_pins!( - gpioa::PA0 => (ADC1, 1), - gpioa::PA0 => (ADC2, 1), - gpioa::PA1 => (ADC1, 2), - gpioa::PA1 => (ADC2, 2), - gpioa::PA2 => (ADC1, 3), - gpioa::PA3 => (ADC1, 4), - gpioa::PA4 => (ADC2, 17), - gpioa::PA5 => (ADC2, 13), - gpioa::PA6 => (ADC2, 3), - gpioa::PA7 => (ADC2, 4), - - gpiob::PB0 => (ADC1, 15), - gpiob::PB1 => (ADC1, 12), - gpiob::PB2 => (ADC2, 12), - gpiob::PB11 => (ADC1, 14), - gpiob::PB11 => (ADC2, 14), - gpiob::PB12 => (ADC1, 11), - gpiob::PB15 => (ADC2, 15), - - gpioc::PC0 => (ADC1, 6), - gpioc::PC0 => (ADC2, 6), - gpioc::PC1 => (ADC1, 7), - gpioc::PC1 => (ADC2, 7), - gpioc::PC2 => (ADC1, 8), - gpioc::PC2 => (ADC2, 8), - gpioc::PC3 => (ADC1, 9), - gpioc::PC3 => (ADC2, 9), - gpioc::PC4 => (ADC2, 5), - gpioc::PC5 => (ADC2, 11), - - gpiof::PF0 => (ADC1, 10), - gpiof::PF1 => (ADC2, 10), + gpio::PA0 => (ADC1, 1), + gpio::PA0 => (ADC2, 1), + gpio::PA1 => (ADC1, 2), + gpio::PA1 => (ADC2, 2), + gpio::PA2 => (ADC1, 3), + gpio::PA3 => (ADC1, 4), + gpio::PA4 => (ADC2, 17), + gpio::PA5 => (ADC2, 13), + gpio::PA6 => (ADC2, 3), + gpio::PA7 => (ADC2, 4), + + gpio::PB0 => (ADC1, 15), + gpio::PB1 => (ADC1, 12), + gpio::PB2 => (ADC2, 12), + gpio::PB11 => (ADC1, 14), + gpio::PB11 => (ADC2, 14), + gpio::PB12 => (ADC1, 11), + gpio::PB15 => (ADC2, 15), + + gpio::PC0 => (ADC1, 6), + gpio::PC0 => (ADC2, 6), + gpio::PC1 => (ADC1, 7), + gpio::PC1 => (ADC2, 7), + gpio::PC2 => (ADC1, 8), + gpio::PC2 => (ADC2, 8), + gpio::PC3 => (ADC1, 9), + gpio::PC3 => (ADC2, 9), + gpio::PC4 => (ADC2, 5), + gpio::PC5 => (ADC2, 11), + + gpio::PF0 => (ADC1, 10), + gpio::PF1 => (ADC2, 10), Temperature => (ADC1, 16), Vbat => (ADC1, 17), @@ -2718,85 +2718,85 @@ adc_pins!( feature = "stm32g484", ))] adc_pins!( - gpioa::PA0 => (ADC1, 1), - gpioa::PA0 => (ADC2, 1), - gpioa::PA1 => (ADC1, 2), - gpioa::PA1 => (ADC2, 2), - gpioa::PA2 => (ADC1, 3), - gpioa::PA3 => (ADC1, 4), - gpioa::PA4 => (ADC2, 17), - gpioa::PA5 => (ADC2, 13), - gpioa::PA6 => (ADC2, 3), - gpioa::PA7 => (ADC2, 4), - gpioa::PA8 => (ADC5, 1), - gpioa::PA9 => (ADC5, 2), - - gpiob::PB0 => (ADC3, 12), - gpiob::PB0 => (ADC1, 15), - gpiob::PB1 => (ADC3, 1), - gpiob::PB1 => (ADC1, 12), - gpiob::PB2 => (ADC2, 12), - gpiob::PB11 => (ADC1, 14), - gpiob::PB11 => (ADC2, 14), - gpiob::PB12 => (ADC4, 3), - gpiob::PB12 => (ADC1, 11), - gpiob::PB13 => (ADC3, 5), - gpiob::PB14 => (ADC4, 4), - gpiob::PB14 => (ADC1, 5), - gpiob::PB15 => (ADC4, 5), - gpiob::PB15 => (ADC2, 15), - - gpioc::PC0 => (ADC1, 6), - gpioc::PC0 => (ADC2, 6), - gpioc::PC1 => (ADC1, 7), - gpioc::PC1 => (ADC2, 7), - gpioc::PC2 => (ADC1, 8), - gpioc::PC2 => (ADC2, 8), - gpioc::PC3 => (ADC1, 9), - gpioc::PC3 => (ADC2, 9), - gpioc::PC4 => (ADC2, 5), - gpioc::PC5 => (ADC2, 11), - - gpioe::PE7 => (ADC3, 4), - gpioe::PE8 => (ADC3, 6), - gpioe::PE8 => (ADC4, 6), - gpioe::PE8 => (ADC5, 6), - gpioe::PE9 => (ADC3, 2), - gpioe::PE10 => (ADC3, 14), - gpioe::PE10 => (ADC4, 14), - gpioe::PE10 => (ADC5, 14), - gpioe::PE11 => (ADC3, 15), - gpioe::PE11 => (ADC4, 15), - gpioe::PE11 => (ADC5, 15), - gpioe::PE12 => (ADC3, 16), - gpioe::PE12 => (ADC4, 16), - gpioe::PE12 => (ADC5, 16), - gpioe::PE13 => (ADC3, 3), - gpioe::PE14 => (ADC4, 1), - gpioe::PE15 => (ADC4, 2), - - gpiod::PD8 => (ADC4, 12), - gpiod::PD8 => (ADC5, 12), - gpiod::PD9 => (ADC4, 13), - gpiod::PD9 => (ADC5, 13), - gpiod::PD10 => (ADC3, 7), - gpiod::PD10 => (ADC4, 7), - gpiod::PD10 => (ADC5, 7), - gpiod::PD11 => (ADC3, 8), - gpiod::PD11 => (ADC4, 8), - gpiod::PD11 => (ADC5, 8), - gpiod::PD12 => (ADC3, 9), - gpiod::PD12 => (ADC4, 9), - gpiod::PD12 => (ADC5, 9), - gpiod::PD13 => (ADC3, 10), - gpiod::PD13 => (ADC4, 10), - gpiod::PD13 => (ADC5, 10), - gpiod::PD14 => (ADC3, 11), - gpiod::PD14 => (ADC4, 11), - gpiod::PD14 => (ADC5, 11), - - gpiof::PF0 => (ADC1, 10), - gpiof::PF1 => (ADC2, 10), + gpio::PA0 => (ADC1, 1), + gpio::PA0 => (ADC2, 1), + gpio::PA1 => (ADC1, 2), + gpio::PA1 => (ADC2, 2), + gpio::PA2 => (ADC1, 3), + gpio::PA3 => (ADC1, 4), + gpio::PA4 => (ADC2, 17), + gpio::PA5 => (ADC2, 13), + gpio::PA6 => (ADC2, 3), + gpio::PA7 => (ADC2, 4), + gpio::PA8 => (ADC5, 1), + gpio::PA9 => (ADC5, 2), + + gpio::PB0 => (ADC3, 12), + gpio::PB0 => (ADC1, 15), + gpio::PB1 => (ADC3, 1), + gpio::PB1 => (ADC1, 12), + gpio::PB2 => (ADC2, 12), + gpio::PB11 => (ADC1, 14), + gpio::PB11 => (ADC2, 14), + gpio::PB12 => (ADC4, 3), + gpio::PB12 => (ADC1, 11), + gpio::PB13 => (ADC3, 5), + gpio::PB14 => (ADC4, 4), + gpio::PB14 => (ADC1, 5), + gpio::PB15 => (ADC4, 5), + gpio::PB15 => (ADC2, 15), + + gpio::PC0 => (ADC1, 6), + gpio::PC0 => (ADC2, 6), + gpio::PC1 => (ADC1, 7), + gpio::PC1 => (ADC2, 7), + gpio::PC2 => (ADC1, 8), + gpio::PC2 => (ADC2, 8), + gpio::PC3 => (ADC1, 9), + gpio::PC3 => (ADC2, 9), + gpio::PC4 => (ADC2, 5), + gpio::PC5 => (ADC2, 11), + + gpio::PE7 => (ADC3, 4), + gpio::PE8 => (ADC3, 6), + gpio::PE8 => (ADC4, 6), + gpio::PE8 => (ADC5, 6), + gpio::PE9 => (ADC3, 2), + gpio::PE10 => (ADC3, 14), + gpio::PE10 => (ADC4, 14), + gpio::PE10 => (ADC5, 14), + gpio::PE11 => (ADC3, 15), + gpio::PE11 => (ADC4, 15), + gpio::PE11 => (ADC5, 15), + gpio::PE12 => (ADC3, 16), + gpio::PE12 => (ADC4, 16), + gpio::PE12 => (ADC5, 16), + gpio::PE13 => (ADC3, 3), + gpio::PE14 => (ADC4, 1), + gpio::PE15 => (ADC4, 2), + + gpio::PD8 => (ADC4, 12), + gpio::PD8 => (ADC5, 12), + gpio::PD9 => (ADC4, 13), + gpio::PD9 => (ADC5, 13), + gpio::PD10 => (ADC3, 7), + gpio::PD10 => (ADC4, 7), + gpio::PD10 => (ADC5, 7), + gpio::PD11 => (ADC3, 8), + gpio::PD11 => (ADC4, 8), + gpio::PD11 => (ADC5, 8), + gpio::PD12 => (ADC3, 9), + gpio::PD12 => (ADC4, 9), + gpio::PD12 => (ADC5, 9), + gpio::PD13 => (ADC3, 10), + gpio::PD13 => (ADC4, 10), + gpio::PD13 => (ADC5, 10), + gpio::PD14 => (ADC3, 11), + gpio::PD14 => (ADC4, 11), + gpio::PD14 => (ADC5, 11), + + gpio::PF0 => (ADC1, 10), + gpio::PF1 => (ADC2, 10), Temperature => (ADC1, 16), Vbat => (ADC1, 17), @@ -2849,56 +2849,56 @@ adc_opamp!( #[cfg(any(feature = "stm32g491", feature = "stm32g4a1",))] adc_pins!( - gpioa::PA0 => (ADC1, 1), - gpioa::PA0 => (ADC2, 1), - gpioa::PA1 => (ADC1, 2), - gpioa::PA1 => (ADC2, 2), - gpioa::PA2 => (ADC1, 3), - gpioa::PA3 => (ADC1, 4), - gpioa::PA4 => (ADC2, 17), - gpioa::PA5 => (ADC2, 13), - gpioa::PA6 => (ADC2, 3), - gpioa::PA7 => (ADC2, 4), - - gpiob::PB0 => (ADC3, 12), - gpiob::PB0 => (ADC1, 15), - gpiob::PB1 => (ADC3, 1), - gpiob::PB1 => (ADC1, 12), - gpiob::PB2 => (ADC2, 12), - gpiob::PB11 => (ADC1, 14), - gpiob::PB11 => (ADC2, 14), - gpiob::PB12 => (ADC1, 11), - gpiob::PB13 => (ADC3, 5), - gpiob::PB14 => (ADC1, 5), - gpiob::PB15 => (ADC2, 15), - - gpioc::PC0 => (ADC1, 6), - gpioc::PC0 => (ADC2, 6), - gpioc::PC1 => (ADC1, 7), - gpioc::PC1 => (ADC2, 7), - gpioc::PC2 => (ADC1, 8), - gpioc::PC2 => (ADC2, 8), - gpioc::PC3 => (ADC1, 9), - gpioc::PC3 => (ADC2, 9), - gpioc::PC4 => (ADC2, 5), - gpioc::PC5 => (ADC2, 11), - - gpioe::PE7 => (ADC3, 4), - gpioe::PE8 => (ADC3, 6), - gpioe::PE9 => (ADC3, 2), - gpioe::PE10 => (ADC3, 14), - gpioe::PE11 => (ADC3, 15), - gpioe::PE12 => (ADC3, 16), - gpioe::PE13 => (ADC3, 3), - - gpiod::PD10 => (ADC3, 7), - gpiod::PD11 => (ADC3, 8), - gpiod::PD12 => (ADC3, 9), - gpiod::PD13 => (ADC3, 10), - gpiod::PD14 => (ADC3, 11), - - gpiof::PF0 => (ADC1, 10), - gpiof::PF1 => (ADC2, 10), + gpio::PA0 => (ADC1, 1), + gpio::PA0 => (ADC2, 1), + gpio::PA1 => (ADC1, 2), + gpio::PA1 => (ADC2, 2), + gpio::PA2 => (ADC1, 3), + gpio::PA3 => (ADC1, 4), + gpio::PA4 => (ADC2, 17), + gpio::PA5 => (ADC2, 13), + gpio::PA6 => (ADC2, 3), + gpio::PA7 => (ADC2, 4), + + gpio::PB0 => (ADC3, 12), + gpio::PB0 => (ADC1, 15), + gpio::PB1 => (ADC3, 1), + gpio::PB1 => (ADC1, 12), + gpio::PB2 => (ADC2, 12), + gpio::PB11 => (ADC1, 14), + gpio::PB11 => (ADC2, 14), + gpio::PB12 => (ADC1, 11), + gpio::PB13 => (ADC3, 5), + gpio::PB14 => (ADC1, 5), + gpio::PB15 => (ADC2, 15), + + gpio::PC0 => (ADC1, 6), + gpio::PC0 => (ADC2, 6), + gpio::PC1 => (ADC1, 7), + gpio::PC1 => (ADC2, 7), + gpio::PC2 => (ADC1, 8), + gpio::PC2 => (ADC2, 8), + gpio::PC3 => (ADC1, 9), + gpio::PC3 => (ADC2, 9), + gpio::PC4 => (ADC2, 5), + gpio::PC5 => (ADC2, 11), + + gpio::PE7 => (ADC3, 4), + gpio::PE8 => (ADC3, 6), + gpio::PE9 => (ADC3, 2), + gpio::PE10 => (ADC3, 14), + gpio::PE11 => (ADC3, 15), + gpio::PE12 => (ADC3, 16), + gpio::PE13 => (ADC3, 3), + + gpio::PD10 => (ADC3, 7), + gpio::PD11 => (ADC3, 8), + gpio::PD12 => (ADC3, 9), + gpio::PD13 => (ADC3, 10), + gpio::PD14 => (ADC3, 11), + + gpio::PF0 => (ADC1, 10), + gpio::PF1 => (ADC2, 10), Temperature => (ADC1, 16), Vbat => (ADC1, 17), diff --git a/src/can.rs b/src/can.rs index 398916a4..43518f33 100644 --- a/src/can.rs +++ b/src/can.rs @@ -54,11 +54,11 @@ macro_rules! pins { rx: [ $($( #[ $pmetarx:meta ] )* $rx:ident<$rxaf:ident>),+ $(,)? ])) => { $( $( #[ $pmetatx ] )* - impl sealed::Tx<$PER> for $tx> {} + impl sealed::Tx<$PER> for $tx<$txaf> {} )+ $( $( #[ $pmetarx ] )* - impl sealed::Rx<$PER> for $rx> {} + impl sealed::Rx<$PER> for $rx<$rxaf> {} )+ }; } @@ -66,12 +66,7 @@ macro_rules! pins { mod fdcan1 { use super::sealed; use super::{Can, CanExt}; - use crate::gpio::{ - gpioa::{PA11, PA12}, - gpiob::{PB8, PB9}, - gpiod::{PD0, PD1}, - AF9, - }; + use crate::gpio::{AF9, PA11, PA12, PB8, PB9, PD0, PD1}; use crate::stm32::FDCAN1; use fdcan; @@ -121,10 +116,7 @@ mod fdcan1 { mod fdcan2 { use super::sealed; use super::{Can, CanExt}; - use crate::gpio::{ - gpiob::{PB12, PB13, PB5, PB6}, - AF9, - }; + use crate::gpio::{AF9, PB12, PB13, PB5, PB6}; use crate::stm32::FDCAN2; use fdcan; use fdcan::message_ram; @@ -168,11 +160,7 @@ mod fdcan2 { mod fdcan3 { use super::sealed; use super::{Can, CanExt}; - use crate::gpio::{ - gpioa::{PA15, PA8}, - gpiob::{PB3, PB4}, - AF11, - }; + use crate::gpio::{AF11, PA15, PA8, PB3, PB4}; use crate::stm32::FDCAN3; use fdcan; use fdcan::message_ram; diff --git a/src/comparator.rs b/src/comparator.rs index b5e80fc4..cbfef185 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -9,31 +9,8 @@ use core::marker::PhantomData; use crate::dac; use crate::exti::{Event as ExtiEvent, ExtiExt}; -use crate::gpio::{ - gpioa::{PA0, PA1, PA11, PA12, PA2, PA3, PA4, PA5, PA6, PA7}, - gpiob::{PB0, PB1, PB14, PB15, PB2, PB6, PB7, PB8, PB9}, - gpioc::PC2, - gpiof::PF4, - Analog, OpenDrain, Output, PushPull, SignalEdge, AF2, AF3, AF8, -}; +use crate::gpio::{self, Analog, OpenDrain, Output, PushPull, SignalEdge}; -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] -use crate::gpio::{ - gpioa::{PA10, PA8, PA9}, - gpiob::{PB10, PB11, PB12, PB13}, - gpioc::{PC6, PC7, PC8}, - gpiod::{PD10, PD11, PD12, PD13, PD14, PD15}, - AF7, -}; - -use crate::gpio::gpioc::{PC0, PC1}; -use crate::gpio::gpioe::{PE7, PE8}; -use crate::gpio::gpiof::PF1; use crate::rcc::{Clocks, Rcc}; use crate::stm32::{COMP, EXTI}; @@ -160,13 +137,13 @@ pub trait NegativeInput { macro_rules! positive_input_pin { ($COMP:ident, $pin_0:ident, $pin_1:ident) => { - impl PositiveInput<$COMP> for &$pin_0 { + impl PositiveInput<$COMP> for &gpio::$pin_0 { fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| w.inpsel().bit(false)); } } - impl PositiveInput<$COMP> for &$pin_1 { + impl PositiveInput<$COMP> for &gpio::$pin_1 { fn setup(&self, comp: &$COMP) { comp.csr().modify(|_, w| w.inpsel().bit(true)); } @@ -227,10 +204,10 @@ macro_rules! negative_input_pin { } negative_input_pin! { - COMP1: PA4, PA0, - COMP2: PA5, PA2, - COMP3: PF1, PC0, - COMP4: PE8, PB2, + COMP1: gpio::PA4, gpio::PA0, + COMP2: gpio::PA5, gpio::PA2, + COMP3: gpio::PF1, gpio::PC0, + COMP4: gpio::PE8, gpio::PB2, } #[cfg(any( @@ -240,9 +217,9 @@ negative_input_pin! { feature = "stm32g484" ))] negative_input_pin! { - COMP5: PB10, PD13, - COMP6: PD10, PB15, - COMP7: PD15, PB12, + COMP5: gpio::PB10, gpio::PD13, + COMP6: gpio::PD10, gpio::PB15, + COMP7: gpio::PD15, gpio::PB12, } #[derive(Copy, Clone, Eq, PartialEq)] @@ -593,38 +570,37 @@ pub trait OutputPin { #[allow(unused_macros)] // TODO: add support for more devices macro_rules! output_pin { - ($COMP:ident, $pin:ident, $AF:ident, $mode_t:ident, $into:ident) => { - impl OutputPin<$COMP> for $pin> { + ($COMP:ident, $pin:ident, $AF:literal, $mode_t:ident, $into:ident) => { + impl OutputPin<$COMP> for gpio::$pin> { fn setup(self) { self.$into::<$AF>(); } } }; - ($($COMP:ident: $pin:ident, $AF:ident,)+) => {$( + ($($COMP:ident: $pin:ident, $AF:literal,)+) => {$( output_pin!($COMP, $pin, $AF, PushPull, into_alternate); output_pin!($COMP, $pin, $AF, OpenDrain, into_alternate_open_drain); )+}; } output_pin! { - COMP1: PA0, AF8, - COMP1: PA6, AF8, - COMP1: PA11, AF8, - COMP1: PB8, AF8, - COMP1: PF4, AF2, - - COMP2: PA2, AF8, - COMP2: PA7, AF8, - COMP2: PA12, AF8, - COMP2: PB9, AF8, - - COMP3: PB7, AF8, - COMP3: PB15, AF3, - COMP3: PC2, AF3, - - COMP4: PB1, AF8, - COMP4: PB6, AF8, - COMP4: PB14, AF8, + COMP1: PA0, 8, + COMP1: PA6, 8, + COMP1: PA11, 8, + COMP1: PB8, 8, + + COMP2: PA2, 8, + COMP2: PA7, 8, + COMP2: PA12, 8, + COMP2: PB9, 8, + + COMP3: PB7, 8, + COMP3: PB15, 3, + COMP3: PC2, 3, + + COMP4: PB1, 8, + COMP4: PB6, 8, + COMP4: PB14, 8, } #[cfg(any( @@ -634,12 +610,14 @@ output_pin! { feature = "stm32g484", ))] output_pin! { - COMP5: PA9, AF8, - COMP5: PC7, AF7, + COMP1: PF4, 2, + + COMP5: PA9, 8, + COMP5: PC7, 7, - COMP6: PA10, AF8, - COMP6: PC6, AF7, + COMP6: PA10, 8, + COMP6: PC6, 7, - COMP7: PA8, AF8, - COMP7: PC8, AF7, + COMP7: PA8, 8, + COMP7: PC8, 7, } diff --git a/src/dac.rs b/src/dac.rs index e2bafb4b..cf4a350c 100644 --- a/src/dac.rs +++ b/src/dac.rs @@ -8,8 +8,8 @@ use core::marker::PhantomData; use core::mem::MaybeUninit; -use crate::gpio::gpioa::{PA4, PA5, PA6}; use crate::gpio::DefaultMode; +use crate::gpio::{PA4, PA5, PA6}; use crate::rcc::{self, *}; use crate::stm32::{DAC1, DAC2, DAC3, DAC4, RCC}; use embedded_hal::delay::DelayNs; diff --git a/src/delay.rs b/src/delay.rs index 1b869adf..3e0b3faa 100644 --- a/src/delay.rs +++ b/src/delay.rs @@ -119,17 +119,12 @@ impl DelayMs for SystDelay { } pub trait DelayExt { - fn delay(&mut self, delay: T) - where - T: Into; + fn delay(&mut self, delay: MicroSecond); } impl DelayExt for SystDelay { - fn delay(&mut self, delay: T) - where - T: Into, - { - self.0.delay_us(delay.into().ticks()) + fn delay(&mut self, delay: MicroSecond) { + self.0.delay_us(delay.ticks()) } } diff --git a/src/fdcan.rs b/src/fdcan.rs index 997e11b9..d1c25933 100644 --- a/src/fdcan.rs +++ b/src/fdcan.rs @@ -818,7 +818,8 @@ where }; let can = self.registers(); - can.cccr().modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); + can.cccr() + .modify(|_, w| w.fdoe().bit(fdoe).brse().bit(brse)); self.control.config.frame_transmit = fts; } @@ -1001,7 +1002,8 @@ where let can = self.registers(); //SAFE: state has all possible values, and this can only occur in TestMode - can.test().modify(|_, w| unsafe { w.tx().bits(state as u8) }); + can.test() + .modify(|_, w| unsafe { w.tx().bits(state as u8) }); } } @@ -1657,8 +1659,8 @@ mod impls { /// Implements sealed::{Tx,Rx} for pins associated with a CAN peripheral macro_rules! pins { ($PER:ident => - (tx: [ $($( #[ $pmetatx:meta ] )* $tx:ident<$txaf:ident>),+ $(,)? ], - rx: [ $($( #[ $pmetarx:meta ] )* $rx:ident<$rxaf:ident>),+ $(,)? ])) => { + (tx: [ $($( #[ $pmetatx:meta ] )* crate::gpio::$tx:ident),+ $(,)? ], + rx: [ $($( #[ $pmetarx:meta ] )* crate::gpio::$rx:ident),+ $(,)? ])) => { $( $( #[ $pmetatx ] )* impl super::sealed::Tx<$PER> for $tx> {} @@ -1673,12 +1675,6 @@ mod impls { mod fdcan1 { use crate::fdcan; use crate::fdcan::message_ram; - use crate::gpio::{ - gpioa::{PA11, PA12}, - gpiob::{PB8, PB9}, - gpiod::{PD0, PD1}, - AF9, - }; use crate::stm32; use crate::stm32::FDCAN1; @@ -1718,10 +1714,6 @@ mod impls { mod fdcan2 { use crate::fdcan; use crate::fdcan::message_ram; - use crate::gpio::{ - gpiob::{PB12, PB13, PB5, PB6}, - AF9, - }; use crate::stm32::{self, FDCAN2}; pins! { @@ -1754,11 +1746,6 @@ mod impls { mod fdcan3 { use crate::fdcan; use crate::fdcan::message_ram; - use crate::gpio::{ - gpioa::{PA15, PA8}, - gpiob::{PB3, PB4}, - AF11, - }; use crate::stm32::{self, FDCAN3}; pins! { diff --git a/src/gpio.rs b/src/gpio.rs index e27a5801..3d57c0e9 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -1,12 +1,91 @@ //! General Purpose Input / Output -use core::marker::PhantomData; +//! +//! The GPIO pins are organised into groups of 16 pins which can be accessed through the +//! `gpioa`, `gpiob`... modules. To get access to the pins, you first need to convert them into a +//! HAL designed struct from the `pac` struct using the [split](trait.GpioExt.html#tymethod.split) function. +//! ```rust +//! // Acquire the GPIOC peripheral +//! // NOTE: `dp` is the device peripherals from the `PAC` crate +//! let mut gpioa = dp.GPIOA.split(); +//! ``` +//! +//! This gives you a struct containing all the pins `px0..px15`. +//! By default pins are in floating input mode. You can change their modes. +//! For example, to set `pa5` high, you would call +//! +//! ```rust +//! let output = gpioa.pa5.into_push_pull_output(); +//! output.set_high(); +//! ``` +//! +//! ## Modes +//! +//! Each GPIO pin can be set to various modes: +//! +//! - **Alternate**: Pin mode required when the pin is driven by other peripherals +//! - **Analog**: Analog input to be used with ADC. +//! - **Dynamic**: Pin mode is selected at runtime. See changing configurations for more details +//! - Input +//! - **PullUp**: Input connected to high with a weak pull up resistor. Will be high when nothing +//! is connected +//! - **PullDown**: Input connected to high with a weak pull up resistor. Will be low when nothing +//! is connected +//! - **Floating**: Input not pulled to high or low. Will be undefined when nothing is connected +//! - Output +//! - **PushPull**: Output which either drives the pin high or low +//! - **OpenDrain**: Output which leaves the gate floating, or pulls it do ground in drain +//! mode. Can be used as an input in the `open` configuration +//! +//! ## 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. +//! +//! 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 crate::rcc::{Enable, Rcc, Reset}; -use crate::stm32::EXTI; -use crate::syscfg::SysCfg; +use core::marker::PhantomData; -/// Default pin mode -pub type DefaultMode = Input; +use crate::pac; +use crate::rcc::Rcc; +pub mod alt; +mod convert; +pub use convert::PinMode; +mod partially_erased; +pub use partially_erased::{PEPin, PartiallyErasedPin}; +mod erased; +pub use erased::{AnyPin, ErasedPin}; +mod exti; +pub use exti::ExtiPin; +mod dynamic; +pub use dynamic::{Dynamic, DynamicPin}; +mod hal_02; +mod hal_1; +pub mod outport; + +pub use embedded_hal_old::digital::v2::PinState; + +use core::fmt; + +/// A filler pin type +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct NoPin(PhantomData); +impl NoPin { + pub fn new() -> Self { + Self(PhantomData) + } +} /// Extension trait to split a GPIO peripheral in independent pins and registers pub trait GpioExt { @@ -17,872 +96,545 @@ pub trait GpioExt { fn split(self, rcc: &mut Rcc) -> Self::Parts; } -/// Input mode (type state) -pub struct Input { - _mode: PhantomData, +/// 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; } -/// Floating input (type state) -pub struct Floating; +/// Some alternate mode (type state) +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Alternate(PhantomData); -/// Pulled down input (type state) -pub struct PullDown; +/// Input mode (type state) +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Input; + +/// Pull setting for an input. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub enum Pull { + /// Floating + None = 0, + /// Pulled up + Up = 1, + /// Pulled down + Down = 2, +} -/// Pulled up input (type state) -pub struct PullUp; +impl From for pac::gpioa::pupdr::PULL { + fn from(value: Pull) -> Self { + match value { + Pull::Down => Self::PullDown, + Pull::Up => Self::PullUp, + Pull::None => Self::Floating, + } + } +} /// Open drain input or output (type state) +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct OpenDrain; -/// Analog mode (type state) -pub struct Analog; - /// Output mode (type state) -pub struct Output { - _mode: PhantomData, +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Output { + _mode: PhantomData, } /// Push pull output (type state) +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] pub struct PushPull; +/// Analog mode (type state) +#[derive(Debug, Default)] +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +pub struct Analog; + +/// JTAG/SWD mote (type state) +pub type Debugger = Alternate<0, PushPull>; + +pub(crate) mod marker { + /// Marker trait that show if `ExtiPin` can be implemented + pub trait Interruptible {} + /// 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 {} +} + +impl marker::Interruptible for Output {} +impl marker::Interruptible for Input {} +impl marker::Readable for Input {} +impl marker::Readable for Output {} +impl marker::Interruptible for Alternate {} +impl marker::Readable 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::NotAlt for Input {} +impl marker::NotAlt for Output {} +impl marker::NotAlt for Analog {} + /// GPIO Pin speed selection +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum Speed { + /// Low speed Low = 0, + /// Medium speed Medium = 1, + /// High speed High = 2, + /// Very high speed VeryHigh = 3, } -/// Trigger edgw +impl From for pac::gpioa::ospeedr::OUTPUT_SPEED { + fn from(value: Speed) -> Self { + match value { + Speed::Low => Self::LowSpeed, + Speed::Medium => Self::MediumSpeed, + Speed::High => Self::HighSpeed, + Speed::VeryHigh => Self::VeryHighSpeed, + } + } +} + +/// GPIO interrupt trigger edge selection +#[cfg_attr(feature = "defmt", derive(defmt::Format))] +#[derive(Debug, PartialEq, Eq, Clone, Copy)] pub enum SignalEdge { + /// Rising edge of voltage Rising, + /// Falling edge of voltage Falling, + /// Rising and falling edge of voltage RisingFalling, } -/// Altername Mode (type state) -pub struct Alternate; -pub struct AlternateOD; - -pub const AF0: u8 = 0; -pub const AF1: u8 = 1; -pub const AF2: u8 = 2; -pub const AF3: u8 = 3; -pub const AF4: u8 = 4; -pub const AF5: u8 = 5; -pub const AF6: u8 = 6; -pub const AF7: u8 = 7; -pub const AF8: u8 = 8; -pub const AF9: u8 = 9; -pub const AF10: u8 = 10; -pub const AF11: u8 = 11; -pub const AF12: u8 = 12; -pub const AF13: u8 = 13; -pub const AF14: u8 = 14; -pub const AF15: u8 = 15; - -/// External Interrupt Pin -pub trait ExtiPin { - fn make_interrupt_source(&mut self, syscfg: &mut SysCfg); - fn trigger_on_edge(&mut self, exti: &mut EXTI, level: SignalEdge); - fn enable_interrupt(&mut self, exti: &mut EXTI); - fn disable_interrupt(&mut self, exti: &mut EXTI); - fn clear_interrupt_pending_bit(&mut self); - fn check_interrupt(&self) -> bool; -} - -macro_rules! exti_erased { - ($PIN:ty, $extigpionr:expr) => { - impl ExtiPin for $PIN { - /// Make corresponding EXTI line sensitive to this pin - fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { - let offset = 4 * (self.i % 4); - match self.i { - 0..=3 => { - syscfg.exticr1().modify(|r, w| unsafe { - w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) - }); - } - 4..=7 => { - syscfg.exticr2().modify(|r, w| unsafe { - w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) - }); - } - 8..=11 => { - syscfg.exticr3().modify(|r, w| unsafe { - w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) - }); - } - 12..=15 => { - syscfg.exticr4().modify(|r, w| unsafe { - w.bits((r.bits() & !(0xf << offset)) | ($extigpionr << offset)) - }); - } - _ => {} - } - } - - /// Generate interrupt on rising edge, falling edge or both - fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: SignalEdge) { - match edge { - SignalEdge::Rising => { - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); - } - SignalEdge::Falling => { - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); - } - SignalEdge::RisingFalling => { - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - } - } - } +macro_rules! af { + ($($i:literal: $AFi:ident),+) => { + $( + #[doc = concat!("Alternate function ", $i, " (type state)" )] + pub type $AFi = Alternate<$i, Otype>; + )+ + }; +} - /// Enable external interrupts from this pin. - fn enable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.i)) }); - } +af!( + 0: AF0, + 1: AF1, + 2: AF2, + 3: AF3, + 4: AF4, + 5: AF5, + 6: AF6, + 7: AF7, + 8: AF8, + 9: AF9, + 10: AF10, + 11: AF11, + 12: AF12, + 13: AF13, + 14: AF14, + 15: AF15 +); + +/// 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 } + } +} - /// Disable external interrupts from this pin - fn disable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.i)) }); - } +impl crate::Sealed for Pin {} - /// Clear the interrupt pending bit for this pin - fn clear_interrupt_pending_bit(&mut self) { - unsafe { (*EXTI::ptr()).pr1().write(|w| w.bits(1 << self.i)) }; - } +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::() + )) + } +} - /// Reads the interrupt pending bit for this pin - fn check_interrupt(&self) -> bool { - unsafe { ((*EXTI::ptr()).pr1().read().bits() & (1 << self.i)) != 0 } - } - } - }; +#[cfg(feature = "defmt")] +impl defmt::Format for Pin { + fn format(&self, f: defmt::Formatter) { + defmt::write!(f, "P{}{}<{}>", P, N, crate::stripped_type_name::()); + } } -macro_rules! exti { - ($PIN:ty, $extigpionr:expr, $i:expr, $exticri:ident) => { - impl ExtiPin for $PIN { - /// Configure EXTI Line $i to trigger from this pin. - fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { - let offset = 4 * ($i % 4); - syscfg.$exticri().modify(|r, w| unsafe { - let mut exticr = r.bits(); - exticr = (exticr & !(0xf << offset)) | ($extigpionr << offset); //FIXME: clears other pins - w.bits(exticr) - }); - } +impl PinExt for Pin { + type Mode = MODE; - /// Generate interrupt on rising edge, falling edge or both - fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: SignalEdge) { - match edge { - SignalEdge::Rising => { - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); - } - SignalEdge::Falling => { - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); - } - SignalEdge::RisingFalling => { - exti.rtsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - exti.ftsr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - } - } - } + #[inline(always)] + fn pin_id(&self) -> u8 { + N + } + #[inline(always)] + fn port_id(&self) -> u8 { + P as u8 - b'A' + } +} - /// Enable external interrupts from this pin. - fn enable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1() - .modify(|r, w| unsafe { w.bits(r.bits() | (1 << $i)) }); - } +pub trait PinSpeed: Sized { + /// Set pin speed + fn set_speed(&mut self, speed: Speed); - /// Disable external interrupts from this pin - fn disable_interrupt(&mut self, exti: &mut EXTI) { - exti.imr1() - .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << $i)) }); - } + #[inline(always)] + fn speed(mut self, speed: Speed) -> Self { + self.set_speed(speed); + self + } +} - /// Clear the interrupt pending bit for this pin - fn clear_interrupt_pending_bit(&mut self) { - unsafe { (*EXTI::ptr()).pr1().write(|w| w.bits(1 << $i)) }; - } +pub trait PinPull: Sized { + /// Set the internal pull-up and pull-down resistor + fn set_internal_resistor(&mut self, resistor: Pull); - /// Reads the interrupt pending bit for this pin - fn check_interrupt(&self) -> bool { - unsafe { ((*EXTI::ptr()).pr1().read().bits() & (1 << $i)) != 0 } - } - } - }; + #[inline(always)] + fn internal_resistor(mut self, resistor: Pull) -> Self { + self.set_internal_resistor(resistor); + self + } } -macro_rules! gpio { - ($GPIOX:ident, $gpiox:ident, $iopxenr:ident, $PXx:ident, $Pxn:expr, [ - $($PXi:ident: ($pxi:ident, $i:expr, $exticri:ident),)+ - ]) => { - /// GPIO - pub mod $gpiox { - use core::marker::PhantomData; - use embedded_hal_old::digital::v2::{toggleable, InputPin, OutputPin, StatefulOutputPin}; - use crate::stm32::{EXTI, $GPIOX}; - use crate::exti::{ExtiExt, Event}; - use crate::rcc::Rcc; - use super::*; +impl PinSpeed for Pin +where + MODE: marker::OutputSpeed, +{ + #[inline(always)] + fn set_speed(&mut self, speed: Speed) { + self.set_speed(speed) + } +} - /// GPIO parts - pub struct Parts { - $( - pub $pxi: $PXi>, - )+ - } +impl Pin +where + MODE: marker::OutputSpeed, +{ + /// Set pin speed + pub fn set_speed(&mut self, speed: Speed) { + unsafe { &(*gpiox::

()) } + .ospeedr() + .modify(|_, w| w.ospeedr(N).variant(speed.into())); + } - impl GpioExt for $GPIOX { - type Parts = Parts; + /// Set pin speed + pub fn speed(mut self, speed: Speed) -> Self { + self.set_speed(speed); + self + } +} - fn split(self, rcc: &mut Rcc) -> Parts { - $GPIOX::enable(&rcc.rb); - $GPIOX::reset(&rcc.rb); +impl PinPull for Pin +where + MODE: marker::Active, +{ + #[inline(always)] + fn set_internal_resistor(&mut self, resistor: Pull) { + self.set_internal_resistor(resistor) + } +} - Parts { - $( - $pxi: $PXi { _mode: PhantomData }, - )+ - } - } - } +impl Pin +where + MODE: marker::Active, +{ + /// Set the internal pull-up and pull-down resistor + pub fn set_internal_resistor(&mut self, resistor: Pull) { + unsafe { &(*gpiox::

()) } + .pupdr() + .modify(|_, w| w.pupdr(N).variant(resistor.into())); + } - /// Partially erased pin - pub struct $PXx { - i: u8, - _mode: PhantomData, - } + /// Set the internal pull-up and pull-down resistor + pub fn internal_resistor(mut self, resistor: Pull) -> Self { + self.set_internal_resistor(resistor); + self + } - impl OutputPin for $PXx> { - type Error = (); + /// Enables / disables the internal pull up + pub fn internal_pull_up(self, on: bool) -> Self { + if on { + self.internal_resistor(Pull::Up) + } else { + self.internal_resistor(Pull::None) + } + } - fn set_high(&mut self) -> Result<(), ()> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs(self.i).set_bit()) }; - Ok(()) - } + /// Enables / disables the internal pull down + pub fn internal_pull_down(self, on: bool) -> Self { + if on { + self.internal_resistor(Pull::Down) + } else { + self.internal_resistor(Pull::None) + } + } +} - fn set_low(&mut self) -> Result<(), ()> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br(self.i).set_bit()) }; - 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) + } - impl embedded_hal::digital::ErrorType for $PXx> { - type Error = core::convert::Infallible; - } + /// 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 embedded_hal::digital::OutputPin for $PXx> { - fn set_high(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs(self.i).set_bit()) }; - Ok(()) - } +impl From> for PartiallyErasedPin { + /// Pin-to-partially erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: Pin) -> Self { + p.erase_number() + } +} - fn set_low(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br(self.i).set_bit()) }; - Ok(()) - } - } +impl From> for ErasedPin { + /// Pin-to-erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: Pin) -> Self { + p.erase() + } +} - impl StatefulOutputPin for $PXx> { - fn is_set_high(&self) -> Result { - let is_set_high = !self.is_set_low()?; - Ok(is_set_high) - } +impl Pin { + /// Set the output of the pin regardless of its mode. + /// Primarily used to set the output value of the pin + /// before changing its mode to an output to avoid + /// a short spike of an incorrect value + #[inline(always)] + fn _set_state(&mut self, state: PinState) { + match state { + PinState::High => self._set_high(), + PinState::Low => self._set_low(), + } + } + #[inline(always)] + fn _set_high(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + let gpio = unsafe { &(*gpiox::

()) }; + gpio.bsrr().write(|w| w.bs(N).set_bit()); + } + #[inline(always)] + fn _set_low(&mut self) { + // NOTE(unsafe) atomic write to a stateless register + let gpio = unsafe { &(*gpiox::

()) }; + gpio.bsrr().write(|w| w.br(N).set_bit()); + } + #[inline(always)] + fn _is_set_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + let gpio = unsafe { &(*gpiox::

()) }; + gpio.odr().read().odr(N).bit_is_clear() + } + #[inline(always)] + fn _is_low(&self) -> bool { + // NOTE(unsafe) atomic read with no side effects + let gpio = unsafe { &(*gpiox::

()) }; + gpio.idr().read().idr(N).bit_is_clear() + } +} - fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr(self.i).is_low()}; - Ok(is_set_low) - } - } +impl Pin> { + /// Drives the pin high + #[inline(always)] + pub fn set_high(&mut self) { + self._set_high() + } - impl embedded_hal::digital::StatefulOutputPin for $PXx> { - fn is_set_high(&mut self) -> Result { - let is_set_high = !self.is_set_low()?; - Ok(is_set_high) - } + /// Drives the pin low + #[inline(always)] + pub fn set_low(&mut self) { + self._set_low() + } - fn is_set_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr(self.i).is_low() }; - Ok(is_set_low) - } - } + /// 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 + } + } - impl toggleable::Default for $PXx> {} + /// 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(), + } + } - impl InputPin for $PXx> { - type Error = (); + /// Is the pin in drive high mode? + #[inline(always)] + pub fn is_set_high(&self) -> bool { + !self.is_set_low() + } - fn is_high(&self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } + /// Is the pin in drive low mode? + #[inline(always)] + pub fn is_set_low(&self) -> bool { + self._is_set_low() + } - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; - Ok(is_low) - } - } + /// Toggle pin output + #[inline(always)] + pub fn toggle(&mut self) { + if self.is_set_low() { + self.set_high() + } else { + self.set_low() + } + } +} - impl embedded_hal::digital::InputPin for $PXx> { - fn is_high(&mut self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } +pub trait ReadPin { + #[inline(always)] + fn is_high(&self) -> bool { + !self.is_low() + } + fn is_low(&self) -> bool; +} - fn is_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; - Ok(is_low) - } - } +impl ReadPin for Pin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_low(&self) -> bool { + self.is_low() + } +} +impl Pin +where + MODE: marker::Readable, +{ + /// Is the input pin high? + #[inline(always)] + pub fn is_high(&self) -> bool { + !self.is_low() + } - impl InputPin for $PXx> { - type Error = (); + /// Is the input pin low? + #[inline(always)] + pub fn is_low(&self) -> bool { + self._is_low() + } +} - fn is_high(&self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } +macro_rules! gpio { + ($GPIOX:ident, $gpiox:ident, $PEPin:ident, $port_id:expr, $PXn:ident, [ + $($PXi:ident: ($pxi:ident, $i:expr, [$($A:literal),*] $(, $MODE:ty)?),)+ + ]) => { + /// GPIO + pub mod $gpiox { + use crate::pac::$GPIOX; + use crate::rcc::{Rcc, Enable, Reset}; - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; - Ok(is_low) - } + /// GPIO parts + pub struct Parts { + $( + /// Pin + pub $pxi: $PXi $(<$MODE>)?, + )+ } - impl embedded_hal::digital::ErrorType for $PXx> { - type Error = core::convert::Infallible; - } + impl super::GpioExt for $GPIOX { + type Parts = Parts; - impl embedded_hal::digital::InputPin for $PXx> { - fn is_high(&mut self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } + fn split(self, rcc: &mut Rcc) -> Parts { + Self::enable(&rcc.rb); + Self::reset(&rcc.rb); - fn is_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr(self.i).is_low() }; - Ok(is_low) + Parts { + $( + $pxi: $PXi::new(), + )+ + } } } - exti_erased!($PXx>, $Pxn); - exti_erased!($PXx>, $Pxn); + #[doc="Common type for "] + #[doc=stringify!($GPIOX)] + #[doc=" related pins"] + pub type $PXn = super::PartiallyErasedPin<$port_id, MODE>; $( - pub struct $PXi { - _mode: PhantomData, - } - - impl crate::Sealed for $PXi {} - - #[allow(clippy::from_over_into)] - impl Into<$PXi>> for $PXi { - fn into(self) -> $PXi> { - self.into_pull_down_input() - } - } - - #[allow(clippy::from_over_into)] - impl Into<$PXi>> for $PXi { - fn into(self) -> $PXi> { - self.into_pull_up_input() - } - } - - #[allow(clippy::from_over_into)] - impl Into<$PXi> for $PXi { - fn into(self) -> $PXi { - self.into_analog() - } - } - - #[allow(clippy::from_over_into)] - impl Into<$PXi>> for $PXi { - fn into(self) -> $PXi> { - self.into_open_drain_output() - } - } - - #[allow(clippy::from_over_into)] - impl Into<$PXi>> for $PXi { - fn into(self) -> $PXi> { - self.into_push_pull_output() - } - } + #[doc=stringify!($PXi)] + #[doc=" pin"] + pub type $PXi = super::Pin<$port_id, $i, MODE>; - impl $PXi { - /// Configures the pin to operate as a floating input pin - pub fn into_floating_input(self) -> $PXi> { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).floating() - }); - gpio.moder().modify(|_, w| { - w.moder($i).input() - }) - }; - $PXi { _mode: PhantomData } - } - - /// Configures the pin to operate as a pulled down input pin - pub fn into_pull_down_input(self) -> $PXi> { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).pull_down() - }); - gpio.moder().modify(|_, w| { - w.moder($i).input() - }) - }; - $PXi { _mode: PhantomData } - } - - /// Configures the pin to operate as a pulled up input pin - pub fn into_pull_up_input(self) -> $PXi> { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).pull_up() - }); - gpio.moder().modify(|_, w| { - w.moder($i).input() - }) - }; - $PXi { _mode: PhantomData } - } - - /// Configures the pin to operate as an analog pin - pub fn into_analog(self) -> $PXi { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).floating() - }); - gpio.moder().modify(|_, w| { - w.moder($i).analog() - }); - } - $PXi { _mode: PhantomData } - } - - /// Configures the pin to operate as an open drain output pin - pub fn into_open_drain_output(self) -> $PXi> { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).floating() - }); - gpio.otyper().modify(|_, w| { - w.ot($i).open_drain() - }); - gpio.moder().modify(|_, w| { - w.moder($i).output() - }) - }; - $PXi { _mode: PhantomData } - } - - /// Configures the pin to operate as an push pull output pin - pub fn into_push_pull_output(self) -> $PXi> { - unsafe { - let gpio = &(*$GPIOX::ptr()); - gpio.pupdr().modify(|_, w| { - w.pupdr($i).floating() - }); - gpio.otyper().modify(|_, w| { - w.ot($i).push_pull() - }); - gpio.moder().modify(|_, w| { - w.moder($i).output() - }) - }; - $PXi { _mode: PhantomData } - } - - /// Configures the pin as external trigger - pub fn listen(self, edge: SignalEdge, exti: &mut EXTI) -> $PXi { - exti.listen(Event::from_code($i), edge); - $PXi { _mode: PhantomData } - } - - /// Set pin speed - pub fn set_speed(self, speed: Speed) -> Self { - let offset = 2 * $i; - unsafe { - (*$GPIOX::ptr()).ospeedr().modify(|r, w| { - w.bits((r.bits() & !(0b11 << offset)) | ((speed as u32) << offset)) - }); - } - self - } - - pub fn into_alternate(self) -> $PXi> { - let mode = A as u8; - unsafe { - let gpio = &(*$GPIOX::ptr()); - if $i < 8 { - gpio.afrl().modify(|_, w| { - w.afr($i).set(mode) - }); - } else { - let offset = $i - 8; - gpio.afrh().modify(|_, w| { - w.afr(offset).set(mode) - }); - } - gpio.moder().modify(|_, w| { - w.moder($i).alternate() - }); - gpio.otyper().modify(|_, w| { - w.ot($i).push_pull() - }); - } - $PXi { _mode: PhantomData } - } - - pub fn into_alternate_open_drain(self) -> $PXi> { - let mode = A as u8; - unsafe { - let gpio = &(*$GPIOX::ptr()); - if $i < 8 { - gpio.afrl().modify(|_, w| { - w.afr($i).set(mode) - }); - } else { - let offset = $i - 8; - gpio.afrh().modify(|_, w| { - w.afr(offset).set(mode) - }); - } - gpio.otyper().modify(|_, w| { - w.ot($i).open_drain() - }); - gpio.moder().modify(|_, w| { - w.moder($i).alternate() - }); - } - $PXi { _mode: PhantomData } - } - } - - impl $PXi> { - /// 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) -> $PXx> { - $PXx { i: $i, _mode: self._mode } - } - } - - impl OutputPin for $PXi> { - type Error = (); - - fn set_high(&mut self) -> Result<(), ()> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs($i).set_bit()) }; - Ok(()) - } - - fn set_low(&mut self) -> Result<(), ()>{ - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br($i).set_bit()) }; - Ok(()) - } - } - - impl embedded_hal::digital::ErrorType for $PXi> { - type Error = core::convert::Infallible; - } - - impl embedded_hal::digital::OutputPin for $PXi> { - fn set_high(&mut self) -> Result<(), Self::Error> { - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.bs($i).set_bit()) }; - Ok(()) - } - - fn set_low(&mut self) -> Result<(), Self::Error>{ - // NOTE(unsafe) atomic write to a stateless register - unsafe { (*$GPIOX::ptr()).bsrr().write(|w| w.br($i).set_bit()) }; - Ok(()) - } - } - - impl StatefulOutputPin for $PXi> { - fn is_set_high(&self) -> Result { - let is_set_high = !self.is_set_low()?; - Ok(is_set_high) - } - - fn is_set_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr($i).is_low()}; - Ok(is_set_low) - } - } - - impl embedded_hal::digital::StatefulOutputPin for $PXi> { - fn is_set_high(&mut self) -> Result { - let is_set_high = !self.is_set_low()?; - Ok(is_set_high) - } - - fn is_set_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_set_low = unsafe { (*$GPIOX::ptr()).odr().read().odr($i).is_low() }; - Ok(is_set_low) - } - } - - impl toggleable::Default for $PXi> {} - - impl InputPin for $PXi> { - type Error = (); - - fn is_high(&self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } - - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low() }; - Ok(is_low) - } - } - - impl embedded_hal::digital::InputPin for $PXi> { - fn is_high(&mut self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } - - fn is_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low() }; - Ok(is_low) - } - } - - impl $PXi> { - /// 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) -> $PXx> { - $PXx { i: $i, _mode: self._mode } - } - } - - impl embedded_hal::digital::ErrorType for $PXi> { - type Error = core::convert::Infallible; - } - - impl embedded_hal::digital::InputPin for $PXi> { - fn is_high(&mut self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } - - fn is_low(&mut self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low()}; - Ok(is_low) - } - } - - impl InputPin for $PXi> { - type Error = (); - - fn is_high(&self) -> Result { - let is_high = !self.is_low()?; - Ok(is_high) - } - - fn is_low(&self) -> Result { - // NOTE(unsafe) atomic read with no side effects - let is_low = unsafe { (*$GPIOX::ptr()).idr().read().idr($i).is_low()}; - Ok(is_low) - } - } - - exti!($PXi>, $Pxn, $i, $exticri); - exti!($PXi>, $Pxn, $i, $exticri); + $( + impl super::marker::IntoAf<$A> for $PXi { } + )* )+ - impl $PXx { - pub fn get_id (&self) -> u8 { - self.i - } - } } + + pub use $gpiox::{ $($PXi,)+ }; + } +} +use gpio; + +mod g4; +pub use g4::*; + +const fn gpiox() -> *const crate::pac::gpioa::RegisterBlock { + match P { + 'A' => crate::pac::GPIOA::ptr(), + 'B' => crate::pac::GPIOB::ptr() as _, + 'C' => crate::pac::GPIOC::ptr() as _, + #[cfg(feature = "gpiod")] + 'D' => crate::pac::GPIOD::ptr() as _, + #[cfg(feature = "gpioe")] + 'E' => crate::pac::GPIOE::ptr() as _, + #[cfg(feature = "gpiof")] + 'F' => crate::pac::GPIOF::ptr() as _, + #[cfg(feature = "gpiog")] + 'G' => crate::pac::GPIOG::ptr() as _, + _ => panic!("Unknown GPIO port"), } } - -gpio!(GPIOA, gpioa, gpioaen, PA, 0, [ - PA0: (pa0, 0, exticr1), - PA1: (pa1, 1, exticr1), - PA2: (pa2, 2, exticr1), - PA3: (pa3, 3, exticr1), - PA4: (pa4, 4, exticr2), - PA5: (pa5, 5, exticr2), - PA6: (pa6, 6, exticr2), - PA7: (pa7, 7, exticr2), - PA8: (pa8, 8, exticr3), - PA9: (pa9, 9, exticr3), - PA10: (pa10, 10, exticr3), - PA11: (pa11, 11, exticr3), - PA12: (pa12, 12, exticr4), - PA13: (pa13, 13, exticr4), - PA14: (pa14, 14, exticr4), - PA15: (pa15, 15, exticr4), -]); - -gpio!(GPIOB, gpiob, gpioben, PB, 1, [ - PB0: (pb0, 0, exticr1), - PB1: (pb1, 1, exticr1), - PB2: (pb2, 2, exticr1), - PB3: (pb3, 3, exticr1), - PB4: (pb4, 4, exticr2), - PB5: (pb5, 5, exticr2), - PB6: (pb6, 6, exticr2), - PB7: (pb7, 7, exticr2), - PB8: (pb8, 8, exticr3), - PB9: (pb9, 9, exticr3), - PB10: (pb10, 10, exticr3), - PB11: (pb11, 11, exticr3), - PB12: (pb12, 12, exticr4), - PB13: (pb13, 13, exticr4), - PB14: (pb14, 14, exticr4), - PB15: (pb15, 15, exticr4), -]); - -gpio!(GPIOC, gpioc, gpiocen, PC, 2, [ - PC0: (pc0, 0, exticr1), - PC1: (pc1, 1, exticr1), - PC2: (pc2, 2, exticr1), - PC3: (pc3, 3, exticr1), - PC4: (pc4, 4, exticr2), - PC5: (pc5, 5, exticr2), - PC6: (pc6, 6, exticr2), - PC7: (pc7, 7, exticr2), - PC8: (pc8, 8, exticr3), - PC9: (pc9, 9, exticr3), - PC10: (pc10, 10, exticr3), - PC11: (pc11, 11, exticr3), - PC12: (pc12, 12, exticr4), - PC13: (pc13, 13, exticr4), - PC14: (pc14, 14, exticr4), - PC15: (pc15, 15, exticr4), -]); - -gpio!(GPIOD, gpiod, gpioden, PD, 3, [ - PD0: (pd0, 0, exticr1), - PD1: (pd1, 1, exticr1), - PD2: (pd2, 2, exticr1), - PD3: (pd3, 3, exticr1), - PD4: (pd4, 4, exticr2), - PD5: (pd5, 5, exticr2), - PD6: (pd6, 6, exticr2), - PD7: (pd7, 7, exticr2), - PD8: (pd8, 8, exticr3), - PD9: (pd9, 9, exticr3), - PD10: (pd10, 10, exticr3), - PD11: (pd11, 11, exticr3), - PD12: (pd12, 12, exticr4), - PD13: (pd13, 13, exticr4), - PD14: (pd14, 14, exticr4), - PD15: (pd15, 15, exticr4), -]); - -gpio!(GPIOE, gpioe, gpioeen, PE, 4, [ - PE0: (pe0, 0, exticr1), - PE1: (pe1, 1, exticr1), - PE2: (pe2, 2, exticr1), - PE3: (pe3, 3, exticr1), - PE4: (pe4, 4, exticr2), - PE5: (pe5, 5, exticr2), - PE6: (pe6, 6, exticr2), - PE7: (pe7, 7, exticr2), - PE8: (pe8, 8, exticr3), - PE9: (pe9, 9, exticr3), - PE10: (pe10, 10, exticr3), - PE11: (pe11, 11, exticr3), - PE12: (pe12, 12, exticr4), - PE13: (pe13, 13, exticr4), - PE14: (pe14, 14, exticr4), - PE15: (pe15, 15, exticr4), -]); - -gpio!(GPIOF, gpiof, gpiofen, PF, 5, [ - PF0: (pf0, 0, exticr1), - PF1: (pf1, 1, exticr1), - PF2: (pf2, 2, exticr1), - PF3: (pf3, 3, exticr1), - PF4: (pf4, 4, exticr2), - PF5: (pf5, 5, exticr2), - PF6: (pf6, 6, exticr2), - PF7: (pf7, 7, exticr2), - PF8: (pf8, 8, exticr3), - PF9: (pf9, 9, exticr3), - PF10: (pf10, 10, exticr3), - PF11: (pf11, 11, exticr3), - PF12: (pf12, 12, exticr4), - PF13: (pf13, 13, exticr4), - PF14: (pf14, 14, exticr4), - PF15: (pf15, 15, exticr4), -]); - -gpio!(GPIOG, gpiog, gpiogen, PG, 6, [ - PG0: (pg0, 0, exticr1), - PG1: (pg1, 1, exticr1), - PG2: (pg2, 2, exticr1), - PG3: (pg3, 3, exticr1), - PG4: (pg4, 4, exticr2), - PG5: (pg5, 5, exticr2), - PG6: (pg6, 6, exticr2), - PG7: (pg7, 7, exticr2), - PG8: (pg8, 8, exticr3), - PG9: (pg9, 9, exticr3), - PG10: (pg10, 10, exticr3), - PG11: (pg11, 11, exticr3), - PG12: (pg12, 12, exticr4), - PG13: (pg13, 13, exticr4), - PG14: (pg14, 14, exticr4), - PG15: (pg15, 15, exticr4), -]); diff --git a/src/gpio/alt.rs b/src/gpio/alt.rs new file mode 100644 index 00000000..84dc52ca --- /dev/null +++ b/src/gpio/alt.rs @@ -0,0 +1,396 @@ +mod g4; +pub use g4::*; + +macro_rules! extipin { + ($( $(#[$attr:meta])* $PX:ident,)*) => { + fn make_interrupt_source(&mut self, _syscfg: &mut $crate::syscfg::SysCfg) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.make_interrupt_source(_syscfg), + )* + _ => {}, + } + + } + + fn trigger_on_edge(&mut self, _exti: &mut $crate::pac::EXTI, _level: $crate::gpio::SignalEdge) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.trigger_on_edge(_exti, _level), + )* + _ => {}, + } + } + + fn enable_interrupt(&mut self, _exti: &mut $crate::pac::EXTI) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.enable_interrupt(_exti), + )* + _ => {}, + } + } + fn disable_interrupt(&mut self, _exti: &mut $crate::pac::EXTI) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.disable_interrupt(_exti), + )* + _ => {}, + } + } + fn clear_interrupt_pending_bit(&mut self) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.clear_interrupt_pending_bit(), + )* + _ => {}, + } + } + fn check_interrupt(&self) -> bool { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.check_interrupt(), + )* + _ => false, + } + } + }; +} +use extipin; + +macro_rules! pin { + ( $($(#[$docs:meta])* <$name:ident, $Otype:ident> for $(no: $NoPin:ident,)? [$( + $(#[$attr:meta])* $PX:ident<$A:literal $(, Speed::$Speed:ident)?>, + )*],)*) => { + $( + #[derive(Debug)] + $(#[$docs])* + pub enum $name { + $( + None($NoPin<$Otype>), + )? + + $( + $(#[$attr])* + $PX(gpio::$PX<$crate::gpio::Alternate<$A, $Otype>>), + )* + } + + impl crate::Sealed for $name { } + + #[allow(unreachable_patterns)] + impl $crate::gpio::ReadPin for $name { + fn is_low(&self) -> bool { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.is_low(), + )* + _ => false, + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::PinSpeed for $name { + fn set_speed(&mut self, _speed: $crate::gpio::Speed) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.set_speed(_speed), + )* + _ => {} + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::PinPull for $name { + fn set_internal_resistor(&mut self, _pull: $crate::gpio::Pull) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.set_internal_resistor(_pull), + )* + _ => {} + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::ExtiPin for $name { + extipin! { $( $(#[$attr])* $PX, )* } + } + + $( + impl From<$NoPin<$Otype>> for $name { + fn from(p: $NoPin<$Otype>) -> Self { + Self::None(p) + } + } + )? + + $( + $(#[$attr])* + impl From> for $name + where + MODE: $crate::gpio::marker::NotAlt + $crate::gpio::PinMode + { + fn from(p: gpio::$PX) -> Self { + Self::$PX(p.into_mode() $(.speed($crate::gpio::Speed::$Speed))?) + } + } + + $(#[$attr])* + impl From>> for $name { + fn from(p: gpio::$PX<$crate::gpio::Alternate<$A, $Otype>>) -> Self { + Self::$PX(p $(.speed($crate::gpio::Speed::$Speed))?) + } + } + + $(#[$attr])* + #[allow(irrefutable_let_patterns)] + impl TryFrom<$name> for gpio::$PX + where + MODE: $crate::gpio::PinMode, + $crate::gpio::Alternate<$A, $Otype>: $crate::gpio::PinMode, + { + type Error = (); + + fn try_from(a: $name) -> Result { + if let $name::$PX(p) = a { + Ok(p.into_mode()) + } else { + Err(()) + } + } + } + )* + )* + }; + + ( $($(#[$docs:meta])* <$name:ident> default:$DefaultOtype:ident for $(no: $NoPin:ident,)? [$( + $(#[$attr:meta])* $PX:ident<$A:literal>, + )*],)*) => { + $( + #[derive(Debug)] + $(#[$docs])* + pub enum $name { + $( + None($NoPin), + )? + + $( + $(#[$attr])* + $PX(gpio::$PX<$crate::gpio::Alternate<$A, Otype>>), + )* + } + + impl crate::Sealed for $name { } + + #[allow(unreachable_patterns)] + impl $crate::gpio::ReadPin for $name { + fn is_low(&self) -> bool { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.is_low(), + )* + _ => false, + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::PinSpeed for $name { + fn set_speed(&mut self, _speed: $crate::gpio::Speed) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.set_speed(_speed), + )* + _ => {} + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::PinPull for $name { + fn set_internal_resistor(&mut self, _pull: $crate::gpio::Pull) { + match self { + $( + $(#[$attr])* + Self::$PX(p) => p.set_internal_resistor(_pull), + )* + _ => {} + } + } + } + + #[allow(unreachable_patterns)] + impl $crate::gpio::ExtiPin for $name { + extipin! { $( $(#[$attr])* $PX, )* } + } + + $( + impl From<$NoPin> for $name { + fn from(p: $NoPin) -> Self { + Self::None(p) + } + } + )? + + $( + $(#[$attr])* + impl From> for $name + where + MODE: $crate::gpio::marker::NotAlt + $crate::gpio::PinMode, + $crate::gpio::Alternate<$A, Otype>: $crate::gpio::PinMode, + { + fn from(p: gpio::$PX) -> Self { + Self::$PX(p.into_mode()) + } + } + + $(#[$attr])* + impl From>> for $name { + fn from(p: gpio::$PX<$crate::gpio::Alternate<$A, Otype>>) -> Self { + Self::$PX(p) + } + } + + $(#[$attr])* + #[allow(irrefutable_let_patterns)] + impl TryFrom<$name> for gpio::$PX + where + MODE: $crate::gpio::PinMode, + $crate::gpio::Alternate<$A, Otype>: $crate::gpio::PinMode, + { + type Error = (); + + fn try_from(a: $name) -> Result { + if let $name::$PX(p) = a { + Ok(p.into_mode()) + } else { + Err(()) + } + } + } + )* + )* + }; +} +use pin; + +// CAN pins +#[cfg(feature = "fdcan1")] +pub trait CanCommon { + type Rx; + type Tx; +} + +// Serial pins +pub trait SerialAsync { + /// Receive + type Rx; + /// Transmit + type Tx; +} +/// Synchronous mode +pub trait SerialSync { + type Ck; +} +/// Hardware flow control (RS232) +pub trait SerialFlowControl { + /// "Clear To Send" blocks the data transmission at the end of the current transfer when high + type Cts; + /// "Request to send" indicates that the USART is ready to receive a data (when low) + type Rts; +} + +// I2C pins +pub trait I2cCommon { + type Scl; + type Sda; + type Smba; +} + +// I2S pins +pub trait I2sCommon { + type Ck: crate::gpio::PinSpeed; + type Sd; + type Ws: crate::gpio::ReadPin + crate::gpio::ExtiPin; +} +pub trait I2sMaster { + type Mck; +} +pub trait I2sExtPin { + type ExtSd; +} + +// QuadSPI pins + +#[cfg(feature = "quadspi1")] +pub trait QuadSpiBanks { + type Bank1; + type Bank2; +} +#[cfg(feature = "quadspi1")] +pub trait QuadSpiBank { + type Io0: crate::gpio::PinSpeed; + type Io1: crate::gpio::PinSpeed; + type Io2: crate::gpio::PinSpeed; + type Io3: crate::gpio::PinSpeed; + type Ncs: crate::gpio::PinSpeed; +} + +// SAI pins + +#[cfg(feature = "sai1")] +pub trait SaiChannels { + type A; + type B; +} +#[cfg(feature = "sai1")] +pub trait SaiChannel { + type Fs; + type Mclk; + type Sck; + type Sd; +} + +// SPI pins +pub trait SpiCommon { + type Miso; + type Mosi; + type Nss; + type Sck; +} + +// Timer pins + +/// Input capture / Output compare channel `C` +pub trait TimCPin { + type Ch; +} + +/// Complementary output channel `C` +pub trait TimNCPin { + type ChN; +} + +/// Break input +pub trait TimBkin { + type Bkin; +} + +/// External trigger timer input +pub trait TimEtr { + type Etr; +} diff --git a/src/gpio/alt/g4.rs b/src/gpio/alt/g4.rs new file mode 100644 index 00000000..af441a57 --- /dev/null +++ b/src/gpio/alt/g4.rs @@ -0,0 +1,2060 @@ +use super::*; +use crate::gpio::{self, NoPin, OpenDrain, PushPull}; + +// auto-generated using codegen +// STM32CubeMX DB release: DB.6.0.130 + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp1 { + use super::*; + + pin! { + for [ + PA0<8>, + PA6<8>, + PA11<8>, + PB8<8>, + #[cfg(feature = "gpio-g47x")] + PF4<2>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp2 { + use super::*; + + pin! { + for [ + PA2<8>, + PA7<8>, + PA12<8>, + PB9<8>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp3 { + use super::*; + + pin! { + for [ + PB7<8>, + PB15<3>, + PC2<3>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp4 { + use super::*; + + pin! { + for [ + PB1<8>, + PB6<8>, + PB14<8>, + ], + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp5 { + use super::*; + + pin! { + for [ + PA9<8>, + PC7<7>, + ], + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp6 { + use super::*; + + pin! { + for [ + PA10<8>, + PC6<7>, + ], + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp7 { + use super::*; + + pin! { + for [ + PA8<8>, + PC8<7>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod crs { + use super::*; + + pin! { + for [ + PA10<3>, + PB3<3>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod fdcan1 { + use super::*; + + pin! { + for no:NoPin, [ + PA11<9>, + PB8<9>, + PD0<9>, + ], + for no:NoPin, [ + PA12<9>, + PB9<9>, + PD1<9>, + ], + } + + impl CanCommon for crate::pac::FDCAN1 { + type Rx = Rx; + type Tx = Tx; + } +} + +#[cfg(any(feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod fdcan2 { + use super::*; + + pin! { + for no:NoPin, [ + PB5<9>, + PB12<9>, + ], + for no:NoPin, [ + PB6<9>, + PB13<9>, + ], + } + + impl CanCommon for crate::pac::FDCAN2 { + type Rx = Rx; + type Tx = Tx; + } +} + +#[cfg(feature = "gpio-g47x")] +#[cfg(not(feature = "stm32g471"))] +pub mod fdcan3 { + use super::*; + + pin! { + for no:NoPin, [ + PA8<11>, + PB3<11>, + ], + for no:NoPin, [ + PA15<11>, + PB4<11>, + ], + } + + impl CanCommon for crate::pac::FDCAN3 { + type Rx = Rx; + type Tx = Tx; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod fmc { + use super::*; + + pin! { + for [ + PF10<12>, + ], + for [ + PF7<12>, + ], + for [ + PG0<12>, + ], + for [ + PG1<12>, + ], + for [ + PG2<12>, + ], + for [ + PG3<12>, + ], + for [ + PG4<12>, + ], + for [ + PG5<12>, + ], + for [ + PD11<12>, + ], + for [ + PD12<12>, + ], + for [ + PD13<12>, + ], + for [ + PE3<12>, + ], + for [ + PF2<12>, + ], + for [ + PE4<12>, + ], + for [ + PE5<12>, + ], + for [ + PE6<12>, + ], + for [ + PE2<12>, + ], + for [ + PF8<12>, + ], + for [ + PF9<12>, + ], + for [ + PF3<12>, + ], + for [ + PF4<12>, + ], + for [ + PF5<12>, + ], + for [ + PF12<12>, + ], + for [ + PF13<12>, + ], + for [ + PF14<12>, + ], + for [ + PF15<12>, + ], + for [ + PD3<12>, + ], + for [ + PD14<12>, + ], + for [ + PD15<12>, + ], + for [ + PE13<12>, + ], + for [ + PE14<12>, + ], + for [ + PE15<12>, + ], + for [ + PD8<12>, + ], + for [ + PD9<12>, + ], + for [ + PD10<12>, + ], + for [ + PD0<12>, + ], + for [ + PD1<12>, + ], + for [ + PE7<12>, + ], + for [ + PE8<12>, + ], + for [ + PE9<12>, + ], + for [ + PE10<12>, + ], + for [ + PE11<12>, + ], + for [ + PE12<12>, + ], + for [ + PD14<12>, + ], + for [ + PD15<12>, + ], + for [ + PE13<12>, + ], + for [ + PE14<12>, + ], + for [ + PE15<12>, + ], + for [ + PD8<12>, + ], + for [ + PD9<12>, + ], + for [ + PD10<12>, + ], + for [ + PD0<12>, + ], + for [ + PD1<12>, + ], + for [ + PE7<12>, + ], + for [ + PE8<12>, + ], + for [ + PE9<12>, + ], + for [ + PE10<12>, + ], + for [ + PE11<12>, + ], + for [ + PE12<12>, + ], + for [ + PG6<12>, + PG7<12>, + ], + for [ + PE0<12>, + ], + for [ + PE1<12>, + ], + for [ + PD7<12>, + PG9<12>, + ], + for [ + PD7<12>, + ], + for [ + PG9<12>, + ], + for [ + PG8<12>, + ], + for [ + PF11<12>, + ], + for [ + PB7<12>, + ], + for [ + PD4<12>, + ], + for [ + PD6<12>, + ], + for [ + PD5<12>, + ], + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod hrtim1 { + use super::*; + + pin! { + for [ + PA8<13>, + ], + for [ + PA9<13>, + ], + for [ + PA10<13>, + ], + for [ + PA11<13>, + ], + for [ + PB12<13>, + ], + for [ + PB13<13>, + ], + for [ + PB14<13>, + ], + for [ + PB15<13>, + ], + for [ + PC8<3>, + ], + for [ + PC9<3>, + ], + for [ + PC6<13>, + ], + for [ + PC7<13>, + ], + for [ + PC12<3>, + ], + for [ + PC5<13>, + PC6<3>, + ], + for [ + PC11<3>, + ], + for [ + PB7<13>, + ], + for [ + PB6<13>, + ], + for [ + PB9<13>, + ], + for [ + PB5<13>, + ], + for [ + PB4<13>, + ], + for [ + PB8<13>, + ], + for [ + PB3<13>, + ], + for [ + PA12<13>, + ], + for [ + PA15<13>, + ], + for [ + PB10<13>, + ], + for [ + PB11<13>, + ], + for [ + PB0<13>, + PC7<3>, + ], + for [ + PC10<13>, + ], + for [ + PB2<13>, + PB6<12>, + ], + for [ + PB1<13>, + PB3<12>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2c1 { + use super::*; + + pin! { + for [ + PA13<4>, + PA15<4>, + PB8<4>, + ], + for [ + PA14<4>, + PB7<4>, + PB9<4>, + ], + for [ + PB5<4>, + ], + } + use crate::pac::I2C1 as I2C; + impl I2cCommon for I2C { + type Scl = Scl; + type Sda = Sda; + type Smba = Smba; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2c2 { + use super::*; + + pin! { + for [ + PA9<4>, + PC4<4>, + #[cfg(feature = "gpio-g47x")] + PF6<4>, + ], + for [ + PA8<4>, + PF0<4>, + ], + for [ + PA10<4>, + PB12<4>, + PF2<4>, + ], + } + use crate::pac::I2C2 as I2C; + impl I2cCommon for I2C { + type Scl = Scl; + type Sda = Sda; + type Smba = Smba; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2c3 { + use super::*; + + pin! { + for [ + PA8<2>, + PC8<8>, + #[cfg(feature = "gpio-g47x")] + PF3<4>, + #[cfg(feature = "gpio-g47x")] + PG7<4>, + ], + for [ + PB5<8>, + PC9<8>, + PC11<8>, + #[cfg(feature = "gpio-g47x")] + PF4<4>, + #[cfg(feature = "gpio-g47x")] + PG8<4>, + ], + for [ + PA9<2>, + PB2<4>, + #[cfg(feature = "gpio-g47x")] + PG6<4>, + ], + } + use crate::pac::I2C3 as I2C; + impl I2cCommon for I2C { + type Scl = Scl; + type Sda = Sda; + type Smba = Smba; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod i2c4 { + use super::*; + + pin! { + for [ + PA13<3>, + PC6<8>, + PF14<4>, + PG3<4>, + ], + for [ + PB7<3>, + PC7<8>, + PF15<4>, + PG4<4>, + ], + for [ + PA14<3>, + PD11<4>, + PF13<4>, + ], + } + use crate::pac::I2C4 as I2C; + impl I2cCommon for I2C { + type Scl = Scl; + type Sda = Sda; + type Smba = Smba; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2s { + use super::*; + + pin! { + for [ + PA12<5>, + PC9<5>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2s2 { + use super::*; + + pin! { + for [ + PB13<5>, + PF1<5>, + ], + for no:NoPin, [ + PA8<5>, + PC6<6>, + ], + for [ + PA11<5>, + PB15<5>, + ], + for [ + PB12<5>, + PF0<5>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod i2s3 { + use super::*; + + pin! { + for [ + PB3<6>, + PC10<6>, + ], + for no:NoPin, [ + PA9<5>, + PC7<6>, + ], + for [ + PB5<6>, + PC12<6>, + ], + for [ + PA4<6>, + PA15<6>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod ir { + use super::*; + + pin! { + default:PushPull for [ + PA13<5>, + PB9<6>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod lptim1 { + use super::*; + + pin! { + for [ + PB6<11>, + PC3<1>, + ], + for [ + PB5<11>, + PC0<1>, + ], + for [ + PB7<11>, + PC2<1>, + ], + } + + pin! { + default:PushPull for [ + PA14<1>, + PB2<1>, + PC1<1>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod lpuart1 { + use super::*; + + pin! { + for [ + PA6<12>, + PB13<8>, + #[cfg(feature = "gpio-g47x")] + PG5<8>, + ], + for [ + PB1<12>, + PB12<8>, + #[cfg(feature = "gpio-g47x")] + PG6<8>, + ], + for [ + PB1<12>, + PB12<8>, + #[cfg(feature = "gpio-g47x")] + PG6<8>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PA3<12>, + PB10<8>, + PC0<8>, + #[cfg(feature = "gpio-g47x")] + PG8<8>, + ], + default:PushPull for no:NoPin, [ + PA2<12>, + PB11<8>, + PC1<8>, + #[cfg(feature = "gpio-g47x")] + PG7<8>, + ], + } +} + +#[cfg(any(feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod quadspi1 { + use super::*; + + pin! { + for [ + PB1<10>, + PE12<10>, + #[cfg(feature = "gpio-g47x")] + PF8<10>, + ], + for [ + PB0<10>, + PE13<10>, + PF9<10>, + ], + for [ + PA7<10>, + PE14<10>, + #[cfg(feature = "gpio-g47x")] + PF7<10>, + ], + for [ + PA6<10>, + PE15<10>, + #[cfg(feature = "gpio-g47x")] + PF6<10>, + ], + for [ + PA2<10>, + PB11<10>, + PE11<10>, + ], + for [ + PC1<10>, + PD4<10>, + ], + for [ + PB2<10>, + PC2<10>, + PD5<10>, + ], + for [ + PC3<10>, + PD6<10>, + ], + for [ + PC4<10>, + PD7<10>, + ], + for [ + PD3<10>, + ], + for [ + PA3<10>, + PB10<10>, + PE10<10>, + PF10<10>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod rcc { + use super::*; + + pin! { + for [ + PA8<0>, + PG10<0>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod rtc { + use super::*; + + pin! { + for [ + PB2<0>, + ], + for [ + PA1<0>, + PB15<0>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod sai1 { + use super::*; + + pin! { + for [ + PA3<3>, + PB8<3>, + PE2<3>, + #[cfg(feature = "gpio-g47x")] + PG7<3>, + ], + for [ + PA8<12>, + PE5<3>, + ], + for [ + PA10<12>, + PC3<3>, + PD6<3>, + PE6<3>, + ], + for [ + PB9<3>, + PE4<3>, + ], + for [ + PC5<3>, + PF10<13>, + ], + for [ + PA9<14>, + PB9<14>, + PE4<13>, + ], + for [ + PA4<13>, + PA14<13>, + PB6<14>, + PE9<13>, + PF9<13>, + ], + for [ + PA3<13>, + PB8<14>, + PE2<13>, + #[cfg(feature = "gpio-g47x")] + PG7<13>, + ], + for [ + PB4<14>, + PE10<13>, + #[cfg(feature = "gpio-g47x")] + PF7<13>, + ], + for [ + PA8<14>, + PB10<14>, + PE5<13>, + ], + for [ + PB3<14>, + PE8<13>, + #[cfg(feature = "gpio-g47x")] + PF8<13>, + ], + for [ + PA10<14>, + PC1<13>, + PC3<13>, + PD6<13>, + PE6<13>, + ], + for [ + PA13<13>, + PB5<12>, + PE3<13>, + PE7<13>, + #[cfg(feature = "gpio-g47x")] + PF6<3>, + ], + } + + use crate::pac::SAI; + pub struct ChannelA; + pub struct ChannelB; + impl SaiChannels for SAI { + type A = ChannelA; + type B = ChannelB; + } + impl SaiChannel for ChannelA { + type Fs = FsA; + type Mclk = MclkA; + type Sck = SckA; + type Sd = SdA; + } + impl SaiChannel for ChannelB { + type Fs = FsB; + type Mclk = MclkB; + type Sck = SckB; + type Sd = SdB; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod spi1 { + use super::*; + + pin! { + for no:NoPin, [ + PA6<5>, + PB4<5>, + #[cfg(feature = "gpio-g47x")] + PG3<5>, + ], + for no:NoPin, [ + PA7<5>, + PB5<5>, + #[cfg(feature = "gpio-g47x")] + PG4<5>, + ], + for [ + PA4<5>, + PA15<5>, + #[cfg(feature = "gpio-g47x")] + PG5<5>, + ], + for no:NoPin, [ + PA5<5>, + PB3<5>, + #[cfg(feature = "gpio-g47x")] + PG2<5>, + ], + } + impl SpiCommon for crate::pac::SPI1 { + type Miso = Miso; + type Mosi = Mosi; + type Nss = Nss; + type Sck = Sck; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod spi2 { + use super::*; + + pin! { + for no:NoPin, [ + PA10<5>, + PB14<5>, + ], + for no:NoPin, [ + PA11<5>, + PB15<5>, + ], + for [ + PB12<5>, + PD15<6>, + PF0<5>, + ], + for no:NoPin, [ + PB13<5>, + PF1<5>, + PF9<5>, + PF10<5>, + ], + } + impl SpiCommon for crate::pac::SPI2 { + type Miso = Miso; + type Mosi = Mosi; + type Nss = Nss; + type Sck = Sck; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod spi3 { + use super::*; + + pin! { + for no:NoPin, [ + PB4<6>, + PC11<6>, + ], + for no:NoPin, [ + PB5<6>, + PC12<6>, + ], + for [ + PA4<6>, + PA15<6>, + ], + for no:NoPin, [ + PB3<6>, + PC10<6>, + #[cfg(feature = "gpio-g47x")] + PG9<6>, + ], + } + impl SpiCommon for crate::pac::SPI3 { + type Miso = Miso; + type Mosi = Mosi; + type Nss = Nss; + type Sck = Sck; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod spi4 { + use super::*; + + pin! { + for no:NoPin, [ + PE5<5>, + PE13<5>, + ], + for no:NoPin, [ + PE6<5>, + PE14<5>, + ], + for [ + PE3<5>, + PE4<5>, + PE11<5>, + ], + for no:NoPin, [ + PE2<5>, + PE12<5>, + ], + } + impl SpiCommon for crate::pac::SPI4 { + type Miso = Miso; + type Mosi = Mosi; + type Nss = Nss; + type Sck = Sck; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod sys { + use super::*; + + pin! { + for [ + PA14<0>, + ], + for [ + PA15<0>, + ], + for [ + PB3<0>, + ], + for [ + PA13<0>, + ], + for [ + PB4<0>, + ], + for [ + #[cfg(feature = "gpio-g47x")] + PC3<0>, + ], + for [ + PE2<0>, + ], + for [ + PE3<0>, + ], + for [ + PE4<0>, + ], + for [ + PE5<0>, + ], + for [ + PE6<0>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim1 { + use super::*; + + pin! { + for [ + PA6<6>, + PA14<6>, + PA15<9>, + PB8<12>, + PB10<12>, + PB12<6>, + PC13<2>, + PE15<2>, + ], + for [ + PA11<12>, + PC3<6>, + PE14<6>, + ], + for [ + PA12<11>, + PC4<2>, + PE7<2>, + ], + } + + pin! { + default:PushPull for [ + PA8<6>, + PC0<2>, + PE9<2>, + ], + default:PushPull for [ + PA7<6>, + PA11<6>, + PB13<6>, + PC13<4>, + PE8<2>, + ], + default:PushPull for [ + PA9<6>, + PC1<2>, + PE11<2>, + ], + default:PushPull for [ + PA12<6>, + PB0<6>, + PB14<6>, + PE10<2>, + ], + default:PushPull for [ + PA10<6>, + PC2<2>, + PE13<2>, + ], + default:PushPull for [ + PB1<6>, + PB9<12>, + PB15<4>, + PE12<2>, + PF0<6>, + ], + default:PushPull for [ + PA11<11>, + PC3<2>, + PE14<2>, + ], + default:PushPull for [ + PC5<6>, + PE15<6>, + ], + } + + use crate::pac::TIM1 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimNCPin<1> for TIM { + type ChN = Ch2N; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimNCPin<2> for TIM { + type ChN = Ch3N; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimNCPin<3> for TIM { + type ChN = Ch4N; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim15 { + use super::*; + + pin! { + for [ + PA9<9>, + PC5<2>, + ], + } + + pin! { + default:PushPull for [ + PA2<9>, + PB14<1>, + PF9<3>, + ], + default:PushPull for [ + PA1<9>, + PB15<2>, + #[cfg(feature = "gpio-g47x")] + PG9<14>, + ], + default:PushPull for [ + PA3<9>, + PB15<1>, + PF10<3>, + ], + } + + use crate::pac::TIM15 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim16 { + use super::*; + + pin! { + for [ + PB5<1>, + ], + } + + pin! { + default:PushPull for [ + PA6<1>, + PA12<1>, + PB4<1>, + PB8<1>, + PE0<4>, + ], + default:PushPull for [ + PA13<1>, + PB6<1>, + ], + } + + use crate::pac::TIM16 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim17 { + use super::*; + + pin! { + for [ + PA10<1>, + PB4<10>, + ], + } + + pin! { + default:PushPull for [ + PA7<1>, + PB5<10>, + PB9<1>, + PE1<4>, + ], + default:PushPull for [ + PB7<1>, + ], + } + + use crate::pac::TIM17 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim2 { + use super::*; + + pin! { + for [ + PA0<14>, + PA5<2>, + PA15<14>, + PD3<2>, + ], + } + + pin! { + default:PushPull for [ + PA0<1>, + PA5<1>, + PA15<1>, + PD3<2>, + ], + default:PushPull for [ + PA1<1>, + PB3<1>, + PD4<2>, + ], + default:PushPull for [ + PA2<1>, + PA9<10>, + PB10<1>, + PD7<2>, + ], + default:PushPull for [ + PA3<1>, + PA10<10>, + PB11<1>, + PD6<2>, + ], + } + + use crate::pac::TIM2 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim20 { + use super::*; + + pin! { + for [ + #[cfg(feature = "gpio-g47x")] + PF7<2>, + PF9<2>, + #[cfg(feature = "gpio-g47x")] + PG3<2>, + #[cfg(feature = "gpio-g47x")] + PG6<2>, + ], + for [ + #[cfg(feature = "gpio-g47x")] + PF8<2>, + PF10<2>, + #[cfg(feature = "gpio-g47x")] + PG4<2>, + ], + for [ + #[cfg(feature = "gpio-g49x")] + PA15<3>, + PE0<6>, + #[cfg(feature = "gpio-g47x")] + PF11<2>, + #[cfg(feature = "gpio-g47x")] + PG5<2>, + ], + } + + pin! { + default:PushPull for [ + PB2<3>, + PE2<6>, + #[cfg(feature = "gpio-g47x")] + PF12<2>, + ], + default:PushPull for [ + PE4<6>, + #[cfg(feature = "gpio-g47x")] + PF4<3>, + #[cfg(feature = "gpio-g47x")] + PG0<2>, + ], + default:PushPull for [ + PC2<6>, + PE3<6>, + #[cfg(feature = "gpio-g47x")] + PF13<2>, + ], + default:PushPull for [ + PE5<6>, + #[cfg(feature = "gpio-g47x")] + PF5<2>, + #[cfg(feature = "gpio-g47x")] + PG1<2>, + ], + default:PushPull for [ + PC8<6>, + PF2<2>, + #[cfg(feature = "gpio-g47x")] + PF14<2>, + ], + default:PushPull for [ + PE6<6>, + #[cfg(feature = "gpio-g47x")] + PG2<2>, + ], + default:PushPull for [ + PE1<6>, + #[cfg(feature = "gpio-g47x")] + PF3<2>, + #[cfg(feature = "gpio-g47x")] + PF15<2>, + ], + default:PushPull for [ + PE0<3>, + #[cfg(feature = "gpio-g47x")] + PG3<6>, + ], + } + + use crate::pac::TIM20 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimNCPin<1> for TIM { + type ChN = Ch2N; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimNCPin<2> for TIM { + type ChN = Ch3N; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimNCPin<3> for TIM { + type ChN = Ch4N; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim3 { + use super::*; + + pin! { + for [ + PB3<10>, + PD2<2>, + ], + } + + pin! { + default:PushPull for [ + PA6<2>, + PB4<2>, + PC6<2>, + PE2<2>, + ], + default:PushPull for [ + PA4<2>, + PA7<2>, + PB5<2>, + PC7<2>, + PE3<2>, + ], + default:PushPull for [ + PB0<2>, + PC8<2>, + PE4<2>, + ], + default:PushPull for [ + PB1<2>, + PB7<10>, + PC9<2>, + PE5<2>, + ], + } + + use crate::pac::TIM3 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim4 { + use super::*; + + pin! { + for [ + PA8<10>, + PB3<2>, + PE0<2>, + ], + } + + pin! { + default:PushPull for [ + PA11<10>, + PB6<2>, + PD12<2>, + ], + default:PushPull for [ + PA12<10>, + PB7<2>, + PD13<2>, + ], + default:PushPull for [ + PA13<10>, + PB8<2>, + PD14<2>, + ], + default:PushPull for [ + PB9<2>, + PD15<2>, + #[cfg(feature = "gpio-g47x")] + PF6<2>, + ], + } + + use crate::pac::TIM4 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod tim5 { + use super::*; + + pin! { + for [ + PB12<2>, + PD11<1>, + PF6<1>, + ], + } + + pin! { + default:PushPull for [ + PA0<2>, + PB2<2>, + PF6<6>, + ], + default:PushPull for [ + PA1<2>, + PC12<1>, + PF7<6>, + ], + default:PushPull for [ + PA2<2>, + PE8<1>, + PF8<6>, + ], + default:PushPull for [ + PA3<2>, + PE9<1>, + PF9<6>, + ], + } + + use crate::pac::TIM5 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod tim8 { + use super::*; + + pin! { + for [ + PA0<9>, + PA6<4>, + PA10<11>, + PB7<5>, + PD2<4>, + ], + for [ + PB6<10>, + PC9<6>, + PD1<6>, + ], + for [ + PA0<10>, + PB6<6>, + ], + } + + pin! { + default:PushPull for [ + PA15<2>, + PB6<5>, + PC6<4>, + ], + default:PushPull for [ + PA7<4>, + PB3<4>, + PC10<4>, + ], + default:PushPull for [ + PA14<5>, + PB8<10>, + PC7<4>, + ], + default:PushPull for [ + PB0<4>, + PB4<4>, + PC11<4>, + ], + default:PushPull for [ + PB9<10>, + PC8<4>, + ], + default:PushPull for [ + PB1<4>, + PB5<3>, + PC12<4>, + ], + default:PushPull for [ + PC9<4>, + PD1<4>, + ], + default:PushPull for [ + PC13<6>, + PD0<6>, + ], + } + + use crate::pac::TIM8 as TIM; + impl TimCPin<0> for TIM { + type Ch = Ch1; + } + impl TimNCPin<0> for TIM { + type ChN = Ch1N; + } + impl TimCPin<1> for TIM { + type Ch = Ch2; + } + impl TimNCPin<1> for TIM { + type ChN = Ch2N; + } + impl TimCPin<2> for TIM { + type Ch = Ch3; + } + impl TimNCPin<2> for TIM { + type ChN = Ch3N; + } + impl TimCPin<3> for TIM { + type Ch = Ch4; + } + impl TimNCPin<3> for TIM { + type ChN = Ch4N; + } + impl TimBkin for TIM { + type Bkin = Bkin; + } + impl TimEtr for TIM { + type Etr = Etr; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod uart4 { + use super::*; + + pin! { + for [ + PB7<14>, + ], + for [ + PA15<8>, + ], + for [ + PA15<8>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PC11<5>, + ], + default:PushPull for no:NoPin, [ + PC10<5>, + ], + } + + use crate::pac::UART4 as UART; + impl SerialAsync for UART { + type Rx = Rx; + type Tx = Tx; + } + impl SerialFlowControl for UART { + type Cts = Cts; + type Rts = Rts; + } +} + +#[cfg(any(feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod uart5 { + use super::*; + + pin! { + for [ + PB5<14>, + ], + for [ + PB4<8>, + ], + for [ + PB4<8>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PD2<5>, + ], + default:PushPull for no:NoPin, [ + PC12<5>, + ], + } + + use crate::pac::UART5 as UART; + impl SerialAsync for UART { + type Rx = Rx; + type Tx = Tx; + } + impl SerialFlowControl for UART { + type Cts = Cts; + type Rts = Rts; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod ucpd1 { + use super::*; + + pin! { + for [ + PA2<14>, + PA5<14>, + PA7<14>, + PB0<14>, + PC12<14>, + ], + for [ + PA2<14>, + PA5<14>, + PA7<14>, + PB0<14>, + PC12<14>, + ], + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod usart1 { + use super::*; + + pin! { + for [ + PA8<7>, + ], + for [ + PA11<7>, + ], + for [ + PA12<7>, + ], + for [ + PA11<7>, + ], + for [ + PA12<7>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PA10<7>, + PB7<7>, + PC5<7>, + PE1<7>, + ], + default:PushPull for no:NoPin, [ + PA9<7>, + PB6<7>, + PC4<7>, + PE0<7>, + #[cfg(feature = "gpio-g47x")] + PG9<7>, + ], + } + + use crate::pac::USART1 as USART; + impl SerialAsync for USART { + type Rx = Rx; + type Tx = Tx; + } + impl SerialSync for USART { + type Ck = Ck; + } + impl SerialFlowControl for USART { + type Cts = Cts; + type Rts = Rts; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod usart2 { + use super::*; + + pin! { + for [ + PA4<7>, + PB5<7>, + PD7<7>, + ], + for [ + PA0<7>, + PD3<7>, + ], + for [ + PA1<7>, + PD4<7>, + ], + for [ + PA0<7>, + PD3<7>, + ], + for [ + PA1<7>, + PD4<7>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PA3<7>, + PA15<7>, + PB4<7>, + PD6<7>, + ], + default:PushPull for no:NoPin, [ + PA2<7>, + PA14<7>, + PB3<7>, + PD5<7>, + ], + } + + use crate::pac::USART2 as USART; + impl SerialAsync for USART { + type Rx = Rx; + type Tx = Tx; + } + impl SerialSync for USART { + type Ck = Ck; + } + impl SerialFlowControl for USART { + type Cts = Cts; + type Rts = Rts; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod usart3 { + use super::*; + + pin! { + for [ + PB12<7>, + PC12<7>, + PD10<7>, + ], + for [ + PA13<7>, + PB13<7>, + PD11<7>, + ], + for [ + PB14<7>, + PD12<7>, + #[cfg(feature = "gpio-g47x")] + PF6<7>, + ], + for [ + PA13<7>, + PB13<7>, + PD11<7>, + ], + for [ + PB14<7>, + PD12<7>, + #[cfg(feature = "gpio-g47x")] + PF6<7>, + ], + } + + pin! { + default:PushPull for no:NoPin, [ + PB8<7>, + PB11<7>, + PC11<7>, + PD9<7>, + PE15<7>, + ], + default:PushPull for no:NoPin, [ + PB9<7>, + PB10<7>, + PC10<7>, + PD8<7>, + ], + } + + use crate::pac::USART3 as USART; + impl SerialAsync for USART { + type Rx = Rx; + type Tx = Tx; + } + impl SerialSync for USART { + type Ck = Ck; + } + impl SerialFlowControl for USART { + type Cts = Cts; + type Rts = Rts; + } +} diff --git a/src/gpio/convert.rs b/src/gpio/convert.rs new file mode 100644 index 00000000..2ac350c0 --- /dev/null +++ b/src/gpio/convert.rs @@ -0,0 +1,362 @@ +use super::*; +use crate::pac::gpioa::{moder::MODE as Mode, otyper::OUTPUT_TYPE as OutputType}; + +impl Input { + pub fn new( + pin: Pin, + pull: Pull, + ) -> Pin { + pin.into_mode().internal_resistor(pull) + } +} + +impl Output { + pub fn new( + mut pin: Pin, + state: PinState, + ) -> Pin + where + Self: PinMode, + { + pin._set_state(state); + pin.into_mode() + } +} + +impl Analog { + pub fn new(pin: Pin) -> Pin { + pin.into_mode() + } +} + +impl Pin> { + /// Turns pin alternate configuration pin into open drain + pub fn set_open_drain(self) -> Pin> { + self.into_mode() + } +} + +impl Pin { + /// Configures the pin to operate alternate mode + pub fn into_alternate(self) -> Pin> + where + Self: marker::IntoAf, + { + self.into_mode() + } + + /// Configures the pin to operate in alternate open drain mode + #[allow(path_statements)] + pub fn into_alternate_open_drain(self) -> Pin> + where + Self: 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) -> Pin { + self.into_mode().internal_resistor(Pull::None) + } + + /// Configures the pin to operate as a pulled down input pin + pub fn into_pull_down_input(self) -> Pin { + self.into_mode().internal_resistor(Pull::Down) + } + + /// Configures the pin to operate as a pulled up input pin + pub fn into_pull_up_input(self) -> Pin { + self.into_mode().internal_resistor(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) -> 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, + 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) -> 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, + 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) -> 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) -> DynamicPin { + self.into_floating_input(); + 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!((*gpiox::

()), 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) => { + unsafe { + if MODE::OTYPER != M::OTYPER { + if let Some(otyper) = M::OTYPER { + $block.otyper().modify(|_, w| w.ot($N).variant(otyper)); + } + } + + if MODE::AFR != M::AFR { + if let Some(afr) = M::AFR { + if $N < 8 { + $block.afrl().modify(|_, w| w.afr($N).bits(afr)); + } else { + $block.afrh().modify(|_, w| w.afr($N - 8).bits(afr)); + } + } + } + + if MODE::MODER != M::MODER { + if let Some(mode) = M::MODER { + $block.moder().modify(|_, w| w.moder($N).variant(mode)); + } + } + } + }; +} +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!((*gpiox::

()), n); + } + + #[inline(always)] + /// Converts pin into specified mode + pub fn into_mode(mut self) -> PartiallyErasedPin { + self.mode::(); + PartiallyErasedPin::new(self.i) + } +} + +impl Pin +where + MODE: PinMode, +{ + fn with_mode(&mut self, f: F) -> R + where + M: PinMode, + F: FnOnce(&mut Pin) -> R, + { + self.mode::(); // change physical mode, without changing typestate + + // This will reset the pin back to the original mode when dropped. + // (so either when `with_mode` returns or when `f` unwinds) + let mut resetti = ResetMode::::new(); + + f(&mut resetti.pin) + } + + /// Temporarily configures this pin as a input. + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + pub fn with_input(&mut self, f: impl FnOnce(&mut Pin) -> R) -> R { + self.with_mode(f) + } + + /// Temporarily configures this pin as an analog pin. + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + pub fn with_analog(&mut self, f: impl FnOnce(&mut Pin) -> R) -> R { + self.with_mode(f) + } + + /// Temporarily configures this pin as an open drain output. + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + /// The value of the pin after conversion is undefined. If you + /// want to control it, use `with_open_drain_output_in_state` + pub fn with_open_drain_output( + &mut self, + f: impl FnOnce(&mut Pin>) -> R, + ) -> R { + self.with_mode(f) + } + + /// Temporarily configures this pin as an open drain output . + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + /// Note that the new state is set slightly before conversion + /// happens. This can cause a short output glitch if switching + /// between output modes + pub fn with_open_drain_output_in_state( + &mut self, + state: PinState, + f: impl FnOnce(&mut Pin>) -> R, + ) -> R { + self._set_state(state); + self.with_mode(f) + } + + /// Temporarily configures this pin as a push-pull output. + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + /// The value of the pin after conversion is undefined. If you + /// want to control it, use `with_push_pull_output_in_state` + pub fn with_push_pull_output( + &mut self, + f: impl FnOnce(&mut Pin>) -> R, + ) -> R { + self.with_mode(f) + } + + /// Temporarily configures this pin as a push-pull output. + /// + /// The closure `f` is called with the reconfigured pin. After it returns, + /// the pin will be configured back. + /// Note that the new state is set slightly before conversion + /// happens. This can cause a short output glitch if switching + /// between output modes + pub fn with_push_pull_output_in_state( + &mut self, + state: PinState, + f: impl FnOnce(&mut Pin>) -> R, + ) -> R { + self._set_state(state); + self.with_mode(f) + } +} + +/// Wrapper around a pin that transitions the pin to mode ORIG when dropped +struct ResetMode { + pub pin: Pin, + _mode: PhantomData, +} +impl ResetMode { + fn new() -> Self { + Self { + pin: Pin::new(), + _mode: PhantomData, + } + } +} +impl Drop + for ResetMode +{ + fn drop(&mut self) { + self.pin.mode::(); + } +} + +/// 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: Option = None; + #[doc(hidden)] + const OTYPER: Option = None; + #[doc(hidden)] + const AFR: Option = None; +} + +impl crate::Sealed for Input {} +impl PinMode for Input { + const MODER: Option = Some(Mode::Input); +} + +impl crate::Sealed for Analog {} +impl PinMode for Analog { + const MODER: Option = Some(Mode::Analog); +} + +impl crate::Sealed for Output {} +impl PinMode for Output { + const MODER: Option = Some(Mode::Output); + const OTYPER: Option = Some(OutputType::OpenDrain); +} + +impl PinMode for Output { + const MODER: Option = Some(Mode::Output); + const OTYPER: Option = Some(OutputType::PushPull); +} + +impl crate::Sealed for Alternate {} +impl PinMode for Alternate { + const MODER: Option = Some(Mode::Alternate); + const OTYPER: Option = Some(OutputType::OpenDrain); + const AFR: Option = Some(A); +} + +impl PinMode for Alternate { + const MODER: Option = Some(Mode::Alternate); + const OTYPER: Option = Some(OutputType::PushPull); + const AFR: Option = Some(A); +} diff --git a/src/gpio/dynamic.rs b/src/gpio/dynamic.rs new file mode 100644 index 00000000..fbd33177 --- /dev/null +++ b/src/gpio/dynamic.rs @@ -0,0 +1,154 @@ +use super::*; +use embedded_hal::digital::ErrorKind; + +/// 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(Clone, Copy, Debug, PartialEq, Eq)] +pub enum PinModeError { + /// For operations unsupported in current mode + IncorrectMode, +} + +impl embedded_hal::digital::Error for PinModeError { + fn kind(&self) -> ErrorKind { + ErrorKind::Other + } +} + +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 conversion 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) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_pull_up_input(); + self.mode = Dynamic::InputPullUp; + } + /// Switch pin into pull-down input + #[inline] + pub fn make_pull_down_input(&mut self) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_pull_down_input(); + self.mode = Dynamic::InputPullDown; + } + /// Switch pin into floating input + #[inline] + pub fn make_floating_input(&mut self) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_floating_input(); + self.mode = Dynamic::InputFloating; + } + /// Switch pin into push-pull output + #[inline] + pub fn make_push_pull_output(&mut self) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_push_pull_output(); + 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, state: PinState) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_push_pull_output_in_state(state); + self.mode = Dynamic::OutputPushPull; + } + /// Switch pin into open-drain output + #[inline] + pub fn make_open_drain_output(&mut self) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_open_drain_output(); + 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, state: PinState) { + // NOTE(unsafe), we have a mutable reference to the current pin + Pin::::new().into_open_drain_output_in_state(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 00000000..363d6d34 --- /dev/null +++ b/src/gpio/erased.rs @@ -0,0 +1,172 @@ +use super::*; + +pub use ErasedPin as AnyPin; + +/// 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, + } + } + + /// Convert type erased pin to `Pin` with fixed type + pub fn restore(self) -> Pin { + assert_eq!(self.port_id(), P as u8 - b'A'); + assert_eq!(self.pin_id(), N); + Pin::new() + } + + #[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: 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 00000000..c63e93cb --- /dev/null +++ b/src/gpio/exti.rs @@ -0,0 +1,116 @@ +use super::{marker, Pin, PinExt, SignalEdge}; +use crate::exti::{Event, ExtiExt}; +use crate::pac::EXTI; +use crate::syscfg::SysCfg; + +/// External Interrupt Pin +pub trait ExtiPin { + /// Make corresponding EXTI line sensitive to this pin + fn make_interrupt_source(&mut self, syscfg: &mut SysCfg); + + /// Generate interrupt on rising edge, falling edge or both + fn trigger_on_edge(&mut self, exti: &mut EXTI, level: SignalEdge); + + /// Enable external interrupts from this pin. + fn enable_interrupt(&mut self, exti: &mut EXTI); + + /// Disable external interrupts from this pin + fn disable_interrupt(&mut self, exti: &mut EXTI); + + /// Clear the interrupt pending bit for this pin + fn clear_interrupt_pending_bit(&mut self); + + /// Reads the interrupt pending bit for this pin + fn check_interrupt(&self) -> bool; +} + +impl Pin { + /// Configures the pin as external trigger + pub fn listen(self, edge: SignalEdge, exti: &mut EXTI) -> Self { + exti.listen(Event::from_code(self.pin_id()), edge); + self + } +} + +impl ExtiPin for PIN +where + PIN: PinExt, + PIN::Mode: marker::Interruptible, +{ + #[inline(always)] + fn make_interrupt_source(&mut self, syscfg: &mut SysCfg) { + let i = self.pin_id(); + let port = self.port_id() as u32; + let offset = 4 * (i % 4); + match i { + 0..=3 => { + syscfg.exticr1().modify(|r, w| unsafe { + w.bits((r.bits() & !(0xf << offset)) | (port << offset)) + }); + } + 4..=7 => { + syscfg.exticr2().modify(|r, w| unsafe { + w.bits((r.bits() & !(0xf << offset)) | (port << offset)) + }); + } + 8..=11 => { + syscfg.exticr3().modify(|r, w| unsafe { + w.bits((r.bits() & !(0xf << offset)) | (port << offset)) + }); + } + 12..=15 => { + syscfg.exticr4().modify(|r, w| unsafe { + w.bits((r.bits() & !(0xf << offset)) | (port << offset)) + }); + } + _ => unreachable!(), + } + } + + #[inline(always)] + fn trigger_on_edge(&mut self, exti: &mut EXTI, edge: SignalEdge) { + let i = self.pin_id(); + match edge { + SignalEdge::Rising => { + exti.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) }); + exti.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) }); + } + SignalEdge::Falling => { + exti.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) }); + exti.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << i)) }); + } + SignalEdge::RisingFalling => { + exti.rtsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) }); + exti.ftsr1() + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << i)) }); + } + } + } + + #[inline(always)] + fn enable_interrupt(&mut self, exti: &mut EXTI) { + exti.imr1() + .modify(|r, w| unsafe { w.bits(r.bits() | (1 << self.pin_id())) }); + } + + #[inline(always)] + fn disable_interrupt(&mut self, exti: &mut EXTI) { + exti.imr1() + .modify(|r, w| unsafe { w.bits(r.bits() & !(1 << self.pin_id())) }); + } + + #[inline(always)] + fn clear_interrupt_pending_bit(&mut self) { + unsafe { (*EXTI::ptr()).pr1().write(|w| w.bits(1 << self.pin_id())) }; + } + + #[inline(always)] + fn check_interrupt(&self) -> bool { + unsafe { ((*EXTI::ptr()).pr1().read().bits() & (1 << self.pin_id())) != 0 } + } +} diff --git a/src/gpio/g4.rs b/src/gpio/g4.rs new file mode 100644 index 00000000..235dbc90 --- /dev/null +++ b/src/gpio/g4.rs @@ -0,0 +1,369 @@ +use super::*; + +pub use super::Analog as DefaultMode; + +// auto-generated using codegen +// STM32CubeMX DB release: DB.6.0.130 + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 7, 8, 9, 10, 14, 15]), + PA1: (pa1, 1, [0, 1, 7, 9, 15]), + PA2: (pa2, 2, [1, 7, 8, 9, 12, 14, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 12, 13, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 13, 15]), + PA5: (pa5, 5, [1, 2, 5, 14, 15]), + PA6: (pa6, 6, [1, 2, 4, 5, 6, 8, 12, 15]), + PA7: (pa7, 7, [1, 2, 4, 5, 6, 8, 14, 15]), + PA8: (pa8, 8, [0, 2, 4, 5, 6, 7, 10, 12, 14, 15]), + PA9: (pa9, 9, [2, 4, 5, 6, 7, 9, 10, 14, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 10, 11, 12, 14, 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, 4, 5, 7, 10, 13, 15], super::Debugger), + PA14: (pa14, 14, [0, 1, 4, 5, 6, 7, 13, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 15], super::Debugger), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 4, 6, 14, 15]), + PB1: (pb1, 1, [2, 4, 6, 8, 12, 15]), + PB2: (pb2, 2, [0, 1, 4, 15]), + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 14, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 4, 5, 6, 7, 10, 14, 15], super::Debugger), + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 15]), + PB6: (pb6, 6, [1, 2, 5, 6, 7, 8, 10, 11, 14, 15]), + PB7: (pb7, 7, [1, 2, 4, 5, 7, 8, 10, 11, 14, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 7, 8, 9, 10, 12, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 14, 15]), + PB10: (pb10, 10, [1, 7, 8, 12, 14, 15]), + PB11: (pb11, 11, [1, 7, 8, 15]), + PB12: (pb12, 12, [4, 5, 6, 7, 8, 15]), + PB13: (pb13, 13, [5, 6, 7, 8, 15]), + PB14: (pb14, 14, [1, 5, 6, 7, 8, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 15]), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2, 8, 15]), + PC1: (pc1, 1, [1, 2, 8, 13, 15]), + PC2: (pc2, 2, [1, 2, 3, 15]), + PC3: (pc3, 3, [1, 2, 3, 6, 13, 15]), + PC4: (pc4, 4, [2, 4, 7, 15]), + PC5: (pc5, 5, [2, 3, 6, 7, 15]), + PC6: (pc6, 6, [2, 4, 6, 15]), + PC7: (pc7, 7, [2, 4, 6, 15]), + PC8: (pc8, 8, [2, 4, 8, 15]), + PC9: (pc9, 9, [2, 4, 5, 6, 8, 15]), + PC10: (pc10, 10, [4, 5, 6, 7, 15]), + PC11: (pc11, 11, [4, 5, 6, 7, 8, 15]), + PC12: (pc12, 12, [4, 6, 7, 14, 15]), + PC13: (pc13, 13, [2, 4, 6, 15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [6, 9, 15]), + PD1: (pd1, 1, [4, 6, 9, 15]), + PD2: (pd2, 2, [2, 4, 15]), + PD3: (pd3, 3, [2, 7, 15]), + PD4: (pd4, 4, [2, 7, 15]), + PD5: (pd5, 5, [7, 15]), + PD6: (pd6, 6, [2, 3, 7, 13, 15]), + PD7: (pd7, 7, [2, 7, 15]), + PD8: (pd8, 8, [7, 15]), + PD9: (pd9, 9, [7, 15]), + PD10: (pd10, 10, [7, 15]), + PD11: (pd11, 11, [7, 15]), + PD12: (pd12, 12, [2, 7, 15]), + PD13: (pd13, 13, [2, 15]), + PD14: (pd14, 14, [2, 15]), + PD15: (pd15, 15, [2, 6, 15]), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [2, 4, 7, 15]), + PE1: (pe1, 1, [4, 7, 15]), + PE2: (pe2, 2, [0, 2, 3, 13, 15]), + PE3: (pe3, 3, [0, 2, 13, 15]), + PE4: (pe4, 4, [0, 2, 3, 13, 15]), + PE5: (pe5, 5, [0, 2, 3, 13, 15]), + PE6: (pe6, 6, [0, 3, 13, 15]), + PE7: (pe7, 7, [2, 13, 15]), + PE8: (pe8, 8, [2, 13, 15]), + PE9: (pe9, 9, [2, 13, 15]), + PE10: (pe10, 10, [2, 13, 15]), + PE11: (pe11, 11, [2, 15]), + PE12: (pe12, 12, [2, 15]), + PE13: (pe13, 13, [2, 15]), + PE14: (pe14, 14, [2, 6, 15]), + PE15: (pe15, 15, [2, 6, 7, 15]), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 5, 6, 15]), + PF1: (pf1, 1, [5, 15]), + PF2: (pf2, 2, [4, 15]), + PF9: (pf9, 9, [3, 5, 13, 15]), + PF10: (pf10, 10, [3, 5, 13, 15]), +]); + +#[cfg(feature = "gpio-g43x")] +gpio!(GPIOG, gpiog, PG, 'G', PGn, [ + PG10: (pg10, 10, [0, 15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 2, 7, 8, 9, 10, 14, 15]), + PA1: (pa1, 1, [0, 1, 2, 7, 9, 15]), + PA2: (pa2, 2, [1, 2, 7, 8, 9, 10, 12, 14, 15]), + PA3: (pa3, 3, [1, 2, 3, 7, 9, 10, 12, 13, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 13, 15]), + PA5: (pa5, 5, [1, 2, 5, 14, 15]), + PA6: (pa6, 6, [1, 2, 4, 5, 6, 8, 10, 12, 15]), + PA7: (pa7, 7, [1, 2, 4, 5, 6, 8, 10, 14, 15]), + PA8: (pa8, 8, [0, 2, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15]), + PA9: (pa9, 9, [2, 4, 5, 6, 7, 8, 9, 10, 13, 14, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15]), + PA11: (pa11, 11, [5, 6, 7, 8, 9, 10, 11, 12, 13, 15]), + PA12: (pa12, 12, [1, 5, 6, 7, 8, 9, 10, 11, 13, 15]), + PA13: (pa13, 13, [0, 1, 3, 4, 5, 7, 10, 13, 15], super::Debugger), + PA14: (pa14, 14, [0, 1, 3, 4, 5, 6, 7, 13, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 4, 5, 6, 7, 8, 9, 11, 13, 14, 15], super::Debugger), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 4, 6, 10, 13, 14, 15]), + PB1: (pb1, 1, [2, 4, 6, 8, 10, 12, 13, 15]), + PB2: (pb2, 2, [0, 1, 2, 3, 4, 10, 13, 15]), + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 11, 12, 13, 14, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 4, 5, 6, 7, 8, 10, 11, 13, 14, 15], super::Debugger), + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB6: (pb6, 6, [1, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]), + PB7: (pb7, 7, [1, 2, 3, 4, 5, 7, 8, 10, 11, 12, 13, 14, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 7, 8, 9, 10, 12, 13, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 13, 14, 15]), + PB10: (pb10, 10, [1, 7, 8, 10, 12, 13, 14, 15]), + PB11: (pb11, 11, [1, 7, 8, 10, 13, 15]), + PB12: (pb12, 12, [2, 4, 5, 6, 7, 8, 9, 13, 15]), + PB13: (pb13, 13, [5, 6, 7, 8, 9, 13, 15]), + PB14: (pb14, 14, [1, 5, 6, 7, 8, 13, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 13, 15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2, 8, 15]), + PC1: (pc1, 1, [1, 2, 8, 10, 13, 15]), + PC2: (pc2, 2, [1, 2, 3, 6, 10, 15]), + PC3: (pc3, 3, [0, 1, 2, 3, 6, 10, 13, 15]), + PC4: (pc4, 4, [2, 4, 7, 10, 15]), + PC5: (pc5, 5, [2, 3, 6, 7, 13, 15]), + PC6: (pc6, 6, [2, 3, 4, 6, 7, 8, 13, 15]), + PC7: (pc7, 7, [2, 3, 4, 6, 7, 8, 13, 15]), + PC8: (pc8, 8, [2, 3, 4, 6, 7, 8, 15]), + PC9: (pc9, 9, [2, 3, 4, 5, 6, 8, 15]), + PC10: (pc10, 10, [4, 5, 6, 7, 13, 15]), + PC11: (pc11, 11, [3, 4, 5, 6, 7, 8, 15]), + PC12: (pc12, 12, [1, 3, 4, 5, 6, 7, 14, 15]), + PC13: (pc13, 13, [2, 4, 6, 15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [6, 9, 12, 15]), + PD1: (pd1, 1, [4, 6, 9, 12, 15]), + PD2: (pd2, 2, [2, 4, 5, 15]), + PD3: (pd3, 3, [2, 7, 10, 12, 15]), + PD4: (pd4, 4, [2, 7, 10, 12, 15]), + PD5: (pd5, 5, [7, 10, 12, 15]), + PD6: (pd6, 6, [2, 3, 7, 10, 12, 13, 15]), + PD7: (pd7, 7, [2, 7, 10, 12, 15]), + PD8: (pd8, 8, [7, 12, 15]), + PD9: (pd9, 9, [7, 12, 15]), + PD10: (pd10, 10, [7, 12, 15]), + PD11: (pd11, 11, [1, 4, 7, 12, 15]), + PD12: (pd12, 12, [2, 7, 12, 15]), + PD13: (pd13, 13, [2, 12, 15]), + PD14: (pd14, 14, [2, 12, 15]), + PD15: (pd15, 15, [2, 6, 12, 15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [2, 3, 4, 6, 7, 12, 15]), + PE1: (pe1, 1, [4, 6, 7, 12, 15]), + PE2: (pe2, 2, [0, 2, 3, 5, 6, 12, 13, 15]), + PE3: (pe3, 3, [0, 2, 5, 6, 12, 13, 15]), + PE4: (pe4, 4, [0, 2, 3, 5, 6, 12, 13, 15]), + PE5: (pe5, 5, [0, 2, 3, 5, 6, 12, 13, 15]), + PE6: (pe6, 6, [0, 3, 5, 6, 12, 13, 15]), + PE7: (pe7, 7, [2, 12, 13, 15]), + PE8: (pe8, 8, [1, 2, 12, 13, 15]), + PE9: (pe9, 9, [1, 2, 12, 13, 15]), + PE10: (pe10, 10, [2, 10, 12, 13, 15]), + PE11: (pe11, 11, [2, 5, 10, 12, 15]), + PE12: (pe12, 12, [2, 5, 10, 12, 15]), + PE13: (pe13, 13, [2, 5, 10, 12, 15]), + PE14: (pe14, 14, [2, 5, 6, 10, 12, 15]), + PE15: (pe15, 15, [2, 6, 7, 10, 12, 15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 5, 6, 15]), + PF1: (pf1, 1, [5, 15]), + PF2: (pf2, 2, [2, 4, 12, 15]), + PF3: (pf3, 3, [2, 4, 12, 15]), + PF4: (pf4, 4, [2, 3, 4, 12, 15]), + PF5: (pf5, 5, [2, 12, 15]), + PF6: (pf6, 6, [1, 2, 3, 4, 6, 7, 10, 15]), + PF7: (pf7, 7, [2, 6, 10, 12, 13, 15]), + PF8: (pf8, 8, [2, 6, 10, 12, 13, 15]), + PF9: (pf9, 9, [2, 3, 5, 6, 10, 12, 13, 15]), + PF10: (pf10, 10, [2, 3, 5, 10, 12, 13, 15]), + PF11: (pf11, 11, [2, 12, 15]), + PF12: (pf12, 12, [2, 12, 15]), + PF13: (pf13, 13, [2, 4, 12, 15]), + PF14: (pf14, 14, [2, 4, 12, 15]), + PF15: (pf15, 15, [2, 4, 12, 15]), +]); + +#[cfg(feature = "gpio-g47x")] +gpio!(GPIOG, gpiog, PG, 'G', PGn, [ + PG0: (pg0, 0, [2, 12, 15]), + PG1: (pg1, 1, [2, 12, 15]), + PG2: (pg2, 2, [2, 5, 12, 15]), + PG3: (pg3, 3, [2, 4, 5, 6, 12, 15]), + PG4: (pg4, 4, [2, 4, 5, 12, 15]), + PG5: (pg5, 5, [2, 5, 8, 12, 15]), + PG6: (pg6, 6, [2, 4, 8, 12, 15]), + PG7: (pg7, 7, [3, 4, 8, 12, 13, 15]), + PG8: (pg8, 8, [4, 8, 12, 15]), + PG9: (pg9, 9, [6, 7, 12, 14, 15]), + PG10: (pg10, 10, [0, 15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOA, gpioa, PA, 'A', PAn, [ + PA0: (pa0, 0, [1, 7, 8, 9, 10, 14, 15]), + PA1: (pa1, 1, [0, 1, 7, 9, 15]), + PA2: (pa2, 2, [1, 7, 8, 9, 10, 12, 14, 15]), + PA3: (pa3, 3, [1, 3, 7, 9, 10, 12, 13, 15]), + PA4: (pa4, 4, [2, 5, 6, 7, 13, 15]), + PA5: (pa5, 5, [1, 2, 5, 14, 15]), + PA6: (pa6, 6, [1, 2, 4, 5, 6, 8, 10, 12, 15]), + PA7: (pa7, 7, [1, 2, 4, 5, 6, 8, 10, 14, 15]), + PA8: (pa8, 8, [0, 2, 4, 5, 6, 7, 10, 12, 14, 15]), + PA9: (pa9, 9, [2, 4, 5, 6, 7, 9, 10, 14, 15]), + PA10: (pa10, 10, [1, 3, 4, 5, 6, 7, 10, 11, 12, 14, 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, 4, 5, 7, 10, 13, 15], super::Debugger), + PA14: (pa14, 14, [0, 1, 4, 5, 6, 7, 13, 15], super::Debugger), + PA15: (pa15, 15, [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 14, 15], super::Debugger), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOB, gpiob, PB, 'B', PBn, [ + PB0: (pb0, 0, [2, 4, 6, 10, 14, 15]), + PB1: (pb1, 1, [2, 4, 6, 8, 10, 12, 15]), + PB2: (pb2, 2, [0, 1, 3, 4, 10, 15]), + PB3: (pb3, 3, [0, 1, 2, 3, 4, 5, 6, 7, 10, 14, 15], super::Debugger), + PB4: (pb4, 4, [0, 1, 2, 4, 5, 6, 7, 8, 10, 14, 15], super::Debugger), + PB5: (pb5, 5, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 15]), + PB6: (pb6, 6, [1, 2, 5, 6, 7, 8, 9, 10, 11, 14, 15]), + PB7: (pb7, 7, [1, 2, 4, 5, 7, 8, 10, 11, 14, 15]), + PB8: (pb8, 8, [1, 2, 3, 4, 7, 8, 9, 10, 12, 14, 15]), + PB9: (pb9, 9, [1, 2, 3, 4, 6, 7, 8, 9, 10, 12, 14, 15]), + PB10: (pb10, 10, [1, 7, 8, 10, 12, 14, 15]), + PB11: (pb11, 11, [1, 7, 8, 10, 15]), + PB12: (pb12, 12, [4, 5, 6, 7, 8, 9, 15]), + PB13: (pb13, 13, [5, 6, 7, 8, 9, 15]), + PB14: (pb14, 14, [1, 5, 6, 7, 8, 15]), + PB15: (pb15, 15, [0, 1, 2, 3, 4, 5, 15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOC, gpioc, PC, 'C', PCn, [ + PC0: (pc0, 0, [1, 2, 8, 15]), + PC1: (pc1, 1, [1, 2, 8, 10, 13, 15]), + PC2: (pc2, 2, [1, 2, 3, 6, 10, 15]), + PC3: (pc3, 3, [1, 2, 3, 6, 10, 13, 15]), + PC4: (pc4, 4, [2, 4, 7, 10, 15]), + PC5: (pc5, 5, [2, 3, 6, 7, 15]), + PC6: (pc6, 6, [2, 4, 6, 15]), + PC7: (pc7, 7, [2, 4, 6, 15]), + PC8: (pc8, 8, [2, 4, 6, 8, 15]), + PC9: (pc9, 9, [2, 4, 5, 6, 8, 15]), + PC10: (pc10, 10, [4, 5, 6, 7, 15]), + PC11: (pc11, 11, [4, 5, 6, 7, 8, 15]), + PC12: (pc12, 12, [4, 5, 6, 7, 14, 15]), + PC13: (pc13, 13, [2, 4, 6, 15]), + PC14: (pc14, 14, [15]), + PC15: (pc15, 15, [15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOD, gpiod, PD, 'D', PDn, [ + PD0: (pd0, 0, [6, 9, 15]), + PD1: (pd1, 1, [4, 6, 9, 15]), + PD2: (pd2, 2, [2, 4, 5, 15]), + PD3: (pd3, 3, [2, 7, 10, 15]), + PD4: (pd4, 4, [2, 7, 10, 15]), + PD5: (pd5, 5, [7, 10, 15]), + PD6: (pd6, 6, [2, 3, 7, 10, 13, 15]), + PD7: (pd7, 7, [2, 7, 10, 15]), + PD8: (pd8, 8, [7, 15]), + PD9: (pd9, 9, [7, 15]), + PD10: (pd10, 10, [7, 15]), + PD11: (pd11, 11, [7, 15]), + PD12: (pd12, 12, [2, 7, 15]), + PD13: (pd13, 13, [2, 15]), + PD14: (pd14, 14, [2, 15]), + PD15: (pd15, 15, [2, 6, 15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOE, gpioe, PE, 'E', PEn, [ + PE0: (pe0, 0, [2, 3, 4, 6, 7, 15]), + PE1: (pe1, 1, [4, 6, 7, 15]), + PE2: (pe2, 2, [0, 2, 3, 6, 13, 15]), + PE3: (pe3, 3, [0, 2, 6, 13, 15]), + PE4: (pe4, 4, [0, 2, 3, 6, 13, 15]), + PE5: (pe5, 5, [0, 2, 3, 6, 13, 15]), + PE6: (pe6, 6, [0, 3, 6, 13, 15]), + PE7: (pe7, 7, [2, 13, 15]), + PE8: (pe8, 8, [2, 13, 15]), + PE9: (pe9, 9, [2, 13, 15]), + PE10: (pe10, 10, [2, 10, 13, 15]), + PE11: (pe11, 11, [2, 10, 15]), + PE12: (pe12, 12, [2, 10, 15]), + PE13: (pe13, 13, [2, 10, 15]), + PE14: (pe14, 14, [2, 6, 10, 15]), + PE15: (pe15, 15, [2, 6, 7, 10, 15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOF, gpiof, PF, 'F', PFn, [ + PF0: (pf0, 0, [4, 5, 6, 15]), + PF1: (pf1, 1, [5, 15]), + PF2: (pf2, 2, [2, 4, 15]), + PF9: (pf9, 9, [2, 3, 5, 10, 13, 15]), + PF10: (pf10, 10, [2, 3, 5, 10, 13, 15]), +]); + +#[cfg(feature = "gpio-g49x")] +gpio!(GPIOG, gpiog, PG, 'G', PGn, [ + PG10: (pg10, 10, [0, 15]), +]); diff --git a/src/gpio/hal_02.rs b/src/gpio/hal_02.rs new file mode 100644 index 00000000..25026fa5 --- /dev/null +++ b/src/gpio/hal_02.rs @@ -0,0 +1,242 @@ +use core::convert::Infallible; + +use super::{ + dynamic::PinModeError, marker, DynamicPin, ErasedPin, Input, OpenDrain, Output, + PartiallyErasedPin, Pin, PinMode, PinState, +}; + +use embedded_hal_old::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: 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: 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: 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/hal_1.rs b/src/gpio/hal_1.rs new file mode 100644 index 00000000..11db87cb --- /dev/null +++ b/src/gpio/hal_1.rs @@ -0,0 +1,168 @@ +use core::convert::Infallible; + +use super::{ + dynamic::PinModeError, marker, DynamicPin, ErasedPin, Output, PartiallyErasedPin, Pin, +}; + +use embedded_hal::digital::{ErrorType, InputPin, OutputPin, StatefulOutputPin}; + +// Implementations for `Pin` +impl ErrorType for Pin { + type Error = Infallible; +} + +impl OutputPin for Pin> { + #[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(&mut self) -> Result { + Ok(Self::is_set_high(self)) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(Self::is_set_low(self)) + } +} + +impl InputPin for Pin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(Self::is_high(self)) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(Self::is_low(self)) + } +} + +// Implementations for `ErasedPin` +impl ErrorType for ErasedPin { + type Error = core::convert::Infallible; +} + +impl OutputPin for ErasedPin> { + #[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(&mut self) -> Result { + Ok(Self::is_set_high(self)) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(Self::is_set_low(self)) + } +} + +impl InputPin for ErasedPin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(Self::is_high(self)) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(Self::is_low(self)) + } +} + +// Implementations for `PartiallyErasedPin` +impl ErrorType for PartiallyErasedPin { + type Error = Infallible; +} + +impl OutputPin for PartiallyErasedPin> { + #[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(&mut self) -> Result { + Ok(Self::is_set_high(self)) + } + + #[inline(always)] + fn is_set_low(&mut self) -> Result { + Ok(Self::is_set_low(self)) + } +} + +impl InputPin for PartiallyErasedPin +where + MODE: marker::Readable, +{ + #[inline(always)] + fn is_high(&mut self) -> Result { + Ok(Self::is_high(self)) + } + + #[inline(always)] + fn is_low(&mut self) -> Result { + Ok(Self::is_low(self)) + } +} + +// Implementations for `DynamicPin +impl ErrorType for DynamicPin { + type Error = PinModeError; +} + +impl OutputPin for DynamicPin { + 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 { + fn is_high(&mut self) -> Result { + Self::is_high(self) + } + fn is_low(&mut self) -> Result { + Self::is_low(self) + } +} diff --git a/src/gpio/outport.rs b/src/gpio/outport.rs new file mode 100644 index 00000000..7373b0db --- /dev/null +++ b/src/gpio/outport.rs @@ -0,0 +1,108 @@ +use super::*; + +/// Convert tuple or array of pins to output port +pub trait OutPort { + type Target; + fn outport(self) -> Self::Target; +} + +macro_rules! out_port { + ( $name:ident => $n:literal, ( $($i:tt),+ ), ( $($N:ident),+ )) => { + pub struct $name ( + $(pub Pin>,)+ + ); + + impl OutPort for ($(Pin>),+) { + type Target = $name

; + fn outport(self) -> Self::Target { + $name($(self.$i),+) + } + } + + /// Wrapper for tuple of `Pin`s + impl $name

{ + const fn mask() -> u32 { + 0 $( | (1 << { $N }))+ + } + const fn value_for_write_bsrr(val: u32) -> u32 { + 0 $( | (1 << (if val & (1 << $i) != 0 { $N } else { $N + 16 })))+ + } + + #[doc=concat!("Set/reset pins according to `", $n, "` lower bits")] + #[inline(never)] + pub fn write(&mut self, word: u32) { + unsafe { (*gpiox::

()).bsrr().write(|w| w.bits(Self::value_for_write_bsrr(word))); } + } + + /// Set all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { (*gpiox::

()).bsrr().write(|w| w.bits(Self::mask())); } + } + + /// Reset all pins to `PinState::Low` + pub fn all_low(&mut self) { + unsafe { (*gpiox::

()).bsrr().write(|w| w.bits(Self::mask() << 16)); } + } + } + } +} + +out_port!(OutPort2 => 2, (0, 1), (N0, N1)); +out_port!(OutPort3 => 3, (0, 1, 2), (N0, N1, N2)); +out_port!(OutPort4 => 4, (0, 1, 2, 3), (N0, N1, N2, N3)); +out_port!(OutPort5 => 5, (0, 1, 2, 3, 4), (N0, N1, N2, N3, N4)); +out_port!(OutPort6 => 6, (0, 1, 2, 3, 4, 5), (N0, N1, N2, N3, N4, N5)); +out_port!(OutPort7 => 7, (0, 1, 2, 3, 4, 5, 6), (N0, N1, N2, N3, N4, N5, N6)); +out_port!(OutPort8 => 8, (0, 1, 2, 3, 4, 5, 6, 7), (N0, N1, N2, N3, N4, N5, N6, N7)); + +/// Wrapper for array of `PartiallyErasedPin`s +pub struct OutPortArray(pub [PEPin>; SIZE]); + +impl OutPort for [PEPin>; SIZE] { + type Target = OutPortArray; + fn outport(self) -> Self::Target { + OutPortArray(self) + } +} + +impl OutPortArray { + fn mask(&self) -> u32 { + let mut msk = 0; + for pin in self.0.iter() { + msk |= 1 << pin.i; + } + msk + } + fn value_for_write_bsrr(&self, val: u32) -> u32 { + let mut msk = 0; + for (idx, pin) in self.0.iter().enumerate() { + let n = pin.i; + msk |= 1 << (if val & (1 << idx) != 0 { n } else { n + 16 }); + } + msk + } + + /// Set/reset pins according to `SIZE` lower bits + #[inline(never)] + pub fn write(&mut self, word: u32) { + unsafe { + (*gpiox::

()) + .bsrr() + .write(|w| w.bits(self.value_for_write_bsrr(word))); + } + } + + /// Set all pins to `PinState::High` + pub fn all_high(&mut self) { + unsafe { + (*gpiox::

()).bsrr().write(|w| w.bits(self.mask())); + } + } + + /// Reset all pins to `PinState::Low` + pub fn all_low(&mut self) { + unsafe { + (*gpiox::

()).bsrr().write(|w| w.bits(self.mask() << 16)); + } + } +} diff --git a/src/gpio/partially_erased.rs b/src/gpio/partially_erased.rs new file mode 100644 index 00000000..812ea2c0 --- /dev/null +++ b/src/gpio/partially_erased.rs @@ -0,0 +1,153 @@ +use super::*; + +pub use PartiallyErasedPin as PEPin; + +/// 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, + } + } + + /// Convert partially type erased pin to `Pin` with fixed type + pub fn restore(self) -> Pin { + assert_eq!(self.i, N); + Pin::new() + } +} + +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 { + (*gpiox::

()).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 { + (*gpiox::

()).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 { (*gpiox::

()).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: 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 { (*gpiox::

()).idr().read().bits() & (1 << self.i) == 0 } + } +} + +impl From> for ErasedPin { + /// Partially erased pin-to-erased pin conversion using the [`From`] trait. + /// + /// Note that [`From`] is the reciprocal of [`Into`]. + fn from(p: PartiallyErasedPin) -> Self { + ErasedPin::new(P as u8 - b'A', p.i) + } +} diff --git a/src/i2c.rs b/src/i2c.rs index 6567d08d..61514926 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -3,29 +3,15 @@ use crate::stm32::i2c1; use embedded_hal::i2c::{ErrorKind, Operation, SevenBitAddress, TenBitAddress}; use embedded_hal_old::blocking::i2c::{Read, Write, WriteRead}; -use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiof::*}; -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] -use crate::gpio::{gpiog::*, AF3}; -use crate::gpio::{AlternateOD, AF2, AF4, AF8}; -use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] +use crate::gpio::alt::I2cCommon; +use crate::rcc::Rcc; +#[cfg(feature = "i2c4")] use crate::stm32::I2C4; use crate::stm32::{I2C1, I2C2, I2C3, RCC}; use crate::time::Hertz; use core::cmp; use core::convert::TryInto; +use core::ops::Deref; /// I2C bus configuration. #[derive(Debug, Clone, Copy)] @@ -39,12 +25,9 @@ pub struct Config { impl Config { /// Creates a default configuration for the given bus frequency. - pub fn new(speed: T) -> Self - where - T: Into, - { + pub fn new(speed: Hertz) -> Self { Config { - speed: Some(speed.into()), + speed: Some(speed), timing: None, analog_filter: true, digital_filter: 0, @@ -108,31 +91,37 @@ impl Config { (psc, scll, sclh, sdadel, scldel) }; - reg.presc() - .set(psc.try_into().unwrap()) - .scldel() - .set(scldel) - .sdadel() - .set(sdadel) - .sclh() - .set(sclh.try_into().unwrap()) - .scll() - .set(scll.try_into().unwrap()) + reg.presc().set(psc.try_into().unwrap()); + reg.scldel().set(scldel); + reg.sdadel().set(sdadel); + reg.sclh().set(sclh.try_into().unwrap()); + reg.scll().set(scll.try_into().unwrap()) } } -/// I2C abstraction -pub struct I2c { - i2c: I2C, - sda: SDA, - scl: SCL, +impl From for Config { + fn from(value: Hertz) -> Self { + Self::new(value) + } +} + +pub trait Instance: + crate::Sealed + crate::rcc::Instance + I2cCommon + Deref +{ } -/// I2C SDA pin -pub trait SDAPin {} +impl Instance for I2C1 {} +impl Instance for I2C2 {} +impl Instance for I2C3 {} +#[cfg(feature = "i2c4")] +impl Instance for I2C4 {} -/// I2C SCL pin -pub trait SCLPin {} +/// I2C abstraction +pub struct I2c { + i2c: I2C, + sda: I2C::Sda, + scl: I2C::Scl, +} /// I2C error #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -158,11 +147,26 @@ impl embedded_hal::i2c::Error for Error { } } -pub trait I2cExt { - fn i2c(self, sda: SDA, scl: SCL, config: Config, rcc: &mut Rcc) -> I2c - where - SDA: SDAPin, - SCL: SCLPin; +pub trait I2cExt: Instance + Sized { + fn i2c( + self, + sda: impl Into, + scl: impl Into, + config: impl Into, + rcc: &mut Rcc, + ) -> I2c; +} + +impl I2cExt for I2C { + fn i2c( + self, + sda: impl Into, + scl: impl Into, + config: impl Into, + rcc: &mut Rcc, + ) -> I2c { + I2c::new(self, sda, scl, config, rcc) + } } /// Sequence to flush the TXDR register. This resets the TXIS and TXE flags @@ -206,363 +210,232 @@ macro_rules! busy_wait { }; } -macro_rules! i2c { - ($I2CX:ident, $i2cx:ident, - sda: [ $($( #[ $pmetasda:meta ] )* $PSDA:ty,)+ ], - scl: [ $($( #[ $pmetascl:meta ] )* $PSCL:ty,)+ ], - ) => { - $( - $( #[ $pmetasda ] )* - impl SDAPin<$I2CX> for $PSDA {} - )+ - - $( - $( #[ $pmetascl ] )* - impl SCLPin<$I2CX> for $PSCL {} - )+ - - impl I2cExt<$I2CX> for $I2CX { - fn i2c( - self, - sda: SDA, - scl: SCL, - config: Config, - rcc: &mut Rcc, - ) -> I2c<$I2CX, SDA, SCL> - where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX>, - { - I2c::$i2cx(self, sda, scl, config, rcc) - } +impl I2c { + /// Initializes the I2C peripheral. + pub fn new( + i2c: I2C, + sda: impl Into, + scl: impl Into, + config: impl Into, + rcc: &mut Rcc, + ) -> Self { + let config = config.into(); + // Enable and reset I2C + unsafe { + let rcc_ptr = &(*RCC::ptr()); + I2C::enable(rcc_ptr); + I2C::reset(rcc_ptr); } - impl I2c<$I2CX, SDA, SCL> where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX> - { - /// Initializes the I2C peripheral. - pub fn $i2cx(i2c: $I2CX, sda: SDA, scl: SCL, config: Config, rcc: &mut Rcc) -> Self - where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX>, - { - // Enable and reset I2C - unsafe { - let rcc_ptr = &(*RCC::ptr()); - $I2CX::enable(rcc_ptr); - $I2CX::reset(rcc_ptr); - } + // Make sure the I2C unit is disabled so we can configure it + i2c.cr1().modify(|_, w| w.pe().clear_bit()); - // Make sure the I2C unit is disabled so we can configure it - i2c.cr1().modify(|_, w| w.pe().clear_bit()); + // Setup protocol timings + i2c.timingr() + .write(|w| config.timing_bits(I2C::get_frequency(&rcc.clocks), w)); - // Setup protocol timings - i2c.timingr().write(|w| config.timing_bits(<$I2CX as RccBus>::Bus::get_frequency(&rcc.clocks), w)); + // Enable the I2C processing + i2c.cr1().modify(|_, w| { + w.pe().set_bit(); + w.dnf().set(config.digital_filter); + w.anfoff().bit(!config.analog_filter) + }); - // Enable the I2C processing - i2c.cr1().modify(|_, w| { - w.pe() - .set_bit() - .dnf() - .set(config.digital_filter) - .anfoff() - .bit(!config.analog_filter) - }); + I2c { + i2c, + sda: sda.into(), + scl: scl.into(), + } + } - I2c { i2c, sda, scl } - } + /// Disables I2C and releases the peripheral as well as the pins. + pub fn release(self) -> (I2C, I2C::Sda, I2C::Scl) { + // Disable I2C. + unsafe { + let rcc_ptr = &(*RCC::ptr()); + I2C::reset(rcc_ptr); + I2C::disable(rcc_ptr); + } + + (self.i2c, self.sda, self.scl) + } +} - /// Disables I2C and releases the peripheral as well as the pins. - pub fn release(self) -> ($I2CX, SDA, SCL) { - // Disable I2C. - unsafe { - let rcc_ptr = &(*RCC::ptr()); - $I2CX::reset(rcc_ptr); - $I2CX::disable(rcc_ptr); +impl I2c { + // copied from f3 hal + fn read_inner( + &mut self, + mut addr: u16, + addr_10b: bool, + buffer: &mut [u8], + ) -> Result<(), Error> { + if !addr_10b { + addr <<= 1 + }; + let end = buffer.len() / 0xFF; + + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2().modify(|_, w| { + if i == 0 { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().read(); + w.start().start(); + } + w.nbytes().set(buffer.len() as u8); + if i == end { + w.reload().completed().autoend().automatic() + } else { + w.reload().not_completed() } + }); - (self.i2c, self.sda, self.scl) + for byte in buffer { + // Wait until we have received something + busy_wait!(self.i2c, rxne, is_not_empty); + *byte = self.i2c.rxdr().read().rxdata().bits(); } - } - - impl I2c<$I2CX, SDA, SCL> { - // copied from f3 hal - fn read_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &mut [u8]) -> Result<(), Error> { - if !addr_10b { addr <<= 1 }; - let end = buffer.len() / 0xFF; - - // Process 255 bytes at a time - for (i, buffer) in buffer.chunks_mut(0xFF).enumerate() { - // Prepare to receive `bytes` - self.i2c.cr2().modify(|_, w| { - if i == 0 { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().read(); - w.start().start(); - } - w.nbytes().set(buffer.len() as u8); - if i == end { - w.reload().completed().autoend().automatic() - } else { - w.reload().not_completed() - } - }); - - for byte in buffer { - // Wait until we have received something - busy_wait!(self.i2c, rxne, is_not_empty); - *byte = self.i2c.rxdr().read().rxdata().bits(); - } - - if i != end { - // Wait until the last transmission is finished - busy_wait!(self.i2c, tcr, is_complete); - } - } + if i != end { // Wait until the last transmission is finished - // auto stop is set - busy_wait!(self.i2c, stopf, is_stop); - self.i2c.icr().write(|w| w.stopcf().clear()); - - Ok(()) + busy_wait!(self.i2c, tcr, is_complete); } + } - fn write_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &[u8]) -> Result<(), Error> { - if !addr_10b { addr <<= 1 }; - let end = buffer.len() / 0xFF; - - if buffer.is_empty() { - // 0 byte write - self.i2c.cr2().modify(|_, w| { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().write(); - w.nbytes().set(0); - w.reload().completed(); - w.autoend().automatic(); - w.start().start() - }); - return Ok(()) + // Wait until the last transmission is finished + // auto stop is set + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); + + Ok(()) + } + + fn write_inner(&mut self, mut addr: u16, addr_10b: bool, buffer: &[u8]) -> Result<(), Error> { + if !addr_10b { + addr <<= 1 + }; + let end = buffer.len() / 0xFF; + + if buffer.is_empty() { + // 0 byte write + self.i2c.cr2().modify(|_, w| { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().write(); + w.nbytes().set(0); + w.reload().completed(); + w.autoend().automatic(); + w.start().start() + }); + return Ok(()); + } + // Process 255 bytes at a time + for (i, buffer) in buffer.chunks(0xFF).enumerate() { + // Prepare to receive `bytes` + self.i2c.cr2().modify(|_, w| { + if i == 0 { + w.add10().bit(addr_10b); + w.sadd().set(addr); + w.rd_wrn().write(); + w.start().start(); } - // Process 255 bytes at a time - for (i, buffer) in buffer.chunks(0xFF).enumerate() { - // Prepare to receive `bytes` - self.i2c.cr2().modify(|_, w| { - if i == 0 { - w.add10().bit(addr_10b); - w.sadd().set(addr); - w.rd_wrn().write(); - w.start().start(); - } - w.nbytes().set(buffer.len() as u8); - if i == end { - w.reload().completed().autoend().automatic() - } else { - w.reload().not_completed() - } - }); - - for byte in buffer { - // Wait until we are allowed to send data - // (START has been ACKed or last byte went through) - busy_wait!(self.i2c, txis, is_empty); - self.i2c.txdr().write(|w| w.txdata().set(*byte)); - } - - if i != end { - // Wait until the last transmission is finished - busy_wait!(self.i2c, tcr, is_complete); - } + w.nbytes().set(buffer.len() as u8); + if i == end { + w.reload().completed().autoend().automatic() + } else { + w.reload().not_completed() } + }); + + for byte in buffer { + // Wait until we are allowed to send data + // (START has been ACKed or last byte went through) + busy_wait!(self.i2c, txis, is_empty); + self.i2c.txdr().write(|w| w.txdata().set(*byte)); + } + if i != end { // Wait until the last transmission is finished - // auto stop is set - busy_wait!(self.i2c, stopf, is_stop); - self.i2c.icr().write(|w| w.stopcf().clear()); - Ok(()) + busy_wait!(self.i2c, tcr, is_complete); } } - impl embedded_hal::i2c::ErrorType for I2c<$I2CX, SDA, SCL> { - type Error = Error; - } + // Wait until the last transmission is finished + // auto stop is set + busy_wait!(self.i2c, stopf, is_stop); + self.i2c.icr().write(|w| w.stopcf().clear()); + Ok(()) + } +} - // TODO: custom read/write/read_write impl with hardware stop logic - impl embedded_hal::i2c::I2c for I2c<$I2CX, SDA, SCL> { - fn transaction( - &mut self, - address: SevenBitAddress, - operation: &mut [Operation<'_>] - ) -> Result<(), Self::Error> { - Ok(for op in operation { - // Wait for any operation on the bus to finish - // for example in the case of another bus master having claimed the bus - while self.i2c.isr().read().busy().bit_is_set() {}; - match op { - Operation::Read(data) => self.read_inner(address as u16, false, data)?, - Operation::Write(data) => self.write_inner(address as u16, false, data)?, - } - }) - } - } - impl embedded_hal::i2c::I2c for I2c<$I2CX, SDA, SCL> { - fn transaction( - &mut self, - address: TenBitAddress, - operation: &mut [Operation<'_>] - ) -> Result<(), Self::Error> { - Ok(for op in operation { - // Wait for any operation on the bus to finish - // for example in the case of another bus master having claimed the bus - while self.i2c.isr().read().busy().bit_is_set() {}; - match op { - Operation::Read(data) => self.read_inner(address, true, data)?, - Operation::Write(data) => self.write_inner(address, true, data)?, - } - }) +impl embedded_hal::i2c::ErrorType for I2c { + type Error = Error; +} + +// TODO: custom read/write/read_write impl with hardware stop logic +impl embedded_hal::i2c::I2c for I2c { + fn transaction( + &mut self, + address: SevenBitAddress, + operation: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operation { + // Wait for any operation on the bus to finish + // for example in the case of another bus master having claimed the bus + while self.i2c.isr().read().busy().bit_is_set() {} + match op { + Operation::Read(data) => self.read_inner(address as u16, false, data)?, + Operation::Write(data) => self.write_inner(address as u16, false, data)?, } } - - impl WriteRead for I2c<$I2CX, SDA, SCL> { - type Error = Error; - - fn write_read( - &mut self, - addr: u8, - bytes: &[u8], - buffer: &mut [u8], - ) -> Result<(), Self::Error> { - self.write_inner(addr as u16, false, bytes)?; - self.read_inner(addr as u16, false, buffer)?; - Ok(()) + Ok(()) + } +} +impl embedded_hal::i2c::I2c for I2c { + fn transaction( + &mut self, + address: TenBitAddress, + operation: &mut [Operation<'_>], + ) -> Result<(), Self::Error> { + for op in operation { + // Wait for any operation on the bus to finish + // for example in the case of another bus master having claimed the bus + while self.i2c.isr().read().busy().bit_is_set() {} + match op { + Operation::Read(data) => self.read_inner(address, true, data)?, + Operation::Write(data) => self.write_inner(address, true, data)?, } } + Ok(()) + } +} - impl Write for I2c<$I2CX, SDA, SCL> { - type Error = Error; +impl WriteRead for I2c { + type Error = Error; - fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { - self.write_inner(addr as u16, false, bytes)?; - Ok(()) - } - } + fn write_read(&mut self, addr: u8, bytes: &[u8], buffer: &mut [u8]) -> Result<(), Self::Error> { + self.write_inner(addr as u16, false, bytes)?; + self.read_inner(addr as u16, false, buffer)?; + Ok(()) + } +} - impl Read for I2c<$I2CX, SDA, SCL> { - type Error = Error; +impl Write for I2c { + type Error = Error; - fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { - self.read_inner(addr as u16, false, bytes)?; - Ok(()) - } - } + fn write(&mut self, addr: u8, bytes: &[u8]) -> Result<(), Self::Error> { + self.write_inner(addr as u16, false, bytes)?; + Ok(()) } } -i2c!( - I2C1, - i2c1, - sda: [ - PA14>, - PB7>, - PB9>, - ], - scl: [ - PA13>, - PA15>, - PB8>, - ], -); - -i2c!( - I2C2, - i2c2, - sda: [ - PA8>, - PF0>, - ], - scl: [ - PA9>, - PC4>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF6>, - ], -); - -i2c!( - I2C3, - i2c3, - sda: [ - PB5>, - PC11>, - PC9>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF4>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG8>, - ], - scl: [ - PA8>, - PC8>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF3>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG7>, - ], -); - -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] -i2c!( - I2C4, - i2c4, - sda: [ - PB7>, - PC7>, - PF15>, - PG4>, - ], - scl: [ - PA13>, - PC6>, - PF14>, - PG3>, - ], -); +impl Read for I2c { + type Error = Error; + + fn read(&mut self, addr: u8, bytes: &mut [u8]) -> Result<(), Self::Error> { + self.read_inner(addr as u16, false, bytes)?; + Ok(()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 0590f854..9310ebbc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -105,3 +105,9 @@ pub mod timer; pub mod independent_watchdog; #[cfg(feature = "usb")] pub mod usb; + +fn stripped_type_name() -> &'static str { + let s = core::any::type_name::(); + let p = s.split("::"); + p.last().unwrap() +} diff --git a/src/opamp.rs b/src/opamp.rs index 98cf644b..fb02a440 100644 --- a/src/opamp.rs +++ b/src/opamp.rs @@ -868,108 +868,108 @@ macro_rules! opamps { #[cfg(any(feature = "stm32g431", feature = "stm32g441"))] opamps! { Opamp1 => opamp1: { - vinm0: crate::gpio::gpioa::PA3, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA3, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA3: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA3: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA1: vinp0, - crate::gpio::gpioa::PA3: vinp1, - crate::gpio::gpioa::PA7: vinp2, + crate::gpio::PA1: vinp0, + crate::gpio::PA3: vinp1, + crate::gpio::PA7: vinp2, }, - output: crate::gpio::gpioa::PA2, + output: crate::gpio::PA2, }, Opamp2 => opamp2: { - vinm0: crate::gpio::gpioa::PA5, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA5, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA5: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA5: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA7: vinp0, - crate::gpio::gpiob::PB14: vinp1, - crate::gpio::gpiob::PB0: vinp2, - crate::gpio::gpiod::PD14: vinp3, + crate::gpio::PA7: vinp0, + crate::gpio::PB14: vinp1, + crate::gpio::PB0: vinp2, + crate::gpio::PD14: vinp3, }, - output: crate::gpio::gpioa::PA6, + output: crate::gpio::PA6, }, Opamp3 => opamp3: { - vinm0: crate::gpio::gpiob::PB2, - vinm1: crate::gpio::gpiob::PB10, + vinm0: crate::gpio::PB2, + vinm1: crate::gpio::PB10, inverting: { - crate::gpio::gpiob::PB2: vinm0, - crate::gpio::gpiob::PB10: vinm1, + crate::gpio::PB2: vinm0, + crate::gpio::PB10: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB0: vinp0, - crate::gpio::gpiob::PB13: vinp1, - crate::gpio::gpioa::PA1: vinp2, + crate::gpio::PB0: vinp0, + crate::gpio::PB13: vinp1, + crate::gpio::PA1: vinp2, }, - output: crate::gpio::gpiob::PB1, + output: crate::gpio::PB1, }, } #[cfg(any(feature = "stm32g471", feature = "stm32g491", feature = "stm32g4a1"))] opamps! { Opamp1 => opamp1: { - vinm0: crate::gpio::gpioa::PA3, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA3, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA3: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA3: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA1: vinp0, - crate::gpio::gpioa::PA3: vinp1, - crate::gpio::gpioa::PA7: vinp2, + crate::gpio::PA1: vinp0, + crate::gpio::PA3: vinp1, + crate::gpio::PA7: vinp2, }, - output: crate::gpio::gpioa::PA2, + output: crate::gpio::PA2, }, Opamp2 => opamp2: { - vinm0: crate::gpio::gpioa::PA5, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA5, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA5: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA5: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA7: vinp0, - crate::gpio::gpiob::PB14: vinp1, - crate::gpio::gpiob::PB0: vinp2, - crate::gpio::gpiod::PD14: vinp3, + crate::gpio::PA7: vinp0, + crate::gpio::PB14: vinp1, + crate::gpio::PB0: vinp2, + crate::gpio::PD14: vinp3, }, - output: crate::gpio::gpioa::PA6, + output: crate::gpio::PA6, }, Opamp3 => opamp3: { - vinm0: crate::gpio::gpiob::PB2, - vinm1: crate::gpio::gpiob::PB10, + vinm0: crate::gpio::PB2, + vinm1: crate::gpio::PB10, inverting: { - crate::gpio::gpiob::PB2: vinm0, - crate::gpio::gpiob::PB10: vinm1, + crate::gpio::PB2: vinm0, + crate::gpio::PB10: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB0: vinp0, - crate::gpio::gpiob::PB13: vinp1, - crate::gpio::gpioa::PA1: vinp2, + crate::gpio::PB0: vinp0, + crate::gpio::PB13: vinp1, + crate::gpio::PA1: vinp2, }, - output: crate::gpio::gpiob::PB1, + output: crate::gpio::PB1, }, Opamp6 => opamp6: { - vinm0: crate::gpio::gpioa::PA1, - vinm1: crate::gpio::gpiob::PB1, + vinm0: crate::gpio::PA1, + vinm1: crate::gpio::PB1, inverting: { - crate::gpio::gpioa::PA1: vinm0, - crate::gpio::gpiob::PB1: vinm1, + crate::gpio::PA1: vinm0, + crate::gpio::PB1: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB12: vinp0, - crate::gpio::gpiod::PD9: vinp1, - crate::gpio::gpiob::PB13: vinp2, + crate::gpio::PB12: vinp0, + crate::gpio::PD9: vinp1, + crate::gpio::PB13: vinp2, }, - output: crate::gpio::gpiob::PB11, + output: crate::gpio::PB11, }, } @@ -981,88 +981,88 @@ opamps! { ))] opamps! { Opamp1 => opamp1: { - vinm0: crate::gpio::gpioa::PA3, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA3, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA3: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA3: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA1: vinp0, - crate::gpio::gpioa::PA3: vinp1, - crate::gpio::gpioa::PA7: vinp2, + crate::gpio::PA1: vinp0, + crate::gpio::PA3: vinp1, + crate::gpio::PA7: vinp2, }, - output: crate::gpio::gpioa::PA2, + output: crate::gpio::PA2, }, Opamp2 => opamp2: { - vinm0: crate::gpio::gpioa::PA5, - vinm1: crate::gpio::gpioc::PC5, + vinm0: crate::gpio::PA5, + vinm1: crate::gpio::PC5, inverting: { - crate::gpio::gpioa::PA5: vinm0, - crate::gpio::gpioc::PC5: vinm1, + crate::gpio::PA5: vinm0, + crate::gpio::PC5: vinm1, }, non_inverting: { - crate::gpio::gpioa::PA7: vinp0, - crate::gpio::gpiob::PB14: vinp1, - crate::gpio::gpiob::PB0: vinp2, - crate::gpio::gpiod::PD14: vinp3, + crate::gpio::PA7: vinp0, + crate::gpio::PB14: vinp1, + crate::gpio::PB0: vinp2, + crate::gpio::PD14: vinp3, }, - output: crate::gpio::gpioa::PA6, + output: crate::gpio::PA6, }, Opamp3 => opamp3: { - vinm0: crate::gpio::gpiob::PB2, - vinm1: crate::gpio::gpiob::PB10, + vinm0: crate::gpio::PB2, + vinm1: crate::gpio::PB10, inverting: { - crate::gpio::gpiob::PB2: vinm0, - crate::gpio::gpiob::PB10: vinm1, + crate::gpio::PB2: vinm0, + crate::gpio::PB10: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB0: vinp0, - crate::gpio::gpiob::PB13: vinp1, - crate::gpio::gpioa::PA1: vinp2, + crate::gpio::PB0: vinp0, + crate::gpio::PB13: vinp1, + crate::gpio::PA1: vinp2, }, - output: crate::gpio::gpiob::PB1, + output: crate::gpio::PB1, }, Opamp4 => opamp4: { - vinm0: crate::gpio::gpiob::PB10, - vinm1: crate::gpio::gpiod::PD8, + vinm0: crate::gpio::PB10, + vinm1: crate::gpio::PD8, inverting: { - crate::gpio::gpiob::PB10: vinm0, - crate::gpio::gpiod::PD8: vinm1, + crate::gpio::PB10: vinm0, + crate::gpio::PD8: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB13: vinp0, - crate::gpio::gpiod::PD11: vinp1, - crate::gpio::gpiob::PB11: vinp2, + crate::gpio::PB13: vinp0, + crate::gpio::PD11: vinp1, + crate::gpio::PB11: vinp2, }, - output: crate::gpio::gpiob::PB12, + output: crate::gpio::PB12, }, Opamp5 => opamp5: { - vinm0: crate::gpio::gpiob::PB15, - vinm1: crate::gpio::gpioa::PA3, + vinm0: crate::gpio::PB15, + vinm1: crate::gpio::PA3, inverting: { - crate::gpio::gpiob::PB15: vinm0, - crate::gpio::gpioa::PA3: vinm1, + crate::gpio::PB15: vinm0, + crate::gpio::PA3: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB14: vinp0, - crate::gpio::gpiod::PD12: vinp1, - crate::gpio::gpioc::PC3: vinp2, + crate::gpio::PB14: vinp0, + crate::gpio::PD12: vinp1, + crate::gpio::PC3: vinp2, }, - output: crate::gpio::gpioa::PA8, + output: crate::gpio::PA8, }, Opamp6 => opamp6: { - vinm0: crate::gpio::gpioa::PA1, - vinm1: crate::gpio::gpiob::PB1, + vinm0: crate::gpio::PA1, + vinm1: crate::gpio::PB1, inverting: { - crate::gpio::gpioa::PA1: vinm0, - crate::gpio::gpiob::PB1: vinm1, + crate::gpio::PA1: vinm0, + crate::gpio::PB1: vinm1, }, non_inverting: { - crate::gpio::gpiob::PB12: vinp0, - crate::gpio::gpiod::PD9: vinp1, - crate::gpio::gpiob::PB13: vinp2, + crate::gpio::PB12: vinp0, + crate::gpio::PD9: vinp1, + crate::gpio::PB13: vinp2, }, - output: crate::gpio::gpiob::PB11, + output: crate::gpio::PB11, }, } diff --git a/src/pwm.rs b/src/pwm.rs index c5c86e07..5543a138 100644 --- a/src/pwm.rs +++ b/src/pwm.rs @@ -196,14 +196,6 @@ use crate::stm32::{TIM1, TIM15, TIM16, TIM17, TIM2, TIM3, TIM4, TIM8}; use crate::rcc::{Enable, GetBusFreq, Rcc, Reset}; use crate::time::{ExtU32, Hertz, NanoSecond, RateExtU32}; -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] -use crate::gpio::gpiog::*; #[cfg(any( feature = "stm32g471", feature = "stm32g473", @@ -212,15 +204,14 @@ use crate::gpio::gpiog::*; feature = "stm32g484" ))] use crate::gpio::AF14; -use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiod::*, gpioe::*, gpiof::*}; -use crate::gpio::{Alternate, AF1, AF10, AF11, AF12, AF2, AF3, AF4, AF5, AF6, AF9}; +use crate::gpio::{self, AF1, AF10, AF11, AF12, AF2, AF3, AF4, AF5, AF6, AF9}; use core::mem::size_of; // This trait marks that a GPIO pin can be used with a specific timer channel // TIM is the timer being used // CHANNEL is a marker struct for the channel (or multi channels for tuples) -// Example: impl Pins for PA8> { type Channel = Pwm; } +// Example: impl Pins for PA8 { type Channel = Pwm; } /// Pins is a trait that marks which GPIO pins may be used as PWM channels; it should not be directly used. /// See the device datasheet 'Pin descriptions' chapter for which pins can be used with which timer PWM channels (or look at Implementors) pub trait Pins { @@ -551,27 +542,27 @@ macro_rules! pins { pins! { LPTIMER1: OUT: [ - PA14>, - PB2>, - PC1> + gpio::PA14, + gpio::PB2, + gpio::PC1 ] } // Dual channel timers pins! { TIM15: CH1(ComplementaryDisabled): [ - PA2>, - PB14>, - PF9> + gpio::PA2, + gpio::PB14, + gpio::PF9 ] CH2(ComplementaryImpossible): [ - PA3>, - PB15>, - PF10> + gpio::PA3, + gpio::PB15, + gpio::PF10 ] CH1N: [ - PA1>, - PB15>, + gpio::PA1, + gpio::PB15, #[cfg(any( feature = "stm32g471", feature = "stm32g473", @@ -579,47 +570,47 @@ pins! { feature = "stm32g483", feature = "stm32g484" ))] - PG9> + gpio::PG9 ] CH2N: [] BRK: [ - PA9>, - PC5> + gpio::PA9, + gpio::PC5 ] BRK2: [] TIM16: CH1(ComplementaryDisabled): [ - PA6>, - PA12>, - PB4>, - PB8>, - PE0> + gpio::PA6, + gpio::PA12, + gpio::PB4, + gpio::PB8, + gpio::PE0 ] CH2(ComplementaryImpossible): [] CH1N: [ - PA13>, - PB6> + gpio::PA13, + gpio::PB6 ] CH2N: [] BRK: [ - PB5> + gpio::PB5 ] BRK2: [] TIM17: CH1(ComplementaryDisabled): [ - PA7>, - PB5>, - PB9>, - PE1> + gpio::PA7, + gpio::PB5, + gpio::PB9, + gpio::PE1 ] CH2(ComplementaryImpossible): [] CH1N: [ - PB7> + gpio::PB7 ] CH2N: [] BRK: [ - PA10>, - PB4> + gpio::PA10, + gpio::PB4 ] BRK2: [] } @@ -627,87 +618,87 @@ pins! { pins! { TIM1: CH1(ComplementaryDisabled): [ - PA8>, - PC0>, - PE9> + gpio::PA8, + gpio::PC0, + gpio::PE9 ] CH2(ComplementaryDisabled): [ - PA9>, - PC1>, - PE11> + gpio::PA9, + gpio::PC1, + gpio::PE11 ] CH3(ComplementaryDisabled): [ - PA10>, - PC2>, - PE13> + gpio::PA10, + gpio::PC2, + gpio::PE13 ] CH4(ComplementaryDisabled): [ - PA11>, - PC3>, - PE14> + gpio::PA11, + gpio::PC3, + gpio::PE14 ] CH1N: [ - PA7>, - PA11>, - PB13>, - PC13>, - PE8> + gpio::PA7, + gpio::PA11, + gpio::PB13, + gpio::PC13, + gpio::PE8 ] CH2N: [ - PA12>, - PB0>, - PB14>, - PE10> + gpio::PA12, + gpio::PB0, + gpio::PB14, + gpio::PE10 ] CH3N: [ - PB1>, - PB9>, - PB15>, - PE12>, - PF0> + gpio::PB1, + gpio::PB9, + gpio::PB15, + gpio::PE12, + gpio::PF0 ] CH4N: [ - PC5>, - PE15> + gpio::PC5, + gpio::PE15 ] BRK: [ - PA6>, - PA14>, - PA15>, - PB8>, - PB10>, - PB12>, - PC13>, - PE15> + gpio::PA6, + gpio::PA14, + gpio::PA15, + gpio::PB8, + gpio::PB10, + gpio::PB12, + gpio::PC13, + gpio::PE15 ] BRK2: [ - PA11>, - PC3>, - PE14> + gpio::PA11, + gpio::PC3, + gpio::PE14 ] TIM2: CH1(ComplementaryImpossible): [ - PA0>, - PA5>, - PA15>, - PD3> + gpio::PA0, + gpio::PA5, + gpio::PA15, + gpio::PD3 ] CH2(ComplementaryImpossible): [ - PA1>, - PB3>, - PD4> + gpio::PA1, + gpio::PB3, + gpio::PD4 ] CH3(ComplementaryImpossible): [ - PA2>, - PA9>, - PB10>, - PD7> + gpio::PA2, + gpio::PA9, + gpio::PB10, + gpio::PD7 ] CH4(ComplementaryImpossible): [ - PA3>, - PA10>, - PB11>, - PD6> + gpio::PA3, + gpio::PA10, + gpio::PB11, + gpio::PD6 ] CH1N: [] CH2N: [] @@ -717,28 +708,28 @@ pins! { BRK2: [] TIM3: CH1(ComplementaryImpossible): [ - PA6>, - PB4>, - PC6>, - PE2> + gpio::PA6, + gpio::PB4, + gpio::PC6, + gpio::PE2 ] CH2(ComplementaryImpossible): [ - PA4>, - PA7>, - PB5>, - PC7>, - PE3> + gpio::PA4, + gpio::PA7, + gpio::PB5, + gpio::PC7, + gpio::PE3 ] CH3(ComplementaryImpossible): [ - PB0>, - PC8>, - PE4> + gpio::PB0, + gpio::PC8, + gpio::PE4 ] CH4(ComplementaryImpossible): [ - PB1>, - PB7>, - PC9>, - PE5> + gpio::PB1, + gpio::PB7, + gpio::PC9, + gpio::PE5 ] CH1N: [] CH2N: [] @@ -748,23 +739,23 @@ pins! { BRK2: [] TIM4: CH1(ComplementaryImpossible): [ - PA11>, - PB6>, - PD12> + gpio::PA11, + gpio::PB6, + gpio::PD12 ] CH2(ComplementaryImpossible): [ - PA12>, - PB7>, - PD13> + gpio::PA12, + gpio::PB7, + gpio::PD13 ] CH3(ComplementaryImpossible): [ - PA13>, - PB8>, - PD14> + gpio::PA13, + gpio::PB8, + gpio::PD14 ] CH4(ComplementaryImpossible): [ - PB9>, - PD15>, + gpio::PB9, + gpio::PD15, #[cfg(any( feature = "stm32g471", feature = "stm32g473", @@ -772,7 +763,7 @@ pins! { feature = "stm32g483", feature = "stm32g484" ))] - PF6> + gpio::PF6 ] CH1N: [] CH2N: [] @@ -791,24 +782,24 @@ pins! { pins! { TIM5: CH1(ComplementaryImpossible): [ - PA0>, - PB2>, - PF6> + gpio::PA0, + gpio::PB2, + gpio::PF6 ] CH2(ComplementaryImpossible): [ - PA1>, - PC12>, - PF7> + gpio::PA1, + gpio::PC12, + gpio::PF7 ] CH3(ComplementaryImpossible): [ - PA2>, - PE8>, - PF8> + gpio::PA2, + gpio::PE8, + gpio::PF8 ] CH4(ComplementaryImpossible): [ - PA3>, - PE9>, - PF9> + gpio::PA3, + gpio::PE9, + gpio::PF9 ] CH1N: [] CH2N: [] @@ -820,53 +811,53 @@ pins! { pins! { TIM8: CH1(ComplementaryDisabled): [ - PA15>, - PB6>, - PC6> + gpio::PA15, + gpio::PB6, + gpio::PC6 ] CH2(ComplementaryDisabled): [ - PA14>, - PB8>, - PC7> + gpio::PA14, + gpio::PB8, + gpio::PC7 ] CH3(ComplementaryDisabled): [ - PB9>, - PC8> + gpio::PB9, + gpio::PC8 ] CH4(ComplementaryDisabled): [ - PC9>, - PD1> + gpio::PC9, + gpio::PD1 ] CH1N: [ - PA7>, - PB3>, - PC10> + gpio::PA7, + gpio::PB3, + gpio::PC10 ] CH2N: [ - PB0>, - PB4>, - PC11> + gpio::PB0, + gpio::PB4, + gpio::PC11 ] CH3N: [ - PB1>, - PB5>, - PC12> + gpio::PB1, + gpio::PB5, + gpio::PC12 ] CH4N: [ - PC13>, - PD0> + gpio::PC13, + gpio::PD0 ] BRK: [ - PA0>, - PA6>, - PA10>, - PB7>, - PD2> + gpio::PA0, + gpio::PA6, + gpio::PA10, + gpio::PB7, + gpio::PD2 ] BRK2: [ - PB6>, - PC9>, - PD1> + gpio::PB6, + gpio::PC9, + gpio::PD1 ] } #[cfg(any( @@ -880,108 +871,108 @@ pins! { pins! { TIM20: CH1(ComplementaryDisabled): [ - PB2>, - PE2>, + gpio::PB2, + gpio::PE2, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF12> + gpio::PF12 ] CH2(ComplementaryDisabled): [ - PC2>, - PE3>, + gpio::PC2, + gpio::PE3, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF13> + gpio::PF13 ] CH3(ComplementaryDisabled): [ - PC8>, - PF2>, + gpio::PC8, + gpio::PF2, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF14> + gpio::PF14 ] CH4(ComplementaryDisabled): [ - PE1>, + gpio::PE1, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF3>, + gpio::PF3, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF15> + gpio::PF15 ] CH1N: [ - PE4>, + gpio::PE4, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF4>, + gpio::PF4, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG0> + gpio::PG0 ] CH2N: [ - PE5>, + gpio::PE5, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PF5>, + gpio::PF5, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG1> + gpio::PG1 ] CH3N: [ - PE6>, + gpio::PE6, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG2> + gpio::PG2 ] CH4N: [ - PE0>, + gpio::PE0, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG3> + gpio::PG3 ] BRK: [ #[cfg(any( @@ -990,22 +981,22 @@ pins! { feature = "stm32g483", feature = "stm32g484", ))] - PF7>, - PF9>, + gpio::PF7, + gpio::PF9, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG3>, + gpio::PG3, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG6> + gpio::PG6 ] BRK2: [ #[cfg(any( @@ -1014,15 +1005,15 @@ pins! { feature = "stm32g483", feature = "stm32g484", ))] - PF8>, - PF10>, + gpio::PF8, + gpio::PF10, #[cfg(any( feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484", ))] - PG4> + gpio::PG4 ] } diff --git a/src/rcc/clockout.rs b/src/rcc/clockout.rs index b9f49944..3cd85cf1 100644 --- a/src/rcc/clockout.rs +++ b/src/rcc/clockout.rs @@ -2,10 +2,10 @@ use crate::gpio::*; use crate::rcc::*; use crate::stm32::RCC; -pub type LscoPin = gpioa::PA2; +pub type LscoPin = gpioa::PA2; pub struct Lsco { - pin: gpioa::PA2>, + pin: gpioa::PA2, } impl Lsco { @@ -20,7 +20,7 @@ impl Lsco { } pub fn release(self) -> LscoPin { - self.pin.into_floating_input() + self.pin.into_analog() } } @@ -43,7 +43,7 @@ impl LSCOExt for LscoPin { }; rcc.rb.bdcr().modify(|_, w| w.lscosel().bit(src_select_bit)); Lsco { - pin: self.into_alternate(), + pin: self.into_mode(), } } } @@ -77,8 +77,8 @@ pub trait MCOExt { macro_rules! mco { ($($PIN:ident),+) => { $( - impl MCOExt<$PIN>> for $PIN { - fn mco(self, src: MCOSrc, psc: Prescaler, rcc: &mut Rcc) -> Mco<$PIN>> { + impl MCOExt> for crate::gpio::$PIN { + fn mco(self, src: MCOSrc, psc: Prescaler, rcc: &mut Rcc) -> Mco> { let psc_bits = match psc { Prescaler::NotDivided => 0b000, Prescaler::Div2 => 0b001, @@ -120,7 +120,4 @@ macro_rules! mco { }; } -use crate::gpio::gpioa::PA8; -use crate::gpio::gpiog::PG10; - mco!(PA8, PG10); diff --git a/src/serial/usart.rs b/src/serial/usart.rs index 8582a67b..75a10c0d 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -4,8 +4,7 @@ use core::marker::PhantomData; use crate::dma::{ mux::DmaMuxResources, traits::TargetAddress, MemoryToPeripheral, PeripheralToMemory, }; -use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiod::*, gpioe::*, gpiog::*}; -use crate::gpio::{Alternate, AlternateOD, AF12, AF5, AF7, AF8}; +use crate::gpio::{self, OpenDrain, AF12, AF5, AF7, AF8}; use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; use crate::stm32::*; @@ -159,20 +158,21 @@ where macro_rules! uart_shared { ($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident, - tx: [ $($( #[ $pmeta1:meta ] )* ($PTX:ident, $TAF:expr),)+ ], - rx: [ $($( #[ $pmeta2:meta ] )* ($PRX:ident, $RAF:expr),)+ ]) => { + tx: [ $($( #[ $pmeta1:meta ] )* ($PTX:ident, $TAF:ident),)+ ], + rx: [ $($( #[ $pmeta2:meta ] )* ($PRX:ident, $RAF:ident),)+ ]) => { $( $( #[ $pmeta1 ] )* - impl TxPin<$USARTX> for $PTX> { + impl TxPin<$USARTX> for gpio::$PTX<$TAF> { } - impl TxPin<$USARTX> for $PTX> { + $( #[ $pmeta1 ] )* + impl TxPin<$USARTX> for gpio::$PTX<$TAF> { } )+ $( $( #[ $pmeta2 ] )* - impl RxPin<$USARTX> for $PRX> { + impl RxPin<$USARTX> for gpio::$PRX<$RAF> { } )+ diff --git a/src/spi.rs b/src/spi.rs index 37de2169..875dcfeb 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1,26 +1,13 @@ use crate::dma::mux::DmaMuxResources; use crate::dma::traits::TargetAddress; use crate::dma::MemoryToPeripheral; -use crate::gpio::{gpioa::*, gpiob::*, gpioc::*, gpiof::*, Alternate, AF5, AF6}; -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] -use crate::gpio::{gpioe::*, gpiog::*}; -use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] +use crate::gpio::alt::SpiCommon; +use crate::rcc::Rcc; +#[cfg(feature = "spi4")] use crate::stm32::SPI4; use crate::stm32::{RCC, SPI1, SPI2, SPI3}; use crate::time::Hertz; +use core::ops::Deref; use core::ptr; use embedded_hal::spi::ErrorKind; @@ -47,40 +34,73 @@ impl embedded_hal::spi::Error for Error { } } -/// A filler type for when the SCK pin is unnecessary -pub struct NoSck; -/// A filler type for when the Miso pin is unnecessary -pub struct NoMiso; -/// A filler type for when the Mosi pin is unnecessary -pub struct NoMosi; - -pub trait Pins {} - -pub trait PinSck {} - -pub trait PinMiso {} - -pub trait PinMosi {} - -impl Pins for (SCK, MISO, MOSI) -where - SCK: PinSck, - MISO: PinMiso, - MOSI: PinMosi, +pub trait Instance: + crate::Sealed + crate::rcc::Instance + SpiCommon + Deref { + const TX_MUX: DmaMuxResources; + fn ptr() -> *const crate::pac::spi1::RegisterBlock; +} + +impl Instance for SPI1 { + const TX_MUX: DmaMuxResources = DmaMuxResources::SPI1_TX; + fn ptr() -> *const crate::pac::spi1::RegisterBlock { + Self::ptr() + } +} +impl Instance for SPI2 { + const TX_MUX: DmaMuxResources = DmaMuxResources::SPI2_TX; + fn ptr() -> *const crate::pac::spi1::RegisterBlock { + Self::ptr() + } +} +impl Instance for SPI3 { + const TX_MUX: DmaMuxResources = DmaMuxResources::SPI3_TX; + fn ptr() -> *const crate::pac::spi1::RegisterBlock { + Self::ptr() + } +} +#[cfg(feature = "spi4")] +impl Instance for SPI4 { + const TX_MUX: DmaMuxResources = DmaMuxResources::SPI4_TX; + fn ptr() -> *const crate::pac::spi1::RegisterBlock { + Self::ptr() + } } #[derive(Debug)] -pub struct Spi { +pub struct Spi { spi: SPI, - pins: PINS, + pins: (SPI::Sck, SPI::Miso, SPI::Mosi), +} + +pub trait SpiExt: Instance + Sized { + fn spi( + self, + pins: ( + impl Into, + impl Into, + impl Into, + ), + mode: Mode, + freq: Hertz, + rcc: &mut Rcc, + ) -> Spi; } -pub trait SpiExt: Sized { - fn spi(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi - where - PINS: Pins, - T: Into; +impl SpiExt for SPI { + fn spi( + self, + pins: ( + impl Into, + impl Into, + impl Into, + ), + mode: Mode, + freq: Hertz, + rcc: &mut Rcc, + ) -> Spi { + Spi::new(self, pins, mode, freq, rcc) + } } pub trait FrameSize: Copy + Default { @@ -94,396 +114,248 @@ impl FrameSize for u16 { const DFF: bool = true; } -macro_rules! spi { - ($SPIX:ident, $spiX:ident, - sck: [ $($( #[ $pmetasck:meta ] )* $SCK:ty,)+ ], - miso: [ $($( #[ $pmetamiso:meta ] )* $MISO:ty,)+ ], - mosi: [ $($( #[ $pmetamosi:meta ] )* $MOSI:ty,)+ ], - $mux:expr, - ) => { - impl PinSck<$SPIX> for NoSck {} - - impl PinMiso<$SPIX> for NoMiso {} - - impl PinMosi<$SPIX> for NoMosi {} - - $( - $( #[ $pmetasck ] )* - impl PinSck<$SPIX> for $SCK {} - )* - $( - $( #[ $pmetamiso ] )* - impl PinMiso<$SPIX> for $MISO {} - )* - $( - $( #[ $pmetamosi ] )* - impl PinMosi<$SPIX> for $MOSI {} - )* - - impl> Spi<$SPIX, PINS> { - pub fn $spiX( - spi: $SPIX, - pins: PINS, - mode: Mode, - speed: T, - rcc: &mut Rcc - ) -> Self - where - T: Into - { - // Enable and reset SPI - unsafe { - let rcc_ptr = &(*RCC::ptr()); - $SPIX::enable(rcc_ptr); - $SPIX::reset(rcc_ptr); - } - - // disable SS output - spi.cr2().write(|w| w.ssoe().clear_bit()); - - let spi_freq = speed.into().raw(); - let bus_freq = <$SPIX as RccBus>::Bus::get_frequency(&rcc.clocks).raw(); - let br = match bus_freq / spi_freq { - 0 => unreachable!(), - 1..=2 => 0b000, - 3..=5 => 0b001, - 6..=11 => 0b010, - 12..=23 => 0b011, - 24..=47 => 0b100, - 48..=95 => 0b101, - 96..=191 => 0b110, - _ => 0b111, - }; - - spi.cr2().write(|w| unsafe { - w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit() - }); - - spi.cr1().write(|w| unsafe { - w.cpha() - .bit(mode.phase == Phase::CaptureOnSecondTransition) - .cpol() - .bit(mode.polarity == Polarity::IdleHigh) - .mstr() - .set_bit() - .br() - .bits(br) - .lsbfirst() - .clear_bit() - .ssm() - .set_bit() - .ssi() - .set_bit() - .rxonly() - .clear_bit() - .dff() - .clear_bit() - .bidimode() - .clear_bit() - .ssi() - .set_bit() - .spe() - .set_bit() - }); - - Spi { spi, pins } - } - - pub fn release(self) -> ($SPIX, PINS) { - (self.spi, self.pins) - } - - pub fn enable_tx_dma(self) -> Spi<$SPIX, PINS> { - self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); - Spi { - spi: self.spi, - pins: self.pins, - } - } +impl Spi { + pub fn new( + spi: SPI, + pins: ( + impl Into, + impl Into, + impl Into, + ), + mode: Mode, + speed: Hertz, + rcc: &mut Rcc, + ) -> Self { + // Enable and reset SPI + unsafe { + let rcc_ptr = &(*RCC::ptr()); + SPI::enable(rcc_ptr); + SPI::reset(rcc_ptr); } - impl Spi<$SPIX, PINS> { - fn nb_read(&mut self) -> nb::Result { - let sr = self.spi.sr().read(); - Err(if sr.ovr().bit_is_set() { - nb::Error::Other(Error::Overrun) - } else if sr.modf().bit_is_set() { - nb::Error::Other(Error::ModeFault) - } else if sr.crcerr().bit_is_set() { - nb::Error::Other(Error::Crc) - } else if sr.rxne().bit_is_set() { - // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows - // reading a half-word) - return Ok(unsafe { - ptr::read_volatile(&self.spi.dr() as *const _ as *const W) - }); - } else { - nb::Error::WouldBlock - }) - } - fn nb_write(&mut self, word: W) -> nb::Result<(), Error> { - let sr = self.spi.sr().read(); - Err(if sr.ovr().bit_is_set() { - nb::Error::Other(Error::Overrun) - } else if sr.modf().bit_is_set() { - nb::Error::Other(Error::ModeFault) - } else if sr.crcerr().bit_is_set() { - nb::Error::Other(Error::Crc) - } else if sr.txe().bit_is_set() { - let dr = self.spi.dr().as_ptr() as *mut W; - // NOTE(write_volatile) see note above - unsafe { ptr::write_volatile(dr, word) }; - return Ok(()); - } else { - nb::Error::WouldBlock - }) - } - fn set_tx_only(&mut self) { - self.spi - .cr1() - .modify(|_, w| w.bidimode().set_bit().bidioe().set_bit()); - } - fn set_bidi(&mut self) { - self.spi - .cr1() - .modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit()); - } + // disable SS output + spi.cr2().write(|w| w.ssoe().clear_bit()); + + let spi_freq = speed.raw(); + let bus_freq = SPI::get_frequency(&rcc.clocks).raw(); + let br = match bus_freq / spi_freq { + 0 => unreachable!(), + 1..=2 => 0b000, + 3..=5 => 0b001, + 6..=11 => 0b010, + 12..=23 => 0b011, + 24..=47 => 0b100, + 48..=95 => 0b101, + 96..=191 => 0b110, + _ => 0b111, + }; + + spi.cr2() + .write(|w| unsafe { w.frxth().set_bit().ds().bits(0b111).ssoe().clear_bit() }); + + spi.cr1().write(|w| unsafe { + w.cpha().bit(mode.phase == Phase::CaptureOnSecondTransition); + w.cpol().bit(mode.polarity == Polarity::IdleHigh); + w.mstr().set_bit(); + w.br().bits(br); + w.lsbfirst().clear_bit(); + w.ssm().set_bit(); + w.ssi().set_bit(); + w.rxonly().clear_bit(); + w.dff().clear_bit(); + w.bidimode().clear_bit(); + w.ssi().set_bit(); + w.spe().set_bit() + }); + + Spi { + spi, + pins: (pins.0.into(), pins.1.into(), pins.2.into()), } + } - impl SpiExt<$SPIX> for $SPIX { - fn spi(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<$SPIX, PINS> - where - PINS: Pins<$SPIX>, - T: Into - { - Spi::$spiX(self, pins, mode, freq, rcc) - } + #[allow(clippy::type_complexity)] + pub fn release(self) -> (SPI, (SPI::Sck, SPI::Miso, SPI::Mosi)) { + (self.spi, self.pins) + } + + pub fn enable_tx_dma(self) -> Spi { + self.spi.cr2().modify(|_, w| w.txdmaen().set_bit()); + Spi { + spi: self.spi, + pins: self.pins, } + } +} + +impl Spi { + fn nb_read(&mut self) -> nb::Result { + let sr = self.spi.sr().read(); + Err(if sr.ovr().bit_is_set() { + nb::Error::Other(Error::Overrun) + } else if sr.modf().bit_is_set() { + nb::Error::Other(Error::ModeFault) + } else if sr.crcerr().bit_is_set() { + nb::Error::Other(Error::Crc) + } else if sr.rxne().bit_is_set() { + // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows + // reading a half-word) + return Ok(unsafe { ptr::read_volatile(&self.spi.dr() as *const _ as *const W) }); + } else { + nb::Error::WouldBlock + }) + } + fn nb_write(&mut self, word: W) -> nb::Result<(), Error> { + let sr = self.spi.sr().read(); + Err(if sr.ovr().bit_is_set() { + nb::Error::Other(Error::Overrun) + } else if sr.modf().bit_is_set() { + nb::Error::Other(Error::ModeFault) + } else if sr.crcerr().bit_is_set() { + nb::Error::Other(Error::Crc) + } else if sr.txe().bit_is_set() { + let dr = self.spi.dr().as_ptr() as *mut W; + // NOTE(write_volatile) see note above + unsafe { ptr::write_volatile(dr, word) }; + return Ok(()); + } else { + nb::Error::WouldBlock + }) + } + fn set_tx_only(&mut self) { + self.spi + .cr1() + .modify(|_, w| w.bidimode().set_bit().bidioe().set_bit()); + } + fn set_bidi(&mut self) { + self.spi + .cr1() + .modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit()); + } +} + +impl embedded_hal::spi::ErrorType for Spi { + type Error = Error; +} - impl embedded_hal::spi::ErrorType for Spi<$SPIX, PINS> { - type Error = Error; +impl embedded_hal::spi::SpiBus for Spi { + fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + if words.is_empty() { + return Ok(()); } + // clear tx-only status in the case the previous operation was a write + self.set_bidi(); + // prefill write fifo so that the clock doen't stop while fetch the read byte + // one frame should be enough? + nb::block!(self.nb_write(0u8))?; + let len = words.len(); + for w in words[..len - 1].iter_mut() { + // TODO: 16 bit frames, bidirectional pins + nb::block!(self.nb_write(0u8))?; + *w = nb::block!(self.nb_read())?; + } + // safety: length > 0 checked at start of function + *words.last_mut().unwrap() = nb::block!(self.nb_read())?; + Ok(()) + } - impl embedded_hal::spi::SpiBus for Spi<$SPIX, PINS> { - fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { - if words.len() == 0 { return Ok(()) } - // clear tx-only status in the case the previous operation was a write - self.set_bidi(); - // prefill write fifo so that the clock doen't stop while fetch the read byte - // one frame should be enough? - nb::block!(self.nb_write(0u8))?; - let len = words.len(); - for w in words[..len-1].iter_mut() { - // TODO: 16 bit frames, bidirectional pins - nb::block!(self.nb_write(0u8))?; - *w = nb::block!(self.nb_read())?; - } - // safety: length > 0 checked at start of function - *words.last_mut().unwrap() = nb::block!(self.nb_read())?; - Ok(()) - } - - fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { - self.set_tx_only(); - Ok(for w in words { - nb::block!(self.nb_write(*w))? - }) - } - - fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { - if read.len() == 0 { - return self.write(write) - } else if write.len() == 0 { - return self.read(read) - } - - self.set_bidi(); - // same prefill as in read, this time with actual data - nb::block!(self.nb_write(write[0]))?; - let common_len = core::cmp::min(read.len(), write.len()); - // take 1 less because write skips the first element - let zipped = read.iter_mut().zip(write.into_iter().skip(1)).take(common_len - 1); - for (r, w) in zipped { - nb::block!(self.nb_write(*w))?; - *r = nb::block!(self.nb_read())?; - } - read[common_len-1] = nb::block!(self.nb_read())?; - - if read.len() > common_len { - self.read(&mut read[common_len..]) - } else { - self.write(&write[common_len..]) - } - } - fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { - if words.len() == 0 { return Ok(()) } - self.set_bidi(); - nb::block!(self.nb_write(words[0]))?; - let cells = core::cell::Cell::from_mut(words).as_slice_of_cells(); - - for rw in cells.windows(2) { - let r = &rw[0]; - let w = &rw[1]; - - nb::block!(self.nb_write(w.get()))?; - r.set(nb::block!(self.nb_read())?); - } - *words.last_mut().unwrap() = nb::block!(self.nb_read())?; - Ok(()) - } - fn flush(&mut self) -> Result<(), Self::Error> { - // stop receiving data - self.set_tx_only(); - // wait for tx fifo to be drained by the peripheral - while self.spi.sr().read().ftlvl() != 0 { core::hint::spin_loop() }; - // drain rx fifo - Ok(while match self.nb_read::() { - Ok(_) => true, - Err(nb::Error::WouldBlock) => false, - Err(nb::Error::Other(e)) => return Err(e) - } { core::hint::spin_loop() }) - } + fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> { + self.set_tx_only(); + for w in words { + nb::block!(self.nb_write(*w))?; } + Ok(()) + } - impl embedded_hal_old::spi::FullDuplex for Spi<$SPIX, PINS> { - type Error = Error; + fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> { + if read.is_empty() { + return self.write(write); + } else if write.is_empty() { + return self.read(read); + } - fn read(&mut self) -> nb::Result { - self.nb_read() - } + self.set_bidi(); + // same prefill as in read, this time with actual data + nb::block!(self.nb_write(write[0]))?; + let common_len = core::cmp::min(read.len(), write.len()); + // take 1 less because write skips the first element + let zipped = read + .iter_mut() + .zip(write.iter().skip(1)) + .take(common_len - 1); + for (r, w) in zipped { + nb::block!(self.nb_write(*w))?; + *r = nb::block!(self.nb_read())?; + } + read[common_len - 1] = nb::block!(self.nb_read())?; - fn send(&mut self, byte: u8) -> nb::Result<(), Error> { - self.nb_write(byte) - } + if read.len() > common_len { + self.read(&mut read[common_len..]) + } else { + self.write(&write[common_len..]) + } + } + fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> { + if words.is_empty() { + return Ok(()); } - unsafe impl TargetAddress for Spi<$SPIX, Pin> { - #[inline(always)] - fn address(&self) -> u32 { - // unsafe: only the Tx part accesses the Tx register - &unsafe { &*<$SPIX>::ptr() }.dr() as *const _ as u32 - } + self.set_bidi(); + nb::block!(self.nb_write(words[0]))?; + let cells = core::cell::Cell::from_mut(words).as_slice_of_cells(); - type MemSize = u8; + for rw in cells.windows(2) { + let r = &rw[0]; + let w = &rw[1]; - const REQUEST_LINE: Option = Some($mux as u8); + nb::block!(self.nb_write(w.get()))?; + r.set(nb::block!(self.nb_read())?); + } + *words.last_mut().unwrap() = nb::block!(self.nb_read())?; + Ok(()) + } + fn flush(&mut self) -> Result<(), Self::Error> { + // stop receiving data + self.set_tx_only(); + // wait for tx fifo to be drained by the peripheral + while self.spi.sr().read().ftlvl() != 0 { + core::hint::spin_loop() } + // drain rx fifo + + while match self.nb_read::() { + Ok(_) => true, + Err(nb::Error::WouldBlock) => false, + Err(nb::Error::Other(e)) => return Err(e), + } { + core::hint::spin_loop(); + } + Ok(()) + } +} +impl embedded_hal_old::spi::FullDuplex for Spi { + type Error = Error; - impl embedded_hal_old::blocking::spi::transfer::Default for Spi<$SPIX, PINS> {} + fn read(&mut self) -> nb::Result { + self.nb_read() + } - impl embedded_hal_old::blocking::spi::write::Default for Spi<$SPIX, PINS> {} + fn send(&mut self, byte: u8) -> nb::Result<(), Error> { + self.nb_write(byte) + } +} +unsafe impl TargetAddress for Spi { + #[inline(always)] + fn address(&self) -> u32 { + // unsafe: only the Tx part accesses the Tx register + &unsafe { &*::ptr() }.dr() as *const _ as u32 } + + type MemSize = u8; + + const REQUEST_LINE: Option = Some(SPI::TX_MUX as u8); } -spi!( - SPI1, - spi1, - sck: [ - PA5>, - PB3>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG2>, - ], - miso: [ - PA6>, - PB4>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG3>, - ], - mosi: [ - PA7>, - PB5>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG4>, - ], - DmaMuxResources::SPI1_TX, -); - -spi!( - SPI2, - spi2, - sck: [ - PF1>, - PF9>, - PF10>, - PB13>, - ], - miso: [ - PA10>, - PB14>, - ], - mosi: [ - PA11>, - PB15>, - ], - DmaMuxResources::SPI2_TX, -); - -spi!( - SPI3, - spi3, - sck: [ - PB3>, - PC10>, - #[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG9>, - ], - miso: [ - PB4>, - PC11>, - ], - mosi: [ - PB5>, - PC12>, - ], - DmaMuxResources::SPI3_TX, -); - -#[cfg(any( - feature = "stm32g471", - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" -))] -spi!( - SPI4, - spi4, - sck: [ - PE2>, - PE12>, - ], - miso: [ - PE5>, - PE13>, - ], - mosi: [ - PE6>, - PE14>, - ], - DmaMuxResources::SPI4_TX, -); +impl embedded_hal_old::blocking::spi::transfer::Default for Spi {} + +impl embedded_hal_old::blocking::spi::write::Default for Spi {} diff --git a/src/usb.rs b/src/usb.rs index 0d9181c8..a3eb0f48 100644 --- a/src/usb.rs +++ b/src/usb.rs @@ -5,7 +5,7 @@ pub use stm32_usbd::UsbBus; use crate::gpio; -use crate::gpio::gpioa::{PA11, PA12}; +use crate::gpio::{PA11, PA12}; use crate::rcc::{Enable, Reset}; use crate::stm32::{RCC, USB}; use core::fmt;