Skip to content

Spi u16 frame #524

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Changed

- Support `u16` read/write for SPI
- 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
158 changes: 116 additions & 42 deletions src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,32 @@ impl Ms for Master {
const MSTR: bool = true;
}

pub trait FrameSize: Copy + Default {
const DFF: bool;
}

impl FrameSize for u8 {
const DFF: bool = false;
}

impl FrameSize for u16 {
const DFF: bool = true;
}

/// The bit format to send the data in
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BitFormat {
/// Least significant bit first
LsbFirst,
/// Most significant bit first
MsbFirst,
}

#[derive(Debug)]
pub struct Spi<SPI, PINS, const BIDI: bool = false, OPERATION = Master> {
pub struct Spi<SPI, PINS, const BIDI: bool = false, W = u8, OPERATION = Master> {
spi: SPI,
pins: PINS,
_operation: PhantomData<OPERATION>,
_operation: PhantomData<(W, OPERATION)>,
}

// Implemented by all SPI instances
Expand All @@ -149,8 +170,8 @@ pub trait Instance:
// Implemented by all SPI instances
macro_rules! spi {
($SPI:ty: $Spi:ident) => {
pub type $Spi<PINS, const BIDI: bool = false, OPERATION = Master> =
Spi<$SPI, PINS, BIDI, OPERATION>;
pub type $Spi<PINS, const BIDI: bool = false, W = u8, OPERATION = Master> =
Spi<$SPI, PINS, BIDI, W, OPERATION>;

impl Instance for $SPI {
fn ptr() -> *const spi1::RegisterBlock {
Expand Down Expand Up @@ -182,7 +203,7 @@ pub trait SpiExt: Sized + Instance {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), false, Master>
) -> Spi<Self, (SCK, MISO, MOSI), false, u8, Master>
where
(SCK, MISO, MOSI): Pins<Self>;
fn spi_bidi<SCK, MISO, MOSI>(
Expand All @@ -191,7 +212,7 @@ pub trait SpiExt: Sized + Instance {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), true, Master>
) -> Spi<Self, (SCK, MISO, MOSI), true, u8, Master>
where
(SCK, MISO, MOSI): Pins<Self>;
fn spi_slave<SCK, MISO, MOSI>(
Expand All @@ -200,7 +221,7 @@ pub trait SpiExt: Sized + Instance {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), false, Slave>
) -> Spi<Self, (SCK, MISO, MOSI), false, u8, Slave>
where
(SCK, MISO, MOSI): Pins<Self>;
fn spi_bidi_slave<SCK, MISO, MOSI>(
Expand All @@ -209,7 +230,7 @@ pub trait SpiExt: Sized + Instance {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), true, Slave>
) -> Spi<Self, (SCK, MISO, MOSI), true, u8, Slave>
where
(SCK, MISO, MOSI): Pins<Self>;
}
Expand All @@ -221,7 +242,7 @@ impl<SPI: Instance> SpiExt for SPI {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), false, Master>
) -> Spi<Self, (SCK, MISO, MOSI), false, u8, Master>
where
(SCK, MISO, MOSI): Pins<Self>,
{
Expand All @@ -233,7 +254,7 @@ impl<SPI: Instance> SpiExt for SPI {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), true, Master>
) -> Spi<Self, (SCK, MISO, MOSI), true, u8, Master>
where
(SCK, MISO, MOSI): Pins<Self>,
{
Expand All @@ -245,7 +266,7 @@ impl<SPI: Instance> SpiExt for SPI {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), false, Slave>
) -> Spi<Self, (SCK, MISO, MOSI), false, u8, Slave>
where
(SCK, MISO, MOSI): Pins<Self>,
{
Expand All @@ -257,22 +278,26 @@ impl<SPI: Instance> SpiExt for SPI {
mode: impl Into<Mode>,
freq: Hertz,
clocks: &Clocks,
) -> Spi<Self, (SCK, MISO, MOSI), true, Slave>
) -> Spi<Self, (SCK, MISO, MOSI), true, u8, Slave>
where
(SCK, MISO, MOSI): Pins<Self>,
{
Spi::new_bidi_slave(self, pins, mode, freq, clocks)
}
}

impl<SPI: Instance, PINS, const BIDI: bool, OPERATION: Ms> Spi<SPI, PINS, BIDI, OPERATION> {
impl<SPI: Instance, PINS, const BIDI: bool, W: FrameSize, OPERATION: Ms>
Spi<SPI, PINS, BIDI, W, OPERATION>
{
pub fn init(self) -> Self {
self.spi.cr1.modify(|_, w| {
// bidimode: 2-line or 1-line unidirectional
w.bidimode().bit(BIDI);
w.bidioe().bit(BIDI);
// master/slave mode
w.mstr().bit(OPERATION::MSTR);
// data frame size
w.dff().bit(W::DFF);
// spe: enable the SPI bus
w.spe().set_bit()
});
Expand All @@ -281,31 +306,51 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION: Ms> Spi<SPI, PINS, BIDI,
}
}

impl<SPI: Instance, PINS, OPERATION: Ms> Spi<SPI, PINS, false, OPERATION> {
pub fn to_bidi_transfer_mode(self) -> Spi<SPI, PINS, true, OPERATION> {
impl<SPI: Instance, PINS, W: FrameSize, OPERATION: Ms> Spi<SPI, PINS, false, W, OPERATION> {
pub fn to_bidi_transfer_mode(self) -> Spi<SPI, PINS, true, W, OPERATION> {
self.into_mode()
}
}

impl<SPI: Instance, PINS, W: FrameSize, OPERATION: Ms> Spi<SPI, PINS, true, W, OPERATION> {
pub fn to_normal_transfer_mode(self) -> Spi<SPI, PINS, false, W, OPERATION> {
self.into_mode()
}
}

impl<SPI: Instance, PINS, const BIDI: bool, W: FrameSize> Spi<SPI, PINS, BIDI, W, Master> {
pub fn to_slave_operation(self) -> Spi<SPI, PINS, BIDI, W, Slave> {
self.into_mode()
}
}

impl<SPI: Instance, PINS, OPERATION: Ms> Spi<SPI, PINS, true, OPERATION> {
pub fn to_normal_transfer_mode(self) -> Spi<SPI, PINS, false, OPERATION> {
impl<SPI: Instance, PINS, const BIDI: bool, W: FrameSize> Spi<SPI, PINS, BIDI, W, Slave> {
pub fn to_master_operation(self) -> Spi<SPI, PINS, BIDI, W, Master> {
self.into_mode()
}
}

impl<SPI: Instance, PINS, const BIDI: bool> Spi<SPI, PINS, BIDI, Master> {
pub fn to_slave_operation(self) -> Spi<SPI, PINS, BIDI, Slave> {
impl<SPI, PINS, const BIDI: bool, OPERATION: Ms> Spi<SPI, PINS, BIDI, u8, OPERATION>
where
SPI: Instance,
{
/// Converts from 8bit dataframe to 16bit.
pub fn frame_size_16bit(self) -> Spi<SPI, PINS, BIDI, u16, OPERATION> {
self.into_mode()
}
}

impl<SPI: Instance, PINS, const BIDI: bool> Spi<SPI, PINS, BIDI, Slave> {
pub fn to_master_operation(self) -> Spi<SPI, PINS, BIDI, Master> {
impl<SPI, PINS, const BIDI: bool, OPERATION: Ms> Spi<SPI, PINS, BIDI, u16, OPERATION>
where
SPI: Instance,
{
/// Converts from 16bit dataframe to 8bit.
pub fn frame_size_8bit(self) -> Spi<SPI, PINS, BIDI, u8, OPERATION> {
self.into_mode()
}
}

impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, Master> {
impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, u8, Master> {
pub fn new(
spi: SPI,
mut pins: (SCK, MISO, MOSI),
Expand All @@ -331,7 +376,7 @@ impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, Master>
}
}

impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), true, Master> {
impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), true, u8, Master> {
pub fn new_bidi(
spi: SPI,
mut pins: (SCK, MISO, MOSI),
Expand All @@ -357,7 +402,7 @@ impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), true, Master> {
}
}

impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, Slave> {
impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, u8, Slave> {
pub fn new_slave(
spi: SPI,
mut pins: (SCK, MISO, MOSI),
Expand All @@ -383,7 +428,7 @@ impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), false, Slave> {
}
}

impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), true, Slave> {
impl<SPI: Instance, SCK, MISO, MOSI> Spi<SPI, (SCK, MISO, MOSI), true, u8, Slave> {
pub fn new_bidi_slave(
spi: SPI,
mut pins: (SCK, MISO, MOSI),
Expand Down Expand Up @@ -421,7 +466,7 @@ where
}
}

impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPERATION> {
impl<SPI: Instance, PINS, const BIDI: bool, W, OPERATION> Spi<SPI, PINS, BIDI, W, OPERATION> {
fn _new(spi: SPI, pins: PINS) -> Self {
Self {
spi,
Expand All @@ -431,7 +476,9 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPER
}

/// Convert the spi to another mode.
fn into_mode<const BIDI2: bool, OPERATION2: Ms>(self) -> Spi<SPI, PINS, BIDI2, OPERATION2> {
fn into_mode<const BIDI2: bool, W2: FrameSize, OPERATION2: Ms>(
self,
) -> Spi<SPI, PINS, BIDI2, W2, OPERATION2> {
let mut spi = Spi::_new(self.spi, self.pins);
spi.enable(false);
spi.init()
Expand Down Expand Up @@ -482,6 +529,14 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPER
self
}

/// Select which frame format is used for data transfers
pub fn bit_format(&mut self, format: BitFormat) {
match format {
BitFormat::LsbFirst => self.spi.cr1.modify(|_, w| w.lsbfirst().set_bit()),
BitFormat::MsbFirst => self.spi.cr1.modify(|_, w| w.lsbfirst().clear_bit()),
}
}

/// Enable interrupts for the given `event`:
/// - Received data ready to be read (RXNE)
/// - Transmit data register empty (TXE)
Expand Down Expand Up @@ -550,13 +605,36 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPER
pub fn is_overrun(&self) -> bool {
self.spi.sr.read().ovr().bit_is_set()
}
}

pub fn use_dma(self) -> DmaBuilder<SPI> {
DmaBuilder { spi: self.spi }
trait ReadWriteReg<W> {
fn read_data_reg(&mut self) -> W;
fn write_data_reg(&mut self, data: W);
}

impl<SPI, PINS, const BIDI: bool, W, OPERATION> ReadWriteReg<W>
for Spi<SPI, PINS, BIDI, W, OPERATION>
where
SPI: Instance,
W: FrameSize,
{
fn read_data_reg(&mut self) -> W {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
// reading a half-word)
unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const W) }
}

fn write_data_reg(&mut self, data: W) {
// NOTE(write_volatile) see note above
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut W, data) }
}
}

impl<SPI: Instance, PINS, const BIDI: bool, W: FrameSize, OPERATION>
Spi<SPI, PINS, BIDI, W, OPERATION>
{
#[inline(always)]
fn check_read(&mut self) -> nb::Result<u8, Error> {
fn check_read(&mut self) -> nb::Result<W, Error> {
let sr = self.spi.sr.read();

Err(if sr.ovr().bit_is_set() {
Expand All @@ -566,14 +644,14 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPER
} else if sr.crcerr().bit_is_set() {
Error::Crc.into()
} else if sr.rxne().bit_is_set() {
return Ok(self.read_u8());
return Ok(self.read_data_reg());
} else {
nb::Error::WouldBlock
})
}

#[inline(always)]
fn check_send(&mut self, byte: u8) -> nb::Result<(), Error> {
fn check_send(&mut self, byte: W) -> nb::Result<(), Error> {
let sr = self.spi.sr.read();

Err(if sr.ovr().bit_is_set() {
Expand All @@ -592,23 +670,19 @@ impl<SPI: Instance, PINS, const BIDI: bool, OPERATION> Spi<SPI, PINS, BIDI, OPER
});
Error::Crc.into()
} else if sr.txe().bit_is_set() {
self.send_u8(byte);
self.write_data_reg(byte);
return Ok(());
} else {
nb::Error::WouldBlock
})
}
}

#[inline(always)]
fn read_u8(&mut self) -> u8 {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows reading a half-word)
unsafe { ptr::read_volatile(&self.spi.dr as *const _ as *const u8) }
}
// Spi DMA

#[inline(always)]
fn send_u8(&mut self, byte: u8) {
// NOTE(write_volatile) see note above
unsafe { ptr::write_volatile(&self.spi.dr as *const _ as *mut u8, byte) }
impl<SPI: Instance, PINS, const BIDI: bool> Spi<SPI, PINS, BIDI, u8, Master> {
pub fn use_dma(self) -> DmaBuilder<SPI> {
DmaBuilder { spi: self.spi }
}
}

Expand Down
Loading