stm32: use funcs for info/state, const for ENABLE_BIT.

This commit is contained in:
Dario Nieuwenhuis 2024-05-21 01:24:10 +02:00
parent 2b09f9efd7
commit 6a508b3210
5 changed files with 81 additions and 72 deletions

View File

@ -653,9 +653,9 @@ fn main() {
crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false)); crate::pac::RCC.#en_reg().modify(|w| w.#set_en_field(false));
#decr_stop_refcount #decr_stop_refcount
} }
fn enable_bit() -> crate::rcc::ClockEnableBit {
unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) } const ENABLE_BIT: crate::rcc::ClockEnableBit =
} unsafe { crate::rcc::ClockEnableBit::new(#en_reg_offs, #en_bit_offs) };
} }
impl crate::rcc::RccPeripheral for peripherals::#pname {} impl crate::rcc::RccPeripheral for peripherals::#pname {}

View File

@ -208,7 +208,7 @@ impl<'d> I2S<'d> {
// rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR // rate to reach the proper audio sample frequency. The ODD bit in the SPI_I2SPR
// register also has to be defined. // register also has to be defined.
spi.regs.i2spr().modify(|w| { spi.info.regs.i2spr().modify(|w| {
w.set_i2sdiv(div); w.set_i2sdiv(div);
w.set_odd(match odd { w.set_odd(match odd {
true => Odd::ODD, true => Odd::ODD,
@ -235,7 +235,7 @@ impl<'d> I2S<'d> {
// 5. The I2SE bit in SPI_I2SCFGR register must be set. // 5. The I2SE bit in SPI_I2SCFGR register must be set.
spi.regs.i2scfgr().modify(|w| { spi.info.regs.i2scfgr().modify(|w| {
w.set_ckpol(config.clock_polarity.ckpol()); w.set_ckpol(config.clock_polarity.ckpol());
w.set_i2smod(true); w.set_i2smod(true);

View File

@ -4,8 +4,10 @@ macro_rules! peri_trait {
() => { () => {
#[allow(private_interfaces)] #[allow(private_interfaces)]
pub(crate) trait SealedInstance { pub(crate) trait SealedInstance {
const INFO: Info; #[allow(unused)]
const STATE: &'static State; fn info() -> &'static Info;
#[allow(unused)]
fn state() -> &'static State;
} }
/// SPI instance trait. /// SPI instance trait.
@ -18,8 +20,14 @@ macro_rules! peri_trait_impl {
($instance:ident, $info:expr) => { ($instance:ident, $info:expr) => {
#[allow(private_interfaces)] #[allow(private_interfaces)]
impl SealedInstance for crate::peripherals::$instance { impl SealedInstance for crate::peripherals::$instance {
const INFO: Info = $info; fn info() -> &'static Info {
const STATE: &'static State = &State::new(); static INFO: Info = $info;
&INFO
}
fn state() -> &'static State {
static STATE: State = State::new();
&STATE
}
} }
impl Instance for crate::peripherals::$instance {} impl Instance for crate::peripherals::$instance {}
}; };

View File

@ -67,10 +67,11 @@ pub(crate) unsafe fn get_freqs() -> &'static Clocks {
} }
pub(crate) trait SealedRccPeripheral { pub(crate) trait SealedRccPeripheral {
const ENABLE_BIT: ClockEnableBit;
fn frequency() -> Hertz; fn frequency() -> Hertz;
fn enable_and_reset_with_cs(cs: CriticalSection); fn enable_and_reset_with_cs(cs: CriticalSection);
fn disable_with_cs(cs: CriticalSection); fn disable_with_cs(cs: CriticalSection);
fn enable_bit() -> ClockEnableBit;
fn enable_and_reset() { fn enable_and_reset() {
critical_section::with(|cs| Self::enable_and_reset_with_cs(cs)) critical_section::with(|cs| Self::enable_and_reset_with_cs(cs))
@ -151,7 +152,7 @@ pub(crate) struct ClockEnableBit {
impl ClockEnableBit { impl ClockEnableBit {
/// Safety: offset+bit must correspond to a valid xxxEN bit. /// Safety: offset+bit must correspond to a valid xxxEN bit.
pub(crate) unsafe fn new(offset: u8, bit: u8) -> Self { pub(crate) const unsafe fn new(offset: u8, bit: u8) -> Self {
Self { offset, bit } Self { offset, bit }
} }

View File

@ -13,7 +13,7 @@ use crate::dma::{slice_ptr_parts, word, ChannelAndRequest};
use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed}; use crate::gpio::{AFType, AnyPin, Pull, SealedPin as _, Speed};
use crate::mode::{Async, Blocking, Mode as PeriMode}; use crate::mode::{Async, Blocking, Mode as PeriMode};
use crate::pac::spi::{regs, vals, Spi as Regs}; use crate::pac::spi::{regs, vals, Spi as Regs};
use crate::rcc::{ClockEnableBit, RccPeripheral}; use crate::rcc::{ClockEnableBit, SealedRccPeripheral};
use crate::time::Hertz; use crate::time::Hertz;
use crate::Peripheral; use crate::Peripheral;
@ -93,8 +93,7 @@ impl Config {
} }
/// SPI driver. /// SPI driver.
pub struct Spi<'d, M: PeriMode> { pub struct Spi<'d, M: PeriMode> {
pub(crate) regs: Regs, pub(crate) info: &'static Info,
enable_bit: ClockEnableBit,
kernel_clock: Hertz, kernel_clock: Hertz,
sck: Option<PeripheralRef<'d, AnyPin>>, sck: Option<PeripheralRef<'d, AnyPin>>,
mosi: Option<PeripheralRef<'d, AnyPin>>, mosi: Option<PeripheralRef<'d, AnyPin>>,
@ -115,7 +114,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
rx_dma: Option<ChannelAndRequest<'d>>, rx_dma: Option<ChannelAndRequest<'d>>,
config: Config, config: Config,
) -> Self { ) -> Self {
let regs = T::INFO.regs; let regs = T::info().regs;
let kernel_clock = T::frequency(); let kernel_clock = T::frequency();
let br = compute_baud_rate(kernel_clock, config.frequency); let br = compute_baud_rate(kernel_clock, config.frequency);
@ -205,8 +204,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
} }
Self { Self {
regs, info: T::info(),
enable_bit: T::enable_bit(),
kernel_clock, kernel_clock,
sck, sck,
mosi, mosi,
@ -228,7 +226,7 @@ impl<'d, M: PeriMode> Spi<'d, M> {
let br = compute_baud_rate(self.kernel_clock, config.frequency); let br = compute_baud_rate(self.kernel_clock, config.frequency);
#[cfg(any(spi_v1, spi_f1, spi_v2))] #[cfg(any(spi_v1, spi_f1, spi_v2))]
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_cpha(cpha); w.set_cpha(cpha);
w.set_cpol(cpol); w.set_cpol(cpol);
w.set_br(br); w.set_br(br);
@ -237,12 +235,12 @@ impl<'d, M: PeriMode> Spi<'d, M> {
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
{ {
self.regs.cfg2().modify(|w| { self.info.regs.cfg2().modify(|w| {
w.set_cpha(cpha); w.set_cpha(cpha);
w.set_cpol(cpol); w.set_cpol(cpol);
w.set_lsbfirst(lsbfirst); w.set_lsbfirst(lsbfirst);
}); });
self.regs.cfg1().modify(|w| { self.info.regs.cfg1().modify(|w| {
w.set_mbr(br); w.set_mbr(br);
}); });
} }
@ -252,11 +250,11 @@ impl<'d, M: PeriMode> Spi<'d, M> {
/// Get current SPI configuration. /// Get current SPI configuration.
pub fn get_current_config(&self) -> Config { pub fn get_current_config(&self) -> Config {
#[cfg(any(spi_v1, spi_f1, spi_v2))] #[cfg(any(spi_v1, spi_f1, spi_v2))]
let cfg = self.regs.cr1().read(); let cfg = self.info.regs.cr1().read();
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
let cfg = self.regs.cfg2().read(); let cfg = self.info.regs.cfg2().read();
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
let cfg1 = self.regs.cfg1().read(); let cfg1 = self.info.regs.cfg1().read();
let polarity = if cfg.cpol() == vals::Cpol::IDLELOW { let polarity = if cfg.cpol() == vals::Cpol::IDLELOW {
Polarity::IdleLow Polarity::IdleLow
@ -296,40 +294,40 @@ impl<'d, M: PeriMode> Spi<'d, M> {
#[cfg(any(spi_v1, spi_f1))] #[cfg(any(spi_v1, spi_f1))]
{ {
self.regs.cr1().modify(|reg| { self.info.regs.cr1().modify(|reg| {
reg.set_spe(false); reg.set_spe(false);
reg.set_dff(word_size) reg.set_dff(word_size)
}); });
self.regs.cr1().modify(|reg| { self.info.regs.cr1().modify(|reg| {
reg.set_spe(true); reg.set_spe(true);
}); });
} }
#[cfg(spi_v2)] #[cfg(spi_v2)]
{ {
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
}); });
self.regs.cr2().modify(|w| { self.info.regs.cr2().modify(|w| {
w.set_frxth(word_size.1); w.set_frxth(word_size.1);
w.set_ds(word_size.0); w.set_ds(word_size.0);
}); });
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(true); w.set_spe(true);
}); });
} }
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
{ {
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_csusp(true); w.set_csusp(true);
}); });
while self.regs.sr().read().eot() {} while self.info.regs.sr().read().eot() {}
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
}); });
self.regs.cfg1().modify(|w| { self.info.regs.cfg1().modify(|w| {
w.set_dsize(word_size); w.set_dsize(word_size);
}); });
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_csusp(false); w.set_csusp(false);
w.set_spe(true); w.set_spe(true);
}); });
@ -340,22 +338,22 @@ impl<'d, M: PeriMode> Spi<'d, M> {
/// Blocking write. /// Blocking write.
pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> { pub fn blocking_write<W: Word>(&mut self, words: &[W]) -> Result<(), Error> {
self.regs.cr1().modify(|w| w.set_spe(true)); self.info.regs.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
for word in words.iter() { for word in words.iter() {
let _ = transfer_word(self.regs, *word)?; let _ = transfer_word(self.info.regs, *word)?;
} }
Ok(()) Ok(())
} }
/// Blocking read. /// Blocking read.
pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_read<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
self.regs.cr1().modify(|w| w.set_spe(true)); self.info.regs.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
for word in words.iter_mut() { for word in words.iter_mut() {
*word = transfer_word(self.regs, W::default())?; *word = transfer_word(self.info.regs, W::default())?;
} }
Ok(()) Ok(())
} }
@ -364,11 +362,11 @@ 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. /// 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<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> { pub fn blocking_transfer_in_place<W: Word>(&mut self, words: &mut [W]) -> Result<(), Error> {
self.regs.cr1().modify(|w| w.set_spe(true)); self.info.regs.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
for word in words.iter_mut() { for word in words.iter_mut() {
*word = transfer_word(self.regs, *word)?; *word = transfer_word(self.info.regs, *word)?;
} }
Ok(()) Ok(())
} }
@ -380,13 +378,13 @@ impl<'d, M: PeriMode> Spi<'d, M> {
/// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored. /// The transfer runs for `max(read.len(), write.len())` bytes. If `read` is shorter extra bytes are ignored.
/// If `write` is shorter it is padded with zero bytes. /// If `write` is shorter it is padded with zero bytes.
pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> { pub fn blocking_transfer<W: Word>(&mut self, read: &mut [W], write: &[W]) -> Result<(), Error> {
self.regs.cr1().modify(|w| w.set_spe(true)); self.info.regs.cr1().modify(|w| w.set_spe(true));
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
let len = read.len().max(write.len()); let len = read.len().max(write.len());
for i in 0..len { for i in 0..len {
let wb = write.get(i).copied().unwrap_or_default(); let wb = write.get(i).copied().unwrap_or_default();
let rb = transfer_word(self.regs, wb)?; let rb = transfer_word(self.info.regs, wb)?;
if let Some(r) = read.get_mut(i) { if let Some(r) = read.get_mut(i) {
*r = rb; *r = rb;
} }
@ -588,25 +586,25 @@ impl<'d> Spi<'d, Async> {
} }
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
}); });
let tx_dst = self.regs.tx_ptr(); let tx_dst = self.info.regs.tx_ptr();
let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) }; let tx_f = unsafe { self.tx_dma.as_mut().unwrap().write(data, tx_dst, Default::default()) };
set_txdmaen(self.regs, true); set_txdmaen(self.info.regs, true);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(true); w.set_spe(true);
}); });
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_cstart(true); w.set_cstart(true);
}); });
tx_f.await; tx_f.await;
finish_dma(self.regs); finish_dma(self.info.regs);
Ok(()) Ok(())
} }
@ -618,22 +616,22 @@ impl<'d> Spi<'d, Async> {
} }
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
}); });
// SPIv3 clears rxfifo on SPE=0 // SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))] #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
set_rxdmaen(self.regs, true); set_rxdmaen(self.info.regs, true);
let clock_byte_count = data.len(); let clock_byte_count = data.len();
let rx_src = self.regs.rx_ptr(); let rx_src = self.info.regs.rx_ptr();
let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) }; let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read(rx_src, data, Default::default()) };
let tx_dst = self.regs.tx_ptr(); let tx_dst = self.info.regs.tx_ptr();
let clock_byte = 0x00u8; let clock_byte = 0x00u8;
let tx_f = unsafe { let tx_f = unsafe {
self.tx_dma self.tx_dma
@ -642,18 +640,18 @@ impl<'d> Spi<'d, Async> {
.write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default()) .write_repeated(&clock_byte, clock_byte_count, tx_dst, Default::default())
}; };
set_txdmaen(self.regs, true); set_txdmaen(self.info.regs, true);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(true); w.set_spe(true);
}); });
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_cstart(true); w.set_cstart(true);
}); });
join(tx_f, rx_f).await; join(tx_f, rx_f).await;
finish_dma(self.regs); finish_dma(self.info.regs);
Ok(()) Ok(())
} }
@ -667,20 +665,20 @@ impl<'d> Spi<'d, Async> {
} }
self.set_word_size(W::CONFIG); self.set_word_size(W::CONFIG);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(false); w.set_spe(false);
}); });
// SPIv3 clears rxfifo on SPE=0 // SPIv3 clears rxfifo on SPE=0
#[cfg(not(any(spi_v3, spi_v4, spi_v5)))] #[cfg(not(any(spi_v3, spi_v4, spi_v5)))]
flush_rx_fifo(self.regs); flush_rx_fifo(self.info.regs);
set_rxdmaen(self.regs, true); set_rxdmaen(self.info.regs, true);
let rx_src = self.regs.rx_ptr(); let rx_src = self.info.regs.rx_ptr();
let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) }; let rx_f = unsafe { self.rx_dma.as_mut().unwrap().read_raw(rx_src, read, Default::default()) };
let tx_dst = self.regs.tx_ptr(); let tx_dst = self.info.regs.tx_ptr();
let tx_f = unsafe { let tx_f = unsafe {
self.tx_dma self.tx_dma
.as_mut() .as_mut()
@ -688,18 +686,18 @@ impl<'d> Spi<'d, Async> {
.write_raw(write, tx_dst, Default::default()) .write_raw(write, tx_dst, Default::default())
}; };
set_txdmaen(self.regs, true); set_txdmaen(self.info.regs, true);
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_spe(true); w.set_spe(true);
}); });
#[cfg(any(spi_v3, spi_v4, spi_v5))] #[cfg(any(spi_v3, spi_v4, spi_v5))]
self.regs.cr1().modify(|w| { self.info.regs.cr1().modify(|w| {
w.set_cstart(true); w.set_cstart(true);
}); });
join(tx_f, rx_f).await; join(tx_f, rx_f).await;
finish_dma(self.regs); finish_dma(self.info.regs);
Ok(()) Ok(())
} }
@ -728,7 +726,7 @@ impl<'d, M: PeriMode> Drop for Spi<'d, M> {
self.mosi.as_ref().map(|x| x.set_as_disconnected()); self.mosi.as_ref().map(|x| x.set_as_disconnected());
self.miso.as_ref().map(|x| x.set_as_disconnected()); self.miso.as_ref().map(|x| x.set_as_disconnected());
self.enable_bit.disable(); self.info.enable_bit.disable();
} }
} }
@ -1106,8 +1104,9 @@ mod word_impl {
impl_word!(u32, 32 - 1); impl_word!(u32, 32 - 1);
} }
struct Info { pub(crate) struct Info {
regs: Regs, pub(crate) regs: Regs,
pub(crate) enable_bit: ClockEnableBit,
} }
struct State {} struct State {}
@ -1134,6 +1133,7 @@ foreach_peripheral!(
(spi, $inst:ident) => { (spi, $inst:ident) => {
peri_trait_impl!($inst, Info { peri_trait_impl!($inst, Info {
regs: crate::pac::$inst, regs: crate::pac::$inst,
enable_bit: crate::peripherals::$inst::ENABLE_BIT,
}); });
}; };
); );