From 683ca6595ff7f4c6f0e70e90d3cdeab13d0b1c07 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Mon, 1 Sep 2025 00:05:20 +0200 Subject: stm32/spi: update for new version numbering, add i2s support for all versions. --- embassy-stm32/CHANGELOG.md | 1 + embassy-stm32/Cargo.toml | 8 +- embassy-stm32/src/adc/mod.rs | 68 +++++----------- embassy-stm32/src/i2s.rs | 183 +++++++++++++++++++++---------------------- embassy-stm32/src/lib.rs | 2 +- embassy-stm32/src/spi/mod.rs | 134 +++++++++++++++---------------- 6 files changed, 181 insertions(+), 215 deletions(-) diff --git a/embassy-stm32/CHANGELOG.md b/embassy-stm32/CHANGELOG.md index 8ed4dbd65..5545fc454 100644 --- a/embassy-stm32/CHANGELOG.md +++ b/embassy-stm32/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - feat: Derive Clone, Copy for QSPI Config - fix: stm32/i2c in master mode (blocking): subsequent transmissions failed after a NACK was received - feat: stm32/timer: add set_polarity functions for main and complementary outputs in complementary_pwm +- Add I2S support for STM32F1, STM32C0, STM32F0, STM32F3, STM32F7, STM32G0, STM32WL, STM32H5, STM32H7RS ## 0.4.0 - 2025-08-26 diff --git a/embassy-stm32/Cargo.toml b/embassy-stm32/Cargo.toml index cdb4e07d1..9c2ba1f53 100644 --- a/embassy-stm32/Cargo.toml +++ b/embassy-stm32/Cargo.toml @@ -173,8 +173,8 @@ cortex-m = "0.7.6" futures-util = { version = "0.3.30", default-features = false } sdio-host = "0.9.0" critical-section = "1.1" -stm32-metapac = { version = "18" } -#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ecb93d42a6cbcd9e09cab74873908a2ca22327f7" } +#stm32-metapac = { version = "18" } +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb" } vcell = "0.1.3" nb = "1.0.0" @@ -202,8 +202,8 @@ proptest-state-machine = "0.3.0" proc-macro2 = "1.0.36" quote = "1.0.15" -stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} -#stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-ecb93d42a6cbcd9e09cab74873908a2ca22327f7", default-features = false, features = ["metadata"] } +#stm32-metapac = { version = "18", default-features = false, features = ["metadata"]} +stm32-metapac = { git = "https://github.com/embassy-rs/stm32-data-generated", tag = "stm32-data-d8432edd0406495adec19d31923584e80b8e03cb", default-features = false, features = ["metadata"] } [features] default = ["rt"] diff --git a/embassy-stm32/src/adc/mod.rs b/embassy-stm32/src/adc/mod.rs index 778edc6f6..ea986f4cf 100644 --- a/embassy-stm32/src/adc/mod.rs +++ b/embassy-stm32/src/adc/mod.rs @@ -2,12 +2,12 @@ #![macro_use] #![allow(missing_docs)] // TODO -#![cfg_attr(adc_f3_v2, allow(unused))] +#![cfg_attr(adc_f3v3, allow(unused))] -#[cfg(not(any(adc_f3_v2, adc_wba)))] +#[cfg(not(any(adc_f3v3, adc_wba)))] #[cfg_attr(adc_f1, path = "f1.rs")] -#[cfg_attr(adc_f3, path = "f3.rs")] -#[cfg_attr(adc_f3_v1_1, path = "f3_v1_1.rs")] +#[cfg_attr(adc_f3v1, path = "f3.rs")] +#[cfg_attr(adc_f3v2, path = "f3_v1_1.rs")] #[cfg_attr(adc_v1, path = "v1.rs")] #[cfg_attr(adc_l0, path = "v1.rs")] #[cfg_attr(adc_v2, path = "v2.rs")] @@ -20,10 +20,10 @@ mod _version; use core::marker::PhantomData; #[allow(unused)] -#[cfg(not(any(adc_f3_v2, adc_wba)))] +#[cfg(not(any(adc_f3v3, adc_wba)))] pub use _version::*; use embassy_hal_internal::{impl_peripheral, PeripheralType}; -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] use embassy_sync::waitqueue::AtomicWaker; #[cfg(any(adc_u5, adc_wba))] @@ -31,7 +31,7 @@ use embassy_sync::waitqueue::AtomicWaker; pub mod adc4; pub use crate::pac::adc::vals; -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3v3)))] pub use crate::pac::adc::vals::Res as Resolution; pub use crate::pac::adc::vals::SampleTime; use crate::peripherals; @@ -47,16 +47,16 @@ dma_trait!(RxDma4, adc4::Instance); pub struct Adc<'d, T: Instance> { #[allow(unused)] adc: crate::Peri<'d, T>, - #[cfg(not(any(adc_f3_v2, adc_f3_v1_1, adc_wba)))] + #[cfg(not(any(adc_f3v3, adc_f3v2, adc_wba)))] sample_time: SampleTime, } -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] pub struct State { pub waker: AtomicWaker, } -#[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] +#[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] impl State { pub const fn new() -> Self { Self { @@ -69,10 +69,10 @@ trait SealedInstance { #[cfg(not(adc_wba))] #[allow(unused)] fn regs() -> crate::pac::adc::Adc; - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0)))] #[allow(unused)] fn common_regs() -> crate::pac::adccommon::AdcCommon; - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] fn state() -> &'static State; } @@ -100,22 +100,8 @@ pub(crate) fn blocking_delay_us(us: u32) { /// ADC instance. #[cfg(not(any( - adc_f1, - adc_v1, - adc_l0, - adc_v2, - adc_v3, - adc_v4, - adc_g4, - adc_f3, - adc_f3_v1_1, - adc_g0, - adc_u0, - adc_h5, - adc_h7rs, - adc_u5, - adc_c0, - adc_wba, + adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, + adc_u5, adc_c0, adc_wba, )))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::PeripheralType { @@ -123,22 +109,8 @@ pub trait Instance: SealedInstance + crate::PeripheralType { } /// ADC instance. #[cfg(any( - adc_f1, - adc_v1, - adc_l0, - adc_v2, - adc_v3, - adc_v4, - adc_g4, - adc_f3, - adc_f3_v1_1, - adc_g0, - adc_u0, - adc_h5, - adc_h7rs, - adc_u5, - adc_c0, - adc_wba, + adc_f1, adc_v1, adc_l0, adc_v2, adc_v3, adc_v4, adc_g4, adc_f3v1, adc_f3v2, adc_g0, adc_u0, adc_h5, adc_h7rs, + adc_u5, adc_c0, adc_wba, ))] #[allow(private_bounds)] pub trait Instance: SealedInstance + crate::PeripheralType + crate::rcc::RccPeripheral { @@ -258,12 +230,12 @@ foreach_adc!( crate::pac::$inst } - #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3_v2, adc_f3_v1_1, adc_g0, adc_u5, adc_wba)))] + #[cfg(not(any(adc_f1, adc_v1, adc_l0, adc_f3v3, adc_f3v2, adc_g0, adc_u5, adc_wba)))] fn common_regs() -> crate::pac::adccommon::AdcCommon { return crate::pac::$common_inst } - #[cfg(any(adc_f1, adc_f3, adc_v1, adc_l0, adc_f3_v1_1))] + #[cfg(any(adc_f1, adc_f3v1, adc_v1, adc_l0, adc_f3v2))] fn state() -> &'static State { static STATE: State = State::new(); &STATE @@ -295,7 +267,7 @@ macro_rules! impl_adc_pin { /// Get the maximum reading value for this resolution. /// /// This is `2**n - 1`. -#[cfg(not(any(adc_f1, adc_f3_v2)))] +#[cfg(not(any(adc_f1, adc_f3v3)))] pub const fn resolution_to_max_count(res: Resolution) -> u32 { match res { #[cfg(adc_v4)] @@ -309,7 +281,7 @@ pub const fn resolution_to_max_count(res: Resolution) -> u32 { Resolution::BITS12 => (1 << 12) - 1, Resolution::BITS10 => (1 << 10) - 1, Resolution::BITS8 => (1 << 8) - 1, - #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3, adc_f3_v1_1, adc_h5))] + #[cfg(any(adc_v1, adc_v2, adc_v3, adc_l0, adc_c0, adc_g0, adc_f3v1, adc_f3v2, adc_h5))] Resolution::BITS6 => (1 << 6) - 1, #[allow(unreachable_patterns)] _ => core::unreachable!(), diff --git a/embassy-stm32/src/i2s.rs b/embassy-stm32/src/i2s.rs index a51d21bb0..0c4ab56e3 100644 --- a/embassy-stm32/src/i2s.rs +++ b/embassy-stm32/src/i2s.rs @@ -27,7 +27,8 @@ enum Function { Transmit, /// Receive audio data Receive, - #[cfg(spi_v3)] + #[cfg(any(spi_v4, spi_v5))] + /// Transmit and Receive audio data FullDuplex, } @@ -72,7 +73,6 @@ impl From for Error { } impl Standard { - #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn i2sstd(&self) -> vals::I2sstd { match self { Standard::Philips => vals::I2sstd::PHILIPS, @@ -83,7 +83,6 @@ impl Standard { } } - #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn pcmsync(&self) -> vals::Pcmsync { match self { Standard::PcmLongSync => vals::Pcmsync::LONG, @@ -106,7 +105,6 @@ pub enum Format { } impl Format { - #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn datlen(&self) -> vals::Datlen { match self { Format::Data16Channel16 => vals::Datlen::BITS16, @@ -116,7 +114,6 @@ impl Format { } } - #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn chlen(&self) -> vals::Chlen { match self { Format::Data16Channel16 => vals::Chlen::BITS16, @@ -137,7 +134,6 @@ pub enum ClockPolarity { } impl ClockPolarity { - #[cfg(any(spi_v1, spi_v3, spi_f1))] const fn ckpol(&self) -> vals::Ckpol { match self { ClockPolarity::IdleHigh => vals::Ckpol::IDLE_HIGH, @@ -314,7 +310,8 @@ impl<'d, W: Word> I2S<'d, W> { ) } - #[cfg(spi_v3)] + #[cfg(any(spi_v4, spi_v5))] + /// Create a full duplex driver. pub fn new_full_duplex( peri: Peri<'d, T>, @@ -357,7 +354,7 @@ impl<'d, W: Word> I2S<'d, W> { if let Some(rx_ring_buffer) = &mut self.rx_ring_buffer { rx_ring_buffer.start(); // SPIv3 clears rxfifo on SPE=0 - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] flush_rx_fifo(self.spi.info.regs); set_rxdmaen(self.spi.info.regs, true); @@ -365,7 +362,7 @@ impl<'d, W: Word> I2S<'d, W> { self.spi.info.regs.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.spi.info.regs.cr1().modify(|w| { w.set_cstart(true); }); @@ -404,7 +401,7 @@ impl<'d, W: Word> I2S<'d, W> { join(rx_f, tx_f).await; - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] { if let Mode::Master = self.mode { regs.cr1().modify(|w| { @@ -492,103 +489,98 @@ impl<'d, W: Word> I2S<'d, W> { let (odd, div) = compute_baud_rate(pclk, config.frequency, config.master_clock, config.format); - #[cfg(any(spi_v1, spi_v3, spi_f1))] + #[cfg(any(spi_v4, spi_v5))] { - #[cfg(spi_v3)] - { - regs.cr1().modify(|w| w.set_spe(false)); + regs.cr1().modify(|w| w.set_spe(false)); - reset_incompatible_bitfields::(); - } + reset_incompatible_bitfields::(); + } - use stm32_metapac::spi::vals::{I2scfg, Odd}; - - // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud - // rate to reach the proper audio sample frequency. The ODD bit in the - // SPI_I2SPR/SPI_I2SCFGR register also has to be defined. - - // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the - // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to - // the external DAC/ADC audio component (the I2SDIV and ODD values should be - // computed depending on the state of the MCK output, for more details refer to - // Section 28.4.4: Clock generator). - - // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the - // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the - // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit. - // Select also the I2S master mode and direction (Transmitter or Receiver) through the - // I2SCFG[1:0] bits in the SPI_I2SCFGR register. - - // 4. If needed, select all the potential interruption sources and the DMA capabilities by - // writing the SPI_CR2 register. - - // 5. The I2SE bit in SPI_I2SCFGR register must be set. - - let clk_reg = { - #[cfg(any(spi_v1, spi_f1))] - { - regs.i2spr() - } - #[cfg(spi_v3)] - { - regs.i2scfgr() - } - }; - - clk_reg.modify(|w| { - w.set_i2sdiv(div); - w.set_odd(match odd { - true => Odd::ODD, - false => Odd::EVEN, - }); + use stm32_metapac::spi::vals::{I2scfg, Odd}; + + // 1. Select the I2SDIV[7:0] bits in the SPI_I2SPR/SPI_I2SCFGR register to define the serial clock baud + // rate to reach the proper audio sample frequency. The ODD bit in the + // SPI_I2SPR/SPI_I2SCFGR register also has to be defined. - w.set_mckoe(config.master_clock); + // 2. Select the CKPOL bit to define the steady level for the communication clock. Set the + // MCKOE bit in the SPI_I2SPR/SPI_I2SCFGR register if the master clock MCK needs to be provided to + // the external DAC/ADC audio component (the I2SDIV and ODD values should be + // computed depending on the state of the MCK output, for more details refer to + // Section 28.4.4: Clock generator). + + // 3. Set the I2SMOD bit in SPI_I2SCFGR to activate the I2S functionalities and choose the + // I2S standard through the I2SSTD[1:0] and PCMSYNC bits, the data length through the + // DATLEN[1:0] bits and the number of bits per channel by configuring the CHLEN bit. + // Select also the I2S master mode and direction (Transmitter or Receiver) through the + // I2SCFG[1:0] bits in the SPI_I2SCFGR register. + + // 4. If needed, select all the potential interruption sources and the DMA capabilities by + // writing the SPI_CR2 register. + + // 5. The I2SE bit in SPI_I2SCFGR register must be set. + + let clk_reg = { + #[cfg(any(spi_v1, spi_v2, spi_v3))] + { + regs.i2spr() + } + #[cfg(any(spi_v4, spi_v5))] + { + regs.i2scfgr() + } + }; + + clk_reg.modify(|w| { + w.set_i2sdiv(div); + w.set_odd(match odd { + true => Odd::ODD, + false => Odd::EVEN, }); - regs.i2scfgr().modify(|w| { - w.set_ckpol(config.clock_polarity.ckpol()); + w.set_mckoe(config.master_clock); + }); - w.set_i2smod(true); + regs.i2scfgr().modify(|w| { + w.set_ckpol(config.clock_polarity.ckpol()); - w.set_i2sstd(config.standard.i2sstd()); - w.set_pcmsync(config.standard.pcmsync()); + w.set_i2smod(true); - w.set_datlen(config.format.datlen()); - w.set_chlen(config.format.chlen()); + w.set_i2sstd(config.standard.i2sstd()); + w.set_pcmsync(config.standard.pcmsync()); - w.set_i2scfg(match (config.mode, function) { - (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX, - (Mode::Master, Function::Receive) => I2scfg::MASTER_RX, - #[cfg(spi_v3)] - (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX, - (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX, - (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX, - #[cfg(spi_v3)] - (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX, - }); + w.set_datlen(config.format.datlen()); + w.set_chlen(config.format.chlen()); - #[cfg(any(spi_v1, spi_f1))] - w.set_i2se(true); + w.set_i2scfg(match (config.mode, function) { + (Mode::Master, Function::Transmit) => I2scfg::MASTER_TX, + (Mode::Master, Function::Receive) => I2scfg::MASTER_RX, + #[cfg(any(spi_v4, spi_v5))] + (Mode::Master, Function::FullDuplex) => I2scfg::MASTER_FULL_DUPLEX, + (Mode::Slave, Function::Transmit) => I2scfg::SLAVE_TX, + (Mode::Slave, Function::Receive) => I2scfg::SLAVE_RX, + #[cfg(any(spi_v4, spi_v5))] + (Mode::Slave, Function::FullDuplex) => I2scfg::SLAVE_FULL_DUPLEX, }); - let mut opts = TransferOptions::default(); - opts.half_transfer_ir = true; - - Self { - mode: config.mode, - spi, - txsd: txsd.map(|w| w.into()), - rxsd: rxsd.map(|w| w.into()), - ws: Some(ws.into()), - ck: Some(ck.into()), - mck: mck.map(|w| w.into()), - tx_ring_buffer: txdma.map(|(ch, buf)| unsafe { - WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) - }), - rx_ring_buffer: rxdma.map(|(ch, buf)| unsafe { - ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts) - }), - } + #[cfg(any(spi_v1, spi_v2, spi_v3))] + w.set_i2se(true); + }); + + let mut opts = TransferOptions::default(); + opts.half_transfer_ir = true; + + Self { + mode: config.mode, + spi, + txsd: txsd.map(|w| w.into()), + rxsd: rxsd.map(|w| w.into()), + ws: Some(ws.into()), + ck: Some(ck.into()), + mck: mck.map(|w| w.into()), + tx_ring_buffer: txdma + .map(|(ch, buf)| unsafe { WritableRingBuffer::new(ch.channel, ch.request, regs.tx_ptr(), buf, opts) }), + rx_ring_buffer: rxdma + .map(|(ch, buf)| unsafe { ReadableRingBuffer::new(ch.channel, ch.request, regs.rx_ptr(), buf, opts) }), } } } @@ -639,7 +631,8 @@ fn compute_baud_rate(i2s_clock: Hertz, request_freq: Hertz, mclk: bool, data_for } } -#[cfg(spi_v3)] +#[cfg(any(spi_v4, spi_v5))] + // The STM32H7 reference manual specifies that any incompatible bitfields should be reset // to their reset values while operating in I2S mode. fn reset_incompatible_bitfields() { diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs index 3be98c462..7e0f7884e 100644 --- a/embassy-stm32/src/lib.rs +++ b/embassy-stm32/src/lib.rs @@ -87,7 +87,7 @@ pub mod hsem; pub mod hspi; #[cfg(i2c)] pub mod i2c; -#[cfg(any(all(spi_v1, rcc_f4), spi_v3))] +#[cfg(any(spi_v1_i2s, spi_v2_i2s, spi_v3_i2s, spi_v4_i2s, spi_v5_i2s))] pub mod i2s; #[cfg(stm32wb)] pub mod ipcc; diff --git a/embassy-stm32/src/spi/mod.rs b/embassy-stm32/src/spi/mod.rs index 4c5308eba..a49ebcbee 100644 --- a/embassy-stm32/src/spi/mod.rs +++ b/embassy-stm32/src/spi/mod.rs @@ -174,7 +174,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { self.info.rcc.enable_and_reset(); let regs = self.info.regs; - #[cfg(any(spi_v1, spi_f1))] + #[cfg(any(spi_v1, spi_v2))] { regs.cr2().modify(|w| { w.set_ssoe(false); @@ -198,7 +198,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_dff(::CONFIG) }); } - #[cfg(spi_v2)] + #[cfg(spi_v3)] { regs.cr2().modify(|w| { let (ds, frxth) = ::CONFIG; @@ -220,7 +220,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_spe(true); }); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] { regs.ifcr().write(|w| w.0 = 0xffff_ffff); regs.cfg2().modify(|w| { @@ -274,7 +274,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { } } - #[cfg(any(spi_v1, spi_f1, spi_v2))] + #[cfg(any(spi_v1, spi_v2, spi_v3))] self.info.regs.cr1().modify(|w| { w.set_cpha(cpha); w.set_cpol(cpol); @@ -282,7 +282,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_lsbfirst(lsbfirst); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] { self.info.regs.cr1().modify(|w| { w.set_spe(false); @@ -306,11 +306,11 @@ impl<'d, M: PeriMode> Spi<'d, M> { /// Get current SPI configuration. pub fn get_current_config(&self) -> Config { - #[cfg(any(spi_v1, spi_f1, spi_v2))] + #[cfg(any(spi_v1, spi_v2, spi_v3))] let cfg = self.info.regs.cr1().read(); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] let cfg = self.info.regs.cfg2().read(); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] let cfg1 = self.info.regs.cfg1().read(); let polarity = if cfg.cpol() == vals::Cpol::IDLE_LOW { @@ -335,9 +335,9 @@ impl<'d, M: PeriMode> Spi<'d, M> { Some(pin) => pin.pull(), }; - #[cfg(any(spi_v1, spi_f1, spi_v2))] + #[cfg(any(spi_v1, spi_v2, spi_v3))] let br = cfg.br(); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] let br = cfg1.mbr(); let frequency = compute_frequency(self.kernel_clock, br); @@ -360,16 +360,16 @@ impl<'d, M: PeriMode> Spi<'d, M> { w.set_spe(false); }); - #[cfg(any(spi_v1, spi_f1))] + #[cfg(any(spi_v1, spi_v2))] self.info.regs.cr1().modify(|reg| { reg.set_dff(word_size); }); - #[cfg(spi_v2)] + #[cfg(spi_v3)] self.info.regs.cr2().modify(|w| { w.set_frxth(word_size.1); w.set_ds(word_size.0); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cfg1().modify(|w| { w.set_dsize(word_size); }); @@ -380,7 +380,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { /// Blocking write. pub fn blocking_write(&mut self, words: &[W]) -> Result<(), Error> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| w.set_spe(false)); self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); @@ -391,7 +391,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { // This is the case when the SPI has been created with `new_(blocking_?)txonly_nosck`. // See https://github.com/embassy-rs/embassy/issues/2902 // This is not documented as an errata by ST, and I've been unable to find anything online... - #[cfg(not(any(spi_v1, spi_f1)))] + #[cfg(not(any(spi_v1, spi_v2)))] write_word(self.info.regs, *word)?; // if we're doing tx only, after writing the last byte to FIFO we have to wait @@ -401,14 +401,14 @@ impl<'d, M: PeriMode> Spi<'d, M> { // Luckily this doesn't affect SPIv2+. // See http://efton.sk/STM32/gotcha/g68.html // ST doesn't seem to document this in errata sheets (?) - #[cfg(any(spi_v1, spi_f1))] + #[cfg(any(spi_v1, spi_v2))] transfer_word(self.info.regs, *word)?; } // wait until last word is transmitted. (except on v1, see above) - #[cfg(not(any(spi_v1, spi_f1, spi_v2)))] + #[cfg(not(any(spi_v1, spi_v2, spi_v3)))] while !self.info.regs.sr().read().txc() {} - #[cfg(spi_v2)] + #[cfg(spi_v3)] while self.info.regs.sr().read().bsy() {} Ok(()) @@ -417,7 +417,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { /// Blocking read. pub fn blocking_read(&mut self, words: &mut [W]) -> Result<(), Error> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| w.set_spe(false)); self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); @@ -433,7 +433,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { /// This writes the contents of `data` on MOSI, and puts the received data on MISO in `data`, at the same time. pub fn blocking_transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| w.set_spe(false)); self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); @@ -452,7 +452,7 @@ impl<'d, M: PeriMode> Spi<'d, M> { /// If `write` is shorter it is padded with zero bytes. pub fn blocking_transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { // needed in v3+ to avoid overrun causing the SPI RX state machine to get stuck...? - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| w.set_spe(false)); self.set_word_size(W::CONFIG); self.info.regs.cr1().modify(|w| w.set_spe(true)); @@ -572,7 +572,7 @@ impl<'d> Spi<'d, Async> { peri: Peri<'d, T>, sck: Peri<'d, impl SckPin>, miso: Peri<'d, impl MisoPin>, - #[cfg(any(spi_v1, spi_f1, spi_v2))] tx_dma: Peri<'d, impl TxDma>, + #[cfg(any(spi_v1, spi_v2, spi_v3))] tx_dma: Peri<'d, impl TxDma>, rx_dma: Peri<'d, impl RxDma>, config: Config, ) -> Self { @@ -581,9 +581,9 @@ impl<'d> Spi<'d, Async> { new_pin!(sck, config.sck_af()), None, new_pin!(miso, AfType::input(config.miso_pull)), - #[cfg(any(spi_v1, spi_f1, spi_v2))] + #[cfg(any(spi_v1, spi_v2, spi_v3))] new_dma!(tx_dma), - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] None, new_dma!(rx_dma), config, @@ -677,7 +677,7 @@ impl<'d> Spi<'d, Async> { self.info.regs.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| { w.set_cstart(true); }); @@ -690,7 +690,7 @@ impl<'d> Spi<'d, Async> { } /// SPI read, using DMA. - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { if data.is_empty() { return Ok(()); @@ -710,7 +710,7 @@ impl<'d> Spi<'d, Async> { prev }); - #[cfg(spi_v3)] + #[cfg(spi_v4)] let i2scfg = regs.i2scfgr().modify(|w| { w.i2smod().then(|| { let prev = w.i2scfg(); @@ -766,7 +766,7 @@ impl<'d> Spi<'d, Async> { w.set_tsize(0); }); - #[cfg(spi_v3)] + #[cfg(spi_v4)] if let Some(i2scfg) = i2scfg { regs.i2scfgr().modify(|w| { w.set_i2scfg(i2scfg); @@ -777,7 +777,7 @@ impl<'d> Spi<'d, Async> { } /// SPI read, using DMA. - #[cfg(any(spi_v1, spi_f1, spi_v2))] + #[cfg(any(spi_v1, spi_v2, spi_v3))] pub async fn read(&mut self, data: &mut [W]) -> Result<(), Error> { if data.is_empty() { return Ok(()); @@ -790,7 +790,7 @@ impl<'d> Spi<'d, Async> { self.set_word_size(W::CONFIG); // SPIv3 clears rxfifo on SPE=0 - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] flush_rx_fifo(self.info.regs); set_rxdmaen(self.info.regs, true); @@ -813,7 +813,7 @@ impl<'d> Spi<'d, Async> { self.info.regs.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| { w.set_cstart(true); }); @@ -838,7 +838,7 @@ impl<'d> Spi<'d, Async> { self.set_word_size(W::CONFIG); // SPIv3 clears rxfifo on SPE=0 - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] flush_rx_fifo(self.info.regs); set_rxdmaen(self.info.regs, true); @@ -858,7 +858,7 @@ impl<'d> Spi<'d, Async> { self.info.regs.cr1().modify(|w| { w.set_spe(true); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] self.info.regs.cr1().modify(|w| { w.set_cstart(true); }); @@ -898,9 +898,9 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> { } } -#[cfg(not(any(spi_v3, spi_v4, spi_v5)))] +#[cfg(not(any(spi_v4, spi_v5, spi_v6)))] use vals::Br; -#[cfg(any(spi_v3, spi_v4, spi_v5))] +#[cfg(any(spi_v4, spi_v5, spi_v6))] use vals::Mbr as Br; fn compute_baud_rate(kernel_clock: Hertz, freq: Hertz) -> Br { @@ -941,21 +941,21 @@ pub(crate) trait RegsExt { impl RegsExt for Regs { fn tx_ptr(&self) -> *mut W { - #[cfg(any(spi_v1, spi_f1))] + #[cfg(any(spi_v1, spi_v2))] let dr = self.dr(); - #[cfg(spi_v2)] + #[cfg(spi_v3)] let dr = self.dr16(); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] let dr = self.txdr32(); dr.as_ptr() as *mut W } fn rx_ptr(&self) -> *mut W { - #[cfg(any(spi_v1, spi_f1))] + #[cfg(any(spi_v1, spi_v2))] let dr = self.dr(); - #[cfg(spi_v2)] + #[cfg(spi_v3)] let dr = self.dr16(); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] let dr = self.rxdr32(); dr.as_ptr() as *mut W } @@ -965,22 +965,22 @@ fn check_error_flags(sr: regs::Sr, ovr: bool) -> Result<(), Error> { if sr.ovr() && ovr { return Err(Error::Overrun); } - #[cfg(not(any(spi_f1, spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v1, spi_v4, spi_v5, spi_v6)))] if sr.fre() { return Err(Error::Framing); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] if sr.tifre() { return Err(Error::Framing); } if sr.modf() { return Err(Error::ModeFault); } - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] if sr.crcerr() { return Err(Error::Crc); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] if sr.crce() { return Err(Error::Crc); } @@ -994,11 +994,11 @@ fn spin_until_tx_ready(regs: Regs, ovr: bool) -> Result<(), Error> { check_error_flags(sr, ovr)?; - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] if sr.txe() { return Ok(()); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] if sr.txp() { return Ok(()); } @@ -1011,11 +1011,11 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { check_error_flags(sr, true)?; - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] if sr.rxne() { return Ok(()); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] if sr.rxp() { return Ok(()); } @@ -1023,46 +1023,46 @@ fn spin_until_rx_ready(regs: Regs) -> Result<(), Error> { } pub(crate) fn flush_rx_fifo(regs: Regs) { - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] while regs.sr().read().rxne() { - #[cfg(not(spi_v2))] + #[cfg(not(spi_v3))] let _ = regs.dr().read(); - #[cfg(spi_v2)] + #[cfg(spi_v3)] let _ = regs.dr16().read(); } - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] while regs.sr().read().rxp() { let _ = regs.rxdr32().read(); } } pub(crate) fn set_txdmaen(regs: Regs, val: bool) { - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] regs.cr2().modify(|reg| { reg.set_txdmaen(val); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] regs.cfg1().modify(|reg| { reg.set_txdmaen(val); }); } pub(crate) fn set_rxdmaen(regs: Regs, val: bool) { - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] regs.cr2().modify(|reg| { reg.set_rxdmaen(val); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] regs.cfg1().modify(|reg| { reg.set_rxdmaen(val); }); } fn finish_dma(regs: Regs) { - #[cfg(spi_v2)] + #[cfg(spi_v3)] while regs.sr().read().ftlvl().to_bits() > 0 {} - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] { if regs.cr2().read().tsize() == 0 { while !regs.sr().read().txc() {} @@ -1070,7 +1070,7 @@ fn finish_dma(regs: Regs) { while !regs.sr().read().eot() {} } } - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] while regs.sr().read().bsy() {} // Disable the spi peripheral @@ -1080,12 +1080,12 @@ fn finish_dma(regs: Regs) { // The peripheral automatically disables the DMA stream on completion without error, // but it does not clear the RXDMAEN/TXDMAEN flag in CR2. - #[cfg(not(any(spi_v3, spi_v4, spi_v5)))] + #[cfg(not(any(spi_v4, spi_v5, spi_v6)))] regs.cr2().modify(|reg| { reg.set_txdmaen(false); reg.set_rxdmaen(false); }); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] regs.cfg1().modify(|reg| { reg.set_txdmaen(false); reg.set_rxdmaen(false); @@ -1098,7 +1098,7 @@ fn transfer_word(regs: Regs, tx_word: W) -> Result { unsafe { ptr::write_volatile(regs.tx_ptr(), tx_word); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] regs.cr1().modify(|reg| reg.set_cstart(true)); } @@ -1117,7 +1117,7 @@ fn write_word(regs: Regs, tx_word: W) -> Result<(), Error> { unsafe { ptr::write_volatile(regs.tx_ptr(), tx_word); - #[cfg(any(spi_v3, spi_v4, spi_v5))] + #[cfg(any(spi_v4, spi_v5, spi_v6))] regs.cr1().modify(|reg| reg.set_cstart(true)); } Ok(()) @@ -1225,7 +1225,7 @@ macro_rules! impl_word { }; } -#[cfg(any(spi_v1, spi_f1))] +#[cfg(any(spi_v1, spi_v2))] mod word_impl { use super::*; @@ -1235,7 +1235,7 @@ mod word_impl { impl_word!(u16, vals::Dff::BITS16); } -#[cfg(spi_v2)] +#[cfg(spi_v3)] mod word_impl { use super::*; @@ -1256,7 +1256,7 @@ mod word_impl { impl_word!(u16, (vals::Ds::BITS16, vals::Frxth::HALF)); } -#[cfg(any(spi_v3, spi_v4, spi_v5))] +#[cfg(any(spi_v4, spi_v5, spi_v6))] mod word_impl { use super::*; -- cgit