@@ -61,6 +61,7 @@ pub use crate::hal::spi::{
61
61
use crate :: stm32;
62
62
use crate :: stm32:: rcc:: { d2ccip1r, d3ccipr} ;
63
63
use crate :: stm32:: spi1:: cfg1:: MBR_A as MBR ;
64
+ use core:: convert:: From ;
64
65
use core:: marker:: PhantomData ;
65
66
use core:: ptr;
66
67
use nb;
@@ -111,6 +112,76 @@ where
111
112
{
112
113
}
113
114
115
+ /// A structure for specifying SPI configuration.
116
+ ///
117
+ /// This structure uses builder semantics to generate the configuration.
118
+ ///
119
+ /// `Example`
120
+ /// ```
121
+ /// use embedded_hal::spi::Mode;
122
+ ///
123
+ /// let config = Config::new(Mode::MODE_0)
124
+ /// .manage_cs()
125
+ /// ```
126
+ #[ derive( Copy , Clone ) ]
127
+ pub struct Config {
128
+ mode : Mode ,
129
+ swap_miso_mosi : bool ,
130
+ cs_delay : f32 ,
131
+ managed_cs : bool ,
132
+ }
133
+
134
+ impl Config {
135
+ /// Create a default configuration for the SPI interface.
136
+ ///
137
+ /// Arguments:
138
+ /// * `mode` - The SPI mode to configure.
139
+ pub fn new ( mode : Mode ) -> Self {
140
+ Config {
141
+ mode : mode,
142
+ swap_miso_mosi : false ,
143
+ cs_delay : 0.0 ,
144
+ managed_cs : false ,
145
+ }
146
+ }
147
+
148
+ /// Specify that the SPI MISO/MOSI lines are swapped.
149
+ ///
150
+ /// Note:
151
+ /// * This function updates the HAL peripheral to treat the pin provided in the MISO parameter
152
+ /// as the MOSI pin and the pin provided in the MOSI parameter as the MISO pin.
153
+ pub fn swap_mosi_miso ( mut self ) -> Self {
154
+ self . swap_miso_mosi = true ;
155
+ self
156
+ }
157
+
158
+ /// Specify a delay between CS assertion and the beginning of the SPI transaction.
159
+ ///
160
+ /// Note:
161
+ /// * This function introduces a delay on SCK from the initiation of the transaction. The delay
162
+ /// is specified as a number of SCK cycles, so the actual delay may vary.
163
+ ///
164
+ /// Arguments:
165
+ /// * `delay` - The delay between CS assertion and the start of the transaction in seconds.
166
+ /// register for the output pin.
167
+ pub fn cs_delay ( mut self , delay : f32 ) -> Self {
168
+ self . cs_delay = delay;
169
+ self
170
+ }
171
+
172
+ /// CS pin is automatically managed by the SPI peripheral.
173
+ pub fn manage_cs ( mut self ) -> Self {
174
+ self . managed_cs = true ;
175
+ self
176
+ }
177
+ }
178
+
179
+ impl From < Mode > for Config {
180
+ fn from ( mode : Mode ) -> Self {
181
+ Self :: new ( mode)
182
+ }
183
+ }
184
+
114
185
/// A filler type for when the SCK pin is unnecessary
115
186
pub struct NoSck ;
116
187
/// A filler type for when the Miso pin is unnecessary
@@ -270,27 +341,29 @@ pub struct Spi<SPI, WORD = u8> {
270
341
pub trait SpiExt < SPI , WORD > : Sized {
271
342
type Rec : ResetEnable ;
272
343
273
- fn spi < PINS , T > (
344
+ fn spi < PINS , T , CONFIG > (
274
345
self ,
275
346
_pins : PINS ,
276
- mode : Mode ,
347
+ config : CONFIG ,
277
348
freq : T ,
278
349
prec : Self :: Rec ,
279
350
clocks : & CoreClocks ,
280
351
) -> Spi < SPI , WORD >
281
352
where
282
353
PINS : Pins < SPI > ,
283
- T : Into < Hertz > ;
354
+ T : Into < Hertz > ,
355
+ CONFIG : Into < Config > ;
284
356
285
- fn spi_unchecked < T > (
357
+ fn spi_unchecked < T , CONFIG > (
286
358
self ,
287
- mode : Mode ,
359
+ config : CONFIG ,
288
360
freq : T ,
289
361
prec : Self :: Rec ,
290
362
clocks : & CoreClocks ,
291
363
) -> Spi < SPI , WORD >
292
364
where
293
- T : Into < Hertz > ;
365
+ T : Into < Hertz > ,
366
+ CONFIG : Into < Config > ;
294
367
}
295
368
296
369
macro_rules! spi {
@@ -312,22 +385,25 @@ macro_rules! spi {
312
385
// For each $TY
313
386
$(
314
387
impl Spi <$SPIX, $TY> {
315
- pub fn $spiX<T >(
388
+ pub fn $spiX<T , CONFIG >(
316
389
spi: $SPIX,
317
- mode : Mode ,
390
+ config : CONFIG ,
318
391
freq: T ,
319
392
prec: rec:: $Rec,
320
393
clocks: & CoreClocks ,
321
394
) -> Self
322
395
where
323
396
T : Into <Hertz >,
397
+ CONFIG : Into <Config >,
324
398
{
325
399
// Enable clock for SPI
326
400
prec. enable( ) ;
327
401
328
402
// Disable SS output
329
403
spi. cfg2. write( |w| w. ssoe( ) . disabled( ) ) ;
330
404
405
+ let config: Config = config. into( ) ;
406
+
331
407
let spi_freq = freq. into( ) . 0 ;
332
408
let spi_ker_ck = match Self :: kernel_clk( clocks) {
333
409
Some ( ker_hz) => ker_hz. 0 ,
@@ -353,23 +429,46 @@ macro_rules! spi {
353
429
// ssi: select slave = master mode
354
430
spi. cr1. write( |w| w. ssi( ) . slave_not_selected( ) ) ;
355
431
432
+ // Calculate the CS->transaction cycle delay bits.
433
+ let cycle_delay: u8 = {
434
+ let mut delay: u32 = ( config. cs_delay * spi_freq as f32 ) as u32 ;
435
+
436
+ // If the cs-delay is specified as non-zero, add 1 to the delay cycles
437
+ // before truncation to an integer to ensure that we have at least as
438
+ // many cycles as required.
439
+ if config. cs_delay > 0.0_f32 {
440
+ delay = delay + 1 ;
441
+ }
442
+
443
+ if delay > 0xF {
444
+ delay = 0xF ;
445
+ }
446
+
447
+ delay as u8
448
+ } ;
449
+
450
+ // The calculated cycle delay may not be more than 4 bits wide for the
451
+ // configuration register.
452
+
356
453
// mstr: master configuration
357
454
// lsbfrst: MSB first
358
- // ssm: enable software slave management (NSS pin
359
- // free for other uses)
360
455
// comm: full-duplex
361
456
spi. cfg2. write( |w| {
362
457
w. cpha( )
363
- . bit( mode. phase ==
458
+ . bit( config . mode. phase ==
364
459
Phase :: CaptureOnSecondTransition )
365
460
. cpol( )
366
- . bit( mode. polarity == Polarity :: IdleHigh )
461
+ . bit( config . mode. polarity == Polarity :: IdleHigh )
367
462
. master( )
368
463
. master( )
369
464
. lsbfrst( )
370
465
. msbfirst( )
371
466
. ssm( )
372
- . enabled( )
467
+ . bit( config. managed_cs == false )
468
+ . mssi( )
469
+ . bits( cycle_delay)
470
+ . ioswp( )
471
+ . bit( config. swap_miso_mosi == true )
373
472
. comm( )
374
473
. full_duplex( )
375
474
} ) ;
@@ -460,28 +559,30 @@ macro_rules! spi {
460
559
impl SpiExt <$SPIX, $TY> for $SPIX {
461
560
type Rec = rec:: $Rec;
462
561
463
- fn spi<PINS , T >( self ,
562
+ fn spi<PINS , T , CONFIG >( self ,
464
563
_pins: PINS ,
465
- mode : Mode ,
564
+ config : CONFIG ,
466
565
freq: T ,
467
566
prec: rec:: $Rec,
468
567
clocks: & CoreClocks ) -> Spi <$SPIX, $TY>
469
568
where
470
569
PINS : Pins <$SPIX>,
471
- T : Into <Hertz >
570
+ T : Into <Hertz >,
571
+ CONFIG : Into <Config >,
472
572
{
473
- Spi :: <$SPIX, $TY>:: $spiX( self , mode , freq, prec, clocks)
573
+ Spi :: <$SPIX, $TY>:: $spiX( self , config , freq, prec, clocks)
474
574
}
475
575
476
- fn spi_unchecked<T >( self ,
477
- mode : Mode ,
576
+ fn spi_unchecked<T , CONFIG >( self ,
577
+ config : CONFIG ,
478
578
freq: T ,
479
579
prec: rec:: $Rec,
480
580
clocks: & CoreClocks ) -> Spi <$SPIX, $TY>
481
581
where
482
- T : Into <Hertz >
582
+ T : Into <Hertz >,
583
+ CONFIG : Into <Config >,
483
584
{
484
- Spi :: <$SPIX, $TY>:: $spiX( self , mode , freq, prec, clocks)
585
+ Spi :: <$SPIX, $TY>:: $spiX( self , config , freq, prec, clocks)
485
586
}
486
587
}
487
588
0 commit comments