From 1290de40a3fa2dda3079de4726ee3657e46dbcb0 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Sun, 23 Mar 2025 21:15:52 +0300 Subject: [PATCH 1/4] F4 GPIO --- .vscode/settings.json | 4 +- Cargo.toml | 231 +++- examples/adc-continious.rs | 3 +- examples/adc-one-shot.rs | 3 +- examples/button.rs | 2 +- examples/comp.rs | 34 +- examples/comp_w_dac.rs | 26 +- examples/cordic.rs | 30 +- examples/i2c.rs | 5 +- examples/spi-dma.rs | 7 +- examples/spi-example.rs | 9 +- examples/spi-sd.rs | 9 +- examples/uart-dma-rx.rs | 5 +- examples/uart-dma-tx.rs | 13 +- examples/uart-fifo.rs | 3 +- examples/uart.rs | 4 +- src/comparator.rs | 216 +--- src/dma/transfer.rs | 2 +- src/gpio.rs | 20 +- src/gpio/alt.rs | 378 +++++++ src/gpio/alt/g4.rs | 2093 ++++++++++++++++++++++++++++++++++++ src/i2c.rs | 575 ++++------ src/serial/config.rs | 12 + src/serial/usart.rs | 461 +++----- src/spi.rs | 698 ++++++------ 25 files changed, 3509 insertions(+), 1334 deletions(-) create mode 100644 src/gpio/alt.rs create mode 100644 src/gpio/alt/g4.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 5ecc8746..bc2285d3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +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": [ "stm32g484", diff --git a/Cargo.toml b/Cargo.toml index b1cb7421..0d6df68a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -80,19 +80,225 @@ rt = ["stm32g4/rt"] usb = ["dep:stm32-usbd"] stm32g431 = ["stm32g4/stm32g431", "cat2"] stm32g441 = ["stm32g4/stm32g441", "cat2"] -stm32g473 = ["stm32g4/stm32g473", "cat3", "adc3", "adc4", "adc5"] -stm32g474 = ["stm32g4/stm32g474", "cat3", "adc3", "adc4", "adc5"] -stm32g483 = ["stm32g4/stm32g483", "cat3", "adc3", "adc4", "adc5"] -stm32g484 = ["stm32g4/stm32g484", "cat3", "adc3", "adc4", "adc5"] -stm32g491 = ["stm32g4/stm32g491", "cat4", "adc3"] -stm32g4a1 = ["stm32g4/stm32g4a1", "cat4", "adc3"] +stm32g473 = ["stm32g4/stm32g473", "cat3"] +stm32g474 = ["stm32g4/stm32g474", "cat3"] +stm32g483 = ["stm32g4/stm32g483", "cat3"] +stm32g484 = ["stm32g4/stm32g484", "cat3"] +stm32g491 = ["stm32g4/stm32g491", "cat4"] +stm32g4a1 = ["stm32g4/stm32g4a1", "cat4"] +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 = [ + "adc3", + "adc4", + "adc5", + "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 = [ + "adc3", + "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", +] -gpio-g43x = [] - -gpio-g47x = [] - -gpio-g49x = [] +adc3 = [] +adc4 = [] +adc5 = [] +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 = [] @@ -106,9 +312,6 @@ defmt = [ "embedded-io/defmt-03", ] cordic = ["dep:fixed"] -adc3 = [] -adc4 = [] -adc5 = [] # Device category cat2 = ["gpio-g43x"] diff --git a/examples/adc-continious.rs b/examples/adc-continious.rs index b44b4755..10094c6b 100644 --- a/examples/adc-continious.rs +++ b/examples/adc-continious.rs @@ -42,7 +42,6 @@ fn main() -> ! { info!("Setup Gpio"); let gpioa = dp.GPIOA.split(&mut rcc); - let pa0 = gpioa.pa0.into_analog(); info!("Setup Adc1"); let mut delay = cp.SYST.delay(&rcc.clocks); @@ -54,7 +53,7 @@ fn main() -> ! { adc.set_auto_delay(true); adc.set_continuous(Continuous::Continuous); adc.reset_sequence(); - adc.configure_channel(&pa0, Sequence::One, SampleTime::Cycles_640_5); + adc.configure_channel(&gpioa.pa0, Sequence::One, SampleTime::Cycles_640_5); adc.configure_channel(&Vref, Sequence::Two, SampleTime::Cycles_640_5); adc.configure_channel(&Temperature, Sequence::Three, SampleTime::Cycles_640_5); let adc = adc.enable(); diff --git a/examples/adc-one-shot.rs b/examples/adc-one-shot.rs index 388b6757..efa30118 100644 --- a/examples/adc-one-shot.rs +++ b/examples/adc-one-shot.rs @@ -43,13 +43,12 @@ fn main() -> ! { info!("Setup Gpio"); let gpioa = dp.GPIOA.split(&mut rcc); - let pa7 = gpioa.pa7.into_analog(); info!("Enter Loop"); loop { info!("Convert"); - let sample = adc.convert(&pa7, SampleTime::Cycles_640_5); + let sample = adc.convert(&gpioa.pa7, SampleTime::Cycles_640_5); info!("sample to mv"); let millivolts = adc.sample_to_millivolts(sample); info!("pa7: {}mV", millivolts); diff --git a/examples/button.rs b/examples/button.rs index c3530b90..0e1551ac 100644 --- a/examples/button.rs +++ b/examples/button.rs @@ -17,7 +17,7 @@ use cortex_m_rt::entry; type ButtonPin = gpio::PC13; -// Make LED pin globally available +// Make LED and BUTTON pins globally available static G_BUTTON: Mutex>> = Mutex::new(RefCell::new(None)); static G_LED_ON: AtomicBool = AtomicBool::new(true); diff --git a/examples/comp.rs b/examples/comp.rs index 1b4deb5a..8ba44e37 100644 --- a/examples/comp.rs +++ b/examples/comp.rs @@ -9,53 +9,47 @@ #![no_std] mod utils; -extern crate cortex_m_rt as rt; -use rt::entry; +use cortex_m_rt::entry; #[entry] fn main() -> ! { - use hal::comparator::{refint_input, ComparatorExt, ComparatorSplit, Config, Hysteresis}; - use hal::gpio::GpioExt; - use hal::rcc::RccExt; - use hal::stm32; - use stm32g4xx_hal as hal; - - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + use stm32g4xx_hal::{ + comparator::{refint_input, ComparatorExt, ComparatorSplit, Config, Hysteresis}, + gpio::{GpioExt, PushPull}, + pac, + rcc::RccExt, + }; + + let dp = pac::Peripherals::take().expect("cannot take peripherals"); let mut rcc = dp.RCC.constrain(); let gpioa = dp.GPIOA.split(&mut rcc); let (comp1, comp2, ..) = dp.COMP.split(&mut rcc); - let pa1 = gpioa.pa1.into_analog(); - let pa0 = gpioa.pa0.into_analog(); - let comp1 = comp1.comparator(pa1, pa0, Config::default(), &rcc.clocks); + let comp1 = comp1.comparator(gpioa.pa1, gpioa.pa0, Config::default(), &rcc.clocks); let comp1 = comp1.enable(); // led1 pa1 will be updated manually when to match comp1 value let mut led1 = gpioa.pa5.into_push_pull_output(); - let pa7 = gpioa.pa7.into_analog(); let comp2 = comp2.comparator( - pa7, + gpioa.pa7, refint_input::VRefintM12, Config::default() .hysteresis(Hysteresis::None) .output_inverted(), &rcc.clocks, ); - let led2 = gpioa.pa12.into_push_pull_output(); + let led2 = gpioa.pa12; // Configure PA12 to the comparator's alternate function so it gets // changed directly by the comparator. - comp2.output_pin(led2); + comp2.output_pin::(led2); let _comp2 = comp2.enable().lock(); loop { // Read comp1 output and update led1 accordingly - match comp1.output() { - true => led1.set_high(), - false => led1.set_low(), - } + led1.set_state(comp1.output().into()); } } diff --git a/examples/comp_w_dac.rs b/examples/comp_w_dac.rs index 679d819b..1f1dd244 100644 --- a/examples/comp_w_dac.rs +++ b/examples/comp_w_dac.rs @@ -10,16 +10,17 @@ use rt::entry; #[entry] fn main() -> ! { - use hal::comparator::{self, ComparatorExt, ComparatorSplit}; - use hal::dac::{Dac1IntSig1, DacExt, DacOut}; - use hal::delay::SYSTDelayExt; - use hal::gpio::GpioExt; - use hal::rcc::RccExt; - use hal::stasis::Freeze; - use hal::stm32; - use stm32g4xx_hal as hal; + use stm32g4xx_hal::{ + comparator::{self, ComparatorExt, ComparatorSplit}, + dac::{Dac1IntSig1, DacExt, DacOut}, + delay::SYSTDelayExt, + gpio::{GpioExt, PushPull}, + pac, + rcc::RccExt, + stasis::Freeze, + }; - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let dp = pac::Peripherals::take().expect("cannot take peripherals"); let cp = cortex_m::Peripherals::take().expect("cannot take core peripherals"); let mut rcc = dp.RCC.constrain(); @@ -34,20 +35,19 @@ fn main() -> ! { let (mut dac, [dac_token]) = dac.freeze(); let (comp1, _comp2, ..) = dp.COMP.split(&mut rcc); - let pa1 = gpioa.pa1.into_analog(); // Set up comparator with pa1 as positive, and the DAC as negative input let comp = comp1.comparator( - pa1, + gpioa.pa1, dac_token, comparator::Config::default().hysteresis(comparator::Hysteresis::None), &rcc.clocks, ); - let led2 = gpioa.pa0.into_push_pull_output(); + let led2 = gpioa.pa0; // Configure PA12 to the comparator's alternate function so it gets // changed directly by the comparator. - comp.output_pin(led2); + comp.output_pin::(led2); let _comp1 = comp.enable().lock(); enum Direction { diff --git a/examples/cordic.rs b/examples/cordic.rs index a3efa083..08437212 100644 --- a/examples/cordic.rs +++ b/examples/cordic.rs @@ -3,22 +3,20 @@ #![no_main] #![no_std] -extern crate cortex_m; -extern crate cortex_m_rt as rt; -extern crate stm32g4xx_hal as hal; - -use hal::cordic::{ - op::{dynamic::Mode as _, Magnitude, SinCos, Sqrt}, - prec::P60, - scale::N0, - types::{I1F15, Q15, Q31}, - Ext as _, +use cortex_m_rt::entry; +use stm32g4xx_hal::{ + cordic::{ + op::{dynamic::Mode as _, Magnitude, SinCos, Sqrt}, + prec::P60, + scale::N0, + types::{I1F15, Q15, Q31}, + Ext as _, + }, + pac, + prelude::*, + pwr::PwrExt, + rcc::Config, }; -use hal::prelude::*; -use hal::pwr::PwrExt; -use hal::rcc::Config; -use hal::stm32; -use rt::entry; #[macro_use] mod utils; @@ -27,7 +25,7 @@ use utils::logger::println; #[entry] fn main() -> ! { - let dp = stm32::Peripherals::take().expect("cannot take peripherals"); + let dp = pac::Peripherals::take().expect("cannot take peripherals"); let pwr = dp.PWR.constrain().freeze(); let mut rcc = dp.RCC.freeze(Config::hsi(), pwr); diff --git a/examples/i2c.rs b/examples/i2c.rs index 4bf0366e..8dacce08 100644 --- a/examples/i2c.rs +++ b/examples/i2c.rs @@ -22,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, 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/spi-dma.rs b/examples/spi-dma.rs index 318ab48f..5e2cd299 100644 --- a/examples/spi-dma.rs +++ b/examples/spi-dma.rs @@ -6,7 +6,6 @@ use crate::hal::{ delay::DelayFromCountDownTimer, - gpio::{AF5, PA5, PA6, PA7}, prelude::*, pwr::PwrExt, rcc::Config, @@ -40,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 = Some(gpioa.pa5); + let miso = Some(gpioa.pa6); + let mosi = Some(gpioa.pa7); let spi = dp .SPI1 diff --git a/examples/spi-example.rs b/examples/spi-example.rs index 34194167..3d520b40 100644 --- a/examples/spi-example.rs +++ b/examples/spi-example.rs @@ -41,9 +41,12 @@ fn main() -> ! { 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 spi = dp.SPI1.spi( + (Some(sclk), Some(miso), Some(mosi)), + spi::MODE_0, + 400.kHz(), + &mut rcc, + ); let mut cs = gpioa.pa8.into_push_pull_output(); cs.set_high(); diff --git a/examples/spi-sd.rs b/examples/spi-sd.rs index 46e10df2..3dc80386 100644 --- a/examples/spi-sd.rs +++ b/examples/spi-sd.rs @@ -43,9 +43,12 @@ fn main() -> ! { let miso: PB14 = gpiob.pb14.into_alternate(); let mosi: PB15 = gpiob.pb15.into_alternate(); - let spi = dp - .SPI2 - .spi((sck, miso, mosi), spi::MODE_0, 400.kHz(), &mut rcc); + let spi = dp.SPI2.spi( + (Some(sck), Some(miso), Some(mosi)), + spi::MODE_0, + 400.kHz(), + &mut rcc, + ); struct Clock; diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs index 4b26d3fc..bf09f681 100644 --- a/examples/uart-dma-rx.rs +++ b/examples/uart-dma-rx.rs @@ -42,14 +42,13 @@ fn main() -> ! { //let rx = gpioa.pa3.into_alternate(); let gpioc = dp.GPIOC.split(&mut rcc); let tx = gpioc.pc10.into_alternate(); - let rx = gpioc.pc11.into_alternate(); + let rx = gpioc.pc11; let usart = dp //.USART2 .USART3 .usart( - tx, - rx, + (tx, rx), FullConfig::default() .baudrate(115200.bps()) .receiver_timeout_us(1000), // Timeout after 1ms diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index c52b10e6..a79e28dc 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -10,7 +10,6 @@ use core::fmt::Write; use hal::dma::{channel::DMAExt, config::DmaConfig, TransferExt}; use hal::prelude::*; use hal::pwr::PwrExt; -use hal::serial::*; use hal::time::ExtU32; use hal::{rcc, stm32}; use stm32g4xx_hal as hal; @@ -41,16 +40,8 @@ fn main() -> ! { info!("Init UART"); let gpioa = dp.GPIOA.split(&mut rcc); let tx = gpioa.pa2.into_alternate(); - let rx = gpioa.pa3.into_alternate(); - let mut usart = dp - .USART2 - .usart( - tx, - rx, - FullConfig::default().baudrate(115200.bps()), - &mut rcc, - ) - .unwrap(); + let rx = gpioa.pa3; + let mut usart = dp.USART2.usart((tx, rx), 115200.bps(), &mut rcc).unwrap(); let mut delay_syst = cp.SYST.delay(&rcc.clocks); let mut led = gpioa.pa5.into_push_pull_output(); diff --git a/examples/uart-fifo.rs b/examples/uart-fifo.rs index 801ae471..eb1da3b3 100644 --- a/examples/uart-fifo.rs +++ b/examples/uart-fifo.rs @@ -36,8 +36,7 @@ fn main() -> ! { let mut usart = dp .USART2 .usart( - tx, - rx, + (tx, rx), FullConfig::default() .baudrate(115200.bps()) .fifo_enable() diff --git a/examples/uart.rs b/examples/uart.rs index e4ec6519..9cd645dd 100644 --- a/examples/uart.rs +++ b/examples/uart.rs @@ -40,7 +40,7 @@ fn main() -> ! { let rx = gpioc.pc5.into_alternate(); let mut usart = dp .USART1 - .usart(tx, rx, FullConfig::default(), &mut rcc) + .usart((tx, rx), FullConfig::default(), &mut rcc) .unwrap();*/ let gpioc = dp.GPIOC.split(&mut rcc); @@ -48,7 +48,7 @@ fn main() -> ! { let rx = gpioc.pc11.into_alternate(); let mut usart = dp .USART3 - .usart(tx, rx, FullConfig::default(), &mut rcc) + .usart((tx, rx), FullConfig::default(), &mut rcc) .unwrap(); writeln!(usart, "Hello USART3, yay!!\r\n").unwrap(); diff --git a/src/comparator.rs b/src/comparator.rs index e5603f4e..1490e928 100644 --- a/src/comparator.rs +++ b/src/comparator.rs @@ -9,7 +9,7 @@ use core::marker::PhantomData; use crate::dac; use crate::exti::{Event as ExtiEvent, ExtiExt}; -use crate::gpio::{self, Analog, OpenDrain, Output, PushPull, SignalEdge}; +use crate::gpio::{self, alt::CompOutput, Analog, SignalEdge}; use crate::rcc::{Clocks, Rcc}; use crate::stasis; @@ -157,28 +157,13 @@ positive_input_pin!(COMP2, PA7, PA3); positive_input_pin!(COMP3, PA0, PC1); positive_input_pin!(COMP4, PB0, PE7); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp5")] positive_input_pin!(COMP5, PB13, PD12); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp6")] positive_input_pin!(COMP6, PB11, PD11); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] positive_input_pin!(COMP7, PB14, PD14); macro_rules! negative_input_pin_helper { @@ -207,12 +192,7 @@ negative_input_pin! { COMP4: gpio::PE8, gpio::PB2, } -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] negative_input_pin! { COMP5: gpio::PB10, gpio::PD13, COMP6: gpio::PD10, gpio::PB15, @@ -273,12 +253,7 @@ macro_rules! refint_input { refint_input!(COMP1, COMP2, COMP3, COMP4,); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] refint_input!(COMP5, COMP6, COMP7,); macro_rules! dac_input_helper { @@ -312,49 +287,19 @@ dac_input!(COMP3: Dac1Ch1, 0b101); dac_input!(COMP4: Dac3Ch2, 0b100); dac_input!(COMP4: Dac1Ch1, 0b101); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp5")] dac_input!(COMP5: Dac4Ch1, 0b100); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp5")] dac_input!(COMP5: Dac1Ch2, 0b101); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp6")] dac_input!(COMP6: Dac4Ch2, 0b100); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp6")] dac_input!(COMP6: Dac2Ch1, 0b101); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] dac_input!(COMP7: Dac4Ch1, 0b100); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] dac_input!(COMP7: Dac2Ch1, 0b101); pub struct Comparator { @@ -400,14 +345,10 @@ macro_rules! impl_comparator { let voltage_scaler_delay = clocks.sys_clk.raw() / (1_000_000 / 200); // 200us cortex_m::asm::delay(voltage_scaler_delay); self.csr().modify(|_, w| unsafe { - w.hyst() - .bits(config.hysteresis as u8) - .scalen() - .bit(NP::USE_VREFINT) - .brgen() - .bit(NP::USE_RESISTOR_DIVIDER) - .pol() - .bit(config.inverted) + w.hyst().bits(config.hysteresis as u8); + w.scalen().bit(NP::USE_VREFINT); + w.brgen().bit(NP::USE_RESISTOR_DIVIDER); + w.pol().bit(config.inverted) }); Comparator { @@ -492,60 +433,37 @@ macro_rules! impl_comparator { pub fn unpend(&self, exti: &EXTI) { exti.unpend($Event); } - - /// Configures a GPIO pin to output the signal of the comparator - /// - /// Multiple GPIO pins may be configured as the output simultaneously. - pub fn output_pin>(&self, pin: P) { - pin.setup(); - } } }; } +impl Comparator { + /// Configures a GPIO pin to output the signal of the comparator + /// + /// Multiple GPIO pins may be configured as the output simultaneously. + pub fn output_pin(&self, pin: impl Into>) { + let _pin = pin.into(); + } +} + impl_comparator!(COMP1, comp1, ExtiEvent::COMP1); impl_comparator!(COMP2, comp2, ExtiEvent::COMP2); impl_comparator!(COMP3, comp1, ExtiEvent::COMP3); impl_comparator!(COMP4, comp2, ExtiEvent::COMP4); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp5")] impl_comparator!(COMP5, comp1, ExtiEvent::COMP5); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp6")] impl_comparator!(COMP6, comp2, ExtiEvent::COMP6); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] impl_comparator!(COMP7, comp2, ExtiEvent::COMP7); -#[cfg(not(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -)))] +#[cfg(not(feature = "comp7"))] type Comparators = (COMP1, COMP2, COMP3, COMP4); -#[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" -))] +#[cfg(feature = "comp7")] type Comparators = (COMP1, COMP2, COMP3, COMP4, COMP5, COMP6, COMP7); /// Enables the comparator peripheral, and splits the [`COMP`] into independent [`COMP1`] and [`COMP2`] @@ -562,26 +480,11 @@ pub fn split(_comp: COMP, rcc: &mut Rcc) -> Comparators { COMP2 { _rb: PhantomData }, COMP3 { _rb: PhantomData }, COMP4 { _rb: PhantomData }, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" - ))] + #[cfg(feature = "comp5")] COMP5 { _rb: PhantomData }, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" - ))] + #[cfg(feature = "comp6")] COMP6 { _rb: PhantomData }, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g483", - feature = "stm32g474", - feature = "stm32g484" - ))] + #[cfg(feature = "comp7")] COMP7 { _rb: PhantomData }, ) } @@ -596,56 +499,3 @@ impl ComparatorSplit for COMP { split(self, rcc) } } - -pub trait OutputPin { - fn setup(self); -} - -#[allow(unused_macros)] // TODO: add support for more devices -macro_rules! output_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:literal,)+) => {$( - output_pin!($COMP, $pin, $AF, PushPull, into_alternate); - output_pin!($COMP, $pin, $AF, OpenDrain, into_alternate_open_drain); - )+}; -} - -output_pin! { - 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(feature = "gpio-g47x")] -output_pin! { - COMP1: PF4, 2, - - COMP5: PA9, 8, - COMP5: PC7, 7, - - COMP6: PA10, 8, - COMP6: PC6, 7, - - COMP7: PA8, 8, - COMP7: PC8, 7, -} diff --git a/src/dma/transfer.rs b/src/dma/transfer.rs index bf1828a7..d6c81a38 100644 --- a/src/dma/transfer.rs +++ b/src/dma/transfer.rs @@ -483,7 +483,7 @@ where macro_rules! impl_serial_timeout { ($($uart:ident, )*) => {$( - impl CircTransfer, BUF> + impl CircTransfer, BUF> where CHANNEL: Channel, /*BUF: StaticWriteBuffer + Deref*/ { diff --git a/src/gpio.rs b/src/gpio.rs index 7923142d..d6a828b0 100644 --- a/src/gpio.rs +++ b/src/gpio.rs @@ -58,6 +58,7 @@ use core::marker::PhantomData; use crate::pac; use crate::rcc::Rcc; +pub mod alt; mod convert; pub use convert::PinMode; mod partially_erased; @@ -76,16 +77,6 @@ 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 { /// The parts to split the GPIO into @@ -172,6 +163,8 @@ pub(crate) mod marker { /// 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 {} } @@ -186,6 +179,9 @@ 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))] @@ -623,9 +619,13 @@ const fn gpiox() -> *const crate::pac::gpioa::RegisterBlock { '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"), } diff --git a/src/gpio/alt.rs b/src/gpio/alt.rs new file mode 100644 index 00000000..9cb9001b --- /dev/null +++ b/src/gpio/alt.rs @@ -0,0 +1,378 @@ +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 [$( + $(#[$attr:meta])* $PX:ident<$A:literal $(, Speed::$Speed:ident)?>, + )*],)*) => { + $( + #[derive(Debug)] + $(#[$docs])* + pub enum $name { + $( + $(#[$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, )* } + } + + $( + $(#[$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 [$( + $(#[$attr:meta])* $PX:ident<$A:literal>, + )*],)*) => { + $( + #[derive(Debug)] + $(#[$docs])* + pub enum $name { + $( + $(#[$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, )* } + } + + $( + $(#[$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; +} + +/// Comparator pins +pub trait CompOutput { + /// Output pin + type Out; +} + +// 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..51b2048b --- /dev/null +++ b/src/gpio/alt/g4.rs @@ -0,0 +1,2093 @@ +use super::*; +use crate::gpio::{self, 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! { + default:PushPull for [ + PA0<8>, + PA6<8>, + PA11<8>, + PB8<8>, + #[cfg(feature = "gpio-g47x")] + PF4<2>, + ], + } + impl CompOutput for crate::comparator::COMP1 { + type Out = Out; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp2 { + use super::*; + + pin! { + default:PushPull for [ + PA2<8>, + PA7<8>, + PA12<8>, + PB9<8>, + ], + } + impl CompOutput for crate::comparator::COMP2 { + type Out = Out; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp3 { + use super::*; + + pin! { + default:PushPull for [ + PB7<8>, + PB15<3>, + PC2<3>, + ], + } + + impl CompOutput for crate::comparator::COMP3 { + type Out = Out; + } +} + +#[cfg(any(feature = "gpio-g43x", feature = "gpio-g47x", feature = "gpio-g49x"))] +pub mod comp4 { + use super::*; + + pin! { + default:PushPull for [ + PB1<8>, + PB6<8>, + PB14<8>, + ], + } + impl CompOutput for crate::comparator::COMP4 { + type Out = Out; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp5 { + use super::*; + + pin! { + default:PushPull for [ + PA9<8>, + PC7<7>, + ], + } + impl CompOutput for crate::comparator::COMP5 { + type Out = Out; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp6 { + use super::*; + + pin! { + default:PushPull for [ + PA10<8>, + PC6<7>, + ], + } + + impl CompOutput for crate::comparator::COMP6 { + type Out = Out; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod comp7 { + use super::*; + + pin! { + default:PushPull for [ + PA8<8>, + PC8<7>, + ], + } + + impl CompOutput for crate::comparator::COMP7 { + type Out = Out; + } +} + +#[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 [ + PA11<9>, + PB8<9>, + PD0<9>, + ], + for [ + 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 [ + PB5<9>, + PB12<9>, + ], + for [ + PB6<9>, + PB13<9>, + ], + } + + impl CanCommon for crate::pac::FDCAN2 { + type Rx = Rx; + type Tx = Tx; + } +} + +#[cfg(feature = "gpio-g47x")] +pub mod fdcan3 { + use super::*; + + pin! { + for [ + PA8<11>, + PB3<11>, + ], + for [ + 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 [ + 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 [ + 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 [ + PA3<12>, + PB10<8>, + PC0<8>, + #[cfg(feature = "gpio-g47x")] + PG8<8>, + ], + default:PushPull for [ + PA2<12>, + PB11<8>, + PC1<8>, + #[cfg(feature = "gpio-g47x")] + PG7<8>, + ], + } + + use crate::pac::LPUART1 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 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 [ + PA6<5>, + PB4<5>, + #[cfg(feature = "gpio-g47x")] + PG3<5>, + ], + for [ + PA7<5>, + PB5<5>, + #[cfg(feature = "gpio-g47x")] + PG4<5>, + ], + for [ + PA4<5>, + PA15<5>, + #[cfg(feature = "gpio-g47x")] + PG5<5>, + ], + for [ + 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 [ + PA10<5>, + PB14<5>, + ], + for [ + PA11<5>, + PB15<5>, + ], + for [ + PB12<5>, + PD15<6>, + PF0<5>, + ], + for [ + 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 [ + PB4<6>, + PC11<6>, + ], + for [ + PB5<6>, + PC12<6>, + ], + for [ + PA4<6>, + PA15<6>, + ], + for [ + 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 [ + PE5<5>, + PE13<5>, + ], + for [ + PE6<5>, + PE14<5>, + ], + for [ + PE3<5>, + PE4<5>, + PE11<5>, + ], + for [ + 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 [ + PC11<5>, + ], + default:PushPull for [ + 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 [ + PD2<5>, + ], + default:PushPull for [ + 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 [ + PA10<7>, + PB7<7>, + PC5<7>, + PE1<7>, + ], + default:PushPull for [ + 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 [ + PA3<7>, + PA15<7>, + PB4<7>, + PD6<7>, + ], + default:PushPull for [ + 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 [ + PB8<7>, + PB11<7>, + PC11<7>, + PD9<7>, + PE15<7>, + ], + default:PushPull for [ + 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/i2c.rs b/src/i2c.rs index 272af5bb..600ac482 100644 --- a/src/i2c.rs +++ b/src/i2c.rs @@ -3,19 +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::{self, OpenDrain}; -use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; -#[cfg(any( - 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}; use crate::time::Hertz; use core::cmp; use core::convert::TryInto; +use core::ops::Deref; /// I2C bus configuration. #[derive(Debug, Clone, Copy)] @@ -109,18 +105,23 @@ impl From for Config { } } -/// I2C abstraction -pub struct I2c { - i2c: I2C, - sda: SDA, - scl: SCL, +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))] @@ -146,17 +147,26 @@ impl embedded_hal::i2c::Error for Error { } } -pub trait I2cExt { - fn i2c( +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: SDA, - scl: SCL, + sda: impl Into, + scl: impl Into, config: impl Into, rcc: &mut Rcc, - ) -> I2c - where - SDA: SDAPin, - SCL: SCLPin; + ) -> I2c { + I2c::new(self, sda, scl, config, rcc) + } } /// Sequence to flush the TXDR register. This resets the TXIS and TXE flags @@ -200,351 +210,228 @@ macro_rules! busy_wait { }; } -macro_rules! i2c { - ($I2CX:ident, $i2cx:ident, - sda: [ $($( #[ $pmetasda:meta ] )* $PSDA:ident<$AFDA:ident>,)+ ], - scl: [ $($( #[ $pmetascl:meta ] )* $PSCL:ident<$AFCL:ident>,)+ ], - ) => { - $( - $( #[ $pmetasda ] )* - impl SDAPin<$I2CX> for gpio::$PSDA> {} - )+ - - $( - $( #[ $pmetascl ] )* - impl SCLPin<$I2CX> for gpio::$PSCL> {} - )+ - - impl I2cExt<$I2CX> for $I2CX { - fn i2c( - self, - sda: SDA, - scl: SCL, - config: impl Into, - 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 + I2C::enable(rcc); + I2C::reset(rcc); + + // 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)); + + // Enable the I2C processing + i2c.cr1().modify(|_, w| { + w.pe().set_bit(); + w.dnf().set(config.digital_filter); + w.anfoff().bit(!config.analog_filter) + }); + + I2c { + i2c, + sda: sda.into(), + scl: scl.into(), } + } - 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: impl Into, rcc: &mut Rcc) -> Self - where - SDA: SDAPin<$I2CX>, - SCL: SCLPin<$I2CX>, - { - let config = config.into(); - // Enable and reset I2C - $I2CX::enable(rcc); - $I2CX::reset(rcc); - - // 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(<$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) - }); - - 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 { + I2C::reset_unchecked(); + I2C::disable_unchecked(); + } - /// Disables I2C and releases the peripheral as well as the pins. - pub fn release(self) -> ($I2CX, SDA, SCL) { - // Disable I2C. - unsafe { - $I2CX::reset_unchecked(); - $I2CX::disable_unchecked(); + (self.i2c, self.sda, self.scl) + } +} + +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); } + } + + // 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()); - 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(()) + 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 = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF6, - ], -); - -i2c!( - I2C3, - i2c3, - sda: [ - PB5, - PC11, - PC9, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF4, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG8, - ], - scl: [ - PA8, - PC8, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PF3, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG7, - ], -); - -#[cfg(any( - 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/serial/config.rs b/src/serial/config.rs index 3531b71a..619ebdac 100644 --- a/src/serial/config.rs +++ b/src/serial/config.rs @@ -68,6 +68,12 @@ pub struct LowPowerConfig { pub(crate) rx_fifo_interrupt: bool, } +impl From for LowPowerConfig { + fn from(value: Bps) -> Self { + Self::default().baudrate(value) + } +} + #[derive(PartialEq, PartialOrd, Clone, Copy)] pub struct FullConfig { pub(crate) baudrate: Bps, @@ -84,6 +90,12 @@ pub struct FullConfig { pub(crate) receiver_timeout: Option, } +impl From for FullConfig { + fn from(value: Bps) -> Self { + Self::default().baudrate(value) + } +} + impl LowPowerConfig { pub fn baudrate(mut self, baudrate: Bps) -> Self { self.baudrate = baudrate; diff --git a/src/serial/usart.rs b/src/serial/usart.rs index e31755ff..fcbf2970 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -4,7 +4,7 @@ use core::marker::PhantomData; use crate::dma::{ mux::DmaMuxResources, traits::TargetAddress, MemoryToPeripheral, PeripheralToMemory, }; -use crate::gpio::{self, OpenDrain}; +use crate::gpio::{self, PushPull}; use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; use crate::stm32::*; @@ -86,36 +86,31 @@ impl Event { } } +pub use gpio::alt::SerialAsync as CommonPins; + +// Implemented by all USART/UART instances +pub trait Instance: crate::Sealed + crate::Ptr + Enable + Reset + CommonPins {} + /// Serial receiver -pub struct Rx { - pin: Pin, - _usart: PhantomData, +pub struct Rx { + pin: USART::Rx, + usart: USART, _dma: PhantomData, } /// Serial transmitter -pub struct Tx { - pin: Pin, +pub struct Tx { + pin: USART::Tx, usart: USART, _dma: PhantomData, } /// Serial abstraction -pub struct Serial { - tx: Tx, - rx: Rx, +pub struct Serial { + tx: Tx, + rx: Rx, } -/// Serial TX pin -pub trait TxPin {} - -/// Serial RX pin -pub trait RxPin {} - -pub struct NoTx; - -impl TxPin for NoTx {} - /// Type state for Tx/Rx, indicating operation without DMA #[derive(Debug)] pub struct NoDMA; @@ -123,20 +118,16 @@ pub struct NoDMA; #[derive(Debug)] pub struct DMA; -pub trait SerialExt { - fn usart( +pub trait SerialExt: Sized + Instance { + fn usart( self, - tx: TX, - rx: RX, - config: Config, + pins: (impl Into>, impl Into>), + config: impl Into, rcc: &mut Rcc, - ) -> Result, InvalidConfig> - where - TX: TxPin, - RX: RxPin; + ) -> Result, InvalidConfig>; } -impl fmt::Write for Serial +impl fmt::Write for Serial where Self: embedded_hal_old::serial::Write, >::Error: Debug, @@ -149,7 +140,7 @@ where } } -impl fmt::Write for Tx +impl fmt::Write for Tx where Self: embedded_hal_old::serial::Write, >::Error: Debug, @@ -163,26 +154,10 @@ where } macro_rules! uart_shared { - ($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident, - tx: [ $($( #[ $pmeta1:meta ] )* ($PTX:ident, $TAF:ident),)+ ], - rx: [ $($( #[ $pmeta2:meta ] )* ($PRX:ident, $RAF:ident),)+ ]) => { - - $( - $( #[ $pmeta1 ] )* - impl TxPin<$USARTX> for gpio::$PTX { - } - $( #[ $pmeta1 ] )* - impl TxPin<$USARTX> for gpio::$PTX> { - } - )+ - - $( - $( #[ $pmeta2 ] )* - impl RxPin<$USARTX> for gpio::$PRX { - } - )+ + ($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident) => { + impl Instance for $USARTX {} - impl Rx<$USARTX, Pin, Dma> { + impl Rx<$USARTX, Dma> { /// Starts listening for an interrupt event pub fn listen(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; @@ -208,8 +183,8 @@ macro_rules! uart_shared { } } - impl Rx<$USARTX, Pin, NoDMA> { - pub fn enable_dma(self) -> Rx<$USARTX, Pin, DMA> { + impl Rx<$USARTX, NoDMA> { + pub fn enable_dma(self) -> Rx<$USARTX, DMA> { // NOTE(unsafe) critical section prevents races cortex_m::interrupt::free(|_| unsafe { let cr3 = &(*$USARTX::ptr()).cr3(); @@ -218,37 +193,35 @@ macro_rules! uart_shared { Rx { pin: self.pin, - _usart: PhantomData, + usart: self.usart, _dma: PhantomData, } } fn data_ready(&mut self) -> nb::Result<(), Error> { let usart = unsafe { &(*$USARTX::ptr()) }; let isr = usart.isr().read(); - Err( - if isr.pe().bit_is_set() { - usart.icr().write(|w| w.pecf().clear()); - nb::Error::Other(Error::Parity) - } else if isr.fe().bit_is_set() { - usart.icr().write(|w| w.fecf().clear()); - nb::Error::Other(Error::Framing) - } else if isr.nf().bit_is_set() { - usart.icr().write(|w| w.ncf().clear()); - nb::Error::Other(Error::Noise) - } else if isr.ore().bit_is_set() { - usart.icr().write(|w| w.orecf().clear()); - nb::Error::Other(Error::Overrun) - } else if isr.rxne().bit_is_set() { - return Ok(()) - } else { - nb::Error::WouldBlock - } - ) - } - } - - impl Rx<$USARTX, Pin, DMA> { - pub fn disable_dma(self) -> Rx<$USARTX, Pin, NoDMA> { + Err(if isr.pe().bit_is_set() { + usart.icr().write(|w| w.pecf().clear()); + nb::Error::Other(Error::Parity) + } else if isr.fe().bit_is_set() { + usart.icr().write(|w| w.fecf().clear()); + nb::Error::Other(Error::Framing) + } else if isr.nf().bit_is_set() { + usart.icr().write(|w| w.ncf().clear()); + nb::Error::Other(Error::Noise) + } else if isr.ore().bit_is_set() { + usart.icr().write(|w| w.orecf().clear()); + nb::Error::Other(Error::Overrun) + } else if isr.rxne().bit_is_set() { + return Ok(()); + } else { + nb::Error::WouldBlock + }) + } + } + + impl Rx<$USARTX, DMA> { + pub fn disable_dma(self) -> Rx<$USARTX, NoDMA> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { let cr3 = &(*$USARTX::ptr()).cr3(); @@ -257,13 +230,13 @@ macro_rules! uart_shared { Rx { pin: self.pin, - _usart: PhantomData, + usart: self.usart, _dma: PhantomData, } } } - impl embedded_hal_old::serial::Read for Rx<$USARTX, Pin, NoDMA> { + impl embedded_hal_old::serial::Read for Rx<$USARTX, NoDMA> { type Error = Error; fn read(&mut self) -> nb::Result { @@ -272,7 +245,7 @@ macro_rules! uart_shared { } } - impl embedded_hal_old::serial::Read for Serial<$USARTX, TX, RX> { + impl embedded_hal_old::serial::Read for Serial<$USARTX, Otype> { type Error = Error; fn read(&mut self) -> nb::Result { @@ -280,7 +253,7 @@ macro_rules! uart_shared { } } - impl Tx<$USARTX, Pin, Dma> { + impl Tx<$USARTX, Dma, Otype> { /// Starts listening for an interrupt event pub fn listen(&mut self) { let usart = unsafe { &(*$USARTX::ptr()) }; @@ -306,8 +279,8 @@ macro_rules! uart_shared { } } - impl Tx<$USARTX, Pin, NoDMA> { - pub fn enable_dma(self) -> Tx<$USARTX, Pin, DMA> { + impl Tx<$USARTX, NoDMA, Otype> { + pub fn enable_dma(self) -> Tx<$USARTX, DMA, Otype> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { let cr3 = &(*$USARTX::ptr()).cr3(); @@ -322,8 +295,8 @@ macro_rules! uart_shared { } } - impl Tx<$USARTX, Pin, DMA> { - pub fn disable_dma(self) -> Tx<$USARTX, Pin, NoDMA> { + impl Tx<$USARTX, DMA, Otype> { + pub fn disable_dma(self) -> Tx<$USARTX, NoDMA, Otype> { // NOTE(unsafe) critical section prevents races interrupt::free(|_| unsafe { let cr3 = &(*$USARTX::ptr()).cr3(); @@ -338,7 +311,7 @@ macro_rules! uart_shared { } } - impl embedded_hal_old::serial::Write for Tx<$USARTX, Pin, NoDMA> { + impl embedded_hal_old::serial::Write for Tx<$USARTX, NoDMA, Otype> { type Error = Error; fn flush(&mut self) -> nb::Result<(), Self::Error> { @@ -361,7 +334,7 @@ macro_rules! uart_shared { } } - impl embedded_hal_old::serial::Write for Serial<$USARTX, TX, RX> { + impl embedded_hal_old::serial::Write for Serial<$USARTX, Otype> { type Error = Error; fn flush(&mut self) -> nb::Result<(), Self::Error> { @@ -373,25 +346,28 @@ macro_rules! uart_shared { } } - impl embedded_io::ErrorType for Tx<$USARTX, Pin, NoDMA> { + impl embedded_io::ErrorType for Tx<$USARTX, NoDMA, Otype> { type Error = Error; } - impl WriteReady for Tx<$USARTX, Pin, NoDMA> { + impl WriteReady for Tx<$USARTX, NoDMA, Otype> { fn write_ready(&mut self) -> Result { let usart = unsafe { &(*$USARTX::ptr()) }; Ok(usart.isr().read().txe().bit_is_set()) } } // writes until fifo (or tdr) is full - impl embedded_io::Write for Tx<$USARTX, Pin, NoDMA> { + impl embedded_io::Write for Tx<$USARTX, NoDMA, Otype> { fn write(&mut self, buf: &[u8]) -> Result { - if buf.len() == 0 { return Ok(0) } + if buf.len() == 0 { + return Ok(0); + } let usart = unsafe { &(*$USARTX::ptr()) }; while !self.write_ready()? { core::hint::spin_loop() } // can't know fifo capacity in advance - let count = buf.into_iter() + let count = buf + .into_iter() .take_while(|_| usart.isr().read().txe().bit_is_set()) .map(|b| usart.tdr().write(|w| unsafe { w.tdr().bits(*b as u16) })) .count(); @@ -403,10 +379,10 @@ macro_rules! uart_shared { } } - impl embedded_io::ErrorType for Rx<$USARTX, Pin, NoDMA> { + impl embedded_io::ErrorType for Rx<$USARTX, NoDMA> { type Error = Error; } - impl ReadReady for Rx<$USARTX, Pin, NoDMA> { + impl ReadReady for Rx<$USARTX, NoDMA> { fn read_ready(&mut self) -> Result { match self.data_ready() { Ok(()) => Ok(true), @@ -415,9 +391,11 @@ macro_rules! uart_shared { } } } - impl embedded_io::Read for Rx<$USARTX, Pin, NoDMA> { + impl embedded_io::Read for Rx<$USARTX, NoDMA> { fn read(&mut self, buf: &mut [u8]) -> Result { - if buf.len() == 0 { return Ok(0) } + if buf.len() == 0 { + return Ok(0); + } let usart = unsafe { &(*$USARTX::ptr()) }; let mut count = 0; @@ -432,15 +410,15 @@ macro_rules! uart_shared { } } - impl embedded_io::ErrorType for Serial<$USARTX, TX, RX> { + impl embedded_io::ErrorType for Serial<$USARTX, Otype> { type Error = Error; } - impl WriteReady for Serial<$USARTX, TX, RX> { + impl WriteReady for Serial<$USARTX, Otype> { fn write_ready(&mut self) -> Result { self.tx.write_ready() } } - impl embedded_io::Write for Serial<$USARTX, TX, RX> { + impl embedded_io::Write for Serial<$USARTX, Otype> { fn write(&mut self, buf: &[u8]) -> Result { embedded_io::Write::write(&mut self.tx, buf) } @@ -448,22 +426,21 @@ macro_rules! uart_shared { embedded_io::Write::flush(&mut self.tx) } } - impl ReadReady for Serial<$USARTX, TX, RX> { + impl ReadReady for Serial<$USARTX, Otype> { fn read_ready(&mut self) -> Result { self.rx.read_ready() } } - impl embedded_io::Read for Serial<$USARTX, TX, RX> { + impl embedded_io::Read for Serial<$USARTX, Otype> { fn read(&mut self, buf: &mut [u8]) -> Result { embedded_io::Read::read(&mut self.rx, buf) } } - impl Serial<$USARTX, TX, RX> { - + impl Serial<$USARTX, Otype> { /// Separates the serial struct into separate channel objects for sending (Tx) and /// receiving (Rx) - pub fn split(self) -> (Tx<$USARTX, TX, NoDMA>, Rx<$USARTX, RX, NoDMA>) { + pub fn split(self) -> (Tx<$USARTX, NoDMA, Otype>, Rx<$USARTX, NoDMA>) { (self.tx, self.rx) } @@ -471,14 +448,8 @@ macro_rules! uart_shared { /// /// This function can be used in combination with `release()` to deinitialize the /// peripheral after it has been split. - pub fn join( - tx: Tx<$USARTX, TX, NoDMA>, - rx: Rx<$USARTX, RX, NoDMA>, - ) -> Self { - Serial{ - tx, - rx, - } + pub fn join(tx: Tx<$USARTX, NoDMA, Otype>, rx: Rx<$USARTX, NoDMA>) -> Self { + Serial { tx, rx } } /// Disables the USART and returns the peripheral as well the pins. @@ -486,7 +457,13 @@ macro_rules! uart_shared { /// This function makes the components available for further use. For example, the /// USART can later be reinitialized with a different baud rate or other configuration /// changes. - pub fn release(self) -> ($USARTX, TX, RX) { + pub fn release( + self, + ) -> ( + $USARTX, + <$USARTX as CommonPins>::Tx, + <$USARTX as CommonPins>::Rx, + ) { // Disable the UART as well as its clock. self.tx.usart.cr1().modify(|_, w| w.ue().clear_bit()); unsafe { @@ -496,7 +473,7 @@ macro_rules! uart_shared { } } - unsafe impl TargetAddress for Tx<$USARTX, Pin, DMA> { + unsafe impl TargetAddress for Tx<$USARTX, DMA, Otype> { #[inline(always)] fn address(&self) -> u32 { // unsafe: only the Tx part accesses the Tx register @@ -508,7 +485,7 @@ macro_rules! uart_shared { const REQUEST_LINE: Option = Some(DmaMuxResources::$dmamux_tx as u8); } - unsafe impl TargetAddress for Rx<$USARTX, Pin, DMA> { + unsafe impl TargetAddress for Rx<$USARTX, DMA> { #[inline(always)] fn address(&self) -> u32 { // unsafe: only the Rx part accesses the Rx register @@ -519,41 +496,36 @@ macro_rules! uart_shared { const REQUEST_LINE: Option = Some(DmaMuxResources::$dmamux_rx as u8); } - } + }; } macro_rules! uart_lp { ($USARTX:ident, $usartX:ident, $clk_mul:expr ) => { - impl SerialExt<$USARTX, LowPowerConfig> for $USARTX { - fn usart( + impl SerialExt for $USARTX { + fn usart( self, - tx: TX, - rx: RX, - config: LowPowerConfig, + pins: (impl Into>, impl Into>), + config: impl Into, rcc: &mut Rcc, - ) -> Result, InvalidConfig> - where - TX: TxPin<$USARTX>, - RX: RxPin<$USARTX>, - { - Serial::$usartX(self, tx, rx, config, rcc) + ) -> Result, InvalidConfig> { + Serial::$usartX(self, pins, config, rcc) } } - impl Serial<$USARTX, TX, RX> - where - TX: TxPin<$USARTX>, - RX: RxPin<$USARTX>, - { + impl Serial<$USARTX, Otype> { pub fn $usartX( usart: $USARTX, - tx: TX, - rx: RX, - config: LowPowerConfig, + pins: ( + impl Into<<$USARTX as CommonPins>::Tx>, + impl Into<<$USARTX as CommonPins>::Rx>, + ), + config: impl Into, rcc: &mut Rcc, ) -> Result { + let config = config.into(); + // Enable clock for USART $USARTX::enable(rcc); $USARTX::reset(rcc); @@ -577,52 +549,38 @@ macro_rules! uart_lp { usart.cr3().reset(); usart.cr2().write(|w| unsafe { - w.stop() - .bits(config.stopbits.bits()) - .swap() - .bit(config.swap) + w.stop().bits(config.stopbits.bits()); + w.swap().bit(config.swap) }); usart.cr3().write(|w| unsafe { - w.txftcfg() - .bits(config.tx_fifo_threshold.bits()) - .rxftcfg() - .bits(config.rx_fifo_threshold.bits()) - .txftie() - .bit(config.tx_fifo_interrupt) - .rxftie() - .bit(config.rx_fifo_interrupt) + w.txftcfg().bits(config.tx_fifo_threshold.bits()); + w.rxftcfg().bits(config.rx_fifo_threshold.bits()); + w.txftie().bit(config.tx_fifo_interrupt); + w.rxftie().bit(config.rx_fifo_interrupt) }); // Enable the UART and perform remaining configuration. usart.cr1().write(|w| { - w.ue() - .set_bit() - .te() - .set_bit() - .re() - .set_bit() - .m0() - .bit(config.wordlength == WordLength::DataBits9) - .m1() - .bit(config.wordlength == WordLength::DataBits7) - .pce() - .bit(config.parity != Parity::ParityNone) - .ps() - .bit(config.parity == Parity::ParityOdd) - .fifoen() - .bit(config.fifo_enable) + w.ue().set_bit(); + w.te().set_bit(); + w.re().set_bit(); + w.m0().bit(config.wordlength == WordLength::DataBits9); + w.m1().bit(config.wordlength == WordLength::DataBits7); + w.pce().bit(config.parity != Parity::ParityNone); + w.ps().bit(config.parity == Parity::ParityOdd); + w.fifoen().bit(config.fifo_enable) }); Ok(Serial { tx: Tx { - pin: tx, + pin: pins.0.into(), usart, _dma: PhantomData, }, rx: Rx { - pin: rx, - _usart: PhantomData, + pin: pins.1.into(), + usart: unsafe { $USARTX::steal() }, _dma: PhantomData, }, }) @@ -670,34 +628,29 @@ macro_rules! uart_full { ($USARTX:ident, $usartX:ident ) => { - impl SerialExt<$USARTX, FullConfig> for $USARTX { - fn usart( + impl SerialExt for $USARTX { + fn usart( self, - tx: TX, - rx: RX, - config: FullConfig, + pins: (impl Into>, impl Into>), + config: impl Into, rcc: &mut Rcc, - ) -> Result, InvalidConfig> - where - TX: TxPin<$USARTX>, - RX: RxPin<$USARTX>, - { - Serial::$usartX(self, tx, rx, config, rcc) + ) -> Result, InvalidConfig> { + Serial::$usartX(self, pins, config, rcc) } } - impl Serial<$USARTX, TX, RX> - where - TX: TxPin<$USARTX>, - RX: RxPin<$USARTX>, - { + impl Serial<$USARTX, Otype> { pub fn $usartX( usart: $USARTX, - tx: TX, - rx: RX, - config: FullConfig, + pins: ( + impl Into<<$USARTX as CommonPins>::Tx>, + impl Into<<$USARTX as CommonPins>::Rx>, + ), + config: impl Into, rcc: &mut Rcc, ) -> Result { + let config = config.into(); + // Enable clock for USART $USARTX::enable(rcc); $USARTX::reset(rcc); @@ -722,10 +675,8 @@ macro_rules! uart_full { usart.cr3().reset(); usart.cr2().write(|w| unsafe { - w.stop() - .bits(config.stopbits.bits()) - .swap() - .bit(config.swap) + w.stop().bits(config.stopbits.bits()); + w.swap().bit(config.swap) }); if let Some(timeout) = config.receiver_timeout { @@ -735,45 +686,33 @@ macro_rules! uart_full { } usart.cr3().write(|w| unsafe { - w.txftcfg() - .bits(config.tx_fifo_threshold.bits()) - .rxftcfg() - .bits(config.rx_fifo_threshold.bits()) - .txftie() - .bit(config.tx_fifo_interrupt) - .rxftie() - .bit(config.rx_fifo_interrupt) + w.txftcfg().bits(config.tx_fifo_threshold.bits()); + w.rxftcfg().bits(config.rx_fifo_threshold.bits()); + w.txftie().bit(config.tx_fifo_interrupt); + w.rxftie().bit(config.rx_fifo_interrupt) }); // Enable the UART and perform remaining configuration. usart.cr1().modify(|_, w| { - w.ue() - .set_bit() - .te() - .set_bit() - .re() - .set_bit() - .m0() - .bit(config.wordlength == WordLength::DataBits7) - .m1() - .bit(config.wordlength == WordLength::DataBits9) - .pce() - .bit(config.parity != Parity::ParityNone) - .ps() - .bit(config.parity == Parity::ParityOdd) - .fifoen() - .bit(config.fifo_enable) + w.ue().set_bit(); + w.te().set_bit(); + w.re().set_bit(); + w.m0().bit(config.wordlength == WordLength::DataBits7); + w.m1().bit(config.wordlength == WordLength::DataBits9); + w.pce().bit(config.parity != Parity::ParityNone); + w.ps().bit(config.parity == Parity::ParityOdd); + w.fifoen().bit(config.fifo_enable) }); Ok(Serial { tx: Tx { - pin: tx, + pin: pins.0.into(), usart, _dma: PhantomData, }, rx: Rx { - pin: rx, - _usart: PhantomData, + pin: pins.1.into(), + usart: unsafe { $USARTX::steal() }, _dma: PhantomData, }, }) @@ -815,7 +754,7 @@ macro_rules! uart_full { } } - impl Rx<$USARTX, Pin, Dma> { + impl Rx<$USARTX, Dma> { /// Check if receiver timeout has lapsed /// Returns the current state of the ISR RTOF bit pub fn timeout_lapsed(&self) -> bool { @@ -832,88 +771,18 @@ macro_rules! uart_full { }; } -uart_shared!(USART1, USART1_RX, USART1_TX, -tx: [ - (PA9, AF7), - (PB6, AF7), - (PC4, AF7), - (PE0, AF7), - #[cfg(any(feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484"))] - (PG9, AF7), -], -rx: [ - (PA10, AF7), - (PB7, AF7), - (PC5, AF7), - (PE1, AF7), -]); - -uart_shared!(USART2, USART2_RX, USART2_TX, - tx: [ - (PA2, AF7), - (PA14, AF7), - (PB3, AF7), - (PD5, AF7), - ], - rx: [ - (PA3, AF7), - (PA15, AF7), - (PB4, AF7), - (PD6, AF7), - ] -); - -uart_shared!(USART3, USART3_RX, USART3_TX, - tx: [ - (PB9, AF7), - (PB10, AF7), - (PC10, AF7), - (PD8, AF7), - ], - rx: [ - (PB8, AF7), - (PB11, AF7), - (PC11, AF7), - (PD9, AF7), - (PE15, AF7), - ] -); - -uart_shared!(UART4, USART4_RX, USART4_TX, - tx: [ - (PC10, AF5), - ], - rx: [ - (PC11, AF5), - ] -); +uart_shared!(USART1, USART1_RX, USART1_TX); + +uart_shared!(USART2, USART2_RX, USART2_TX); + +uart_shared!(USART3, USART3_RX, USART3_TX); + +uart_shared!(UART4, USART4_RX, USART4_TX); #[cfg(not(any(feature = "stm32g431", feature = "stm32g441")))] -uart_shared!(UART5, USART5_RX, USART5_TX, - tx: [ - (PC12, AF5), - ], - rx: [ - (PD2, AF5), - ] -); - -uart_shared!(LPUART1, LPUART1_RX, LPUART1_TX, - tx: [ - (PA2, AF12), - (PB11, AF8), - (PC1, AF8), - #[cfg(any(feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484"))] - (PG7, AF8), - ], - rx: [ - (PA3, AF12), - (PB10, AF8), - (PC0, AF8), - #[cfg(any(feature = "stm32g473", feature = "stm32g474", feature = "stm32g483", feature = "stm32g484"))] - (PG8, AF8), - ] -); +uart_shared!(UART5, USART5_RX, USART5_TX); + +uart_shared!(LPUART1, LPUART1_RX, LPUART1_TX); uart_full!(USART1, usart1); uart_full!(USART2, usart2); diff --git a/src/spi.rs b/src/spi.rs index 9dd0e5c3..c2be63a5 100644 --- a/src/spi.rs +++ b/src/spi.rs @@ -1,17 +1,13 @@ use crate::dma::mux::DmaMuxResources; use crate::dma::traits::TargetAddress; use crate::dma::MemoryToPeripheral; -use crate::gpio; -use crate::rcc::{Enable, GetBusFreq, Rcc, RccBus, Reset}; -#[cfg(any( - 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::{SPI1, SPI2, SPI3}; use crate::time::Hertz; +use core::ops::Deref; use core::ptr; use embedded_hal::spi::ErrorKind; @@ -38,40 +34,79 @@ 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, + #[allow(clippy::type_complexity)] + pins: (Option, Option, Option), +} + +#[allow(non_upper_case_globals)] +pub trait SpiExt: Instance + Sized { + const NoSck: Option = None; + const NoMiso: Option = None; + const NoMosi: Option = None; + const NoNss: Option = None; + fn spi( + self, + pins: ( + Option>, + Option>, + Option>, + ), + 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: ( + Option>, + Option>, + Option>, + ), + mode: Mode, + freq: Hertz, + rcc: &mut Rcc, + ) -> Spi { + Spi::new(self, pins, mode, freq, rcc) + } } pub trait FrameSize: Copy + Default { @@ -85,388 +120,253 @@ impl FrameSize for u16 { const DFF: bool = true; } -macro_rules! spi { - ($SPIX:ident, $spiX:ident, - sck: [ $($( #[ $pmetasck:meta ] )* $SCK:ident<$ASCK:ident>,)+ ], - miso: [ $($( #[ $pmetamiso:meta ] )* $MISO:ident<$AMISO:ident>,)+ ], - mosi: [ $($( #[ $pmetamosi:meta ] )* $MOSI:ident<$AMOSI:ident>,)+ ], - $mux:expr, - ) => { - impl PinSck<$SPIX> for NoSck {} - - impl PinMiso<$SPIX> for NoMiso {} - - impl PinMosi<$SPIX> for NoMosi {} - - $( - $( #[ $pmetasck ] )* - impl PinSck<$SPIX> for gpio::$SCK {} - )* - $( - $( #[ $pmetamiso ] )* - impl PinMiso<$SPIX> for gpio::$MISO {} - )* - $( - $( #[ $pmetamosi ] )* - impl PinMosi<$SPIX> for gpio::$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 - $SPIX::enable(rcc); - $SPIX::reset(rcc); - - // disable SS output - spi.cr2().write(|w| w.ssoe().disabled()); - - 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| { - w.frxth().quarter().ds().eight_bit().ssoe().disabled() - }); - - spi.cr1().write(|w| unsafe { - w.cpha() - .bit(mode.phase == Phase::CaptureOnSecondTransition) - .cpol() - .bit(mode.polarity == Polarity::IdleHigh) - .mstr() - .master() - .br() - .bits(br) - .lsbfirst() - .msbfirst() - .ssm() - .enabled() - .ssi() - .slave_not_selected() - .rxonly() - .full_duplex() - .crcl() - .eight_bit() - .bidimode() - .unidirectional() - .spe() - .enabled() - }); - - 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().enabled()); - Spi { - spi: self.spi, - pins: self.pins, - } - } +impl Spi { + pub fn new( + spi: SPI, + pins: ( + Option>, + Option>, + Option>, + ), + mode: Mode, + speed: Hertz, + rcc: &mut Rcc, + ) -> Self { + // Enable and reset SPI + SPI::enable(rcc); + SPI::reset(rcc); + + // disable SS output + spi.cr2().write(|w| w.ssoe().disabled()); + + 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| w.frxth().quarter().ds().eight_bit().ssoe().disabled()); + + spi.cr1().write(|w| unsafe { + w.cpha().bit(mode.phase == Phase::CaptureOnSecondTransition); + w.cpol().bit(mode.polarity == Polarity::IdleHigh); + w.mstr().master(); + w.br().bits(br); + w.lsbfirst().msbfirst(); + w.ssm().enabled(); + w.ssi().slave_not_selected(); + w.rxonly().full_duplex(); + w.crcl().eight_bit(); + w.bidimode().unidirectional(); + w.spe().enabled() + }); + + Spi { + spi, + pins: ( + pins.0.map(Into::into), + pins.1.map(Into::into), + pins.2.map(Into::into), + ), } + } - 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().bidirectional().bidioe().output_enabled()); - } - - fn set_bidi(&mut self) { - self.spi - .cr1() - .modify(|_, w| w.bidimode().unidirectional().bidioe().output_disabled()); - } - } + #[allow(clippy::type_complexity)] + pub fn release( + self, + ) -> ( + SPI, + (Option, Option, Option), + ) { + (self.spi, self.pins) + } - 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) - } + pub fn enable_tx_dma(self) -> Spi { + self.spi.cr2().modify(|_, w| w.txdmaen().enabled()); + 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().bidirectional().bidioe().output_enabled()); + } + fn set_bidi(&mut self) { + self.spi + .cr1() + .modify(|_, w| w.bidimode().unidirectional().bidioe().output_disabled()); + } +} + +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().is_empty() { 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().is_empty() { + 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 = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG2, - ], - miso: [ - PA6, - PB4, - #[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG3, - ], - mosi: [ - PA7, - PB5, - #[cfg(any( - 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 = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484" - ))] - PG9, - ], - miso: [ - PB4, - PC11, - ], - mosi: [ - PB5, - PC12, - ], - DmaMuxResources::SPI3_TX, -); - -#[cfg(any( - 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 {} From 93f1d049000386af07422d5dcc5f708368954542 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Tue, 10 Jun 2025 10:14:18 +0300 Subject: [PATCH 2/4] CAN, USART --- examples/can-echo.rs | 2 +- examples/uart-dma-rx.rs | 2 +- examples/uart-dma-tx.rs | 4 +- examples/uart-fifo.rs | 2 +- examples/uart.rs | 6 +- src/can.rs | 176 ++++++++++------------------------------ src/lib.rs | 10 ++- src/serial/usart.rs | 123 ++++++++++++++-------------- 8 files changed, 119 insertions(+), 206 deletions(-) diff --git a/examples/can-echo.rs b/examples/can-echo.rs index 2f8c0890..7720d3d0 100644 --- a/examples/can-echo.rs +++ b/examples/can-echo.rs @@ -61,7 +61,7 @@ fn main() -> ! { let tx = gpiob.pb9.into_alternate().speed(Speed::VeryHigh); info!("-- Create CAN 1 instance"); - let mut can = dp.FDCAN1.fdcan(tx, rx, &mut rcc); + let mut can = dp.FDCAN1.fdcan((tx, rx), &mut rcc); can.set_protocol_exception_handling(false); info!("-- Configure nominal timing"); diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs index bf09f681..d2cd0a26 100644 --- a/examples/uart-dma-rx.rs +++ b/examples/uart-dma-rx.rs @@ -48,7 +48,7 @@ fn main() -> ! { //.USART2 .USART3 .usart( - (tx, rx), + (Some(tx), Some(rx)), FullConfig::default() .baudrate(115200.bps()) .receiver_timeout_us(1000), // Timeout after 1ms diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index a79e28dc..84ee1522 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -39,8 +39,8 @@ fn main() -> ! { info!("Init UART"); let gpioa = dp.GPIOA.split(&mut rcc); - let tx = gpioa.pa2.into_alternate(); - let rx = gpioa.pa3; + let tx = Some(gpioa.pa2.into_alternate()); + let rx = Some(gpioa.pa3); let mut usart = dp.USART2.usart((tx, rx), 115200.bps(), &mut rcc).unwrap(); let mut delay_syst = cp.SYST.delay(&rcc.clocks); diff --git a/examples/uart-fifo.rs b/examples/uart-fifo.rs index eb1da3b3..e2b4b032 100644 --- a/examples/uart-fifo.rs +++ b/examples/uart-fifo.rs @@ -36,7 +36,7 @@ fn main() -> ! { let mut usart = dp .USART2 .usart( - (tx, rx), + (Some(tx), Some(rx)), FullConfig::default() .baudrate(115200.bps()) .fifo_enable() diff --git a/examples/uart.rs b/examples/uart.rs index 9cd645dd..eb878c50 100644 --- a/examples/uart.rs +++ b/examples/uart.rs @@ -33,14 +33,14 @@ fn main() -> ! { let rx = gpioa.pa3.into_alternate(); let mut usart = dp .USART2 - .usart(tx, rx, FullConfig::default(), &mut rcc) + .usart(((Some(tx), Some(rx)), FullConfig::default(), &mut rcc) .unwrap();*/ /*let gpioc = dp.GPIOC.split(&mut rcc); let tx = gpioc.pc4.into_alternate(); let rx = gpioc.pc5.into_alternate(); let mut usart = dp .USART1 - .usart((tx, rx), FullConfig::default(), &mut rcc) + .usart(((Some(tx), Some(rx)), FullConfig::default(), &mut rcc) .unwrap();*/ let gpioc = dp.GPIOC.split(&mut rcc); @@ -48,7 +48,7 @@ fn main() -> ! { let rx = gpioc.pc11.into_alternate(); let mut usart = dp .USART3 - .usart((tx, rx), FullConfig::default(), &mut rcc) + .usart((Some(tx), Some(rx)), FullConfig::default(), &mut rcc) .unwrap(); writeln!(usart, "Hello USART3, yay!!\r\n").unwrap(); diff --git a/src/can.rs b/src/can.rs index 8e89eb14..928a2a60 100644 --- a/src/can.rs +++ b/src/can.rs @@ -1,193 +1,103 @@ //! # Controller Area Network (CAN) Interface //! +use crate::gpio::alt::CanCommon; use crate::rcc::{self, Rcc}; -mod sealed { - /// A TX pin configured for CAN communication - pub trait Tx {} - /// An RX pin configured for CAN communication - pub trait Rx {} -} +pub trait Instance: CanCommon + rcc::Instance + crate::Ptr {} /// Storage type for the CAN controller #[derive(Debug)] -pub struct Can { - rb: FDCAN, +pub struct Can { + rb: CAN, } #[allow(dead_code)] -impl Can { +impl Can { /// Returns a reference to the inner peripheral - fn inner(&self) -> &FDCAN { + fn inner(&self) -> &CAN { &self.rb } } /// Extension trait for CAN controller -pub trait CanExt: Sized +pub trait CanExt: Sized + Instance where - Self: rcc::Instance, Can: fdcan::Instance, { - fn fdcan( + fn fdcan( self, - _tx: TX, - _rx: RX, + pins: (impl Into, impl Into), rcc: &mut Rcc, - ) -> fdcan::FdCan, fdcan::ConfigMode> - where - TX: sealed::Tx, - RX: sealed::Rx, - { + ) -> fdcan::FdCan, fdcan::ConfigMode> { Self::enable(rcc); + let _pins = (pins.0.into(), pins.1.into()); self.fdcan_unchecked() } fn fdcan_unchecked(self) -> fdcan::FdCan, fdcan::ConfigMode>; } -/// 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>),+ $(,)? ])) => { - $( - $( #[ $pmetatx ] )* - impl sealed::Tx<$PER> for $tx<$txaf> {} - )+ - $( - $( #[ $pmetarx ] )* - impl sealed::Rx<$PER> for $rx<$rxaf> {} - )+ - }; + +impl Can +where + Self: fdcan::message_ram::Instance, +{ + pub fn new(rb: CAN) -> fdcan::FdCan { + fdcan::FdCan::new(Self { rb }).into_config_mode() + } +} + +unsafe impl fdcan::Instance for Can +where + Self: fdcan::message_ram::Instance, +{ + const REGISTERS: *mut fdcan::RegisterBlock = CAN::PTR as *mut _; +} + +impl CanExt for CAN +where + Can: fdcan::message_ram::Instance, +{ + fn fdcan_unchecked(self) -> fdcan::FdCan, fdcan::ConfigMode> { + Can::new(self) + } } mod fdcan1 { - use super::sealed; - use super::{Can, CanExt}; - use crate::gpio::{AF9, PA11, PA12, PB8, PB9, PD0, PD1}; + use super::{Can, Instance}; use crate::stm32::FDCAN1; use fdcan; - // All STM32G4 models with CAN support these pins - pins! { - FDCAN1 => ( - tx: [ - PA12, - PB9, - PD1, - ], - rx: [ - PA11, - PB8, - PD0, - ] - ) - } + impl Instance for FDCAN1 {} - impl Can { - pub fn fdcan1(rb: FDCAN1) -> fdcan::FdCan { - fdcan::FdCan::new(Self { rb }).into_config_mode() - } - } - impl CanExt for FDCAN1 { - fn fdcan_unchecked(self) -> fdcan::FdCan, fdcan::ConfigMode> { - Can::fdcan1(self) - } - } - unsafe impl fdcan::Instance for Can { - const REGISTERS: *mut fdcan::RegisterBlock = FDCAN1::ptr() as *mut _; - } unsafe impl fdcan::message_ram::Instance for Can { const MSG_RAM: *mut fdcan::message_ram::RegisterBlock = (0x4000_a400 as *mut _); } } -#[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", - feature = "stm32g491", - feature = "stm32g4a1", -))] +#[cfg(feature = "fdcan2")] mod fdcan2 { - use super::sealed; - use super::{Can, CanExt}; - use crate::gpio::{AF9, PB12, PB13, PB5, PB6}; + use super::{Can, Instance}; use crate::stm32::FDCAN2; use fdcan; use fdcan::message_ram; - pins! { - FDCAN2 => ( - tx: [ - PB6, - PB13, - ], - rx: [ - PB5, - PB12, - ]) - } + impl Instance for FDCAN2 {} - impl Can { - pub fn fdcan2(rb: FDCAN2) -> fdcan::FdCan { - fdcan::FdCan::new(Self { rb }).into_config_mode() - } - } - impl CanExt for FDCAN2 { - fn fdcan_unchecked(self) -> fdcan::FdCan, fdcan::ConfigMode> { - Can::fdcan2(self) - } - } - unsafe impl fdcan::Instance for Can { - const REGISTERS: *mut fdcan::RegisterBlock = FDCAN2::ptr() as *mut _; - } unsafe impl fdcan::message_ram::Instance for Can { const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_a750 as *mut _); } } -#[cfg(any( - feature = "stm32g473", - feature = "stm32g474", - feature = "stm32g483", - feature = "stm32g484", -))] +#[cfg(feature = "fdcan3")] mod fdcan3 { - use super::sealed; - use super::{Can, CanExt}; - use crate::gpio::{AF11, PA15, PA8, PB3, PB4}; + use super::{Can, Instance}; use crate::stm32::FDCAN3; use fdcan; use fdcan::message_ram; - pins! { - FDCAN3 => ( - tx: [ - PA15, - PB4, - ], - rx: [ - PA8, - PB3, - ]) - } + impl Instance for FDCAN3 {} - impl Can { - pub fn fdcan3(rb: FDCAN3) -> fdcan::FdCan { - fdcan::FdCan::new(Self { rb }).into_config_mode() - } - } - impl CanExt for FDCAN3 { - fn fdcan_unchecked(self) -> fdcan::FdCan, fdcan::ConfigMode> { - Can::fdcan3(self) - } - } - unsafe impl fdcan::Instance for Can { - const REGISTERS: *mut fdcan::RegisterBlock = FDCAN3::ptr() as *mut _; - } unsafe impl fdcan::message_ram::Instance for Can { const MSG_RAM: *mut message_ram::RegisterBlock = (0x4000_aaa0 as *mut _); } diff --git a/src/lib.rs b/src/lib.rs index 241cabf3..884d4083 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,15 +107,17 @@ impl Sealed for Periph {} pub trait Ptr: Sealed { /// RegisterBlock structure type RB; + /// Pointer to the register block + const PTR: *const Self::RB; /// Return the pointer to the register block - fn ptr() -> *const Self::RB; + fn ptr() -> *const Self::RB { + Self::PTR + } } impl Ptr for Periph { type RB = RB; - fn ptr() -> *const Self::RB { - Self::ptr() - } + const PTR: *const Self::RB = Self::PTR; } fn stripped_type_name() -> &'static str { diff --git a/src/serial/usart.rs b/src/serial/usart.rs index fcbf2970..4485db96 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -92,15 +92,15 @@ pub use gpio::alt::SerialAsync as CommonPins; pub trait Instance: crate::Sealed + crate::Ptr + Enable + Reset + CommonPins {} /// Serial receiver -pub struct Rx { - pin: USART::Rx, +pub struct Rx { + pin: Option>, usart: USART, _dma: PhantomData, } /// Serial transmitter -pub struct Tx { - pin: USART::Tx, +pub struct Tx { + pin: Option>, usart: USART, _dma: PhantomData, } @@ -118,10 +118,16 @@ pub struct NoDMA; #[derive(Debug)] pub struct DMA; +#[allow(non_upper_case_globals)] pub trait SerialExt: Sized + Instance { + const NoTx: Option> = None; + const NoRx: Option> = None; fn usart( self, - pins: (impl Into>, impl Into>), + pins: ( + Option>>, + Option>>, + ), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig>; @@ -160,35 +166,30 @@ macro_rules! uart_shared { impl Rx<$USARTX, Dma> { /// Starts listening for an interrupt event pub fn listen(&mut self) { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1().modify(|_, w| w.rxneie().set_bit()); + self.usart.cr1().modify(|_, w| w.rxneie().set_bit()); } /// Stop listening for an interrupt event pub fn unlisten(&mut self) { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1().modify(|_, w| w.rxneie().clear_bit()); + self.usart.cr1().modify(|_, w| w.rxneie().clear_bit()); } /// Return true if the rx register is not empty (and can be read) pub fn is_rxne(&self) -> bool { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr().read().rxne().bit_is_set() + self.usart.isr().read().rxne().bit_is_set() } /// Returns true if the rx fifo threshold has been reached. pub fn fifo_threshold_reached(&self) -> bool { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr().read().rxft().bit_is_set() + self.usart.isr().read().rxft().bit_is_set() } } impl Rx<$USARTX, NoDMA> { pub fn enable_dma(self) -> Rx<$USARTX, DMA> { // NOTE(unsafe) critical section prevents races - cortex_m::interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3(); - cr3.modify(|_, w| w.dmar().set_bit()); + cortex_m::interrupt::free(|_| { + self.usart.cr3().modify(|_, w| w.dmar().set_bit()); }); Rx { @@ -198,7 +199,7 @@ macro_rules! uart_shared { } } fn data_ready(&mut self) -> nb::Result<(), Error> { - let usart = unsafe { &(*$USARTX::ptr()) }; + let usart = &self.usart; let isr = usart.isr().read(); Err(if isr.pe().bit_is_set() { usart.icr().write(|w| w.pecf().clear()); @@ -223,9 +224,8 @@ macro_rules! uart_shared { impl Rx<$USARTX, DMA> { pub fn disable_dma(self) -> Rx<$USARTX, NoDMA> { // NOTE(unsafe) critical section prevents races - interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3(); - cr3.modify(|_, w| w.dmar().clear_bit()); + interrupt::free(|_| { + self.usart.cr3().modify(|_, w| w.dmar().clear_bit()); }); Rx { @@ -240,8 +240,8 @@ macro_rules! uart_shared { type Error = Error; fn read(&mut self) -> nb::Result { - let usart = unsafe { &(*$USARTX::ptr()) }; - self.data_ready().map(|_| usart.rdr().read().bits() as u8) + self.data_ready() + .map(|_| self.usart.rdr().read().bits() as u8) } } @@ -256,35 +256,30 @@ macro_rules! uart_shared { impl Tx<$USARTX, Dma, Otype> { /// Starts listening for an interrupt event pub fn listen(&mut self) { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1().modify(|_, w| w.txeie().set_bit()); + self.usart.cr1().modify(|_, w| w.txeie().set_bit()); } /// Stop listening for an interrupt event pub fn unlisten(&mut self) { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.cr1().modify(|_, w| w.txeie().clear_bit()); + self.usart.cr1().modify(|_, w| w.txeie().clear_bit()); } /// Return true if the tx register is empty (and can accept data) pub fn is_txe(&self) -> bool { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr().read().txe().bit_is_set() + self.usart.isr().read().txe().bit_is_set() } /// Returns true if the tx fifo threshold has been reached. pub fn fifo_threshold_reached(&self) -> bool { - let usart = unsafe { &(*$USARTX::ptr()) }; - usart.isr().read().txft().bit_is_set() + self.usart.isr().read().txft().bit_is_set() } } impl Tx<$USARTX, NoDMA, Otype> { pub fn enable_dma(self) -> Tx<$USARTX, DMA, Otype> { // NOTE(unsafe) critical section prevents races - interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3(); - cr3.modify(|_, w| w.dmat().set_bit()); + interrupt::free(|_| { + self.usart.cr3().modify(|_, w| w.dmat().set_bit()); }); Tx { @@ -298,9 +293,8 @@ macro_rules! uart_shared { impl Tx<$USARTX, DMA, Otype> { pub fn disable_dma(self) -> Tx<$USARTX, NoDMA, Otype> { // NOTE(unsafe) critical section prevents races - interrupt::free(|_| unsafe { - let cr3 = &(*$USARTX::ptr()).cr3(); - cr3.modify(|_, w| w.dmat().clear_bit()); + interrupt::free(|_| { + self.usart.cr3().modify(|_, w| w.dmat().clear_bit()); }); Tx { @@ -315,8 +309,7 @@ macro_rules! uart_shared { type Error = Error; fn flush(&mut self) -> nb::Result<(), Self::Error> { - let usart = unsafe { &(*$USARTX::ptr()) }; - if usart.isr().read().tc().bit_is_set() { + if self.usart.isr().read().tc().bit_is_set() { Ok(()) } else { Err(nb::Error::WouldBlock) @@ -324,9 +317,8 @@ macro_rules! uart_shared { } fn write(&mut self, byte: u8) -> nb::Result<(), Self::Error> { - let usart = unsafe { &(*$USARTX::ptr()) }; - if usart.isr().read().txe().bit_is_set() { - usart.tdr().write(|w| unsafe { w.bits(byte as u32) }); + if self.usart.isr().read().txe().bit_is_set() { + self.usart.tdr().write(|w| unsafe { w.bits(byte as u32) }); Ok(()) } else { Err(nb::Error::WouldBlock) @@ -351,8 +343,7 @@ macro_rules! uart_shared { } impl WriteReady for Tx<$USARTX, NoDMA, Otype> { fn write_ready(&mut self) -> Result { - let usart = unsafe { &(*$USARTX::ptr()) }; - Ok(usart.isr().read().txe().bit_is_set()) + Ok(self.usart.isr().read().txe().bit_is_set()) } } // writes until fifo (or tdr) is full @@ -361,15 +352,18 @@ macro_rules! uart_shared { if buf.len() == 0 { return Ok(0); } - let usart = unsafe { &(*$USARTX::ptr()) }; while !self.write_ready()? { core::hint::spin_loop() } // can't know fifo capacity in advance let count = buf .into_iter() - .take_while(|_| usart.isr().read().txe().bit_is_set()) - .map(|b| usart.tdr().write(|w| unsafe { w.tdr().bits(*b as u16) })) + .take_while(|_| self.usart.isr().read().txe().bit_is_set()) + .map(|b| { + self.usart + .tdr() + .write(|w| unsafe { w.tdr().bits(*b as u16) }) + }) .count(); Ok(count) @@ -396,14 +390,13 @@ macro_rules! uart_shared { if buf.len() == 0 { return Ok(0); } - let usart = unsafe { &(*$USARTX::ptr()) }; let mut count = 0; while !self.read_ready()? { core::hint::spin_loop() } while self.read_ready()? && count < buf.len() { - buf[count] = usart.rdr().read().bits() as u8; + buf[count] = self.usart.rdr().read().bits() as u8; count += 1 } Ok(count) @@ -461,15 +454,17 @@ macro_rules! uart_shared { self, ) -> ( $USARTX, - <$USARTX as CommonPins>::Tx, - <$USARTX as CommonPins>::Rx, + ( + Option<<$USARTX as CommonPins>::Tx>, + Option<<$USARTX as CommonPins>::Rx>, + ), ) { // Disable the UART as well as its clock. self.tx.usart.cr1().modify(|_, w| w.ue().clear_bit()); unsafe { $USARTX::disable_unchecked(); } - (self.tx.usart, self.tx.pin, self.rx.pin) + (self.tx.usart, (self.tx.pin, self.rx.pin)) } } @@ -506,7 +501,10 @@ macro_rules! uart_lp { impl SerialExt for $USARTX { fn usart( self, - pins: (impl Into>, impl Into>), + pins: ( + Option>>, + Option>>, + ), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig> { @@ -518,8 +516,8 @@ macro_rules! uart_lp { pub fn $usartX( usart: $USARTX, pins: ( - impl Into<<$USARTX as CommonPins>::Tx>, - impl Into<<$USARTX as CommonPins>::Rx>, + Option::Tx>>, + Option::Rx>>, ), config: impl Into, rcc: &mut Rcc, @@ -574,12 +572,12 @@ macro_rules! uart_lp { Ok(Serial { tx: Tx { - pin: pins.0.into(), + pin: pins.0.map(Into::into), usart, _dma: PhantomData, }, rx: Rx { - pin: pins.1.into(), + pin: pins.1.map(Into::into), usart: unsafe { $USARTX::steal() }, _dma: PhantomData, }, @@ -631,7 +629,10 @@ macro_rules! uart_full { impl SerialExt for $USARTX { fn usart( self, - pins: (impl Into>, impl Into>), + pins: ( + Option>>, + Option>>, + ), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig> { @@ -643,8 +644,8 @@ macro_rules! uart_full { pub fn $usartX( usart: $USARTX, pins: ( - impl Into<<$USARTX as CommonPins>::Tx>, - impl Into<<$USARTX as CommonPins>::Rx>, + Option::Tx>>, + Option::Rx>>, ), config: impl Into, rcc: &mut Rcc, @@ -706,12 +707,12 @@ macro_rules! uart_full { Ok(Serial { tx: Tx { - pin: pins.0.into(), + pin: pins.0.map(Into::into), usart, _dma: PhantomData, }, rx: Rx { - pin: pins.1.into(), + pin: pins.1.map(Into::into), usart: unsafe { $USARTX::steal() }, _dma: PhantomData, }, From 9bcc4a756a943a148ab0b3a5e8df4433c3b90f3b Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Wed, 11 Jun 2025 07:08:31 +0300 Subject: [PATCH 3/4] tx/rx constructors --- examples/uart-dma-rx.rs | 2 +- examples/uart-dma-tx.rs | 4 +- examples/uart-fifo.rs | 2 +- examples/uart.rs | 2 +- src/serial/usart.rs | 87 ++++++++++++++++++++++++++++++++++------- 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/examples/uart-dma-rx.rs b/examples/uart-dma-rx.rs index d2cd0a26..bf09f681 100644 --- a/examples/uart-dma-rx.rs +++ b/examples/uart-dma-rx.rs @@ -48,7 +48,7 @@ fn main() -> ! { //.USART2 .USART3 .usart( - (Some(tx), Some(rx)), + (tx, rx), FullConfig::default() .baudrate(115200.bps()) .receiver_timeout_us(1000), // Timeout after 1ms diff --git a/examples/uart-dma-tx.rs b/examples/uart-dma-tx.rs index 84ee1522..a79e28dc 100644 --- a/examples/uart-dma-tx.rs +++ b/examples/uart-dma-tx.rs @@ -39,8 +39,8 @@ fn main() -> ! { info!("Init UART"); let gpioa = dp.GPIOA.split(&mut rcc); - let tx = Some(gpioa.pa2.into_alternate()); - let rx = Some(gpioa.pa3); + let tx = gpioa.pa2.into_alternate(); + let rx = gpioa.pa3; let mut usart = dp.USART2.usart((tx, rx), 115200.bps(), &mut rcc).unwrap(); let mut delay_syst = cp.SYST.delay(&rcc.clocks); diff --git a/examples/uart-fifo.rs b/examples/uart-fifo.rs index e2b4b032..eb1da3b3 100644 --- a/examples/uart-fifo.rs +++ b/examples/uart-fifo.rs @@ -36,7 +36,7 @@ fn main() -> ! { let mut usart = dp .USART2 .usart( - (Some(tx), Some(rx)), + (tx, rx), FullConfig::default() .baudrate(115200.bps()) .fifo_enable() diff --git a/examples/uart.rs b/examples/uart.rs index eb878c50..8693a37b 100644 --- a/examples/uart.rs +++ b/examples/uart.rs @@ -48,7 +48,7 @@ fn main() -> ! { let rx = gpioc.pc11.into_alternate(); let mut usart = dp .USART3 - .usart((Some(tx), Some(rx)), FullConfig::default(), &mut rcc) + .usart((tx, rx), FullConfig::default(), &mut rcc) .unwrap(); writeln!(usart, "Hello USART3, yay!!\r\n").unwrap(); diff --git a/src/serial/usart.rs b/src/serial/usart.rs index 4485db96..e3282856 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -120,17 +120,24 @@ pub struct DMA; #[allow(non_upper_case_globals)] pub trait SerialExt: Sized + Instance { - const NoTx: Option> = None; - const NoRx: Option> = None; fn usart( self, - pins: ( - Option>>, - Option>>, - ), + pins: (impl Into>, impl Into>), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig>; + fn tx( + self, + tx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig>; + fn rx( + self, + rx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig>; } impl fmt::Write for Serial @@ -501,19 +508,45 @@ macro_rules! uart_lp { impl SerialExt for $USARTX { fn usart( self, - pins: ( - Option>>, - Option>>, - ), + pins: (impl Into>, impl Into>), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig> { Serial::$usartX(self, pins, config, rcc) } + fn tx( + self, + tx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig> { + Serial::::_new(self, (Some(tx), None::>), config, rcc) + .map(|s| s.split().0) + } + fn rx( + self, + rx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig> { + Serial::::_new(self, (None::>, Some(rx)), config, rcc) + .map(|s| s.split().1) + } } impl Serial<$USARTX, Otype> { pub fn $usartX( + usart: $USARTX, + pins: ( + impl Into<<$USARTX as CommonPins>::Tx>, + impl Into<<$USARTX as CommonPins>::Rx>, + ), + config: impl Into, + rcc: &mut Rcc, + ) -> Result { + Self::_new(usart, (Some(pins.0), Some(pins.1)), config, rcc) + } + fn _new( usart: $USARTX, pins: ( Option::Tx>>, @@ -629,19 +662,45 @@ macro_rules! uart_full { impl SerialExt for $USARTX { fn usart( self, - pins: ( - Option>>, - Option>>, - ), + pins: (impl Into>, impl Into>), config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig> { Serial::$usartX(self, pins, config, rcc) } + fn tx( + self, + tx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig> { + Serial::::_new(self, (Some(tx), None::>), config, rcc) + .map(|s| s.split().0) + } + fn rx( + self, + rx: impl Into>, + config: impl Into, + rcc: &mut Rcc, + ) -> Result, InvalidConfig> { + Serial::::_new(self, (None::>, Some(rx)), config, rcc) + .map(|s| s.split().1) + } } impl Serial<$USARTX, Otype> { pub fn $usartX( + usart: $USARTX, + pins: ( + impl Into<<$USARTX as CommonPins>::Tx>, + impl Into<<$USARTX as CommonPins>::Rx>, + ), + config: impl Into, + rcc: &mut Rcc, + ) -> Result { + Self::_new(usart, (Some(pins.0), Some(pins.1)), config, rcc) + } + fn _new( usart: $USARTX, pins: ( Option::Tx>>, From cd838293bf8373d602521b91b32f0dc1cb7cd184 Mon Sep 17 00:00:00 2001 From: Andrey Zgarbul Date: Wed, 11 Jun 2025 08:17:26 +0300 Subject: [PATCH 4/4] generic Config --- src/serial/usart.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/serial/usart.rs b/src/serial/usart.rs index e3282856..8be4ab21 100644 --- a/src/serial/usart.rs +++ b/src/serial/usart.rs @@ -89,7 +89,9 @@ impl Event { pub use gpio::alt::SerialAsync as CommonPins; // Implemented by all USART/UART instances -pub trait Instance: crate::Sealed + crate::Ptr + Enable + Reset + CommonPins {} +pub trait Instance: crate::Sealed + crate::Ptr + Enable + Reset + CommonPins { + type Config; +} /// Serial receiver pub struct Rx { @@ -119,23 +121,23 @@ pub struct NoDMA; pub struct DMA; #[allow(non_upper_case_globals)] -pub trait SerialExt: Sized + Instance { +pub trait SerialExt: Sized + Instance { fn usart( self, pins: (impl Into>, impl Into>), - config: impl Into, + config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig>; fn tx( self, tx: impl Into>, - config: impl Into, + config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig>; fn rx( self, rx: impl Into>, - config: impl Into, + config: impl Into, rcc: &mut Rcc, ) -> Result, InvalidConfig>; } @@ -168,8 +170,6 @@ where macro_rules! uart_shared { ($USARTX:ident, $dmamux_rx:ident, $dmamux_tx:ident) => { - impl Instance for $USARTX {} - impl Rx<$USARTX, Dma> { /// Starts listening for an interrupt event pub fn listen(&mut self) { @@ -505,7 +505,11 @@ macro_rules! uart_lp { ($USARTX:ident, $usartX:ident, $clk_mul:expr ) => { - impl SerialExt for $USARTX { + impl Instance for $USARTX { + type Config = LowPowerConfig; + } + + impl SerialExt for $USARTX { fn usart( self, pins: (impl Into>, impl Into>), @@ -659,7 +663,11 @@ macro_rules! uart_full { ($USARTX:ident, $usartX:ident ) => { - impl SerialExt for $USARTX { + impl Instance for $USARTX { + type Config = FullConfig; + } + + impl SerialExt for $USARTX { fn usart( self, pins: (impl Into>, impl Into>),