Skip to content

Commit 98c4685

Browse files
committed
spi: handle edge cases in hal-1 trait impls
1 parent 83c37fa commit 98c4685

File tree

1 file changed

+40
-30
lines changed

1 file changed

+40
-30
lines changed

src/spi.rs

Lines changed: 40 additions & 30 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<W: FrameSize>(&mut self) -> nb::Result<W, ()> {
239+
fn nb_read_no_err<W: FrameSize>(&mut self) -> nb::Result<W, core::convert::Infallible> {
240240
if self.spi.sr.read().rxne().bit_is_set() {
241241
Ok(self.read_unchecked())
242242
} else {
@@ -267,7 +267,7 @@ macro_rules! spi {
267267
.cr1
268268
.modify(|_, w| w.bidimode().clear_bit().bidioe().clear_bit());
269269
}
270-
fn fifo_cap(&self) -> u8 {
270+
fn tx_fifo_cap(&self) -> u8 {
271271
match self.spi.sr.read().ftlvl().bits() {
272272
0 => 4,
273273
1 => 3,
@@ -293,22 +293,22 @@ macro_rules! spi {
293293

294294
impl<PINS> embedded_hal_one::spi::SpiBus for Spi<$SPIX, PINS> {
295295
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
296-
if words.len() == 0 { return Ok(()) }
296+
let len = words.len();
297+
if len == 0 { return Ok(()) }
297298

298299
// FIFO threshold to 16 bits
299300
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
300301

302+
let half_len = len / 2;
303+
let pair_left = len % 2;
304+
301305
// prefill write fifo so that the clock doen't stop while fetch the read byte
302-
let prefill = self.fifo_cap() as usize / 2;
306+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, half_len);
303307
for _ in 0..prefill {
304308
nb::block!(self.nb_write(0u16))?;
305309
}
306310

307-
let len = words.len();
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) {
311+
for r in words.chunks_exact_mut(2).take(half_len - prefill) {
312312
nb::block!(self.nb_write(0u16))?;
313313
let r_two: u16 = unsafe {
314314
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
@@ -317,13 +317,15 @@ macro_rules! spi {
317317
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
318318
}
319319

320+
let odd_idx = len.saturating_sub(prefill + pair_left);
320321
// FIFO threshold to 8 bits
321322
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
322323
if pair_left == 1 {
323324
nb::block!(self.nb_write(0u8))?;
325+
words[odd_idx] = nb::block!(self.nb_read_no_err()).unwrap();
324326
}
325327

326-
Ok(for r in words[len - prefill - pair_left..].iter_mut() {
328+
Ok(for r in words[odd_idx+1..].iter_mut() {
327329
*r = nb::block!(self.nb_read())?;
328330
})
329331
}
@@ -351,31 +353,30 @@ macro_rules! spi {
351353
let pair_left = common_len % 2;
352354

353355
// write two bytes at once
354-
let prefill = self.fifo_cap() / 2;
355356
let mut write_iter = write.chunks_exact(2).map(|two|
356357
// safety: chunks_exact guarantees that chunks have 2 elements
357358
// second byte in send queue goes to the top of the 16-bit data register for
358359
// packing
359360
u16::from_le_bytes(unsafe { *two.as_ptr().cast() })
360361
);
361362

363+
// FIFO threshold to 16 bits
364+
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
365+
362366
// same prefill as in read, this time with actual data
363-
let mut prefilled = 0;
364-
for b in write_iter.by_ref().take(prefill as usize) {
367+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, half_len);
368+
for b in write_iter.by_ref().take(prefill) {
365369
nb::block!(self.nb_write(b))?;
366-
prefilled += 2
367370
}
368371

369-
// FIFO threshold to 16 bits
370-
self.spi.cr2.modify(|_, w| w.frxth().clear_bit());
371372
// write ahead of reading
372-
let zipped = read.chunks_exact_mut(2).zip(write_iter).take(half_len - prefilled/2);
373+
let zipped = read.chunks_exact_mut(2).zip(write_iter).take(half_len - prefill);
373374
for (r, w) in zipped {
374375

375-
nb::block!(self.nb_write(w))?;
376376
let r_two: u16 = unsafe {
377377
nb::block!(self.nb_read_no_err()).unwrap_unchecked()
378378
};
379+
nb::block!(self.nb_write(w))?;
379380
// same as above, length is checked by chunks_exact
380381
unsafe { *r.as_mut_ptr().cast() = r_two.to_le_bytes(); }
381382
}
@@ -385,11 +386,17 @@ macro_rules! spi {
385386

386387
if pair_left == 1 {
387388
let write_idx = common_len - 1;
388-
nb::block!(self.nb_write(write[write_idx]))?;
389+
if prefill == 0 {
390+
nb::block!(self.nb_write(write[write_idx]))?;
391+
read[write_idx - 2*prefill] = nb::block!(self.nb_read_no_err()).unwrap();
392+
} else { // there's already data in the fifo, so read that before writing more
393+
read[write_idx - 2*prefill] = nb::block!(self.nb_read_no_err()).unwrap();
394+
nb::block!(self.nb_write(write[write_idx]))?;
395+
}
389396
}
390397

391398
// read words left in the fifo
392-
for r in read[common_len-prefilled-pair_left..common_len].iter_mut() {
399+
for r in read[common_len-2*prefill..common_len].iter_mut() {
393400
*r = nb::block!(self.nb_read())?
394401
}
395402

@@ -407,35 +414,38 @@ macro_rules! spi {
407414
let half_len = len / 2;
408415
let pair_left = len % 2;
409416

410-
let prefill = self.fifo_cap() / 2;
417+
let prefill = core::cmp::min(self.tx_fifo_cap() as usize / 2, half_len);
411418
let words_alias: &mut [[u8; 2]] = unsafe {
412419
let ptr = words.as_mut_ptr();
413420
core::slice::from_raw_parts_mut(ptr as *mut [u8; 2], half_len)
414421
};
415422

416-
let mut prefilled = 0;
417423
for b in words_alias.into_iter().take(prefill as usize) {
418424
nb::block!(self.nb_write(u16::from_le_bytes(*b)))?;
419-
prefilled += 2
420425
}
421426

422-
for i in 0..words_alias.len() - prefilled/2 {
427+
// data is in fifo isn't zero as long as words.len() > 1 so read-then-write is fine
428+
for i in 0..words_alias.len() - prefill {
423429
let read: u16 = unsafe { nb::block!(self.nb_read_no_err()).unwrap_unchecked() };
424430
words_alias[i] = read.to_le_bytes();
425-
let write = u16::from_le_bytes(words_alias[i + prefilled/2]);
431+
let write = u16::from_le_bytes(words_alias[i + prefill]);
426432
nb::block!(self.nb_write(write))?;
427433
}
428434
self.spi.cr2.modify(|_, w| w.frxth().set_bit());
429435

430436
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();
437+
let read_idx = len - 2*prefill - 1;
438+
if prefill == 0 {
439+
nb::block!(self.nb_write(*words.last().unwrap()))?;
440+
words[read_idx] = nb::block!(self.nb_read_no_err()).unwrap();
441+
} else {
442+
words[read_idx] = nb::block!(self.nb_read_no_err()).unwrap();
443+
nb::block!(self.nb_write(*words.last().unwrap()))?;
444+
}
435445
}
436446

437447
// read words left in the fifo
438-
Ok(for r in words.iter_mut().skip(len-prefilled) {
448+
Ok(for r in words.iter_mut().skip(len-2*prefill) {
439449
*r = nb::block!(self.nb_read())?;
440450
})
441451
}

0 commit comments

Comments
 (0)