forked from M-Labs/humpback-dds
cpld: spi slave WIP
This commit is contained in:
parent
8e7fe971cb
commit
a406dea0c7
135
src/cpld.rs
135
src/cpld.rs
|
@ -7,61 +7,144 @@ use stm32h7xx_hal::{
|
||||||
OutputPin,
|
OutputPin,
|
||||||
},
|
},
|
||||||
blocking::spi::Transfer,
|
blocking::spi::Transfer,
|
||||||
|
spi::FullDuplex,
|
||||||
},
|
},
|
||||||
pac,
|
pac,
|
||||||
prelude::*,
|
prelude::*,
|
||||||
spi,
|
spi,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use core::cell;
|
||||||
|
|
||||||
use cortex_m;
|
use cortex_m;
|
||||||
use cortex_m::asm::nop;
|
use cortex_m::asm::nop;
|
||||||
use cortex_m_semihosting::hprintln;
|
use cortex_m_semihosting::hprintln;
|
||||||
|
|
||||||
use nb::block;
|
use nb::block;
|
||||||
|
use super::{Parts};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Enum for structuring error
|
||||||
|
*/
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error<E> {
|
||||||
|
SPI(E),
|
||||||
|
CSError,
|
||||||
|
GetRefMutDataError,
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic structure for CPLD signal multiplexing
|
* Basic structure for CPLD signal multiplexing
|
||||||
*/
|
*/
|
||||||
pub struct CPLD<SPI, CS0, CS1, CS2> {
|
#[derive(Debug)]
|
||||||
spi: SPI,
|
pub struct CPLDData<SPI, CS0, CS1, CS2> {
|
||||||
chip_select: (CS0, CS1, CS2),
|
pub(crate) spi: SPI,
|
||||||
|
pub(crate) chip_select: (CS0, CS1, CS2),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<SPI, CS0, CS1, CS2> CPLD<SPI, CS0, CS1, CS2> where
|
#[derive(Debug)]
|
||||||
SPI: Transfer<u8>,
|
pub struct CPLD<SPI, CS0, CS1, CS2> {
|
||||||
|
pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SelectChip {
|
||||||
|
type Error;
|
||||||
|
fn select_chip(&mut self, channel: u8) -> Result<(), Self::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SPI, CS0, CS1, CS2, E> SelectChip for CPLDData<SPI, CS0, CS1, CS2>
|
||||||
|
where
|
||||||
|
SPI: Transfer<u8, Error = E>,
|
||||||
CS0: OutputPin,
|
CS0: OutputPin,
|
||||||
CS1: OutputPin,
|
CS1: OutputPin,
|
||||||
CS2: OutputPin,
|
CS2: OutputPin,
|
||||||
{
|
{
|
||||||
|
type Error = Error<E>;
|
||||||
|
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<SPI, CS0, CS1, CS2> {
|
||||||
|
fn do_on_get_ref_mut_data<R, E>(
|
||||||
|
&mut self,
|
||||||
|
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2>>) -> Result<R, Error<E>>,
|
||||||
|
) -> Result<R, Error<E>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<SPI, CS0, CS1, CS2> DoOnGetRefMutData<SPI, CS0, CS1, CS2> for CPLD<SPI, CS0, CS1, CS2> {
|
||||||
|
fn do_on_get_ref_mut_data<R, E>(
|
||||||
|
&mut self,
|
||||||
|
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2>>) -> 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, E> Transfer<u8> for CPLD<SPI, CS0, CS1, CS2>
|
||||||
|
where
|
||||||
|
SPI: Transfer<u8, Error = E>,
|
||||||
|
CS0: OutputPin,
|
||||||
|
CS1: OutputPin,
|
||||||
|
CS2: OutputPin,
|
||||||
|
{
|
||||||
|
type Error = Error<E>;
|
||||||
|
|
||||||
|
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<SPI, CS0, CS1, CS2, E> CPLD<SPI, CS0, CS1, CS2> where
|
||||||
|
SPI: Transfer<u8, Error = E>,
|
||||||
|
CS0: OutputPin,
|
||||||
|
CS1: OutputPin,
|
||||||
|
CS2: OutputPin,
|
||||||
|
{
|
||||||
// Constructor for CPLD
|
// Constructor for CPLD
|
||||||
pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2)) -> Self {
|
pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2)) -> Self {
|
||||||
|
|
||||||
// Init CS to be 0
|
// Init data
|
||||||
let mut obj = Self{spi, chip_select};
|
let data = CPLDData {
|
||||||
obj.select_chip(0);
|
spi,
|
||||||
return obj
|
chip_select,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Init CPLD
|
||||||
|
CPLD {
|
||||||
|
data: cell::RefCell::new(data),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Select chip
|
// Destroy the wrapper, return the CPLD data
|
||||||
pub fn select_chip(&mut self, channel: u8) {
|
pub fn destroy(self) -> (SPI, (CS0, CS1, CS2)) {
|
||||||
match channel & (1 << 0) {
|
let cpld = self.data.into_inner();
|
||||||
0 => self.chip_select.0.set_low(),
|
(cpld.spi, cpld.chip_select)
|
||||||
_ => 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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the SPI and CS pins
|
// Split SPI into chips, wrapped by Parts struct
|
||||||
pub fn release(self) -> (SPI, (CS0, CS1, CS2)) {
|
pub fn split<'a>(&'a self) -> Parts<'a, CPLD<SPI, CS0, CS1, CS2>, SPI, CS0, CS1, CS2> {
|
||||||
return (self.spi, self.chip_select);
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
mod cpld;
|
||||||
|
pub use cpld::{CPLD, Error};
|
||||||
|
|
||||||
|
mod spi_slave;
|
||||||
|
pub use spi_slave::{SPISlave, Parts};
|
|
@ -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<u8> for SPISlave<'a, DEV, SPI, CS0, CS1, CS2>
|
||||||
|
where
|
||||||
|
CS2: OutputPin,
|
||||||
|
CS1: OutputPin,
|
||||||
|
CS0: OutputPin,
|
||||||
|
DEV: DoOnGetRefMutData<SPI, CS0, CS1, CS2>,
|
||||||
|
SPI: Transfer<u8, Error = E>,
|
||||||
|
{
|
||||||
|
type Error = Error<E>;
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue