Skip to content

Commit 8ce257a

Browse files
committed
spi: more optimizations, fix transfer in place
1 parent d04eec8 commit 8ce257a

File tree

2 files changed

+75
-23
lines changed

2 files changed

+75
-23
lines changed

examples/spi-hal-one.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,25 +48,34 @@ fn main() -> ! {
4848
// 1/4 works for the first ~5 bytes (+4 prefilled), then we hit cpu limits
4949
let mut spi = dp
5050
.SPI1
51-
.spi((sclk, miso, mosi), spi::MODE_0, 2.MHz(), &mut rcc);
51+
.spi((sclk, miso, mosi), spi::MODE_0, 4.MHz(), &mut rcc);
5252
let mut cs = gpioa.pa8.into_push_pull_output();
5353
cs.set_high().unwrap();
5454

55-
// "Hello world!"
56-
const MESSAGE: &[u8] = "Hello world, but longer!".as_bytes();
55+
// Odd number of bits to test packing edge case
56+
const MESSAGE: &[u8] = "Hello world, but longer".as_bytes();
5757
let received = &mut [0u8; MESSAGE.len()];
5858

5959
cs.set_low().unwrap();
6060
SpiBus::transfer(&mut spi, received, MESSAGE).unwrap();
6161
spi.flush().unwrap();
6262
cs.set_high().unwrap();
63+
64+
info!("Received {:?}", core::str::from_utf8(received).ok());
65+
assert_eq!(MESSAGE, received);
6366

6467
cs.set_low().unwrap();
65-
embedded_hal::blocking::spi::Write::write(&mut spi, MESSAGE).unwrap();
68+
spi.transfer_in_place(received).unwrap();
69+
spi.flush().unwrap();
6670
cs.set_high().unwrap();
71+
6772
info!("Received {:?}", core::str::from_utf8(received).ok());
6873
assert_eq!(MESSAGE, received);
6974

75+
cs.set_low().unwrap();
76+
embedded_hal::blocking::spi::Write::write(&mut spi, MESSAGE).unwrap();
77+
cs.set_high().unwrap();
78+
7079
loop {
7180
cortex_m::asm::nop();
7281
}

src/spi.rs

Lines changed: 62 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -236,7 +236,7 @@ macro_rules! spi {
236236
})
237237
}
238238
#[inline]
239-
fn nb_read_no_err(&mut self) -> nb::Result<u8, ()> {
239+
fn nb_read_no_err<W: FrameSize>(&mut self) -> nb::Result<W, ()> {
240240
if self.spi.sr.read().rxne().bit_is_set() {
241241
Ok(self.read_unchecked())
242242
} else {
@@ -295,20 +295,35 @@ macro_rules! spi {
295295
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
296296
if words.len() == 0 { return Ok(()) }
297297

298+
// FIFO threshold to 16 bits
299+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
300+
298301
// prefill write fifo so that the clock doen't stop while fetch the read byte
299-
let prefill = self.fifo_cap() as usize;
302+
let prefill = self.fifo_cap() as usize / 2;
300303
for _ in 0..prefill {
301-
nb::block!(self.nb_write(0u8))?;
304+
nb::block!(self.nb_write(0u16))?;
302305
}
303306

304307
let len = words.len();
305-
for r in words[..len-prefill].iter_mut() {
306-
// TODO: 16 bit frames, bidirectional pins
308+
let half_len = len / 2;
309+
let pair_left = len % 2;
310+
311+
for r in words.chunks_exact_mut(2).take(half_len-prefill) {
312+
nb::block!(self.nb_write(0u16))?;
313+
let r_two: u16 = unsafe {
314+
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
315+
};
316+
// safety: chunks have exact length of 2
317+
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
318+
}
319+
320+
// FIFO threshold to 8 bits
321+
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
322+
if pair_left == 1 {
307323
nb::block!(self.nb_write(0u8))?;
308-
// errors have been checked by the write above
309-
*r = unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() };
310324
}
311-
Ok(for r in words[len-prefill..].iter_mut() {
325+
326+
Ok(for r in words[len - prefill - pair_left..].iter_mut() {
312327
*r = nb::block!(self.nb_read())?;
313328
})
314329
}
@@ -331,26 +346,50 @@ macro_rules! spi {
331346
return self.read(read)
332347
}
333348

334-
let prefill = self.fifo_cap();
335-
let mut write_iter = write.into_iter();
349+
let common_len = core::cmp::min(read.len(), write.len());
350+
let half_len = common_len / 2;
351+
let pair_left = common_len % 2;
352+
353+
// write two bytes at once
354+
let prefill = self.fifo_cap() / 2;
355+
let mut write_iter = write.chunks_exact(2).map(|two|
356+
// safety: chunks_exact guarantees that chunks have 2 elements
357+
// second byte in send queue goes to the top of the 16-bit data register for
358+
// packing
359+
u16::from_le_bytes(unsafe { *two.as_ptr().cast() })
360+
);
336361

337362
// same prefill as in read, this time with actual data
338363
let mut prefilled = 0;
339364
for b in write_iter.by_ref().take(prefill as usize) {
340-
nb::block!(self.nb_write(*b))?;
341-
prefilled += 1
365+
nb::block!(self.nb_write(b))?;
366+
prefilled += 2
342367
}
343368

344-
let common_len = core::cmp::min(read.len(), write.len());
369+
// FIFO threshold to 16 bits
370+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
345371
// write ahead of reading
346-
let zipped = read.iter_mut().zip(write_iter).take(common_len - prefilled);
372+
let zipped = read.chunks_exact_mut(2).zip(write_iter).take(half_len - prefilled/2);
347373
for (r, w) in zipped {
348-
nb::block!(self.nb_write(*w))?;
349-
*r = unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() };
374+
375+
nb::block!(self.nb_write(w))?;
376+
let r_two: u16 = unsafe {
377+
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
378+
};
379+
// same as above, length is checked by chunks_exact
380+
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
381+
}
382+
383+
// FIFO threshold to 8 bits
384+
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
385+
386+
if pair_left == 1 {
387+
let write_idx = common_len - 1;
388+
nb::block!(self.nb_write(write[write_idx]))?;
350389
}
351390

352391
// read words left in the fifo
353-
for r in read[common_len-prefilled..common_len].iter_mut() {
392+
for r in read[common_len-prefilled-pair_left..common_len].iter_mut() {
354393
*r = nb::block!(self.nb_read())?
355394
}
356395

@@ -373,13 +412,17 @@ macro_rules! spi {
373412
nb::block!(self.nb_write(w.get()))?;
374413
}
375414

376-
for (r, w) in write_iter.zip(read_iter.by_ref()) {
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()) {
377418
nb::block!(self.nb_write(w.get()))?;
378419
r.set(unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() });
379420
}
421+
380422

381423
Ok(for r in read_iter {
382-
r.set(nb::block!(self.nb_read())?);
424+
let read = nb::block!(self.nb_read())?;
425+
r.set(read);
383426
})
384427
}
385428
fn flush(&mut self) -> Result<(), Self::Error> {

0 commit comments

Comments
 (0)