use embedded_hal::{
delay::DelayNs,
spi::{self, ErrorKind, ErrorType, Phase, Polarity},
};
use embedded_hal_nb::spi::FullDuplex;
use super::{Pins, PinsFull, PinsNoCS, SharedBus, SpiConfig, SpiExclusiveDevice, SpiX};
const EMPTY_WRITE_PAD: u8 = 0x00;
pub struct SpiBus<SPI, PINS> {
spi: SPI,
pins: PINS,
}
impl<SPI, PINS> SpiBus<SPI, PINS> {
pub fn release(self) -> (SPI, PINS) {
(self.spi, self.pins)
}
}
impl<SPI: SpiX, PINS> SpiBus<SPI, PINS> {
pub(crate) fn start_frame(&mut self) {
if !self.spi.csmode().read().mode().is_off() {
self.spi.csmode().write(|w| w.mode().hold());
}
}
pub(crate) fn end_frame(&mut self) {
if !self.spi.csmode().read().mode().is_off() {
self.spi.csmode().write(|w| w.mode().auto());
}
}
fn read_input(&self) -> nb::Result<u8, ErrorKind> {
let rxdata = self.spi.rxdata().read();
if rxdata.empty().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
Ok(rxdata.data().bits())
}
}
fn write_output(&self, word: u8) -> nb::Result<(), ErrorKind> {
if self.spi.txdata().read().full().bit_is_set() {
Err(nb::Error::WouldBlock)
} else {
self.spi.txdata().write(|w| unsafe { w.data().bits(word) });
Ok(())
}
}
fn wait_for_rxfifo(&self) {
while self.read_input().is_ok() {}
}
}
impl<SPI: SpiX, PINS: Pins<SPI>> SpiBus<SPI, PINS> {
pub fn new(spi: SPI, pins: PINS) -> Self {
Self { spi, pins }
}
pub fn new_device<D: DelayNs>(
self,
config: &SpiConfig,
delay: D,
) -> SpiExclusiveDevice<SPI, PINS, D> {
SpiExclusiveDevice::new(self, config, delay)
}
pub(crate) unsafe fn configure(&mut self, config: &SpiConfig, cs_index: Option<u32>) {
self.spi
.sckdiv()
.write(|w| unsafe { w.div().bits(config.clock_divisor as u16) });
if let Some(index) = cs_index {
self.spi.csid().write(|w| unsafe { w.bits(index) });
}
self.spi
.csmode()
.write(|w| w.mode().variant(config.cs_mode));
self.spi.csdef().reset();
let phase = config.mode.phase == Phase::CaptureOnSecondTransition;
let polarity = config.mode.polarity == Polarity::IdleHigh;
self.spi
.sckmode()
.write(|w| w.pha().bit(phase).pol().bit(polarity));
self.spi.fmt().write(|w| unsafe {
w.proto().single();
w.endian().big(); w.dir().rx();
w.len().bits(8)
});
self.spi
.txmark()
.write(|w| unsafe { w.txmark().bits(config.txmark) });
self.spi
.rxmark()
.write(|w| unsafe { w.rxmark().bits(config.rxmark) });
self.spi.delay0().write(|w| unsafe {
w.cssck().bits(config.delays.cssck); w.sckcs().bits(config.delays.sckcs) });
self.spi.delay1().write(|w| unsafe {
w.intercs().bits(config.delays.intercs); w.interxfr().bits(config.delays.interxfr) });
self.end_frame(); }
}
impl<SPI: SpiX, PINS: PinsNoCS<SPI>> SpiBus<SPI, PINS> {
pub fn shared(spi: SPI, pins: PINS) -> SharedBus<SPI, PINS> {
SharedBus::new(Self::new(spi, pins))
}
}
impl<SPI: SpiX, PINS> ErrorType for SpiBus<SPI, PINS> {
type Error = ErrorKind;
}
impl<SPI: SpiX, PINS: Pins<SPI>> FullDuplex for SpiBus<SPI, PINS> {
fn read(&mut self) -> nb::Result<u8, Self::Error> {
self.read_input()
}
fn write(&mut self, word: u8) -> nb::Result<(), Self::Error> {
self.write_output(word)
}
}
impl<SPI: SpiX, PINS: PinsFull<SPI>> spi::SpiBus for SpiBus<SPI, PINS> {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
let mut iwrite = 0;
let mut iread = 0;
self.wait_for_rxfifo();
while iwrite < words.len() || iread < words.len() {
if iwrite < words.len() {
match self.write_output(EMPTY_WRITE_PAD) {
Ok(()) => iwrite += 1,
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
if iread < iwrite {
match self.read_input() {
Ok(data) => {
unsafe { *words.get_unchecked_mut(iread) = data };
iread += 1;
}
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
}
Ok(())
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
let mut iwrite = 0;
let mut iread = 0;
self.wait_for_rxfifo();
while iwrite < words.len() || iread < words.len() {
if iwrite < words.len() {
let byte = unsafe { words.get_unchecked(iwrite) };
match self.write_output(*byte) {
Ok(()) => iwrite += 1,
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
if iread < iwrite {
match self.read_input() {
Ok(_) => iread += 1,
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
}
Ok(())
}
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
let mut iwrite = 0;
let mut iread = 0;
let max_len = read.len().max(write.len());
self.wait_for_rxfifo();
while iwrite < max_len || iread < max_len {
if iwrite < max_len {
let byte = write.get(iwrite).unwrap_or(&EMPTY_WRITE_PAD);
match self.write_output(*byte) {
Ok(()) => iwrite += 1,
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
if iread < iwrite {
match self.read_input() {
Ok(data) => {
if let Some(byte) = read.get_mut(iread) {
*byte = data;
}
iread += 1;
}
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
}
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
let mut iwrite = 0;
let mut iread = 0;
self.wait_for_rxfifo();
while iwrite < words.len() || iread < words.len() {
if iwrite < words.len() {
let byte = unsafe { words.get_unchecked(iwrite) };
match self.write_output(*byte) {
Ok(()) => iwrite += 1,
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
if iread < iwrite {
match self.read_input() {
Ok(data) => {
unsafe { *words.get_unchecked_mut(iread) = data };
iread += 1;
}
Err(nb::Error::WouldBlock) => {}
Err(nb::Error::Other(e)) => return Err(e),
}
}
}
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
self.wait_for_rxfifo(); Ok(())
}
}