forked from M-Labs/humpback-dds
dds: add ram control
This commit is contained in:
parent
3edc4c6957
commit
3211261488
256
src/dds.rs
256
src/dds.rs
@ -2,7 +2,8 @@ use embedded_hal::blocking::spi::Transfer;
|
|||||||
use crate::Error;
|
use crate::Error;
|
||||||
use core::mem::size_of;
|
use core::mem::size_of;
|
||||||
use core::convert::TryInto;
|
use core::convert::TryInto;
|
||||||
use arrayvec::ArrayVec;
|
use heapless::Vec;
|
||||||
|
use heapless::consts::*;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
* Bitmask for all configurations (Order: CFR3, CFR2, CFR1)
|
||||||
@ -64,6 +65,8 @@ construct_bitmask!(DDSCFRMask; u32;
|
|||||||
const WRITE_MASK :u8 = 0x00;
|
const WRITE_MASK :u8 = 0x00;
|
||||||
const READ_MASK :u8 = 0x80;
|
const READ_MASK :u8 = 0x80;
|
||||||
|
|
||||||
|
static mut RAM_VEC: Vec<u8, U8192> = Vec(heapless::i::Vec::new());
|
||||||
|
|
||||||
#[derive(Clone, PartialEq)]
|
#[derive(Clone, PartialEq)]
|
||||||
pub enum RAMDestination {
|
pub enum RAMDestination {
|
||||||
Frequency = 0,
|
Frequency = 0,
|
||||||
@ -483,94 +486,167 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Configure a RAM mode profile, but with RAM data generated by a closure
|
* Configure a RAM mode profile, wrt supplied frequency data
|
||||||
|
* This will setup the static RAM_VEC by converting frequency to ftw
|
||||||
*/
|
*/
|
||||||
pub fn set_ram_profile_with_closure<F>(&mut self, profile: u8, start_addr: u16,
|
pub unsafe fn set_frequency_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
no_dwell_high: bool, zero_crossing: bool, op_mode: RAMOperationMode, playback_rate: f64,
|
||||||
op_mode: RAMOperationMode, playback_rate: f64, f: F) -> Result<(), Error<E>>
|
frequency_data: &[f64]
|
||||||
where
|
|
||||||
F: FnOnce() -> ArrayVec::<[f64; 2048]>
|
|
||||||
{
|
|
||||||
// Check the legality of the profile setup
|
|
||||||
assert!(profile < 7);
|
|
||||||
assert!(start_addr < 1024);
|
|
||||||
let mut vec = f();
|
|
||||||
if (ram_dst != RAMDestination::Polar && ((vec.len() as u16) + start_addr) < 1024) ||
|
|
||||||
((((vec.len()/2) as u16) + start_addr) < 1024) {
|
|
||||||
return Err(Error::DDSRAMError);
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Convert argument into bytes for RAM
|
|
||||||
let mut byte_vec: ArrayVec<[u8; 8192]> = ArrayVec::new();
|
|
||||||
match ram_dst {
|
|
||||||
RAMDestination::Frequency => {
|
|
||||||
for freq in vec.into_iter() {
|
|
||||||
let ftw = self.frequency_to_ftw(freq);
|
|
||||||
byte_vec.push(((ftw >> 24) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((ftw >> 16) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((ftw >> 8) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((ftw >> 0) & 0xFF) as u8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RAMDestination::Phase => {
|
|
||||||
for deg in vec.into_iter() {
|
|
||||||
let pow = self.degree_to_pow(deg);
|
|
||||||
byte_vec.push(((pow >> 8) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((pow >> 0) & 0xFF) as u8);
|
|
||||||
byte_vec.push(0);
|
|
||||||
byte_vec.push(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RAMDestination::Amplitude => {
|
|
||||||
for amp in vec.into_iter() {
|
|
||||||
let asf = self.amplitude_to_asf(amp);
|
|
||||||
byte_vec.push(((asf >> 8) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((asf << 2) & 0xFC) as u8);
|
|
||||||
byte_vec.push(0);
|
|
||||||
byte_vec.push(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
RAMDestination::Polar => {
|
|
||||||
// Alternate phase and amplitude
|
|
||||||
let mut phase = true;
|
|
||||||
for pol in vec.into_iter() {
|
|
||||||
if phase {
|
|
||||||
let pow = self.degree_to_pow(pol);
|
|
||||||
byte_vec.push(((pow >> 8) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((pow >> 0) & 0xFF) as u8);
|
|
||||||
phase = false;
|
|
||||||
} else {
|
|
||||||
let asf = self.amplitude_to_asf(pol);
|
|
||||||
byte_vec.push(((asf >> 8) & 0xFF) as u8);
|
|
||||||
byte_vec.push(((asf << 2) & 0xFC) as u8);
|
|
||||||
phase = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if phase {
|
|
||||||
return Err(Error::DDSRAMError);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let data = byte_vec.as_slice();
|
|
||||||
self.set_ram_profile(profile, start_addr, start_addr + (((data.len()/4) - 1) as u16),
|
|
||||||
ram_dst, no_dwell_high, zero_crossing, op_mode, playback_rate, data)
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Configure a RAM mode profile
|
|
||||||
* TODO: Possibly remove redundant end_addr parameter.
|
|
||||||
* This can be inferred by start_addr and data size.
|
|
||||||
*/
|
|
||||||
pub fn set_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
|
||||||
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
|
||||||
op_mode: RAMOperationMode, playback_rate: f64, data: &[u8]
|
|
||||||
) -> Result<(), Error<E>> {
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
// Check the legality of the profile setup
|
// Check the legality of the profile setup
|
||||||
assert!(profile < 7);
|
assert!(profile <= 7);
|
||||||
assert!(end_addr >= start_addr);
|
assert!(end_addr >= start_addr);
|
||||||
assert!(end_addr < 1024);
|
assert!(end_addr < 1024);
|
||||||
assert_eq!(data.len() as u16, (end_addr - start_addr + 1) * 4);
|
assert_eq!(frequency_data.len() as u16, end_addr - start_addr + 1);
|
||||||
|
|
||||||
|
// Clear RAM vector, and add address byte
|
||||||
|
RAM_VEC.clear();
|
||||||
|
RAM_VEC.push(0x16)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
|
||||||
|
// Convert frequency data into bytes recognized by DDS
|
||||||
|
for freq in frequency_data.iter() {
|
||||||
|
let ftw = self.frequency_to_ftw(*freq);
|
||||||
|
RAM_VEC.push(((ftw >> 24) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 16) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((ftw >> 0) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Frequency,
|
||||||
|
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a RAM mode profile, wrt supplied amplitude data
|
||||||
|
* This will setup the static RAM_VEC by converting amplitude to asf
|
||||||
|
*/
|
||||||
|
pub unsafe fn set_amplitude_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
|
no_dwell_high: bool, zero_crossing: bool, op_mode: RAMOperationMode, playback_rate: f64,
|
||||||
|
amplitude_data: &[f64]
|
||||||
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile <= 7);
|
||||||
|
assert!(end_addr >= start_addr);
|
||||||
|
assert!(end_addr < 1024);
|
||||||
|
assert_eq!(amplitude_data.len() as u16, end_addr - start_addr + 1);
|
||||||
|
|
||||||
|
// Clear RAM vector, and add address byte
|
||||||
|
RAM_VEC.clear();
|
||||||
|
RAM_VEC.push(0x16)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
|
||||||
|
// Convert amplitude data into bytes recognized by DDS
|
||||||
|
for amp in amplitude_data.iter() {
|
||||||
|
let asf = self.amplitude_to_asf(*amp);
|
||||||
|
RAM_VEC.push(((asf >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((asf << 2) & 0xFC) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(0)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(0)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Amplitude,
|
||||||
|
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a RAM mode profile, wrt supplied phase data
|
||||||
|
* This will setup the static RAM_VEC by converting phase to ftw
|
||||||
|
*/
|
||||||
|
pub unsafe fn set_phase_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
|
no_dwell_high: bool, zero_crossing: bool, op_mode: RAMOperationMode, playback_rate: f64,
|
||||||
|
phase_data: &[f64]
|
||||||
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile <= 7);
|
||||||
|
assert!(end_addr >= start_addr);
|
||||||
|
assert!(end_addr < 1024);
|
||||||
|
assert_eq!(phase_data.len() as u16, end_addr - start_addr + 1);
|
||||||
|
|
||||||
|
// Clear RAM vector, and add address byte
|
||||||
|
RAM_VEC.clear();
|
||||||
|
RAM_VEC.push(0x16)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
|
||||||
|
// Convert phase data into bytes recognized by DDS
|
||||||
|
for deg in phase_data.iter() {
|
||||||
|
let pow = self.degree_to_pow(*deg);
|
||||||
|
RAM_VEC.push(((pow >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((pow >> 0) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(0)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(0)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Phase,
|
||||||
|
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a RAM mode profile, wrt supplied phase data
|
||||||
|
* This will setup the static RAM_VEC by converting phase to ftw
|
||||||
|
*/
|
||||||
|
pub unsafe fn set_polar_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
|
no_dwell_high: bool, zero_crossing: bool, op_mode: RAMOperationMode, playback_rate: f64,
|
||||||
|
polar_data: &[(f64, f64)]
|
||||||
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile <= 7);
|
||||||
|
assert!(end_addr >= start_addr);
|
||||||
|
assert!(end_addr < 1024);
|
||||||
|
assert_eq!(polar_data.len() as u16, end_addr - start_addr + 1);
|
||||||
|
|
||||||
|
// Clear RAM vector, and add address byte
|
||||||
|
RAM_VEC.clear();
|
||||||
|
RAM_VEC.push(0x16)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
|
||||||
|
// Convert amplitude data into bytes recognized by DDS
|
||||||
|
for (deg, amp) in polar_data.iter() {
|
||||||
|
let pow = self.degree_to_pow(*deg);
|
||||||
|
let asf = self.amplitude_to_asf(*amp);
|
||||||
|
RAM_VEC.push(((pow >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((pow >> 0) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((asf >> 8) & 0xFF) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
RAM_VEC.push(((asf << 2) & 0xFC) as u8)
|
||||||
|
.map_err(|_| Error::DDSRAMError)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.set_ram_profile(profile, start_addr, end_addr, RAMDestination::Phase,
|
||||||
|
no_dwell_high, zero_crossing, op_mode, playback_rate)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Configure a RAM mode profile, w.r.t static vector (RAM_VEC)
|
||||||
|
*/
|
||||||
|
fn set_ram_profile(&mut self, profile: u8, start_addr: u16, end_addr: u16,
|
||||||
|
ram_dst: RAMDestination, no_dwell_high: bool, zero_crossing: bool,
|
||||||
|
op_mode: RAMOperationMode, playback_rate: f64
|
||||||
|
) -> Result<(), Error<E>> {
|
||||||
|
|
||||||
|
// Check the legality of the profile setup
|
||||||
|
assert!(profile <= 7);
|
||||||
|
assert!(end_addr >= start_addr);
|
||||||
|
assert!(end_addr < 1024);
|
||||||
|
// assert_eq! RAM_VEC.len() as u16, ((end_addr - start_addr + 1) * 4) + 1);
|
||||||
|
|
||||||
// Calculate address step rate, and check legality
|
// Calculate address step rate, and check legality
|
||||||
let step_rate = (self.f_sys_clk/(4.0 * playback_rate)) as u64;
|
let step_rate = (self.f_sys_clk/(4.0 * playback_rate)) as u64;
|
||||||
@ -595,7 +671,9 @@ where
|
|||||||
|
|
||||||
// Temporarily disable RAM mode while accessing into RAM
|
// Temporarily disable RAM mode while accessing into RAM
|
||||||
self.disable_ram_configuration()?;
|
self.disable_ram_configuration()?;
|
||||||
self.write_ram(data)?;
|
unsafe {
|
||||||
|
self.write_ram()?;
|
||||||
|
}
|
||||||
|
|
||||||
// Properly configure start_addr and end_addr
|
// Properly configure start_addr and end_addr
|
||||||
self.enable_ram_configuration(ram_dst)
|
self.enable_ram_configuration(ram_dst)
|
||||||
@ -622,14 +700,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write data in RAM
|
// Write data in RAM
|
||||||
fn write_ram(&mut self, data: &[u8]) -> Result<(), Error<E>> {
|
unsafe fn write_ram(&mut self) -> Result<(), Error<E>> {
|
||||||
let mut vec: ArrayVec<[u8; 8192]> = ArrayVec::new();
|
self.spi.transfer(&mut RAM_VEC)
|
||||||
vec.try_push(0x16)
|
|
||||||
.map_err(|_| Error::DDSRAMError)?;
|
|
||||||
vec.try_extend_from_slice(data)
|
|
||||||
.map_err(|_| Error::DDSRAMError)?;
|
|
||||||
let mut data_slice = vec.as_mut_slice();
|
|
||||||
self.spi.transfer(&mut data_slice)
|
|
||||||
.map(|_| ())
|
.map(|_| ())
|
||||||
.map_err(Error::SPI)
|
.map_err(Error::SPI)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user