Adding work after functional DDS interface

This commit is contained in:
Ryan Summers 2020-06-10 12:40:44 +02:00
parent 8b4d5397be
commit 519fa86058
9 changed files with 439 additions and 167 deletions

View File

@ -9,7 +9,7 @@ members = [
[profile.dev] [profile.dev]
codegen-units = 1 codegen-units = 1
incremental = false incremental = false
opt-level = 3 opt-level = 1
[profile.release] [profile.release]
debug = true debug = true

View File

@ -19,7 +19,7 @@ use embedded_hal::{
pub struct Ad9959<INTERFACE, DELAY, UPDATE> { pub struct Ad9959<INTERFACE, DELAY, UPDATE> {
interface: INTERFACE, interface: INTERFACE,
delay: DELAY, delay: DELAY,
reference_clock_frequency: u32, reference_clock_frequency: f32,
system_clock_multiplier: u8, system_clock_multiplier: u8,
io_update: UPDATE, io_update: UPDATE,
} }
@ -84,6 +84,7 @@ pub enum Channel {
#[derive(Debug)] #[derive(Debug)]
pub enum Error<InterfaceE> { pub enum Error<InterfaceE> {
Interface(InterfaceE), Interface(InterfaceE),
Check,
Bounds, Bounds,
Pin, Pin,
Frequency, Frequency,
@ -107,7 +108,7 @@ where
io_update: UPDATE, io_update: UPDATE,
delay: DELAY, delay: DELAY,
desired_mode: Mode, desired_mode: Mode,
clock_frequency: u32, clock_frequency: f32,
multiplier: u8) -> Result<Self, Error<InterfaceE>> multiplier: u8) -> Result<Self, Error<InterfaceE>>
where where
RST: OutputPin, RST: OutputPin,
@ -135,7 +136,7 @@ where
// Program the interface configuration in the AD9959. Default to all channels enabled. // Program the interface configuration in the AD9959. Default to all channels enabled.
let mut csr: [u8; 1] = [0xF0]; let mut csr: [u8; 1] = [0xF0];
csr[0].set_bits(1..3, desired_mode as u8); csr[0].set_bits(1..3, desired_mode as u8);
ad9959.interface.write(0, &csr)?; ad9959.interface.write(Register::CSR as u8, &csr)?;
// Configure the interface to the desired mode. // Configure the interface to the desired mode.
ad9959.interface.configure_mode(Mode::FourBitSerial)?; ad9959.interface.configure_mode(Mode::FourBitSerial)?;
@ -145,6 +146,13 @@ where
ad9959.interface.configure_mode(desired_mode)?; ad9959.interface.configure_mode(desired_mode)?;
// Read back the CSR to ensure it specifies the mode correctly.
let mut updated_csr: [u8; 1] = [0];
ad9959.interface.read(Register::CSR as u8, &mut updated_csr)?;
if updated_csr[0] != csr[0] {
return Err(Error::Check);
}
// Set the clock frequency to configure the device as necessary. // Set the clock frequency to configure the device as necessary.
ad9959.configure_system_clock(clock_frequency, multiplier)?; ad9959.configure_system_clock(clock_frequency, multiplier)?;
Ok(ad9959) Ok(ad9959)
@ -164,21 +172,21 @@ where
/// ///
/// Arguments: /// Arguments:
/// * `reference_clock_frequency` - The reference clock frequency provided to the AD9959 core. /// * `reference_clock_frequency` - The reference clock frequency provided to the AD9959 core.
/// * `prescaler` - The frequency prescaler of the system clock. Must be 1 or 4-20. /// * `multiplier` - The frequency multiplier of the system clock. Must be 1 or 4-20.
/// ///
/// Returns: /// Returns:
/// The actual frequency configured for the internal system clock. /// The actual frequency configured for the internal system clock.
pub fn configure_system_clock(&mut self, pub fn configure_system_clock(&mut self,
reference_clock_frequency: u32, reference_clock_frequency: f32,
prescaler: u8) -> Result<f64, Error<InterfaceE>> multiplier: u8) -> Result<f64, Error<InterfaceE>>
{ {
self.reference_clock_frequency = reference_clock_frequency; self.reference_clock_frequency = reference_clock_frequency;
if prescaler != 1 && (prescaler > 20 || prescaler < 4) { if multiplier != 1 && (multiplier > 20 || multiplier < 4) {
return Err(Error::Bounds); return Err(Error::Bounds);
} }
let frequency = prescaler as f64 * self.reference_clock_frequency as f64; let frequency = multiplier as f64 * self.reference_clock_frequency as f64;
if frequency > 500_000_000.0f64 { if frequency > 500_000_000.0f64 {
return Err(Error::Frequency); return Err(Error::Frequency);
} }
@ -186,17 +194,28 @@ where
// TODO: Update / disable any enabled channels? // TODO: Update / disable any enabled channels?
let mut fr1: [u8; 3] = [0, 0, 0]; let mut fr1: [u8; 3] = [0, 0, 0];
self.interface.read(Register::FR1 as u8, &mut fr1)?; self.interface.read(Register::FR1 as u8, &mut fr1)?;
fr1[0].set_bits(2..=6, prescaler); fr1[0].set_bits(2..=6, multiplier);
let vco_range = frequency > 255e6; let vco_range = frequency > 255e6;
fr1[0].set_bit(7, vco_range); fr1[0].set_bit(7, vco_range);
self.interface.write(Register::FR1 as u8, &fr1)?; self.interface.write(Register::FR1 as u8, &fr1)?;
self.system_clock_multiplier = prescaler; self.system_clock_multiplier = multiplier;
Ok(self.system_clock_frequency()) Ok(self.system_clock_frequency())
} }
pub fn get_reference_clock_frequency(&self) -> f32 {
self.reference_clock_frequency
}
pub fn get_reference_clock_multiplier(&mut self) -> Result<u8, Error<InterfaceE>> {
let mut fr1: [u8; 3] = [0, 0, 0];
self.interface.read(Register::FR1 as u8, &mut fr1)?;
Ok(fr1[0].get_bits(2..=6) as u8)
}
/// Perform a self-test of the communication interface. /// Perform a self-test of the communication interface.
/// ///
/// Note: /// Note:
@ -262,6 +281,13 @@ where
Ok(()) Ok(())
} }
pub fn is_enabled(&mut self, channel: Channel) -> Result<bool, Error<InterfaceE>> {
let mut csr: [u8; 1] = [0; 1];
self.interface.read(Register::CSR as u8, &mut csr)?;
Ok(csr[0].get_bit(channel as usize + 4))
}
fn modify_channel(&mut self, channel: Channel, register: Register, data: &[u8]) -> Result<(), Error<InterfaceE>> { fn modify_channel(&mut self, channel: Channel, register: Register, data: &[u8]) -> Result<(), Error<InterfaceE>> {
let mut csr: [u8; 1] = [0]; let mut csr: [u8; 1] = [0];
self.interface.read(Register::CSR as u8, &mut csr)?; self.interface.read(Register::CSR as u8, &mut csr)?;
@ -282,22 +308,48 @@ where
Ok(()) Ok(())
} }
fn read_channel(&mut self, channel: Channel, register: Register, mut data: &mut [u8]) -> Result<(), Error<InterfaceE>> {
let mut csr: [u8; 1] = [0];
self.interface.read(Register::CSR as u8, &mut csr)?;
let mut new_csr = csr;
new_csr[0].set_bits(4..8, 0);
new_csr[0].set_bit(4 + channel as usize, true);
self.interface.write(Register::CSR as u8, &new_csr)?;
self.interface.read(register as u8, &mut data)?;
// Restore the previous CSR. Note that the re-enable of the channel happens immediately, so
// the CSR update does not need to be latched.
self.interface.write(Register::CSR as u8, &csr)?;
Ok(())
}
/// Configure the phase of a specified channel. /// Configure the phase of a specified channel.
/// ///
/// Arguments: /// Arguments:
/// * `channel` - The channel to configure the frequency of. /// * `channel` - The channel to configure the frequency of.
/// * `phase_turns` - The desired phase offset in normalized turns. /// * `phase_turns` - The desired phase offset in turns.
/// ///
/// Returns: /// Returns:
/// The actual programmed phase offset of the channel in degrees. /// The actual programmed phase offset of the channel in turns.
pub fn set_phase(&mut self, channel: Channel, phase_turns: f32) -> Result<f32, Error<InterfaceE>> { pub fn set_phase(&mut self, channel: Channel, phase_turns: f32) -> Result<f32, Error<InterfaceE>> {
if phase_turns > 1.0 || phase_turns < 0.0 { let phase_offset: u16 = (phase_turns * (1 << 14) as f32) as u16 & 0x3FFFu16;
return Err(Error::Bounds);
self.modify_channel(channel, Register::CPOW0, &phase_offset.to_be_bytes())?;
Ok((phase_offset as f32) / ((1 << 14) as f32))
} }
let phase_offset: u16 = (phase_turns * 1u32.wrapping_shl(14) as f32) as u16; pub fn get_phase(&mut self, channel: Channel) -> Result<f32, Error<InterfaceE>> {
self.modify_channel(channel, Register::CPOW0, &phase_offset.to_be_bytes())?; let mut phase_offset: [u8; 2] = [0; 2];
Ok((phase_offset as f32 / 1u32.wrapping_shl(14) as f32) * 360.0) self.read_channel(channel, Register::CPOW0, &mut phase_offset)?;
let phase_offset = u16::from_be_bytes(phase_offset) & 0x3FFFu16;
Ok((phase_offset as f32) / ((1 << 14) as f32))
} }
/// Configure the amplitude of a specified channel. /// Configure the amplitude of a specified channel.
@ -313,17 +365,38 @@ where
return Err(Error::Bounds); return Err(Error::Bounds);
} }
let amplitude_control: u16 = (amplitude / 1u16.wrapping_shl(10) as f32) as u16; let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
let mut acr: [u8; 3] = [0, amplitude_control.to_be_bytes()[0], amplitude_control.to_be_bytes()[1]];
let mut acr: [u8; 3] = [0; 3];
// Enable the amplitude multiplier for the channel if required. The amplitude control has // Enable the amplitude multiplier for the channel if required. The amplitude control has
// full-scale at 0x3FF (amplitude of 1), so the multiplier should be disabled whenever // full-scale at 0x3FF (amplitude of 1), so the multiplier should be disabled whenever
// full-scale is used. // full-scale is used.
acr[1].set_bit(4, amplitude_control >= 1u16.wrapping_shl(10)); if amplitude_control < (1 << 10) {
let masked_control = amplitude_control & 0x3FF;
acr[1] = masked_control.to_be_bytes()[0];
acr[2] = masked_control.to_be_bytes()[1];
// Enable the amplitude multiplier
acr[1].set_bit(4, true);
}
self.modify_channel(channel, Register::ACR, &acr)?; self.modify_channel(channel, Register::ACR, &acr)?;
Ok(amplitude_control as f32 / 1_u16.wrapping_shl(10) as f32) Ok(amplitude_control as f32 / (1 << 10) as f32)
}
pub fn get_amplitude(&mut self, channel: Channel) -> Result<f32, Error<InterfaceE>> {
let mut acr: [u8; 3] = [0; 3];
self.read_channel(channel, Register::ACR, &mut acr)?;
if acr[1].get_bit(4) {
let amplitude_control: u16 = (((acr[1] as u16) << 8) | (acr[2] as u16)) & 0x3FF;
Ok(amplitude_control as f32 / (1 << 10) as f32)
} else {
Ok(1.0)
}
} }
/// Configure the frequency of a specified channel. /// Configure the frequency of a specified channel.
@ -347,4 +420,14 @@ where
self.modify_channel(channel, Register::CFTW0, &tuning_word.to_be_bytes())?; self.modify_channel(channel, Register::CFTW0, &tuning_word.to_be_bytes())?;
Ok((tuning_word as f64 / 1u64.wrapping_shl(32) as f64) * self.system_clock_frequency()) Ok((tuning_word as f64 / 1u64.wrapping_shl(32) as f64) * self.system_clock_frequency())
} }
pub fn get_frequency(&mut self, channel: Channel) -> Result<f64, Error<InterfaceE>> {
// Read the frequency tuning word for the channel.
let mut tuning_word: [u8; 4] = [0; 4];
self.read_channel(channel, Register::CFTW0, &mut tuning_word)?;
let tuning_word = u32::from_be_bytes(tuning_word);
// Convert the tuning word into a frequency.
Ok(tuning_word as f64 * self.system_clock_frequency() / ((1u64 << 32)) as f64)
}
} }

View File

@ -113,8 +113,8 @@ type AFE2 = afe::ProgrammableGainAmplifier<
macro_rules! route_request { macro_rules! route_request {
($request:ident, ($request:ident,
readable_attributes: [$(($read_attribute:tt, $getter:tt)),*], readable_attributes: [$($read_attribute:tt: $getter:tt),*],
modifiable_attributes: [$(($write_attribute:tt, $TYPE:ty, $setter:tt)),*]) => { modifiable_attributes: [$($write_attribute:tt: $TYPE:ty, $setter:tt),*]) => {
match $request.req { match $request.req {
server::AccessRequest::Read => { server::AccessRequest::Read => {
match $request.attribute { match $request.attribute {
@ -126,17 +126,13 @@ macro_rules! route_request {
"Failed to set attribute"), "Failed to set attribute"),
}; };
let encoded_data: String<U128> = match serde_json_core::to_string(&value) { let encoded_data: String<U256> = match serde_json_core::to_string(&value) {
Ok(data) => data, Ok(data) => data,
Err(_) => return server::Response::error($request.attribute, Err(_) => return server::Response::error($request.attribute,
"Failed to encode attribute value"), "Failed to encode attribute value"),
}; };
// Encoding data into a string surrounds it with qutotations. Because this server::Response::success($request.attribute, &encoded_data)
// value is then serialzed into another string, we remove the double
// quotations because they cannot be properly escaped.
server::Response::success($request.attribute,
&encoded_data[1..encoded_data.len()-1])
}, },
)* )*
_ => server::Response::error($request.attribute, "Unknown attribute") _ => server::Response::error($request.attribute, "Unknown attribute")
@ -146,22 +142,14 @@ macro_rules! route_request {
match $request.attribute { match $request.attribute {
$( $(
$write_attribute => { $write_attribute => {
// To avoid sending double quotations in the request, they are eliminated on let new_value = match serde_json_core::from_str::<$TYPE>(&$request.value) {
// the sender side. However, to properly deserialize the data, quotes need
// to be added back.
let mut value: String<U128> = String::new();
value.push('"').unwrap();
value.push_str($request.value).unwrap();
value.push('"').unwrap();
let new_value = match serde_json_core::from_str::<$TYPE>(value.as_str()) {
Ok(data) => data, Ok(data) => data,
Err(_) => return server::Response::error($request.attribute, Err(_) => return server::Response::error($request.attribute,
"Failed to decode value"), "Failed to decode value"),
}; };
match $setter(new_value) { match $setter(new_value) {
Ok(_) => server::Response::success($request.attribute, $request.value), Ok(_) => server::Response::success($request.attribute, &$request.value),
Err(_) => server::Response::error($request.attribute, Err(_) => server::Response::error($request.attribute,
"Failed to set attribute"), "Failed to set attribute"),
} }
@ -344,6 +332,17 @@ const APP: () = {
spi spi
}; };
let mut fp_led_0 = gpiod.pd5.into_push_pull_output();
let mut fp_led_1 = gpiod.pd6.into_push_pull_output();
let mut fp_led_2 = gpiog.pg4.into_push_pull_output();
let mut fp_led_3 = gpiod.pd12.into_push_pull_output();
fp_led_0.set_low().unwrap();
fp_led_1.set_low().unwrap();
fp_led_2.set_low().unwrap();
fp_led_3.set_low().unwrap();
let pounder_devices = { let pounder_devices = {
let ad9959 = { let ad9959 = {
let qspi_interface = { let qspi_interface = {
@ -375,7 +374,7 @@ const APP: () = {
io_update, io_update,
asm_delay, asm_delay,
ad9959::Mode::FourBitSerial, ad9959::Mode::FourBitSerial,
100_000_000, 100_000_000f32,
5).unwrap() 5).unwrap()
}; };
@ -426,16 +425,6 @@ const APP: () = {
adc2_in_p).unwrap() adc2_in_p).unwrap()
}; };
let mut fp_led_0 = gpiod.pd5.into_push_pull_output();
let mut fp_led_1 = gpiod.pd6.into_push_pull_output();
let mut fp_led_2 = gpiog.pg4.into_push_pull_output();
let mut fp_led_3 = gpiod.pd12.into_push_pull_output();
fp_led_0.set_low().unwrap();
fp_led_1.set_low().unwrap();
fp_led_2.set_low().unwrap();
fp_led_3.set_low().unwrap();
let mut eeprom_i2c = { let mut eeprom_i2c = {
let sda = gpiof.pf0.into_alternate_af4().set_open_drain(); let sda = gpiof.pf0.into_alternate_af4().set_open_drain();
let scl = gpiof.pf1.into_alternate_af4().set_open_drain(); let scl = gpiof.pf1.into_alternate_af4().set_open_drain();
@ -517,7 +506,7 @@ const APP: () = {
hal::dma::DMAREQ_ID::TIM2_CH2); hal::dma::DMAREQ_ID::TIM2_CH2);
// Configure timer 2 to trigger conversions for the ADC // Configure timer 2 to trigger conversions for the ADC
let mut timer2 = dp.TIM2.timer(500.khz(), &mut clocks); let mut timer2 = dp.TIM2.timer(50.khz(), &mut clocks);
timer2.configure_channel(hal::timer::Channel::One, 0.25); timer2.configure_channel(hal::timer::Channel::One, 0.25);
timer2.configure_channel(hal::timer::Channel::Two, 0.75); timer2.configure_channel(hal::timer::Channel::Two, 0.75);
@ -572,7 +561,7 @@ const APP: () = {
c.resources.dac1.send(output).unwrap(); c.resources.dac1.send(output).unwrap();
} }
#[idle(resources=[net_interface, mac_addr, eth_mac, iir_state, iir_ch, afe1, afe2])] #[idle(resources=[net_interface, pounder, mac_addr, eth_mac, iir_state, iir_ch, afe1, afe2])]
fn idle(mut c: idle::Context) -> ! { fn idle(mut c: idle::Context) -> ! {
let mut socket_set_entries: [_; 8] = Default::default(); let mut socket_set_entries: [_; 8] = Default::default();
@ -617,7 +606,7 @@ const APP: () = {
info!("Got request: {:?}", req); info!("Got request: {:?}", req);
route_request!(req, route_request!(req,
readable_attributes: [ readable_attributes: [
("stabilizer/iir/state", (|| { "stabilizer/iir/state": (|| {
let state = c.resources.iir_state.lock(|iir_state| let state = c.resources.iir_state.lock(|iir_state|
server::Status { server::Status {
t: time, t: time,
@ -628,13 +617,32 @@ const APP: () = {
}); });
Ok::<server::Status, ()>(state) Ok::<server::Status, ()>(state)
})), }),
("stabilizer/afe1/gain", (|| c.resources.afe1.get_gain())), "stabilizer/afe1/gain": (|| c.resources.afe1.get_gain()),
("stabilizer/afe2/gain", (|| c.resources.afe2.get_gain())) "stabilizer/afe2/gain": (|| c.resources.afe2.get_gain()),
"pounder/in0": (|| {
c.resources.pounder.get_input_channel_state(
pounder::Channel::In0)
}),
"pounder/in1": (|| {
c.resources.pounder.get_input_channel_state(
pounder::Channel::In1)
}),
"pounder/out0": (|| {
c.resources.pounder.get_output_channel_state(
pounder::Channel::Out0)
}),
"pounder/out1": (|| {
c.resources.pounder.get_output_channel_state(
pounder::Channel::Out1)
}),
"pounder/dds/clock": (|| {
c.resources.pounder.get_dds_clock_config()
})
], ],
modifiable_attributes: [ modifiable_attributes: [
("stabilizer/iir1/state", server::IirRequest, (|req: server::IirRequest| { "stabilizer/iir1/state": server::IirRequest, (|req: server::IirRequest| {
c.resources.iir_ch.lock(|iir_ch| { c.resources.iir_ch.lock(|iir_ch| {
if req.channel > 1 { if req.channel > 1 {
return Err(()); return Err(());
@ -644,8 +652,8 @@ const APP: () = {
Ok::<server::IirRequest, ()>(req) Ok::<server::IirRequest, ()>(req)
}) })
})), }),
("stabilizer/iir2/state", server::IirRequest, (|req: server::IirRequest| { "stabilizer/iir2/state": server::IirRequest, (|req: server::IirRequest| {
c.resources.iir_ch.lock(|iir_ch| { c.resources.iir_ch.lock(|iir_ch| {
if req.channel > 1 { if req.channel > 1 {
return Err(()); return Err(());
@ -655,13 +663,32 @@ const APP: () = {
Ok::<server::IirRequest, ()>(req) Ok::<server::IirRequest, ()>(req)
}) })
})), }),
("stabilizer/afe1/gain", afe::Gain, (|gain| { "pounder/in0": pounder::ChannelState, (|state| {
c.resources.pounder.set_channel_state(pounder::Channel::In0,
state)
}),
"pounder/in1": pounder::ChannelState, (|state| {
c.resources.pounder.set_channel_state(pounder::Channel::In1,
state)
}),
"pounder/out0": pounder::ChannelState, (|state| {
c.resources.pounder.set_channel_state(pounder::Channel::Out0,
state)
}),
"pounder/out1": pounder::ChannelState, (|state| {
c.resources.pounder.set_channel_state(pounder::Channel::Out1,
state)
}),
"pounder/dds/clock": pounder::DdsClockConfig, (|config| {
c.resources.pounder.configure_dds_clock(config)
}),
"stabilizer/afe1/gain": afe::Gain, (|gain| {
Ok::<(), ()>(c.resources.afe1.set_gain(gain)) Ok::<(), ()>(c.resources.afe1.set_gain(gain))
})), }),
("stabilizer/afe2/gain", afe::Gain, (|gain| { "stabilizer/afe2/gain": afe::Gain, (|gain| {
Ok::<(), ()>(c.resources.afe2.set_gain(gain)) Ok::<(), ()>(c.resources.afe2.set_gain(gain))
})) })
] ]
) )
}); });

View File

@ -1,8 +1,7 @@
use super::error::Error; use super::{Channel, Error};
use super::DdsChannel;
pub trait AttenuatorInterface { pub trait AttenuatorInterface {
fn modify(&mut self, attenuation: f32, channel: DdsChannel) -> Result<f32, Error> { fn set_attenuation(&mut self, channel: Channel, attenuation: f32) -> Result<f32, Error> {
if attenuation > 31.5 || attenuation < 0.0 { if attenuation > 31.5 || attenuation < 0.0 {
return Err(Error::Bounds); return Err(Error::Bounds);
} }
@ -14,28 +13,28 @@ pub trait AttenuatorInterface {
// Read all the channels, modify the channel of interest, and write all the channels back. // Read all the channels, modify the channel of interest, and write all the channels back.
// This ensures the staging register and the output register are always in sync. // This ensures the staging register and the output register are always in sync.
let mut channels = [0_u8; 4]; let mut channels = [0_u8; 4];
self.read_all(&mut channels)?; self.read_all_attenuators(&mut channels)?;
// The lowest 2 bits of the 8-bit shift register on the attenuator are ignored. Shift the // The lowest 2 bits of the 8-bit shift register on the attenuator are ignored. Shift the
// attenuator code into the upper 6 bits of the register value. Note that the attenuator // attenuator code into the upper 6 bits of the register value. Note that the attenuator
// treats inputs as active-low, so the code is inverted before writing. // treats inputs as active-low, so the code is inverted before writing.
channels[channel as usize] = !attenuation_code.wrapping_shl(2); channels[channel as usize] = (!attenuation_code) << 2;
self.write_all(&channels)?; self.write_all_attenuators(&channels)?;
// Finally, latch the output of the updated channel to force it into an active state. // Finally, latch the output of the updated channel to force it into an active state.
self.latch(channel)?; self.latch_attenuators(channel)?;
Ok(attenuation_code as f32 / 2.0) Ok(attenuation_code as f32 / 2.0)
} }
fn read(&mut self, channel: DdsChannel) -> Result<f32, Error> { fn get_attenuation(&mut self, channel: Channel) -> Result<f32, Error> {
let mut channels = [0_u8; 4]; let mut channels = [0_u8; 4];
// Reading the data always shifts data out of the staging registers, so we perform a // Reading the data always shifts data out of the staging registers, so we perform a
// duplicate write-back to ensure the staging register is always equal to the output // duplicate write-back to ensure the staging register is always equal to the output
// register. // register.
self.read_all(&mut channels)?; self.read_all_attenuators(&mut channels)?;
self.write_all(&channels)?; self.write_all_attenuators(&channels)?;
// The attenuation code is stored in the upper 6 bits of the register, where each LSB // The attenuation code is stored in the upper 6 bits of the register, where each LSB
// represents 0.5 dB. The attenuator stores the code as active-low, so inverting the result // represents 0.5 dB. The attenuator stores the code as active-low, so inverting the result
@ -43,15 +42,15 @@ pub trait AttenuatorInterface {
// dont-care bits) into an active-high state and then masking off the don't care bits. If // dont-care bits) into an active-high state and then masking off the don't care bits. If
// the shift occurs before the inversion, the upper 2 bits (which would then be don't // the shift occurs before the inversion, the upper 2 bits (which would then be don't
// care) would contain erroneous data. // care) would contain erroneous data.
let attenuation_code = (!channels[channel as usize]).wrapping_shr(2); let attenuation_code = (!channels[channel as usize]) >> 2;
// Convert the desired channel code into dB of attenuation. // Convert the desired channel code into dB of attenuation.
Ok(attenuation_code as f32 / 2.0) Ok(attenuation_code as f32 / 2.0)
} }
fn reset(&mut self) -> Result<(), Error>; fn reset_attenuators(&mut self) -> Result<(), Error>;
fn latch(&mut self, channel: DdsChannel) -> Result<(), Error>; fn latch_attenuators(&mut self, channel: Channel) -> Result<(), Error>;
fn read_all(&mut self, channels: &mut [u8; 4]) -> Result<(), Error>; fn read_all_attenuators(&mut self, channels: &mut [u8; 4]) -> Result<(), Error>;
fn write_all(&mut self, channels: &[u8; 4]) -> Result<(), Error>; fn write_all_attenuators(&mut self, channels: &[u8; 4]) -> Result<(), Error>;
} }

View File

@ -1,11 +0,0 @@
#[derive(Debug)]
pub enum Error {
Spi,
I2c,
DDS,
Qspi,
Bounds,
InvalidAddress,
InvalidChannel,
Adc,
}

View File

@ -1,16 +1,13 @@
use mcp23017; use mcp23017;
use ad9959; use ad9959;
pub mod error; use serde::{Serialize, Deserialize};
pub mod attenuators; mod attenuators;
mod rf_power; mod rf_power;
pub mod types;
use super::hal; use super::hal;
use error::Error;
use attenuators::AttenuatorInterface; use attenuators::AttenuatorInterface;
use types::{DdsChannel, InputChannel};
use rf_power::PowerMeasurementInterface; use rf_power::PowerMeasurementInterface;
use embedded_hal::{ use embedded_hal::{
@ -18,17 +15,79 @@ use embedded_hal::{
adc::OneShot adc::OneShot
}; };
const EXT_CLK_SEL_PIN: u8 = 8 + 7;
#[allow(dead_code)] #[allow(dead_code)]
const OSC_EN_N_PIN: u8 = 8 + 7; const OSC_EN_N_PIN: u8 = 8 + 6;
const EXT_CLK_SEL_PIN: u8 = 8 + 6;
const ATT_RST_N_PIN: u8 = 8 + 5; const ATT_RST_N_PIN: u8 = 8 + 5;
const ATT_LE0_PIN: u8 = 8 + 0;
const ATT_LE1_PIN: u8 = 8 + 1;
const ATT_LE2_PIN: u8 = 8 + 2;
const ATT_LE3_PIN: u8 = 8 + 3; const ATT_LE3_PIN: u8 = 8 + 3;
const ATT_LE2_PIN: u8 = 8 + 2;
const ATT_LE1_PIN: u8 = 8 + 1;
const ATT_LE0_PIN: u8 = 8 + 0;
#[derive(Debug, Copy, Clone)]
pub enum Error {
Spi,
I2c,
Dds,
Qspi,
Bounds,
InvalidAddress,
InvalidChannel,
Adc,
}
#[derive(Debug, Copy, Clone)]
pub enum Channel {
In0,
In1,
Out0,
Out1,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct DdsChannelState {
pub phase_offset: f32,
pub frequency: f64,
pub amplitude: f32,
pub enabled: bool,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct ChannelState {
pub parameters: DdsChannelState,
pub attenuation: f32,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct InputChannelState {
pub attenuation: f32,
pub power: f32,
pub mixer: DdsChannelState,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct OutputChannelState {
pub attenuation: f32,
pub channel: DdsChannelState,
}
#[derive(Serialize, Deserialize, Copy, Clone, Debug)]
pub struct DdsClockConfig {
pub multiplier: u8,
pub reference_clock: f32,
pub external_clock: bool,
}
impl Into<ad9959::Channel> for Channel {
fn into(self) -> ad9959::Channel {
match self {
Channel::In0 => ad9959::Channel::Two,
Channel::In1 => ad9959::Channel::Four,
Channel::Out0 => ad9959::Channel::One,
Channel::Out1 => ad9959::Channel::Three,
}
}
}
pub struct QspiInterface { pub struct QspiInterface {
pub qspi: hal::qspi::Qspi, pub qspi: hal::qspi::Qspi,
@ -78,32 +137,40 @@ impl ad9959::Interface for QspiInterface {
// Encode the address into the first 4 bytes. // Encode the address into the first 4 bytes.
for address_bit in 0..8 { for address_bit in 0..8 {
let offset: u8 = { let offset: u8 = {
if address_bit % 2 == 0 { if address_bit % 2 != 0 {
4 4
} else { } else {
0 0
} }
}; };
if addr & address_bit != 0 { // Encode MSB first. Least significant bits are placed at the most significant
encoded_data[(address_bit >> 1) as usize] |= 1 << offset; // byte.
let byte_position = 3 - (address_bit >> 1) as usize;
if addr & (1 << address_bit) != 0 {
encoded_data[byte_position] |= 1 << offset;
} }
} }
// Encode the data into the remaining bytes. // Encode the data into the remaining bytes.
for byte_index in 0..data.len() { for byte_index in 0..data.len() {
let byte = data[byte_index]; let byte = data[byte_index];
for address_bit in 0..8 { for bit in 0..8 {
let offset: u8 = { let offset: u8 = {
if address_bit % 2 == 0 { if bit % 2 != 0 {
4 4
} else { } else {
0 0
} }
}; };
if byte & address_bit != 0 { // Encode MSB first. Least significant bits are placed at the most
encoded_data[(byte_index + 1) * 4 + (address_bit >> 1) as usize] |= 1 << offset; // significant byte.
let byte_position = 3 - (bit >> 1) as usize;
if byte & (1 << bit) != 0 {
encoded_data[(byte_index + 1) * 4 + byte_position] |= 1 << offset;
} }
} }
} }
@ -129,9 +196,8 @@ impl ad9959::Interface for QspiInterface {
return Err(Error::InvalidAddress); return Err(Error::InvalidAddress);
} }
// It is not possible to read data from the AD9959 in single bit two wire mode because the // This implementation only supports operation (read) in four-bit-serial mode.
// QSPI interface assumes that data is always received on IO1. if self.mode != ad9959::Mode::FourBitSerial {
if self.mode == ad9959::Mode::SingleBitTwoWire {
return Err(Error::Qspi); return Err(Error::Qspi);
} }
@ -178,27 +244,100 @@ where
// Configure power-on-default state for pounder. All LEDs are on, on-board oscillator // Configure power-on-default state for pounder. All LEDs are on, on-board oscillator
// selected, attenuators out of reset. // selected, attenuators out of reset.
devices.mcp23017.write_gpio(mcp23017::Port::GPIOA, 0xF).map_err(|_| Error::I2c)?; devices.mcp23017.write_gpio(mcp23017::Port::GPIOA, 0x3F).map_err(|_| Error::I2c)?;
devices.mcp23017.write_gpio(mcp23017::Port::GPIOB, devices.mcp23017.write_gpio(mcp23017::Port::GPIOB, 1 << 5).map_err(|_| Error::I2c)?;
1_u8.wrapping_shl(5)).map_err(|_| Error::I2c)?;
devices.mcp23017.all_pin_mode(mcp23017::PinMode::OUTPUT).map_err(|_| Error::I2c)?; devices.mcp23017.all_pin_mode(mcp23017::PinMode::OUTPUT).map_err(|_| Error::I2c)?;
// Select the on-board clock with a 5x prescaler (500MHz). // Select the on-board clock with a 5x prescaler (500MHz).
devices.select_onboard_clock(5u8)?; devices.select_onboard_clock(4u8)?;
Ok(devices) Ok(devices)
} }
pub fn select_external_clock(&mut self, frequency: u32, prescaler: u8) -> Result<(), Error>{ fn select_external_clock(&mut self, frequency: f32, prescaler: u8) -> Result<(), Error>{
self.mcp23017.digital_write(EXT_CLK_SEL_PIN, true).map_err(|_| Error::I2c)?; self.mcp23017.digital_write(EXT_CLK_SEL_PIN, true).map_err(|_| Error::I2c)?;
self.ad9959.configure_system_clock(frequency, prescaler).map_err(|_| Error::DDS)?; self.ad9959.configure_system_clock(frequency, prescaler).map_err(|_| Error::Dds)?;
Ok(()) Ok(())
} }
pub fn select_onboard_clock(&mut self, prescaler: u8) -> Result<(), Error> { fn select_onboard_clock(&mut self, prescaler: u8) -> Result<(), Error> {
self.mcp23017.digital_write(EXT_CLK_SEL_PIN, false).map_err(|_| Error::I2c)?; self.mcp23017.digital_write(EXT_CLK_SEL_PIN, false).map_err(|_| Error::I2c)?;
self.ad9959.configure_system_clock(100_000_000, prescaler).map_err(|_| Error::DDS)?; self.ad9959.configure_system_clock(100_000_000f32, prescaler).map_err(|_| Error::Dds)?;
Ok(())
}
pub fn configure_dds_clock(&mut self, config: DdsClockConfig) -> Result<(), Error> {
if config.external_clock {
self.select_external_clock(config.reference_clock, config.multiplier)
} else {
self.select_onboard_clock(config.multiplier)
}
}
pub fn get_dds_clock_config(&mut self) -> Result<DdsClockConfig, Error> {
let external_clock = self.mcp23017.digital_read(EXT_CLK_SEL_PIN).map_err(|_| Error::I2c)?;
let multiplier = self.ad9959.get_reference_clock_multiplier().map_err(|_| Error::Dds)?;
let reference_clock = self.ad9959.get_reference_clock_frequency();
Ok(DdsClockConfig{multiplier, reference_clock, external_clock})
}
pub fn get_input_channel_state(&mut self, channel: Channel) -> Result<InputChannelState, Error> {
match channel {
Channel::In0 | Channel::In1 => {
let channel_state = self.get_dds_channel_state(channel)?;
let attenuation = self.get_attenuation(channel)?;
let power = self.measure_power(channel)?;
Ok(InputChannelState {
attenuation: attenuation,
power: power,
mixer: channel_state
})
}
_ => Err(Error::InvalidChannel),
}
}
fn get_dds_channel_state(&mut self, channel: Channel) -> Result<DdsChannelState, Error> {
let frequency = self.ad9959.get_frequency(channel.into()).map_err(|_| Error::Dds)?;
let phase_offset = self.ad9959.get_phase(channel.into()).map_err(|_| Error::Dds)?;
let amplitude = self.ad9959.get_amplitude(channel.into()).map_err(|_| Error::Dds)?;
let enabled = self.ad9959.is_enabled(channel.into()).map_err(|_| Error::Dds)?;
Ok(DdsChannelState {phase_offset, frequency, amplitude, enabled})
}
pub fn get_output_channel_state(&mut self, channel: Channel) -> Result<OutputChannelState, Error> {
match channel {
Channel::Out0 | Channel::Out1 => {
let channel_state = self.get_dds_channel_state(channel)?;
let attenuation = self.get_attenuation(channel)?;
Ok(OutputChannelState {
attenuation: attenuation,
channel: channel_state,
})
}
_ => Err(Error::InvalidChannel),
}
}
pub fn set_channel_state(&mut self, channel: Channel, state: ChannelState) -> Result<(), Error> {
self.ad9959.set_frequency(channel.into(), state.parameters.frequency).map_err(|_| Error::Dds)?;
self.ad9959.set_phase(channel.into(), state.parameters.phase_offset).map_err(|_| Error::Dds)?;
self.ad9959.set_amplitude(channel.into(), state.parameters.amplitude).map_err(|_| Error::Dds)?;
if state.parameters.enabled {
self.ad9959.enable_channel(channel.into()).map_err(|_| Error::Dds)?;
} else {
self.ad9959.disable_channel(channel.into()).map_err(|_| Error::Dds)?;
}
self.set_attenuation(channel, state.attenuation)?;
Ok(()) Ok(())
} }
@ -206,21 +345,21 @@ where
impl<DELAY> AttenuatorInterface for PounderDevices<DELAY> impl<DELAY> AttenuatorInterface for PounderDevices<DELAY>
{ {
fn reset(&mut self) -> Result<(), Error> { fn reset_attenuators(&mut self) -> Result<(), Error> {
self.mcp23017.digital_write(ATT_RST_N_PIN, true).map_err(|_| Error::I2c)?; self.mcp23017.digital_write(ATT_RST_N_PIN, false).map_err(|_| Error::I2c)?;
// TODO: Measure the I2C transaction speed to the RST pin to ensure that the delay is // TODO: Measure the I2C transaction speed to the RST pin to ensure that the delay is
// sufficient. Document the delay here. // sufficient. Document the delay here.
self.mcp23017.digital_write(ATT_RST_N_PIN, false).map_err(|_| Error::I2c)?; self.mcp23017.digital_write(ATT_RST_N_PIN, true).map_err(|_| Error::I2c)?;
Ok(()) Ok(())
} }
fn latch(&mut self, channel: DdsChannel) -> Result<(), Error> { fn latch_attenuators(&mut self, channel: Channel) -> Result<(), Error> {
let pin = match channel { let pin = match channel {
DdsChannel::Zero => ATT_LE1_PIN, Channel::In0 => ATT_LE0_PIN,
DdsChannel::One => ATT_LE0_PIN, Channel::In1 => ATT_LE2_PIN,
DdsChannel::Two => ATT_LE3_PIN, Channel::Out0 => ATT_LE1_PIN,
DdsChannel::Three => ATT_LE2_PIN, Channel::Out1 => ATT_LE3_PIN,
}; };
self.mcp23017.digital_write(pin, true).map_err(|_| Error::I2c)?; self.mcp23017.digital_write(pin, true).map_err(|_| Error::I2c)?;
@ -231,13 +370,13 @@ impl<DELAY> AttenuatorInterface for PounderDevices<DELAY>
Ok(()) Ok(())
} }
fn read_all(&mut self, channels: &mut [u8; 4]) -> Result<(), Error> { fn read_all_attenuators(&mut self, channels: &mut [u8; 4]) -> Result<(), Error> {
self.attenuator_spi.transfer(channels).map_err(|_| Error::Spi)?; self.attenuator_spi.transfer(channels).map_err(|_| Error::Spi)?;
Ok(()) Ok(())
} }
fn write_all(&mut self, channels: &[u8; 4]) -> Result<(), Error> { fn write_all_attenuators(&mut self, channels: &[u8; 4]) -> Result<(), Error> {
let mut result = [0_u8; 4]; let mut result = [0_u8; 4];
result.clone_from_slice(channels); result.clone_from_slice(channels);
self.attenuator_spi.transfer(&mut result).map_err(|_| Error::Spi)?; self.attenuator_spi.transfer(&mut result).map_err(|_| Error::Spi)?;
@ -247,16 +386,17 @@ impl<DELAY> AttenuatorInterface for PounderDevices<DELAY>
} }
impl<DELAY> PowerMeasurementInterface for PounderDevices<DELAY> { impl<DELAY> PowerMeasurementInterface for PounderDevices<DELAY> {
fn sample_converter(&mut self, channel: InputChannel) -> Result<f32, Error> { fn sample_converter(&mut self, channel: Channel) -> Result<f32, Error> {
let adc_scale = match channel { let adc_scale = match channel {
InputChannel::Zero => { Channel::In0 => {
let adc_reading: u32 = self.adc1.read(&mut self.adc1_in_p).map_err(|_| Error::Adc)?; let adc_reading: u32 = self.adc1.read(&mut self.adc1_in_p).map_err(|_| Error::Adc)?;
adc_reading as f32 / self.adc1.max_sample() as f32 adc_reading as f32 / self.adc1.max_sample() as f32
}, },
InputChannel::One => { Channel::In1 => {
let adc_reading: u32 = self.adc2.read(&mut self.adc2_in_p).map_err(|_| Error::Adc)?; let adc_reading: u32 = self.adc2.read(&mut self.adc2_in_p).map_err(|_| Error::Adc)?;
adc_reading as f32 / self.adc2.max_sample() as f32 adc_reading as f32 / self.adc2.max_sample() as f32
}, },
_ => return Err(Error::InvalidChannel),
}; };
// Convert analog percentage to voltage. // Convert analog percentage to voltage.

View File

@ -1,10 +1,9 @@
use super::Error; use super::{Error, Channel};
use super::InputChannel;
pub trait PowerMeasurementInterface { pub trait PowerMeasurementInterface {
fn sample_converter(&mut self, channel: InputChannel) -> Result<f32, Error>; fn sample_converter(&mut self, channel: Channel) -> Result<f32, Error>;
fn measure_power(&mut self, channel: InputChannel) -> Result<f32, Error> { fn measure_power(&mut self, channel: Channel) -> Result<f32, Error> {
let analog_measurement = self.sample_converter(channel)?; let analog_measurement = self.sample_converter(channel)?;
// The AD8363 with VSET connected to VOUT provides an output voltage of 51.7mV / dB at // The AD8363 with VSET connected to VOUT provides an output voltage of 51.7mV / dB at

View File

@ -1,16 +0,0 @@
#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
pub enum DdsChannel {
Zero,
One,
Two,
Three,
}
#[allow(dead_code)]
#[derive(Debug, Copy, Clone)]
pub enum InputChannel {
Zero,
One,
}

View File

@ -27,10 +27,10 @@ pub enum AccessRequest {
} }
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
pub struct Request<'a, 'b> { pub struct Request<'a> {
pub req: AccessRequest, pub req: AccessRequest,
pub attribute: &'a str, pub attribute: &'a str,
pub value: &'b str, pub value: String<U256>,
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
@ -42,24 +42,74 @@ pub struct IirRequest {
#[derive(Serialize)] #[derive(Serialize)]
pub struct Response { pub struct Response {
code: i32, code: i32,
attribute: String<U128>, attribute: String<U256>,
value: String<U128>, value: String<U256>,
}
impl<'a> Request<'a> {
pub fn restore_value(&mut self) {
let mut new_value: String<U256> = String::new();
for byte in self.value.as_str().chars() {
if byte == '\'' {
new_value.push('"').unwrap();
} else {
new_value.push(byte).unwrap();
}
}
self.value = new_value;
}
} }
impl Response { impl Response {
fn sanitize_value(&mut self) {
let mut new_value: String<U256> = String::new();
for byte in self.value.as_str().chars() {
if byte == '"' {
new_value.push('\'').unwrap();
} else {
new_value.push(byte).unwrap();
}
}
self.value = new_value;
}
fn wrap_and_sanitize_value(&mut self) {
let mut new_value: String<U256> = String::new();
new_value.push('\'').unwrap();
for byte in self.value.as_str().chars() {
if byte == '"' {
new_value.push('\'').unwrap();
} else {
new_value.push(byte).unwrap();
}
}
new_value.push('\'').unwrap();
self.value = new_value;
}
pub fn success<'a, 'b>(attribute: &'a str, value: &'b str) -> Self pub fn success<'a, 'b>(attribute: &'a str, value: &'b str) -> Self
{ {
Self { code: 200, attribute: String::from(attribute), value: String::from(value)} let mut res = Self { code: 200, attribute: String::from(attribute), value: String::from(value)};
res.sanitize_value();
res
} }
pub fn error<'a, 'b>(attribute: &'a str, message: &'b str) -> Self pub fn error<'a, 'b>(attribute: &'a str, message: &'b str) -> Self
{ {
Self { code: 400, attribute: String::from(attribute), value: String::from(message)} let mut res = Self { code: 400, attribute: String::from(attribute), value: String::from(message)};
res.wrap_and_sanitize_value();
res
} }
pub fn custom<'a>(code: i32, message : &'a str) -> Self pub fn custom<'a>(code: i32, message : &'a str) -> Self
{ {
Self { code: code, attribute: String::from(""), value: String::from(message)} let mut res = Self { code: code, attribute: String::from(""), value: String::from(message)};
res.wrap_and_sanitize_value();
res
} }
} }
@ -73,7 +123,7 @@ pub struct Status {
} }
pub fn json_reply<T: Serialize>(socket: &mut net::socket::TcpSocket, msg: &T) { pub fn json_reply<T: Serialize>(socket: &mut net::socket::TcpSocket, msg: &T) {
let mut u: String<U128> = to_string(msg).unwrap(); let mut u: String<U512> = to_string(msg).unwrap();
u.push('\n').unwrap(); u.push('\n').unwrap();
socket.write_str(&u).unwrap(); socket.write_str(&u).unwrap();
} }
@ -122,7 +172,8 @@ impl Server {
} else { } else {
let r = from_slice::<Request>(&self.data[..self.data.len() - 1]); let r = from_slice::<Request>(&self.data[..self.data.len() - 1]);
match r { match r {
Ok(res) => { Ok(mut res) => {
res.restore_value();
let response = f(&res); let response = f(&res);
json_reply(socket, &response); json_reply(socket, &response);
}, },