Compare commits

...

2 Commits

Author SHA1 Message Date
occheung e834e6fcea spi mux: remove traits 2020-09-17 12:19:05 +08:00
occheung f77013c290 fpga config: fix unwrap bug 2020-09-17 11:48:32 +08:00
4 changed files with 41 additions and 101 deletions

View File

@ -79,7 +79,7 @@ fn main() -> ! {
// Pre-load the configuration bytes // Pre-load the configuration bytes
let config_data = include_bytes!("../build/top.bin"); let config_data = include_bytes!("../build/top.bin");
flash_ice40_fpga(fpga_cfg_spi, fpga_ss, fpga_creset, fpga_cdone, delay, config_data)?; flash_ice40_fpga(fpga_cfg_spi, fpga_ss, fpga_creset, fpga_cdone, delay, config_data).unwrap();
loop { loop {
nop(); nop();

View File

@ -23,12 +23,7 @@ pub struct CPLD<SPI, CS0, CS1, CS2, GPIO> {
pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2, GPIO>>, pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2, GPIO>>,
} }
pub trait SelectChip { impl<SPI, CS0, CS1, CS2, GPIO, E> CPLDData<SPI, CS0, CS1, CS2, GPIO>
type Error;
fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error>;
}
impl<SPI, CS0, CS1, CS2, GPIO, E> SelectChip for CPLDData<SPI, CS0, CS1, CS2, GPIO>
where where
SPI: Transfer<u8, Error = E>, SPI: Transfer<u8, Error = E>,
CS0: OutputPin, CS0: OutputPin,
@ -36,8 +31,7 @@ where
CS2: OutputPin, CS2: OutputPin,
GPIO: OutputPin, GPIO: OutputPin,
{ {
type Error = Error<E>; pub(crate) fn select_chip(&mut self, chip: u8) -> Result<(), Error<E>> {
fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error> {
match chip & (1 << 0) { match chip & (1 << 0) {
0 => self.chip_select.0.set_low(), 0 => self.chip_select.0.set_low(),
_ => self.chip_select.0.set_high(), _ => self.chip_select.0.set_high(),
@ -52,49 +46,13 @@ where
}.map_err(|_| Error::CSError)?; }.map_err(|_| Error::CSError)?;
Ok(()) Ok(())
} }
}
pub trait IssueIOUpdate { pub(crate) fn issue_io_update(&mut self) -> Result<(), Error<E>> {
type Error;
fn issue_io_update(&mut self) -> Result<(), Self::Error>;
}
impl<SPI, CS0, CS1, CS2, GPIO, E> IssueIOUpdate for CPLDData<SPI, CS0, CS1, CS2, GPIO>
where
SPI: Transfer<u8>,
CS0: OutputPin,
CS1: OutputPin,
CS2: OutputPin,
GPIO: OutputPin<Error = E>,
{
type Error = Error<E>;
fn issue_io_update(&mut self) -> Result<(), Self::Error> {
self.io_update.set_high().map_err(|_| Error::IOUpdateError)?; self.io_update.set_high().map_err(|_| Error::IOUpdateError)?;
self.io_update.set_low().map_err(|_| Error::IOUpdateError) self.io_update.set_low().map_err(|_| Error::IOUpdateError)
} }
} }
pub trait DoOnGetRefMutData<SPI, CS0, CS1, CS2, GPIO> {
fn do_on_get_ref_mut_data<R, E>(
&self,
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2, GPIO>>) -> Result<R, Error<E>>,
) -> Result<R, Error<E>>;
}
impl<SPI, CS0, CS1, CS2, GPIO> DoOnGetRefMutData<SPI, CS0, CS1, CS2, GPIO> for CPLD<SPI, CS0, CS1, CS2, GPIO> {
fn do_on_get_ref_mut_data<R, E>(
&self,
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2, GPIO>>) -> Result<R, Error<E>>,
) -> Result<R, Error<E>> {
let dev = self
.data
.try_borrow_mut()
.map_err(|_| Error::GetRefMutDataError)?;
f(dev)
}
}
impl<SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for CPLD<SPI, CS0, CS1, CS2, GPIO> impl<SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for CPLD<SPI, CS0, CS1, CS2, GPIO>
where where
SPI: Transfer<u8, Error = E>, SPI: Transfer<u8, Error = E>,
@ -106,7 +64,7 @@ where
type Error = Error<E>; type Error = Error<E>;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.do_on_get_ref_mut_data(move |mut dev| dev.spi.transfer(words).map_err(Error::SPI)) self.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?.spi.transfer(words).map_err(Error::SPI)
} }
} }
@ -140,26 +98,7 @@ impl<SPI, CS0, CS1, CS2, GPIO, E> CPLD<SPI, CS0, CS1, CS2, GPIO> where
} }
// Split SPI into chips, wrapped by Parts struct // Split SPI into chips, wrapped by Parts struct
pub fn split<'a>(&'a self) -> Parts<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO> { pub fn split<'a>(&'a self) -> Parts<'a, SPI, CS0, CS1, CS2, GPIO> {
Parts::new(&self) Parts::new(&self)
} }
// Select Chip
pub fn select_chip(&mut self, channel: u8) -> Result<(), Error<E>> {
self.do_on_get_ref_mut_data(|mut dev| dev.select_chip(channel))
}
} }
impl<SPI, CS0, CS1, CS2, GPIO, E> CPLD<SPI, CS0, CS1, CS2, GPIO>
where
SPI: Transfer<u8>,
CS0: OutputPin,
CS1: OutputPin,
CS2: OutputPin,
GPIO: OutputPin<Error = E>
{
// Issue I/O Update
pub fn issue_io_update(&mut self) -> Result<(), Error<E>> {
self.do_on_get_ref_mut_data(|mut dev| dev.issue_io_update())
}
}

View File

@ -13,6 +13,7 @@ use nb::block;
use log::{warn, debug}; use log::{warn, debug};
#[derive(Debug)]
pub enum FPGAFlashError { pub enum FPGAFlashError {
SPICommunicationError, SPICommunicationError,
NegotiationError, NegotiationError,

View File

@ -4,60 +4,60 @@ use embedded_hal::{
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::cpld::{DoOnGetRefMutData, SelectChip, IssueIOUpdate}; use crate::cpld::CPLD;
use crate::Error; use crate::Error;
pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> ( pub struct SPISlave<'a, SPI, CS0, CS1, CS2, GPIO> (
&'a DEV, // SPI device to be multiplexed
u8, // Channel of SPI slave &'a CPLD<SPI, CS0, CS1, CS2, GPIO>,
bool, // Need I/O Update // Channel of SPI slave
PhantomData<(SPI, CS0, CS1, CS2, GPIO)>, u8,
// Need I/O Update
bool,
); );
pub struct Parts<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> { pub struct Parts<'a, SPI, CS0, CS1, CS2, GPIO> {
pub spi1: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi1: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi2: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi2: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi3: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi3: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi4: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi4: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi5: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi5: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi6: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi6: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
pub spi7: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>, pub spi7: SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>,
} }
impl<'a, DEV, SPI, CS0, CS1, CS2, GPIO> Parts<'a, DEV, SPI, CS0, CS1, CS2, GPIO> { impl<'a, SPI, CS0, CS1, CS2, GPIO> Parts<'a, SPI, CS0, CS1, CS2, GPIO> {
pub(crate) fn new(cpld: &'a DEV) -> Self { pub(crate) fn new(cpld: &'a CPLD<SPI, CS0, CS1, CS2, GPIO>) -> Self {
Parts { Parts {
spi1: SPISlave(&cpld, 1, false, PhantomData), spi1: SPISlave(&cpld, 1, false),
spi2: SPISlave(&cpld, 2, false, PhantomData), spi2: SPISlave(&cpld, 2, false),
spi3: SPISlave(&cpld, 3, true, PhantomData), spi3: SPISlave(&cpld, 3, true),
spi4: SPISlave(&cpld, 4, true, PhantomData), spi4: SPISlave(&cpld, 4, true),
spi5: SPISlave(&cpld, 5, true, PhantomData), spi5: SPISlave(&cpld, 5, true),
spi6: SPISlave(&cpld, 6, true, PhantomData), spi6: SPISlave(&cpld, 6, true),
spi7: SPISlave(&cpld, 7, true, PhantomData), spi7: SPISlave(&cpld, 7, true),
} }
} }
} }
impl<'a, DEV, SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO> impl<'a, SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>
where where
CS2: OutputPin, CS2: OutputPin,
CS1: OutputPin, CS1: OutputPin,
CS0: OutputPin, CS0: OutputPin,
DEV: DoOnGetRefMutData<SPI, CS0, CS1, CS2, GPIO>,
SPI: Transfer<u8, Error = E>, SPI: Transfer<u8, Error = E>,
GPIO: OutputPin, GPIO: OutputPin,
{ {
type Error = Error<E>; type Error = Error<E>;
fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> { fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> {
self.0.do_on_get_ref_mut_data(move |mut dev| { let mut dev = self.0.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?;
dev.select_chip(self.1).map_err(|_| Error::CSError)?; dev.select_chip(self.1).map_err(|_| Error::CSError)?;
let result = dev.spi.transfer(words).map_err(Error::SPI)?; let result = dev.spi.transfer(words).map_err(Error::SPI)?;
dev.select_chip(0).map_err(|_| Error::CSError)?; dev.select_chip(0).map_err(|_| Error::CSError)?;
if self.2 { if self.2 {
dev.issue_io_update().map_err(|_| Error::IOUpdateError)?; dev.issue_io_update().map_err(|_| Error::IOUpdateError)?;
} }
Ok(result) Ok(result)
})
} }
} }