Skip to content

Commit

Permalink
SPI bidi 2 pins & rm unused bidioe
Browse files Browse the repository at this point in the history
  • Loading branch information
burrbull committed Apr 26, 2023
1 parent 5a39f12 commit e8a17a4
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 81 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Add missing timer pins [#536]
- Revised temperature sensor input pins for all MCUs [#529]
- Support `u16` read/write for SPI
- SPI bidi takes 2 pins
- Use `bool` for BIDI mode type
- `PwmHz::get_period`: fix computation of return value, prevent division by zero
- apply #[inline] attribute to bitbanding functions [#517]
Expand Down
5 changes: 2 additions & 3 deletions examples/ist7920-bidi-normal-spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use stm32f4xx_hal as hal;

use crate::hal::{pac, prelude::*, timer::Timer};

use hal::spi::{Mode, NoMiso, Phase, Polarity};
use hal::spi::{Mode, Phase, Polarity};

use display_interface_spi::SPIInterface;
use ist7920::Ist7920;
Expand All @@ -29,7 +29,6 @@ fn main() -> ! {
led.set_low();

let sck = gpiob.pb3.into_alternate();
let miso = NoMiso::new();
let mosi = gpiob.pb5.into_alternate();

let dc = gpiob.pb4.into_push_pull_output();
Expand All @@ -46,7 +45,7 @@ fn main() -> ! {
// Change spi transfer mode to Bidi for more efficient operations.
// let spi = Spi::new(dp.SPI1, (sck, miso, mosi), mode, 8.MHz(), &clocks).to_bidi_transfer_mode();
// or
let spi = dp.SPI1.spi_bidi((sck, miso, mosi), mode, 8.MHz(), &clocks);
let spi = dp.SPI1.spi_bidi((sck, mosi), mode, 8.MHz(), &clocks);

let iface = SPIInterface::new(spi, dc, cs);

Expand Down
122 changes: 73 additions & 49 deletions src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -211,15 +211,13 @@ pub trait SpiExt: Sized + Instance {

fn spi_bidi(
self,
pins: (
impl Into<Self::Sck>,
impl Into<Self::Miso>,
impl Into<Self::Mosi>,
),
pins: (impl Into<Self::Sck>, impl Into<Self::Mosi>),
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, true, u8>;
) -> Spi<Self, true, u8>
where
NoPin: Into<Self::Miso>;

fn spi_slave(
self,
Expand All @@ -237,19 +235,15 @@ pub trait SpiExt: Sized + Instance {
pins: (
impl Into<Self::Sck>,
impl Into<Self::Miso>,
impl Into<Self::Mosi>,
Option<Self::Nss>,
),
mode: impl Into<Mode>,
) -> SpiSlave<Self, true, u8>;
) -> SpiSlave<Self, true, u8>
where
NoPin: Into<Self::Mosi>;
}

impl<SPI: Instance> SpiExt for SPI {
/// Enables the SPI clock, resets the peripheral, sets `Alternate` mode for `pins` and initialize the peripheral as SPI Master Normal mode.
///
/// # Note
/// Depending on `freq` you may need to set GPIO speed for `pins` (the `Speed::Low` is default for GPIO) before create `Spi` instance.
/// Otherwise it may lead to the 'wrong last bit in every received byte' problem.
fn spi(
self,
pins: (
Expand All @@ -270,15 +264,14 @@ impl<SPI: Instance> SpiExt for SPI {
/// Otherwise it may lead to the 'wrong last bit in every received byte' problem.
fn spi_bidi(
self,
pins: (
impl Into<Self::Sck>,
impl Into<Self::Miso>,
impl Into<Self::Mosi>,
),
pins: (impl Into<Self::Sck>, impl Into<Self::Mosi>),
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, true, u8> {
) -> Spi<Self, true, u8>
where
NoPin: Into<Self::Miso>,
{
Spi::new_bidi(self, pins, mode, freq, clocks)
}
/// Enables the SPI clock, resets the peripheral, sets `Alternate` mode for `pins` and initialize the peripheral as SPI Slave Normal mode.
Expand Down Expand Up @@ -308,11 +301,13 @@ impl<SPI: Instance> SpiExt for SPI {
pins: (
impl Into<Self::Sck>,
impl Into<Self::Miso>,
impl Into<Self::Mosi>,
Option<Self::Nss>,
),
mode: impl Into<Mode>,
) -> SpiSlave<Self, true, u8> {
) -> SpiSlave<Self, true, u8>
where
NoPin: Into<Self::Mosi>,
{
SpiSlave::new_bidi(self, pins, mode)
}
}
Expand Down Expand Up @@ -457,23 +452,22 @@ impl<SPI: Instance> Spi<SPI, true, u8> {
/// Otherwise it may lead to the 'wrong last bit in every received byte' problem.
pub fn new_bidi(
spi: SPI,
pins: (
impl Into<SPI::Sck>,
impl Into<SPI::Miso>,
impl Into<SPI::Mosi>,
),
pins: (impl Into<SPI::Sck>, impl Into<SPI::Mosi>),
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Self {
) -> Self
where
NoPin: Into<SPI::Miso>,
{
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());
SPI::enable(rcc);
SPI::reset(rcc);
}

let pins = (pins.0.into(), pins.1.into(), pins.2.into());
let pins = (pins.0.into(), NoPin::new().into(), pins.1.into());

Self::_new(spi, pins)
.pre_init(mode.into(), freq, SPI::clock(clocks))
Expand Down Expand Up @@ -518,22 +512,20 @@ impl<SPI: Instance> SpiSlave<SPI, true, u8> {
/// Otherwise it may lead to the 'wrong last bit in every received byte' problem.
pub fn new_bidi(
spi: SPI,
pins: (
impl Into<SPI::Sck>,
impl Into<SPI::Miso>,
impl Into<SPI::Mosi>,
Option<SPI::Nss>,
),
pins: (impl Into<SPI::Sck>, impl Into<SPI::Miso>, Option<SPI::Nss>),
mode: impl Into<Mode>,
) -> Self {
) -> Self
where
NoPin: Into<SPI::Mosi>,
{
unsafe {
// NOTE(unsafe) this reference will only be used for atomic writes with no side effects.
let rcc = &(*RCC::ptr());
SPI::enable(rcc);
SPI::reset(rcc);
}

let pins = (pins.0.into(), pins.1.into(), pins.2.into(), pins.3);
let pins = (pins.0.into(), pins.1.into(), NoPin::new().into(), pins.2);

Self::_new(spi, pins).pre_init(mode.into()).init()
}
Expand Down Expand Up @@ -565,7 +557,7 @@ impl<SPI: Instance, const BIDI: bool, W> Spi<SPI, BIDI, W> {
/// Convert the spi to another mode.
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> Spi<SPI, BIDI2, W2> {
let mut spi = Spi::_new(self.inner.spi, self.pins);
spi.enable(false);
spi.disable();
spi.init()
}
}
Expand All @@ -582,7 +574,7 @@ impl<SPI: Instance, const BIDI: bool, W> SpiSlave<SPI, BIDI, W> {
/// Convert the spi to another mode.
fn into_mode<const BIDI2: bool, W2: FrameSize>(self) -> SpiSlave<SPI, BIDI2, W2> {
let mut spi = SpiSlave::_new(self.inner.spi, self.pins);
spi.enable(false);
spi.disable();
spi.init()
}
}
Expand Down Expand Up @@ -662,10 +654,20 @@ impl<SPI: Instance> Inner<SPI> {
}

/// Enable/disable spi
pub fn enable(&mut self, enable: bool) {
pub fn enable(&mut self) {
self.spi.cr1.modify(|_, w| {
// spe: enable the SPI bus
w.spe().set_bit()
});
}

/// Enable/disable spi
pub fn disable(&mut self) {
// Wait for !BSY
while self.is_busy() {}
self.spi.cr1.modify(|_, w| {
// spe: enable the SPI bus
w.spe().bit(enable)
w.spe().clear_bit()
});
}

Expand Down Expand Up @@ -745,6 +747,16 @@ impl<SPI: Instance> Inner<SPI> {
self.spi.sr.read().ovr().bit_is_set()
}

#[inline]
fn bidi_output(&mut self) {
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
}

#[inline]
fn bidi_input(&mut self) {
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
}

fn read_data_reg<W: FrameSize>(&mut self) -> W {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
// reading a half-word)
Expand Down Expand Up @@ -933,14 +945,14 @@ impl<SPI: Instance, const BIDI: bool, W: FrameSize> Spi<SPI, BIDI, W> {
impl<SPI: Instance, const BIDI: bool, W: FrameSize> SpiSlave<SPI, BIDI, W> {
pub fn read_nonblocking(&mut self) -> nb::Result<W, Error> {
if BIDI {
self.spi.cr1.modify(|_, w| w.bidioe().clear_bit());
self.bidi_input();
}
self.check_read()
}

pub fn write_nonblocking(&mut self, byte: W) -> nb::Result<(), Error> {
if BIDI {
self.spi.cr1.modify(|_, w| w.bidioe().set_bit());
self.bidi_output();
}
self.check_send(byte)
}
Expand Down Expand Up @@ -970,20 +982,32 @@ impl<SPI: Instance, const BIDI: bool, W: FrameSize> SpiSlave<SPI, BIDI, W> {
}

pub fn write(&mut self, words: &[W]) -> Result<(), Error> {
for word in words {
nb::block!(self.write_nonblocking(*word))?;
if !BIDI {
nb::block!(self.read_nonblocking())?;
if BIDI {
self.bidi_output();
for word in words {
nb::block!(self.check_send(*word))?;
}
} else {
for word in words {
nb::block!(self.check_send(*word))?;
nb::block!(self.check_read::<W>())?;
}
}

Ok(())
}

pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
for word in words {
nb::block!(self.write_nonblocking(W::default()))?;
*word = nb::block!(self.read_nonblocking())?;
if BIDI {
self.bidi_input();
for word in words {
*word = nb::block!(self.check_read())?;
}
} else {
for word in words {
nb::block!(self.check_send(W::default()))?;
*word = nb::block!(self.check_read())?;
}
}

Ok(())
Expand Down
30 changes: 20 additions & 10 deletions src/spi/hal_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ mod blocking {
use super::super::{Error, Instance, Spi};
use embedded_hal::blocking::spi::{Operation, Transactional, Transfer, Write, WriteIter};

impl<SPI, const BIDI: bool> Transfer<u8> for Spi<SPI, BIDI, u8>
impl<SPI> Transfer<u8> for Spi<SPI, false, u8>
where
SPI: Instance,
{
Expand All @@ -64,7 +64,7 @@ mod blocking {
}
}

impl<SPI, const BIDI: bool> Transfer<u16> for Spi<SPI, BIDI, u16>
impl<SPI> Transfer<u16> for Spi<SPI, false, u16>
where
SPI: Instance,
{
Expand Down Expand Up @@ -97,10 +97,15 @@ mod blocking {
where
WI: IntoIterator<Item = u8>,
{
for word in words.into_iter() {
nb::block!(self.write_nonblocking(word))?;
if !BIDI {
nb::block!(self.read_nonblocking())?;
if BIDI {
self.bidi_output();
for word in words.into_iter() {
nb::block!(self.check_send(word))?;
}
} else {
for word in words.into_iter() {
nb::block!(self.check_send(word))?;
nb::block!(self.check_read::<u8>())?;
}
}

Expand Down Expand Up @@ -129,10 +134,15 @@ mod blocking {
where
WI: IntoIterator<Item = u16>,
{
for word in words.into_iter() {
nb::block!(self.write_nonblocking(word))?;
if !BIDI {
nb::block!(self.read_nonblocking())?;
if BIDI {
self.bidi_output();
for word in words.into_iter() {
nb::block!(self.check_send(word))?;
}
} else {
for word in words.into_iter() {
nb::block!(self.check_send(word))?;
nb::block!(self.check_read::<u16>())?;
}
}

Expand Down
23 changes: 4 additions & 19 deletions src/spi/hal_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,9 @@ mod nb {

mod blocking {
use super::super::{FrameSize, Instance, Spi};
use embedded_hal_one::spi::{
blocking::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite},
nb::FullDuplex,
};
use embedded_hal_one::spi::blocking::{SpiBus, SpiBusFlush, SpiBusRead, SpiBusWrite};

impl<SPI, const BIDI: bool, W: FrameSize + 'static> SpiBus<W> for Spi<SPI, BIDI, W>
impl<SPI, W: FrameSize + 'static> SpiBus<W> for Spi<SPI, false, W>
where
SPI: Instance,
{
Expand All @@ -95,14 +92,7 @@ mod blocking {
SPI: Instance,
{
fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
for word in words {
nb::block!(self.write_nonblocking(*word))?;
if !BIDI {
nb::block!(self.read_nonblocking())?;
}
}

Ok(())
self.write(words)
}
}

Expand All @@ -111,12 +101,7 @@ mod blocking {
SPI: Instance,
{
fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
for word in words {
nb::block!(<Self as FullDuplex<W>>::write(self, W::default()))?;
*word = nb::block!(<Self as FullDuplex<W>>::read(self))?;
}

Ok(())
self.read(words)
}
}
}

0 comments on commit e8a17a4

Please sign in to comment.