use core::ops::Deref;
use crate::pac::{spi1, AUX, GPIO, SPI1, SPI2};
use embedded_hal::spi::{Phase, Polarity};
const SHIFT_LENGTH_BITS: u8 = 8;
const SHIFT_LENGTH_POS: u32 = 24;
const DATA_POS: u32 = SHIFT_LENGTH_POS - SHIFT_LENGTH_BITS as u32;
const IO_OFFSET: usize = 0x20;
const TXHOLD_OFFSET: usize = 0x30;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ChipSelect {
Cs0,
Cs1,
Cs2,
None,
}
impl ChipSelect {
fn pattern(self) -> u8 {
match self {
ChipSelect::Cs0 => 0b110,
ChipSelect::Cs1 => 0b101,
ChipSelect::Cs2 => 0b011,
ChipSelect::None => 0b111,
}
}
}
pub struct AuxSpi<S> {
spi: S,
}
impl AuxSpi<SPI1> {
pub fn init_spi1(
gpio: &GPIO,
aux: &AUX,
spi1: SPI1,
mode: embedded_hal::spi::Mode,
chip_select: ChipSelect,
speed: u16,
) -> Self {
aux.enables().modify(|_, w| w.spi_1().set_bit());
gpio.gpfsel1().modify(|_, w| w.fsel19().spi1_miso());
gpio.gpfsel2()
.modify(|_, w| w.fsel20().spi1_mosi().fsel21().spi1_sclk());
match chip_select {
ChipSelect::Cs0 => gpio.gpfsel1().modify(|_, w| w.fsel18().spi1_ce0_n()),
ChipSelect::Cs1 => gpio.gpfsel1().modify(|_, w| w.fsel17().spi1_ce1_n()),
ChipSelect::Cs2 => gpio.gpfsel1().modify(|_, w| w.fsel16().spi1_ce2_n()),
ChipSelect::None => {}
}
AuxSpi::configure(spi1, mode, chip_select, speed)
}
}
impl AuxSpi<SPI2> {
pub fn init_spi2(
gpio: &GPIO,
aux: &AUX,
spi2: SPI2,
mode: embedded_hal::spi::Mode,
chip_select: ChipSelect,
speed: u16,
) -> Self {
aux.enables().modify(|_, w| w.spi_2().set_bit());
gpio.gpfsel4().modify(|_, w| {
w.fsel40().reserved4(); w.fsel41().reserved4(); w.fsel42().reserved4() });
match chip_select {
ChipSelect::Cs0 => gpio.gpfsel4().modify(|_, w| w.fsel43().reserved4()),
ChipSelect::Cs1 => gpio.gpfsel4().modify(|_, w| w.fsel44().reserved4()),
ChipSelect::Cs2 => gpio.gpfsel4().modify(|_, w| w.fsel45().reserved4()),
ChipSelect::None => {}
}
AuxSpi::configure(spi2, mode, chip_select, speed)
}
}
impl<S: Deref<Target = spi1::RegisterBlock>> AuxSpi<S> {
fn configure(
spi: S,
mode: embedded_hal::spi::Mode,
chip_select: ChipSelect,
speed: u16,
) -> Self {
let cpol = mode.polarity == Polarity::IdleHigh;
let cpha = mode.phase == Phase::CaptureOnSecondTransition;
let out_rising = cpol ^ cpha;
spi.cntl0().write(|w| {
let w = w
.enable()
.set_bit()
.clear_fifos()
.set_bit()
.variable_width()
.set_bit()
.msb_first()
.set_bit()
.invert_clk()
.bit(cpol)
.out_rising()
.bit(out_rising)
.in_rising()
.bit(!out_rising);
unsafe {
w.chip_selects()
.bits(chip_select.pattern())
.speed()
.bits(speed)
}
});
spi.cntl0().modify(|_, w| w.clear_fifos().clear_bit());
spi.cntl1().write(|w| w.msb_first().set_bit());
Self { spi }
}
fn fifo_ptr(&self, offset: usize) -> *mut u32 {
let base = core::ptr::from_ref(&*self.spi) as usize;
(base + offset) as *mut u32
}
fn fifo_write(&self, byte: u8, hold_cs: bool) {
let word = (byte as u32) << DATA_POS | (SHIFT_LENGTH_BITS as u32) << SHIFT_LENGTH_POS;
let offset = if hold_cs { TXHOLD_OFFSET } else { IO_OFFSET };
unsafe { core::ptr::write_volatile(self.fifo_ptr(offset), word) };
}
fn fifo_read(&self) -> u8 {
(unsafe { core::ptr::read_volatile(self.fifo_ptr(IO_OFFSET)) } & 0xff) as u8
}
fn shift(
&mut self,
len: usize,
mut tx: impl FnMut(usize) -> u8,
mut rx: impl FnMut(usize, u8),
) {
let mut sent = 0;
let mut received = 0;
while received < len {
if sent < len && self.spi.stat().read().tx_full().bit_is_clear() {
let is_last = sent == len - 1;
self.fifo_write(tx(sent), !is_last);
sent += 1;
}
if self.spi.stat().read().rx_empty().bit_is_clear() {
let byte = self.fifo_read();
rx(received, byte);
received += 1;
}
}
}
}
impl<S: Deref<Target = spi1::RegisterBlock>> embedded_hal::spi::ErrorType for AuxSpi<S> {
type Error = core::convert::Infallible;
}
impl<S: Deref<Target = spi1::RegisterBlock>> embedded_hal::spi::SpiBus<u8> for AuxSpi<S> {
fn read(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
self.shift(words.len(), |_| 0, |i, byte| words[i] = byte);
Ok(())
}
fn write(&mut self, words: &[u8]) -> Result<(), Self::Error> {
self.shift(words.len(), |i| words[i], |_, _| {});
Ok(())
}
fn transfer(&mut self, read: &mut [u8], write: &[u8]) -> Result<(), Self::Error> {
let len = read.len().max(write.len());
self.shift(
len,
|i| write.get(i).copied().unwrap_or(0),
|i, byte| {
if let Some(slot) = read.get_mut(i) {
*slot = byte;
}
},
);
Ok(())
}
fn transfer_in_place(&mut self, words: &mut [u8]) -> Result<(), Self::Error> {
let len = words.len();
let mut sent = 0;
let mut received = 0;
while received < len {
if sent < len && self.spi.stat().read().tx_full().bit_is_clear() {
let is_last = sent == len - 1;
self.fifo_write(words[sent], !is_last);
sent += 1;
}
if self.spi.stat().read().rx_empty().bit_is_clear() {
words[received] = self.fifo_read();
received += 1;
}
}
Ok(())
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}