From fca38e5d6330f94fece3671289ef3d7b8e27a7ef Mon Sep 17 00:00:00 2001 From: Ryan Summers Date: Mon, 9 Nov 2020 15:16:44 +0100 Subject: [PATCH] Adding support for hardware IO_update --- Cargo.lock | 2 +- ad9959/src/lib.rs | 9 ++++ src/hrtimer.rs | 7 ++- src/main.rs | 115 ++++++++++++++++++++++++++++++++------------- src/pounder/mod.rs | 2 +- 5 files changed, 98 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ff768f0..5395319 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -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", diff --git a/ad9959/src/lib.rs b/ad9959/src/lib.rs index 5a2d132..99f1072 100644 --- a/ad9959/src/lib.rs +++ b/ad9959/src/lib.rs @@ -104,6 +104,7 @@ impl Ad9959 { pub fn new( interface: I, reset_pin: &mut impl OutputPin, + io_update: &mut impl OutputPin, delay: &mut impl DelayMs, desired_mode: Mode, clock_frequency: f32, @@ -119,6 +120,8 @@ impl Ad9959 { // 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 Ad9959 { .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) diff --git a/src/hrtimer.rs b/src/hrtimer.rs index 4af2144..d344396 100644 --- a/src/hrtimer.rs +++ b/src/hrtimer.rs @@ -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()); } diff --git a/src/main.rs b/src/main.rs index 4295170..9c0d474 100644 --- a/src/main.rs +++ b/src/main.rs @@ -183,6 +183,8 @@ const APP: () = { timer: hal::timer::Timer, + 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)) diff --git a/src/pounder/mod.rs b/src/pounder/mod.rs index e299e2b..0e32a22 100644 --- a/src/pounder/mod.rs +++ b/src/pounder/mod.rs @@ -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;