Skip to content

Commit 92d7d3f

Browse files
committed
spi: 16 bit frame support
1 parent de35cce commit 92d7d3f

File tree

2 files changed

+131
-21
lines changed

2 files changed

+131
-21
lines changed

examples/spi-hal-one.rs

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,23 +59,39 @@ fn main() -> ! {
5959

6060
cs.set_low().unwrap();
6161
SpiBus::transfer(&mut spi, received, MESSAGE).unwrap();
62-
spi.flush().unwrap();
62+
// downside of having 8 and 16 bit impls on the same struct is you have to specify which flush
63+
// impl to call, although internally they call the same function
64+
SpiBus::<u8>::flush(&mut spi).unwrap();
6365
cs.set_high().unwrap();
6466

6567
info!("Received {:?}", core::str::from_utf8(received).ok());
6668
assert_eq!(MESSAGE, received);
6769

6870
cs.set_low().unwrap();
6971
spi.transfer_in_place(received).unwrap();
70-
spi.flush().unwrap();
72+
SpiBus::<u8>::flush(&mut spi).unwrap();
7173
cs.set_high().unwrap();
7274

7375
info!("Received {:?}", core::str::from_utf8(received).ok());
7476
assert_eq!(MESSAGE, received);
7577

78+
// Switch between 8 and 16 bit frames on the fly
79+
const TX_16B: &[u16] = &[0xf00f, 0xfeef, 0xfaaf];
80+
let rx_16b = &mut [0u16; TX_16B.len()];
81+
82+
cs.set_low().unwrap();
83+
SpiBus::transfer(&mut spi, rx_16b, TX_16B).unwrap();
84+
SpiBus::<u16>::flush(&mut spi).unwrap();
85+
cs.set_high().unwrap();
86+
info!("Received {:?}", rx_16b);
87+
assert_eq!(TX_16B, rx_16b);
88+
7689
cs.set_low().unwrap();
77-
embedded_hal::blocking::spi::Write::write(&mut spi, MESSAGE).unwrap();
90+
SpiBus::transfer_in_place(&mut spi, rx_16b).unwrap();
91+
SpiBus::<u16>::flush(&mut spi).unwrap();
7892
cs.set_high().unwrap();
93+
info!("Received {:?}", rx_16b);
94+
assert_eq!(TX_16B, rx_16b);
7995

8096
loop {
8197
cortex_m::asm::nop();

src/spi.rs

Lines changed: 112 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,19 @@ macro_rules! spi {
275275
_ => 0,
276276
}
277277
}
278+
fn flush_inner(&mut self) -> Result<(), Error> {
279+
// stop receiving data
280+
self.set_tx_only();
281+
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
282+
// drain rx fifo
283+
while match self.nb_read::<u8>() {
284+
Ok(_) => true,
285+
Err(nb::Error::WouldBlock) => false,
286+
Err(nb::Error::Other(e)) => { return Err(e) }
287+
} { core::hint::spin_loop() };
288+
// wait for idle
289+
Ok(while self.spi.sr.read().bsy().bit() { core::hint::spin_loop() })
290+
}
278291
}
279292

280293
impl SpiExt<$SPIX> for $SPIX {
@@ -291,13 +304,13 @@ macro_rules! spi {
291304
type Error = Error;
292305
}
293306

294-
impl<PINS> embedded_hal_one::spi::SpiBus for Spi<$SPIX, PINS> {
307+
impl<PINS> embedded_hal_one::spi::SpiBus<u8> for Spi<$SPIX, PINS> {
295308
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
296309
let len = words.len();
297310
if len == 0 { return Ok(()) }
298311

299312
// flush data from previous operations, otherwise we'd get unwanted data
300-
self.flush()?;
313+
self.flush_inner()?;
301314
// FIFO threshold to 16 bits
302315
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
303316
self.set_bidi();
@@ -312,9 +325,7 @@ macro_rules! spi {
312325
}
313326

314327
for r in words.chunks_exact_mut(2).take(half_len - prefill) {
315-
let r_two: u16 = unsafe {
316-
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
317-
};
328+
let r_two: u16 = nb::block!(self.nb_read_no_err()).unwrap();
318329
nb::block!(self.nb_write(0u16))?;
319330
// safety: chunks have exact length of 2
320331
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
@@ -347,6 +358,7 @@ macro_rules! spi {
347358
return self.read(read)
348359
}
349360

361+
self.flush_inner()?;
350362
self.set_bidi();
351363
let common_len = core::cmp::min(read.len(), write.len());
352364
let half_len = common_len / 2;
@@ -372,9 +384,7 @@ macro_rules! spi {
372384
// write ahead of reading
373385
let zipped = read.chunks_exact_mut(2).zip(write_iter).take(half_len - prefill);
374386
for (r, w) in zipped {
375-
let r_two: u16 = unsafe {
376-
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
377-
};
387+
let r_two: u16 = nb::block!(self.nb_read_no_err()).unwrap();
378388
nb::block!(self.nb_write(w))?;
379389
// same as above, length is checked by chunks_exact
380390
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
@@ -409,6 +419,7 @@ macro_rules! spi {
409419
let len = words.len();
410420
if len == 0 { return Ok(()) }
411421

422+
self.flush_inner()?;
412423
self.set_bidi();
413424
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
414425
let half_len = len / 2;
@@ -426,7 +437,7 @@ macro_rules! spi {
426437

427438
// data is in fifo isn't zero as long as words.len() > 1 so read-then-write is fine
428439
for i in 0..words_alias.len() - prefill {
429-
let read: u16 = unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() };
440+
let read: u16 = nb::block!(self.nb_read_no_err()).unwrap();
430441
words_alias[i] = read.to_le_bytes();
431442
let write = u16::from_le_bytes(words_alias[i + prefill]);
432443
nb::block!(self.nb_write(write))?;
@@ -450,16 +461,99 @@ macro_rules! spi {
450461
})
451462
}
452463
fn flush(&mut self) -> Result<(), Self::Error> {
453-
// stop receiving data
464+
self.flush_inner()
465+
}
466+
}
467+
impl<PINS> embedded_hal_one::spi::SpiBus<u16> for Spi<$SPIX, PINS> {
468+
fn read(&mut self, words: &mut [u16]) -> Result<(), Self::Error> {
469+
let len = words.len();
470+
if len == 0 { return Ok(()) }
471+
// flush data from previous operations, otherwise we'd get unwanted data
472+
self.flush_inner()?;
473+
// FIFO threshold to 16 bits
474+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
475+
self.set_bidi();
476+
// prefill write fifo so that the clock doen't stop while fetch the read byte
477+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, len);
478+
for _ in 0..prefill {
479+
nb::block!(self.nb_write(0u16))?;
480+
}
481+
482+
for w in &mut words[..len-prefill] {
483+
*w = nb::block!(self.nb_read_no_err()).unwrap();
484+
nb::block!(self.nb_write(0u16))?;
485+
}
486+
Ok(for w in &mut words[len-prefill..] {
487+
*w = nb::block!(self.nb_read())?;
488+
})
489+
}
490+
fn write(&mut self, words: &[u16]) -> Result<(), Self::Error> {
454491
self.set_tx_only();
455-
// drain rx fifo
456-
while match self.nb_read::<u8>() {
457-
Ok(_) => true,
458-
Err(nb::Error::WouldBlock) => false,
459-
Err(nb::Error::Other(e)) => { return Err(e) }
460-
} { core::hint::spin_loop() };
461-
// wait for idle
462-
Ok(while self.spi.sr.read().bsy().bit() { core::hint::spin_loop() })
492+
Ok(for w in words {
493+
nb::block!(self.nb_write(*w))?
494+
})
495+
}
496+
fn transfer(&mut self, read: &mut [u16], write: &[u16]) -> Result<(), Self::Error> {
497+
if read.len() == 0 {
498+
return self.write(write)
499+
} else if write.len() == 0 {
500+
return self.read(read)
501+
}
502+
503+
self.flush_inner()?;
504+
// FIFO threshold to 16 bits
505+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
506+
self.set_bidi();
507+
let common_len = core::cmp::min(read.len(), write.len());
508+
// same prefill as in read, this time with actual data
509+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, common_len);
510+
511+
let mut write_iter = write.into_iter();
512+
for w in write_iter.by_ref().take(prefill) {
513+
nb::block!(self.nb_write(*w))?;
514+
}
515+
516+
let zipped = read.into_iter().zip(write_iter).take(common_len - prefill);
517+
for (r, w) in zipped {
518+
*r = nb::block!(self.nb_read_no_err()).unwrap();
519+
nb::block!(self.nb_write(*w))?;
520+
}
521+
522+
for r in &mut read[common_len - prefill..common_len] {
523+
*r = nb::block!(self.nb_read())?
524+
}
525+
526+
if read.len() > common_len {
527+
self.read(&mut read[common_len..])
528+
} else {
529+
self.write(&write[common_len..])
530+
}
531+
}
532+
fn transfer_in_place(&mut self, words: &mut [u16]) -> Result<(), Self::Error> {
533+
let len = words.len();
534+
if len == 0 { return Ok(()) }
535+
536+
self.flush_inner()?;
537+
self.set_bidi();
538+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
539+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, len);
540+
541+
for w in &words[..prefill] {
542+
nb::block!(self.nb_write(*w))?;
543+
}
544+
545+
for read_idx in 0..len - prefill {
546+
let write_idx = read_idx + prefill;
547+
words[read_idx] = nb::block!(self.nb_read_no_err()).unwrap();
548+
nb::block!(self.nb_write(words[write_idx]))?;
549+
}
550+
551+
Ok(for r in &mut words[len - prefill..] {
552+
*r = nb::block!(self.nb_read())?;
553+
})
554+
}
555+
fn flush(&mut self) -> Result<(), Self::Error> {
556+
self.flush_inner()
463557
}
464558
}
465559

0 commit comments

Comments
 (0)