Skip to content
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 @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Update to `stm32f1` v0.16.0 [#503] [#534]
- `Spi` now takes `Option<PIN>` for `SCK`, `MISO`, `MOSI` [#514],
add `SPIx::NoSck`, etc. [#537]
- `spi::FrameSize` and `embedded-hal` 1.0 implementations
- move `Qei` mod inside `pwm_input` mod [#516]

### Changed
Expand Down
135 changes: 108 additions & 27 deletions src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ mod hal_02;
mod hal_1;

use core::ops::{Deref, DerefMut};
use core::ptr;

use crate::pac::{self, RCC};

Expand Down Expand Up @@ -109,6 +108,36 @@ pub struct Mode {
pub phase: Phase,
}

type SpiRB = pac::spi1::RegisterBlock;

pub trait FrameSize: Copy + Default {
const DFF: bool;
#[doc(hidden)]
fn read_data(spi: &SpiRB) -> Self;
#[doc(hidden)]
fn write_data(self, spi: &SpiRB);
}

impl FrameSize for u8 {
const DFF: bool = false;
fn read_data(spi: &SpiRB) -> Self {
spi.dr8().read().dr().bits()
}
fn write_data(self, spi: &SpiRB) {
spi.dr8().write(|w| w.dr().set(self));
}
}

impl FrameSize for u16 {
const DFF: bool = true;
fn read_data(spi: &SpiRB) -> Self {
spi.dr().read().dr().bits()
}
fn write_data(self, spi: &SpiRB) {
spi.dr().write(|w| w.dr().set(self));
}
}

/// Interrupt event
pub enum Event {
/// New data has been received
Expand Down Expand Up @@ -519,24 +548,7 @@ impl<SPI: Instance, Otype, PULL> SpiSlave<SPI, u8, Otype, PULL> {
}
}

pub trait SpiReadWrite<T> {
fn read_data_reg(&mut self) -> T;
fn write_data_reg(&mut self, data: T);
fn spi_write(&mut self, words: &[T]) -> Result<(), Error>;
}

impl<SPI: Instance, W: Copy> SpiReadWrite<W> for SpiInner<SPI, W> {
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_ptr() 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_ptr() as *mut W, data) }
}

impl<SPI: Instance, W: FrameSize> SpiInner<SPI, W> {
// Implement write as per the "Transmit only procedure" page 712
// of RM0008 Rev 20. This is more than twice as fast as the
// default Write<> implementation (which reads and drops each
Expand All @@ -547,7 +559,7 @@ impl<SPI: Instance, W: Copy> SpiReadWrite<W> for SpiInner<SPI, W> {
loop {
let sr = self.spi.sr().read();
if sr.txe().bit_is_set() {
self.write_data_reg(*word);
(*word).write_data(&self.spi);
if sr.modf().bit_is_set() {
return Err(Error::ModeFault);
}
Expand All @@ -560,13 +572,13 @@ impl<SPI: Instance, W: Copy> SpiReadWrite<W> for SpiInner<SPI, W> {
// Wait for final !BSY
while self.is_busy() {}
// Clear OVR set due to dropped received values
let _ = self.read_data_reg();
let _ = W::read_data(&self.spi);
let _ = self.spi.sr().read();
Ok(())
}
}

impl<SPI: Instance, W: Copy> SpiInner<SPI, W> {
impl<SPI: Instance, W> SpiInner<SPI, W> {
/// Select which frame format is used for data transfers
pub fn bit_format(&mut self, format: SpiBitFormat) {
self.spi
Expand Down Expand Up @@ -676,9 +688,9 @@ impl<SPI: Instance, Otype, PULL> SpiSlave<SPI, u16, Otype, PULL> {
impl<SPI, W> SpiInner<SPI, W>
where
SPI: Instance,
W: Copy,
W: FrameSize,
{
pub fn read_nonblocking(&mut self) -> nb::Result<W, Error> {
pub(crate) fn check_read(&mut self) -> nb::Result<W, Error> {
let sr = self.spi.sr().read();

Err(if sr.ovr().bit_is_set() {
Expand All @@ -690,12 +702,13 @@ where
} else if sr.rxne().bit_is_set() {
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
// reading a half-word)
return Ok(self.read_data_reg());
return Ok(W::read_data(&self.spi));
} else {
nb::Error::WouldBlock
})
}
pub fn write_nonblocking(&mut self, data: W) -> nb::Result<(), Error> {

pub(crate) fn check_send(&mut self, data: W) -> nb::Result<(), Error> {
let sr = self.spi.sr().read();

// NOTE: Error::Overrun was deleted in #408. Need check
Expand All @@ -705,15 +718,83 @@ where
Error::Crc.into()
} else if sr.txe().bit_is_set() {
// NOTE(write_volatile) see note above
self.write_data_reg(data);
data.write_data(&self.spi);
return Ok(());
} else {
nb::Error::WouldBlock
})
}

#[inline(always)]
pub fn read_nonblocking(&mut self) -> nb::Result<W, Error> {
// TODO: bidimode
self.check_read()
}

#[inline(always)]
pub fn write_nonblocking(&mut self, data: W) -> nb::Result<(), Error> {
// TODO: bidimode
self.check_send(data)
}

#[inline(always)]
pub fn write(&mut self, words: &[W]) -> Result<(), Error> {
self.spi_write(words)
}

pub fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Error> {
for word in words {
nb::block!(self.write_nonblocking(*word))?;
*word = nb::block!(self.read_nonblocking())?;
}

Ok(())
}

pub fn transfer(&mut self, buff: &mut [W], data: &[W]) -> Result<(), Error> {
if data.len() == buff.len() {
for (d, b) in data.iter().cloned().zip(buff.iter_mut()) {
nb::block!(self.write_nonblocking(d))?;
*b = nb::block!(self.read_nonblocking())?;
}
} else {
let mut iter_r = buff.iter_mut();
let mut iter_w = data.iter().cloned();
loop {
match (iter_r.next(), iter_w.next()) {
(Some(r), Some(w)) => {
nb::block!(self.write_nonblocking(w))?;
*r = nb::block!(self.read_nonblocking())?;
}
(Some(r), None) => {
nb::block!(self.write_nonblocking(W::default()))?;
*r = nb::block!(self.read_nonblocking())?;
}
(None, Some(w)) => {
nb::block!(self.write_nonblocking(w))?;
let _ = nb::block!(self.read_nonblocking())?;
}
(None, None) => break,
}
}
}

Ok(())
}

pub fn flush(&mut self) -> Result<(), Error> {
Ok(())
}

pub fn read(&mut self, words: &mut [W]) -> Result<(), Error> {
// TODO: bidimode
for word in words {
nb::block!(self.check_send(W::default()))?;
*word = nb::block!(self.check_read())?;
}

Ok(())
}
}

// DMA
Expand Down
4 changes: 2 additions & 2 deletions src/spi/hal_02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl From<Mode> for super::Mode {
impl<SPI, W, PULL> spi::FullDuplex<W> for Spi<SPI, W, PULL>
where
SPI: Instance,
W: Copy,
W: FrameSize,
{
type Error = Error;

Expand All @@ -49,7 +49,7 @@ where
impl<SPI, W, PULL> blocking::transfer::Default<W> for Spi<SPI, W, PULL>
where
SPI: Instance,
W: Copy,
W: FrameSize,
{
}

Expand Down
20 changes: 10 additions & 10 deletions src/spi/hal_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,13 @@ impl<SPI: Instance, W, PULL> ErrorType for Spi<SPI, W, PULL> {
}

mod nb {
use super::{Error, Instance, Spi};
use super::{Error, FrameSize, Instance, Spi};
use embedded_hal_nb::spi::FullDuplex;

impl<SPI, W, PULL> FullDuplex<W> for Spi<SPI, W, PULL>
where
SPI: Instance,
W: Copy,
W: FrameSize,
{
fn read(&mut self) -> nb::Result<W, Error> {
self.read_nonblocking()
Expand All @@ -62,25 +62,25 @@ mod nb {
}

mod blocking {
use super::super::{Instance, Spi};
use super::super::{FrameSize, Instance, Spi};
use core::ops::DerefMut;
use embedded_hal::spi::SpiBus;

impl<SPI: Instance, W, PULL> SpiBus<W> for Spi<SPI, W, PULL>
where
SPI: Instance,
W: Copy + 'static,
W: FrameSize + 'static,
{
fn transfer_in_place(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
todo!()
fn transfer_in_place(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.deref_mut().transfer_in_place(words)
}

fn transfer(&mut self, _buff: &mut [W], _data: &[W]) -> Result<(), Self::Error> {
todo!()
fn transfer(&mut self, buff: &mut [W], data: &[W]) -> Result<(), Self::Error> {
self.deref_mut().transfer(buff, data)
}

fn read(&mut self, _words: &mut [W]) -> Result<(), Self::Error> {
todo!()
fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error> {
self.deref_mut().read(words)
}

fn write(&mut self, words: &[W]) -> Result<(), Self::Error> {
Expand Down
Loading