Updating after review
This commit is contained in:
parent
f4a4357396
commit
14a647867a
@ -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>(
|
||||
|
@ -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) });
|
||||
|
16
src/main.rs
16
src/main.rs
@ -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,
|
||||
|
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user