diff --git a/src/common/lpspi.rs b/src/common/lpspi.rs index 2c263b17..3b050468 100644 --- a/src/common/lpspi.rs +++ b/src/common/lpspi.rs @@ -359,7 +359,7 @@ impl Transaction { /// Sets the clock speed parameters. /// /// This should only happen when the LPSPI peripheral is disabled. -fn set_spi_clock(source_clock_hz: u32, spi_clock_hz: u32, reg: &ral::lpspi::RegisterBlock) { +fn compute_spi_clock(source_clock_hz: u32, spi_clock_hz: u32) -> ClockConfigs { // Round up, so we always get a resulting SPI clock that is // equal or less than the requested frequency. let half_div = @@ -372,16 +372,16 @@ fn set_spi_clock(source_clock_hz: u32, spi_clock_hz: u32, reg: &ral::lpspi::Regi // Because half_div is in range [3,128], sckdiv is in range [4, 254]. let sckdiv = 2 * (half_div - 1); - ral::write_reg!(ral::lpspi, reg, CCR, + ClockConfigs { // Delay between two clock transitions of two consecutive transfers // is exactly sckdiv/2, which causes the transfer to be seamless. - DBT: half_div - 1, + dbt: (half_div - 1) as u8, // Add one sckdiv/2 setup and hold time before and after the transfer, // to make sure the signal is stable at sample time - PCSSCK: half_div - 1, - SCKPCS: half_div - 1, - SCKDIV: sckdiv - ); + pcssck: (half_div - 1) as u8, + sckpcs: (half_div - 1) as u8, + sckdiv: sckdiv as u8, + } } /// LPSPI clock configurations. @@ -416,6 +416,47 @@ pub struct ClockConfigs { pub sckdiv: u8, } +impl ClockConfigs { + const fn as_raw(self) -> u32 { + use ral::lpspi::CCR; + (self.sckpcs as u32) << CCR::SCKPCS::offset + | (self.pcssck as u32) << CCR::PCSSCK::offset + | (self.dbt as u32) << CCR::DBT::offset + | (self.sckdiv as u32) << CCR::SCKDIV::offset + } +} + +/// In-memory clock configuration register values. +/// +/// Newer LPSPI IP blocks, like those found on the 1180, have `CCR[DBT]` +/// and `CCR[SCKDIV]` fields that are WO/RAZ. RAZ is incompatible +/// with older IP blocks, like those found on all the other MCUs. +/// +/// If we cache these values, all RMW on CCR will behave as if we +/// read those values through the register. +struct CcrCache { + dbt: u8, + sckdiv: u8, +} + +impl CcrCache { + /// Reac the clock configuration values, considering the cached values. + fn read_ccr(&self, lpspi: &ral::lpspi::RegisterBlock) -> ClockConfigs { + let (sckpcs, pcssck) = ral::read_reg!(ral::lpspi, lpspi, CCR, SCKPCS, PCSSCK); + ClockConfigs { + sckpcs: sckpcs as u8, + pcssck: pcssck as u8, + dbt: self.dbt, + sckdiv: self.sckdiv, + } + } + /// Update the cached values. + fn update(&mut self, clock_configs: ClockConfigs) { + self.dbt = clock_configs.dbt; + self.sckdiv = clock_configs.sckdiv; + } +} + /// An LPSPI driver. /// /// The driver exposes low-level methods for coordinating @@ -432,6 +473,7 @@ pub struct Lpspi
{ pins: P, bit_order: BitOrder, mode: Mode, + ccr_cache: CcrCache, } /// Pins for a LPSPI device. @@ -505,6 +547,8 @@ impl
Lpspi
{ pins, bit_order: BitOrder::default(), mode: MODE_0, + // Once we issue a reset, below, these are zero. + ccr_cache: CcrCache { dbt: 0, sckdiv: 0 }, }; // Reset and disable @@ -593,7 +637,7 @@ impl
Lpspi
{
/// The handle to a [`Disabled`](crate::lpspi::Disabled) driver lets you modify
/// LPSPI settings that require a fully disabled peripheral.
pub fn disabled Lpspi {
let cfgr1 = ral::read_reg!(ral::lpspi, self.lpspi, CFGR1);
let dmr0 = ral::read_reg!(ral::lpspi, self.lpspi, DMR0);
let dmr1 = ral::read_reg!(ral::lpspi, self.lpspi, DMR1);
- let ccr = ral::read_reg!(ral::lpspi, self.lpspi, CCR);
+ let ccr = self.clock_configs().as_raw();
let fcr = ral::read_reg!(ral::lpspi, self.lpspi, FCR);
// Backup enabled state
@@ -1002,14 +1046,7 @@ impl Lpspi {
/// These values are decided by calls to [`set_clock_hz`](Disabled::set_clock_hz)
/// and [`set_clock_configs`](Disabled::set_clock_configs).
pub fn clock_configs(&self) -> ClockConfigs {
- let (sckpcs, pcssck, dbt, sckdiv) =
- ral::read_reg!(ral::lpspi, self.lpspi, CCR, SCKPCS, PCSSCK, DBT, SCKDIV);
- ClockConfigs {
- sckpcs: sckpcs as u8,
- pcssck: pcssck as u8,
- dbt: dbt as u8,
- sckdiv: sckdiv as u8,
- }
+ self.ccr_cache.read_ccr(&self.lpspi)
}
/// Produce a transaction that considers bus-managed software state.
@@ -1175,10 +1212,11 @@ fn set_watermark(lpspi: &ral::lpspi::RegisterBlock, direction: Direction, waterm
pub struct Disabled<'a, const N: u8> {
lpspi: &'a ral::lpspi::Instance