use crate::spi_slave::Parts; use crate::urukul::Error; use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin}; use core::cell; /* * Basic structure for CPLD signal multiplexing */ #[derive(Debug)] pub struct CPLDData { pub(crate) spi: SPI, pub(crate) chip_select: (CS0, CS1, CS2), pub(crate) io_update: GPIO, } #[derive(Debug)] pub struct CPLD { pub(crate) data: cell::RefCell>, } impl CPLDData where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin, { pub(crate) fn select_chip(&mut self, chip: u8) -> Result<(), Error> { match chip & (1 << 0) { 0 => self.chip_select.0.set_low(), _ => self.chip_select.0.set_high(), } .map_err(|_| Error::CSError)?; match chip & (1 << 1) { 0 => self.chip_select.1.set_low(), _ => self.chip_select.1.set_high(), } .map_err(|_| Error::CSError)?; match chip & (1 << 2) { 0 => self.chip_select.2.set_low(), _ => self.chip_select.2.set_high(), } .map_err(|_| Error::CSError)?; Ok(()) } pub(crate) fn issue_io_update(&mut self) -> Result<(), Error> { self.io_update .set_high() .map_err(|_| Error::IOUpdateError)?; // I/O Update minimum pulse width: 1 SYNC_CLK cycle // 1 SYNC_CLK cycle = 4 REF_CLK cycle, where f_ref_clk is at least 3.2 MHz // Therefore the maximum required pulse length is 1.25 us, // equivalent to 500 cycles with STM32 sysclk at 400 MHz, longer delay is provided. cortex_m::asm::delay(1_000); self.io_update.set_low().map_err(|_| Error::IOUpdateError) } } impl Transfer for CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin, { type Error = Error; fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { self.data .try_borrow_mut() .map_err(|_| Error::GetRefMutDataError)? .spi .transfer(words) .map_err(Error::SPI) } } impl CPLD where SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, GPIO: OutputPin, { // Constructor for CPLD pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2), io_update: GPIO) -> Self { // Init data let data = CPLDData { spi, chip_select, io_update, }; // Init CPLD CPLD { data: cell::RefCell::new(data), } } // Destroy the wrapper, return the CPLD data pub fn destroy(self) -> (SPI, (CS0, CS1, CS2), GPIO) { let cpld = self.data.into_inner(); (cpld.spi, cpld.chip_select, cpld.io_update) } // Split SPI into chips, wrapped by Parts struct pub fn split<'a>(&'a self) -> Parts<'a, SPI, CS0, CS1, CS2, GPIO> { Parts::new(&self) } }