Skip to content

Commit 2d179f4

Browse files
committed
Implement SpiBus from embedded-hal 1
1 parent f52c59d commit 2d179f4

File tree

2 files changed

+148
-21
lines changed

2 files changed

+148
-21
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ version = "0.2.5"
4040
features = ["unproven"]
4141
version = "0.2.4"
4242

43+
[dependencies.embedded-hal-one]
44+
version = "1.0.0-rc.3"
45+
package = "embedded-hal"
46+
4347
[dependencies.embedded-dma]
4448
version = "0.1.2"
4549

src/spi.rs

Lines changed: 144 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ pub enum Error {
3737
Crc,
3838
}
3939

40+
impl embedded_hal_one::spi::Error for Error {
41+
fn kind(&self) -> embedded_hal_one::spi::ErrorKind {
42+
match self {
43+
Self::Overrun => embedded_hal_one::spi::ErrorKind::Overrun,
44+
Self::ModeFault => embedded_hal_one::spi::ErrorKind::ModeFault,
45+
Self::Crc => embedded_hal_one::spi::ErrorKind::Other,
46+
}
47+
}
48+
}
49+
4050
/// A filler type for when the SCK pin is unnecessary
4151
pub struct NoSck;
4252
/// A filler type for when the Miso pin is unnecessary
@@ -73,6 +83,17 @@ pub trait SpiExt<SPI>: Sized {
7383
T: Into<Hertz>;
7484
}
7585

86+
pub trait FrameSize: Copy + Default {
87+
const DFF: bool;
88+
}
89+
90+
impl FrameSize for u8 {
91+
const DFF: bool = false;
92+
}
93+
impl FrameSize for u16 {
94+
const DFF: bool = true;
95+
}
96+
7697
macro_rules! spi {
7798
($SPIX:ident, $spiX:ident,
7899
sck: [ $($( #[ $pmetasck:meta ] )* $SCK:ty,)+ ],
@@ -181,22 +202,9 @@ macro_rules! spi {
181202
}
182203
}
183204

184-
impl SpiExt<$SPIX> for $SPIX {
185-
fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<$SPIX, PINS>
186-
where
187-
PINS: Pins<$SPIX>,
188-
T: Into<Hertz>
189-
{
190-
Spi::$spiX(self, pins, mode, freq, rcc)
191-
}
192-
}
193-
194-
impl<PINS> hal::spi::FullDuplex<u8> for Spi<$SPIX, PINS> {
195-
type Error = Error;
196-
197-
fn read(&mut self) -> nb::Result<u8, Error> {
205+
impl<PINS> Spi<$SPIX, PINS> {
206+
fn nb_read<W: FrameSize>(&mut self) -> nb::Result<W, Error> {
198207
let sr = self.spi.sr.read();
199-
200208
Err(if sr.ovr().bit_is_set() {
201209
nb::Error::Other(Error::Overrun)
202210
} else if sr.modf().bit_is_set() {
@@ -207,31 +215,146 @@ macro_rules! spi {
207215
// NOTE(read_volatile) read only 1 byte (the svd2rust API only allows
208216
// reading a half-word)
209217
return Ok(unsafe {
210-
ptr::read_volatile(&self.spi.dr as *const _ as *const u8)
218+
ptr::read_volatile(&self.spi.dr as *const _ as *const W)
211219
});
212220
} else {
213221
nb::Error::WouldBlock
214222
})
215223
}
216-
217-
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
224+
fn nb_write<W: FrameSize>(&mut self, word: W) -> nb::Result<(), Error> {
218225
let sr = self.spi.sr.read();
219-
220226
Err(if sr.ovr().bit_is_set() {
221227
nb::Error::Other(Error::Overrun)
222228
} else if sr.modf().bit_is_set() {
223229
nb::Error::Other(Error::ModeFault)
224230
} else if sr.crcerr().bit_is_set() {
225231
nb::Error::Other(Error::Crc)
226232
} else if sr.txe().bit_is_set() {
227-
let dr = &self.spi.dr as *const _ as *const UnsafeCell<u8>;
233+
let dr = &self.spi.dr as *const _ as *const UnsafeCell<W>;
228234
// NOTE(write_volatile) see note above
229-
unsafe { ptr::write_volatile(UnsafeCell::raw_get(dr), byte) };
235+
unsafe { ptr::write_volatile(UnsafeCell::raw_get(dr), word) };
230236
return Ok(());
231237
} else {
232238
nb::Error::WouldBlock
233239
})
234240
}
241+
fn set_tx_only(&mut self) {
242+
self.spi
243+
.cr1
244+
.modify(|_, w| w.bidimode().set_bit().bidioe().set_bit());
245+
}
246+
fn set_bidi(&mut self) {
247+
self.spi
248+
.cr1
249+
.modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit());
250+
}
251+
}
252+
253+
impl SpiExt<$SPIX> for $SPIX {
254+
fn spi<PINS, T>(self, pins: PINS, mode: Mode, freq: T, rcc: &mut Rcc) -> Spi<$SPIX, PINS>
255+
where
256+
PINS: Pins<$SPIX>,
257+
T: Into<Hertz>
258+
{
259+
Spi::$spiX(self, pins, mode, freq, rcc)
260+
}
261+
}
262+
263+
impl<PINS> embedded_hal_one::spi::ErrorType for Spi<$SPIX, PINS> {
264+
type Error = Error;
265+
}
266+
267+
impl<PINS> embedded_hal_one::spi::SpiBus for Spi<$SPIX, PINS> {
268+
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
269+
if words.len() == 0 { return Ok(()) }
270+
// clear tx-only status in the case the previous operation was a write
271+
self.set_bidi();
272+
// prefill write fifo so that the clock doen't stop while fetch the read byte
273+
// one frame should be enough?
274+
nb::block!(self.nb_write(0u8))?;
275+
let len = words.len();
276+
for w in words[..len-1].iter_mut() {
277+
// TODO: 16 bit frames, bidirectional pins
278+
nb::block!(self.nb_write(0u8))?;
279+
*w = nb::block!(self.nb_read())?;
280+
}
281+
// safety: length > 0 checked at start of function
282+
*words.last_mut().unwrap() = nb::block!(self.nb_read())?;
283+
Ok(())
284+
}
285+
286+
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
287+
self.set_tx_only();
288+
Ok(for w in words {
289+
nb::block!(self.nb_write(*w))?
290+
})
291+
}
292+
293+
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
294+
if read.len() == 0 {
295+
return self.write(write)
296+
} else if write.len() == 0 {
297+
return self.read(read)
298+
}
299+
300+
self.set_bidi();
301+
// same prefill as in read, this time with actual data
302+
nb::block!(self.nb_write(write[0]))?;
303+
let common_len = core::cmp::min(read.len(), write.len());
304+
// take 1 less because write skips the first element
305+
let zipped = read.iter_mut().zip(write.into_iter().skip(1)).take(common_len - 1);
306+
for (r, w) in zipped {
307+
nb::block!(self.nb_write(*w))?;
308+
*r = nb::block!(self.nb_read())?;
309+
}
310+
read[common_len-1] = nb::block!(self.nb_read())?;
311+
312+
if read.len() > common_len {
313+
self.read(&mut read[common_len..])
314+
} else {
315+
self.write(&write[common_len..])
316+
}
317+
}
318+
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
319+
if words.len() == 0 { return Ok(()) }
320+
self.set_bidi();
321+
nb::block!(self.nb_write(words[0]))?;
322+
let cells = core::cell::Cell::from_mut(words).as_slice_of_cells();
323+
324+
for rw in cells.windows(2) {
325+
let r = &rw[0];
326+
let w = &rw[1];
327+
328+
nb::block!(self.nb_write(w.get()))?;
329+
r.set(nb::block!(self.nb_read())?);
330+
}
331+
*words.last_mut().unwrap() = nb::block!(self.nb_read())?;
332+
Ok(())
333+
}
334+
fn flush(&mut self) -> Result<(), Self::Error> {
335+
// stop receiving data
336+
self.set_tx_only();
337+
// wait for tx fifo to be drained by the peripheral
338+
while self.spi.sr.read().ftlvl() != 0 { core::hint::spin_loop() };
339+
// drain rx fifo
340+
Ok(while match self.nb_read::<u8>() {
341+
Ok(_) => true,
342+
Err(nb::Error::WouldBlock) => false,
343+
Err(nb::Error::Other(e)) => return Err(e)
344+
} { core::hint::spin_loop() })
345+
}
346+
}
347+
348+
impl<PINS> hal::spi::FullDuplex<u8> for Spi<$SPIX, PINS> {
349+
type Error = Error;
350+
351+
fn read(&mut self) -> nb::Result<u8, Error> {
352+
self.nb_read()
353+
}
354+
355+
fn send(&mut self, byte: u8) -> nb::Result<(), Error> {
356+
self.nb_write(byte)
357+
}
235358
}
236359
unsafe impl<Pin> TargetAddress<MemoryToPeripheral> for Spi<$SPIX, Pin> {
237360
#[inline(always)]

0 commit comments

Comments
 (0)