#![no_std] extern crate embedded_hal; use embedded_hal::{ digital::v2::OutputPin, blocking::spi::Transfer, }; use core::{ cell, marker::PhantomData, }; use cortex_m; use cortex_m_semihosting::hprintln; #[macro_use] pub mod bitmask_macro; pub mod spi_slave; use crate::spi_slave::{ Parts, SPISlave, }; pub mod cpld; use crate::cpld::CPLD; use crate::cpld::DoOnGetRefMutData; pub mod config_register; use crate::config_register::ConfigRegister; use crate::config_register::CFGMask; pub mod attenuator; use crate::attenuator::Attenuator; pub mod dds; use crate::dds::DDS; pub mod scpi; /* * Enum for structuring error */ #[derive(Debug)] pub enum Error { SPI(E), CSError, GetRefMutDataError, AttenuatorError, IOUpdateError, DDSError, ConfigRegisterError, DDSCLKError, } /* * Struct for Urukul master device */ pub struct Urukul { config_register: ConfigRegister, attenuator: Attenuator, dds: [DDS; 4], } impl Urukul where SPI: Transfer, { /* * Master constructor for the entire Urukul device * Supply 7 SPI channels to Urukul and 4 reference clock frequencies */ pub fn new(spi1: SPI, spi2: SPI, spi3: SPI, spi4: SPI, spi5: SPI, spi6: SPI, spi7: SPI, f_ref_clks: [u64; 4]) -> Self { // Construct Urukul Urukul { config_register: ConfigRegister::new(spi1), attenuator: Attenuator::new(spi2), dds: [ DDS::new(spi4, f_ref_clks[1]), DDS::new(spi5, f_ref_clks[1]), DDS::new(spi6, f_ref_clks[2]), DDS::new(spi7, f_ref_clks[3]), ], } } /* * Reset method. To be invoked by initialization and manual reset. * Only Urukul struct provides reset method. * DDS reset is controlled by Urukul (RST). * Attenuators only have shift register reset, which does not affect its data * CPLD only has a "all-zero" default state. */ pub fn reset(&mut self) -> Result<(), Error> { // Reset DDS and attenuators self.config_register.set_configurations(&mut [ (CFGMask::RST, 1), (CFGMask::IO_RST, 1), (CFGMask::IO_UPDATE, 0) ])?; // Set 0 to all fields on configuration register. self.config_register.set_configurations(&mut [ (CFGMask::RF_SW, 0), (CFGMask::LED, 0), (CFGMask::PROFILE, 0), (CFGMask::IO_UPDATE, 0), (CFGMask::MASK_NU, 0), (CFGMask::CLK_SEL0, 0), (CFGMask::SYNC_SEL, 0), (CFGMask::RST, 0), (CFGMask::IO_RST, 0), (CFGMask::CLK_SEL1, 0), (CFGMask::DIV, 0), ])?; // Init all DDS chips. Configure SDIO as input only. for chip_no in 0..4 { self.dds[chip_no].init()?; } // Clock tree reset. CPLD divides clock frequency by 4 by default. for chip_no in 0..4 { self.dds[chip_no].set_ref_clk_frequency(25_000_000); } Ok(()) } } // /* // * Struct for a better Urukul master device // */ // pub struct BetterUrukul<'a, SPI, CS0, CS1, CS2, GPIO> { // cpld: CPLD, // parts: Option, SPI, CS0, CS1, CS2, GPIO>>, // config_register: Option, SPI, CS0, CS1, CS2, GPIO>>>, // attenuator: Option, SPI, CS0, CS1, CS2, GPIO>>>, // dds: [Option, SPI, CS0, CS1, CS2, GPIO>>>; 4], // } // impl<'a, SPI, CS0, CS1, CS2, GPIO> BetterUrukul<'a, SPI, CS0, CS1, CS2, GPIO> // where // SPI: Transfer, // 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])); // } // }