Adding WIP QSPI streaming

master
Ryan Summers 2020-10-21 10:17:22 +02:00
parent 66c917b576
commit db182b923d
5 changed files with 102 additions and 20 deletions

View File

@ -59,9 +59,8 @@ features = ["stm32h743v"]
[dependencies.stm32h7xx-hal]
features = ["stm32h743v", "rt", "unproven"]
[patch.crates-io]
stm32h7xx-hal = { git = "https://github.com/quartiq/stm32h7xx-hal.git", branch = "feature/pounder-support" }
git = "https://github.com/quartiq/stm32h7xx-hal.git"
branch = "feature/pounder-support"
[features]
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]

View File

@ -376,9 +376,6 @@ where
// Latch the configuration and 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.latch_configuration()?;
self.interface
.write(Register::CSR as u8, &csr)
.map_err(|_| Error::Interface)?;
Ok(())
}
@ -571,4 +568,69 @@ where
Ok(tuning_word as f64 * self.system_clock_frequency()
/ (1u64 << 32) as f64)
}
pub fn write_profile(&mut self, channel: Channel, freq: f64, turns: f32, amplitude: f32) -> Result<(), Error> {
// The function for channel frequency is `f_out = FTW * f_s / 2^32`, where FTW is the
// frequency tuning word and f_s is the system clock rate.
let tuning_word: u32 =
((freq as f64 / self.system_clock_frequency())
* 1u64.wrapping_shl(32) as f64) as u32;
let phase_offset: u16 = (turns * (1 << 14) as f32) as u16 & 0x3FFFu16;
let amplitude_control: u16 = (amplitude * (1 << 10) as f32) as u16;
let mut acr: [u8; 3] = [0; 3];
// 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 is used.
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_closure(channel, |interface| {
let mut data: [u8; 11] = [0; 11];
data[0..2].copy_from_slice(&phase_offset.to_be_bytes());
data[2] = Register::CFTW0 as u8;
data[3..7].copy_from_slice(&tuning_word.to_be_bytes());
data[7] = Register::ACR as u8;
data[8..11].copy_from_slice(&acr);
interface.write(Register::CPOW0 as u8, &data).map_err(|_| Error::Interface)
})?;
Ok(())
}
fn modify_channel_closure<F>(&mut self, channel: Channel, f: F) -> Result<(), Error>
where
F: FnOnce(&mut INTERFACE) -> Result<(), Error>,
{
// Disable all other outputs so that we can update the configuration register of only the
// specified channel.
let mut csr: [u8; 1] = [0];
self.interface
.read(Register::CSR as u8, &mut csr)
.map_err(|_| Error::Interface)?;
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)
.map_err(|_| Error::Interface)?;
let result = f(&mut self.interface);
// Latch the configuration and 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.latch_configuration()?;
result
}
}

View File

@ -91,11 +91,11 @@ def main():
# A sample configuration for an output channel.
channel_config = {
'attenuation': 31.5,
'attenuation': 0.0,
'parameters': {
'phase_offset': 0.5,
'frequency': 100.0e6,
'amplitude': 0.2,
'amplitude': 1.0,
'enabled': True,
}
}

View File

@ -187,8 +187,7 @@ const APP: () = {
'static,
'static,
'static,
ethernet::EthernetDMA<'static>,
>,
ethernet::EthernetDMA<'static>>,
eth_mac: ethernet::EthernetMAC,
mac_addr: net::wire::EthernetAddress,
@ -654,7 +653,7 @@ const APP: () = {
);
// 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::Two, 0.75);
@ -746,6 +745,35 @@ const APP: () = {
// TODO: Replace with reference to CPU clock from CCDR.
next_ms += 400_000.cycles();
match c.resources.pounder {
Some(pounder) => {
let state = pounder::ChannelState {
parameters: pounder::DdsChannelState {
phase_offset: 0.0,
frequency: 100_000_000.0,
amplitude: 1.0,
enabled: true,
},
attenuation: 10.0,
};
let state1 = pounder::ChannelState {
parameters: pounder::DdsChannelState {
phase_offset: 0.5,
frequency: 50_000_000.0,
amplitude: 1.0,
enabled: true,
},
attenuation: 10.0,
};
pounder.set_channel_state(pounder::Channel::Out0, state).unwrap();
pounder.set_channel_state(pounder::Channel::Out1, state1).unwrap();
},
_ => panic!("Failed"),
}
loop {
let tick = Instant::now() > next_ms;

View File

@ -474,15 +474,8 @@ where
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)?;
self.ad9959.write_profile(channel.into(), state.parameters.frequency,
state.parameters.phase_offset, state.parameters.amplitude).map_err(|_| Error::Dds)?;
if state.parameters.enabled {
self.ad9959