cpld: auto invoke io update

This commit is contained in:
occheung 2020-08-24 17:03:44 +08:00
parent 9ec5698f63
commit 29abca72cd
3 changed files with 195 additions and 59 deletions

View File

@ -30,20 +30,22 @@ pub enum Error<E> {
CSError, CSError,
GetRefMutDataError, GetRefMutDataError,
AttenuatorError, AttenuatorError,
IOUpdateError,
} }
/* /*
* Basic structure for CPLD signal multiplexing * Basic structure for CPLD signal multiplexing
*/ */
#[derive(Debug)] #[derive(Debug)]
pub struct CPLDData<SPI, CS0, CS1, CS2> { pub struct CPLDData<SPI, CS0, CS1, CS2, GPIO> {
pub(crate) spi: SPI, pub(crate) spi: SPI,
pub(crate) chip_select: (CS0, CS1, CS2), pub(crate) chip_select: (CS0, CS1, CS2),
pub(crate) io_update: GPIO,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct CPLD<SPI, CS0, CS1, CS2> { pub struct CPLD<SPI, CS0, CS1, CS2, GPIO> {
pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2>>, pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2, GPIO>>,
} }
pub trait SelectChip { pub trait SelectChip {
@ -51,12 +53,13 @@ pub trait SelectChip {
fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error>; fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error>;
} }
impl<SPI, CS0, CS1, CS2, E> SelectChip for CPLDData<SPI, CS0, CS1, CS2> 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,
CS1: OutputPin, CS1: OutputPin,
CS2: OutputPin, CS2: OutputPin,
GPIO: OutputPin,
{ {
type Error = Error<E>; type Error = Error<E>;
fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error> { fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error> {
@ -77,17 +80,38 @@ where
} }
} }
pub trait DoOnGetRefMutData<SPI, CS0, CS1, CS2> { trait IssueIOUpdate {
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_low().map_err(|_| Error::IOUpdateError)
}
}
pub trait DoOnGetRefMutData<SPI, CS0, CS1, CS2, GPIO> {
fn do_on_get_ref_mut_data<R, E>( fn do_on_get_ref_mut_data<R, E>(
&self, &self,
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2>>) -> Result<R, Error<E>>, f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2, GPIO>>) -> Result<R, Error<E>>,
) -> Result<R, Error<E>>; ) -> Result<R, Error<E>>;
} }
impl<SPI, CS0, CS1, CS2> DoOnGetRefMutData<SPI, CS0, CS1, CS2> for CPLD<SPI, CS0, CS1, CS2> { 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>( fn do_on_get_ref_mut_data<R, E>(
&self, &self,
f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2>>) -> Result<R, Error<E>>, f: impl FnOnce(cell::RefMut<CPLDData<SPI, CS0, CS1, CS2, GPIO>>) -> Result<R, Error<E>>,
) -> Result<R, Error<E>> { ) -> Result<R, Error<E>> {
let dev = self let dev = self
.data .data
@ -97,12 +121,13 @@ impl<SPI, CS0, CS1, CS2> DoOnGetRefMutData<SPI, CS0, CS1, CS2> for CPLD<SPI, CS0
} }
} }
impl<SPI, CS0, CS1, CS2, E> Transfer<u8> for CPLD<SPI, CS0, CS1, CS2> 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>,
CS0: OutputPin, CS0: OutputPin,
CS1: OutputPin, CS1: OutputPin,
CS2: OutputPin, CS2: OutputPin,
GPIO: OutputPin,
{ {
type Error = Error<E>; type Error = Error<E>;
@ -111,19 +136,21 @@ where
} }
} }
impl<SPI, CS0, CS1, CS2, E> CPLD<SPI, CS0, CS1, CS2> where impl<SPI, CS0, CS1, CS2, GPIO, E> CPLD<SPI, CS0, CS1, CS2, GPIO> where
SPI: Transfer<u8, Error = E>, SPI: Transfer<u8, Error = E>,
CS0: OutputPin, CS0: OutputPin,
CS1: OutputPin, CS1: OutputPin,
CS2: OutputPin, CS2: OutputPin,
GPIO: 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), io_update: GPIO) -> Self {
// Init data // Init data
let data = CPLDData { let data = CPLDData {
spi, spi,
chip_select, chip_select,
io_update,
}; };
// Init CPLD // Init CPLD
@ -133,13 +160,13 @@ impl<SPI, CS0, CS1, CS2, E> CPLD<SPI, CS0, CS1, CS2> where
} }
// Destroy the wrapper, return the CPLD data // Destroy the wrapper, return the CPLD data
pub fn destroy(self) -> (SPI, (CS0, CS1, CS2)) { pub fn destroy(self) -> (SPI, (CS0, CS1, CS2), GPIO) {
let cpld = self.data.into_inner(); let cpld = self.data.into_inner();
(cpld.spi, cpld.chip_select) (cpld.spi, cpld.chip_select, cpld.io_update)
} }
// 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>, SPI, CS0, CS1, CS2> { pub fn split<'a>(&'a self) -> Parts<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO> {
Parts::new(&self) Parts::new(&self)
} }
@ -148,3 +175,18 @@ impl<SPI, CS0, CS1, CS2, E> CPLD<SPI, CS0, CS1, CS2> where
self.do_on_get_ref_mut_data(|mut dev| dev.select_chip(channel)) 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

@ -75,7 +75,7 @@ fn main() -> ! {
let miso = gpioa.pa6.into_alternate_af5(); let miso = gpioa.pa6.into_alternate_af5();
let (mut cs0, mut cs1, mut cs2) = ( let (cs0, cs1, cs2) = (
gpiob.pb12.into_push_pull_output(), gpiob.pb12.into_push_pull_output(),
gpioa.pa15.into_push_pull_output(), gpioa.pa15.into_push_pull_output(),
gpioc.pc7.into_push_pull_output(), gpioc.pc7.into_push_pull_output(),
@ -84,37 +84,83 @@ fn main() -> ! {
/* /*
* I/O_Update -> PB13 * I/O_Update -> PB13
*/ */
// TODO: Incoporate io_update into DDS
let mut io_update = gpiob.pb15.into_push_pull_output(); let mut io_update = gpiob.pb15.into_push_pull_output();
let mut spi = dp.SPI1.spi( let spi = dp.SPI1.spi(
(sclk, miso, mosi), (sclk, miso, mosi),
spi::MODE_0, spi::MODE_0,
3.mhz(), 3.mhz(),
ccdr.peripheral.SPI1, ccdr.peripheral.SPI1,
&ccdr.clocks, &ccdr.clocks,
); );
// debug led
let mut yellow = gpioe.pe1.into_push_pull_output();
yellow.set_high().unwrap();
/* let mut switch = CPLD::new(spi, (cs0, cs1, cs2), io_update);
let mut switch = CPLD::new(spi, (cs0, cs1, cs2));
let parts = switch.split(); let parts = switch.split();
let mut config = ConfigRegister::new(parts.spi1); let mut config = ConfigRegister::new(parts.spi1);
let mut att = Attenuator::new(parts.spi2); let mut att = Attenuator::new(parts.spi2);
let mut dds0 = DDS::new(parts.spi4); let mut dds0 = DDS::new(parts.spi4);
loop { // Reset all DDS, set CLK_SEL to 0
let mut counter = config.get_status(StatusMask::RF_SW).unwrap(); config.set_configurations(&mut [
hprintln!("{}", counter); (CFGMask::RST, 1),
config.set_configurations(&mut [ (CFGMask::IO_RST, 1),
(CFGMask::RF_SW, ((counter + 1)%16) as u32) (CFGMask::IO_UPDATE, 0)
]).unwrap(); ]).unwrap();
}
*/
config.set_configurations(&mut [
(CFGMask::IO_RST, 0),
(CFGMask::RST, 0),
(CFGMask::RF_SW, 1)
]).unwrap();
dds0.write_register(0x00, &mut[
0x00, 0x00, 0x00, 0x02
]).unwrap();
// io_update.set_high().unwrap();
// io_update.set_low().unwrap();
// switch.issue_io_update();
dds0.write_register(0x02, &mut[
0x01F, 0x3F, 0xC0, 0x00
]).unwrap();
// io_update.set_high().unwrap();
// io_update.set_low().unwrap();
// switch.issue_io_update();
hprintln!("{:#X?}", dds0.read_register(0x00, &mut[
0x00, 0x00, 0x00, 0x00
]).unwrap()).unwrap();
// Calculate FTW
let f_out = 10_000_000;
let f_sclk = 100_000_000;
let resolution :u64 = 1 << 32;
let ftw = (resolution * f_out / f_sclk) as u32;
hprintln!("{}", ftw);
// Read single-tone profile 0
let mut profile :[u8; 8] = [0; 8];
dds0.read_register(0x0E, &mut profile).unwrap();
// Overwrite FTW on profile
profile[4] = ((ftw >> 24) & 0xFF) as u8;
profile[5] = ((ftw >> 16) & 0xFF) as u8;
profile[6] = ((ftw >> 8 ) & 0xFF) as u8;
profile[7] = ((ftw >> 0 ) & 0xFF) as u8;
dds0.write_register(0x0E, &mut profile).unwrap();
// io_update.set_high().unwrap();
// io_update.set_low().unwrap();
// switch.issue_io_update();
hprintln!("{:#X?}", dds0.read_register(0x0E, &mut profile).unwrap()).unwrap();
/*
cs0.set_low().unwrap(); cs0.set_low().unwrap();
cs1.set_low().unwrap(); cs1.set_low().unwrap();
cs2.set_low().unwrap(); cs2.set_low().unwrap();
@ -139,29 +185,72 @@ fn main() -> ! {
cs0.set_low().unwrap(); cs0.set_low().unwrap();
// Release reset, control I/O Update through EEM // Release reset, control I/O Update through EEM
// Relay clock signal from internal OSC (CLK_SEL = 0)
// Enable Switch 0
cs0.set_high().unwrap(); cs0.set_high().unwrap();
spi.transfer(&mut [ spi.transfer(&mut [
0x00, 0x00, 0x0A 0x00, 0x00, 0x01
]).unwrap(); ]).unwrap();
cs0.set_low().unwrap(); cs0.set_low().unwrap();
cs0.set_low().unwrap(); cs0.set_low().unwrap();
cs1.set_low().unwrap(); cs1.set_low().unwrap();
cs2.set_high().unwrap(); cs2.set_high().unwrap();
hprintln!("{:?}", spi.transfer(&mut [ // Configure SDIO to be input only, enable 3-wires communication
spi.transfer(&mut [
0x00, 0x00, 0x00, 0x00, 0x02 0x00, 0x00, 0x00, 0x00, 0x02
]).unwrap()).unwrap(); ]).unwrap();
// IO Update after every SPI transfer
io_update.set_high().unwrap();
delay.delay_ms(1_u16);
io_update.set_low().unwrap();
// Bypass PLL, bypass divisor
spi.transfer(&mut [
0x02, 0x1F, 0x3F, 0xC0, 0x00
]).unwrap();
io_update.set_high().unwrap(); io_update.set_high().unwrap();
delay.delay_ms(1_u16); delay.delay_ms(1_u16);
io_update.set_low().unwrap(); io_update.set_low().unwrap();
hprintln!("{:?}", spi.transfer(&mut [ hprintln!("{:#X?}", spi.transfer(&mut [
0x80, 0x00, 0x00, 0x00, 0x00 0x82, 0x00, 0x00, 0x00, 0x00
]).unwrap()).unwrap(); ]).unwrap()).unwrap();
let f_out = 10_000_000.0;
let f_sclk = 100_000_000.0;
let resolution :u64 = 1 << 32;
let ftw = ((resolution as f32) * f_out / f_sclk) as u32;
hprintln!("{:#X}", ftw);
// Read profile 0
let mut profile_arr_0 :[u8; 9] = [0; 9];
profile_arr_0[0] = 0x8E;
hprintln!("{:#X?}", spi.transfer(&mut profile_arr_0).unwrap()).unwrap();
// Write FTW to profile 0
profile_arr_0[0] = 0x0E;
profile_arr_0[5] = ((ftw >> 24) & 0xFF) as u8;
profile_arr_0[6] = ((ftw >> 16) & 0xFF) as u8;
profile_arr_0[7] = ((ftw >> 8 ) & 0xFF) as u8;
profile_arr_0[8] = ((ftw >> 0 ) & 0xFF) as u8;
hprintln!("{:#X?}", profile_arr_0).unwrap();
spi.transfer(&mut profile_arr_0).unwrap();
// Update after write
io_update.set_high().unwrap();
delay.delay_ms(1_u16);
io_update.set_low().unwrap();
// Read profile again, new value should be present
profile_arr_0[0] = 0x8E;
hprintln!("{:#X?}", spi.transfer(&mut profile_arr_0).unwrap()).unwrap();
*/
loop {} loop {}
} }

View File

@ -4,45 +4,47 @@ use embedded_hal::{
}; };
use core::marker::PhantomData; use core::marker::PhantomData;
use crate::{DoOnGetRefMutData, Error, SelectChip}; use crate::{DoOnGetRefMutData, Error, SelectChip, IssueIOUpdate};
pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2> ( pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> (
&'a DEV, &'a DEV,
u8, u8, // Channel of SPI slave
PhantomData<(SPI, CS0, CS1, CS2)>, bool, // Need I/O Update
PhantomData<(SPI, CS0, CS1, CS2, GPIO)>,
); );
pub struct Parts<'a, DEV: 'a, SPI, CS0, CS1, CS2> { pub struct Parts<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> {
pub spi1: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi1: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi2: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi2: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi3: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi3: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi4: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi4: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi5: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi5: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi6: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi6: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
pub spi7: SPISlave<'a, DEV, SPI, CS0, CS1, CS2>, pub spi7: SPISlave<'a, DEV, SPI, CS0, CS1, CS2, GPIO>,
} }
impl<'a, DEV, SPI, CS0, CS1, CS2> Parts<'a, DEV, SPI, CS0, CS1, CS2> { impl<'a, DEV, SPI, CS0, CS1, CS2, GPIO> Parts<'a, DEV, SPI, CS0, CS1, CS2, GPIO> {
pub(crate) fn new(cpld: &'a DEV) -> Self { pub(crate) fn new(cpld: &'a DEV) -> Self {
Parts { Parts {
spi1: SPISlave(&cpld, 1, PhantomData), spi1: SPISlave(&cpld, 1, false, PhantomData),
spi2: SPISlave(&cpld, 2, PhantomData), spi2: SPISlave(&cpld, 2, false, PhantomData),
spi3: SPISlave(&cpld, 3, PhantomData), spi3: SPISlave(&cpld, 3, true, PhantomData),
spi4: SPISlave(&cpld, 4, PhantomData), spi4: SPISlave(&cpld, 4, true, PhantomData),
spi5: SPISlave(&cpld, 5, PhantomData), spi5: SPISlave(&cpld, 5, true, PhantomData),
spi6: SPISlave(&cpld, 6, PhantomData), spi6: SPISlave(&cpld, 6, true, PhantomData),
spi7: SPISlave(&cpld, 7, PhantomData), spi7: SPISlave(&cpld, 7, true, PhantomData),
} }
} }
} }
impl<'a, DEV, SPI, CS0, CS1, CS2, E> Transfer<u8> for SPISlave<'a, DEV, SPI, CS0, CS1, CS2> impl<'a, DEV, SPI, CS0, CS1, CS2, GPIO, E> Transfer<u8> for SPISlave<'a, DEV, 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>, DEV: DoOnGetRefMutData<SPI, CS0, CS1, CS2, GPIO>,
SPI: Transfer<u8, Error = E>, SPI: Transfer<u8, Error = E>,
GPIO: OutputPin,
{ {
type Error = Error<E>; type Error = Error<E>;
@ -51,6 +53,9 @@ where
dev.select_chip(self.1); dev.select_chip(self.1);
let result = dev.spi.transfer(words).map_err(Error::SPI); let result = dev.spi.transfer(words).map_err(Error::SPI);
dev.select_chip(0); dev.select_chip(0);
if self.2 {
dev.issue_io_update();
}
result result
}) })
} }