pub use crate::iomuxc::spi::module;
use crate::ccm;
use crate::iomuxc::{daisy, spi};
use core::marker::PhantomData;
use imxrt1062_pac as pac;
use pac::lpspi1::sr;
pub struct Unclocked {}
impl Unclocked {
pub(crate) fn new() -> Self {
Unclocked {}
}
pub fn clock(
self,
handle: &mut ccm::Handle,
clock_select: ccm::spi::ClockSelect,
divider: ccm::spi::PrescalarSelect,
) -> (
Builder<module::_1>,
Builder<module::_2>,
Builder<module::_3>,
Builder<module::_4>,
) {
let (ccm, _) = handle.raw();
ccm.ccgr1.modify(|_, w| unsafe {
w.cg0()
.bits(0b00)
.cg1()
.bits(0b00)
.cg2()
.bits(0b00)
.cg3()
.bits(0b00)
});
ccm.cbcmr.modify(|_, w| {
w.lpspi_podf()
.variant(divider)
.lpspi_clk_sel()
.variant(clock_select.into())
});
ccm.ccgr1.modify(|_, w| unsafe {
w.cg0()
.bits(0b11)
.cg1()
.bits(0b11)
.cg2()
.bits(0b11)
.cg3()
.bits(0b11)
});
let source_clock = ccm::Frequency::from(clock_select) / ccm::Divider::from(divider);
(
Builder::new(source_clock, pac::LPSPI1::ptr()),
Builder::new(source_clock, pac::LPSPI2::ptr()),
Builder::new(source_clock, pac::LPSPI3::ptr()),
Builder::new(source_clock, pac::LPSPI4::ptr()),
)
}
}
pub struct Builder<M> {
_module: PhantomData<M>,
reg: &'static pac::lpspi1::RegisterBlock,
source_clock: ccm::Frequency,
}
impl<M> Builder<M>
where
M: module::Module,
{
fn new(source_clock: ccm::Frequency, reg: *const pac::lpspi1::RegisterBlock) -> Self {
Builder {
_module: PhantomData,
reg: unsafe { &*reg },
source_clock,
}
}
pub fn build<SDO, SDI, SCK>(self, mut sdo: SDO, mut sdi: SDI, mut sck: SCK) -> SPI<M>
where
SDO: spi::Pin<Module = M, Wire = spi::SDO> + daisy::IntoDaisy,
SDI: spi::Pin<Module = M, Wire = spi::SDI> + daisy::IntoDaisy,
SCK: spi::Pin<Module = M, Wire = spi::SCK> + daisy::IntoDaisy,
{
sdo.configure();
sdi.configure();
sck.configure();
let _ = sdo.into_daisy();
let _ = sdi.into_daisy();
let _ = sck.into_daisy();
SPI::new(self.source_clock, self.reg)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[repr(transparent)]
pub struct ClockSpeed(pub u32);
impl Default for ClockSpeed {
fn default() -> Self {
ClockSpeed(8_000_000)
}
}
impl ClockSpeed {
unsafe fn set(self, source_clock: ccm::Frequency, reg: &pac::lpspi1::RegisterBlock) {
log::debug!(
"SPI baud rate = {:?}, source clock = {:?}",
self,
source_clock
);
let source_clock_ticks = ccm::Ticks::from(source_clock);
let mut div = source_clock_ticks.0 / self.0;
if source_clock_ticks.0 / div > self.0 {
div += 1;
}
let div = div.saturating_sub(2).min(255).max(0) as u8;
reg.ccr.write(|w|
w.sckdiv().bits(div)
.dbt().bits(div / 2)
.sckpcs().bits(0x1F)
.pcssck().bits(0x1F));
}
}
pub struct SPI<M> {
reg: &'static pac::lpspi1::RegisterBlock,
_module: PhantomData<M>,
source_clock: ccm::Frequency,
}
#[derive(Debug)]
pub struct ClockSpeedError;
#[derive(Debug)]
pub struct ModeError;
#[derive(Debug)]
pub struct PinLowTimeoutError;
#[derive(Debug)]
pub struct BusIdleTimeoutError;
const RETRIES: usize = 100_000;
impl<M> SPI<M>
where
M: module::Module,
{
fn new(source_clock: ccm::Frequency, reg: &'static pac::lpspi1::RegisterBlock) -> Self {
let mut spi = SPI {
reg,
_module: PhantomData,
source_clock,
};
spi.reg.cr.write_with_zero(|w| w.rst().set_bit());
spi.reg.cr.write_with_zero(|w| w.rst().clear_bit());
spi.set_clock_speed(ClockSpeed::default()).unwrap();
spi.reg
.cfgr1
.write(|w| w.master().master_1().sample().sample_1());
spi.set_mode(embedded_hal::spi::MODE_0).unwrap();
spi.reg.fcr.write(|w| unsafe {
w.rxwater().bits(0xf).txwater().bits(0xf)
});
spi.reg.cr.write_with_zero(|w| w.men().set_bit());
spi
}
fn with_master_disabled<F: FnMut() -> R, R>(&self, mut act: F) -> R {
let men = self.reg.cr.read().men().bit_is_set();
self.reg.cr.modify(|_, w| w.men().clear_bit());
let res = act();
self.reg.cr.modify(|_, w| w.men().bit(men));
res
}
pub fn enable_chip_select_0<PCS>(&mut self, mut pcs: PCS)
where
PCS: spi::Pin<Module = M, Wire = spi::PCS0> + daisy::IntoDaisy,
{
pcs.configure();
let _ = pcs.into_daisy();
}
pub fn set_mode(&mut self, mode: embedded_hal::spi::Mode) -> Result<(), ModeError> {
self.reg.tcr.modify(|_, w| {
w.cpol()
.bit(mode.polarity == embedded_hal::spi::Polarity::IdleHigh)
.cpha()
.bit(mode.phase == embedded_hal::spi::Phase::CaptureOnSecondTransition)
});
Ok(())
}
pub fn set_clock_speed(&mut self, clock_speed: ClockSpeed) -> Result<(), ClockSpeedError> {
self.with_master_disabled(|| unsafe {
clock_speed.set(self.source_clock, self.reg);
Ok(())
})
}
#[inline(always)]
fn wait<F>(&mut self, mut on: F) -> Result<(), Error>
where
F: FnMut(sr::R) -> bool,
{
for _ in 0..RETRIES {
if on(self.check_errors()?) {
return Ok(());
}
}
Err(Error::WaitTimeout)
}
fn clear_status(&mut self) {
self.reg.sr.write(|w| {
w.wcf()
.wcf_1()
.fcf()
.fcf_1()
.tcf()
.tcf_1()
.tef()
.tef_1()
.ref_()
.ref_1()
.dmf()
.dmf_1()
});
}
pub fn clear_fifo(&mut self) {
self.reg.cr.modify(|_, w| w.rrf().set_bit().rtf().set_bit());
}
#[inline(always)]
fn check_errors(&mut self) -> Result<sr::R, Error> {
let status = self.reg.sr.read();
if status.tef().bit_is_set() {
Err(Error::Transmit)
} else if status.ref_().bit_is_set() {
Err(Error::Receive)
} else if status.dmf().bit_is_set() {
Err(Error::DataMismatch)
} else {
Ok(status)
}
}
#[inline(always)]
fn send<Word: Into<u32> + Copy>(&mut self, word: Word) -> nb::Result<(), Error> {
let sr = self.check_errors()?;
self.clear_status();
self.reg.tcr.modify(|_, w| unsafe {
w.framesz()
.bits((core::mem::size_of::<Word>() * 8 - 1) as u16)
});
if sr.mbf().bit_is_set() || sr.tdf().bit_is_clear() {
return Err(nb::Error::WouldBlock);
}
self.reg
.tdr
.write(|w| unsafe { w.data().bits(word.into()) });
self.wait(|msr| msr.tdf().bit_is_set())?;
Ok(())
}
#[inline(always)]
fn read(&mut self) -> nb::Result<u32, Error> {
let sr = self.check_errors()?;
if sr.mbf().bit_is_set() {
return Err(nb::Error::WouldBlock);
}
if self.reg.rsr.read().rxempty().bit_is_clear() {
let word = self.reg.rdr.read().data().bits();
Ok(word)
} else {
Err(nb::Error::WouldBlock)
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Error {
Transmit,
Receive,
DataMismatch,
WaitTimeout,
}
impl<M> embedded_hal::spi::FullDuplex<u8> for SPI<M>
where
M: module::Module,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u8, Self::Error> {
Self::read(self).map(|w| w as u8)
}
fn send(&mut self, word: u8) -> nb::Result<(), Self::Error> {
Self::send::<u8>(self, word)
}
}
impl<M> embedded_hal::blocking::spi::write::Default<u8> for SPI<M> where M: module::Module {}
impl<M> embedded_hal::blocking::spi::transfer::Default<u8> for SPI<M> where M: module::Module {}
impl<M> embedded_hal::blocking::spi::write_iter::Default<u8> for SPI<M> where M: module::Module {}
impl<M> embedded_hal::spi::FullDuplex<u16> for SPI<M>
where
M: module::Module,
{
type Error = Error;
fn read(&mut self) -> nb::Result<u16, Self::Error> {
Self::read(self).map(|w| w as u16)
}
fn send(&mut self, word: u16) -> nb::Result<(), Self::Error> {
Self::send::<u16>(self, word)
}
}
impl<M> embedded_hal::blocking::spi::write::Default<u16> for SPI<M> where M: module::Module {}
impl<M> embedded_hal::blocking::spi::transfer::Default<u16> for SPI<M> where M: module::Module {}
impl<M> embedded_hal::blocking::spi::write_iter::Default<u16> for SPI<M> where M: module::Module {}