@@ -359,7 +359,7 @@ impl Transaction {
359359/// Sets the clock speed parameters.
360360///
361361/// This should only happen when the LPSPI peripheral is disabled.
362- fn set_spi_clock ( source_clock_hz : u32 , spi_clock_hz : u32 , reg : & ral :: lpspi :: RegisterBlock ) {
362+ fn compute_spi_clock ( source_clock_hz : u32 , spi_clock_hz : u32 ) -> ClockConfigs {
363363 // Round up, so we always get a resulting SPI clock that is
364364 // equal or less than the requested frequency.
365365 let half_div =
@@ -372,16 +372,16 @@ fn set_spi_clock(source_clock_hz: u32, spi_clock_hz: u32, reg: &ral::lpspi::Regi
372372 // Because half_div is in range [3,128], sckdiv is in range [4, 254].
373373 let sckdiv = 2 * ( half_div - 1 ) ;
374374
375- ral :: write_reg! ( ral :: lpspi , reg , CCR ,
375+ ClockConfigs {
376376 // Delay between two clock transitions of two consecutive transfers
377377 // is exactly sckdiv/2, which causes the transfer to be seamless.
378- DBT : half_div - 1 ,
378+ dbt : ( half_div - 1 ) as u8 ,
379379 // Add one sckdiv/2 setup and hold time before and after the transfer,
380380 // to make sure the signal is stable at sample time
381- PCSSCK : half_div - 1 ,
382- SCKPCS : half_div - 1 ,
383- SCKDIV : sckdiv
384- ) ;
381+ pcssck : ( half_div - 1 ) as u8 ,
382+ sckpcs : ( half_div - 1 ) as u8 ,
383+ sckdiv : sckdiv as u8 ,
384+ }
385385}
386386
387387/// LPSPI clock configurations.
@@ -416,6 +416,47 @@ pub struct ClockConfigs {
416416 pub sckdiv : u8 ,
417417}
418418
419+ impl ClockConfigs {
420+ const fn as_raw ( self ) -> u32 {
421+ use ral:: lpspi:: CCR ;
422+ ( self . sckpcs as u32 ) << CCR :: SCKPCS :: offset
423+ | ( self . pcssck as u32 ) << CCR :: PCSSCK :: offset
424+ | ( self . dbt as u32 ) << CCR :: DBT :: offset
425+ | ( self . sckdiv as u32 ) << CCR :: SCKDIV :: offset
426+ }
427+ }
428+
429+ /// In-memory clock configuration register values.
430+ ///
431+ /// Newer LPSPI IP blocks, like those found on the 1180, have `CCR[DBT]`
432+ /// and `CCR[SCKDIV]` fields that are WO/RAZ. RAZ is incompatible
433+ /// with older IP blocks, like those found on all the other MCUs.
434+ ///
435+ /// If we cache these values, all RMW on CCR will behave as if we
436+ /// read those values through the register.
437+ struct CcrCache {
438+ dbt : u8 ,
439+ sckdiv : u8 ,
440+ }
441+
442+ impl CcrCache {
443+ /// Reac the clock configuration values, considering the cached values.
444+ fn read_ccr ( & self , lpspi : & ral:: lpspi:: RegisterBlock ) -> ClockConfigs {
445+ let ( sckpcs, pcssck) = ral:: read_reg!( ral:: lpspi, lpspi, CCR , SCKPCS , PCSSCK ) ;
446+ ClockConfigs {
447+ sckpcs : sckpcs as u8 ,
448+ pcssck : pcssck as u8 ,
449+ dbt : self . dbt ,
450+ sckdiv : self . sckdiv ,
451+ }
452+ }
453+ /// Update the cached values.
454+ fn update ( & mut self , clock_configs : ClockConfigs ) {
455+ self . dbt = clock_configs. dbt ;
456+ self . sckdiv = clock_configs. sckdiv ;
457+ }
458+ }
459+
419460/// An LPSPI driver.
420461///
421462/// The driver exposes low-level methods for coordinating
@@ -432,6 +473,7 @@ pub struct Lpspi<P, const N: u8> {
432473 pins : P ,
433474 bit_order : BitOrder ,
434475 mode : Mode ,
476+ ccr_cache : CcrCache ,
435477}
436478
437479/// Pins for a LPSPI device.
@@ -505,6 +547,8 @@ impl<P, const N: u8> Lpspi<P, N> {
505547 pins,
506548 bit_order : BitOrder :: default ( ) ,
507549 mode : MODE_0 ,
550+ // Once we issue a reset, below, these are zero.
551+ ccr_cache : CcrCache { dbt : 0 , sckdiv : 0 } ,
508552 } ;
509553
510554 // Reset and disable
@@ -593,7 +637,7 @@ impl<P, const N: u8> Lpspi<P, N> {
593637 /// The handle to a [`Disabled`](crate::lpspi::Disabled) driver lets you modify
594638 /// LPSPI settings that require a fully disabled peripheral.
595639 pub fn disabled < R > ( & mut self , func : impl FnOnce ( & mut Disabled < N > ) -> R ) -> R {
596- let mut disabled = Disabled :: new ( & mut self . lpspi ) ;
640+ let mut disabled = Disabled :: new ( & mut self . lpspi , & mut self . ccr_cache ) ;
597641 func ( & mut disabled)
598642 }
599643
@@ -945,7 +989,7 @@ impl<P, const N: u8> Lpspi<P, N> {
945989 let cfgr1 = ral:: read_reg!( ral:: lpspi, self . lpspi, CFGR1 ) ;
946990 let dmr0 = ral:: read_reg!( ral:: lpspi, self . lpspi, DMR0 ) ;
947991 let dmr1 = ral:: read_reg!( ral:: lpspi, self . lpspi, DMR1 ) ;
948- let ccr = ral :: read_reg! ( ral :: lpspi , self . lpspi , CCR ) ;
992+ let ccr = self . clock_configs ( ) . as_raw ( ) ;
949993 let fcr = ral:: read_reg!( ral:: lpspi, self . lpspi, FCR ) ;
950994
951995 // Backup enabled state
@@ -1002,14 +1046,7 @@ impl<P, const N: u8> Lpspi<P, N> {
10021046 /// These values are decided by calls to [`set_clock_hz`](Disabled::set_clock_hz)
10031047 /// and [`set_clock_configs`](Disabled::set_clock_configs).
10041048 pub fn clock_configs ( & self ) -> ClockConfigs {
1005- let ( sckpcs, pcssck, dbt, sckdiv) =
1006- ral:: read_reg!( ral:: lpspi, self . lpspi, CCR , SCKPCS , PCSSCK , DBT , SCKDIV ) ;
1007- ClockConfigs {
1008- sckpcs : sckpcs as u8 ,
1009- pcssck : pcssck as u8 ,
1010- dbt : dbt as u8 ,
1011- sckdiv : sckdiv as u8 ,
1012- }
1049+ self . ccr_cache . read_ccr ( & self . lpspi )
10131050 }
10141051
10151052 /// Produce a transaction that considers bus-managed software state.
@@ -1175,33 +1212,40 @@ fn set_watermark(lpspi: &ral::lpspi::RegisterBlock, direction: Direction, waterm
11751212pub struct Disabled < ' a , const N : u8 > {
11761213 lpspi : & ' a ral:: lpspi:: Instance < N > ,
11771214 men : bool ,
1215+ ccr_cache : & ' a mut CcrCache ,
11781216}
11791217
11801218impl < ' a , const N : u8 > Disabled < ' a , N > {
1181- fn new ( lpspi : & ' a mut ral:: lpspi:: Instance < N > ) -> Self {
1219+ fn new ( lpspi : & ' a mut ral:: lpspi:: Instance < N > , ccr_cache : & ' a mut CcrCache ) -> Self {
11821220 let men = ral:: read_reg!( ral:: lpspi, lpspi, CR , MEN == MEN_1 ) ;
11831221
11841222 // Request disable
11851223 ral:: modify_reg!( ral:: lpspi, lpspi, CR , MEN : MEN_0 ) ;
11861224 // Wait for the driver to finish its current transfer
11871225 // and enter disabled state
11881226 while ral:: read_reg!( ral:: lpspi, lpspi, CR , MEN == MEN_1 ) { }
1189- Self { lpspi, men }
1227+ Self {
1228+ lpspi,
1229+ men,
1230+ ccr_cache,
1231+ }
11901232 }
11911233
11921234 /// Set the LPSPI clock speed (Hz).
11931235 ///
11941236 /// `source_clock_hz` is the LPSPI peripheral clock speed. To specify the
11951237 /// peripheral clock, see the [`ccm::lpspi_clk`](crate::ccm::lpspi_clk) documentation.
11961238 pub fn set_clock_hz ( & mut self , source_clock_hz : u32 , clock_hz : u32 ) {
1197- set_spi_clock ( source_clock_hz, clock_hz, self . lpspi ) ;
1239+ let clock_configs = compute_spi_clock ( source_clock_hz, clock_hz) ;
1240+ self . set_clock_configs ( clock_configs) ;
11981241 }
11991242
12001243 /// Set LPSPI timing configurations.
12011244 ///
12021245 /// If you're not sure how to select these timing values, prefer
12031246 /// [`set_clock_hz`](Self::set_clock_hz).
12041247 pub fn set_clock_configs ( & mut self , timing : ClockConfigs ) {
1248+ self . ccr_cache . update ( timing) ;
12051249 ral:: write_reg!( ral:: lpspi, self . lpspi, CCR ,
12061250 SCKPCS : timing. sckpcs as u32 ,
12071251 PCSSCK : timing. pcssck as u32 ,
0 commit comments