Updating after review

master
Ryan Summers 2020-12-07 10:55:09 +01:00
parent f4a4357396
commit 14a647867a
4 changed files with 39 additions and 25 deletions

View File

@ -124,7 +124,8 @@ impl<I: Interface> Ad9959<I> {
reset_pin.set_high().or(Err(Error::Pin))?;
// Delay for at least 1 SYNC_CLK period for the reset to occur. The SYNC_CLK is guaranteed
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK).
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK). We use 5uS instead of 4uS to
// guarantee conformance with datasheet requirements.
delay.delay_us(5);
reset_pin.set_low().or(Err(Error::Pin))?;
@ -143,7 +144,8 @@ impl<I: Interface> Ad9959<I> {
io_update.set_high().or(Err(Error::Pin))?;
// Delay for at least 1 SYNC_CLK period for the update to occur. The SYNC_CLK is guaranteed
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK).
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK). We use 5uS instead of 4uS to
// guarantee conformance with datasheet requirements.
delay.delay_us(5);
io_update.set_low().or(Err(Error::Pin))?;
@ -157,7 +159,8 @@ impl<I: Interface> Ad9959<I> {
// active. This is likely due to needing to wait at least 1 clock cycle of the DDS for the
// interface update to occur.
// Delay for at least 1 SYNC_CLK period for the update to occur. The SYNC_CLK is guaranteed
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK).
// to be at least 250KHz (1/4 of 1MHz minimum REF_CLK). We use 5uS instead of 4uS to
// guarantee conformance with datasheet requirements.
delay.delay_us(5);
// Read back the CSR to ensure it specifies the mode correctly.
@ -552,12 +555,6 @@ impl ProfileSerializer {
pow: Option<u16>,
acr: Option<u16>,
) {
// The user should have provided something to update.
assert!(
(ftw.is_some() || acr.is_some() || pow.is_some())
&& channels.len() > 0
);
let mut csr: u8 = *0u8.set_bits(1..3, self.mode as u8);
for channel in channels.iter() {
csr.set_bit(4 + *channel as usize, true);
@ -581,8 +578,6 @@ impl ProfileSerializer {
/// Add a register write to the serialization data.
fn add_write(&mut self, register: Register, value: &[u8]) {
let data = &mut self.data[self.index..];
assert!(value.len() + 1 <= data.len());
data[0] = register as u8;
data[1..][..value.len()].copy_from_slice(value);
self.index += value.len() + 1;
@ -592,24 +587,24 @@ impl ProfileSerializer {
///
/// # Note
/// The serialized profile will be padded to the next 32-bit word boundary by adding dummy
/// writes to the CSR or FR2 registers.
/// writes to the CSR or LSRR registers.
///
/// # Returns
/// A slice of `u32` words representing the serialized profile.
pub fn finalize<'a>(&'a mut self) -> &[u32] {
// Pad the buffer to 32-bit alignment by adding dummy writes to CSR and FR2.
// Pad the buffer to 32-bit alignment by adding dummy writes to CSR and LSRR.
let padding = 4 - (self.index % 4);
match padding {
0 => {}
1 => {
// For a pad size of 1, we have to pad with 5 bytes to align things.
self.add_write(Register::CSR, &[(self.mode as u8) << 1]);
self.add_write(Register::FR2, &[0, 0, 0]);
self.add_write(Register::LSRR, &[0, 0, 0]);
}
2 => self.add_write(Register::CSR, &[(self.mode as u8) << 1]),
3 => self.add_write(Register::FR2, &[0, 0, 0]),
3 => self.add_write(Register::LSRR, &[0, 0, 0]),
_ => panic!("Invalid"),
_ => unreachable!(),
}
unsafe {
core::slice::from_raw_parts::<'a, u32>(

View File

@ -68,28 +68,39 @@ impl HighResTimerE {
// 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: u8 = if source_cycles < 0xFFDF {
let setting: u8 = if source_cycles < 0xFFDF {
1
} else if (source_cycles / 2) < 0xFFDF {
2
} else if (source_cycles / 4) < 0xFFDF {
4
3
} else {
panic!("Unattainable timing parameters!");
};
let divider = 1 << (setting - 1);
// The period register must be greater than or equal to 3 cycles.
let period = (source_cycles / divider as u32) as u16;
assert!(period > 2);
// We now have the prescaler and the period registers. Configure the timer.
// Note(unsafe): The prescaler is guaranteed to be greater than or equal to 4 (minimum
// allowed value) due to the addition. The setting is always 1, 2, or 3, which represents
// all valid values.
self.timer
.timecr
.modify(|_, w| unsafe { w.ck_pscx().bits(divider + 4) });
.modify(|_, w| unsafe { w.ck_pscx().bits(setting + 4) });
// Note(unsafe): The period register is guaranteed to be a 16-bit value, which will fit in
// this register.
self.timer.perer.write(|w| unsafe { w.perx().bits(period) });
// Configure the comparator 1 level.
let offset = (set_offset * source_frequency as f32) as u16;
// Note(unsafe): The offset is always a 16-bit value, so is always valid for values >= 3, as
// specified by the datasheet.
assert!(offset >= 3);
self.timer
.cmp1er
.write(|w| unsafe { w.cmp1x().bits(offset) });

View File

@ -625,12 +625,16 @@ const APP: () = {
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 40MHz, so this comes out to an
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
// the QSPI write, which can take approximately 120nS, so there is additional
// margin.
// IO_Update should be latched for 4 SYNC_CLK cycles after the QSPI profile
// write. With pounder SYNC_CLK running at 100MHz (1/4 of the pounder reference
// clock of 400MHz), this corresponds to 40ns. To accomodate rounding errors, we
// use 50ns instead.
//
// 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 40MHz, so
// this comes out to an offset of 800nS. We use 900ns to be safe - note that the
// timer is triggered after the QSPI write, which can take approximately 120nS,
// so there is additional margin.
hrtimer.configure_single_shot(
hrtimer::Channel::Two,
50_e-9,

View File

@ -58,6 +58,10 @@ impl DdsOutput {
// fashion.
let regs = unsafe { &*hal::stm32::QUADSPI::ptr() };
if regs.sr.read().flevel() != 0 {
warn!("QSPI stalling")
}
for word in profile.iter() {
// Note(unsafe): We are writing to the SPI TX FIFO in a raw manner for performance. This
// is safe because we know the data register is a valid address to write to.