Adding support for hardware IO_update
This commit is contained in:
parent
c97e4d9d20
commit
fca38e5d63
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -567,7 +567,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "stm32h7xx-hal"
|
||||
version = "0.8.0"
|
||||
source = "git+https://github.com/quartiq/stm32h7xx-hal?branch=feature/stabilizer-dma#5fbbfa9352f720994c210e5c21601f3acf9dc40c"
|
||||
source = "git+https://github.com/quartiq/stm32h7xx-hal?branch=feature/stabilizer-dma#8516690d4f35bc4bb184eba2ee8b48d4490ec85b"
|
||||
dependencies = [
|
||||
"bare-metal 1.0.0",
|
||||
"cast",
|
||||
|
@ -104,6 +104,7 @@ impl<I: Interface> Ad9959<I> {
|
||||
pub fn new(
|
||||
interface: I,
|
||||
reset_pin: &mut impl OutputPin,
|
||||
io_update: &mut impl OutputPin,
|
||||
delay: &mut impl DelayMs<u8>,
|
||||
desired_mode: Mode,
|
||||
clock_frequency: f32,
|
||||
@ -119,6 +120,8 @@ impl<I: Interface> Ad9959<I> {
|
||||
// Reset the AD9959
|
||||
reset_pin.set_high().or_else(|_| Err(Error::Pin))?;
|
||||
|
||||
io_update.set_low().or_else(|_| Err(Error::Pin))?;
|
||||
|
||||
// Delay for a clock cycle to allow the device to reset.
|
||||
delay.delay_ms((1000.0 / clock_frequency as f32) as u8);
|
||||
|
||||
@ -137,6 +140,12 @@ impl<I: Interface> Ad9959<I> {
|
||||
.write(Register::CSR as u8, &csr)
|
||||
.map_err(|_| Error::Interface)?;
|
||||
|
||||
// Latch the new interface configuration.
|
||||
io_update.set_high().or_else(|_| Err(Error::Pin))?;
|
||||
// Delay for a clock cycle to allow the device to reset.
|
||||
delay.delay_ms(2 * (1000.0 / clock_frequency as f32) as u8);
|
||||
io_update.set_low().or_else(|_| Err(Error::Pin))?;
|
||||
|
||||
ad9959
|
||||
.interface
|
||||
.configure_mode(desired_mode)
|
||||
|
@ -47,7 +47,7 @@ impl HighResTimerE {
|
||||
let minimum_duration = set_duration + set_offset;
|
||||
|
||||
let source_frequency: u32 = self.clocks.timy_ker_ck().0;
|
||||
let source_cycles = (minimum_duration * source_frequency as f32) as u32;
|
||||
let source_cycles = (minimum_duration * source_frequency as f32) as u32 + 1;
|
||||
|
||||
// Determine the clock divider, which may be 1, 2, or 4. We will choose a clock divider that
|
||||
// allows us the highest resolution per tick, so lower dividers are favored.
|
||||
@ -68,7 +68,7 @@ impl HighResTimerE {
|
||||
// We now have the prescaler and the period registers. Configure the timer.
|
||||
self.timer
|
||||
.timecr
|
||||
.modify(|_, w| unsafe { w.ck_pscx().bits(divider) });
|
||||
.modify(|_, w| unsafe { w.ck_pscx().bits(divider + 4) });
|
||||
self.timer.perer.write(|w| unsafe { w.perx().bits(period) });
|
||||
|
||||
// Configure the comparator 1 level.
|
||||
@ -83,13 +83,16 @@ impl HighResTimerE {
|
||||
Channel::One => {
|
||||
self.timer.sete1r.write(|w| w.cmp1().set_bit());
|
||||
self.timer.rste1r.write(|w| w.per().set_bit());
|
||||
self.common.oenr.write(|w| w.te1oen().set_bit());
|
||||
}
|
||||
Channel::Two => {
|
||||
self.timer.sete2r.write(|w| w.cmp1().set_bit());
|
||||
self.timer.rste2r.write(|w| w.per().set_bit());
|
||||
self.common.oenr.write(|w| w.te2oen().set_bit());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Enable the timer now that it is configured.
|
||||
self.master.mcr.modify(|_, w| w.tecen().set_bit());
|
||||
}
|
||||
|
115
src/main.rs
115
src/main.rs
@ -183,6 +183,8 @@ const APP: () = {
|
||||
|
||||
timer: hal::timer::Timer<hal::stm32::TIM2>,
|
||||
|
||||
profiles: heapless::spsc::Queue<[u32; 4], heapless::consts::U32>,
|
||||
|
||||
// Note: It appears that rustfmt generates a format that GDB cannot recognize, which
|
||||
// results in GDB breakpoints being set improperly.
|
||||
#[rustfmt::skip]
|
||||
@ -241,7 +243,7 @@ const APP: () = {
|
||||
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
|
||||
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
|
||||
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
|
||||
let gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
|
||||
let mut gpiog = dp.GPIOG.split(ccdr.peripheral.GPIOG);
|
||||
|
||||
let afe0 = {
|
||||
let a0_pin = gpiof.pf2.into_push_pull_output();
|
||||
@ -469,16 +471,25 @@ const APP: () = {
|
||||
};
|
||||
|
||||
let mut reset_pin = gpioa.pa0.into_push_pull_output();
|
||||
let mut io_update = gpiog
|
||||
.pg7
|
||||
.into_push_pull_output();
|
||||
|
||||
ad9959::Ad9959::new(
|
||||
let ad9959 = ad9959::Ad9959::new(
|
||||
qspi_interface,
|
||||
&mut reset_pin,
|
||||
&mut io_update,
|
||||
&mut delay,
|
||||
ad9959::Mode::FourBitSerial,
|
||||
100_000_000_f32,
|
||||
5,
|
||||
)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
|
||||
// Return IO_Update
|
||||
gpiog.pg7 = io_update.into_analog();
|
||||
|
||||
ad9959
|
||||
};
|
||||
|
||||
let io_expander = {
|
||||
@ -573,6 +584,9 @@ const APP: () = {
|
||||
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
|
||||
};
|
||||
|
||||
@ -733,15 +747,24 @@ const APP: () = {
|
||||
net_interface: network_interface,
|
||||
eth_mac,
|
||||
mac_addr,
|
||||
|
||||
profiles: heapless::spsc::Queue::new(),
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds = TIM3, resources=[dacs], priority = 3)]
|
||||
#[task(binds = TIM3, resources=[dacs, profiles, pounder], priority = 3)]
|
||||
fn dac_update(c: dac_update::Context) {
|
||||
c.resources.dacs.update();
|
||||
|
||||
if let Some(pounder) = c.resources.pounder {
|
||||
if let Some(profile) = c.resources.profiles.dequeue() {
|
||||
pounder.ad9959.interface.write_profile(profile).unwrap();
|
||||
pounder.io_update_trigger.trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[task(binds=DMA1_STR3, resources=[adcs, dacs, iir_state, iir_ch], priority=2)]
|
||||
#[task(binds=DMA1_STR3, resources=[adcs, dacs, pounder, profiles, iir_state, iir_ch], priority=2)]
|
||||
fn adc_update(mut c: adc_update::Context) {
|
||||
let (adc0_samples, adc1_samples) =
|
||||
c.resources.adcs.transfer_complete_handler();
|
||||
@ -756,6 +779,20 @@ const APP: () = {
|
||||
c.resources
|
||||
.dacs
|
||||
.lock(|dacs| dacs.push(result_adc0, result_adc1));
|
||||
|
||||
let profiles = &mut c.resources.profiles;
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
if let Some(pounder) = pounder {
|
||||
profiles.lock(|profiles| {
|
||||
let profile = pounder.ad9959.serialize_profile(pounder::Channel::Out0.into(),
|
||||
100_000_000_f32,
|
||||
0.0_f32,
|
||||
*adc0 as f32 / 0xFFFF as f32).unwrap();
|
||||
|
||||
profiles.enqueue(profile).unwrap();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@ -822,10 +859,12 @@ const APP: () = {
|
||||
"stabilizer/afe0/gain": (|| c.resources.afe0.get_gain()),
|
||||
"stabilizer/afe1/gain": (|| c.resources.afe1.get_gain()),
|
||||
"pounder/dds/clock": (|| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) => pounder.get_dds_clock_config(),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) => pounder.get_dds_clock_config(),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
})
|
||||
],
|
||||
|
||||
@ -853,38 +892,48 @@ const APP: () = {
|
||||
})
|
||||
}),
|
||||
"pounder/in0": pounder::ChannelState, (|state| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::In0, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
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| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::In1, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
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| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::Out0, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
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| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) =>
|
||||
pounder.set_channel_state(pounder::Channel::Out1, state),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
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| {
|
||||
match c.resources.pounder {
|
||||
Some(pounder) => pounder.configure_dds_clock(config),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
c.resources.pounder.lock(|pounder| {
|
||||
match pounder {
|
||||
Some(pounder) => pounder.configure_dds_clock(config),
|
||||
_ => Err(pounder::Error::Access),
|
||||
}
|
||||
})
|
||||
}),
|
||||
"stabilizer/afe0/gain": afe::Gain, (|gain| {
|
||||
Ok::<(), ()>(c.resources.afe0.set_gain(gain))
|
||||
|
@ -126,7 +126,7 @@ impl QspiInterface {
|
||||
qspi_regs.dlr.write(|w| w.dl().bits(0xFFFF_FFFF));
|
||||
qspi_regs
|
||||
.ccr
|
||||
.modify(|_, w| w.imode().bits(0).fmode().bits(1));
|
||||
.modify(|_, w| w.imode().bits(0).fmode().bits(0).admode().bits(0));
|
||||
}
|
||||
|
||||
self.streaming = true;
|
||||
|
Loading…
Reference in New Issue
Block a user