2019-08-01 06:59:29 +08:00
|
|
|
use embedded_hal::spi::FullDuplex;
|
|
|
|
use embedded_hal::digital::v2::{InputPin, OutputPin};
|
2019-08-08 04:26:07 +08:00
|
|
|
use embedded_hal::blocking::spi::Transfer;
|
2019-08-01 06:59:29 +08:00
|
|
|
use nb::Error::WouldBlock;
|
|
|
|
|
2019-08-30 06:12:16 +08:00
|
|
|
/// Bit-banged Mode3 SPI
|
2019-08-01 06:59:29 +08:00
|
|
|
pub struct SoftSpi<SCK, MOSI, MISO> {
|
|
|
|
sck: SCK,
|
|
|
|
mosi: MOSI,
|
|
|
|
miso: MISO,
|
|
|
|
state: State,
|
|
|
|
input: Option<u8>,
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
enum State {
|
|
|
|
Idle,
|
|
|
|
Transfer {
|
|
|
|
clock_phase: bool,
|
|
|
|
mask: u8,
|
|
|
|
output: u8,
|
|
|
|
input: u8,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<SCK: OutputPin, MOSI: OutputPin, MISO: InputPin> SoftSpi<SCK, MOSI, MISO> {
|
|
|
|
pub fn new(mut sck: SCK, mut mosi: MOSI, miso: MISO) -> Self {
|
|
|
|
let _ = sck.set_high();
|
|
|
|
let _ = mosi.set_low();
|
|
|
|
SoftSpi {
|
|
|
|
sck, mosi, miso,
|
|
|
|
state: State::Idle,
|
|
|
|
input: None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Call this at twice the data rate
|
|
|
|
pub fn tick(&mut self) {
|
|
|
|
match self.state {
|
|
|
|
State::Idle => {}
|
|
|
|
State::Transfer { clock_phase: false,
|
|
|
|
mask, output, input } => {
|
|
|
|
if output & mask != 0 {
|
|
|
|
let _ = self.mosi.set_high();
|
|
|
|
} else {
|
|
|
|
let _ = self.mosi.set_low();
|
|
|
|
}
|
|
|
|
let _ = self.sck.set_low();
|
|
|
|
|
|
|
|
self.state = State::Transfer {
|
|
|
|
clock_phase: true,
|
|
|
|
mask, output, input,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
State::Transfer { clock_phase: true,
|
|
|
|
mask, output, mut input } => {
|
|
|
|
let _ = self.sck.set_high();
|
|
|
|
if self.miso.is_high().unwrap_or(false) {
|
|
|
|
input |= mask;
|
|
|
|
}
|
|
|
|
|
|
|
|
if mask != 1 {
|
|
|
|
self.state = State::Transfer {
|
|
|
|
clock_phase: false,
|
|
|
|
mask: mask >> 1,
|
|
|
|
output, input,
|
|
|
|
};
|
|
|
|
} else {
|
|
|
|
self.input = Some(input);
|
|
|
|
self.state = State::Idle;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-08 04:26:07 +08:00
|
|
|
|
2019-08-08 06:54:37 +08:00
|
|
|
pub fn run<F: FnMut()>(&mut self, delay: &'_ mut F) {
|
2019-08-08 04:26:07 +08:00
|
|
|
while self.state != State::Idle {
|
|
|
|
self.tick();
|
|
|
|
delay();
|
|
|
|
}
|
|
|
|
}
|
2019-08-01 06:59:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<SCK: OutputPin, MOSI: OutputPin, MISO: InputPin> FullDuplex<u8> for SoftSpi<SCK, MOSI, MISO> {
|
|
|
|
type Error = ();
|
|
|
|
|
|
|
|
fn read(&mut self) -> Result<u8, nb::Error<Self::Error>> {
|
|
|
|
match self.input.take() {
|
|
|
|
Some(input) =>
|
|
|
|
Ok(input),
|
|
|
|
None if self.state == State::Idle =>
|
|
|
|
Err(nb::Error::Other(())),
|
|
|
|
None =>
|
|
|
|
Err(WouldBlock),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn send(&mut self, output: u8) -> Result<(), nb::Error<Self::Error>> {
|
|
|
|
match self.state {
|
|
|
|
State::Idle => {
|
|
|
|
self.state = State::Transfer {
|
|
|
|
clock_phase: false,
|
|
|
|
mask: 0x80,
|
|
|
|
output,
|
|
|
|
input: 0,
|
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
_ => Err(WouldBlock)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-08 04:26:07 +08:00
|
|
|
|
2019-08-08 06:54:37 +08:00
|
|
|
pub struct SyncSoftSpi<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> {
|
2019-08-08 04:26:07 +08:00
|
|
|
spi: SoftSpi<SCK, MOSI, MISO>,
|
2019-08-08 06:54:37 +08:00
|
|
|
delay: &'d mut D,
|
2019-08-08 04:26:07 +08:00
|
|
|
}
|
|
|
|
|
2019-08-08 06:54:37 +08:00
|
|
|
impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> SyncSoftSpi<'d, SCK, MOSI, MISO, D> {
|
|
|
|
pub fn new(spi: SoftSpi<SCK, MOSI, MISO>, delay: &'d mut D) -> Self {
|
|
|
|
SyncSoftSpi { spi, delay }
|
|
|
|
}
|
|
|
|
|
2019-08-08 04:26:07 +08:00
|
|
|
fn retry<R, E, F>(&mut self, f: &F) -> Result<R, E>
|
|
|
|
where
|
|
|
|
F: Fn(&'_ mut SoftSpi<SCK, MOSI, MISO>) -> Result<R, nb::Error<E>>
|
|
|
|
{
|
|
|
|
loop {
|
|
|
|
match f(&mut self.spi) {
|
|
|
|
Ok(r) => return Ok(r),
|
|
|
|
Err(nb::Error::Other(e)) => return Err(e),
|
|
|
|
Err(WouldBlock) => self.spi.run(self.delay),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-08 06:54:37 +08:00
|
|
|
impl<'d, SCK: OutputPin, MOSI: OutputPin, MISO: InputPin, D: FnMut()> Transfer<u8> for SyncSoftSpi<'d, SCK, MOSI, MISO, D> {
|
2019-08-08 07:57:30 +08:00
|
|
|
// TODO: proper type
|
2019-08-08 04:26:07 +08:00
|
|
|
type Error = ();
|
|
|
|
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
|
|
|
|
for b in words.iter_mut() {
|
|
|
|
self.retry(&|spi| spi.send(*b))?;
|
|
|
|
*b = self.retry(&|spi| spi.read())?;
|
|
|
|
}
|
|
|
|
Ok(words)
|
|
|
|
}
|
|
|
|
}
|