Skip to content

Commit

Permalink
Fix #97: split unbalanced SPI transfers into rw+r or rw+w
Browse files Browse the repository at this point in the history
  • Loading branch information
adamgreig committed Sep 25, 2023
1 parent 86ab035 commit 848b59f
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 14 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
- Updated to `embedded-hal` `1.0.0-alpha.11` release ([API changes](https://github.com/rust-embedded/embedded-hal/blob/master/embedded-hal/CHANGELOG.md#v100-alpha11---2023-07-04))
- Updated to `spidev` `0.5.2` release([API changes](https://github.com/rust-embedded/rust-spidev/blob/master/CHANGELOG.md#052--2023-08-02))

### Fixed
- Fix using SPI transfer with unequal buffer sizes (#97, #98).

## [v0.4.0-alpha.3] - 2022-08-04

### Added
Expand Down
57 changes: 43 additions & 14 deletions src/spi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! [`embedded-hal`]: https://docs.rs/embedded-hal
//!

use std::cmp::Ordering;
use std::fmt;
use std::io;
use std::ops;
Expand Down Expand Up @@ -64,9 +65,24 @@ mod embedded_hal_impl {
}

fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
self.0
.transfer(&mut SpidevTransfer::read_write(write, read))
.map_err(|err| SPIError { err })
let read_len = read.len();
match read_len.cmp(&write.len()) {
Ordering::Less => self.0.transfer_multiple(&mut [
SpidevTransfer::read_write(&write[..read_len], read),
SpidevTransfer::write(&write[read_len..]),
]),
Ordering::Equal => self
.0
.transfer(&mut SpidevTransfer::read_write(write, read)),
Ordering::Greater => {
let (read1, read2) = read.split_at_mut(write.len());
self.0.transfer_multiple(&mut [
SpidevTransfer::read_write(write, read1),
SpidevTransfer::read(read2),
])
}
}
.map_err(|err| SPIError { err })
}

fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
Expand All @@ -82,7 +98,7 @@ mod embedded_hal_impl {
}

impl SpiDevice for Spidev {
///Perform a transaction against the device. [Read more][transaction]
/// Perform a transaction against the device. [Read more][transaction]
///
/// [Delay operations][delay] are capped to 65535 microseconds.
///
Expand All @@ -92,24 +108,37 @@ mod embedded_hal_impl {
&mut self,
operations: &mut [SpiOperation<'_, u8>],
) -> Result<(), Self::Error> {
let mut transfers: Vec<_> = operations
.iter_mut()
.map(|op| match op {
SpiOperation::Read(buf) => SpidevTransfer::read(buf),
SpiOperation::Write(buf) => SpidevTransfer::write(buf),
SpiOperation::Transfer(read, write) => SpidevTransfer::read_write(write, read),
let mut transfers = Vec::with_capacity(operations.len());
for op in operations {
match op {
SpiOperation::Read(buf) => transfers.push(SpidevTransfer::read(buf)),
SpiOperation::Write(buf) => transfers.push(SpidevTransfer::write(buf)),
SpiOperation::Transfer(read, write) => match read.len().cmp(&write.len()) {
Ordering::Less => {
let n = read.len();
transfers.push(SpidevTransfer::read_write(&write[..n], read));
transfers.push(SpidevTransfer::write(&write[n..]));
}
Ordering::Equal => transfers.push(SpidevTransfer::read_write(write, read)),
Ordering::Greater => {
let (read1, read2) = read.split_at_mut(write.len());
transfers.push(SpidevTransfer::read_write(write, read1));
transfers.push(SpidevTransfer::read(read2));
}
},
SpiOperation::TransferInPlace(buf) => {
let tx = unsafe {
let p = buf.as_ptr();
std::slice::from_raw_parts(p, buf.len())
};
SpidevTransfer::read_write(tx, buf)
transfers.push(SpidevTransfer::read_write(tx, buf));
}
SpiOperation::DelayUs(us) => {
SpidevTransfer::delay((*us).try_into().unwrap_or(u16::MAX))
let us = (*us).try_into().unwrap_or(u16::MAX);
transfers.push(SpidevTransfer::delay(us));
}
})
.collect();
}
}
self.0
.transfer_multiple(&mut transfers)
.map_err(|err| SPIError { err })?;
Expand Down

0 comments on commit 848b59f

Please sign in to comment.