humpback-dds/src/cpld.rs

117 lines
3.2 KiB
Rust

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<SPI, CS0, CS1, CS2, GPIO> {
pub(crate) spi: SPI,
pub(crate) chip_select: (CS0, CS1, CS2),
pub(crate) io_update: GPIO,
}
#[derive(Debug)]
pub struct CPLD<SPI, CS0, CS1, CS2, GPIO> {
pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2, GPIO>>,
}
impl<SPI, CS0, CS1, CS2, GPIO, E> CPLDData<SPI, CS0, CS1, CS2, GPIO>
where
SPI: Transfer<u8, Error = E>,
CS0: OutputPin,
CS1: OutputPin,
CS2: OutputPin,
GPIO: OutputPin,
{
pub(crate) fn select_chip(&mut self, chip: u8) -> Result<(), Error<E>> {
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<E>> {
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<SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for CPLD<SPI, CS0, CS1, CS2, GPIO>
where
SPI: Transfer<u8, Error = E>,
CS0: OutputPin,
CS1: OutputPin,
CS2: OutputPin,
GPIO: OutputPin,
{
type Error = Error<E>;
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<SPI, CS0, CS1, CS2, GPIO, E> CPLD<SPI, CS0, CS1, CS2, GPIO>
where
SPI: Transfer<u8, Error = E>,
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)
}
}