Expand description
Implement embedded_hal
traits for Spi
structs
As noted in the spi module documentation, the embedded-hal trait
implementations vary by both Size
and Capability
. Each
implementation is optimized to take advantage of all information known at
compile-time, so it is importatnt to carefully read the documentation in
this module.
Variations by Size
Remember that SAMx5x chips operate in 32-bit extension mode and use the
hardware LENGTH
counter to set the number of bytes in each transaction.
The transaction Length
is usually tracked at compile-time using
type-level integers from the typenum
crate, but it can also be tracked
at run-time when using a DynLength
.
The transaction Length
s can be sub-divided into three groups:
Length
s of 1-4 bytes can be completed in a single read/write of theDATA
register. TheseLength
s are marked asAtomicSize
s.Length
sGreaterThan4
are known at compile-time but cannot be completed atomically.- A
DynLength
can be any length, but the value is only known at run-time.
In general, transaction lengths with an AtomicSize
implement embedded HAL
traits with the corresponding Word
type. For example, Spi
structs
using a transaction Length
of 2 bytes implement FullDuplex<u16>
. These
lengths implement both the blocking and non-blocking traits from embedded
HAL. The non-blocking traits are found in the spi
and serial
modules, while the blocking traits are found in the blocking
module.
Transaction lengths GreaterThan4
cannot be completed in a single read or
write of the DATA
register, so these lengths do NOT implement the
non-blocking traits from the embedded HAL spi
and serial
modules.
Instead, they only implement traits from the blocking
module. These traits
are implemented for u8
types, e.g. blocking::spi::Transfer<u8>
, and
operate on [u8]
slices. The length of the slice is checked to ensure it
matches the transaction Length
.
Because a DynLength
is not guaranteed to be an AtomicSize
, the
corresponding Spi
structs only implement the blocking
traits as well.
For a non-blocking alternative that can be used to transfer arbitrary-length
slices, you could use either
DMA
or the spi_future
module.
Variations by Capability
The implementations in this module also seek to optimize as much as possible
based on the Capability
of the Spi
struct. They follow a few general
rules:
Tx
structs can never receive data, so their corresponding trait implementations never read theDATA
register and can never return anError::Overflow
.Rx
structs in aMasterMode
must initiate all transactions, so their implementations of non-blocking traits must track the state of on-going transactions.Duplex
structs must always read as many bytes as they send, even when implementingWrite
-only traits, to ensure they never introduce anError::Overflow
.
Notes on individual embedded HAL traits
spi::FullDuplex
spi::FullDuplex
is only implemented for structs with Duplex
Capability
. Although the embedded HAL documentation assumes a
MasterMode
, this module also implements it for the Slave
OpMode
.
serial::Read
serial::Read
is only implemented for structs with Rx
Capability
. When
in a MasterMode
, it initiates and tracks the state of the on-going
transactions. But this is not required when acting as a Slave
.
serial::Write
serial::Write
is only implemented for structs with Tx
Capability
.
These implementations never read the DATA
register and ignore all
instances of Error::Overflow
.
blocking::serial::Write
This trait uses the blocking::serial::write::Default
implementation for
implementers of serial::Write
.
blocking::spi
traits
These traits are implemented following all of the rules outlined above for
the different Size
and Capability
options.