Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/pounder timestamping #196

Merged
merged 13 commits into from
Jan 11, 2021
Merged
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ jobs:
target/*/release/stabilizer
stabilizer-release.bin

- name: Build (Pounder v1.1)
uses: actions-rs/cargo@v1
with:
command: build
args: --features pounder_v1_1

test:
runs-on: ubuntu-latest
strategy:
Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ branch = "dma"
semihosting = ["panic-semihosting", "cortex-m-log/semihosting"]
bkpt = [ ]
nightly = ["cortex-m/inline-asm", "dsp/nightly"]
pounder_v1_1 = [ ]

[profile.dev]
codegen-units = 1
Expand Down
13 changes: 12 additions & 1 deletion ad9959/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,17 @@ impl<I: Interface> Ad9959<I> {

// Set the clock frequency to configure the device as necessary.
ad9959.configure_system_clock(clock_frequency, multiplier)?;

// Latch the new clock configuration.
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). We use 5uS instead of 4uS to
// guarantee conformance with datasheet requirements.
delay.delay_us(5);

io_update.set_low().or(Err(Error::Pin))?;

Ok(ad9959)
}

Expand All @@ -195,7 +206,7 @@ impl<I: Interface> Ad9959<I> {
///
/// Returns:
/// The actual frequency configured for the internal system clock.
pub fn configure_system_clock(
fn configure_system_clock(
&mut self,
reference_clock_frequency: f32,
multiplier: u8,
Expand Down
4 changes: 2 additions & 2 deletions src/adc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ macro_rules! adc_input {

/// Whenever the DMA request occurs, it should write into SPI's TX FIFO to start a DMA
/// transfer.
fn address(&self) -> u32 {
fn address(&self) -> usize {
// Note(unsafe): It is assumed that SPI is owned by another DMA transfer and this DMA is
// only used for the transmit-half of DMA.
let regs = unsafe { &*hal::stm32::$spi::ptr() };
&regs.txdr as *const _ as u32
&regs.txdr as *const _ as usize
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/dac.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ macro_rules! dac_output {
const REQUEST_LINE: Option<u8> = Some(DMAReq::$dma_req as u8);

/// Whenever the DMA request occurs, it should write into SPI's TX FIFO.
fn address(&self) -> u32 {
&self.spi.inner().txdr as *const _ as u32
fn address(&self) -> usize {
&self.spi.inner().txdr as *const _ as usize
}
}

Expand Down
19 changes: 17 additions & 2 deletions src/design_parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ pub const POUNDER_IO_UPDATE_DELAY: f32 = 900_e-9;

/// The duration to assert IO_Update for the pounder DDS.
// 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.
// SYNC_CLK running at 100MHz (1/4 of the pounder reference clock of 500MHz), this corresponds to
// 32ns. To accomodate rounding errors, we use 50ns instead.
pub const POUNDER_IO_UPDATE_DURATION: f32 = 50_e-9;

/// The DDS reference clock frequency in MHz.
pub const DDS_REF_CLK: MegaHertz = MegaHertz(100);

/// The multiplier used for the DDS reference clock PLL.
pub const DDS_MULTIPLIER: u8 = 5;

/// The DDS system clock frequency after the internal PLL multiplication.
#[allow(dead_code)]
pub const DDS_SYSTEM_CLK: MegaHertz =
MegaHertz(DDS_REF_CLK.0 * DDS_MULTIPLIER as u32);

/// The divider from the DDS system clock to the SYNC_CLK output (sync-clk is always 1/4 of sysclk).
#[allow(dead_code)]
pub const DDS_SYNC_CLK_DIV: u8 = 4;
2 changes: 1 addition & 1 deletion src/digital_input_stamper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ impl InputStamper {
// Utilize the TIM5 CH4 as an input capture channel - use TI4 (the DI0 input trigger) as the
// capture source.
let input_capture =
timer_channel.into_input_capture(timers::tim5::CC4S_A::TI4);
timer_channel.into_input_capture(timers::CaptureTrigger::Input24);

Self {
capture_channel: input_capture,
Expand Down
74 changes: 68 additions & 6 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ extern crate panic_halt;
#[macro_use]
extern crate log;

#[allow(unused_imports)]
use core::convert::TryInto;

// use core::sync::atomic::{AtomicU32, AtomicBool, Ordering};
use cortex_m_rt::exception;
use rtic::cyccnt::{Instant, U32Ext};
Expand Down Expand Up @@ -60,7 +63,7 @@ use heapless::{consts::*, String};
const ADC_SAMPLE_TICKS: u32 = 256;

// The desired ADC sample processing buffer size.
const SAMPLE_BUFFER_SIZE: usize = 1;
const SAMPLE_BUFFER_SIZE: usize = 8;

// The number of cascaded IIR biquads per channel. Select 1 or 2!
const IIR_CASCADE_LENGTH: usize = 1;
Expand Down Expand Up @@ -220,6 +223,8 @@ const APP: () = {

pounder: Option<pounder::PounderDevices>,

pounder_stamper: Option<pounder::timestamp::Timestamper>,

// Format: iir_state[ch][cascade-no][coeff]
#[init([[[0.; 5]; IIR_CASCADE_LENGTH]; 2])]
iir_state: [[iir::IIRState; IIR_CASCADE_LENGTH]; 2],
Expand Down Expand Up @@ -509,7 +514,7 @@ const APP: () = {
delay.delay_ms(2u8);
let (pounder_devices, dds_output) = if pounder_pgood.is_high().unwrap()
{
let mut ad9959 = {
let ad9959 = {
let qspi_interface = {
// Instantiate the QUADSPI pins and peripheral interface.
let qspi_pins = {
Expand Down Expand Up @@ -553,17 +558,24 @@ const APP: () = {
pounder::QspiInterface::new(qspi).unwrap()
};

#[cfg(feature = "pounder_v1_1")]
let reset_pin = gpiog.pg6.into_push_pull_output();
#[cfg(not(feature = "pounder_v1_1"))]
let reset_pin = gpioa.pa0.into_push_pull_output();

let mut io_update = gpiog.pg7.into_push_pull_output();

let ref_clk: hal::time::Hertz =
design_parameters::DDS_REF_CLK.into();

let ad9959 = ad9959::Ad9959::new(
qspi_interface,
reset_pin,
&mut io_update,
&mut delay,
ad9959::Mode::FourBitSerial,
100_000_000_f32,
5,
ref_clk.0 as f32,
design_parameters::DDS_MULTIPLIER,
)
.unwrap();

Expand Down Expand Up @@ -642,7 +654,6 @@ const APP: () = {

let pounder_devices = pounder::PounderDevices::new(
io_expander,
&mut ad9959,
spi,
adc1,
adc2,
Expand Down Expand Up @@ -828,6 +839,51 @@ const APP: () = {
)
};

#[cfg(feature = "pounder_v1_1")]
let pounder_stamper = {
let etr_pin = gpioa.pa0.into_alternate_af3();

// The frequency in the constructor is dont-care, as we will modify the period + clock
// source manually below.
let tim8 =
dp.TIM8.timer(1.khz(), ccdr.peripheral.TIM8, &ccdr.clocks);
let mut timestamp_timer = timers::PounderTimestampTimer::new(tim8);

// Pounder is configured to generate a 500MHz reference clock, so a 125MHz sync-clock is
// output. As a result, dividing the 125MHz sync-clk provides a 31.25MHz tick rate for
// the timestamp timer. 31.25MHz corresponds with a 32ns tick rate.
timestamp_timer.set_external_clock(timers::Prescaler::Div4);
timestamp_timer.start();

// We want the pounder timestamp timer to overflow once per batch.
let tick_ratio = {
let sync_clk_mhz: f32 = design_parameters::DDS_SYSTEM_CLK.0
as f32
/ design_parameters::DDS_SYNC_CLK_DIV as f32;
sync_clk_mhz / design_parameters::TIMER_FREQUENCY.0 as f32
};

let period = (tick_ratio
* ADC_SAMPLE_TICKS as f32
* SAMPLE_BUFFER_SIZE as f32) as u32
/ 4;
timestamp_timer.set_period_ticks((period - 1).try_into().unwrap());
let tim8_channels = timestamp_timer.channels();

let stamper = pounder::timestamp::Timestamper::new(
timestamp_timer,
dma_streams.7,
tim8_channels.ch1,
&mut sampling_timer,
etr_pin,
);

Some(stamper)
};

#[cfg(not(feature = "pounder_v1_1"))]
let pounder_stamper = None;

// Start sampling ADCs.
sampling_timer.start();
timestamp_timer.start();
Expand All @@ -841,6 +897,7 @@ const APP: () = {
input_stamper,
dds_output,
pounder: pounder_devices,
pounder_stamper,

eeprom_i2c,
net_interface: network_interface,
Expand All @@ -849,8 +906,13 @@ const APP: () = {
}
}

#[task(binds=DMA1_STR3, resources=[adcs, dacs, iir_state, iir_ch, dds_output, input_stamper], priority=2)]
#[task(binds=DMA1_STR3, resources=[pounder_stamper, adcs, dacs, iir_state, iir_ch, dds_output, input_stamper], priority=2)]
fn process(c: process::Context) {
if let Some(stamper) = c.resources.pounder_stamper {
let pounder_timestamps = stamper.acquire_buffer();
info!("{:?}", pounder_timestamps);
}

let adc_samples = [
c.resources.adcs.0.acquire_buffer(),
c.resources.adcs.1.acquire_buffer(),
Expand Down
7 changes: 1 addition & 6 deletions src/pounder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use serde::{Deserialize, Serialize};
mod attenuators;
mod dds_output;
mod rf_power;
pub mod timestamp;

pub use dds_output::DdsOutput;

Expand Down Expand Up @@ -274,15 +275,13 @@ impl PounderDevices {
/// Construct and initialize pounder-specific hardware.
///
/// Args:
/// * `ad9959` - The DDS driver for the pounder hardware.
/// * `attenuator_spi` - A SPI interface to control digital attenuators.
/// * `adc1` - The ADC1 peripheral for measuring power.
/// * `adc2` - The ADC2 peripheral for measuring power.
/// * `adc1_in_p` - The input channel for the RF power measurement on IN0.
/// * `adc2_in_p` - The input channel for the RF power measurement on IN1.
pub fn new(
mcp23017: mcp23017::MCP23017<hal::i2c::I2c<hal::stm32::I2C1>>,
ad9959: &mut ad9959::Ad9959<QspiInterface>,
attenuator_spi: hal::spi::Spi<hal::stm32::SPI1, hal::spi::Enabled, u8>,
adc1: hal::adc::Adc<hal::stm32::ADC1, hal::adc::Enabled>,
adc2: hal::adc::Adc<hal::stm32::ADC2, hal::adc::Enabled>,
Expand Down Expand Up @@ -314,14 +313,10 @@ impl PounderDevices {
.write_gpio(mcp23017::Port::GPIOB, 1 << 5)
.map_err(|_| Error::I2c)?;

// Select the on-board clock with a 4x prescaler (400MHz).
devices
.mcp23017
.digital_write(EXT_CLK_SEL_PIN, false)
.map_err(|_| Error::I2c)?;
ad9959
.configure_system_clock(100_000_000f32, 4)
.map_err(|_| Error::Dds)?;

Ok(devices)
}
Expand Down
Loading