Refactoring DDS output control
This commit is contained in:
parent
1c8e385e6d
commit
585613f48f
118
src/main.rs
118
src/main.rs
|
@ -592,44 +592,10 @@ const APP: () = {
|
|||
let adc1_in_p = gpiof.pf11.into_analog();
|
||||
let adc2_in_p = gpiof.pf14.into_analog();
|
||||
|
||||
let io_update_trigger = {
|
||||
let _io_update = gpiog
|
||||
.pg7
|
||||
.into_alternate_af2()
|
||||
.set_speed(hal::gpio::Speed::VeryHigh);
|
||||
|
||||
// Configure the IO_Update signal for the DDS.
|
||||
let mut hrtimer = hrtimer::HighResTimerE::new(
|
||||
dp.HRTIM_TIME,
|
||||
dp.HRTIM_MASTER,
|
||||
dp.HRTIM_COMMON,
|
||||
ccdr.clocks,
|
||||
ccdr.peripheral.HRTIM,
|
||||
);
|
||||
|
||||
// IO_Update should be latched for 50ns after the QSPI profile write. Profile writes
|
||||
// are always 16 bytes, with 2 cycles required per byte, coming out to a total of 32
|
||||
// QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an
|
||||
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
|
||||
// the QSPI write, which can take approximately 120nS, so there is additional
|
||||
// margin.
|
||||
hrtimer.configure_single_shot(
|
||||
hrtimer::Channel::Two,
|
||||
50_e-9,
|
||||
900_e-9,
|
||||
);
|
||||
|
||||
// Ensure that we have enough time for an IO-update every sample.
|
||||
assert!(1.0 / (1000 * SAMPLE_FREQUENCY_KHZ) as f32 > 900_e-9);
|
||||
|
||||
hrtimer
|
||||
};
|
||||
|
||||
Some(
|
||||
pounder::PounderDevices::new(
|
||||
io_expander,
|
||||
ad9959,
|
||||
io_update_trigger,
|
||||
spi,
|
||||
adc1,
|
||||
adc2,
|
||||
|
@ -763,13 +729,46 @@ const APP: () = {
|
|||
cp.DWT.enable_cycle_counter();
|
||||
|
||||
let dds_output = {
|
||||
let io_update_trigger = {
|
||||
let _io_update = gpiog
|
||||
.pg7
|
||||
.into_alternate_af2()
|
||||
.set_speed(hal::gpio::Speed::VeryHigh);
|
||||
|
||||
// Configure the IO_Update signal for the DDS.
|
||||
let mut hrtimer = hrtimer::HighResTimerE::new(
|
||||
dp.HRTIM_TIME,
|
||||
dp.HRTIM_MASTER,
|
||||
dp.HRTIM_COMMON,
|
||||
ccdr.clocks,
|
||||
ccdr.peripheral.HRTIM,
|
||||
);
|
||||
|
||||
// IO_Update should be latched for 50ns after the QSPI profile write. Profile writes
|
||||
// are always 16 bytes, with 2 cycles required per byte, coming out to a total of 32
|
||||
// QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an
|
||||
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
|
||||
// the QSPI write, which can take approximately 120nS, so there is additional
|
||||
// margin.
|
||||
hrtimer.configure_single_shot(
|
||||
hrtimer::Channel::Two,
|
||||
50_e-9,
|
||||
900_e-9,
|
||||
);
|
||||
|
||||
// Ensure that we have enough time for an IO-update every sample.
|
||||
assert!(1.0 / (1000 * SAMPLE_FREQUENCY_KHZ) as f32 > 900_e-9);
|
||||
|
||||
hrtimer
|
||||
};
|
||||
|
||||
let timer3 = dp.TIM3.timer(
|
||||
SAMPLE_FREQUENCY_KHZ.khz(),
|
||||
ccdr.peripheral.TIM3,
|
||||
&ccdr.clocks,
|
||||
);
|
||||
|
||||
DdsOutput::new(timer3)
|
||||
DdsOutput::new(timer3, io_update_trigger)
|
||||
};
|
||||
|
||||
// Start sampling ADCs.
|
||||
|
@ -792,14 +791,9 @@ const APP: () = {
|
|||
}
|
||||
}
|
||||
|
||||
#[task(binds = TIM3, resources=[dds_output, pounder], priority = 3)]
|
||||
#[task(binds = TIM3, resources=[dds_output], priority = 3)]
|
||||
fn dds_update(c: dds_update::Context) {
|
||||
if let Some(pounder) = c.resources.pounder {
|
||||
if let Some(profile) = c.resources.dds_output.update_handler() {
|
||||
pounder.ad9959.interface.write_profile(profile).unwrap();
|
||||
pounder.io_update_trigger.trigger();
|
||||
}
|
||||
}
|
||||
c.resources.dds_output.update_handler();
|
||||
}
|
||||
|
||||
#[task(binds=DMA1_STR3, resources=[adcs, dacs, pounder, dds_output, iir_state, iir_ch], priority=2)]
|
||||
|
@ -828,8 +822,7 @@ const APP: () = {
|
|||
};
|
||||
|
||||
let dds_output = &mut c.resources.dds_output;
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
if let Some(pounder) = pounder {
|
||||
if let Some(pounder) = c.resources.pounder {
|
||||
dds_output.lock(|dds_output| {
|
||||
let profile = pounder
|
||||
.ad9959
|
||||
|
@ -843,7 +836,6 @@ const APP: () = {
|
|||
dds_output.push(profile);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
c.resources.dacs.next_data(&dac0, &dac1);
|
||||
|
@ -944,42 +936,6 @@ const APP: () = {
|
|||
Ok::<server::IirRequest, ()>(req)
|
||||
})
|
||||
}),
|
||||
"pounder/in0": pounder::ChannelState, (|state| {
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::In0, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
}),
|
||||
"pounder/in1": pounder::ChannelState, (|state| {
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::In1, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
}),
|
||||
"pounder/out0": pounder::ChannelState, (|state| {
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::Out0, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
}),
|
||||
"pounder/out1": pounder::ChannelState, (|state| {
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::Out1, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
}),
|
||||
"pounder/dds/clock": pounder::DdsClockConfig, (|config| {
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
|
|
|
@ -7,7 +7,6 @@ mod rf_power;
|
|||
pub use dds_output::DdsOutput;
|
||||
|
||||
use super::hal;
|
||||
use super::hrtimer::HighResTimerE;
|
||||
|
||||
use attenuators::AttenuatorInterface;
|
||||
use rf_power::PowerMeasurementInterface;
|
||||
|
@ -37,6 +36,7 @@ pub enum Error {
|
|||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(dead_code)]
|
||||
pub enum Channel {
|
||||
In0,
|
||||
In1,
|
||||
|
@ -291,7 +291,6 @@ impl ad9959::Interface for QspiInterface {
|
|||
/// A structure containing implementation for Pounder hardware.
|
||||
pub struct PounderDevices {
|
||||
pub ad9959: ad9959::Ad9959<QspiInterface>,
|
||||
pub io_update_trigger: HighResTimerE,
|
||||
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
||||
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
||||
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
||||
|
@ -306,7 +305,6 @@ impl PounderDevices {
|
|||
/// Args:
|
||||
/// * `ad9959` - The DDS driver for the pounder hardware.
|
||||
/// * `attenuator_spi` - A SPI interface to control digital attenuators.
|
||||
/// * `io_update_timer` - The HRTimer with the IO_update signal connected to the output.
|
||||
/// * `adc1` - The ADC1 peripheral for measuring power.
|
||||
/// * `adc2` - The ADC2 peripheral for measuring power.
|
||||
/// * `adc1_in_p` - The input channel for the RF power measurement on IN0.
|
||||
|
@ -314,7 +312,6 @@ impl PounderDevices {
|
|||
pub fn new(
|
||||
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
|
||||
ad9959: ad9959::Ad9959<QspiInterface>,
|
||||
io_update_trigger: HighResTimerE,
|
||||
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
|
||||
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
|
||||
adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>,
|
||||
|
@ -323,7 +320,6 @@ impl PounderDevices {
|
|||
) -> Result<Self, Error> {
|
||||
let mut devices = Self {
|
||||
mcp23017,
|
||||
io_update_trigger,
|
||||
ad9959,
|
||||
attenuator_spi,
|
||||
adc1,
|
||||
|
@ -431,33 +427,6 @@ impl PounderDevices {
|
|||
external_clock,
|
||||
})
|
||||
}
|
||||
|
||||
/// Configure a DDS channel.
|
||||
///
|
||||
/// Args:
|
||||
/// * `channel` - The pounder channel to configure.
|
||||
/// * `state` - The state to configure the channel for.
|
||||
pub fn set_channel_state(
|
||||
&mut self,
|
||||
channel: Channel,
|
||||
state: ChannelState,
|
||||
) -> Result<(), Error> {
|
||||
let profile = self
|
||||
.ad9959
|
||||
.serialize_profile(
|
||||
channel.into(),
|
||||
state.parameters.frequency,
|
||||
state.parameters.phase_offset,
|
||||
state.parameters.amplitude,
|
||||
)
|
||||
.map_err(|_| Error::Dds)?;
|
||||
self.ad9959.interface.write_profile(profile).unwrap();
|
||||
self.io_update_trigger.trigger();
|
||||
|
||||
self.set_attenuation(channel, state.attenuation)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl AttenuatorInterface for PounderDevices {
|
||||
|
|
Loading…
Reference in New Issue