From a406dea0c71ffdf5e0c4c15de80ab238eb1bd126 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 10 Aug 2020 17:04:40 +0800 Subject: [PATCH] cpld: spi slave WIP --- src/cpld.rs | 135 ++++++++++++++++++++++++++++++++++++++--------- src/lib.rs | 7 +++ src/spi_slave.rs | 65 +++++++++++++++++++++++ 3 files changed, 181 insertions(+), 26 deletions(-) create mode 100644 src/lib.rs create mode 100644 src/spi_slave.rs diff --git a/src/cpld.rs b/src/cpld.rs index 730e7e9..031180d 100644 --- a/src/cpld.rs +++ b/src/cpld.rs @@ -7,61 +7,144 @@ use stm32h7xx_hal::{ OutputPin, }, blocking::spi::Transfer, + spi::FullDuplex, }, pac, prelude::*, spi, }; +use core::cell; + use cortex_m; use cortex_m::asm::nop; use cortex_m_semihosting::hprintln; use nb::block; +use super::{Parts}; + +/* + * Enum for structuring error + */ +#[derive(Debug)] +pub enum Error { + SPI(E), + CSError, + GetRefMutDataError, +} /* * Basic structure for CPLD signal multiplexing */ -pub struct CPLD { - spi: SPI, - chip_select: (CS0, CS1, CS2), +#[derive(Debug)] +pub struct CPLDData { + pub(crate) spi: SPI, + pub(crate) chip_select: (CS0, CS1, CS2), } -impl CPLD where - SPI: Transfer, +#[derive(Debug)] +pub struct CPLD { + pub(crate) data: cell::RefCell>, +} + +pub trait SelectChip { + type Error; + fn select_chip(&mut self, channel: u8) -> Result<(), Self::Error>; +} + +impl SelectChip for CPLDData +where + SPI: Transfer, CS0: OutputPin, CS1: OutputPin, CS2: OutputPin, { + type Error = Error; + fn select_chip(&mut self, chip: u8) -> Result<(), Self::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 trait DoOnGetRefMutData { + fn do_on_get_ref_mut_data( + &mut self, + f: impl FnOnce(cell::RefMut>) -> Result>, + ) -> Result>; +} + +impl DoOnGetRefMutData for CPLD { + fn do_on_get_ref_mut_data( + &mut self, + f: impl FnOnce(cell::RefMut>) -> Result>, + ) -> Result> { + let dev = self + .data + .try_borrow_mut() + .map_err(|_| Error::GetRefMutDataError)?; + f(dev) + } +} + +impl Transfer for CPLD +where + SPI: Transfer, + CS0: OutputPin, + CS1: OutputPin, + CS2: OutputPin, +{ + type Error = 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)) + } +} + +impl CPLD where + SPI: Transfer, + CS0: OutputPin, + CS1: OutputPin, + CS2: OutputPin, +{ // Constructor for CPLD pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2)) -> Self { - // Init CS to be 0 - let mut obj = Self{spi, chip_select}; - obj.select_chip(0); - return obj + // Init data + let data = CPLDData { + spi, + chip_select, + }; + + // Init CPLD + CPLD { + data: cell::RefCell::new(data), + } } - // Select chip - pub fn select_chip(&mut self, channel: u8) { - match channel & (1 << 0) { - 0 => self.chip_select.0.set_low(), - _ => self.chip_select.0.set_high(), - }.ok(); - match channel & (1 << 1) { - 0 => self.chip_select.1.set_low(), - _ => self.chip_select.1.set_high(), - }.ok(); - match channel & (1 << 2) { - 0 => self.chip_select.2.set_low(), - _ => self.chip_select.2.set_high(), - }.ok(); + // Destroy the wrapper, return the CPLD data + pub fn destroy(self) -> (SPI, (CS0, CS1, CS2)) { + let cpld = self.data.into_inner(); + (cpld.spi, cpld.chip_select) } - // Return the SPI and CS pins - pub fn release(self) -> (SPI, (CS0, CS1, CS2)) { - return (self.spi, self.chip_select); + // Split SPI into chips, wrapped by Parts struct + pub fn split<'a>(&'a self) -> Parts<'a, CPLD, SPI, CS0, CS1, CS2> { + Parts::new(&self) } + // Select Chip + pub fn select_chip(&mut self, channel: u8) -> Result<(), Error> { + self.do_on_get_ref_mut_data(|mut dev| dev.select_chip(channel)) + } } diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..99dacf1 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,7 @@ +#![no_std] + +mod cpld; +pub use cpld::{CPLD, Error}; + +mod spi_slave; +pub use spi_slave::{SPISlave, Parts}; diff --git a/src/spi_slave.rs b/src/spi_slave.rs new file mode 100644 index 0000000..44baeaf --- /dev/null +++ b/src/spi_slave.rs @@ -0,0 +1,65 @@ +use stm32h7xx_hal::{ + hal::{ + digital::v2::{ + InputPin, + OutputPin, + }, + blocking::spi::Transfer, + }, + pac, + prelude::*, + spi, +}; + +use core::marker::PhantomData; + +use crate::cpld::{DoOnGetRefMutData, Error, SelectChip}; + +pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2> ( + &'a DEV, + u8, + PhantomData<(SPI, CS0, CS1, CS2)>, +); + +pub struct Parts<'a, DEV: 'a, SPI, CS0, CS1, CS2> { + pub spi1: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi2: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi3: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi4: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi5: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi6: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, + pub spi7: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, +} + +impl<'a, DEV, SPI, CS0, CS1, CS2> Parts<'a, DEV, SPI, CS0, CS1, CS2> { + pub(crate) fn new(cpld: &'a DEV) -> Self { + Parts { +// spi0: SPISlave(&cpld, 0, PhantomData), + spi1: SPISlave(&cpld, 1, PhantomData), + spi2: SPISlave(&cpld, 2, PhantomData), + spi3: SPISlave(&cpld, 3, PhantomData), + spi4: SPISlave(&cpld, 4, PhantomData), + spi5: SPISlave(&cpld, 5, PhantomData), + spi6: SPISlave(&cpld, 6, PhantomData), + spi7: SPISlave(&cpld, 7, PhantomData), + } + } +} + +impl<'a, DEV, SPI, CS0, CS1, CS2, E> Transfer for SPISlave<'a, DEV, SPI, CS0, CS1, CS2> +where + CS2: OutputPin, + CS1: OutputPin, + CS0: OutputPin, + DEV: DoOnGetRefMutData, + SPI: Transfer, +{ + type Error = Error; + + fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> { + self.0.do_on_get_ref_mut_data(|mut dev| { + dev.select_chip(self.1) + })?; + self.0.do_on_get_ref_mut_data(move |mut dev| dev.spi.transfer(words).map_err(Error::SPI)) + } +}