Skip to content

Commit 98b8ea2

Browse files
committed
Add bidirectional mode for spi
1 parent 1be2fdc commit 98b8ea2

File tree

2 files changed

+161
-32
lines changed

2 files changed

+161
-32
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3838
- Added missing error flags for dma streams [#318]
3939
- Added PWM input capability to all compatable timers [#271]
4040
- [breaking-change] `gpio::Edge::{RISING, FALLING, RISING_FALLING}` are renamed to `Rising`, `Falling`, `RisingFalling`, respectively.
41+
- Bidi mode support for SPI [#349]
4142

4243
[#265]: https://github.com/stm32-rs/stm32f4xx-hal/pull/265
4344
[#271] https://github.com/stm32-rs/stm32f4xx-hal/pull/271
@@ -46,6 +47,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
4647
[#309]: https://github.com/stm32-rs/stm32f4xx-hal/pull/309
4748
[#313]: https://github.com/stm32-rs/stm32f4xx-hal/pull/313
4849
[#318]: https://github.com/stm32-rs/stm32f4xx-hal/pull/318
50+
[#349]: https://github.com/stm32-rs/stm32f4xx-hal/pull/349
4951

5052
### Changed
5153

src/spi.rs

Lines changed: 159 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -351,10 +351,16 @@ pub enum Event {
351351
Error,
352352
}
353353

354+
/// Normal mode - RX and TX pins are independent
355+
pub struct TransferModeNormal;
356+
/// BIDI mode - use TX pin as RX then spi receive data
357+
pub struct TransferModeBidi;
358+
354359
#[derive(Debug)]
355-
pub struct Spi<SPI, PINS> {
360+
pub struct Spi<SPI, PINS, TRANSFER_MODE> {
356361
spi: SPI,
357362
pins: PINS,
363+
transfer_mode: TRANSFER_MODE,
358364
}
359365

360366
// Implemented by all SPI instances
@@ -368,7 +374,7 @@ macro_rules! spi {
368374
($SPI:ident: ($spi:ident)) => {
369375
impl Instance for $SPI {}
370376

371-
impl<SCK, MISO, MOSI> Spi<$SPI, (SCK, MISO, MOSI)>
377+
impl<SCK, MISO, MOSI> Spi<$SPI, (SCK, MISO, MOSI), TransferModeNormal>
372378
where
373379
SCK: PinSck<$SPI>,
374380
MISO: PinMiso<$SPI>,
@@ -381,7 +387,7 @@ macro_rules! spi {
381387
mode: Mode,
382388
freq: Hertz,
383389
clocks: Clocks,
384-
) -> Self {
390+
) -> Spi<$SPI, (SCK, MISO, MOSI), TransferModeNormal> {
385391
Self::new(spi, pins, mode, freq, clocks)
386392
}
387393
}
@@ -403,30 +409,106 @@ spi! { SPI5: (spi5) }
403409
#[cfg(feature = "spi6")]
404410
spi! { SPI6: (spi6) }
405411

406-
impl<SPI, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI)>
412+
impl<SPI, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), TransferModeNormal>
407413
where
408414
SPI: Instance,
409415
SCK: PinSck<SPI>,
410416
MISO: PinMiso<SPI>,
411417
MOSI: PinMosi<SPI>,
412418
{
413-
pub fn new(spi: SPI, pins: (SCK, MISO, MOSI), mode: Mode, freq: Hertz, clocks: Clocks) -> Self {
419+
pub fn new(
420+
spi: SPI,
421+
pins: (SCK, MISO, MOSI),
422+
mode: Mode,
423+
freq: Hertz,
424+
clocks: Clocks,
425+
) -> Spi<SPI, (SCK, MISO, MOSI), TransferModeNormal> {
426+
unsafe {
427+
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
428+
let rcc = &(*RCC::ptr());
429+
SPI::enable(rcc);
430+
SPI::reset(rcc);
431+
}
432+
433+
Spi {
434+
spi,
435+
pins,
436+
transfer_mode: TransferModeNormal,
437+
}
438+
.pre_init(mode, freq, SPI::get_frequency(&clocks))
439+
.init()
440+
}
441+
442+
pub fn new_bidi(
443+
spi: SPI,
444+
pins: (SCK, MISO, MOSI),
445+
mode: Mode,
446+
freq: Hertz,
447+
clocks: Clocks,
448+
) -> Spi<SPI, (SCK, MISO, MOSI), TransferModeBidi> {
414449
unsafe {
415450
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
416451
let rcc = &(*RCC::ptr());
417452
SPI::enable(rcc);
418453
SPI::reset(rcc);
419454
}
420455

421-
Spi { spi, pins }.init(mode, freq, SPI::get_frequency(&clocks))
456+
Spi {
457+
spi,
458+
pins,
459+
transfer_mode: TransferModeBidi,
460+
}
461+
.pre_init(mode, freq, SPI::get_frequency(&clocks))
462+
.init()
422463
}
423464
}
424465

425-
impl<SPI, PINS> Spi<SPI, PINS>
466+
impl<SPI, PINS> Spi<SPI, PINS, TransferModeNormal>
426467
where
427468
SPI: Instance,
428469
{
429-
pub fn init(self, mode: Mode, freq: Hertz, clock: Hertz) -> Self {
470+
pub fn init(self) -> Self {
471+
self.spi.cr1.modify(|_, w| {
472+
// bidimode: 2-line unidirectional
473+
w.bidimode()
474+
.clear_bit()
475+
.bidioe()
476+
.clear_bit()
477+
// spe: enable the SPI bus
478+
.spe()
479+
.set_bit()
480+
});
481+
482+
self
483+
}
484+
}
485+
486+
impl<SPI, PINS> Spi<SPI, PINS, TransferModeBidi>
487+
where
488+
SPI: Instance,
489+
{
490+
pub fn init(self) -> Self {
491+
self.spi.cr1.modify(|_, w| {
492+
// bidimode: 1-line unidirectional
493+
w.bidimode()
494+
.set_bit()
495+
.bidioe()
496+
.set_bit()
497+
// spe: enable the SPI bus
498+
.spe()
499+
.set_bit()
500+
});
501+
502+
self
503+
}
504+
}
505+
506+
impl<SPI, PINS, TRANSFER_MODE> Spi<SPI, PINS, TRANSFER_MODE>
507+
where
508+
SPI: Instance,
509+
{
510+
/// Pre initializing the SPI bus.
511+
pub fn pre_init(self, mode: Mode, freq: Hertz, clock: Hertz) -> Self {
430512
// disable SS output
431513
self.spi.cr2.write(|w| w.ssoe().clear_bit());
432514

@@ -466,12 +548,6 @@ where
466548
// dff: 8 bit frames
467549
.dff()
468550
.clear_bit()
469-
// bidimode: 2-line unidirectional
470-
.bidimode()
471-
.clear_bit()
472-
// spe: enable the SPI bus
473-
.spe()
474-
.set_bit()
475551
});
476552

477553
self
@@ -533,15 +609,9 @@ where
533609
pub fn free(self) -> (SPI, PINS) {
534610
(self.spi, self.pins)
535611
}
536-
}
537612

538-
impl<SPI, PINS> spi::FullDuplex<u8> for Spi<SPI, PINS>
539-
where
540-
SPI: Instance,
541-
{
542-
type Error = Error;
543-
544-
fn read(&mut self) -> nb::Result<u8, Error> {
613+
#[inline(always)]
614+
fn check_read(&mut self) -> nb::Result<u8, Error> {
545615
let sr = self.spi.sr.read();
546616

547617
Err(if sr.ovr().bit_is_set() {
@@ -551,15 +621,14 @@ where
551621
} else if sr.crcerr().bit_is_set() {
552622
Error::Crc.into()
553623
} else if sr.rxne().bit_is_set() {
554-
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
555-
// reading a half-word)
556-
return Ok(unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) });
624+
return Ok(self.read_u8());
557625
} else {
558626
nb::Error::WouldBlock
559627
})
560628
}
561629

562-
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
630+
#[inline(always)]
631+
fn check_send(&mut self, byte: u8) -> nb::Result<(), Error> {
563632
let sr = self.spi.sr.read();
564633

565634
Err(if sr.ovr().bit_is_set() {
@@ -578,21 +647,79 @@ where
578647
});
579648
Error::Crc.into()
580649
} else if sr.txe().bit_is_set() {
581-
// NOTE(write_volatile) see note above
582-
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
583-
return Ok(());
650+
return Ok(self.send_u8(byte));
584651
} else {
585652
nb::Error::WouldBlock
586653
})
587654
}
655+
656+
#[inline(always)]
657+
fn read_u8(&mut self) -> u8 {
658+
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows reading a half-word)
659+
unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }
660+
}
661+
662+
#[inline(always)]
663+
fn send_u8(&mut self, byte: u8) {
664+
// NOTE(write_volatile) see note above
665+
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
666+
}
588667
}
589668

590-
impl<SPI, PINS> embedded_hal::blocking::spi::transfer::Default<u8> for Spi<SPI, PINS> where
591-
SPI: Instance
669+
impl<SPI, PINS> spi::FullDuplex<u8> for Spi<SPI, PINS, TransferModeNormal>
670+
where
671+
SPI: Instance,
672+
{
673+
type Error = Error;
674+
675+
fn read(&mut self) -> nb::Result<u8, Error> {
676+
self.check_read()
677+
}
678+
679+
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
680+
self.check_send(byte)
681+
}
682+
}
683+
684+
impl<SPI, PINS> spi::FullDuplex<u8> for Spi<SPI, PINS, TransferModeBidi>
685+
where
686+
SPI: Instance,
687+
{
688+
type Error = Error;
689+
690+
fn read(&mut self) -> nb::Result<u8, Error> {
691+
self.spi.cr1.modify(|_, w| w.bidioe().clear_bit());
692+
self.check_read()
693+
}
694+
695+
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
696+
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
697+
self.check_send(byte)
698+
}
699+
}
700+
701+
impl<SPI, PINS> embedded_hal::blocking::spi::transfer::Default<u8>
702+
for Spi<SPI, PINS, TransferModeNormal>
703+
where
704+
SPI: Instance,
705+
{
706+
}
707+
708+
impl<SPI, PINS> embedded_hal::blocking::spi::write::Default<u8>
709+
for Spi<SPI, PINS, TransferModeNormal>
710+
where
711+
SPI: Instance,
712+
{
713+
}
714+
715+
impl<SPI, PINS> embedded_hal::blocking::spi::transfer::Default<u8>
716+
for Spi<SPI, PINS, TransferModeBidi>
717+
where
718+
SPI: Instance,
592719
{
593720
}
594721

595-
impl<SPI, PINS> embedded_hal::blocking::spi::write::Default<u8> for Spi<SPI, PINS> where
722+
impl<SPI, PINS> embedded_hal::blocking::spi::write::Default<u8> for Spi<SPI, PINS, TransferModeBidi> where
596723
SPI: Instance
597724
{
598725
}

0 commit comments

Comments
 (0)