2020-09-24 17:32:53 +08:00
|
|
|
use crate::urukul::Error;
|
2020-08-31 09:31:56 +08:00
|
|
|
use crate::spi_slave::Parts;
|
|
|
|
|
|
|
|
use embedded_hal::{
|
|
|
|
digital::v2::OutputPin,
|
|
|
|
blocking::spi::Transfer,
|
|
|
|
};
|
|
|
|
|
|
|
|
use core::cell;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Basic structure for CPLD signal multiplexing
|
|
|
|
*/
|
2020-08-31 09:34:38 +08:00
|
|
|
#[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>>,
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:19:05 +08:00
|
|
|
impl<SPI, CS0, CS1, CS2, GPIO, E> CPLDData<SPI, CS0, CS1, CS2, GPIO>
|
2020-08-31 09:34:38 +08:00
|
|
|
where
|
|
|
|
SPI: Transfer<u8, Error = E>,
|
|
|
|
CS0: OutputPin,
|
|
|
|
CS1: OutputPin,
|
|
|
|
CS2: OutputPin,
|
|
|
|
GPIO: OutputPin,
|
|
|
|
{
|
2020-09-17 12:19:05 +08:00
|
|
|
pub(crate) fn select_chip(&mut self, chip: u8) -> Result<(), Error<E>> {
|
2020-08-31 09:34:38 +08:00
|
|
|
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(())
|
|
|
|
}
|
|
|
|
|
2020-09-17 12:19:05 +08:00
|
|
|
pub(crate) fn issue_io_update(&mut self) -> Result<(), Error<E>> {
|
2020-08-31 09:34:38 +08:00
|
|
|
self.io_update.set_high().map_err(|_| Error::IOUpdateError)?;
|
|
|
|
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> {
|
2020-09-17 12:19:05 +08:00
|
|
|
self.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?.spi.transfer(words).map_err(Error::SPI)
|
2020-08-31 09:34:38 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
2020-09-17 12:19:05 +08:00
|
|
|
pub fn split<'a>(&'a self) -> Parts<'a, SPI, CS0, CS1, CS2, GPIO> {
|
2020-08-31 09:34:38 +08:00
|
|
|
Parts::new(&self)
|
|
|
|
}
|
|
|
|
}
|