From d890ef98c19444f88692983f454881b9848169ae Mon Sep 17 00:00:00 2001 From: Bob McWhirter Date: Thu, 20 May 2021 14:13:45 -0400 Subject: [PATCH] Make SPIv3 work and improve v1 and v2. --- embassy-stm32/src/spi/v1.rs | 43 ++++++++-- embassy-stm32/src/spi/v2.rs | 82 +++++++++++++++----- embassy-stm32/src/spi/v3.rs | 151 +++++++++++++++++++++++++++--------- 3 files changed, 213 insertions(+), 63 deletions(-) diff --git a/embassy-stm32/src/spi/v1.rs b/embassy-stm32/src/spi/v1.rs index a464c427..43557325 100644 --- a/embassy-stm32/src/spi/v1.rs +++ b/embassy-stm32/src/spi/v1.rs @@ -8,6 +8,7 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use core::ptr; impl WordSize { fn dff(&self) -> spi::vals::Dff { @@ -151,7 +152,11 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.txdr().ptr() as *mut u8; + ptr::write_volatile( + dr, + *word, + ); } loop { let sr = unsafe { regs.sr().read() }; @@ -186,12 +191,24 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.txdr().ptr() as *mut u8; + ptr::write_volatile( + dr, + *word, + ); } + while unsafe { !regs.sr().read().rxne() } { // spin waiting for inbound to shift in. } - *word = unsafe { regs.dr().read().0 as u8 }; + + unsafe { + let dr = regs.dr().ptr() as *const u8; + *word = ptr::read_volatile( + dr + ); + } + let sr = unsafe { regs.sr().read() }; if sr.fre() { return Err(Error::Framing); @@ -220,7 +237,11 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.txdr().ptr() as *mut u16; + ptr::write_volatile( + dr, + *word, + ); } loop { let sr = unsafe { regs.sr().read() }; @@ -255,12 +276,22 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.txdr().ptr() as *mut u16; + ptr::write_volatile( + dr, + *word, + ); } while unsafe { !regs.sr().read().rxne() } { // spin waiting for inbound to shift in. } - *word = unsafe { regs.dr().read().0 as u16 }; + unsafe { + let dr = regs.dr().ptr() as *const u16; + *word = ptr::read_volatile( + dr + ); + } + let sr = unsafe { regs.sr().read() }; if sr.fre() { return Err(Error::Framing); diff --git a/embassy-stm32/src/spi/v2.rs b/embassy-stm32/src/spi/v2.rs index 0bb5762f..82344a5d 100644 --- a/embassy-stm32/src/spi/v2.rs +++ b/embassy-stm32/src/spi/v2.rs @@ -10,6 +10,7 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use core::ptr; impl WordSize { fn ds(&self) -> spi::vals::Ds { @@ -61,16 +62,13 @@ impl<'d, T: Instance> Spi<'d, T> { let mosi = mosi.degrade(); let miso = miso.degrade(); - unsafe { - T::regs().cr2().write(|w| { - w.set_ssoe(false); - }); - } - let br = Self::compute_baud_rate(pclk, freq.into()); unsafe { - T::regs().cr1().write(|w| { + T::regs().cr2().modify(|w| { + w.set_ssoe(false); + }); + T::regs().cr1().modify(|w| { w.set_cpha( match config.mode.phase == Phase::CaptureOnSecondTransition { true => spi::vals::Cpha::SECONDEDGE, @@ -84,7 +82,6 @@ impl<'d, T: Instance> Spi<'d, T> { w.set_mstr(spi::vals::Mstr::MASTER); w.set_br(spi::vals::Br(br)); - w.set_spe(true); w.set_lsbfirst(match config.byte_order { ByteOrder::LsbFirst => spi::vals::Lsbfirst::LSBFIRST, ByteOrder::MsbFirst => spi::vals::Lsbfirst::MSBFIRST, @@ -93,6 +90,7 @@ impl<'d, T: Instance> Spi<'d, T> { w.set_ssm(true); w.set_crcen(false); w.set_bidimode(spi::vals::Bidimode::UNIDIRECTIONAL); + w.set_spe(true); }); } @@ -131,9 +129,15 @@ impl<'d, T: Instance> Spi<'d, T> { fn set_word_size(word_size: WordSize) { unsafe { - T::regs().cr2().write(|w| { - w.set_ds(word_size.ds()); + T::regs().cr1().modify(|w| { + w.set_spe(false); + }); + T::regs().cr2().modify(|w| { w.set_frxth(word_size.frxth()); + w.set_ds(word_size.ds()); + }); + T::regs().cr1().modify(|w| { + w.set_spe(true); }); } } @@ -156,12 +160,16 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { Self::set_word_size(WordSize::EightBit); let regs = T::regs(); - for word in words.iter() { + for (i, word) in words.iter().enumerate() { while unsafe { !regs.sr().read().txe() } { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.dr().ptr() as *mut u8; + ptr::write_volatile( + dr, + *word, + ); } loop { let sr = unsafe { regs.sr().read() }; @@ -191,17 +199,38 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> { Self::set_word_size(WordSize::EightBit); let regs = T::regs(); - for word in words.iter_mut() { + for (i, word) in words.iter_mut().enumerate() { while unsafe { !regs.sr().read().txe() } { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.dr().ptr() as *mut u8; + ptr::write_volatile( + dr, + *word, + ); } - while unsafe { !regs.sr().read().rxne() } { - // spin waiting for inbound to shift in. + loop { + let sr = unsafe { regs.sr().read() }; + if sr.rxne() { + break; + } + if sr.fre() { + return Err(Error::Framing); + } + if sr.ovr() { + return Err(Error::Overrun); + } + if sr.crcerr() { + return Err(Error::Crc); + } + } + unsafe { + let dr = regs.rxdr().ptr() as *const u8; + *word = ptr::read_volatile( + dr + ); } - *word = unsafe { regs.dr().read().0 as u8 }; let sr = unsafe { regs.sr().read() }; if sr.fre() { return Err(Error::Framing); @@ -230,7 +259,11 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.dr().ptr() as *mut u16; + ptr::write_volatile( + dr, + *word, + ); } loop { let sr = unsafe { regs.sr().read() }; @@ -265,12 +298,21 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> // spin } unsafe { - regs.dr().write(|reg| reg.0 = *word as u32); + let dr = regs.dr().ptr() as *mut u16; + ptr::write_volatile( + dr, + *word, + ); } while unsafe { !regs.sr().read().rxne() } { // spin waiting for inbound to shift in. } - *word = unsafe { regs.dr().read().0 as u16 }; + unsafe { + let dr = regs.rxdr().ptr() as *const u16; + *word = ptr::read_volatile( + dr + ); + } let sr = unsafe { regs.sr().read() }; if sr.fre() { return Err(Error::Framing); diff --git a/embassy-stm32/src/spi/v3.rs b/embassy-stm32/src/spi/v3.rs index 6f81f9dd..e30d479e 100644 --- a/embassy-stm32/src/spi/v3.rs +++ b/embassy-stm32/src/spi/v3.rs @@ -10,6 +10,8 @@ use core::marker::PhantomData; use embassy::util::Unborrow; use embassy_extras::unborrow; pub use embedded_hal::spi::{Mode, Phase, Polarity, MODE_0, MODE_1, MODE_2, MODE_3}; +use core::ptr; + impl WordSize { fn dsize(&self) -> u8 { @@ -21,8 +23,8 @@ impl WordSize { fn frxth(&self) -> spi::vals::Fthlv { match self { - WordSize::EightBit => spi::vals::Fthlv::FOURFRAMES, - WordSize::SixteenBit => spi::vals::Fthlv::EIGHTFRAMES, + WordSize::EightBit => spi::vals::Fthlv::ONEFRAME, + WordSize::SixteenBit => spi::vals::Fthlv::ONEFRAME, } } } @@ -38,22 +40,24 @@ pub struct Spi<'d, T: Instance> { impl<'d, T: Instance> Spi<'d, T> { pub fn new( pclk: Hertz, - peri: impl Unborrow + 'd, - sck: impl Unborrow>, - mosi: impl Unborrow>, - miso: impl Unborrow>, + peri: impl Unborrow + 'd, + sck: impl Unborrow>, + mosi: impl Unborrow>, + miso: impl Unborrow>, freq: F, config: Config, ) -> Self - where - F: Into, + where + F: Into, { unborrow!(peri); unborrow!(sck, mosi, miso); 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()); } @@ -61,8 +65,13 @@ impl<'d, T: Instance> Spi<'d, T> { let mosi = mosi.degrade(); let miso = miso.degrade(); + let br = Self::compute_baud_rate(pclk, freq.into()); unsafe { - T::regs().cfg2().write(|w| { + T::regs().ifcr().write(|w| { + w.0 = 0xffff_ffff + }); + T::regs().cfg2().modify(|w| { + //w.set_ssoe(true); w.set_ssoe(false); w.set_cpha( match config.mode.phase == Phase::CaptureOnSecondTransition { @@ -74,30 +83,32 @@ impl<'d, T: Instance> Spi<'d, T> { true => spi::vals::Cpol::IDLEHIGH, false => spi::vals::Cpol::IDLELOW, }); - }); - } - - let br = Self::compute_baud_rate(pclk, freq.into()); - - unsafe { - T::regs().cfg2().write(|w| { w.set_lsbfrst(match config.byte_order { ByteOrder::LsbFirst => spi::vals::Lsbfrst::LSBFIRST, ByteOrder::MsbFirst => spi::vals::Lsbfrst::MSBFIRST, }); w.set_ssm(true); w.set_master(spi::vals::Master::MASTER); + w.set_comm(spi::vals::Comm::FULLDUPLEX); + w.set_ssom(spi::vals::Ssom::ASSERTED); + w.set_midi(0); + w.set_mssi(0); + w.set_afcntr(spi::vals::Afcntr::CONTROLLED); + w.set_ssiop(spi::vals::Ssiop::ACTIVEHIGH); }); - T::regs().cfg1().write(|w| { + T::regs().cfg1().modify(|w| { w.set_crcen(false); w.set_mbr(spi::vals::Mbr(br)); w.set_dsize(WordSize::EightBit.dsize()); - w.set_fthlv(WordSize::EightBit.frxth()); + //w.set_fthlv(WordSize::EightBit.frxth()); }); - T::regs().cr1().write(|w| { - w.set_ssi(true); + T::regs().cr2().modify(|w| { + w.set_tsize(0); + w.set_tser(0); + }); + T::regs().cr1().modify(|w| { + w.set_ssi(false); w.set_spe(true); - //w.set_bidimode(spi::vals::Bidimode::UNIDIRECTIONAL); }); } @@ -114,6 +125,7 @@ impl<'d, T: Instance> Spi<'d, T> { let (afr, n_af) = if pin < 8 { (0, pin) } else { (1, pin - 8) }; block.moder().modify(|w| w.set_moder(pin, Moder::ALTERNATE)); block.afr(afr).modify(|w| w.set_afr(n_af, Afr(af_num))); + block.ospeedr().modify(|w| w.set_ospeedr(pin, crate::pac::gpio::vals::Ospeedr::VERYHIGHSPEED)); } unsafe fn unconfigure_pin(block: Gpio, pin: usize) { @@ -136,14 +148,17 @@ impl<'d, T: Instance> Spi<'d, T> { fn set_word_size(word_size: WordSize) { unsafe { - T::regs().cr1().write(|w| { + T::regs().cr1().modify(|w| { + w.set_csusp(true); + }); + while T::regs().sr().read().eot() {} + T::regs().cr1().modify(|w| { w.set_spe(false); }); - T::regs().cfg1().write(|w| { + T::regs().cfg1().modify(|w| { w.set_dsize(word_size.dsize()); - w.set_fthlv(word_size.frxth()); }); - T::regs().cr1().write(|w| { + T::regs().cr1().modify(|w| { w.set_spe(true); }); } @@ -172,8 +187,12 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { // spin } unsafe { - //regs.dr().write(|reg| reg.0 = *word as u32); - regs.txdr().write(|reg| reg.0 = *word as u32); + let txdr = regs.txdr().ptr() as *mut u8; + ptr::write_volatile( + txdr, + *word, + ); + regs.cr1().modify(|reg| reg.set_cstart(true)); } loop { let sr = unsafe { regs.sr().read() }; @@ -203,17 +222,45 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> { Self::set_word_size(WordSize::EightBit); let regs = T::regs(); - for word in words.iter_mut() { + for (i, word) in words.iter_mut().enumerate() { + unsafe { + regs.cr1().modify(|reg| { + reg.set_ssi(false); + }); + } while unsafe { !regs.sr().read().txp() } { // spin } unsafe { - regs.txdr().write(|reg| reg.0 = *word as u32); + let txdr = regs.txdr().ptr() as *mut u8; + ptr::write_volatile( + txdr, + *word, + ); + regs.cr1().modify(|reg| reg.set_cstart(true)); } - while unsafe { !regs.sr().read().rxp() } { - // spin waiting for inbound to shift in. + loop { + let sr = unsafe { regs.sr().read() }; + + if sr.rxp() { + break; + } + if sr.tifre() { + return Err(Error::Framing); + } + if sr.ovr() { + return Err(Error::Overrun); + } + if sr.crce() { + return Err(Error::Crc); + } + } + unsafe { + let rxdr = regs.rxdr().ptr() as *const u8; + *word = ptr::read_volatile( + rxdr + ); } - *word = unsafe { regs.rxdr().read().0 as u8 }; let sr = unsafe { regs.sr().read() }; if sr.tifre() { return Err(Error::Framing); @@ -242,7 +289,12 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Write for Spi<'d, T> { // spin } unsafe { - regs.txdr().write(|reg| reg.0 = *word as u32); + let txdr = regs.txdr().ptr() as *mut u16; + ptr::write_volatile( + txdr, + *word, + ); + regs.cr1().modify(|reg| reg.set_cstart(true)); } loop { let sr = unsafe { regs.sr().read() }; @@ -277,12 +329,37 @@ impl<'d, T: Instance> embedded_hal::blocking::spi::Transfer for Spi<'d, T> // spin } unsafe { - regs.txdr().write(|reg| reg.0 = *word as u32); + let txdr = regs.txdr().ptr() as *mut u16; + ptr::write_volatile( + txdr, + *word, + ); + regs.cr1().modify(|reg| reg.set_cstart(true)); } - while unsafe { !regs.sr().read().rxp() } { - // spin waiting for inbound to shift in. + + loop { + let sr = unsafe { regs.sr().read() }; + + if sr.rxp() { + break; + } + if sr.tifre() { + return Err(Error::Framing); + } + if sr.ovr() { + return Err(Error::Overrun); + } + if sr.crce() { + return Err(Error::Crc); + } + } + + unsafe { + let rxdr = regs.rxdr().ptr() as *const u16; + *word = ptr::read_volatile( + rxdr + ); } - *word = unsafe { regs.rxdr().read().0 as u16 }; let sr = unsafe { regs.sr().read() }; if sr.tifre() { return Err(Error::Framing);