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))?;
|
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
|
// 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);
|
delay.delay_us(5);
|
||||||
|
|
||||||
reset_pin.set_low().or(Err(Error::Pin))?;
|
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))?;
|
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
|
// 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);
|
delay.delay_us(5);
|
||||||
|
|
||||||
io_update.set_low().or(Err(Error::Pin))?;
|
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
|
// active. This is likely due to needing to wait at least 1 clock cycle of the DDS for the
|
||||||
// interface update to occur.
|
// interface update to occur.
|
||||||
// Delay for at least 1 SYNC_CLK period for the update to occur. The SYNC_CLK is guaranteed
|
// 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);
|
delay.delay_us(5);
|
||||||
|
|
||||||
// Read back the CSR to ensure it specifies the mode correctly.
|
// Read back the CSR to ensure it specifies the mode correctly.
|
||||||
@ -552,12 +555,6 @@ impl ProfileSerializer {
|
|||||||
pow: Option<u16>,
|
pow: Option<u16>,
|
||||||
acr: 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);
|
let mut csr: u8 = *0u8.set_bits(1..3, self.mode as u8);
|
||||||
for channel in channels.iter() {
|
for channel in channels.iter() {
|
||||||
csr.set_bit(4 + *channel as usize, true);
|
csr.set_bit(4 + *channel as usize, true);
|
||||||
@ -581,8 +578,6 @@ impl ProfileSerializer {
|
|||||||
/// Add a register write to the serialization data.
|
/// Add a register write to the serialization data.
|
||||||
fn add_write(&mut self, register: Register, value: &[u8]) {
|
fn add_write(&mut self, register: Register, value: &[u8]) {
|
||||||
let data = &mut self.data[self.index..];
|
let data = &mut self.data[self.index..];
|
||||||
assert!(value.len() + 1 <= data.len());
|
|
||||||
|
|
||||||
data[0] = register as u8;
|
data[0] = register as u8;
|
||||||
data[1..][..value.len()].copy_from_slice(value);
|
data[1..][..value.len()].copy_from_slice(value);
|
||||||
self.index += value.len() + 1;
|
self.index += value.len() + 1;
|
||||||
@ -592,24 +587,24 @@ impl ProfileSerializer {
|
|||||||
///
|
///
|
||||||
/// # Note
|
/// # Note
|
||||||
/// The serialized profile will be padded to the next 32-bit word boundary by adding dummy
|
/// 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
|
/// # Returns
|
||||||
/// A slice of `u32` words representing the serialized profile.
|
/// A slice of `u32` words representing the serialized profile.
|
||||||
pub fn finalize<'a>(&'a mut self) -> &[u32] {
|
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);
|
let padding = 4 - (self.index % 4);
|
||||||
match padding {
|
match padding {
|
||||||
0 => {}
|
0 => {}
|
||||||
1 => {
|
1 => {
|
||||||
// For a pad size of 1, we have to pad with 5 bytes to align things.
|
// 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::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]),
|
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 {
|
unsafe {
|
||||||
core::slice::from_raw_parts::<'a, u32>(
|
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
|
// 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.
|
||||||
let divider: u8 = if source_cycles < 0xFFDF {
|
let setting: u8 = if source_cycles < 0xFFDF {
|
||||||
1
|
1
|
||||||
} else if (source_cycles / 2) < 0xFFDF {
|
} else if (source_cycles / 2) < 0xFFDF {
|
||||||
2
|
2
|
||||||
} else if (source_cycles / 4) < 0xFFDF {
|
} else if (source_cycles / 4) < 0xFFDF {
|
||||||
4
|
3
|
||||||
} else {
|
} else {
|
||||||
panic!("Unattainable timing parameters!");
|
panic!("Unattainable timing parameters!");
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let divider = 1 << (setting - 1);
|
||||||
|
|
||||||
// The period register must be greater than or equal to 3 cycles.
|
// The period register must be greater than or equal to 3 cycles.
|
||||||
let period = (source_cycles / divider as u32) as u16;
|
let period = (source_cycles / divider as u32) as u16;
|
||||||
assert!(period > 2);
|
assert!(period > 2);
|
||||||
|
|
||||||
// We now have the prescaler and the period registers. Configure the timer.
|
// 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
|
self.timer
|
||||||
.timecr
|
.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) });
|
self.timer.perer.write(|w| unsafe { w.perx().bits(period) });
|
||||||
|
|
||||||
// Configure the comparator 1 level.
|
// Configure the comparator 1 level.
|
||||||
let offset = (set_offset * source_frequency as f32) as u16;
|
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
|
self.timer
|
||||||
.cmp1er
|
.cmp1er
|
||||||
.write(|w| unsafe { w.cmp1x().bits(offset) });
|
.write(|w| unsafe { w.cmp1x().bits(offset) });
|
||||||
|
16
src/main.rs
16
src/main.rs
@ -625,12 +625,16 @@ const APP: () = {
|
|||||||
ccdr.peripheral.HRTIM,
|
ccdr.peripheral.HRTIM,
|
||||||
);
|
);
|
||||||
|
|
||||||
// IO_Update should be latched for 50ns after the QSPI profile write. Profile writes
|
// IO_Update should be latched for 4 SYNC_CLK cycles after the QSPI profile
|
||||||
// are always 16 bytes, with 2 cycles required per byte, coming out to a total of 32
|
// write. With pounder SYNC_CLK running at 100MHz (1/4 of the pounder reference
|
||||||
// QSPI clock cycles. The QSPI is configured for 40MHz, so this comes out to an
|
// clock of 400MHz), this corresponds to 40ns. To accomodate rounding errors, we
|
||||||
// offset of 800nS. We use 900ns to be safe - note that the timer is triggered after
|
// use 50ns instead.
|
||||||
// the QSPI write, which can take approximately 120nS, so there is additional
|
//
|
||||||
// margin.
|
// 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.configure_single_shot(
|
||||||
hrtimer::Channel::Two,
|
hrtimer::Channel::Two,
|
||||||
50_e-9,
|
50_e-9,
|
||||||
|
@ -58,6 +58,10 @@ impl DdsOutput {
|
|||||||
// fashion.
|
// fashion.
|
||||||
let regs = unsafe { &*hal::stm32::QUADSPI::ptr() };
|
let regs = unsafe { &*hal::stm32::QUADSPI::ptr() };
|
||||||
|
|
||||||
|
if regs.sr.read().flevel() != 0 {
|
||||||
|
warn!("QSPI stalling")
|
||||||
|
}
|
||||||
|
|
||||||
for word in profile.iter() {
|
for word in profile.iter() {
|
||||||
// Note(unsafe): We are writing to the SPI TX FIFO in a raw manner for performance. This
|
// 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.
|
// is safe because we know the data register is a valid address to write to.
|
||||||
|
Loading…
Reference in New Issue
Block a user