Compare commits
5 Commits
0816220065
...
d78f85721f
Author | SHA1 | Date |
---|---|---|
occheung | d78f85721f | |
occheung | b0272a6fc2 | |
occheung | 49594dfb3b | |
occheung | 69761c4517 | |
occheung | 4852fc54ea |
|
@ -15,7 +15,6 @@ stm32h7xx-hal = {version = "0.6.0", features = [ "stm32h743v", "rt", "unproven"
|
||||||
stm32h7-ethernet = { version = "0.2.0", features = [ "phy_lan8742a", "stm32h743v" ] }
|
stm32h7-ethernet = { version = "0.2.0", features = [ "phy_lan8742a", "stm32h743v" ] }
|
||||||
smoltcp = { version = "0.6.0", default-features = false, features = [ "ethernet", "proto-ipv4", "proto-ipv6", "socket-raw" ] }
|
smoltcp = { version = "0.6.0", default-features = false, features = [ "ethernet", "proto-ipv4", "proto-ipv6", "socket-raw" ] }
|
||||||
nb = "1.0.0"
|
nb = "1.0.0"
|
||||||
# scpi = {path = "../scpi-rs/scpi", version = "0.3.4"}
|
|
||||||
scpi = { git = "https://github.com/occheung/scpi-rs", branch = "issue-4" }
|
scpi = { git = "https://github.com/occheung/scpi-rs", branch = "issue-4" }
|
||||||
lexical-core = { version="0.7.1", features=["radix"], default-features=false }
|
lexical-core = { version="0.7.1", features=["radix"], default-features=false }
|
||||||
libm = { version = "0.2.0" }
|
libm = { version = "0.2.0" }
|
||||||
|
|
|
@ -24,9 +24,12 @@ extern crate smoltcp;
|
||||||
extern crate stm32h7_ethernet as ethernet;
|
extern crate stm32h7_ethernet as ethernet;
|
||||||
|
|
||||||
use stm32h7xx_hal::gpio::Speed;
|
use stm32h7xx_hal::gpio::Speed;
|
||||||
use stm32h7xx_hal::hal::digital::v2::OutputPin;
|
use stm32h7xx_hal::hal::digital::v2::{
|
||||||
|
OutputPin,
|
||||||
|
InputPin,
|
||||||
|
};
|
||||||
use stm32h7xx_hal::rcc::CoreClocks;
|
use stm32h7xx_hal::rcc::CoreClocks;
|
||||||
use stm32h7xx_hal::{pac, prelude::*, stm32, stm32::interrupt};
|
use stm32h7xx_hal::{pac, prelude::*, spi, stm32, stm32::interrupt};
|
||||||
use Speed::*;
|
use Speed::*;
|
||||||
|
|
||||||
use libm::round;
|
use libm::round;
|
||||||
|
@ -55,7 +58,24 @@ use smoltcp::socket::SocketSet;
|
||||||
use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer};
|
use smoltcp::socket::{SocketHandle, TcpSocket, TcpSocketBuffer};
|
||||||
use smoltcp::time::{Duration, Instant};
|
use smoltcp::time::{Duration, Instant};
|
||||||
|
|
||||||
use firmware::scpi::{MyDevice, TREE};
|
use firmware;
|
||||||
|
use firmware::{
|
||||||
|
attenuator::Attenuator,
|
||||||
|
config_register::{
|
||||||
|
ConfigRegister,
|
||||||
|
CFGMask,
|
||||||
|
StatusMask,
|
||||||
|
},
|
||||||
|
dds::{
|
||||||
|
DDS,
|
||||||
|
DDSCFRMask,
|
||||||
|
},
|
||||||
|
cpld::{
|
||||||
|
CPLD,
|
||||||
|
},
|
||||||
|
scpi::TREE,
|
||||||
|
Urukul,
|
||||||
|
};
|
||||||
use scpi::prelude::*;
|
use scpi::prelude::*;
|
||||||
|
|
||||||
/// Configure SYSTICK for 1ms timebase
|
/// Configure SYSTICK for 1ms timebase
|
||||||
|
@ -111,6 +131,7 @@ fn main() -> ! {
|
||||||
.sys_ck(200.mhz())
|
.sys_ck(200.mhz())
|
||||||
.hclk(200.mhz())
|
.hclk(200.mhz())
|
||||||
.pll1_r_ck(100.mhz()) // for TRACECK
|
.pll1_r_ck(100.mhz()) // for TRACECK
|
||||||
|
.pll1_q_ck(48.mhz())
|
||||||
.freeze(vos, &dp.SYSCFG);
|
.freeze(vos, &dp.SYSCFG);
|
||||||
|
|
||||||
// Get the delay provider.
|
// Get the delay provider.
|
||||||
|
@ -127,14 +148,65 @@ fn main() -> ! {
|
||||||
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
|
let gpioa = dp.GPIOA.split(ccdr.peripheral.GPIOA);
|
||||||
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
|
let gpiob = dp.GPIOB.split(ccdr.peripheral.GPIOB);
|
||||||
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
|
let gpioc = dp.GPIOC.split(ccdr.peripheral.GPIOC);
|
||||||
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
|
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
|
||||||
|
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
|
||||||
|
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
|
||||||
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
|
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
|
||||||
let mut link_led = gpiob.pb0.into_push_pull_output(); // LED1, green
|
// let mut link_led = gpiob.pb0.into_push_pull_output(); // LED1, green
|
||||||
let mut status_led = gpioe.pe1.into_push_pull_output(); // LD2, yellow
|
// let mut status_led = gpioe.pe1.into_push_pull_output(); // LD2, yellow
|
||||||
let mut listen_led = gpiob.pb14.into_push_pull_output(); // LD3, red
|
// let mut listen_led = gpiob.pb14.into_push_pull_output(); // LD3, red
|
||||||
link_led.set_low().ok();
|
// link_led.set_low().ok();
|
||||||
status_led.set_low().ok();
|
// status_led.set_low().ok();
|
||||||
listen_led.set_low().ok();
|
// listen_led.set_low().ok();
|
||||||
|
|
||||||
|
// Setup CDONE for checking
|
||||||
|
let fpga_cdone = gpiod.pd15.into_pull_up_input();
|
||||||
|
|
||||||
|
match fpga_cdone.is_high() {
|
||||||
|
Ok(true) => hprintln!("FPGA is ready."),
|
||||||
|
Ok(_) => hprintln!("FPGA is in reset state."),
|
||||||
|
Err(_) => hprintln!("Error: Cannot read C_DONE"),
|
||||||
|
}.unwrap();
|
||||||
|
|
||||||
|
// Setup Urukul
|
||||||
|
/*
|
||||||
|
* Using SPI1, AF5
|
||||||
|
* SCLK -> PA5
|
||||||
|
* MOSI -> PB5
|
||||||
|
* MISO -> PA6
|
||||||
|
* CS -> 0: PB12, 1: PA15, 2: PC7
|
||||||
|
*/
|
||||||
|
|
||||||
|
let sclk = gpioa.pa5.into_alternate_af5();
|
||||||
|
let mosi = gpiob.pb5.into_alternate_af5();
|
||||||
|
let miso = gpioa.pa6.into_alternate_af5();
|
||||||
|
|
||||||
|
|
||||||
|
let (cs0, cs1, cs2) = (
|
||||||
|
gpiob.pb12.into_push_pull_output(),
|
||||||
|
gpioa.pa15.into_push_pull_output(),
|
||||||
|
gpioc.pc7.into_push_pull_output(),
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* I/O_Update -> PB15
|
||||||
|
*/
|
||||||
|
let io_update = gpiob.pb15.into_push_pull_output();
|
||||||
|
|
||||||
|
let spi = dp.SPI1.spi(
|
||||||
|
(sclk, miso, mosi),
|
||||||
|
spi::MODE_0,
|
||||||
|
3.mhz(),
|
||||||
|
ccdr.peripheral.SPI1,
|
||||||
|
&ccdr.clocks,
|
||||||
|
);
|
||||||
|
|
||||||
|
let switch = CPLD::new(spi, (cs0, cs1, cs2), io_update);
|
||||||
|
let parts = switch.split();
|
||||||
|
let mut urukul = Urukul::new(
|
||||||
|
parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7,
|
||||||
|
[25_000_000, 25_000_000, 25_000_000, 25_000_000]
|
||||||
|
);
|
||||||
|
|
||||||
// Setup ethernet pins
|
// Setup ethernet pins
|
||||||
setup_ethernet_pins(
|
setup_ethernet_pins(
|
||||||
|
@ -192,18 +264,17 @@ fn main() -> ! {
|
||||||
.finalize();
|
.finalize();
|
||||||
|
|
||||||
// SCPI configs
|
// SCPI configs
|
||||||
let mut my_device = MyDevice {};
|
// Device was declared in prior
|
||||||
|
|
||||||
let mut errors = ArrayErrorQueue::<[Error; 10]>::new();
|
let mut errors = ArrayErrorQueue::<[Error; 10]>::new();
|
||||||
let mut context = Context::new(&mut my_device, &mut errors, TREE);
|
let mut context = Context::new(&mut urukul, &mut errors, TREE);
|
||||||
|
|
||||||
//Response bytebuffer
|
//Response bytebuffer
|
||||||
let mut buf = ArrayVecFormatter::<[u8; 256]>::new();
|
let mut buf = ArrayVecFormatter::<[u8; 256]>::new();
|
||||||
|
|
||||||
// SCPI configs END
|
// SCPI configs END
|
||||||
|
|
||||||
// TODO: Need Iinitialize TCP socket storage?
|
// TCP socket buffers
|
||||||
// Yes cannot into vectors
|
|
||||||
let mut rx_storage = [0; BUFFER_SIZE];
|
let mut rx_storage = [0; BUFFER_SIZE];
|
||||||
let mut tx_storage = [0; BUFFER_SIZE];
|
let mut tx_storage = [0; BUFFER_SIZE];
|
||||||
|
|
||||||
|
@ -242,11 +313,9 @@ fn main() -> ! {
|
||||||
match iface.poll(&mut sockets, Instant::from_millis(_time as i64)) {
|
match iface.poll(&mut sockets, Instant::from_millis(_time as i64)) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
eth_up = true;
|
eth_up = true;
|
||||||
link_led.set_high().unwrap();
|
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eth_up = false;
|
eth_up = false;
|
||||||
link_led.set_low().unwrap();
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -258,16 +327,6 @@ fn main() -> ! {
|
||||||
socket.set_timeout(Some(Duration::from_millis(5000)));
|
socket.set_timeout(Some(Duration::from_millis(5000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
match socket.is_listening() {
|
|
||||||
false => listen_led.set_low().unwrap(),
|
|
||||||
_ => listen_led.set_high().unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
match socket.is_active() {
|
|
||||||
true => status_led.set_high().unwrap(),
|
|
||||||
_ => status_led.set_low().unwrap(),
|
|
||||||
};
|
|
||||||
|
|
||||||
if socket.can_recv() && receive_and_not_send {
|
if socket.can_recv() && receive_and_not_send {
|
||||||
let data = socket.recv(|buffer| {
|
let data = socket.recv(|buffer| {
|
||||||
(buffer.len(), buffer)
|
(buffer.len(), buffer)
|
||||||
|
@ -293,11 +352,7 @@ fn main() -> ! {
|
||||||
socket.set_timeout(Some(Duration::from_millis(1000000)));
|
socket.set_timeout(Some(Duration::from_millis(1000000)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if socket.can_recv() {
|
if socket.can_recv() {
|
||||||
// hprintln!("{:?}", socket.recv(|buffer| {
|
|
||||||
// (buffer.len(), str::from_utf8(buffer).unwrap())
|
|
||||||
// })).unwrap();
|
|
||||||
let result = context.run(socket.recv(|buffer| {
|
let result = context.run(socket.recv(|buffer| {
|
||||||
(buffer.len(), buffer)
|
(buffer.len(), buffer)
|
||||||
}).unwrap(), &mut buf);
|
}).unwrap(), &mut buf);
|
||||||
|
@ -305,7 +360,6 @@ fn main() -> ! {
|
||||||
writeln!(socket, "{}", str::from_utf8(err.get_message()).unwrap());
|
writeln!(socket, "{}", str::from_utf8(err.get_message()).unwrap());
|
||||||
} else {
|
} else {
|
||||||
write!(socket, "{}", str::from_utf8(buf.as_slice()).unwrap());
|
write!(socket, "{}", str::from_utf8(buf.as_slice()).unwrap());
|
||||||
//break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
use crate::Error;
|
||||||
|
use crate::spi_slave::Parts;
|
||||||
|
|
||||||
|
use embedded_hal::{
|
||||||
|
digital::v2::OutputPin,
|
||||||
|
blocking::spi::Transfer,
|
||||||
|
};
|
||||||
|
|
||||||
|
use core::cell;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Basic structure for CPLD signal multiplexing
|
||||||
|
*/
|
||||||
|
#[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>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait SelectChip {
|
||||||
|
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
|
||||||
|
SPI: Transfer<u8, Error = E>,
|
||||||
|
CS0: OutputPin,
|
||||||
|
CS1: OutputPin,
|
||||||
|
CS2: OutputPin,
|
||||||
|
GPIO: 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 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>(
|
||||||
|
&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>
|
||||||
|
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> {
|
||||||
|
self.do_on_get_ref_mut_data(move |mut dev| dev.spi.transfer(words).map_err(Error::SPI))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
pub fn split<'a>(&'a self) -> Parts<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO> {
|
||||||
|
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())
|
||||||
|
}
|
||||||
|
}
|
238
src/lib.rs
238
src/lib.rs
|
@ -4,9 +4,10 @@ use embedded_hal::{
|
||||||
digital::v2::OutputPin,
|
digital::v2::OutputPin,
|
||||||
blocking::spi::Transfer,
|
blocking::spi::Transfer,
|
||||||
};
|
};
|
||||||
|
use core::{
|
||||||
use core::cell;
|
cell,
|
||||||
|
marker::PhantomData,
|
||||||
|
};
|
||||||
use cortex_m;
|
use cortex_m;
|
||||||
use cortex_m_semihosting::hprintln;
|
use cortex_m_semihosting::hprintln;
|
||||||
|
|
||||||
|
@ -14,11 +15,24 @@ use cortex_m_semihosting::hprintln;
|
||||||
pub mod bitmask_macro;
|
pub mod bitmask_macro;
|
||||||
|
|
||||||
pub mod spi_slave;
|
pub mod spi_slave;
|
||||||
use crate::spi_slave::Parts;
|
use crate::spi_slave::{
|
||||||
|
Parts,
|
||||||
|
SPISlave,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub mod cpld;
|
||||||
|
use crate::cpld::CPLD;
|
||||||
|
use crate::cpld::DoOnGetRefMutData;
|
||||||
|
|
||||||
pub mod config_register;
|
pub mod config_register;
|
||||||
|
use crate::config_register::ConfigRegister;
|
||||||
|
|
||||||
pub mod attenuator;
|
pub mod attenuator;
|
||||||
|
use crate::attenuator::Attenuator;
|
||||||
|
|
||||||
pub mod dds;
|
pub mod dds;
|
||||||
|
use crate::dds::DDS;
|
||||||
|
|
||||||
pub mod scpi;
|
pub mod scpi;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -35,158 +49,86 @@ pub enum Error<E> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Basic structure for CPLD signal multiplexing
|
* Struct for Urukul master device
|
||||||
*/
|
*/
|
||||||
#[derive(Debug)]
|
pub struct Urukul<SPI> {
|
||||||
pub struct CPLDData<SPI, CS0, CS1, CS2, GPIO> {
|
config_register: ConfigRegister<SPI>,
|
||||||
pub(crate) spi: SPI,
|
attenuator: Attenuator<SPI>,
|
||||||
pub(crate) chip_select: (CS0, CS1, CS2),
|
dds: [DDS<SPI>; 4],
|
||||||
pub(crate) io_update: GPIO,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
impl<SPI, E> Urukul<SPI>
|
||||||
pub struct CPLD<SPI, CS0, CS1, CS2, GPIO> {
|
|
||||||
pub(crate) data: cell::RefCell<CPLDData<SPI, CS0, CS1, CS2, GPIO>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait SelectChip {
|
|
||||||
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,
|
|
||||||
CS1: OutputPin,
|
|
||||||
CS2: OutputPin,
|
|
||||||
GPIO: OutputPin,
|
|
||||||
{
|
{
|
||||||
type Error = Error<E>;
|
/*
|
||||||
fn select_chip(&mut self, chip: u8) -> Result<(), Self::Error> {
|
* Master constructor for the entire Urukul device
|
||||||
match chip & (1 << 0) {
|
* Supply 7 SPI channels to Urukul and 4 reference clock frequencies
|
||||||
0 => self.chip_select.0.set_low(),
|
*/
|
||||||
_ => self.chip_select.0.set_high(),
|
pub fn new(spi1: SPI, spi2: SPI, spi3: SPI, spi4: SPI, spi5: SPI, spi6: SPI, spi7: SPI, f_ref_clks: [u64; 4]) -> Self {
|
||||||
}.map_err(|_| Error::CSError)?;
|
// Construct Urukul
|
||||||
match chip & (1 << 1) {
|
Urukul {
|
||||||
0 => self.chip_select.1.set_low(),
|
config_register: ConfigRegister::new(spi1),
|
||||||
_ => self.chip_select.1.set_high(),
|
attenuator: Attenuator::new(spi2),
|
||||||
}.map_err(|_| Error::CSError)?;
|
dds: [
|
||||||
match chip & (1 << 2) {
|
DDS::new(spi4, f_ref_clks[1]),
|
||||||
0 => self.chip_select.2.set_low(),
|
DDS::new(spi5, f_ref_clks[1]),
|
||||||
_ => self.chip_select.2.set_high(),
|
DDS::new(spi6, f_ref_clks[2]),
|
||||||
}.map_err(|_| Error::CSError)?;
|
DDS::new(spi7, f_ref_clks[3]),
|
||||||
Ok(())
|
],
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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>(
|
|
||||||
&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>
|
|
||||||
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> {
|
|
||||||
self.do_on_get_ref_mut_data(move |mut dev| dev.spi.transfer(words).map_err(Error::SPI))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
pub fn split<'a>(&'a self) -> Parts<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO> {
|
|
||||||
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
|
// * Struct for a better Urukul master device
|
||||||
SPI: Transfer<u8>,
|
// */
|
||||||
CS0: OutputPin,
|
// pub struct BetterUrukul<'a, SPI, CS0, CS1, CS2, GPIO> {
|
||||||
CS1: OutputPin,
|
// cpld: CPLD<SPI, CS0, CS1, CS2, GPIO>,
|
||||||
CS2: OutputPin,
|
// parts: Option<Parts<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO>>,
|
||||||
GPIO: OutputPin<Error = E>
|
// config_register: Option<ConfigRegister<SPISlave<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO>>>,
|
||||||
{
|
// attenuator: Option<Attenuator<SPISlave<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO>>>,
|
||||||
// Issue I/O Update
|
// dds: [Option<DDS<SPISlave<'a, CPLD<SPI, CS0, CS1, CS2, GPIO>, SPI, CS0, CS1, CS2, GPIO>>>; 4],
|
||||||
pub fn issue_io_update(&mut self) -> Result<(), Error<E>> {
|
// }
|
||||||
self.do_on_get_ref_mut_data(|mut dev| dev.issue_io_update())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// impl<'a, SPI, CS0, CS1, CS2, GPIO> BetterUrukul<'a, SPI, CS0, CS1, CS2, GPIO>
|
||||||
|
// where
|
||||||
|
// SPI: Transfer<u8>,
|
||||||
|
// CS0: OutputPin,
|
||||||
|
// CS1: OutputPin,
|
||||||
|
// CS2: OutputPin,
|
||||||
|
// GPIO: OutputPin,
|
||||||
|
// {
|
||||||
|
// pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2), io_update: GPIO) -> Self {
|
||||||
|
// // let switch = CPLD::new(spi, chip_select, io_update);
|
||||||
|
// // let parts = switch.split();
|
||||||
|
|
||||||
|
// // Construct Urukul
|
||||||
|
// BetterUrukul {
|
||||||
|
// cpld: CPLD::new(spi, chip_select, io_update),
|
||||||
|
// // parts: CPLD::new(spi, chip_select, io_update).split(),
|
||||||
|
// // config_register: ConfigRegister::new(self.parts.spi1),
|
||||||
|
// // attenuator: Attenuator::new(self.parts.spi2),
|
||||||
|
// // dds: [
|
||||||
|
// // DDS::new(self.parts.spi4, f_ref_clks[1]),
|
||||||
|
// // DDS::new(self.parts.spi5, f_ref_clks[1]),
|
||||||
|
// // DDS::new(self.parts.spi6, f_ref_clks[2]),
|
||||||
|
// // DDS::new(self.parts.spi7, f_ref_clks[3]),
|
||||||
|
// // ],
|
||||||
|
// parts: None,
|
||||||
|
// config_register: None,
|
||||||
|
// attenuator: None,
|
||||||
|
// dds: [None, None, None, None],
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// pub fn init(&'a mut self, f_ref_clks:[u64; 4]) {
|
||||||
|
// self.parts = Some(self.cpld.split());
|
||||||
|
// self.config_register = Some(ConfigRegister::new(self.parts.unwrap().spi1));
|
||||||
|
// self.attenuator = Some(Attenuator::new(self.parts.unwrap().spi2));
|
||||||
|
// self.dds[0] = Some(DDS::new(self.parts.unwrap().spi4, f_ref_clks[0]));
|
||||||
|
// self.dds[1] = Some(DDS::new(self.parts.unwrap().spi5, f_ref_clks[1]));
|
||||||
|
// self.dds[2] = Some(DDS::new(self.parts.unwrap().spi6, f_ref_clks[2]));
|
||||||
|
// self.dds[3] = Some(DDS::new(self.parts.unwrap().spi7, f_ref_clks[3]));
|
||||||
|
// }
|
||||||
|
// }
|
|
@ -15,7 +15,6 @@ use cortex_m_semihosting::hprintln;
|
||||||
|
|
||||||
use firmware;
|
use firmware;
|
||||||
use firmware::{
|
use firmware::{
|
||||||
CPLD,
|
|
||||||
attenuator::Attenuator,
|
attenuator::Attenuator,
|
||||||
config_register::{
|
config_register::{
|
||||||
ConfigRegister,
|
ConfigRegister,
|
||||||
|
@ -26,6 +25,9 @@ use firmware::{
|
||||||
DDS,
|
DDS,
|
||||||
DDSCFRMask,
|
DDSCFRMask,
|
||||||
},
|
},
|
||||||
|
cpld::{
|
||||||
|
CPLD,
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#[entry]
|
#[entry]
|
||||||
|
@ -81,7 +83,7 @@ fn main() -> ! {
|
||||||
);
|
);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I/O_Update -> PB13
|
* I/O_Update -> PB15
|
||||||
*/
|
*/
|
||||||
let io_update = gpiob.pb15.into_push_pull_output();
|
let io_update = gpiob.pb15.into_push_pull_output();
|
||||||
|
|
||||||
|
|
10
src/scpi.rs
10
src/scpi.rs
|
@ -28,7 +28,9 @@ use scpi::{
|
||||||
scpi_tree,
|
scpi_tree,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct MyDevice;
|
use crate::Urukul;
|
||||||
|
|
||||||
|
// pub struct MyDevice;
|
||||||
|
|
||||||
pub struct HelloWorldCommand {}
|
pub struct HelloWorldCommand {}
|
||||||
impl Command for HelloWorldCommand {
|
impl Command for HelloWorldCommand {
|
||||||
|
@ -44,7 +46,11 @@ impl Command for HelloWorldCommand {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Device for MyDevice {
|
/*
|
||||||
|
* Implement "Device" trait from SCPI
|
||||||
|
* TODO: Implement mandatory commands
|
||||||
|
*/
|
||||||
|
impl<SPI> Device for Urukul<SPI> {
|
||||||
fn cls(&mut self) -> Result<()> {
|
fn cls(&mut self) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,8 @@ use embedded_hal::{
|
||||||
};
|
};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
|
|
||||||
use crate::{DoOnGetRefMutData, Error, SelectChip, IssueIOUpdate};
|
use crate::cpld::{DoOnGetRefMutData, SelectChip, IssueIOUpdate};
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> (
|
pub struct SPISlave<'a, DEV: 'a, SPI, CS0, CS1, CS2, GPIO> (
|
||||||
&'a DEV,
|
&'a DEV,
|
||||||
|
|
Loading…
Reference in New Issue