From f9a576d13d736ccbcf17960228ac0df8d82d0928 Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Wed, 6 Oct 2021 21:02:15 +0200 Subject: [PATCH 1/7] feat: Add spi support for STM32F1 variants --- embassy-stm32/src/spi/mod.rs | 1 + embassy-stm32/src/spi/v1.rs | 18 ++++++++++++++++-- stm32-data | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 6249de84..808854f0 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -1,6 +1,7 @@ #![macro_use] #[cfg_attr(spi_v1, path = "v1.rs")] +#[cfg_attr(spi_f1, path = "v1.rs")] #[cfg_attr(spi_v2, path = "v2.rs")] #[cfg_attr(spi_v3, path = "v3.rs")] mod _version; diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 53d8252e..982f1cc4 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -414,7 +414,7 @@ fn write_word(regs: &'static crate::pac::spi::Spi, word: W) -> Result<( let sr = unsafe { regs.sr().read() }; if sr.ovr() { return Err(Error::Overrun); - } else if sr.fre() { + } else if sr_fre(sr) { return Err(Error::Framing); } else if sr.modf() { return Err(Error::ModeFault); @@ -438,7 +438,7 @@ fn read_word(regs: &'static crate::pac::spi::Spi) -> Result { return Err(Error::Overrun); } else if sr.modf() { return Err(Error::ModeFault); - } else if sr.fre() { + } else if sr_fre(sr) { return Err(Error::Framing); } else if sr.crcerr() { return Err(Error::Crc); @@ -450,3 +450,17 @@ fn read_word(regs: &'static crate::pac::spi::Spi) -> Result { } } } + +// SPI on F1 is just V1 without FRE and FRF fields +// This driver only uses FRE, so add a simple function here to read fre on v1, +// and return false on f1 + +#[cfg(spi_v1)] +fn sr_fre(sr: crate::pac::spi::regs::Sr) -> bool { + sr.fre() +} + +#[cfg(spi_f1)] +fn sr_fre(_sr: crate::pac::spi::regs::Sr) -> bool { + false +} diff --git a/stm32-data b/stm32-data index e78ea6f0..bae2d344 160000 --- a/stm32-data +++ b/stm32-data @@ -1 +1 @@ -Subproject commit e78ea6f05058dc1eff1dd4a4f07227d502a3b657 +Subproject commit bae2d34445f87e7b9a88b683c789c5d0c7560fb6 From 39880de9589bb67a88939cba29301ade8dfb592a Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Sat, 9 Oct 2021 11:35:05 +0200 Subject: [PATCH 2/7] partial alternate function configuration on STM32f1 --- embassy-stm32/src/can/bxcan.rs | 6 +++--- embassy-stm32/src/eth/v2/mod.rs | 4 ++-- embassy-stm32/src/gpio.rs | 35 ++++++++++++++++++++++++--------- embassy-stm32/src/i2c/mod.rs | 13 +++++++++++- embassy-stm32/src/i2c/v1.rs | 6 +++--- embassy-stm32/src/spi/mod.rs | 16 +++++++++++++++ embassy-stm32/src/spi/v1.rs | 8 ++++---- embassy-stm32/src/usart/v1.rs | 6 +++--- embassy-stm32/src/usart/v2.rs | 6 +++--- 9 files changed, 72 insertions(+), 28 deletions(-) diff --git a/embassy-stm32/src/can/bxcan.rs b/embassy-stm32/src/can/bxcan.rs index 9e10a8b0..b73b8839 100644 --- a/embassy-stm32/src/can/bxcan.rs +++ b/embassy-stm32/src/can/bxcan.rs @@ -5,7 +5,7 @@ use embassy::util::Unborrow; use embassy_hal_common::unborrow; use crate::gpio::{ - sealed::OutputType::{OpenDrain, PushPull}, + sealed::AFType::{OutputOpenDrain, OutputPushPull}, Pin, }; use crate::{peripherals, rcc::RccPeripheral}; @@ -26,8 +26,8 @@ impl<'d, T: Instance + bxcan::Instance> Can<'d, T> { unborrow!(peri, rx, tx); unsafe { - rx.set_as_af(rx.af_num(), OpenDrain); - tx.set_as_af(tx.af_num(), PushPull); + rx.set_as_af(rx.af_num(), OutputOpenDrain); + tx.set_as_af(tx.af_num(), OutputPushPull); } T::enable(); diff --git a/embassy-stm32/src/eth/v2/mod.rs b/embassy-stm32/src/eth/v2/mod.rs index 8eb7c339..001ac315 100644 --- a/embassy-stm32/src/eth/v2/mod.rs +++ b/embassy-stm32/src/eth/v2/mod.rs @@ -10,7 +10,7 @@ use embassy_net::{Device, DeviceCapabilities, LinkState, PacketBuf, MTU}; use crate::gpio::sealed::Pin as __GpioPin; use crate::gpio::Pin as GpioPin; -use crate::gpio::{sealed::OutputType::PushPull, AnyPin}; +use crate::gpio::{sealed::AFType::OutputPushPull, AnyPin}; use crate::pac::gpio::vals::Ospeedr; use crate::pac::{ETH, RCC, SYSCFG}; use crate::peripherals; @@ -416,7 +416,7 @@ macro_rules! impl_pin { fn configure(&mut self) { // NOTE(unsafe) Exclusive access to the registers critical_section::with(|_| unsafe { - self.set_as_af($af, PushPull); + self.set_as_af($af, OutputPushPull); self.block() .ospeedr() .modify(|w| w.set_ospeedr(self.pin() as usize, Ospeedr::VERYHIGHSPEED)); diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index c7b644e9..3a8117e9 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -350,12 +350,15 @@ impl<'d, T: Pin> InputPin for OutputOpenDrain<'d, T> { pub(crate) mod sealed { use super::*; - /// Output type settings + /// Alternate function type settings #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] - pub enum OutputType { - PushPull, - OpenDrain, + pub enum AFType { + // InputFloating, + // InputPullUp, + // InputPullDown, + OutputPushPull, + OutputOpenDrain, } pub trait Pin { @@ -394,21 +397,35 @@ pub(crate) mod sealed { } #[cfg(gpio_v1)] - unsafe fn set_as_af(&self, _af_num: u8, _af_type: OutputType) { - panic!("F1 alternate GPIO functions not supported yet!"); + unsafe fn set_as_af(&self, _af_num: u8, af_type: AFType) { + // F1 uses the AFIO register for remapping. + // For now, this is not implemented, so af_num is ignored + // _af_num should be zero here, since it is not set by stm32-data + let r = pin.block(); + let n = pin.pin() as usize; + let crlh = if n < 8 { 0 } else { 1 }; + match af_type { + // TODO: Do we need to configure input AF pins differently? + AfType::OutputPushPull => { + r.cr(crlh).modify(|w| w.set_cnf(n % 8, vals::Cnf::PUSHPULL)); + } + AfType::OutputOpenDrain => r + .cr(crlh) + .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)), + } } #[cfg(gpio_v2)] - unsafe fn set_as_af(&self, af_num: u8, af_type: OutputType) { + unsafe fn set_as_af(&self, af_num: u8, af_type: AFType) { let pin = self._pin() as usize; let block = self.block(); block .afr(pin / 8) .modify(|w| w.set_afr(pin % 8, vals::Afr(af_num))); match af_type { - OutputType::PushPull => { + AfType::OutputPushPull => { block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)) } - OutputType::OpenDrain => block + AfType::OutputOpenDrain => block .otyper() .modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), } diff --git a/embassy-stm32/src/i2c/mod.rs b/embassy-stm32/src/i2c/mod.rs index 4af5051d..e922fe42 100644 --- a/embassy-stm32/src/i2c/mod.rs +++ b/embassy-stm32/src/i2c/mod.rs @@ -96,7 +96,6 @@ crate::pac::interrupts!( }; ); -#[cfg(not(rcc_f1))] macro_rules! impl_pin { ($inst:ident, $pin:ident, $signal:ident, $af:expr) => { impl $signal for peripherals::$pin {} @@ -109,6 +108,7 @@ macro_rules! impl_pin { }; } +#[cfg(not(rcc_f1))] crate::pac::peripheral_pins!( ($inst:ident, i2c, I2C, $pin:ident, SDA, $af:expr) => { impl_pin!($inst, $pin, SdaPin, $af); @@ -119,6 +119,17 @@ crate::pac::peripheral_pins!( }; ); +#[cfg(rcc_f1)] +crate::pac::peripheral_pins!( + ($inst:ident, i2c, I2C, $pin:ident, SDA) => { + impl_pin!($inst, $pin, SdaPin, 0); + }; + + ($inst:ident, i2c, I2C, $pin:ident, SCL) => { + impl_pin!($inst, $pin, SclPin, 0); + }; +); + macro_rules! impl_dma { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for T diff --git a/embassy-stm32/src/i2c/v1.rs b/embassy-stm32/src/i2c/v1.rs index c5d5dee0..6fa269fc 100644 --- a/embassy-stm32/src/i2c/v1.rs +++ b/embassy-stm32/src/i2c/v1.rs @@ -9,7 +9,7 @@ use embedded_hal::blocking::i2c::WriteRead; use crate::pac::i2c; -use crate::gpio::sealed::OutputType::OpenDrain; +use crate::gpio::sealed::AFType::OutputOpenDrain; pub struct I2c<'d, T: Instance> { phantom: PhantomData<&'d mut T>, @@ -30,8 +30,8 @@ impl<'d, T: Instance> I2c<'d, T> { T::enable(); unsafe { - scl.set_as_af(scl.af_num(), OpenDrain); - sda.set_as_af(sda.af_num(), OpenDrain); + scl.set_as_af(scl.af_num(), OutputOpenDrain); + sda.set_as_af(sda.af_num(), OutputOpenDrain); } unsafe { diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 808854f0..492fc41c 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -105,6 +105,7 @@ macro_rules! impl_pin { }; } +#[cfg(not(rcc_f1))] crate::pac::peripheral_pins!( ($inst:ident, spi, SPI, $pin:ident, SCK, $af:expr) => { impl_pin!($inst, $pin, SckPin, $af); @@ -119,6 +120,21 @@ crate::pac::peripheral_pins!( }; ); +#[cfg(rcc_f1)] +crate::pac::peripheral_pins!( + ($inst:ident, spi, SPI, $pin:ident, SCK) => { + impl_pin!($inst, $pin, SckPin, 0); + }; + + ($inst:ident, spi, SPI, $pin:ident, MOSI) => { + impl_pin!($inst, $pin, MosiPin, 0); + }; + + ($inst:ident, spi, SPI, $pin:ident, MISO) => { + impl_pin!($inst, $pin, MisoPin, 0); + }; +); + macro_rules! impl_dma { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for T diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 982f1cc4..560d99a2 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -3,7 +3,7 @@ use crate::dma::NoDma; use crate::gpio::{ sealed::{ - OutputType::{OpenDrain, PushPull}, + AFType::{OutputOpenDrain, OutputPushPull}, Pin, }, AnyPin, @@ -59,9 +59,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { unborrow!(sck, mosi, miso, txdma, rxdma); unsafe { - sck.set_as_af(sck.af_num(), PushPull); - mosi.set_as_af(mosi.af_num(), PushPull); - miso.set_as_af(miso.af_num(), OpenDrain); + sck.set_as_af(sck.af_num(), OutputPushPull); + mosi.set_as_af(mosi.af_num(), OutputPushPull); + miso.set_as_af(miso.af_num(), OutputOpenDrain); } let sck = sck.degrade(); diff --git a/embassy-stm32/src/usart/v1.rs b/embassy-stm32/src/usart/v1.rs index d1dd6830..8cd392d1 100644 --- a/embassy-stm32/src/usart/v1.rs +++ b/embassy-stm32/src/usart/v1.rs @@ -1,4 +1,4 @@ -use crate::gpio::sealed::OutputType::{OpenDrain, PushPull}; +use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; use core::future::Future; use core::marker::PhantomData; use embassy::util::Unborrow; @@ -37,8 +37,8 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { let r = inner.regs(); unsafe { - rx.set_as_af(rx.af_num(), OpenDrain); - tx.set_as_af(tx.af_num(), PushPull); + rx.set_as_af(rx.af_num(), OutputOpenDrain); + tx.set_as_af(tx.af_num(), OutputPushPull); r.brr().write_value(regs::Brr(div)); r.cr1().write(|w| { diff --git a/embassy-stm32/src/usart/v2.rs b/embassy-stm32/src/usart/v2.rs index 5e669635..e6e5f69d 100644 --- a/embassy-stm32/src/usart/v2.rs +++ b/embassy-stm32/src/usart/v2.rs @@ -13,7 +13,7 @@ use futures::TryFutureExt; use super::*; use crate::dma::NoDma; -use crate::gpio::sealed::OutputType::{OpenDrain, PushPull}; +use crate::gpio::sealed::AFType::{OutputOpenDrain, OutputPushPull}; use crate::pac::usart::{regs, vals}; pub struct Uart<'d, T: Instance, TxDma = NoDma, RxDma = NoDma> { @@ -43,8 +43,8 @@ impl<'d, T: Instance, TxDma, RxDma> Uart<'d, T, TxDma, RxDma> { let r = inner.regs(); unsafe { - rx.set_as_af(rx.af_num(), OpenDrain); - tx.set_as_af(tx.af_num(), PushPull); + rx.set_as_af(rx.af_num(), OutputOpenDrain); + tx.set_as_af(tx.af_num(), OutputPushPull); r.cr2().write(|_w| {}); r.cr3().write(|_w| {}); From 091e7e1f98c4220889b6fbf4f388320e21f43494 Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Sat, 9 Oct 2021 11:40:39 +0200 Subject: [PATCH 3/7] Generate USART pin definitions for stm32f1 --- embassy-stm32/src/gpio.rs | 12 +++++----- embassy-stm32/src/usart/mod.rs | 40 +++++++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 7 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 3a8117e9..5c48b5be 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -401,15 +401,15 @@ pub(crate) mod sealed { // F1 uses the AFIO register for remapping. // For now, this is not implemented, so af_num is ignored // _af_num should be zero here, since it is not set by stm32-data - let r = pin.block(); - let n = pin.pin() as usize; + let r = self.block(); + let n = self._pin() as usize; let crlh = if n < 8 { 0 } else { 1 }; match af_type { // TODO: Do we need to configure input AF pins differently? - AfType::OutputPushPull => { + AFType::OutputPushPull => { r.cr(crlh).modify(|w| w.set_cnf(n % 8, vals::Cnf::PUSHPULL)); } - AfType::OutputOpenDrain => r + AFType::OutputOpenDrain => r .cr(crlh) .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)), } @@ -422,10 +422,10 @@ pub(crate) mod sealed { .afr(pin / 8) .modify(|w| w.set_afr(pin % 8, vals::Afr(af_num))); match af_type { - AfType::OutputPushPull => { + AFType::OutputPushPull => { block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)) } - AfType::OutputOpenDrain => block + AFType::OutputOpenDrain => block .otyper() .modify(|w| w.set_ot(pin, vals::Ot::OPENDRAIN)), } diff --git a/embassy-stm32/src/usart/mod.rs b/embassy-stm32/src/usart/mod.rs index e64f8d1d..a6955729 100644 --- a/embassy-stm32/src/usart/mod.rs +++ b/embassy-stm32/src/usart/mod.rs @@ -127,7 +127,6 @@ crate::pac::interrupts!( }; ); -#[cfg(not(rcc_f1))] macro_rules! impl_pin { ($inst:ident, $pin:ident, $signal:ident, $af:expr) => { impl sealed::$signal for peripherals::$pin { @@ -140,6 +139,7 @@ macro_rules! impl_pin { }; } +#[cfg(not(rcc_f1))] crate::pac::peripheral_pins!( // USART @@ -177,6 +177,44 @@ crate::pac::peripheral_pins!( }; ); +#[cfg(rcc_f1)] +crate::pac::peripheral_pins!( + + // USART + ($inst:ident, usart, USART, $pin:ident, TX) => { + impl_pin!($inst, $pin, TxPin, 0); + }; + ($inst:ident, usart, USART, $pin:ident, RX) => { + impl_pin!($inst, $pin, RxPin, 0); + }; + ($inst:ident, usart, USART, $pin:ident, CTS) => { + impl_pin!($inst, $pin, CtsPin, 0); + }; + ($inst:ident, usart, USART, $pin:ident, RTS) => { + impl_pin!($inst, $pin, RtsPin, 0); + }; + ($inst:ident, usart, USART, $pin:ident, CK) => { + impl_pin!($inst, $pin, CkPin, 0); + }; + + // UART + ($inst:ident, uart, UART, $pin:ident, TX) => { + impl_pin!($inst, $pin, TxPin, 0); + }; + ($inst:ident, uart, UART, $pin:ident, RX) => { + impl_pin!($inst, $pin, RxPin, 0); + }; + ($inst:ident, uart, UART, $pin:ident, CTS) => { + impl_pin!($inst, $pin, CtsPin, 0); + }; + ($inst:ident, uart, UART, $pin:ident, RTS) => { + impl_pin!($inst, $pin, RtsPin, 0); + }; + ($inst:ident, uart, UART, $pin:ident, CK) => { + impl_pin!($inst, $pin, CkPin, 0); + }; +); + macro_rules! impl_dma { ($inst:ident, {dmamux: $dmamux:ident}, $signal:ident, $request:expr) => { impl sealed::$signal for T From c44bed300b17ef0cb0004758fd085b150533252f Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Sat, 9 Oct 2021 22:03:22 +0200 Subject: [PATCH 4/7] Correctly set alternate function for stm32f1 gpios --- embassy-stm32/src/gpio.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 5c48b5be..7c331fbb 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -407,11 +407,17 @@ pub(crate) mod sealed { match af_type { // TODO: Do we need to configure input AF pins differently? AFType::OutputPushPull => { - r.cr(crlh).modify(|w| w.set_cnf(n % 8, vals::Cnf::PUSHPULL)); + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::OUTPUT50); + w.set_cnf(n % 8, vals::Cnf::ALTPUSHPULL); + }); + } + AFType::OutputOpenDrain => { + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::OUTPUT50); + w.set_cnf(n % 8, vals::Cnf::ALTOPENDRAIN); + }); } - AFType::OutputOpenDrain => r - .cr(crlh) - .modify(|w| w.set_cnf(n % 8, vals::Cnf::OPENDRAIN)), } } #[cfg(gpio_v2)] From 259e84e68e32894a77b6050ee7cbdc9211865447 Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Sat, 9 Oct 2021 22:04:25 +0200 Subject: [PATCH 5/7] Make miso/mosi optional when for unidirectional spi Only suported on v1 currently --- embassy-stm32/src/spi/mod.rs | 8 ++--- embassy-stm32/src/spi/v1.rs | 57 ++++++++++++++++++++++++++---------- embassy-stm32/src/spi/v2.rs | 40 ++++++++++++++++--------- embassy-stm32/src/spi/v3.rs | 44 ++++++++++++++++++---------- 4 files changed, 100 insertions(+), 49 deletions(-) diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 492fc41c..e881a523 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -8,7 +8,7 @@ mod _version; use crate::{dma, peripherals, rcc::RccPeripheral}; pub use _version::*; -use crate::gpio::Pin; +use crate::gpio::OptionalPin; #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] @@ -53,15 +53,15 @@ pub(crate) mod sealed { fn regs() -> &'static crate::pac::spi::Spi; } - pub trait SckPin: Pin { + pub trait SckPin: OptionalPin { fn af_num(&self) -> u8; } - pub trait MosiPin: Pin { + pub trait MosiPin: OptionalPin { fn af_num(&self) -> u8; } - pub trait MisoPin: Pin { + pub trait MisoPin: OptionalPin { fn af_num(&self) -> u8; } diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 560d99a2..6f8f8afb 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -6,9 +6,10 @@ use crate::gpio::{ AFType::{OutputOpenDrain, OutputPushPull}, Pin, }, - AnyPin, + AnyPin, NoPin, }; use crate::pac::spi; +use crate::peripherals; use crate::spi::{ ByteOrder, Config, Error, Instance, MisoPin, MosiPin, RxDmaChannel, SckPin, TxDmaChannel, WordSize, @@ -20,6 +21,7 @@ use core::ptr; use embassy::util::Unborrow; use embassy_hal_common::unborrow; use embassy_traits::spi as traits; +pub use embedded_hal::blocking; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; use futures::future::join3; @@ -32,10 +34,29 @@ impl WordSize { } } +macro_rules! impl_nopin { + ($inst:ident, $signal:ident) => { + impl $signal for NoPin {} + + impl super::sealed::$signal for NoPin { + fn af_num(&self) -> u8 { + 0 + } + } + }; +} +crate::pac::peripherals!( + (spi, $inst:ident) => { + impl_nopin!($inst, SckPin); + impl_nopin!($inst, MosiPin); + impl_nopin!($inst, MisoPin); + }; +); + pub struct Spi<'d, T: Instance, Tx, Rx> { - sck: AnyPin, - mosi: AnyPin, - miso: AnyPin, + sck: Option, + mosi: Option, + miso: Option, txdma: Tx, rxdma: Rx, current_word_size: WordSize, @@ -58,15 +79,18 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { { unborrow!(sck, mosi, miso, txdma, rxdma); - unsafe { - sck.set_as_af(sck.af_num(), OutputPushPull); - mosi.set_as_af(mosi.af_num(), OutputPushPull); - miso.set_as_af(miso.af_num(), OutputOpenDrain); - } + let sck_af = sck.af_num(); + let mosi_af = mosi.af_num(); + let miso_af = miso.af_num(); + let sck = sck.degrade_optional(); + let mosi = mosi.degrade_optional(); + let miso = miso.degrade_optional(); - let sck = sck.degrade(); - let mosi = mosi.degrade(); - let miso = miso.degrade(); + unsafe { + sck.as_ref().map(|x| x.set_as_af(sck_af, OutputPushPull)); + mosi.as_ref().map(|x| x.set_as_af(mosi_af, OutputPushPull)); + miso.as_ref().map(|x| x.set_as_af(miso_af, OutputOpenDrain)); + } unsafe { T::regs().cr2().modify(|w| { @@ -103,6 +127,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { w.set_ssm(true); w.set_crcen(false); w.set_bidimode(spi::vals::Bidimode::UNIDIRECTIONAL); + if mosi.is_none() { + w.set_rxonly(spi::vals::Rxonly::OUTPUTDISABLED); + } w.set_dff(WordSize::EightBit.dff()) }); } @@ -294,9 +321,9 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { fn drop(&mut self) { unsafe { - self.sck.set_as_analog(); - self.mosi.set_as_analog(); - self.miso.set_as_analog(); + self.sck.as_ref().map(|x| x.set_as_analog()); + self.mosi.as_ref().map(|x| x.set_as_analog()); + self.miso.as_ref().map(|x| x.set_as_analog()); } } } diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs index 9df71ef2..cb871a9a 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs @@ -36,9 +36,9 @@ impl WordSize { } pub struct Spi<'d, T: Instance, Tx, Rx> { - sck: AnyPin, - mosi: AnyPin, - miso: AnyPin, + sck: Option, + mosi: Option, + miso: Option, txdma: Tx, rxdma: Rx, phantom: PhantomData<&'d mut T>, @@ -60,15 +60,21 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { { unborrow!(sck, mosi, miso, txdma, rxdma); - unsafe { - Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); - Self::configure_pin(mosi.block(), mosi.pin() as _, mosi.af_num()); - Self::configure_pin(miso.block(), miso.pin() as _, miso.af_num()); - } + let sck_af = sck.af_num(); + let mosi_af = mosi.af_num(); + let miso_af = miso.af_num(); + let sck = sck.degrade_optional(); + let mosi = mosi.degrade_optional(); + let miso = miso.degrade_optional(); - let sck = sck.degrade(); - let mosi = mosi.degrade(); - let miso = miso.degrade(); + unsafe { + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, sck_af)); + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, mosi_af)); + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, miso_af)); + } let pclk = T::frequency(); let freq = freq.into(); @@ -307,9 +313,15 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { fn drop(&mut self) { unsafe { - Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); - Self::unconfigure_pin(self.mosi.block(), self.mosi.pin() as _); - Self::unconfigure_pin(self.miso.block(), self.miso.pin() as _); + self.sck + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); + self.mosi + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); + self.miso + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); } } } diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index b0e57254..ef0f123f 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs @@ -38,9 +38,9 @@ impl WordSize { #[allow(unused)] pub struct Spi<'d, T: Instance, Tx = NoDma, Rx = NoDma> { - sck: AnyPin, - mosi: AnyPin, - miso: AnyPin, + sck: Option, + mosi: Option, + miso: Option, txdma: Tx, rxdma: Rx, phantom: PhantomData<&'d mut T>, @@ -62,17 +62,23 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { { unborrow!(sck, mosi, miso, txdma, rxdma); - unsafe { - Self::configure_pin(sck.block(), sck.pin() as _, sck.af_num()); - //sck.block().otyper().modify(|w| w.set_ot(sck.pin() as _, crate::pac::gpio::vals::Ot::PUSHPULL)); - Self::configure_pin(mosi.block(), mosi.pin() as _, mosi.af_num()); - //mosi.block().otyper().modify(|w| w.set_ot(mosi.pin() as _, crate::pac::gpio::vals::Ot::PUSHPULL)); - Self::configure_pin(miso.block(), miso.pin() as _, miso.af_num()); - } + let sck_af = sck.af_num(); + let mosi_af = mosi.af_num(); + let miso_af = miso.af_num(); + let sck = sck.degrade_optional(); + let mosi = mosi.degrade_optional(); + let miso = miso.degrade_optional(); - let sck = sck.degrade(); - let mosi = mosi.degrade(); - let miso = miso.degrade(); + unsafe { + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, sck_af)); + //sck.block().otyper().modify(|w| w.set_ot(Pin::pin(sck) as _, crate::pac::gpio::vals::Ot::PUSHPULL)); + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, mosi_af)); + //mosi.block().otyper().modify(|w| w.set_ot(Pin::pin(mosi) as _, crate::pac::gpio::vals::Ot::PUSHPULL)); + sck.as_ref() + .map(|x| Self::configure_pin(x.block(), x.pin() as _, miso_af)); + } let pclk = T::frequency(); let br = Self::compute_baud_rate(pclk, freq.into()); @@ -340,9 +346,15 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { impl<'d, T: Instance, Tx, Rx> Drop for Spi<'d, T, Tx, Rx> { fn drop(&mut self) { unsafe { - Self::unconfigure_pin(self.sck.block(), self.sck.pin() as _); - Self::unconfigure_pin(self.mosi.block(), self.mosi.pin() as _); - Self::unconfigure_pin(self.miso.block(), self.miso.pin() as _); + self.sck + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); + self.mosi + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); + self.miso + .as_ref() + .map(|x| Self::unconfigure_pin(x.block(), x.pin() as _)); } } } From 2cbb8a7ece70f5d489b8527f80de708693d9f55b Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Mon, 11 Oct 2021 22:50:33 +0200 Subject: [PATCH 6/7] Add AFType::Input for input configurations. --- embassy-stm32/src/gpio.rs | 12 ++++++++---- embassy-stm32/src/spi/v1.rs | 18 ++++++++---------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/embassy-stm32/src/gpio.rs b/embassy-stm32/src/gpio.rs index 7c331fbb..246cdb04 100644 --- a/embassy-stm32/src/gpio.rs +++ b/embassy-stm32/src/gpio.rs @@ -354,9 +354,7 @@ pub(crate) mod sealed { #[derive(Debug)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] pub enum AFType { - // InputFloating, - // InputPullUp, - // InputPullDown, + Input, OutputPushPull, OutputOpenDrain, } @@ -405,7 +403,12 @@ pub(crate) mod sealed { let n = self._pin() as usize; let crlh = if n < 8 { 0 } else { 1 }; match af_type { - // TODO: Do we need to configure input AF pins differently? + AFType::Input => { + r.cr(crlh).modify(|w| { + w.set_mode(n % 8, vals::Mode::INPUT); + w.set_cnf(n % 8, vals::Cnf::PUSHPULL); + }); + } AFType::OutputPushPull => { r.cr(crlh).modify(|w| { w.set_mode(n % 8, vals::Mode::OUTPUT50); @@ -428,6 +431,7 @@ pub(crate) mod sealed { .afr(pin / 8) .modify(|w| w.set_afr(pin % 8, vals::Afr(af_num))); match af_type { + AFType::Input => {} AFType::OutputPushPull => { block.otyper().modify(|w| w.set_ot(pin, vals::Ot::PUSHPULL)) } diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index 6f8f8afb..d4fa888c 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -1,13 +1,9 @@ #![macro_use] use crate::dma::NoDma; -use crate::gpio::{ - sealed::{ - AFType::{OutputOpenDrain, OutputPushPull}, - Pin, - }, - AnyPin, NoPin, -}; +use crate::gpio::sealed::AFType; +use crate::gpio::sealed::Pin; +use crate::gpio::{AnyPin, NoPin}; use crate::pac::spi; use crate::peripherals; use crate::spi::{ @@ -87,9 +83,11 @@ impl<'d, T: Instance, Tx, Rx> Spi<'d, T, Tx, Rx> { let miso = miso.degrade_optional(); unsafe { - sck.as_ref().map(|x| x.set_as_af(sck_af, OutputPushPull)); - mosi.as_ref().map(|x| x.set_as_af(mosi_af, OutputPushPull)); - miso.as_ref().map(|x| x.set_as_af(miso_af, OutputOpenDrain)); + sck.as_ref() + .map(|x| x.set_as_af(sck_af, AFType::OutputPushPull)); + mosi.as_ref() + .map(|x| x.set_as_af(mosi_af, AFType::OutputPushPull)); + miso.as_ref().map(|x| x.set_as_af(miso_af, AFType::Input)); } unsafe { From 43a7226d8b8e5a2dabae8afbaf9e81651b59ca6e Mon Sep 17 00:00:00 2001 From: Tobias Pisani Date: Mon, 11 Oct 2021 23:33:32 +0200 Subject: [PATCH 7/7] inline FRE register check for SPI on F1 --- embassy-stm32/src/spi/v1.rs | 42 +++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 23 deletions(-) diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index d4fa888c..b727f200 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -439,13 +439,18 @@ fn write_word(regs: &'static crate::pac::spi::Spi, word: W) -> Result<( let sr = unsafe { regs.sr().read() }; if sr.ovr() { return Err(Error::Overrun); - } else if sr_fre(sr) { + } + #[cfg(not(spi_f1))] + if sr.fre() { return Err(Error::Framing); - } else if sr.modf() { + } + if sr.modf() { return Err(Error::ModeFault); - } else if sr.crcerr() { + } + if sr.crcerr() { return Err(Error::Crc); - } else if sr.txe() { + } + if sr.txe() { unsafe { let dr = regs.dr().ptr() as *mut W; ptr::write_volatile(dr, word); @@ -461,13 +466,18 @@ fn read_word(regs: &'static crate::pac::spi::Spi) -> Result { let sr = unsafe { regs.sr().read() }; if sr.ovr() { return Err(Error::Overrun); - } else if sr.modf() { - return Err(Error::ModeFault); - } else if sr_fre(sr) { + } + #[cfg(not(spi_f1))] + if sr.fre() { return Err(Error::Framing); - } else if sr.crcerr() { + } + if sr.modf() { + return Err(Error::ModeFault); + } + if sr.crcerr() { return Err(Error::Crc); - } else if sr.rxne() { + } + if sr.rxne() { unsafe { let dr = regs.dr().ptr() as *const W; return Ok(ptr::read_volatile(dr)); @@ -475,17 +485,3 @@ fn read_word(regs: &'static crate::pac::spi::Spi) -> Result { } } } - -// SPI on F1 is just V1 without FRE and FRF fields -// This driver only uses FRE, so add a simple function here to read fre on v1, -// and return false on f1 - -#[cfg(spi_v1)] -fn sr_fre(sr: crate::pac::spi::regs::Sr) -> bool { - sr.fre() -} - -#[cfg(spi_f1)] -fn sr_fre(_sr: crate::pac::spi::regs::Sr) -> bool { - false -}