30
30
//! phase: Phase::CaptureOnSecondTransition,
31
31
//! }, 1.mhz(), &mut rcc);
32
32
//!
33
- //! let mut data = [ 0 ];
33
+ //! let mut data = [0 ];
34
34
//! loop {
35
35
//! spi.transfer(&mut data).unwrap();
36
36
//! }
37
37
//! });
38
38
//! ```
39
39
40
+ use core:: marker:: PhantomData ;
40
41
use core:: { ops:: Deref , ptr} ;
41
42
42
43
use nb;
@@ -68,6 +69,12 @@ use crate::rcc::{Clocks, Rcc};
68
69
69
70
use crate :: time:: Hertz ;
70
71
72
+ /// Typestate for 8-bit transfer size
73
+ pub struct EightBit ;
74
+
75
+ /// Typestate for 16-bit transfer size
76
+ pub struct SixteenBit ;
77
+
71
78
/// SPI error
72
79
#[ derive( Debug ) ]
73
80
pub enum Error {
@@ -82,9 +89,10 @@ pub enum Error {
82
89
}
83
90
84
91
/// SPI abstraction
85
- pub struct Spi < SPI , SCKPIN , MISOPIN , MOSIPIN > {
92
+ pub struct Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , WIDTH > {
86
93
spi : SPI ,
87
94
pins : ( SCKPIN , MISOPIN , MOSIPIN ) ,
95
+ _width : PhantomData < WIDTH > ,
88
96
}
89
97
90
98
pub trait SckPin < SPI > { }
@@ -204,7 +212,7 @@ spi_pins! {
204
212
macro_rules! spi {
205
213
( $( $SPI: ident: ( $spi: ident, $spiXen: ident, $spiXrst: ident, $apbenr: ident, $apbrstr: ident) , ) +) => {
206
214
$(
207
- impl <SCKPIN , MISOPIN , MOSIPIN > Spi <$SPI, SCKPIN , MISOPIN , MOSIPIN > {
215
+ impl <SCKPIN , MISOPIN , MOSIPIN > Spi <$SPI, SCKPIN , MISOPIN , MOSIPIN , EightBit > {
208
216
/// Creates a new spi instance
209
217
pub fn $spi<F >(
210
218
spi: $SPI,
@@ -226,7 +234,7 @@ macro_rules! spi {
226
234
rcc. regs. $apbrstr. modify( |_, w| w. $spiXrst( ) . set_bit( ) ) ;
227
235
rcc. regs. $apbrstr. modify( |_, w| w. $spiXrst( ) . clear_bit( ) ) ;
228
236
229
- Spi { spi, pins } . spi_init( mode, speed, rcc. clocks)
237
+ Spi :: <$SPI , SCKPIN , MISOPIN , MOSIPIN , EightBit > { spi, pins, _width : PhantomData } . spi_init( mode, speed, rcc. clocks) . into_8bit_width ( )
230
238
}
231
239
}
232
240
) +
@@ -258,27 +266,17 @@ spi! {
258
266
#[ allow( dead_code) ]
259
267
type SpiRegisterBlock = crate :: pac:: spi1:: RegisterBlock ;
260
268
261
- impl < SPI , SCKPIN , MISOPIN , MOSIPIN > Spi < SPI , SCKPIN , MISOPIN , MOSIPIN >
269
+ impl < SPI , SCKPIN , MISOPIN , MOSIPIN , WIDTH > Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , WIDTH >
262
270
where
263
271
SPI : Deref < Target = SpiRegisterBlock > ,
264
272
{
265
- fn spi_init < F > ( self : Self , mode : Mode , speed : F , clocks : Clocks ) -> Self
273
+ fn spi_init < F > ( self , mode : Mode , speed : F , clocks : Clocks ) -> Self
266
274
where
267
275
F : Into < Hertz > ,
268
276
{
269
277
/* Make sure the SPI unit is disabled so we can configure it */
270
278
self . spi . cr1 . modify ( |_, w| w. spe ( ) . clear_bit ( ) ) ;
271
279
272
- // FRXTH: 8-bit threshold on RX FIFO
273
- // DS: 8-bit data size
274
- // SSOE: cleared to disable SS output
275
- //
276
- // NOTE(unsafe): DS reserved bit patterns are 0b0000, 0b0001, and 0b0010. 0b0111 is valid
277
- // (reference manual, pp 804)
278
- self . spi
279
- . cr2
280
- . write ( |w| unsafe { w. frxth ( ) . set_bit ( ) . ds ( ) . bits ( 0b0111 ) . ssoe ( ) . clear_bit ( ) } ) ;
281
-
282
280
let br = match clocks. pclk ( ) . 0 / speed. into ( ) . 0 {
283
281
0 => unreachable ! ( ) ,
284
282
1 ..=2 => 0b000 ,
@@ -323,19 +321,50 @@ where
323
321
324
322
self
325
323
}
326
- pub fn release ( self ) -> ( SPI , ( SCKPIN , MISOPIN , MOSIPIN ) ) {
327
- ( self . spi , self . pins )
324
+
325
+ pub fn into_8bit_width ( self ) -> Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , EightBit > {
326
+ // FRXTH: 8-bit threshold on RX FIFO
327
+ // DS: 8-bit data size
328
+ // SSOE: cleared to disable SS output
329
+ self . spi
330
+ . cr2
331
+ . write ( |w| w. frxth ( ) . set_bit ( ) . ds ( ) . eight_bit ( ) . ssoe ( ) . clear_bit ( ) ) ;
332
+
333
+ Spi {
334
+ spi : self . spi ,
335
+ pins : self . pins ,
336
+ _width : PhantomData ,
337
+ }
328
338
}
329
- }
330
339
331
- impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: spi:: FullDuplex < u8 >
332
- for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN >
333
- where
334
- SPI : Deref < Target = SpiRegisterBlock > ,
335
- {
336
- type Error = Error ;
340
+ pub fn into_16bit_width ( self ) -> Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , SixteenBit > {
341
+ // FRXTH: 16-bit threshold on RX FIFO
342
+ // DS: 8-bit data size
343
+ // SSOE: cleared to disable SS output
344
+ self . spi
345
+ . cr2
346
+ . write ( |w| w. frxth ( ) . set_bit ( ) . ds ( ) . sixteen_bit ( ) . ssoe ( ) . clear_bit ( ) ) ;
337
347
338
- fn read ( & mut self ) -> nb:: Result < u8 , Error > {
348
+ Spi {
349
+ spi : self . spi ,
350
+ pins : self . pins ,
351
+ _width : PhantomData ,
352
+ }
353
+ }
354
+
355
+ fn set_send_only ( & mut self ) {
356
+ self . spi
357
+ . cr1
358
+ . modify ( |_, w| w. bidimode ( ) . set_bit ( ) . bidioe ( ) . set_bit ( ) ) ;
359
+ }
360
+
361
+ fn set_bidi ( & mut self ) {
362
+ self . spi
363
+ . cr1
364
+ . modify ( |_, w| w. bidimode ( ) . clear_bit ( ) . bidioe ( ) . clear_bit ( ) ) ;
365
+ }
366
+
367
+ fn check_read ( & mut self ) -> nb:: Result < ( ) , Error > {
339
368
let sr = self . spi . sr . read ( ) ;
340
369
341
370
Err ( if sr. ovr ( ) . bit_is_set ( ) {
@@ -345,15 +374,26 @@ where
345
374
} else if sr. crcerr ( ) . bit_is_set ( ) {
346
375
nb:: Error :: Other ( Error :: Crc )
347
376
} else if sr. rxne ( ) . bit_is_set ( ) {
348
- // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
349
- // reading a half-word)
350
- return Ok ( unsafe { ptr:: read_volatile ( & self . spi . dr as * const _ as * const u8 ) } ) ;
377
+ return Ok ( ( ) ) ;
351
378
} else {
352
379
nb:: Error :: WouldBlock
353
380
} )
354
381
}
355
382
356
- fn send ( & mut self , byte : u8 ) -> nb:: Result < ( ) , Error > {
383
+ fn send_buffer_size ( & mut self ) -> u8 {
384
+ match self . spi . sr . read ( ) . ftlvl ( ) . bits ( ) {
385
+ // FIFO empty
386
+ 0 => 4 ,
387
+ // FIFO 1/4 full
388
+ 1 => 3 ,
389
+ // FIFO 1/2 full
390
+ 2 => 2 ,
391
+ // FIFO full
392
+ _ => 0 ,
393
+ }
394
+ }
395
+
396
+ fn check_send ( & mut self ) -> nb:: Result < ( ) , Error > {
357
397
let sr = self . spi . sr . read ( ) ;
358
398
359
399
Err ( if sr. ovr ( ) . bit_is_set ( ) {
@@ -363,25 +403,132 @@ where
363
403
} else if sr. crcerr ( ) . bit_is_set ( ) {
364
404
nb:: Error :: Other ( Error :: Crc )
365
405
} else if sr. txe ( ) . bit_is_set ( ) {
366
- // NOTE(write_volatile) see note above
367
- unsafe { ptr:: write_volatile ( & self . spi . dr as * const _ as * mut u8 , byte) }
368
406
return Ok ( ( ) ) ;
369
407
} else {
370
408
nb:: Error :: WouldBlock
371
409
} )
372
410
}
411
+
412
+ fn read_u8 ( & mut self ) -> u8 {
413
+ // NOTE(read_volatile) read only 1 byte (the svd2rust API only allows reading a half-word)
414
+ unsafe { ptr:: read_volatile ( & self . spi . dr as * const _ as * const u8 ) }
415
+ }
416
+
417
+ fn send_u8 ( & mut self , byte : u8 ) {
418
+ // NOTE(write_volatile) see note above
419
+ unsafe { ptr:: write_volatile ( & self . spi . dr as * const _ as * mut u8 , byte) }
420
+ }
421
+
422
+ fn read_u16 ( & mut self ) -> u16 {
423
+ // NOTE(read_volatile) read only 2 bytes (the svd2rust API only allows reading a half-word)
424
+ unsafe { ptr:: read_volatile ( & self . spi . dr as * const _ as * const u16 ) }
425
+ }
426
+
427
+ fn send_u16 ( & mut self , byte : u16 ) {
428
+ // NOTE(write_volatile) see note above
429
+ unsafe { ptr:: write_volatile ( & self . spi . dr as * const _ as * mut u16 , byte) }
430
+ }
431
+
432
+ pub fn release ( self ) -> ( SPI , ( SCKPIN , MISOPIN , MOSIPIN ) ) {
433
+ ( self . spi , self . pins )
434
+ }
373
435
}
374
436
375
- impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: transfer :: Default < u8 >
376
- for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN >
437
+ impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: Transfer < u8 >
438
+ for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , EightBit >
377
439
where
378
440
SPI : Deref < Target = SpiRegisterBlock > ,
379
441
{
442
+ type Error = Error ;
443
+
444
+ fn transfer < ' w > ( & mut self , words : & ' w mut [ u8 ] ) -> Result < & ' w [ u8 ] , Self :: Error > {
445
+ // We want to transfer bidirectionally, make sure we're in the correct mode
446
+ self . set_bidi ( ) ;
447
+
448
+ for word in words. iter_mut ( ) {
449
+ nb:: block!( self . check_send( ) ) ?;
450
+ self . send_u8 ( word. clone ( ) ) ;
451
+ nb:: block!( self . check_read( ) ) ?;
452
+ * word = self . read_u8 ( ) ;
453
+ }
454
+
455
+ Ok ( words)
456
+ }
380
457
}
381
458
382
- impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: write :: Default < u8 >
383
- for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN >
459
+ impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: Write < u8 >
460
+ for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , EightBit >
384
461
where
385
462
SPI : Deref < Target = SpiRegisterBlock > ,
386
463
{
464
+ type Error = Error ;
465
+
466
+ fn write ( & mut self , words : & [ u8 ] ) -> Result < ( ) , Self :: Error > {
467
+ let mut bufcap: u8 = 0 ;
468
+
469
+ // We only want to send, so we don't need to worry about the receive buffer overflowing
470
+ self . set_send_only ( ) ;
471
+
472
+ // Make sure we don't continue with an error condition
473
+ nb:: block!( self . check_send( ) ) ?;
474
+
475
+ // We have a 32 bit buffer to work with, so let's fill it before checking the status
476
+ for word in words {
477
+ // Loop as long as our send buffer is full
478
+ while bufcap == 0 {
479
+ bufcap = self . send_buffer_size ( ) ;
480
+ }
481
+
482
+ self . send_u8 ( * word) ;
483
+ bufcap -= 1 ;
484
+ }
485
+
486
+ // Do one last status register check before continuing
487
+ self . check_send ( ) . ok ( ) ;
488
+ Ok ( ( ) )
489
+ }
490
+ }
491
+
492
+ impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: Transfer < u16 >
493
+ for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , SixteenBit >
494
+ where
495
+ SPI : Deref < Target = SpiRegisterBlock > ,
496
+ {
497
+ type Error = Error ;
498
+
499
+ fn transfer < ' w > ( & mut self , words : & ' w mut [ u16 ] ) -> Result < & ' w [ u16 ] , Self :: Error > {
500
+ // We want to transfer bidirectionally, make sure we're in the correct mode
501
+ self . set_bidi ( ) ;
502
+
503
+ for word in words. iter_mut ( ) {
504
+ nb:: block!( self . check_send( ) ) ?;
505
+ self . send_u16 ( * word) ;
506
+ nb:: block!( self . check_read( ) ) ?;
507
+ * word = self . read_u16 ( ) ;
508
+ }
509
+
510
+ Ok ( words)
511
+ }
512
+ }
513
+
514
+ impl < SPI , SCKPIN , MISOPIN , MOSIPIN > :: embedded_hal:: blocking:: spi:: Write < u16 >
515
+ for Spi < SPI , SCKPIN , MISOPIN , MOSIPIN , SixteenBit >
516
+ where
517
+ SPI : Deref < Target = SpiRegisterBlock > ,
518
+ {
519
+ type Error = Error ;
520
+
521
+ fn write ( & mut self , words : & [ u16 ] ) -> Result < ( ) , Self :: Error > {
522
+ // We only want to send, so we don't need to worry about the receive buffer overflowing
523
+ self . set_send_only ( ) ;
524
+
525
+ for word in words {
526
+ nb:: block!( self . check_send( ) ) ?;
527
+ self . send_u16 ( word. clone ( ) ) ;
528
+ }
529
+
530
+ // Do one last status register check before continuing
531
+ self . check_send ( ) . ok ( ) ;
532
+ Ok ( ( ) )
533
+ }
387
534
}
0 commit comments