Apply rustfmt

master
Etienne Wodey 2024-04-24 15:59:30 +02:00
parent 65e280670a
commit 713545535e
15 changed files with 1243 additions and 1160 deletions

View File

@ -2,9 +2,9 @@ use std::process::Command;
fn main() { fn main() {
Command::new("python3") Command::new("python3")
.arg("fpga/fpga_config.py") .arg("fpga/fpga_config.py")
.spawn() .spawn()
.expect("FPGA bitstream file cannot be built!"); .expect("FPGA bitstream file cannot be built!");
println!("cargo:rerun-if-changed=fpga/fpga_config.py") println!("cargo:rerun-if-changed=fpga/fpga_config.py")
} }

View File

@ -3,4 +3,4 @@ channel = "nightly-2020-10-30"
targets = [ targets = [
"thumbv7em-none-eabihf", "thumbv7em-none-eabihf",
] ]
profile = "minimal" profile = "default"

View File

@ -1,5 +1,5 @@
use embedded_hal::blocking::spi::Transfer;
use core::assert; use core::assert;
use embedded_hal::blocking::spi::Transfer;
use crate::urukul::Error; use crate::urukul::Error;
@ -10,7 +10,7 @@ pub struct Attenuator<SPI> {
impl<SPI, E> Attenuator<SPI> impl<SPI, E> Attenuator<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
pub fn new(spi: SPI) -> Self { pub fn new(spi: SPI) -> Self {
Attenuator { Attenuator {
@ -36,16 +36,21 @@ where
// Set data as attenuation * 2 // Set data as attenuation * 2
// Flip data using bitwise XOR, active low data // Flip data using bitwise XOR, active low data
// Data is most signifant attenuator first // Data is most signifant attenuator first
self.data[3-i] = (((atten * 2.0) as u8) ^ 0xFF) << 2 self.data[3 - i] = (((atten * 2.0) as u8) ^ 0xFF) << 2
} }
let mut clone = self.data.clone(); let mut clone = self.data.clone();
// Transmit SPI once to set attenuation // Transmit SPI once to set attenuation
self.spi.transfer(&mut clone) self.spi
.map(|_| ()) .transfer(&mut clone)
.map_err(|_| Error::AttenuatorError) .map(|_| ())
.map_err(|_| Error::AttenuatorError)
} }
pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error<E>> { pub fn set_channel_attenuation(
&mut self,
channel: u8,
attenuation: f32,
) -> Result<(), Error<E>> {
assert!(channel < 4); assert!(channel < 4);
let mut arr: [f32; 4] = self.get_attenuation()?; let mut arr: [f32; 4] = self.get_attenuation()?;
arr[channel as usize] = attenuation; arr[channel as usize] = attenuation;
@ -64,12 +69,12 @@ where
let mut clone = self.data.clone(); let mut clone = self.data.clone();
match self.spi.transfer(&mut clone).map_err(Error::SPI) { match self.spi.transfer(&mut clone).map_err(Error::SPI) {
Ok(arr) => { Ok(arr) => {
let mut ret :[f32; 4] = [0.0; 4]; let mut ret: [f32; 4] = [0.0; 4];
for index in 0..4 { for index in 0..4 {
ret[index] = ((arr[3 - index] ^ 0xFC) as f32) / 8.0; ret[index] = ((arr[3 - index] ^ 0xFC) as f32) / 8.0;
} }
Ok(ret) Ok(ret)
}, }
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
@ -82,16 +87,14 @@ where
// Test attenuators by getting back the attenuation // Test attenuators by getting back the attenuation
let mut error_count = 0; let mut error_count = 0;
// Convert cached SPI data into attenuation floats // Convert cached SPI data into attenuation floats
let att_floats :[f32; 4] = [ let att_floats: [f32; 4] = [
((self.data[3] ^ 0xFC) as f32) / 8.0, ((self.data[3] ^ 0xFC) as f32) / 8.0,
((self.data[2] ^ 0xFC) as f32) / 8.0, ((self.data[2] ^ 0xFC) as f32) / 8.0,
((self.data[1] ^ 0xFC) as f32) / 8.0, ((self.data[1] ^ 0xFC) as f32) / 8.0,
((self.data[0] ^ 0xFC) as f32) / 8.0, ((self.data[0] ^ 0xFC) as f32) / 8.0,
]; ];
// Set the attenuation to an arbitrary value, then read the attenuation // Set the attenuation to an arbitrary value, then read the attenuation
self.set_attenuation([ self.set_attenuation([3.5, 9.5, 20.0, 28.5])?;
3.5, 9.5, 20.0, 28.5
])?;
match self.get_attenuation() { match self.get_attenuation() {
Ok(arr) => { Ok(arr) => {
if arr[0] != 3.5 { if arr[0] != 3.5 {
@ -106,7 +109,7 @@ where
if arr[3] != 28.5 { if arr[3] != 28.5 {
error_count += 1; error_count += 1;
} }
}, }
Err(_) => return Err(Error::AttenuatorError), Err(_) => return Err(Error::AttenuatorError),
}; };
self.set_attenuation(att_floats)?; self.set_attenuation(att_floats)?;
@ -116,7 +119,7 @@ where
impl<SPI, E> Transfer<u8> for Attenuator<SPI> impl<SPI, E> Transfer<u8> for Attenuator<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
type Error = Error<E>; type Error = Error<E>;

View File

@ -1,16 +1,16 @@
use smoltcp as net;
use net::wire::IpCidr;
use net::wire::EthernetAddress; use net::wire::EthernetAddress;
use net::wire::IpCidr;
use smoltcp as net;
use embedded_nal as nal; use embedded_nal as nal;
use nal::IpAddr; use nal::IpAddr;
use heapless::{ String, consts::* }; use heapless::{consts::*, String};
use serde::{ Serialize, Deserialize }; use serde::{Deserialize, Serialize};
use crate::urukul::ClockSource;
use crate::flash_store::FlashStore; use crate::flash_store::FlashStore;
use crate::urukul::ClockSource;
use core::str::FromStr; use core::str::FromStr;
@ -72,7 +72,7 @@ pub fn get_net_config(store: &mut FlashStore) -> NetConfig {
eth_addr: { eth_addr: {
match store.read_str("MAC").unwrap() { match store.read_str("MAC").unwrap() {
Some(mac) => EthernetAddress::from_str(mac).unwrap(), Some(mac) => EthernetAddress::from_str(mac).unwrap(),
None => EthernetAddress::from_str("AC:6F:7A:DE:D6:C8").unwrap() None => EthernetAddress::from_str("AC:6F:7A:DE:D6:C8").unwrap(),
} }
}, },
broker_ip: { broker_ip: {
@ -84,9 +84,9 @@ pub fn get_net_config(store: &mut FlashStore) -> NetConfig {
name: { name: {
match store.read_str("Name").unwrap() { match store.read_str("Name").unwrap() {
Some(name) => String::from(name), Some(name) => String::from(name),
None => String::from("HumpbackDDS") None => String::from("HumpbackDDS"),
} }
} },
}; };
log::info!("Net config: {:?}", net_config); log::info!("Net config: {:?}", net_config);
net_config net_config

View File

@ -1,6 +1,6 @@
use embedded_hal::blocking::spi::Transfer;
use crate::urukul::Error; use crate::urukul::Error;
use core::mem::size_of; use core::mem::size_of;
use embedded_hal::blocking::spi::Transfer;
// Bitmasks for CFG // Bitmasks for CFG
construct_bitmask!(CFGMask; u32; construct_bitmask!(CFGMask; u32;
@ -23,7 +23,7 @@ construct_bitmask!(StatusMask; u32;
SMP_ERR, 4, 4, SMP_ERR, 4, 4,
PLL_LOCK, 8, 4, PLL_LOCK, 8, 4,
IFC_MODE, 12, 4, IFC_MODE, 12, 4,
PROTO_KEY, 16, 7 PROTO_KEY, 16, 7
); );
pub struct ConfigRegister<SPI> { pub struct ConfigRegister<SPI> {
@ -33,13 +33,10 @@ pub struct ConfigRegister<SPI> {
impl<SPI, E> ConfigRegister<SPI> impl<SPI, E> ConfigRegister<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
pub fn new(spi: SPI) -> Self { pub fn new(spi: SPI) -> Self {
ConfigRegister { ConfigRegister { spi, data: 0 }
spi,
data: 0,
}
} }
/* /*
@ -47,16 +44,16 @@ where
* Return status * Return status
*/ */
fn set_all_configurations(&mut self) -> Result<u32, Error<E>> { fn set_all_configurations(&mut self) -> Result<u32, Error<E>> {
match self.spi.transfer(&mut [ match self
((self.data & 0x00FF0000) >> 16) as u8, .spi
((self.data & 0x0000FF00) >> 8) as u8, .transfer(&mut [
((self.data & 0x000000FF) >> 0) as u8, ((self.data & 0x00FF0000) >> 16) as u8,
]).map_err(Error::SPI) { ((self.data & 0x0000FF00) >> 8) as u8,
Ok(arr) => Ok( ((self.data & 0x000000FF) >> 0) as u8,
((arr[0] as u32) << 16) | ])
((arr[1] as u32) << 8) | .map_err(Error::SPI)
arr[2] as u32 {
), Ok(arr) => Ok(((arr[0] as u32) << 16) | ((arr[1] as u32) << 8) | arr[2] as u32),
Err(e) => Err(e), Err(e) => Err(e),
} }
} }
@ -64,8 +61,8 @@ where
/* /*
* Set configuration bits according to supplied configs * Set configuration bits according to supplied configs
* Return status * Return status
*/ */
pub fn set_configurations(&mut self, configs: &mut[(CFGMask, u32)]) -> Result<u32, Error<E>> { pub fn set_configurations(&mut self, configs: &mut [(CFGMask, u32)]) -> Result<u32, Error<E>> {
for config in configs.into_iter() { for config in configs.into_iter() {
config.0.set_data_by_arg(&mut self.data, config.1) config.0.set_data_by_arg(&mut self.data, config.1)
} }
@ -113,7 +110,7 @@ where
impl<SPI, E> Transfer<u8> for ConfigRegister<SPI> impl<SPI, E> Transfer<u8> for ConfigRegister<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
type Error = Error<E>; type Error = Error<E>;
@ -121,4 +118,3 @@ where
self.spi.transfer(words).map_err(Error::SPI) self.spi.transfer(words).map_err(Error::SPI)
} }
} }

View File

@ -1,10 +1,7 @@
use crate::urukul::Error;
use crate::spi_slave::Parts; use crate::spi_slave::Parts;
use crate::urukul::Error;
use embedded_hal::{ use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin};
digital::v2::OutputPin,
blocking::spi::Transfer,
};
use core::cell; use core::cell;
@ -35,20 +32,25 @@ where
match chip & (1 << 0) { match chip & (1 << 0) {
0 => self.chip_select.0.set_low(), 0 => self.chip_select.0.set_low(),
_ => self.chip_select.0.set_high(), _ => self.chip_select.0.set_high(),
}.map_err(|_| Error::CSError)?; }
.map_err(|_| Error::CSError)?;
match chip & (1 << 1) { match chip & (1 << 1) {
0 => self.chip_select.1.set_low(), 0 => self.chip_select.1.set_low(),
_ => self.chip_select.1.set_high(), _ => self.chip_select.1.set_high(),
}.map_err(|_| Error::CSError)?; }
.map_err(|_| Error::CSError)?;
match chip & (1 << 2) { match chip & (1 << 2) {
0 => self.chip_select.2.set_low(), 0 => self.chip_select.2.set_low(),
_ => self.chip_select.2.set_high(), _ => self.chip_select.2.set_high(),
}.map_err(|_| Error::CSError)?; }
.map_err(|_| Error::CSError)?;
Ok(()) Ok(())
} }
pub(crate) fn issue_io_update(&mut self) -> Result<(), Error<E>> { pub(crate) fn issue_io_update(&mut self) -> Result<(), Error<E>> {
self.io_update.set_high().map_err(|_| Error::IOUpdateError)?; self.io_update
.set_high()
.map_err(|_| Error::IOUpdateError)?;
// I/O Update minimum pulse width: 1 SYNC_CLK cycle // I/O Update minimum pulse width: 1 SYNC_CLK cycle
// 1 SYNC_CLK cycle = 4 REF_CLK cycle, where f_ref_clk is at least 3.2 MHz // 1 SYNC_CLK cycle = 4 REF_CLK cycle, where f_ref_clk is at least 3.2 MHz
// Therefore the maximum required pulse length is 1.25 us, // Therefore the maximum required pulse length is 1.25 us,
@ -69,20 +71,25 @@ where
type Error = Error<E>; type Error = Error<E>;
fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> { fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
self.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?.spi.transfer(words).map_err(Error::SPI) self.data
.try_borrow_mut()
.map_err(|_| Error::GetRefMutDataError)?
.spi
.transfer(words)
.map_err(Error::SPI)
} }
} }
impl<SPI, CS0, CS1, CS2, GPIO, E> CPLD<SPI, CS0, CS1, CS2, GPIO> 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 GPIO: OutputPin,
{ {
// Constructor for CPLD // Constructor for CPLD
pub fn new(spi: SPI, chip_select: (CS0, CS1, CS2), io_update: GPIO) -> 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,

View File

@ -1,9 +1,9 @@
use embedded_hal::blocking::spi::Transfer;
use crate::urukul::Error; use crate::urukul::Error;
use core::mem::size_of;
use core::convert::TryInto; use core::convert::TryInto;
use heapless::Vec; use core::mem::size_of;
use embedded_hal::blocking::spi::Transfer;
use heapless::consts::*; use heapless::consts::*;
use heapless::Vec;
use log::debug; use log::debug;
/* /*
@ -48,7 +48,7 @@ construct_bitmask!(DDSCFRMask; u32;
DIGITAL_RAMP_NO_DWELL_HIGH, 18 +32, 1, DIGITAL_RAMP_NO_DWELL_HIGH, 18 +32, 1,
DIGITAL_RAMP_ENABLE, 19 +32, 1, DIGITAL_RAMP_ENABLE, 19 +32, 1,
DIGITAL_RAMP_DEST, 20 +32, 2, DIGITAL_RAMP_DEST, 20 +32, 2,
SYNC_CLK_ENABLE, 22 +32, 1, SYNC_CLK_ENABLE, 22 +32, 1,
INT_IO_UPDATE_ACTIVE, 23 +32, 1, INT_IO_UPDATE_ACTIVE, 23 +32, 1,
EN_AMP_SCALE_SINGLE_TONE_PRO, 24 +32, 1, EN_AMP_SCALE_SINGLE_TONE_PRO, 24 +32, 1,
@ -63,8 +63,8 @@ construct_bitmask!(DDSCFRMask; u32;
DRV0, 28 +64, 2 DRV0, 28 +64, 2
); );
const WRITE_MASK :u8 = 0x00; const WRITE_MASK: u8 = 0x00;
const READ_MASK :u8 = 0x80; const READ_MASK: u8 = 0x80;
#[link_section = ".sram2.ram"] #[link_section = ".sram2.ram"]
static mut RAM_VEC: Vec<u8, U8192> = Vec(heapless::i::Vec::new()); static mut RAM_VEC: Vec<u8, U8192> = Vec(heapless::i::Vec::new());
@ -90,12 +90,12 @@ pub struct DDS<SPI> {
spi: SPI, spi: SPI,
f_ref_clk: f64, f_ref_clk: f64,
f_sys_clk: f64, f_sys_clk: f64,
ram_dest: RAMDestination ram_dest: RAMDestination,
} }
impl<SPI, E> DDS<SPI> impl<SPI, E> DDS<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
pub fn new(spi: SPI, f_ref_clk: f64) -> Self { pub fn new(spi: SPI, f_ref_clk: f64) -> Self {
DDS { DDS {
@ -109,7 +109,7 @@ where
impl<SPI, E> Transfer<u8> for DDS<SPI> impl<SPI, E> Transfer<u8> for DDS<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
type Error = Error<E>; type Error = Error<E>;
@ -118,18 +118,15 @@ where
} }
} }
impl<SPI, E> DDS<SPI> impl<SPI, E> DDS<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
/* /*
* Implement init: Set SDIO to be input only, using LSB first * Implement init: Set SDIO to be input only, using LSB first
*/ */
pub fn init(&mut self) -> Result<(), Error<E>> { pub fn init(&mut self) -> Result<(), Error<E>> {
match self.write_register(0x00, &mut [ match self.write_register(0x00, &mut [0x00, 0x00, 0x00, 0x02]) {
0x00, 0x00, 0x00, 0x02
]) {
Ok(_) => Ok(()), Ok(_) => Ok(()),
Err(e) => Err(e), Err(e) => Err(e),
} }
@ -182,9 +179,7 @@ where
// Reset PLL lock before re-enabling it // Reset PLL lock before re-enabling it
(DDSCFRMask::PFD_RESET, 1), (DDSCFRMask::PFD_RESET, 1),
])?; ])?;
self.set_configurations(&mut [ self.set_configurations(&mut [(DDSCFRMask::PFD_RESET, 0)])?;
(DDSCFRMask::PFD_RESET, 0),
])?;
self.f_sys_clk = self.f_ref_clk * (divider as f64); self.f_sys_clk = self.f_ref_clk * (divider as f64);
Ok(()) Ok(())
} }
@ -204,13 +199,13 @@ where
// Acquire N-divider, to adjust VCO if necessary // Acquire N-divider, to adjust VCO if necessary
(DDSCFRMask::N, 0), (DDSCFRMask::N, 0),
// Acquire REF_CLK divider bypass // Acquire REF_CLK divider bypass
(DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0) (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0),
]; ];
self.get_configurations(&mut configuration_queries)?; self.get_configurations(&mut configuration_queries)?;
if configuration_queries[0].1 == 1 { if configuration_queries[0].1 == 1 {
// Recalculate sys_clk // Recalculate sys_clk
let divider :f64 = configuration_queries[1].1.into(); let divider: f64 = configuration_queries[1].1.into();
let f_sys_clk = self.f_ref_clk * divider; let f_sys_clk = self.f_ref_clk * divider;
// Adjust VCO // Adjust VCO
match self.get_VCO_no(f_sys_clk, divider as u8) { match self.get_VCO_no(f_sys_clk, divider as u8) {
@ -221,24 +216,20 @@ where
// Reset PLL lock before re-enabling it // Reset PLL lock before re-enabling it
(DDSCFRMask::PFD_RESET, 1), (DDSCFRMask::PFD_RESET, 1),
])?; ])?;
self.set_configurations(&mut [ self.set_configurations(&mut [(DDSCFRMask::PFD_RESET, 0)])?;
(DDSCFRMask::PFD_RESET, 0),
])?;
// Update f_sys_clk from recalculation // Update f_sys_clk from recalculation
self.f_sys_clk = f_sys_clk; self.f_sys_clk = f_sys_clk;
Ok(()) Ok(())
}, }
Err(_) => { Err(_) => {
// Forcibly turn off PLL, enable default clk tree (divide by 2) // Forcibly turn off PLL, enable default clk tree (divide by 2)
self.enable_divided_ref_clk() self.enable_divided_ref_clk()
} }
} }
} } else if configuration_queries[2].1 == 0 {
else if configuration_queries[2].1 == 0 {
self.f_sys_clk = self.f_ref_clk / 2.0; self.f_sys_clk = self.f_ref_clk / 2.0;
Ok(()) Ok(())
} } else {
else {
self.f_sys_clk = self.f_ref_clk; self.f_sys_clk = self.f_ref_clk;
Ok(()) Ok(())
} }
@ -269,7 +260,7 @@ where
fn get_VCO_no(&mut self, f_sys_clk: f64, divider: u8) -> Result<u8, Error<E>> { fn get_VCO_no(&mut self, f_sys_clk: f64, divider: u8) -> Result<u8, Error<E>> {
// Select a VCO // Select a VCO
if divider == 1 { if divider == 1 {
Ok(6) // Bypass PLL if no frequency division needed Ok(6) // Bypass PLL if no frequency division needed
} else if f_sys_clk > 1_150_000_000.0 { } else if f_sys_clk > 1_150_000_000.0 {
Err(Error::DDSCLKError) Err(Error::DDSCLKError)
} else if f_sys_clk > 820_000_000.0 { } else if f_sys_clk > 820_000_000.0 {
@ -285,7 +276,7 @@ where
} else if f_sys_clk > 370_000_000.0 { } else if f_sys_clk > 370_000_000.0 {
Ok(0) Ok(0)
} else { } else {
Ok(7) // Bypass PLL if f_sys_clk is too low Ok(7) // Bypass PLL if f_sys_clk is too low
} }
} }
@ -300,16 +291,28 @@ where
self.read_register(0x01, &mut cfr_reg[4..8])?; self.read_register(0x01, &mut cfr_reg[4..8])?;
self.read_register(0x02, &mut cfr_reg[8..12])?; self.read_register(0x02, &mut cfr_reg[8..12])?;
Ok([ Ok([
(cfr_reg[0] as u32) << 24 | (cfr_reg[1] as u32) << 16 | (cfr_reg[2] as u32) << 8 | (cfr_reg[3] as u32), (cfr_reg[0] as u32) << 24
(cfr_reg[4] as u32) << 24 | (cfr_reg[5] as u32) << 16 | (cfr_reg[6] as u32) << 8 | (cfr_reg[7] as u32), | (cfr_reg[1] as u32) << 16
(cfr_reg[8] as u32) << 24 | (cfr_reg[9] as u32) << 16 | (cfr_reg[10] as u32) << 8 | (cfr_reg[11] as u32) | (cfr_reg[2] as u32) << 8
| (cfr_reg[3] as u32),
(cfr_reg[4] as u32) << 24
| (cfr_reg[5] as u32) << 16
| (cfr_reg[6] as u32) << 8
| (cfr_reg[7] as u32),
(cfr_reg[8] as u32) << 24
| (cfr_reg[9] as u32) << 16
| (cfr_reg[10] as u32) << 8
| (cfr_reg[11] as u32),
]) ])
} }
/* /*
* Get a set of configurations using DDSCFRMask * Get a set of configurations using DDSCFRMask
*/ */
pub fn get_configurations<'w>(&mut self, mask_pairs: &'w mut[(DDSCFRMask, u32)]) -> Result<&'w [(DDSCFRMask, u32)], Error<E>> { pub fn get_configurations<'w>(
&mut self,
mask_pairs: &'w mut [(DDSCFRMask, u32)],
) -> Result<&'w [(DDSCFRMask, u32)], Error<E>> {
let data_array = self.get_all_configurations()?; let data_array = self.get_all_configurations()?;
for index in 0..mask_pairs.len() { for index in 0..mask_pairs.len() {
mask_pairs[index].1 = match mask_pairs[index].0.get_shift() { mask_pairs[index].1 = match mask_pairs[index].0.get_shift() {
@ -327,12 +330,15 @@ where
*/ */
fn set_all_configurations(&mut self, data_array: [u32; 3]) -> Result<(), Error<E>> { fn set_all_configurations(&mut self, data_array: [u32; 3]) -> Result<(), Error<E>> {
for register in 0x00..=0x02 { for register in 0x00..=0x02 {
self.write_register(register, &mut [ self.write_register(
((data_array[register as usize] >> 24) & 0xFF) as u8, register,
((data_array[register as usize] >> 16) & 0xFF) as u8, &mut [
((data_array[register as usize] >> 8 ) & 0xFF) as u8, ((data_array[register as usize] >> 24) & 0xFF) as u8,
((data_array[register as usize] >> 0 ) & 0xFF) as u8 ((data_array[register as usize] >> 16) & 0xFF) as u8,
])?; ((data_array[register as usize] >> 8) & 0xFF) as u8,
((data_array[register as usize] >> 0) & 0xFF) as u8,
],
)?;
} }
Ok(()) Ok(())
} }
@ -340,17 +346,28 @@ where
/* /*
* Set a set of configurations using DDSCFRMask * Set a set of configurations using DDSCFRMask
*/ */
pub fn set_configurations(&mut self, mask_pairs: &mut[(DDSCFRMask, u32)]) -> Result<(), Error<E>> { pub fn set_configurations(
&mut self,
mask_pairs: &mut [(DDSCFRMask, u32)],
) -> Result<(), Error<E>> {
let mut data_array = self.get_all_configurations()?; let mut data_array = self.get_all_configurations()?;
for index in 0..mask_pairs.len() { for index in 0..mask_pairs.len() {
// Reject any attempt to rewrite LSB_FIRST and SDIO_INPUT_ONLY // Reject any attempt to rewrite LSB_FIRST and SDIO_INPUT_ONLY
if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST || mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY { if mask_pairs[index].0 == DDSCFRMask::LSB_FIRST
|| mask_pairs[index].0 == DDSCFRMask::SDIO_IN_ONLY
{
continue; continue;
} }
match mask_pairs[index].0.get_shift() { match mask_pairs[index].0.get_shift() {
0..=31 => mask_pairs[index].0.set_data_by_arg(&mut data_array[0], mask_pairs[index].1), 0..=31 => mask_pairs[index]
32..=63 => mask_pairs[index].0.set_data_by_arg(&mut data_array[1], mask_pairs[index].1), .0
64..=95 => mask_pairs[index].0.set_data_by_arg(&mut data_array[2], mask_pairs[index].1), .set_data_by_arg(&mut data_array[0], mask_pairs[index].1),
32..=63 => mask_pairs[index]
.0
.set_data_by_arg(&mut data_array[1], mask_pairs[index].1),
64..=95 => mask_pairs[index]
.0
.set_data_by_arg(&mut data_array[2], mask_pairs[index].1),
_ => panic!("Invalid DDSCFRMask!"), _ => panic!("Invalid DDSCFRMask!"),
}; };
} }
@ -366,12 +383,17 @@ where
* Frequency: Must be non-negative * Frequency: Must be non-negative
* Amplitude: In a scale from 0 to 1, taking float * Amplitude: In a scale from 0 to 1, taking float
*/ */
pub fn set_single_tone_profile(&mut self, profile: u8, f_out: f64, phase_offset: f64, amp_scale_factor: f64) -> Result<(), Error<E>> { pub fn set_single_tone_profile(
&mut self,
profile: u8,
f_out: f64,
phase_offset: f64,
amp_scale_factor: f64,
) -> Result<(), Error<E>> {
assert!(profile < 8); assert!(profile < 8);
assert!(f_out >= 0.0); assert!(f_out >= 0.0);
assert!(phase_offset >= 0.0 && phase_offset < 360.0); assert!(phase_offset >= 0.0 && phase_offset < 360.0);
assert!(amp_scale_factor >=0.0 && amp_scale_factor <= 1.0); assert!(amp_scale_factor >= 0.0 && amp_scale_factor <= 1.0);
let ftw = self.frequency_to_ftw(f_out); let ftw = self.frequency_to_ftw(f_out);
let pow = self.degree_to_pow(phase_offset); let pow = self.degree_to_pow(phase_offset);
@ -379,44 +401,44 @@ where
// Setup configuration registers before writing single tone register // Setup configuration registers before writing single tone register
self.enable_single_tone_configuration()?; self.enable_single_tone_configuration()?;
// Transfer single tone profile data // Transfer single tone profile data
self.write_register(0x0E + profile, &mut [ self.write_register(
((asf >> 8 ) & 0xFF) as u8, 0x0E + profile,
((asf >> 0 ) & 0xFF) as u8, &mut [
((pow >> 8 ) & 0xFF) as u8, ((asf >> 8) & 0xFF) as u8,
((pow >> 0 ) & 0xFF) as u8, ((asf >> 0) & 0xFF) as u8,
((ftw >> 24) & 0xFF) as u8, ((pow >> 8) & 0xFF) as u8,
((ftw >> 16) & 0xFF) as u8, ((pow >> 0) & 0xFF) as u8,
((ftw >> 8 ) & 0xFF) as u8, ((ftw >> 24) & 0xFF) as u8,
((ftw >> 0 ) & 0xFF) as u8, ((ftw >> 16) & 0xFF) as u8,
]) ((ftw >> 8) & 0xFF) as u8,
((ftw >> 0) & 0xFF) as u8,
],
)
} }
/* /*
* Getter function for single tone profiles * Getter function for single tone profiles
*/ */
pub fn get_single_tone_profile(&mut self, profile: u8) -> Result<(f64, f64, f64), Error<E>> { pub fn get_single_tone_profile(&mut self, profile: u8) -> Result<(f64, f64, f64), Error<E>> {
assert!(profile < 8); assert!(profile < 8);
let mut profile_content: [u8; 8] = [0; 8]; let mut profile_content: [u8; 8] = [0; 8];
self.read_register(0x0E + profile, &mut profile_content)?; self.read_register(0x0E + profile, &mut profile_content)?;
// Convert ftw, pow and asf to f_out, phase and amplitude factor // Convert ftw, pow and asf to f_out, phase and amplitude factor
let ftw: u64 = (profile_content[4] as u64) << 24 | let ftw: u64 = (profile_content[4] as u64) << 24
(profile_content[5] as u64) << 16 | | (profile_content[5] as u64) << 16
(profile_content[6] as u64) << 8 | | (profile_content[6] as u64) << 8
(profile_content[7] as u64); | (profile_content[7] as u64);
let f_out: f64 = ((ftw as f64)/(((1_u64) << 32) as f64))*self.f_sys_clk; let f_out: f64 = ((ftw as f64) / (((1_u64) << 32) as f64)) * self.f_sys_clk;
let pow: u64 = (profile_content[2] as u64) << 8 | let pow: u64 = (profile_content[2] as u64) << 8 | (profile_content[3] as u64);
(profile_content[3] as u64); let phase: f64 = ((pow as f64) / (((1_u64) << 16) as f64)) * 360.0;
let phase: f64 = ((pow as f64)/(((1_u64) << 16) as f64))*360.0;
let asf: u64 = ((profile_content[0] & 0x3F) as u64) << 8 | let asf: u64 = ((profile_content[0] & 0x3F) as u64) << 8 | (profile_content[1] as u64);
(profile_content[1] as u64); let amplitude: f64 = (asf as f64) / (((1_u64) << 14) as f64);
let amplitude: f64 = (asf as f64)/(((1_u64) << 14) as f64);
Ok((f_out, phase, amplitude)) Ok((f_out, phase, amplitude))
} }
@ -426,8 +448,11 @@ where
* Frequency: Must be non-negative * Frequency: Must be non-negative
* Keep other field unchanged in the register * Keep other field unchanged in the register
*/ */
pub fn set_single_tone_profile_frequency(&mut self, profile: u8, f_out: f64) -> Result<(), Error<E>> { pub fn set_single_tone_profile_frequency(
&mut self,
profile: u8,
f_out: f64,
) -> Result<(), Error<E>> {
// Setup configuration registers before writing single tone register // Setup configuration registers before writing single tone register
self.enable_single_tone_configuration()?; self.enable_single_tone_configuration()?;
@ -440,8 +465,8 @@ where
// Overwrite FTW // Overwrite FTW
register[4] = ((ftw >> 24) & 0xFF) as u8; register[4] = ((ftw >> 24) & 0xFF) as u8;
register[5] = ((ftw >> 16) & 0xFF) as u8; register[5] = ((ftw >> 16) & 0xFF) as u8;
register[6] = ((ftw >> 8) & 0xFF) as u8; register[6] = ((ftw >> 8) & 0xFF) as u8;
register[7] = ((ftw >> 0) & 0xFF) as u8; register[7] = ((ftw >> 0) & 0xFF) as u8;
// Update FTW by writing back the register // Update FTW by writing back the register
self.write_register(0x0E + profile, &mut register) self.write_register(0x0E + profile, &mut register)
@ -452,8 +477,11 @@ where
* Phase: Expressed in positive degree, i.e. [0.0, 360.0) * Phase: Expressed in positive degree, i.e. [0.0, 360.0)
* Keep other field unchanged in the register * Keep other field unchanged in the register
*/ */
pub fn set_single_tone_profile_phase(&mut self, profile: u8, phase_offset: f64) -> Result<(), Error<E>> { pub fn set_single_tone_profile_phase(
&mut self,
profile: u8,
phase_offset: f64,
) -> Result<(), Error<E>> {
// Setup configuration registers before writing single tone register // Setup configuration registers before writing single tone register
self.enable_single_tone_configuration()?; self.enable_single_tone_configuration()?;
@ -464,8 +492,8 @@ where
self.read_register(0x0E + profile, &mut register)?; self.read_register(0x0E + profile, &mut register)?;
// Overwrite POW // Overwrite POW
register[2] = ((pow >> 8) & 0xFF) as u8; register[2] = ((pow >> 8) & 0xFF) as u8;
register[3] = ((pow >> 0) & 0xFF) as u8; register[3] = ((pow >> 0) & 0xFF) as u8;
// Update POW by writing back the register // Update POW by writing back the register
self.write_register(0x0E + profile, &mut register) self.write_register(0x0E + profile, &mut register)
@ -476,8 +504,11 @@ where
* Amplitude: In a scale from 0 to 1, taking float * Amplitude: In a scale from 0 to 1, taking float
* Keep other field unchanged in the register * Keep other field unchanged in the register
*/ */
pub fn set_single_tone_profile_amplitude(&mut self, profile: u8, amp_scale_factor: f64) -> Result<(), Error<E>> { pub fn set_single_tone_profile_amplitude(
&mut self,
profile: u8,
amp_scale_factor: f64,
) -> Result<(), Error<E>> {
// Setup configuration registers before writing single tone register // Setup configuration registers before writing single tone register
self.enable_single_tone_configuration()?; self.enable_single_tone_configuration()?;
@ -489,8 +520,8 @@ where
self.read_register(0x0E + profile, &mut register)?; self.read_register(0x0E + profile, &mut register)?;
// Overwrite POW // Overwrite POW
register[0] = ((asf >> 8) & 0xFF) as u8; register[0] = ((asf >> 8) & 0xFF) as u8;
register[1] = ((asf >> 0) & 0xFF) as u8; register[1] = ((asf >> 0) & 0xFF) as u8;
// Update POW by writing back the register // Update POW by writing back the register
self.write_register(0x0E + profile, &mut register) self.write_register(0x0E + profile, &mut register)
@ -499,16 +530,13 @@ where
// Helper function to switch into single tone mode // Helper function to switch into single tone mode
// Need to setup configuration registers before writing single tone register // Need to setup configuration registers before writing single tone register
fn enable_single_tone_configuration(&mut self) -> Result<(), Error<E>> { fn enable_single_tone_configuration(&mut self) -> Result<(), Error<E>> {
self.set_configurations(&mut [ self.set_configurations(&mut [
(DDSCFRMask::RAM_ENABLE, 0), (DDSCFRMask::RAM_ENABLE, 0),
(DDSCFRMask::DIGITAL_RAMP_ENABLE, 0), (DDSCFRMask::DIGITAL_RAMP_ENABLE, 0),
(DDSCFRMask::OSK_ENABLE, 0), (DDSCFRMask::OSK_ENABLE, 0),
(DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0), (DDSCFRMask::PARALLEL_DATA_PORT_ENABLE, 0),
])?; ])?;
self.set_configurations(&mut [ self.set_configurations(&mut [(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1)])
(DDSCFRMask::EN_AMP_SCALE_SINGLE_TONE_PRO, 1),
])
} }
// Helper function to configure the default frequency in the FTW register (0x07) // Helper function to configure the default frequency in the FTW register (0x07)
@ -531,19 +559,18 @@ where
pub fn get_default_ftw(&mut self) -> Result<f64, Error<E>> { pub fn get_default_ftw(&mut self) -> Result<f64, Error<E>> {
let mut ftw_bytes: [u8; 4] = [0; 4]; let mut ftw_bytes: [u8; 4] = [0; 4];
self.read_register(0x07, &mut ftw_bytes)?; self.read_register(0x07, &mut ftw_bytes)?;
let ftw: u64 = (ftw_bytes[0] as u64) << 24 | let ftw: u64 = (ftw_bytes[0] as u64) << 24
(ftw_bytes[1] as u64) << 16 | | (ftw_bytes[1] as u64) << 16
(ftw_bytes[2] as u64) << 8 | | (ftw_bytes[2] as u64) << 8
(ftw_bytes[3] as u64); | (ftw_bytes[3] as u64);
Ok(((ftw as f64)/(((1_u64) << 32) as f64))*self.f_sys_clk) Ok(((ftw as f64) / (((1_u64) << 32) as f64)) * self.f_sys_clk)
} }
pub fn get_default_asf(&mut self) -> Result<f64, Error<E>> { pub fn get_default_asf(&mut self) -> Result<f64, Error<E>> {
let mut asf_register: [u8; 4] = [0; 4]; let mut asf_register: [u8; 4] = [0; 4];
self.read_register(0x09, &mut asf_register)?; self.read_register(0x09, &mut asf_register)?;
let asf: u64 = ((asf_register[2] as u64) << 6) | let asf: u64 = ((asf_register[2] as u64) << 6) | ((asf_register[3] as u64) >> 2);
((asf_register[3] as u64) >> 2); Ok((asf as f64) / (((1_u64) << 14) as f64))
Ok((asf as f64)/(((1_u64) << 14) as f64))
} }
// Helper function to switch into RAM mode // Helper function to switch into RAM mode
@ -558,38 +585,44 @@ where
// Helper function to switch out of RAM mode // Helper function to switch out of RAM mode
// Need to setup configuration registers before writing into RAM profile register // Need to setup configuration registers before writing into RAM profile register
fn disable_ram_configuration(&mut self) -> Result<(), Error<E>> { fn disable_ram_configuration(&mut self) -> Result<(), Error<E>> {
self.set_configurations(&mut [ self.set_configurations(&mut [(DDSCFRMask::RAM_ENABLE, 0)])
(DDSCFRMask::RAM_ENABLE, 0),
])
} }
// Setup a RAM profile // Setup a RAM profile
pub fn set_up_ram_profile(&mut self, profile: u8, start_addr: u16, pub fn set_up_ram_profile(
end_addr: u16, no_dwell_high: bool, zero_crossing: bool, &mut self,
op_mode: RAMOperationMode, ramp_rate: u16 profile: u8,
)-> Result<(), Error<E>> start_addr: u16,
{ end_addr: u16,
no_dwell_high: bool,
zero_crossing: bool,
op_mode: RAMOperationMode,
ramp_rate: u16,
) -> Result<(), Error<E>> {
assert!(profile <= 7); assert!(profile <= 7);
assert!(end_addr >= start_addr); assert!(end_addr >= start_addr);
assert!(end_addr < 1024); assert!(end_addr < 1024);
self.enable_ram_configuration(self.ram_dest)?; self.enable_ram_configuration(self.ram_dest)?;
self.write_register(0x0E + profile, &mut [ self.write_register(
0x00, 0x0E + profile,
((ramp_rate >> 8) & 0xFF).try_into().unwrap(), &mut [
((ramp_rate >> 0) & 0xFF).try_into().unwrap(), 0x00,
((end_addr >> 2) & 0xFF).try_into().unwrap(), ((ramp_rate >> 8) & 0xFF).try_into().unwrap(),
((end_addr & 0x3) << 6).try_into().unwrap(), ((ramp_rate >> 0) & 0xFF).try_into().unwrap(),
((start_addr >> 2) & 0xFF).try_into().unwrap(), ((end_addr >> 2) & 0xFF).try_into().unwrap(),
((start_addr & 0x3) << 6).try_into().unwrap(), ((end_addr & 0x3) << 6).try_into().unwrap(),
((no_dwell_high as u8) << 5) | ((zero_crossing as u8) << 3) | (op_mode as u8) ((start_addr >> 2) & 0xFF).try_into().unwrap(),
]) ((start_addr & 0x3) << 6).try_into().unwrap(),
((no_dwell_high as u8) << 5) | ((zero_crossing as u8) << 3) | (op_mode as u8),
],
)
} }
pub fn get_ram_profile(&mut self, profile: u8) -> Result<(u16, u16, u16, u8), Error<E>> { pub fn get_ram_profile(&mut self, profile: u8) -> Result<(u16, u16, u16, u8), Error<E>> {
assert!(profile <= 7); assert!(profile <= 7);
let mut buffer: [u8; 8] = [0; 8]; let mut buffer: [u8; 8] = [0; 8];
self.read_register(0x0E + profile, &mut buffer)?; self.read_register(0x0E + profile, &mut buffer)?;
let start = u16::from_be_bytes([buffer[5], buffer[6]]) >> 6; let start = u16::from_be_bytes([buffer[5], buffer[6]]) >> 6;
@ -627,29 +660,42 @@ where
// Write RAM bytes into DDS channel // Write RAM bytes into DDS channel
// Assume profile 7 is selected by the CPLD in prior // Assume profile 7 is selected by the CPLD in prior
pub unsafe fn commit_ram_buffer(&mut self, start_addr: u16, ram_dest: RAMDestination) -> Result<(), Error<E>> { pub unsafe fn commit_ram_buffer(
let ram_size = ((RAM_VEC.len() - 1) as u16)/4; &mut self,
if RAM_VEC.len() == 0 || RAM_VEC[0] != 0x16 || start_addr: u16,
(start_addr + ram_size) > 1024 || start_addr >= 1024 { ram_dest: RAMDestination,
return Err(Error::DDSRAMError) ) -> Result<(), Error<E>> {
let ram_size = ((RAM_VEC.len() - 1) as u16) / 4;
if RAM_VEC.len() == 0
|| RAM_VEC[0] != 0x16
|| (start_addr + ram_size) > 1024
|| start_addr >= 1024
{
return Err(Error::DDSRAMError);
} }
let end_addr: [u8; 2] = ((ram_size + start_addr - 1) << 6).to_be_bytes(); let end_addr: [u8; 2] = ((ram_size + start_addr - 1) << 6).to_be_bytes();
// Use profile 7 to setup a temperory RAM profile // Use profile 7 to setup a temperory RAM profile
self.enable_ram_configuration(ram_dest.clone())?; self.enable_ram_configuration(ram_dest.clone())?;
self.write_register(0x15, &mut [ self.write_register(
0x00, 0x15,
0x00, 0x01, &mut [
end_addr[0], end_addr[1], 0x00,
((start_addr >> 2) & 0xFF).try_into().unwrap(), 0x00,
((start_addr & 0x3) << 6).try_into().unwrap(), 0x01,
0x00 end_addr[0],
])?; end_addr[1],
((start_addr >> 2) & 0xFF).try_into().unwrap(),
((start_addr & 0x3) << 6).try_into().unwrap(),
0x00,
],
)?;
self.disable_ram_configuration()?; self.disable_ram_configuration()?;
log::info!("RAM buffer: {:?}", RAM_VEC); log::info!("RAM buffer: {:?}", RAM_VEC);
self.spi.transfer(&mut RAM_VEC) self.spi
.transfer(&mut RAM_VEC)
.map(|_| ()) .map(|_| ())
.map_err(Error::SPI)?; .map_err(Error::SPI)?;
RAM_VEC.clear(); RAM_VEC.clear();
@ -664,10 +710,7 @@ where
pub fn test(&mut self) -> Result<u32, Error<E>> { pub fn test(&mut self) -> Result<u32, Error<E>> {
// Test configuration register by getting SDIO_IN_ONLY and LSB_FIRST. // Test configuration register by getting SDIO_IN_ONLY and LSB_FIRST.
let mut error_count = 0; let mut error_count = 0;
let mut config_checks = [ let mut config_checks = [(DDSCFRMask::SDIO_IN_ONLY, 1), (DDSCFRMask::LSB_FIRST, 0)];
(DDSCFRMask::SDIO_IN_ONLY, 1),
(DDSCFRMask::LSB_FIRST, 0)
];
self.get_configurations(&mut config_checks)?; self.get_configurations(&mut config_checks)?;
if config_checks[0].1 == 0 { if config_checks[0].1 == 0 {
error_count += 1; error_count += 1;
@ -688,7 +731,7 @@ where
pub fn get_f_sys_clk(&mut self) -> f64 { pub fn get_f_sys_clk(&mut self) -> f64 {
self.f_sys_clk self.f_sys_clk
} }
// Acquire real f_sys_clk // Acquire real f_sys_clk
pub fn get_sys_clk_frequency(&mut self) -> Result<f64, Error<E>> { pub fn get_sys_clk_frequency(&mut self) -> Result<f64, Error<E>> {
// Calculate the new system clock frequency, examine the clock tree // Calculate the new system clock frequency, examine the clock tree
@ -698,19 +741,17 @@ where
// Acquire N-divider, to adjust VCO if necessary // Acquire N-divider, to adjust VCO if necessary
(DDSCFRMask::N, 0), (DDSCFRMask::N, 0),
// Acquire REF_CLK divider bypass // Acquire REF_CLK divider bypass
(DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0) (DDSCFRMask::REFCLK_IN_DIV_BYPASS, 0),
]; ];
self.get_configurations(&mut configuration_queries)?; self.get_configurations(&mut configuration_queries)?;
if configuration_queries[0].1 == 1 { if configuration_queries[0].1 == 1 {
// Recalculate sys_clk // Recalculate sys_clk
let divider :f64 = configuration_queries[1].1.into(); let divider: f64 = configuration_queries[1].1.into();
Ok(self.f_ref_clk * divider) Ok(self.f_ref_clk * divider)
} } else if configuration_queries[2].1 == 0 {
else if configuration_queries[2].1 == 0 {
Ok(self.f_ref_clk / 2.0) Ok(self.f_ref_clk / 2.0)
} } else {
else {
Ok(self.f_ref_clk) Ok(self.f_ref_clk)
} }
} }
@ -772,26 +813,8 @@ macro_rules! impl_register_io {
} }
impl_register_io!( impl_register_io!(
0x00, 4, 0x00, 4, 0x01, 4, 0x02, 4, 0x03, 4, 0x04, 4, 0x07, 4, 0x08, 2, 0x09, 4, 0x0A, 4, 0x0B, 8, 0x0C,
0x01, 4, 8, 0x0D, 4, 0x0E, 8, 0x0F, 8, 0x10, 8, 0x11, 8, 0x12, 8, 0x13, 8, 0x14, 8, 0x15, 8
0x02, 4,
0x03, 4,
0x04, 4,
0x07, 4,
0x08, 2,
0x09, 4,
0x0A, 4,
0x0B, 8,
0x0C, 8,
0x0D, 4,
0x0E, 8,
0x0F, 8,
0x10, 8,
0x11, 8,
0x12, 8,
0x13, 8,
0x14, 8,
0x15, 8
); );
// Append bytes to the RAM buffer // Append bytes to the RAM buffer

View File

@ -22,7 +22,7 @@ pub enum Error {
ErrorCorrectionCode, ErrorCorrectionCode,
ReadProtection, ReadProtection,
ReadSecure, ReadSecure,
WriteError WriteError,
} }
/// Embedded flash memory. /// Embedded flash memory.
@ -45,46 +45,58 @@ impl Flash {
// Unlock bank 1 if needed. // Unlock bank 1 if needed.
if self.bank1_is_locked() { if self.bank1_is_locked() {
self.registers.bank1_mut().keyr.write(|w| unsafe { self.registers
w.keyr().bits(0x45670123) .bank1_mut()
}); .keyr
self.registers.bank1_mut().keyr.write(|w| unsafe { .write(|w| unsafe { w.keyr().bits(0x45670123) });
w.keyr().bits(0xCDEF89AB) self.registers
}); .bank1_mut()
.keyr
.write(|w| unsafe { w.keyr().bits(0xCDEF89AB) });
} }
// Unlock bank 2 if needed. // Unlock bank 2 if needed.
if self.bank2_is_locked() { if self.bank2_is_locked() {
self.registers.bank2_mut().keyr.write(|w| unsafe { self.registers
w.keyr().bits(0x45670123) .bank2_mut()
}); .keyr
self.registers.bank2_mut().keyr.write(|w| unsafe { .write(|w| unsafe { w.keyr().bits(0x45670123) });
w.keyr().bits(0xCDEF89AB) self.registers
}); .bank2_mut()
.keyr
.write(|w| unsafe { w.keyr().bits(0xCDEF89AB) });
} }
} }
/// Unlocks the FLASH_OPTCR register /// Unlocks the FLASH_OPTCR register
pub fn unlock_optcr(&mut self) { pub fn unlock_optcr(&mut self) {
if self.optcr_is_locked() { if self.optcr_is_locked() {
self.registers.optkeyr_mut().write(|w| unsafe { self.registers
w.optkeyr().bits(0x08192A3B) .optkeyr_mut()
}); .write(|w| unsafe { w.optkeyr().bits(0x08192A3B) });
self.registers.optkeyr_mut().write(|w| unsafe { self.registers
w.optkeyr().bits(0x4C5D6E7F) .optkeyr_mut()
}); .write(|w| unsafe { w.optkeyr().bits(0x4C5D6E7F) });
} }
} }
/// Locks the FLASH_CR1/2 register. /// Locks the FLASH_CR1/2 register.
pub fn lock(&mut self) { pub fn lock(&mut self) {
self.registers.bank1_mut().cr.modify(|_, w| w.lock().set_bit()); self.registers
self.registers.bank2_mut().cr.modify(|_, w| w.lock().set_bit()); .bank1_mut()
.cr
.modify(|_, w| w.lock().set_bit());
self.registers
.bank2_mut()
.cr
.modify(|_, w| w.lock().set_bit());
} }
/// Lock the FLASH_OPTCR register /// Lock the FLASH_OPTCR register
pub fn lock_optcr(&mut self) { pub fn lock_optcr(&mut self) {
self.registers.optcr_mut().modify(|_, w| w.optlock().set_bit()); self.registers
.optcr_mut()
.modify(|_, w| w.optlock().set_bit());
} }
// More literal methods to get bank status // More literal methods to get bank status
@ -106,7 +118,7 @@ impl Flash {
fn is_busy(&self) -> bool { fn is_busy(&self) -> bool {
let (sr1, sr2) = ( let (sr1, sr2) = (
self.registers.bank1_mut().sr.read(), self.registers.bank1_mut().sr.read(),
self.registers.bank2_mut().sr.read() self.registers.bank2_mut().sr.read(),
); );
sr1.bsy().bit_is_set() || sr2.bsy().bit_is_set() sr1.bsy().bit_is_set() || sr2.bsy().bit_is_set()
} }
@ -115,7 +127,7 @@ impl Flash {
fn is_queuing(&self) -> bool { fn is_queuing(&self) -> bool {
let (sr1, sr2) = ( let (sr1, sr2) = (
self.registers.bank1_mut().sr.read(), self.registers.bank1_mut().sr.read(),
self.registers.bank2_mut().sr.read() self.registers.bank2_mut().sr.read(),
); );
sr1.qw().bit_is_set() || sr2.qw().bit_is_set() sr1.qw().bit_is_set() || sr2.qw().bit_is_set()
} }
@ -145,28 +157,26 @@ impl Flash {
// 4. Set START1/2 bit in FLASH_CR1/2 register // 4. Set START1/2 bit in FLASH_CR1/2 register
match bank_number { match bank_number {
1 => { 1 => {
self.registers.bank1_mut().cr.modify(|_, w| unsafe { self.registers
w.ser() .bank1_mut()
.set_bit() .cr
.snb() .modify(|_, w| unsafe { w.ser().set_bit().snb().bits(sector_number) });
.bits(sector_number) self.registers
}); .bank1_mut()
self.registers.bank1_mut().cr.modify(|_, w| { .cr
w.start().set_bit() .modify(|_, w| w.start().set_bit());
}); }
},
2 => { 2 => {
self.registers.bank2_mut().cr.modify(|_, w| unsafe { self.registers
w.ser() .bank2_mut()
.set_bit() .cr
.snb() .modify(|_, w| unsafe { w.ser().set_bit().snb().bits(sector_number) });
.bits(sector_number) self.registers
}); .bank2_mut()
self.registers.bank2_mut().cr.modify(|_, w| { .cr
w.start().set_bit() .modify(|_, w| w.start().set_bit());
}); }
}, _ => unreachable!(),
_ => unreachable!()
} }
// Lock the flash CR again // Lock the flash CR again
self.lock(); self.lock();
@ -187,24 +197,20 @@ impl Flash {
// mass erase is invoked since it supersedes sector erase. // mass erase is invoked since it supersedes sector erase.
match bank_number { match bank_number {
1 => { 1 => {
self.registers.bank1_mut().cr.modify(|_, w| { self.registers
w.ber() .bank1_mut()
.set_bit() .cr
.start() .modify(|_, w| w.ber().set_bit().start().set_bit());
.set_bit()
});
while self.registers.bank1_mut().sr.read().qw().bit_is_set() {} while self.registers.bank1_mut().sr.read().qw().bit_is_set() {}
}, }
2 => { 2 => {
self.registers.bank2_mut().cr.modify(|_, w| { self.registers
w.ber() .bank2_mut()
.set_bit() .cr
.start() .modify(|_, w| w.ber().set_bit().start().set_bit());
.set_bit()
});
while self.registers.bank2_mut().sr.read().qw().bit_is_set() {} while self.registers.bank2_mut().sr.read().qw().bit_is_set() {}
}, }
_ => unreachable!() _ => unreachable!(),
} }
// Lock the flash CR again // Lock the flash CR again
self.lock(); self.lock();
@ -219,9 +225,7 @@ impl Flash {
self.unlock(); self.unlock();
self.unlock_optcr(); self.unlock_optcr();
// 3. Set MER in FLASH_OPTCR to 1, wait until both QW to clear // 3. Set MER in FLASH_OPTCR to 1, wait until both QW to clear
self.registers.optcr_mut().modify(|_, w| { self.registers.optcr_mut().modify(|_, w| w.mer().set_bit());
w.mer().set_bit()
});
while self.is_queuing() {} while self.is_queuing() {}
// Lock the flash CR and OPTCR again // Lock the flash CR and OPTCR again
self.lock(); self.lock();
@ -231,11 +235,7 @@ impl Flash {
/// Program flash words (32-bytes). /// Program flash words (32-bytes).
/// Flashing incomplete flash word is "tolerated", but you have been warned.. /// Flashing incomplete flash word is "tolerated", but you have been warned..
pub fn program<'a, 'b>( pub fn program<'a, 'b>(&'a mut self, start_offset: usize, data: &'b [u8]) -> Result<(), Error> {
&'a mut self,
start_offset: usize,
data: &'b [u8],
) -> Result<(), Error> {
if (start_offset % 32 != 0) || (data.len() % 32 != 0) { if (start_offset % 32 != 0) || (data.len() % 32 != 0) {
log::warn!("Warning: This flash operation might not be supported..."); log::warn!("Warning: This flash operation might not be supported...");
log::warn!("Consider force writing the data in buffer..."); log::warn!("Consider force writing the data in buffer...");
@ -247,20 +247,19 @@ impl Flash {
while remaining_data.len() != 0 { while remaining_data.len() != 0 {
let single_write_size = 32 - (current_address % 32); let single_write_size = 32 - (current_address % 32);
// Determine the index that split the coming row and the remaining bytes. // Determine the index that split the coming row and the remaining bytes.
let splitting_index = core::cmp::min( let splitting_index = core::cmp::min(single_write_size, remaining_data.len());
single_write_size,
remaining_data.len()
);
let single_row_data = &remaining_data[..splitting_index]; let single_row_data = &remaining_data[..splitting_index];
// 1. Unlock FLASH_CR1/2 register if necessary // 1. Unlock FLASH_CR1/2 register if necessary
self.unlock(); self.unlock();
// 2. Set PG bit in FLASH_CR1/2 // 2. Set PG bit in FLASH_CR1/2
self.registers.bank1_mut().cr.modify(|_, w| { self.registers
w.pg().set_bit() .bank1_mut()
}); .cr
self.registers.bank2_mut().cr.modify(|_, w| { .modify(|_, w| w.pg().set_bit());
w.pg().set_bit() self.registers
}); .bank2_mut()
.cr
.modify(|_, w| w.pg().set_bit());
// 3. Check Protection // 3. Check Protection
// There should not be any data protection anyway... // There should not be any data protection anyway...
// 4. Write data byte by byte // 4. Write data byte by byte
@ -268,22 +267,32 @@ impl Flash {
while self.is_busy() {} while self.is_busy() {}
match self.check_errors() { match self.check_errors() {
Ok(_) => { Ok(_) => {
let address: *mut u8 = unsafe { let address: *mut u8 = unsafe { FLASH_BASE.add(current_address + index) };
FLASH_BASE.add(current_address + index)
};
if address > MAX_FLASH_ADDRESS { if address > MAX_FLASH_ADDRESS {
self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); self.registers
self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); .bank1_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
self.registers
.bank2_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
return Err(Error::WriteError); return Err(Error::WriteError);
} else { } else {
unsafe { unsafe {
core::ptr::write_volatile(address, *byte); core::ptr::write_volatile(address, *byte);
} }
} }
}, }
Err(error) => { Err(error) => {
self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); self.registers
self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); .bank1_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
self.registers
.bank2_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
return Err(error); return Err(error);
} }
} }
@ -295,8 +304,14 @@ impl Flash {
current_address += single_row_data.len(); current_address += single_row_data.len();
} }
// Reset PG1/2 // Reset PG1/2
self.registers.bank1_mut().cr.modify(|_, w| w.pg().clear_bit()); self.registers
self.registers.bank2_mut().cr.modify(|_, w| w.pg().clear_bit()); .bank1_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
self.registers
.bank2_mut()
.cr
.modify(|_, w| w.pg().clear_bit());
// Lock FLASH_CR1/2 register // Lock FLASH_CR1/2 register
self.lock(); self.lock();
Ok(()) Ok(())
@ -304,27 +319,25 @@ impl Flash {
/// Force empty the bytes buffer for flash programming /// Force empty the bytes buffer for flash programming
/// Warning: It can invalidate the whole flash due to invalid CRC. /// Warning: It can invalidate the whole flash due to invalid CRC.
pub fn force_write<'a>( pub fn force_write<'a>(&'a mut self) -> Result<(), Error> {
&'a mut self
) -> Result<(), Error> {
if self.bank1_is_buffering() { if self.bank1_is_buffering() {
self.registers.bank1_mut().cr.modify( self.registers
|_, w| w.fw().set_bit() .bank1_mut()
); .cr
.modify(|_, w| w.fw().set_bit());
} }
if self.bank2_is_buffering() { if self.bank2_is_buffering() {
self.registers.bank2_mut().cr.modify( self.registers
|_, w| w.fw().set_bit() .bank2_mut()
); .cr
.modify(|_, w| w.fw().set_bit());
} }
Ok(()) Ok(())
} }
/// Read a slice from flash memory /// Read a slice from flash memory
pub fn read(&self, start_offset: usize, len: usize) -> &'static [u8] { pub fn read(&self, start_offset: usize, len: usize) -> &'static [u8] {
let address = unsafe { let address = unsafe { FLASH_BASE.add(start_offset) };
FLASH_BASE.add(start_offset)
};
unsafe { core::slice::from_raw_parts(address, len) } unsafe { core::slice::from_raw_parts(address, len) }
} }
@ -337,7 +350,7 @@ impl Flash {
fn check_errors(&self) -> Result<(), Error> { fn check_errors(&self) -> Result<(), Error> {
let (sr1, sr2) = ( let (sr1, sr2) = (
self.registers.bank1_mut().sr.read(), self.registers.bank1_mut().sr.read(),
self.registers.bank2_mut().sr.read() self.registers.bank2_mut().sr.read(),
); );
if sr1.wrperr().bit_is_set() || sr2.wrperr().bit_is_set() { if sr1.wrperr().bit_is_set() || sr2.wrperr().bit_is_set() {
@ -350,8 +363,11 @@ impl Flash {
Err(Error::Inconsistency) Err(Error::Inconsistency)
} else if sr1.operr().bit_is_set() || sr2.operr().bit_is_set() { } else if sr1.operr().bit_is_set() || sr2.operr().bit_is_set() {
Err(Error::Operation) Err(Error::Operation)
} else if sr1.sneccerr1().bit_is_set() || sr1.dbeccerr().bit_is_set() } else if sr1.sneccerr1().bit_is_set()
|| sr2.sneccerr1().bit_is_set() || sr2.dbeccerr().bit_is_set() { || sr1.dbeccerr().bit_is_set()
|| sr2.sneccerr1().bit_is_set()
|| sr2.dbeccerr().bit_is_set()
{
Err(Error::ErrorCorrectionCode) Err(Error::ErrorCorrectionCode)
} else if sr1.rdperr().bit_is_set() || sr2.rdperr().bit_is_set() { } else if sr1.rdperr().bit_is_set() || sr2.rdperr().bit_is_set() {
Err(Error::ReadProtection) Err(Error::ReadProtection)

View File

@ -1,8 +1,8 @@
use crate::flash::Flash;
use crate::flash::Error as FlashError; use crate::flash::Error as FlashError;
use crate::flash::Flash;
use sfkv::{Store, StoreBackend};
use stm32h7xx_hal::pac::FLASH; use stm32h7xx_hal::pac::FLASH;
use sfkv::{ StoreBackend, Store };
use log::error; use log::error;
@ -32,13 +32,13 @@ pub enum SFKVProcessType {
// Idea: Forces BACKUP_SPACE to act as a cache. // Idea: Forces BACKUP_SPACE to act as a cache.
pub struct FakeFlashManager { pub struct FakeFlashManager {
// FSM: Track the type of data being programmed // FSM: Track the type of data being programmed
process_type: SFKVProcessType process_type: SFKVProcessType,
} }
impl StoreBackend for FakeFlashManager { impl StoreBackend for FakeFlashManager {
type Data = [u8]; type Data = [u8];
// Return // Return
fn data(&self) -> &Self::Data { fn data(&self) -> &Self::Data {
unsafe { &BACKUP_SPACE } unsafe { &BACKUP_SPACE }
} }
@ -64,7 +64,7 @@ impl StoreBackend for FakeFlashManager {
let cache_ptr: *const u8 = &BACKUP_SPACE[offset] as *const u8; let cache_ptr: *const u8 = &BACKUP_SPACE[offset] as *const u8;
let payload_ptr: *const u8 = &(*payload)[0] as *const u8; let payload_ptr: *const u8 = &(*payload)[0] as *const u8;
BACKUP_SPACE[offset..(offset+payload.len())].copy_from_slice(payload); BACKUP_SPACE[offset..(offset + payload.len())].copy_from_slice(payload);
// This part program extra trailing termination bytes (4 0xFF s) // This part program extra trailing termination bytes (4 0xFF s)
// However, if the remaining space is too small, there is also no need to program these bytes // However, if the remaining space is too small, there is also no need to program these bytes
@ -74,10 +74,11 @@ impl StoreBackend for FakeFlashManager {
// then we can assert that no k-v pair were ditched // then we can assert that no k-v pair were ditched
// Then there is no concern of accidentally interpreting unused flash memory as malformatted. // Then there is no concern of accidentally interpreting unused flash memory as malformatted.
if (cache_ptr != payload_ptr) if (cache_ptr != payload_ptr)
&& (offset+payload.len()+4 <= FLASH_SECTOR_SIZE) && (offset + payload.len() + 4 <= FLASH_SECTOR_SIZE)
&& self.process_type == SFKVProcessType::Data && self.process_type == SFKVProcessType::Data
{ {
BACKUP_SPACE[(offset+payload.len())..(offset+payload.len()+4)].copy_from_slice(&[0xFF; 4]); BACKUP_SPACE[(offset + payload.len())..(offset + payload.len() + 4)]
.copy_from_slice(&[0xFF; 4]);
} }
} }
self.advance_state(); self.advance_state();
@ -98,18 +99,10 @@ impl FakeFlashManager {
pub fn advance_state(&mut self) { pub fn advance_state(&mut self) {
self.process_type = match self.process_type { self.process_type = match self.process_type {
SFKVProcessType::Length => { SFKVProcessType::Length => SFKVProcessType::Type,
SFKVProcessType::Type SFKVProcessType::Type => SFKVProcessType::Space,
}, SFKVProcessType::Space => SFKVProcessType::Data,
SFKVProcessType::Type => { SFKVProcessType::Data => SFKVProcessType::Length,
SFKVProcessType::Space
},
SFKVProcessType::Space => {
SFKVProcessType::Data
},
SFKVProcessType::Data => {
SFKVProcessType::Length
}
}; };
} }
@ -127,9 +120,7 @@ fn init_flash_cache(flash: FLASH) -> Flash {
// sfkv will perform in-place operation in cache // sfkv will perform in-place operation in cache
// flash will only be updated after invoking `save()` // flash will only be updated after invoking `save()`
unsafe { unsafe {
BACKUP_SPACE.copy_from_slice( BACKUP_SPACE.copy_from_slice(flash.read(FLASH_SECTOR_OFFSET, FLASH_SECTOR_SIZE));
flash.read(FLASH_SECTOR_OFFSET, FLASH_SECTOR_SIZE)
);
} }
flash flash
} }
@ -143,7 +134,8 @@ fn init_flash_store() -> FlashStore {
Ok(_) => {} Ok(_) => {}
Err(e) => { Err(e) => {
error!("corrupt store, erasing. error: {:?}", e); error!("corrupt store, erasing. error: {:?}", e);
let _ = store.erase() let _ = store
.erase()
.map_err(|e| error!("flash erase failed: {:?}", e)); .map_err(|e| error!("flash erase failed: {:?}", e));
} }
} }
@ -166,6 +158,8 @@ pub fn update_flash(flash: &mut Flash, store: &FlashStore) -> Result<(), FlashEr
flash_size + 0x20 - (flash_size % 0x20) flash_size + 0x20 - (flash_size % 0x20)
}; };
unsafe { unsafe {
flash.program(FLASH_SECTOR_OFFSET, &BACKUP_SPACE[..save_size]).map(|_| ()) flash
.program(FLASH_SECTOR_OFFSET, &BACKUP_SPACE[..save_size])
.map(|_| ())
} }
} }

View File

@ -1,7 +1,7 @@
use embedded_hal::{ use embedded_hal::{
digital::v2::{OutputPin, InputPin},
blocking::spi::Transfer,
blocking::delay::DelayUs, blocking::delay::DelayUs,
blocking::spi::Transfer,
digital::v2::{InputPin, OutputPin},
}; };
#[derive(Debug)] #[derive(Debug)]
@ -14,31 +14,38 @@ pub enum FPGAFlashError {
const DATA: &'static [u8] = include_bytes!("../build/top.bin"); const DATA: &'static [u8] = include_bytes!("../build/top.bin");
// A public method to flash iCE40 FPGA on Humpback // A public method to flash iCE40 FPGA on Humpback
pub fn flash_ice40_fpga<SPI: Transfer<u8>, pub fn flash_ice40_fpga<
SS: OutputPin, SPI: Transfer<u8>,
RST: OutputPin, SS: OutputPin,
DELAY: DelayUs<u32>, RST: OutputPin,
DONE: InputPin> DELAY: DelayUs<u32>,
(mut spi: SPI, mut ss: SS, mut creset: RST, cdone: DONE, mut delay: DELAY) -> Result<(), FPGAFlashError> DONE: InputPin,
{ >(
mut spi: SPI,
mut ss: SS,
mut creset: RST,
cdone: DONE,
mut delay: DELAY,
) -> Result<(), FPGAFlashError> {
// Data buffer setup // Data buffer setup
let mut dummy_byte :[u8; 1] = [0x00]; let mut dummy_byte: [u8; 1] = [0x00];
let mut dummy_13_bytes :[u8; 13] = [0x00; 13]; let mut dummy_13_bytes: [u8; 13] = [0x00; 13];
// Drive CRESET_B low // Drive CRESET_B low
creset.set_low() creset
.map_err(|_| FPGAFlashError::NegotiationError)?; .set_low()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Drive SPI_SS_B low // Drive SPI_SS_B low
ss.set_low() ss.set_low().map_err(|_| FPGAFlashError::NegotiationError)?;
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least 200ns // Wait at least 200ns
delay.delay_us(1_u32); delay.delay_us(1_u32);
// Drive CRESET_B high // Drive CRESET_B high
creset.set_high() creset
.map_err(|_| FPGAFlashError::NegotiationError)?; .set_high()
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Wait at least another 1200us to clear internal config memory // Wait at least another 1200us to clear internal config memory
delay.delay_us(1200_u32); delay.delay_us(1200_u32);
@ -46,7 +53,7 @@ pub fn flash_ice40_fpga<SPI: Transfer<u8>,
// Before data transmission starts, check if C_DONE is truly low // Before data transmission starts, check if C_DONE is truly low
// If C_DONE is high, the FPGA reset procedure is unsuccessful // If C_DONE is high, the FPGA reset procedure is unsuccessful
match cdone.is_low() { match cdone.is_low() {
Ok(true) => {}, Ok(true) => {}
_ => return Err(FPGAFlashError::ResetStatusError), _ => return Err(FPGAFlashError::ResetStatusError),
}; };
@ -59,8 +66,7 @@ pub fn flash_ice40_fpga<SPI: Transfer<u8>,
.map_err(|_| FPGAFlashError::SPICommunicationError)?; .map_err(|_| FPGAFlashError::SPICommunicationError)?;
// Drive SPI_SS_B low // Drive SPI_SS_B low
ss.set_low() ss.set_low().map_err(|_| FPGAFlashError::NegotiationError)?;
.map_err(|_| FPGAFlashError::NegotiationError)?;
// Send the whole image without interruption // Send the whole image without interruption
for byte in DATA.into_iter() { for byte in DATA.into_iter() {
@ -80,12 +86,12 @@ pub fn flash_ice40_fpga<SPI: Transfer<u8>,
// Check the CDONE output from FPGA // Check the CDONE output from FPGA
// CDONE needs to be high // CDONE needs to be high
match cdone.is_high() { match cdone.is_high() {
Ok(true) => {}, Ok(true) => {}
_ => return Err(FPGAFlashError::ResetStatusError), _ => return Err(FPGAFlashError::ResetStatusError),
}; };
// Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes) // Send at least another 49 clock cycles to activate IO pins (choosing same 13 bytes)
spi.transfer(&mut dummy_13_bytes).map_err(|_| FPGAFlashError::SPICommunicationError)?; spi.transfer(&mut dummy_13_bytes)
.map_err(|_| FPGAFlashError::SPICommunicationError)?;
Ok(()) Ok(())
} }

View File

@ -2,7 +2,7 @@
pub unsafe fn enable_itm( pub unsafe fn enable_itm(
dbgmcu: &stm32h7xx_hal::stm32::DBGMCU, dbgmcu: &stm32h7xx_hal::stm32::DBGMCU,
dcb: &mut cortex_m::peripheral::DCB, dcb: &mut cortex_m::peripheral::DCB,
itm: &mut cortex_m::peripheral::ITM itm: &mut cortex_m::peripheral::ITM,
) { ) {
// ARMv7-M DEMCR: Set TRCENA. Enables DWT and ITM units // ARMv7-M DEMCR: Set TRCENA. Enables DWT and ITM units
//unsafe { *(0xE000_EDFC as *mut u32) |= 1 << 24 }; //unsafe { *(0xE000_EDFC as *mut u32) |= 1 << 24 };
@ -56,23 +56,17 @@ use log::LevelFilter;
pub use cortex_m_log::log::Logger; pub use cortex_m_log::log::Logger;
use cortex_m_log::{ use cortex_m_log::{
destination::Itm as ItmDest, destination::Itm as ItmDest, modes::InterruptFree, printer::itm::InterruptSync,
printer::itm::InterruptSync, printer::itm::ItmSync,
modes::InterruptFree,
printer::itm::ItmSync
}; };
lazy_static! { lazy_static! {
static ref LOGGER: Logger<ItmSync<InterruptFree>> = Logger { static ref LOGGER: Logger<ItmSync<InterruptFree>> = Logger {
level: LevelFilter::Info, level: LevelFilter::Info,
inner: unsafe { inner: unsafe { InterruptSync::new(ItmDest::new(cortex_m::Peripherals::steal().ITM)) },
InterruptSync::new(
ItmDest::new(cortex_m::Peripherals::steal().ITM)
)
},
}; };
} }
pub fn init() { pub fn init() {
cortex_m_log::log::init(&LOGGER).unwrap(); cortex_m_log::log::init(&LOGGER).unwrap();
} }

View File

@ -4,36 +4,36 @@
#![feature(assoc_char_funcs)] #![feature(assoc_char_funcs)]
#![feature(alloc_error_handler)] #![feature(alloc_error_handler)]
use log::{ trace, warn }; use log::{trace, warn};
use stm32h7xx_hal::ethernet;
use stm32h7xx_hal::gpio::Speed; use stm32h7xx_hal::gpio::Speed;
use stm32h7xx_hal::rng::Rng; use stm32h7xx_hal::rng::Rng;
use stm32h7xx_hal::{pac, prelude::*, spi}; use stm32h7xx_hal::{pac, prelude::*, spi};
use stm32h7xx_hal::ethernet;
use smoltcp as net; use smoltcp as net;
use SaiTLS as tls; use SaiTLS as tls;
use minimq::{ MqttClient, QoS }; use minimq::{MqttClient, QoS};
use alloc_cortex_m::CortexMHeap;
use cortex_m; use cortex_m;
use cortex_m_rt::entry; use cortex_m_rt::entry;
use alloc_cortex_m::CortexMHeap; use rand_core::{CryptoRng, RngCore};
use rtic::cyccnt::{Instant, U32Ext}; use rtic::cyccnt::{Instant, U32Ext};
use rand_core::{RngCore, CryptoRng};
use tls::TlsRng;
use tls::tls::TlsSocket;
use tls::tcp_stack::NetworkStack;
use heapless::{ String, consts, consts::* };
use core::alloc::Layout; use core::alloc::Layout;
use heapless::{consts, consts::*, String};
use tls::tcp_stack::NetworkStack;
use tls::tls::TlsSocket;
use tls::TlsRng;
#[macro_use] #[macro_use]
pub mod bitmask_macro; pub mod bitmask_macro;
pub mod spi_slave;
pub mod cpld; pub mod cpld;
pub mod spi_slave;
use crate::cpld::CPLD; use crate::cpld::CPLD;
pub mod config_register;
pub mod attenuator; pub mod attenuator;
pub mod config_register;
pub mod dds; pub mod dds;
pub mod net_store; pub mod net_store;
use crate::net_store::NetStorage; use crate::net_store::NetStorage;
@ -43,8 +43,8 @@ pub mod mqtt_mux;
use crate::mqtt_mux::MqttMux; use crate::mqtt_mux::MqttMux;
pub mod urukul; pub mod urukul;
use crate::urukul::Urukul; use crate::urukul::Urukul;
pub mod flash;
pub mod config; pub mod config;
pub mod flash;
use crate::config::get_net_config; use crate::config::get_net_config;
pub mod flash_store; pub mod flash_store;
use crate::flash_store::init_flash; use crate::flash_store::init_flash;
@ -77,7 +77,7 @@ static mut TX_STORAGE: [u8; 8192] = [0; 8192];
static mut RX_STORAGE: [u8; 8192] = [0; 8192]; static mut RX_STORAGE: [u8; 8192] = [0; 8192];
struct RngStruct { struct RngStruct {
rng: Rng rng: Rng,
} }
impl RngCore for RngStruct { impl RngCore for RngStruct {
@ -104,7 +104,6 @@ impl TlsRng for RngStruct {}
#[entry] #[entry]
fn main() -> ! { fn main() -> ! {
// Initialize the allocator BEFORE you use it // Initialize the allocator BEFORE you use it
let start = cortex_m_rt::heap_start() as usize; let start = cortex_m_rt::heap_start() as usize;
let size = 32768; // in bytes let size = 32768; // in bytes
@ -134,9 +133,9 @@ fn main() -> ! {
.pll1_q_ck(48.mhz()) .pll1_q_ck(48.mhz())
.pll1_r_ck(400.mhz()) .pll1_r_ck(400.mhz())
.freeze(vos, &dp.SYSCFG); .freeze(vos, &dp.SYSCFG);
let delay = cp.SYST.delay(ccdr.clocks); let delay = cp.SYST.delay(ccdr.clocks);
cp.SCB.invalidate_icache(); cp.SCB.invalidate_icache();
cp.SCB.enable_icache(); cp.SCB.enable_icache();
@ -144,7 +143,7 @@ fn main() -> ! {
// Instantiate random number generator // Instantiate random number generator
let mut rng = RngStruct { let mut rng = RngStruct {
rng: dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks) rng: dp.RNG.constrain(ccdr.peripheral.RNG, &ccdr.clocks),
}; };
// Create sfkv store and flash storage manager // Create sfkv store and flash storage manager
@ -267,7 +266,7 @@ fn main() -> ! {
let parts = switch.split(); let parts = switch.split();
let urukul = Urukul::new( let urukul = Urukul::new(
parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7 parts.spi1, parts.spi2, parts.spi3, parts.spi4, parts.spi5, parts.spi6, parts.spi7,
); );
let mut mqtt_mux = MqttMux::new(urukul, flash, flash_store, net_config.name.as_str()); let mut mqtt_mux = MqttMux::new(urukul, flash, flash_store, net_config.name.as_str());
@ -281,27 +280,17 @@ fn main() -> ! {
next_ms += 400_000.cycles(); next_ms += 400_000.cycles();
let mut tls_socket_entries: [_; 1] = Default::default(); let mut tls_socket_entries: [_; 1] = Default::default();
let mut tls_socket_set = tls::set::TlsSocketSet::new( let mut tls_socket_set = tls::set::TlsSocketSet::new(&mut tls_socket_entries[..]);
&mut tls_socket_entries[..]
);
let tx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut TX_STORAGE[..] }); let tx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut TX_STORAGE[..] });
let rx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut RX_STORAGE[..] }); let rx_buffer = net::socket::TcpSocketBuffer::new(unsafe { &mut RX_STORAGE[..] });
let mut tcp_socket = net::socket::TcpSocket::new(rx_buffer, tx_buffer); let mut tcp_socket = net::socket::TcpSocket::new(rx_buffer, tx_buffer);
tcp_socket.set_keep_alive( tcp_socket.set_keep_alive(Some(net::time::Duration::from_secs(2)));
Some(net::time::Duration::from_secs(2))
);
let tls_socket = TlsSocket::new( let tls_socket = TlsSocket::new(tcp_socket, &mut rng, None);
tcp_socket,
&mut rng,
None
);
let _ = tls_socket_set.add(tls_socket); let _ = tls_socket_set.add(tls_socket);
let tls_stack = NetworkStack::new( let tls_stack = NetworkStack::new(tls_socket_set);
tls_socket_set
);
let mut client = MqttClient::<consts::U2048, _>::new( let mut client = MqttClient::<consts::U2048, _>::new(
net_config.broker_ip, net_config.broker_ip,
@ -325,37 +314,35 @@ fn main() -> ! {
// eth Poll if necessary // eth Poll if necessary
// Do not poll if eth link is down // Do not poll if eth link is down
while !eth_mac.phy_poll_link() {} while !eth_mac.phy_poll_link() {}
client.network_stack.poll(&mut net_interface, net::time::Instant::from_millis(time)); client
.network_stack
.poll(&mut net_interface, net::time::Instant::from_millis(time));
// Process MQTT messages about Urukul/Control // Process MQTT messages about Urukul/Control
let connection = match client let connection = match client.poll(|_client, topic, message, _properties| {
.poll(|_client, topic, message, _properties| { mqtt_mux.process_mqtt_ingress(topic, message);
mqtt_mux.process_mqtt_ingress(topic, message); }) {
}) { Ok(_) => true,
Ok(_) => true, Err(e) => {
Err(e) => { log::info!("Warn: {:?}", e);
log::info!("Warn: {:?}", e); false
false }
}, };
};
// Process MQTT response messages about Urukul // Process MQTT response messages about Urukul
for (topic, message) in mqtt_mux.process_mqtt_egress().unwrap() { for (topic, message) in mqtt_mux.process_mqtt_egress().unwrap() {
client.publish( client
topic.as_str(), .publish(topic.as_str(), message.as_bytes(), QoS::AtMostOnce, &[])
message.as_bytes(), .unwrap();
QoS::AtMostOnce,
&[]
).unwrap();
} }
if connection && !has_subscribed && tick { if connection && !has_subscribed && tick {
let mut str_builder: String<U128> = String::from(net_config.name.as_str()); let mut str_builder: String<U128> = String::from(net_config.name.as_str());
str_builder.push_str("/Control/#").unwrap(); str_builder.push_str("/Control/#").unwrap();
match client.subscribe(str_builder.as_str(), &[]) { match client.subscribe(str_builder.as_str(), &[]) {
Ok(()) => has_subscribed = true, Ok(()) => has_subscribed = true,
Err(minimq::Error::NotReady) => {}, Err(minimq::Error::NotReady) => {}
_e => {}, _e => {}
}; };
} }
@ -363,4 +350,3 @@ fn main() -> ! {
tick = false; tick = false;
} }
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +1,8 @@
use embedded_hal::{
blocking::spi::Transfer,
digital::v2::OutputPin,
};
use crate::cpld::CPLD; use crate::cpld::CPLD;
use crate::urukul::Error; use crate::urukul::Error;
use embedded_hal::{blocking::spi::Transfer, digital::v2::OutputPin};
pub struct SPISlave<'a, SPI, CS0, CS1, CS2, GPIO> ( pub struct SPISlave<'a, SPI, CS0, CS1, CS2, GPIO>(
// SPI device to be multiplexed // SPI device to be multiplexed
&'a CPLD<SPI, CS0, CS1, CS2, GPIO>, &'a CPLD<SPI, CS0, CS1, CS2, GPIO>,
// Channel of SPI slave // Channel of SPI slave
@ -48,8 +45,12 @@ where
{ {
type Error = Error<E>; type Error = Error<E>;
fn transfer<'w>(&mut self, words: &'w mut[u8]) -> Result<&'w [u8], Self::Error> { fn transfer<'w>(&mut self, words: &'w mut [u8]) -> Result<&'w [u8], Self::Error> {
let mut dev = self.0.data.try_borrow_mut().map_err(|_| Error::GetRefMutDataError)?; let mut dev = self
.0
.data
.try_borrow_mut()
.map_err(|_| Error::GetRefMutDataError)?;
dev.select_chip(self.1).map_err(|_| Error::CSError)?; dev.select_chip(self.1).map_err(|_| Error::CSError)?;
let result = dev.spi.transfer(words).map_err(Error::SPI)?; let result = dev.spi.transfer(words).map_err(Error::SPI)?;
dev.select_chip(0).map_err(|_| Error::CSError)?; dev.select_chip(0).map_err(|_| Error::CSError)?;

View File

@ -1,15 +1,13 @@
extern crate embedded_hal; extern crate embedded_hal;
use embedded_hal::{ use embedded_hal::blocking::spi::Transfer;
blocking::spi::Transfer,
};
use serde::{ Serialize, Deserialize }; use serde::{Deserialize, Serialize};
use crate::config_register::ConfigRegister;
use crate::config_register::CFGMask;
use crate::config_register::StatusMask;
use crate::attenuator::Attenuator; use crate::attenuator::Attenuator;
use crate::dds::{ DDS, RAMOperationMode, RAMDestination }; use crate::config_register::CFGMask;
use crate::config_register::ConfigRegister;
use crate::config_register::StatusMask;
use crate::dds::{RAMDestination, RAMOperationMode, DDS};
/* /*
* Enum for structuring error * Enum for structuring error
@ -30,7 +28,7 @@ pub enum Error<E> {
MqttCommandError, MqttCommandError,
VectorOutOfSpace, VectorOutOfSpace,
StringOutOfSpace, StringOutOfSpace,
WaitRetry, // Prompt driver to just wait and retry WaitRetry, // Prompt driver to just wait and retry
} }
impl<E> Error<E> { impl<E> Error<E> {
@ -68,7 +66,15 @@ where
* Master constructor for the entire Urukul device * Master constructor for the entire Urukul device
* Supply 7 SPI channels to Urukul and 4 reference clock frequencies * 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) -> Self { pub fn new(
spi1: SPI,
spi2: SPI,
spi3: SPI,
spi4: SPI,
spi5: SPI,
spi6: SPI,
spi7: SPI,
) -> Self {
// Construct Urukul // Construct Urukul
Urukul { Urukul {
config_register: ConfigRegister::new(spi1), config_register: ConfigRegister::new(spi1),
@ -100,21 +106,21 @@ where
self.config_register.set_configurations(&mut [ self.config_register.set_configurations(&mut [
(CFGMask::RST, 1), (CFGMask::RST, 1),
(CFGMask::IO_RST, 1), (CFGMask::IO_RST, 1),
(CFGMask::IO_UPDATE, 0) (CFGMask::IO_UPDATE, 0),
])?; ])?;
// Set 0 to all fields on configuration register. // Set 0 to all fields on configuration register.
self.config_register.set_configurations(&mut [ self.config_register.set_configurations(&mut [
(CFGMask::RF_SW, 0), (CFGMask::RF_SW, 0),
(CFGMask::LED, 0), (CFGMask::LED, 0),
(CFGMask::PROFILE, 0), (CFGMask::PROFILE, 0),
(CFGMask::IO_UPDATE, 0), (CFGMask::IO_UPDATE, 0),
(CFGMask::MASK_NU, 0), (CFGMask::MASK_NU, 0),
(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL0, 0),
(CFGMask::SYNC_SEL, 0), (CFGMask::SYNC_SEL, 0),
(CFGMask::RST, 0), (CFGMask::RST, 0),
(CFGMask::IO_RST, 0), (CFGMask::IO_RST, 0),
(CFGMask::CLK_SEL1, 0), (CFGMask::CLK_SEL1, 0),
(CFGMask::DIV, 0), (CFGMask::DIV, 0),
])?; ])?;
// Init all DDS chips. Configure SDIO as input only. // Init all DDS chips. Configure SDIO as input only.
for chip_no in 0..4 { for chip_no in 0..4 {
@ -145,12 +151,13 @@ where
impl<SPI, E> Urukul<SPI> impl<SPI, E> Urukul<SPI>
where where
SPI: Transfer<u8, Error = E> SPI: Transfer<u8, Error = E>,
{ {
pub fn get_channel_switch_status(&mut self, channel: u32) -> Result<bool, Error<E>> { pub fn get_channel_switch_status(&mut self, channel: u32) -> Result<bool, Error<E>> {
if channel < 4 { if channel < 4 {
self.config_register.get_status(StatusMask::RF_SW).map(|val| (val & (1 << channel)) != 0) self.config_register
.get_status(StatusMask::RF_SW)
.map(|val| (val & (1 << channel)) != 0)
} else { } else {
Err(Error::ParameterError) Err(Error::ParameterError)
} }
@ -166,15 +173,20 @@ where
prev & (!(1 << channel)) prev & (!(1 << channel))
} }
}; };
self.config_register.set_configurations(&mut [ self.config_register
(CFGMask::RF_SW, next), .set_configurations(&mut [(CFGMask::RF_SW, next)])
]).map(|_| ()) .map(|_| ())
} else { } else {
Err(Error::ParameterError) Err(Error::ParameterError)
} }
} }
pub fn set_clock(&mut self, source: ClockSource, frequency: f64, division: u8) -> Result<(), Error<E>> { pub fn set_clock(
&mut self,
source: ClockSource,
frequency: f64,
division: u8,
) -> Result<(), Error<E>> {
// Change clock source through configuration register // Change clock source through configuration register
self.set_clock_source(source)?; self.set_clock_source(source)?;
@ -188,30 +200,29 @@ where
pub fn get_clock_source(&mut self) -> Result<ClockSource, Error<E>> { pub fn get_clock_source(&mut self) -> Result<ClockSource, Error<E>> {
match ( match (
self.config_register.get_configuration(CFGMask::CLK_SEL0), self.config_register.get_configuration(CFGMask::CLK_SEL0),
self.config_register.get_configuration(CFGMask::CLK_SEL1) self.config_register.get_configuration(CFGMask::CLK_SEL1),
) { ) {
(0, 0) => Ok(ClockSource::OSC), (0, 0) => Ok(ClockSource::OSC),
(0, 1) => Ok(ClockSource::MMCX), (0, 1) => Ok(ClockSource::MMCX),
(1, _) => Ok(ClockSource::SMA), (1, _) => Ok(ClockSource::SMA),
_ => Err(Error::ConfigRegisterError) _ => Err(Error::ConfigRegisterError),
} }
} }
pub fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Error<E>> { pub fn set_clock_source(&mut self, source: ClockSource) -> Result<(), Error<E>> {
// Change clock source through configuration register // Change clock source through configuration register
match source { match source {
ClockSource::OSC => self.config_register.set_configurations(&mut [ ClockSource::OSC => self
(CFGMask::CLK_SEL0, 0), .config_register
(CFGMask::CLK_SEL1, 0), .set_configurations(&mut [(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL1, 0)]),
]), ClockSource::MMCX => self
ClockSource::MMCX => self.config_register.set_configurations(&mut [ .config_register
(CFGMask::CLK_SEL0, 0), .set_configurations(&mut [(CFGMask::CLK_SEL0, 0), (CFGMask::CLK_SEL1, 1)]),
(CFGMask::CLK_SEL1, 1), ClockSource::SMA => self
]), .config_register
ClockSource::SMA => self.config_register.set_configurations(&mut [ .set_configurations(&mut [(CFGMask::CLK_SEL0, 1)]),
(CFGMask::CLK_SEL0, 1), }
]), .map(|_| ())
}.map(|_| ())
} }
pub fn get_clock_frequency(&mut self) -> f64 { pub fn get_clock_frequency(&mut self) -> f64 {
@ -228,24 +239,24 @@ where
pub fn get_clock_division(&mut self) -> Result<u8, Error<E>> { pub fn get_clock_division(&mut self) -> Result<u8, Error<E>> {
match self.config_register.get_configuration(CFGMask::DIV) { match self.config_register.get_configuration(CFGMask::DIV) {
0| 3 => Ok(4), 0 | 3 => Ok(4),
1 => Ok(1), 1 => Ok(1),
2 => Ok(2), 2 => Ok(2),
_ => Err(Error::ConfigRegisterError) _ => Err(Error::ConfigRegisterError),
} }
} }
pub fn set_clock_division(&mut self, division: u8) -> Result<(), Error<E>> { pub fn set_clock_division(&mut self, division: u8) -> Result<(), Error<E>> {
match division { match division {
1 => self.config_register.set_configurations(&mut [ 1 => self
(CFGMask::DIV, 1), .config_register
]), .set_configurations(&mut [(CFGMask::DIV, 1)]),
2 => self.config_register.set_configurations(&mut [ 2 => self
(CFGMask::DIV, 2), .config_register
]), .set_configurations(&mut [(CFGMask::DIV, 2)]),
4 => self.config_register.set_configurations(&mut [ 4 => self
(CFGMask::DIV, 3), .config_register
]), .set_configurations(&mut [(CFGMask::DIV, 3)]),
_ => Err(Error::ParameterError), _ => Err(Error::ParameterError),
}?; }?;
@ -276,11 +287,16 @@ where
self.attenuator.get_channel_attenuation(channel) self.attenuator.get_channel_attenuation(channel)
} }
pub fn set_channel_attenuation(&mut self, channel: u8, attenuation: f32) -> Result<(), Error<E>> { pub fn set_channel_attenuation(
&mut self,
channel: u8,
attenuation: f32,
) -> Result<(), Error<E>> {
if channel >= 4 || attenuation < 0.0 || attenuation > 31.5 { if channel >= 4 || attenuation < 0.0 || attenuation > 31.5 {
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
self.attenuator.set_channel_attenuation(channel, attenuation) self.attenuator
.set_channel_attenuation(channel, attenuation)
} }
pub fn get_profile(&mut self) -> Result<u8, Error<E>> { pub fn get_profile(&mut self) -> Result<u8, Error<E>> {
@ -291,38 +307,70 @@ where
if profile >= 8 { if profile >= 8 {
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
self.config_register.set_configurations(&mut [ self.config_register
(CFGMask::PROFILE, profile.into()) .set_configurations(&mut [(CFGMask::PROFILE, profile.into())])
]).map(|_| ()) .map(|_| ())
} }
pub fn set_channel_single_tone_profile(&mut self, channel: u8, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Error<E>> { pub fn set_channel_single_tone_profile(
if channel >= 4 || profile >= 8 || frequency < 0.0 || phase >= 360.0 || &mut self,
phase < 0.0 || amplitude < 0.0 || amplitude > 1.0 { channel: u8,
profile: u8,
frequency: f64,
phase: f64,
amplitude: f64,
) -> Result<(), Error<E>> {
if channel >= 4
|| profile >= 8
|| frequency < 0.0
|| phase >= 360.0
|| phase < 0.0
|| amplitude < 0.0
|| amplitude > 1.0
{
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude) self.dds[usize::from(channel)].set_single_tone_profile(profile, frequency, phase, amplitude)
} }
pub fn get_channel_single_tone_profile(&mut self, channel: u8, profile: u8) -> Result<(f64, f64, f64), Error<E>> { pub fn get_channel_single_tone_profile(
&mut self,
channel: u8,
profile: u8,
) -> Result<(f64, f64, f64), Error<E>> {
self.dds[usize::from(channel)].get_single_tone_profile(profile) self.dds[usize::from(channel)].get_single_tone_profile(profile)
} }
pub fn set_channel_single_tone_profile_frequency(&mut self, channel: u8, profile: u8, frequency: f64)-> Result<(), Error<E>> { pub fn set_channel_single_tone_profile_frequency(
&mut self,
channel: u8,
profile: u8,
frequency: f64,
) -> Result<(), Error<E>> {
if channel >= 4 || profile >= 8 || frequency < 0.0 { if channel >= 4 || profile >= 8 || frequency < 0.0 {
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
self.dds[usize::from(channel)].set_single_tone_profile_frequency(profile, frequency) self.dds[usize::from(channel)].set_single_tone_profile_frequency(profile, frequency)
} }
pub fn set_channel_single_tone_profile_phase(&mut self, channel: u8, profile: u8, phase: f64)-> Result<(), Error<E>> { pub fn set_channel_single_tone_profile_phase(
&mut self,
channel: u8,
profile: u8,
phase: f64,
) -> Result<(), Error<E>> {
if channel >= 4 || profile >= 8 || phase >= 360.0 || phase < 0.0 { if channel >= 4 || profile >= 8 || phase >= 360.0 || phase < 0.0 {
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
self.dds[usize::from(channel)].set_single_tone_profile_phase(profile, phase) self.dds[usize::from(channel)].set_single_tone_profile_phase(profile, phase)
} }
pub fn set_channel_single_tone_profile_amplitude(&mut self, channel: u8, profile: u8, amplitude: f64)-> Result<(), Error<E>> { pub fn set_channel_single_tone_profile_amplitude(
&mut self,
channel: u8,
profile: u8,
amplitude: f64,
) -> Result<(), Error<E>> {
if channel >= 4 || profile >= 8 || amplitude < 0.0 || amplitude > 1.0 { if channel >= 4 || profile >= 8 || amplitude < 0.0 || amplitude > 1.0 {
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
@ -330,18 +378,20 @@ where
} }
pub fn append_dds_ram_buffer(&mut self, data: &[u8]) -> Result<(), Error<E>> { pub fn append_dds_ram_buffer(&mut self, data: &[u8]) -> Result<(), Error<E>> {
unsafe { unsafe { Ok(crate::dds::append_ram_byte(data)) }
Ok(crate::dds::append_ram_byte(data))
}
} }
// Use profile 7 to write into the RAM // Use profile 7 to write into the RAM
pub fn commit_ram_buffer_to_channel(&mut self, channel: u8, start_addr: u16, ram_dest: RAMDestination) -> Result<(), Error<E>> { pub fn commit_ram_buffer_to_channel(
&mut self,
channel: u8,
start_addr: u16,
ram_dest: RAMDestination,
) -> Result<(), Error<E>> {
let profile = self.get_profile()?; let profile = self.get_profile()?;
self.set_profile(7)?; self.set_profile(7)?;
unsafe { unsafe {
self.dds[usize::from(channel)] self.dds[usize::from(channel)].commit_ram_buffer(start_addr, ram_dest)?;
.commit_ram_buffer(start_addr, ram_dest)?;
} }
self.set_profile(profile) self.set_profile(profile)
} }
@ -350,7 +400,11 @@ where
self.dds[usize::from(channel)].set_default_ftw(frequency) self.dds[usize::from(channel)].set_default_ftw(frequency)
} }
pub fn set_channel_default_asf(&mut self, channel: u8, amplitude_scale: f64) -> Result<(), Error<E>> { pub fn set_channel_default_asf(
&mut self,
channel: u8,
amplitude_scale: f64,
) -> Result<(), Error<E>> {
self.dds[usize::from(channel)].set_default_asf(amplitude_scale) self.dds[usize::from(channel)].set_default_asf(amplitude_scale)
} }
@ -362,14 +416,25 @@ where
self.dds[usize::from(channel)].get_default_asf() self.dds[usize::from(channel)].get_default_asf()
} }
pub fn set_channel_ram_profile(&mut self, channel: u8, profile: u8, start_addr: u16, pub fn set_channel_ram_profile(
end_addr: u16, op_mode: RAMOperationMode, ramp_rate: u16 &mut self,
channel: u8,
profile: u8,
start_addr: u16,
end_addr: u16,
op_mode: RAMOperationMode,
ramp_rate: u16,
) -> Result<(), Error<E>> { ) -> Result<(), Error<E>> {
self.dds[usize::from(channel)] self.dds[usize::from(channel)].set_up_ram_profile(
.set_up_ram_profile(profile, start_addr, end_addr, true, false, op_mode, ramp_rate) profile, start_addr, end_addr, true, false, op_mode, ramp_rate,
)
} }
pub fn get_channel_ram_profile(&mut self, channel: u8, profile: u8) -> Result<(u16, u16, u16, u8), Error<E>> { pub fn get_channel_ram_profile(
&mut self,
channel: u8,
profile: u8,
) -> Result<(u16, u16, u16, u8), Error<E>> {
self.dds[usize::from(channel)].get_ram_profile(profile) self.dds[usize::from(channel)].get_ram_profile(profile)
} }
@ -406,17 +471,28 @@ where
// Note: If a channel is masked, io_update must be completed through configuration register (IO_UPDATE bit-field) // Note: If a channel is masked, io_update must be completed through configuration register (IO_UPDATE bit-field)
// Implication: Deselect such channel if individual communication is needed. // Implication: Deselect such channel if individual communication is needed.
pub fn set_multi_channel_coverage(&mut self, channel: u8) -> Result<(), Error<E>> { pub fn set_multi_channel_coverage(&mut self, channel: u8) -> Result<(), Error<E>> {
self.config_register.set_configurations(&mut [ self.config_register
(CFGMask::MASK_NU, channel.into()) .set_configurations(&mut [(CFGMask::MASK_NU, channel.into())])
]).map(|_| ()) .map(|_| ())
} }
// Difference from individual single tone setup function: // Difference from individual single tone setup function:
// - Remove the need of passing channel // - Remove the need of passing channel
// All selected channels must share the same f_sys_clk // All selected channels must share the same f_sys_clk
pub fn set_multi_channel_single_tone_profile(&mut self, profile: u8, frequency: f64, phase: f64, amplitude: f64) -> Result<(), Error<E>> { pub fn set_multi_channel_single_tone_profile(
if profile >= 8 || frequency < 0.0 || phase >= 360.0 || &mut self,
phase < 0.0 || amplitude < 0.0 || amplitude > 1.0 { profile: u8,
frequency: f64,
phase: f64,
amplitude: f64,
) -> Result<(), Error<E>> {
if profile >= 8
|| frequency < 0.0
|| phase >= 360.0
|| phase < 0.0
|| amplitude < 0.0
|| amplitude > 1.0
{
return Err(Error::ParameterError); return Err(Error::ParameterError);
} }
// Check f_sys_clk of all selected channels // Check f_sys_clk of all selected channels
@ -434,18 +510,18 @@ where
} }
} }
self.multi_dds.set_sys_clk_frequency(reported_f_sys_clk)?; self.multi_dds.set_sys_clk_frequency(reported_f_sys_clk)?;
self.multi_dds.set_single_tone_profile(profile, frequency, phase, amplitude)?; self.multi_dds
.set_single_tone_profile(profile, frequency, phase, amplitude)?;
self.invoke_io_update() self.invoke_io_update()
} }
// Generate a pulse for io_update bit in configuration register // Generate a pulse for io_update bit in configuration register
// This acts like io_update in CPLD struct, but for multi-dds channel // This acts like io_update in CPLD struct, but for multi-dds channel
fn invoke_io_update(&mut self) -> Result<(), Error<E>> { fn invoke_io_update(&mut self) -> Result<(), Error<E>> {
self.config_register.set_configurations(&mut [ self.config_register
(CFGMask::IO_UPDATE, 1) .set_configurations(&mut [(CFGMask::IO_UPDATE, 1)])?;
])?; self.config_register
self.config_register.set_configurations(&mut [ .set_configurations(&mut [(CFGMask::IO_UPDATE, 0)])
(CFGMask::IO_UPDATE, 0) .map(|_| ())
]).map(|_| ())
} }
} }