Skip to content

Commit b50f7d2

Browse files
committed
spi: use packed frames in transfer in place
1 parent 8ce257a commit b50f7d2

File tree

2 files changed

+32
-17
lines changed

2 files changed

+32
-17
lines changed

examples/spi-hal-one.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,11 @@ fn main() -> ! {
4545

4646
// 1/8 SPI/SysClk ratio seems to be the upper limit for continuous transmission
4747
// one byte at a time
48-
// 1/4 works for the first ~5 bytes (+4 prefilled), then we hit cpu limits
48+
// 1/4 works well when writing two packed bytes at once
49+
// At 1/2 the clock stays on for ~80% of the time
4950
let mut spi = dp
5051
.SPI1
51-
.spi((sclk, miso, mosi), spi::MODE_0, 4.MHz(), &mut rcc);
52+
.spi((sclk, miso, mosi), spi::MODE_0, 8.MHz(), &mut rcc);
5253
let mut cs = gpioa.pa8.into_push_pull_output();
5354
cs.set_high().unwrap();
5455

src/spi.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -400,29 +400,43 @@ macro_rules! spi {
400400
}
401401
}
402402
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
403-
if words.len() == 0 { return Ok(()) }
403+
let len = words.len();
404+
if len == 0 { return Ok(()) }
404405

405-
let cells = core::cell::Cell::from_mut(words).as_slice_of_cells();
406-
let mut write_iter = cells.into_iter();
407-
let mut read_iter = cells.into_iter();
406+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
407+
let half_len = len / 2;
408+
let pair_left = len % 2;
408409

409-
let prefill = self.fifo_cap();
410+
let prefill = self.fifo_cap() / 2;
411+
let words_alias: &mut [[u8; 2]] = unsafe {
412+
let ptr = words.as_mut_ptr();
413+
core::slice::from_raw_parts_mut(ptr as *mut [u8; 2], half_len)
414+
};
410415

411-
for w in write_iter.by_ref().take(prefill as usize) {
412-
nb::block!(self.nb_write(w.get()))?;
416+
let mut prefilled = 0;
417+
for b in words_alias.into_iter().take(prefill as usize) {
418+
nb::block!(self.nb_write(u16::from_le_bytes(*b)))?;
419+
prefilled += 2
413420
}
414421

415-
// write iter always finishes first
416-
// we don't want to consume an element from read_iter for nothing
417-
for (w, r) in write_iter.zip(read_iter.by_ref()) {
418-
nb::block!(self.nb_write(w.get()))?;
419-
r.set(unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() });
422+
for i in 0..words_alias.len() - prefilled/2 {
423+
let read: u16 = unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() };
424+
words_alias[i] = read.to_le_bytes();
425+
let write = u16::from_le_bytes(words_alias[i + prefilled/2]);
426+
nb::block!(self.nb_write(write))?;
420427
}
428+
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
421429

430+
if pair_left == 1 {
431+
nb::block!(self.nb_write(*words.last().unwrap()))?;
432+
// reading in the last loop lets the rx buffer overrun for some reason i
433+
// haven't figured out, so we read here
434+
words[len-prefilled-1] = nb::block!(self.nb_read_no_err()).unwrap();
435+
}
422436

423-
Ok(for r in read_iter {
424-
let read = nb::block!(self.nb_read())?;
425-
r.set(read);
437+
// read words left in the fifo
438+
Ok(for r in words.iter_mut().skip(len-prefilled) {
439+
*r = nb::block!(self.nb_read())?;
426440
})
427441
}
428442
fn flush(&mut self) -> Result<(), Self::Error> {

0 commit comments

Comments
 (0)