Skip to content

Commit e20baa4

Browse files
committed
spi: add Read and separate-buffers Transfer
1 parent a7c1233 commit e20baa4

File tree

2 files changed

+99
-10
lines changed

2 files changed

+99
-10
lines changed

src/blocking/spi.rs

Lines changed: 96 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
11
//! Blocking SPI API
22
3-
/// Blocking transfer
3+
/// Blocking transfer with separate buffers
44
pub trait Transfer<W> {
55
/// Error type
66
type Error;
77

8+
/// Writes and reads simultaneously. `write` is written to the slave on MOSI and
9+
/// words received on MISO are stored in `read`.
10+
///
11+
/// It is allowed for `read` and `write` to have different lengths, even zero length.
12+
/// The transfer runs for `max(read.len(), write.len())` words. If `read` is shorter,
13+
/// incoming words after `read` has been filled will be discarded. If `write` is shorter,
14+
/// the value of words sent in MOSI after all `write` has been sent is implementation defined,
15+
/// typically `0x00`, `0xFF`, or configurable.
16+
fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), Self::Error>;
17+
}
18+
19+
/// Blocking transfer with single buffer
20+
pub trait TransferInplace<W> {
21+
/// Error type
22+
type Error;
23+
824
/// Writes and reads simultaneously. The contents of `words` are
925
/// written to the slave, and the received words are stored into the same
1026
/// `words` buffer, overwriting it.
11-
fn transfer(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
27+
fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
1228
}
1329

1430
/// Blocking write
@@ -20,6 +36,16 @@ pub trait Write<W> {
2036
fn write(&mut self, words: &[W]) -> Result<(), Self::Error>;
2137
}
2238

39+
/// Blocking read
40+
pub trait Read<W> {
41+
/// Error type
42+
type Error;
43+
44+
/// Reads `words` to the slave. The word value sent on MOSI during
45+
/// reading is implementation defined, typically `0x00`, `0xFF`, or configurable.
46+
fn read(&mut self, words: &mut [W]) -> Result<(), Self::Error>;
47+
}
48+
2349
/// Blocking write (iterator version)
2450
pub trait WriteIter<W> {
2551
/// Error type
@@ -31,20 +57,56 @@ pub trait WriteIter<W> {
3157
WI: IntoIterator<Item = W>;
3258
}
3359

34-
/// Blocking transfer
60+
/// Blocking transfer with separate buffers
3561
pub mod transfer {
3662
/// Default implementation of `blocking::spi::Transfer<W>` for implementers of
3763
/// `nonblocking::spi::FullDuplex<W>`
64+
///
65+
/// If `read` is longer than `write`, `W::default()` (which is typically 0) is sent on MOSI
66+
/// to fill the remaining bytes.
3867
pub trait Default<W>: crate::nb::spi::FullDuplex<W> {}
3968

4069
impl<W, S> crate::blocking::spi::Transfer<W> for S
70+
where
71+
S: Default<W>,
72+
W: Clone + core::default::Default,
73+
{
74+
type Error = S::Error;
75+
76+
fn transfer(&mut self, read: &mut [W], write: &[W]) -> Result<(), S::Error> {
77+
for i in 0..core::cmp::max(read.len(), write.len()) {
78+
let word_out = if i < write.len() {
79+
write[i].clone()
80+
} else {
81+
W::default()
82+
};
83+
nb::block!(self.write(word_out.clone()))?;
84+
85+
let word_in = nb::block!(self.read())?;
86+
if i < read.len() {
87+
read[i] = word_in;
88+
}
89+
}
90+
91+
Ok(())
92+
}
93+
}
94+
}
95+
96+
/// Blocking simultaneous read+write with separate buffers
97+
pub mod transfer_inplace {
98+
/// Default implementation of `blocking::spi::Transfer<W>` for implementers of
99+
/// `nonblocking::spi::FullDuplex<W>`
100+
pub trait Default<W>: crate::nb::spi::FullDuplex<W> {}
101+
102+
impl<W, S> crate::blocking::spi::TransferInplace<W> for S
41103
where
42104
S: Default<W>,
43105
W: Clone,
44106
{
45107
type Error = S::Error;
46108

47-
fn transfer(&mut self, words: &mut [W]) -> Result<(), S::Error> {
109+
fn transfer_inplace(&mut self, words: &mut [W]) -> Result<(), S::Error> {
48110
for word in words.iter_mut() {
49111
nb::block!(self.write(word.clone()))?;
50112
*word = nb::block!(self.read())?;
@@ -79,6 +141,32 @@ pub mod write {
79141
}
80142
}
81143

144+
/// Blocking read
145+
pub mod read {
146+
/// Default implementation of `blocking::spi::Read<W>` for implementers
147+
/// of `nonblocking::spi::FullDuplex<W>`
148+
///
149+
/// During the read, `W::default()` (which is typically 0) is sent on MOSI.
150+
pub trait Default<W>: crate::nb::spi::FullDuplex<W> {}
151+
152+
impl<W, S> crate::blocking::spi::Read<W> for S
153+
where
154+
S: Default<W>,
155+
W: core::default::Default,
156+
{
157+
type Error = S::Error;
158+
159+
fn read(&mut self, words: &mut [W]) -> Result<(), S::Error> {
160+
for word in words.iter_mut() {
161+
nb::block!(self.write(W::default()))?;
162+
*word = nb::block!(self.read())?;
163+
}
164+
165+
Ok(())
166+
}
167+
}
168+
}
169+
82170
/// Blocking write (iterator version)
83171
pub mod write_iter {
84172
/// Default implementation of `blocking::spi::WriteIter<W>` for implementers of
@@ -129,15 +217,15 @@ pub trait Transactional<W: 'static> {
129217

130218
/// Blocking transactional impl over spi::Write and spi::Transfer
131219
pub mod transactional {
132-
use super::{Operation, Transfer, Write};
220+
use super::{Operation, TransferInplace, Write};
133221

134222
/// Default implementation of `blocking::spi::Transactional<W>` for implementers of
135223
/// `spi::Write<W>` and `spi::Transfer<W>`
136-
pub trait Default<W>: Write<W> + Transfer<W> {}
224+
pub trait Default<W>: Write<W> + TransferInplace<W> {}
137225

138226
impl<W: 'static, E, S> super::Transactional<W> for S
139227
where
140-
S: self::Default<W> + Write<W, Error = E> + Transfer<W, Error = E>,
228+
S: self::Default<W> + Write<W, Error = E> + TransferInplace<W, Error = E>,
141229
W: Copy + Clone,
142230
{
143231
type Error = E;
@@ -146,7 +234,7 @@ pub mod transactional {
146234
for op in operations {
147235
match op {
148236
Operation::Write(w) => self.write(w)?,
149-
Operation::Transfer(t) => self.transfer(t).map(|_| ())?,
237+
Operation::Transfer(t) => self.transfer_inplace(t).map(|_| ())?,
150238
}
151239
}
152240

src/prelude.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,9 @@ pub use crate::blocking::qei::Qei as _embedded_hal_blocking_Qei;
2222
pub use crate::blocking::rng::Read as _embedded_hal_blocking_rng_Read;
2323
pub use crate::blocking::serial::Write as _embedded_hal_blocking_serial_Write;
2424
pub use crate::blocking::spi::{
25-
Transfer as _embedded_hal_blocking_spi_Transfer, Write as _embedded_hal_blocking_spi_Write,
26-
WriteIter as _embedded_hal_blocking_spi_WriteIter,
25+
Read as _embedded_hal_blocking_spi_Read, Transfer as _embedded_hal_blocking_spi_Transfer,
26+
TransferInplace as _embedded_hal_blocking_spi_TransferInplace,
27+
Write as _embedded_hal_blocking_spi_Write, WriteIter as _embedded_hal_blocking_spi_WriteIter,
2728
};
2829
pub use crate::blocking::watchdog::Disable as _embedded_hal_blocking_watchdog_Disable;
2930
pub use crate::blocking::watchdog::Enable as _embedded_hal_blocking_watchdog_Enable;

0 commit comments

Comments
 (0)