-
Notifications
You must be signed in to change notification settings - Fork 205
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
bebd7c3
commit de2d0ea
Showing
2 changed files
with
161 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
use super::*; | ||
use crate::ehal::spi::{self, ErrorKind, ErrorType, SpiBus}; | ||
use num_traits::{AsPrimitive, PrimInt}; | ||
|
||
#[cfg(feature = "thumbv6")] | ||
#[path = "impl_ehal_thumbv6m.rs"] | ||
pub mod impl_ehal_02; | ||
|
||
#[cfg(feature = "thumbv7")] | ||
#[path = "impl_ehal_thumbv7em.rs"] | ||
pub mod impl_ehal_02; | ||
|
||
impl spi::Error for Error { | ||
fn kind(&self) -> ErrorKind { | ||
match self { | ||
Error::Overflow => ErrorKind::Overrun, | ||
Error::LengthError => ErrorKind::Other, | ||
} | ||
} | ||
} | ||
|
||
impl<P, M, C> ErrorType for Spi<Config<P, M, C>, Duplex> | ||
where | ||
Config<P, M, C>: ValidConfig, | ||
P: ValidPads, | ||
M: MasterMode, | ||
C: Size, | ||
{ | ||
type Error = Error; | ||
} | ||
|
||
impl<P, M, C> Spi<Config<P, M, C>, Duplex> | ||
where | ||
Config<P, M, C>: ValidConfig, | ||
P: ValidPads, | ||
M: MasterMode, | ||
C: Size + Copy + 'static, | ||
C::Word: PrimInt + AsPrimitive<DataWidth>, | ||
DataWidth: AsPrimitive<C::Word>, | ||
{ | ||
/// Read and write a single word to the bus simultaneously. | ||
fn transfer_word_in_place(&mut self, word: C::Word) -> Result<C::Word, Error> { | ||
while self.read_flags().contains(Flags::DRE) { | ||
core::hint::spin_loop(); | ||
} | ||
self.read_flags_errors()?; | ||
unsafe { | ||
self.write_data(word.as_()); | ||
} | ||
|
||
while self.read_flags().contains(Flags::TXC | Flags::RXC) { | ||
core::hint::spin_loop(); | ||
} | ||
let word = unsafe { self.read_data().as_() }; | ||
Ok(word) | ||
} | ||
|
||
/// Perform a transfer, word by word. | ||
/// | ||
/// No-op words will be written if `read` is longer than `write`. Extra | ||
/// words are ignored if `write` is longer than `read`. | ||
fn transfer_word_by_word( | ||
&mut self, | ||
read: &mut [C::Word], | ||
write: &[C::Word], | ||
) -> Result<(), Error> { | ||
let nop_word = self.config.nop_word; | ||
for (r, w) in read | ||
.iter_mut() | ||
.zip(write.iter().chain(core::iter::repeat(&nop_word.as_()))) | ||
{ | ||
*r = self.transfer_word_in_place(*w)?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
} | ||
|
||
impl<P, M, C> SpiBus<Word<C>> for Spi<Config<P, M, C>, Duplex> | ||
where | ||
Config<P, M, C>: ValidConfig, | ||
P: ValidPads, | ||
M: MasterMode, | ||
C: Size + Copy + 'static, | ||
C::Word: PrimInt + AsPrimitive<DataWidth>, | ||
DataWidth: AsPrimitive<C::Word>, | ||
{ | ||
fn read(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { | ||
for word in words.iter_mut() { | ||
// Should replace todo with nop_word | ||
*word = self.transfer_word_in_place(self.config.nop_word.as_())?; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[inline] | ||
fn write(&mut self, words: &[Word<C>]) -> Result<(), Self::Error> { | ||
// We are `Duplex`, so we must receive as many words as we send, | ||
// otherwise we could trigger an overflow | ||
for word in words { | ||
let _ = self.transfer_word_in_place(*word)?; | ||
} | ||
Ok(()) | ||
} | ||
|
||
#[inline] | ||
fn transfer(&mut self, read: &mut [Word<C>], write: &[Word<C>]) -> Result<(), Self::Error> { | ||
self.transfer_word_by_word(read, write) | ||
} | ||
|
||
#[inline] | ||
fn transfer_in_place<'w>(&mut self, words: &mut [Word<C>]) -> Result<(), Self::Error> { | ||
// Can only ever do word-by-word to avoid DMA race conditions | ||
for word in words { | ||
let read = self.transfer_word_in_place(*word)?; | ||
*word = read; | ||
} | ||
|
||
Ok(()) | ||
} | ||
|
||
#[inline] | ||
fn flush(&mut self) -> Result<(), Error> { | ||
// Ignore buffer overflow errors | ||
while !self.read_flags().contains(Flags::TXC) { | ||
core::hint::spin_loop(); | ||
} | ||
|
||
Ok(()) | ||
} | ||
} |