Adding WIP HRTimer
This commit is contained in:
parent
071ccd17dc
commit
28cb3906ac
|
@ -0,0 +1,81 @@
|
||||||
|
use crate::hal;
|
||||||
|
use hal::rcc::{CoreClocks, ResetEnable, rec};
|
||||||
|
|
||||||
|
pub enum Channel {
|
||||||
|
One,
|
||||||
|
Two,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HighResTimerE {
|
||||||
|
master: hal::stm32::HRTIM_MASTER,
|
||||||
|
timer: hal::stm32::HRTIM_TIME,
|
||||||
|
common: hal::stm32::HRTIM_COMMON,
|
||||||
|
|
||||||
|
clocks: CoreClocks,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HighResTimerE {
|
||||||
|
pub fn new(timer_regs: hal::stm32::HRTIM_TIME, clocks: CoreClocks, prec: rec::Hrtim) -> Self {
|
||||||
|
let master = unsafe { &*hal::stm32::HRTIM_MASTER::ptr() };
|
||||||
|
let common = unsafe { &*hal::stm32::HRTIM_COMMON::ptr() };
|
||||||
|
prec.reset().enable();
|
||||||
|
|
||||||
|
Self { master, timer: timer_regs, common, clocks }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn configure_single_shot(&mut self, channel: Channel, set_duration: f32, set_offset: f32) {
|
||||||
|
// Disable the timer before configuration.
|
||||||
|
self.master.mcr.modify(|_, w| w.tecen().clear_bit());
|
||||||
|
|
||||||
|
// Configure the desired timer for single shot mode with set and reset of the specified
|
||||||
|
// channel at the desired durations. The HRTIM is on APB2 (D2 domain), and the kernel clock
|
||||||
|
// is the APB bus clock.
|
||||||
|
let minimum_duration = set_duration + set_offset;
|
||||||
|
|
||||||
|
let source_frequency = self.clocks.timy_ker_ck;
|
||||||
|
let source_cycles = minimum_duration * source_frequency;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
let divider = if source_cycles < 0xFFDF {
|
||||||
|
1
|
||||||
|
} else if (source_cycles / 2) < 0xFFDF {
|
||||||
|
2
|
||||||
|
} else if (source_cycles / 4) < 0xFFDF {
|
||||||
|
4
|
||||||
|
} else {
|
||||||
|
panic!("Unattainable timing parameters!");
|
||||||
|
};
|
||||||
|
|
||||||
|
// The period register must be greater than or equal to 3 cycles.
|
||||||
|
assert!((source_cycles / divider) > 2);
|
||||||
|
|
||||||
|
// We now have the prescaler and the period registers. Configure the timer.
|
||||||
|
self.timer.timecr.modify(|_, w| unsafe{w.ck_pscx().bits(divider)})
|
||||||
|
self.timer.perer.write(|w| unsafe{w.per().bits(source_cycles / divider)});
|
||||||
|
|
||||||
|
// Configure the comparator 1 level.
|
||||||
|
self.timer.cmpe1r.write(|w| unsafe{w.cmp1().bits(set_offset * source_frequency)});
|
||||||
|
|
||||||
|
// Configure the set/reset signals.
|
||||||
|
// Set on compare with CMP1, reset upon reaching PER
|
||||||
|
match channel {
|
||||||
|
Channel::One => {
|
||||||
|
self.timer.sete1r().write(|w| w.cmp1().set_bit());
|
||||||
|
self.timer.resete1r().write(|w| w.per().set_bit());
|
||||||
|
},
|
||||||
|
Channel::Two => {
|
||||||
|
self.timer.sete2r().write(|w| w.cmp1().set_bit());
|
||||||
|
self.timer.resete2r().write(|w| w.per().set_bit());
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Enable the timer now that it is configured.
|
||||||
|
self.master.mcr.modify(|_, w| w.tecen().set_bit());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn trigger(&mut self) {
|
||||||
|
// Generate a reset event to force the timer to start counting.
|
||||||
|
self.common.cr2.write(|w| w.terst().set_bit());
|
||||||
|
}
|
||||||
|
}
|
13
src/main.rs
13
src/main.rs
|
@ -445,6 +445,19 @@ const APP: () = {
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut reset_pin = gpioa.pa0.into_push_pull_output();
|
let mut reset_pin = gpioa.pa0.into_push_pull_output();
|
||||||
|
|
||||||
|
// Configure the IO_Update signal for the DDS.
|
||||||
|
let mut hrtimer = HighResTimerE::new(dp.HRTIM_TIME, 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 10MHz, so this comes out to an
|
||||||
|
// offset of 3.2uS.
|
||||||
|
// TODO: This currently does not meet the 2uS timing that we have for profile
|
||||||
|
// updates, since we want to send a profile update for every DAC update. We should
|
||||||
|
// increase the QSPI clock frequency.
|
||||||
|
hrtimer.configure_single_shot(hrtimer::Channel::Two, 50e-9, 3.2e-6);
|
||||||
|
|
||||||
let io_update = gpiog.pg7.into_push_pull_output();
|
let io_update = gpiog.pg7.into_push_pull_output();
|
||||||
|
|
||||||
let asm_delay = {
|
let asm_delay = {
|
||||||
|
|
Loading…
Reference in New Issue