Adding support for hardware IO_update
This commit is contained in:
parent
c97e4d9d20
commit
fca38e5d63
|
@ -567,7 +567,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "stm32h7xx-hal"
|
name = "stm32h7xx-hal"
|
||||||
version = "0.8.0"
|
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 = [
|
dependencies = [
|
||||||
"bare-metal 1.0.0",
|
"bare-metal 1.0.0",
|
||||||
"cast",
|
"cast",
|
||||||
|
|
|
@ -104,6 +104,7 @@ impl<I: Interface> Ad9959<I> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
interface: I,
|
interface: I,
|
||||||
reset_pin: &mut impl OutputPin,
|
reset_pin: &mut impl OutputPin,
|
||||||
|
io_update: &mut impl OutputPin,
|
||||||
delay: &mut impl DelayMs<u8>,
|
delay: &mut impl DelayMs<u8>,
|
||||||
desired_mode: Mode,
|
desired_mode: Mode,
|
||||||
clock_frequency: f32,
|
clock_frequency: f32,
|
||||||
|
@ -119,6 +120,8 @@ impl<I: Interface> Ad9959<I> {
|
||||||
// Reset the AD9959
|
// Reset the AD9959
|
||||||
reset_pin.set_high().or_else(|_| Err(Error::Pin))?;
|
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 for a clock cycle to allow the device to reset.
|
||||||
delay.delay_ms((1000.0 / clock_frequency as f32) as u8);
|
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)
|
.write(Register::CSR as u8, &csr)
|
||||||
.map_err(|_| Error::Interface)?;
|
.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
|
ad9959
|
||||||
.interface
|
.interface
|
||||||
.configure_mode(desired_mode)
|
.configure_mode(desired_mode)
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl HighResTimerE {
|
||||||
let minimum_duration = set_duration + set_offset;
|
let minimum_duration = set_duration + set_offset;
|
||||||
|
|
||||||
let source_frequency: u32 = self.clocks.timy_ker_ck().0;
|
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
|
// 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.
|
// 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.
|
// We now have the prescaler and the period registers. Configure the timer.
|
||||||
self.timer
|
self.timer
|
||||||
.timecr
|
.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) });
|
self.timer.perer.write(|w| unsafe { w.perx().bits(period) });
|
||||||
|
|
||||||
// Configure the comparator 1 level.
|
// Configure the comparator 1 level.
|
||||||
|
@ -83,13 +83,16 @@ impl HighResTimerE {
|
||||||
Channel::One => {
|
Channel::One => {
|
||||||
self.timer.sete1r.write(|w| w.cmp1().set_bit());
|
self.timer.sete1r.write(|w| w.cmp1().set_bit());
|
||||||
self.timer.rste1r.write(|w| w.per().set_bit());
|
self.timer.rste1r.write(|w| w.per().set_bit());
|
||||||
|
self.common.oenr.write(|w| w.te1oen().set_bit());
|
||||||
}
|
}
|
||||||
Channel::Two => {
|
Channel::Two => {
|
||||||
self.timer.sete2r.write(|w| w.cmp1().set_bit());
|
self.timer.sete2r.write(|w| w.cmp1().set_bit());
|
||||||
self.timer.rste2r.write(|w| w.per().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.
|
// Enable the timer now that it is configured.
|
||||||
self.master.mcr.modify(|_, w| w.tecen().set_bit());
|
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>,
|
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
|
// Note: It appears that rustfmt generates a format that GDB cannot recognize, which
|
||||||
// results in GDB breakpoints being set improperly.
|
// results in GDB breakpoints being set improperly.
|
||||||
#[rustfmt::skip]
|
#[rustfmt::skip]
|
||||||
|
@ -241,7 +243,7 @@ const APP: () = {
|
||||||
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
|
let gpiod = dp.GPIOD.split(ccdr.peripheral.GPIOD);
|
||||||
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
|
let gpioe = dp.GPIOE.split(ccdr.peripheral.GPIOE);
|
||||||
let gpiof = dp.GPIOF.split(ccdr.peripheral.GPIOF);
|
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 afe0 = {
|
||||||
let a0_pin = gpiof.pf2.into_push_pull_output();
|
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 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,
|
qspi_interface,
|
||||||
&mut reset_pin,
|
&mut reset_pin,
|
||||||
|
&mut io_update,
|
||||||
&mut delay,
|
&mut delay,
|
||||||
ad9959::Mode::FourBitSerial,
|
ad9959::Mode::FourBitSerial,
|
||||||
100_000_000_f32,
|
100_000_000_f32,
|
||||||
5,
|
5,
|
||||||
)
|
)
|
||||||
.unwrap()
|
.unwrap();
|
||||||
|
|
||||||
|
// Return IO_Update
|
||||||
|
gpiog.pg7 = io_update.into_analog();
|
||||||
|
|
||||||
|
ad9959
|
||||||
};
|
};
|
||||||
|
|
||||||
let io_expander = {
|
let io_expander = {
|
||||||
|
@ -573,6 +584,9 @@ const APP: () = {
|
||||||
900_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
|
hrtimer
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -733,15 +747,24 @@ const APP: () = {
|
||||||
net_interface: network_interface,
|
net_interface: network_interface,
|
||||||
eth_mac,
|
eth_mac,
|
||||||
mac_addr,
|
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) {
|
fn dac_update(c: dac_update::Context) {
|
||||||
c.resources.dacs.update();
|
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) {
|
fn adc_update(mut c: adc_update::Context) {
|
||||||
let (adc0_samples, adc1_samples) =
|
let (adc0_samples, adc1_samples) =
|
||||||
c.resources.adcs.transfer_complete_handler();
|
c.resources.adcs.transfer_complete_handler();
|
||||||
|
@ -756,6 +779,20 @@ const APP: () = {
|
||||||
c.resources
|
c.resources
|
||||||
.dacs
|
.dacs
|
||||||
.lock(|dacs| dacs.push(result_adc0, result_adc1));
|
.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/afe0/gain": (|| c.resources.afe0.get_gain()),
|
||||||
"stabilizer/afe1/gain": (|| c.resources.afe1.get_gain()),
|
"stabilizer/afe1/gain": (|| c.resources.afe1.get_gain()),
|
||||||
"pounder/dds/clock": (|| {
|
"pounder/dds/clock": (|| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) => pounder.get_dds_clock_config(),
|
match pounder {
|
||||||
_ => Err(pounder::Error::Access),
|
Some(pounder) => pounder.get_dds_clock_config(),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
|
|
||||||
|
@ -853,38 +892,48 @@ const APP: () = {
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
"pounder/in0": pounder::ChannelState, (|state| {
|
"pounder/in0": pounder::ChannelState, (|state| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) =>
|
match pounder {
|
||||||
pounder.set_channel_state(pounder::Channel::In0, state),
|
Some(pounder) =>
|
||||||
_ => Err(pounder::Error::Access),
|
pounder.set_channel_state(pounder::Channel::In0, state),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
"pounder/in1": pounder::ChannelState, (|state| {
|
"pounder/in1": pounder::ChannelState, (|state| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) =>
|
match pounder {
|
||||||
pounder.set_channel_state(pounder::Channel::In1, state),
|
Some(pounder) =>
|
||||||
_ => Err(pounder::Error::Access),
|
pounder.set_channel_state(pounder::Channel::In1, state),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
"pounder/out0": pounder::ChannelState, (|state| {
|
"pounder/out0": pounder::ChannelState, (|state| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) =>
|
match pounder {
|
||||||
pounder.set_channel_state(pounder::Channel::Out0, state),
|
Some(pounder) =>
|
||||||
_ => Err(pounder::Error::Access),
|
pounder.set_channel_state(pounder::Channel::Out0, state),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
"pounder/out1": pounder::ChannelState, (|state| {
|
"pounder/out1": pounder::ChannelState, (|state| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) =>
|
match pounder {
|
||||||
pounder.set_channel_state(pounder::Channel::Out1, state),
|
Some(pounder) =>
|
||||||
_ => Err(pounder::Error::Access),
|
pounder.set_channel_state(pounder::Channel::Out1, state),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
"pounder/dds/clock": pounder::DdsClockConfig, (|config| {
|
"pounder/dds/clock": pounder::DdsClockConfig, (|config| {
|
||||||
match c.resources.pounder {
|
c.resources.pounder.lock(|pounder| {
|
||||||
Some(pounder) => pounder.configure_dds_clock(config),
|
match pounder {
|
||||||
_ => Err(pounder::Error::Access),
|
Some(pounder) => pounder.configure_dds_clock(config),
|
||||||
}
|
_ => Err(pounder::Error::Access),
|
||||||
|
}
|
||||||
|
})
|
||||||
}),
|
}),
|
||||||
"stabilizer/afe0/gain": afe::Gain, (|gain| {
|
"stabilizer/afe0/gain": afe::Gain, (|gain| {
|
||||||
Ok::<(), ()>(c.resources.afe0.set_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.dlr.write(|w| w.dl().bits(0xFFFF_FFFF));
|
||||||
qspi_regs
|
qspi_regs
|
||||||
.ccr
|
.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;
|
self.streaming = true;
|
||||||
|
|
Loading…
Reference in New Issue