From e86f449dc0aa103701ba268b6dbc3f9fb5b1f683 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20J=C3=B6rdens?= Date: Tue, 23 Feb 2021 16:57:09 +0100 Subject: [PATCH] lockin bins: remove stale todos, align and document [nfc] --- src/bin/lockin-external.rs | 21 +++++++--------- src/bin/lockin-internal.rs | 49 +++++++++++++------------------------- 2 files changed, 26 insertions(+), 44 deletions(-) diff --git a/src/bin/lockin-external.rs b/src/bin/lockin-external.rs index e44c17e..1b11c76 100644 --- a/src/bin/lockin-external.rs +++ b/src/bin/lockin-external.rs @@ -2,12 +2,12 @@ #![no_std] #![no_main] -use generic_array::typenum::U4; -use stabilizer::{hardware, hardware::design_parameters}; use dsp::{Accu, Complex, ComplexExt, Lockin, RPLL}; +use generic_array::typenum::U4; use hardware::{ Adc0Input, Adc1Input, Dac0Output, Dac1Output, InputStamper, AFE0, AFE1, }; +use stabilizer::{hardware, hardware::design_parameters}; #[rtic::app(device = stm32h7xx_hal::stm32, peripherals = true, monotonic = rtic::cyccnt::CYCCNT)] const APP: () = { @@ -86,22 +86,20 @@ const APP: () = { .map(|t| t as i32); let (pll_phase, pll_frequency) = c.resources.pll.update( timestamp, - 21, // frequency settling time (log2 counter cycles), TODO: expose - 21, // phase settling time, TODO: expose + 21, // frequency settling time (log2 counter cycles), + 21, // phase settling time ); // Harmonic index of the LO: -1 to _de_modulate the fundamental (complex conjugate) - let harmonic: i32 = -1; // TODO: expose + let harmonic: i32 = -1; // Demodulation LO phase offset - let phase_offset: i32 = 0; // TODO: expose + let phase_offset: i32 = 0; // Log2 lowpass time constant - let time_constant: u8 = 6; // TODO: expose + let time_constant: u8 = 6; let sample_frequency = ((pll_frequency - // half-up rounding bias - // .wrapping_add(1 << design_parameters::SAMPLE_BUFFER_SIZE_LOG2 - 1) >> design_parameters::SAMPLE_BUFFER_SIZE_LOG2) as i32) .wrapping_mul(harmonic); @@ -129,7 +127,7 @@ const APP: () = { Quadrature, } - let conf = Conf::FrequencyDiscriminator; // TODO: expose + let conf = Conf::FrequencyDiscriminator; let output = match conf { // Convert from IQ to power and phase. Conf::PowerPhase => [(output.log2() << 24) as _, output.arg()], @@ -147,7 +145,6 @@ const APP: () = { #[idle(resources=[afes])] fn idle(_: idle::Context) -> ! { loop { - // TODO: Implement network interface. cortex_m::asm::wfi(); } } @@ -164,7 +161,7 @@ const APP: () = { #[task(binds = SPI3, priority = 3)] fn spi3(_: spi3::Context) { - panic!("ADC0 input overrun"); + panic!("ADC1 input overrun"); } #[task(binds = SPI4, priority = 3)] diff --git a/src/bin/lockin-internal.rs b/src/bin/lockin-internal.rs index 7ea7e1d..d4e90e6 100644 --- a/src/bin/lockin-internal.rs +++ b/src/bin/lockin-internal.rs @@ -2,8 +2,8 @@ #![no_std] #![no_main] -use generic_array::typenum::U2; use dsp::{Accu, Complex, ComplexExt, Lockin}; +use generic_array::typenum::U2; use hardware::{Adc1Input, Dac0Output, Dac1Output, AFE0, AFE1}; use stabilizer::{hardware, hardware::design_parameters}; @@ -45,24 +45,13 @@ const APP: () = { } } - /// Main DSP processing routine for Stabilizer. + /// Main DSP processing routine. /// - /// # Note - /// Processing time for the DSP application code is bounded by the following constraints: + /// See `dual-iir` for general notes on processing time and timing. /// - /// DSP application code starts after the ADC has generated a batch of samples and must be - /// completed by the time the next batch of ADC samples has been acquired (plus the FIFO buffer - /// time). If this constraint is not met, firmware will panic due to an ADC input overrun. - /// - /// The DSP application code must also fill out the next DAC output buffer in time such that the - /// DAC can switch to it when it has completed the current buffer. If this constraint is not met - /// it's possible that old DAC codes will be generated on the output and the output samples will - /// be delayed by 1 batch. - /// - /// Because the ADC and DAC operate at the same rate, these two constraints actually implement - /// the same time bounds, meeting one also means the other is also met. - /// - /// TODO: Document + /// This is an implementation of an internal-reference lockin on the ADC1 signal. + /// The reference at f_sample/8 is output on DAC0 and the phase of the demodulated + /// signal on DAC1. #[task(binds=DMA1_STR4, resources=[adc, dacs, lockin], priority=2)] fn process(c: process::Context) { let lockin = c.resources.lockin; @@ -72,29 +61,23 @@ const APP: () = { c.resources.dacs.1.acquire_buffer(), ]; - // DAC0 always generates a fixed sinusoidal output. - dac_samples[0] - .iter_mut() - .zip(DAC_SEQUENCE.iter()) - .for_each(|(d, s)| *d = *s as u16 ^ 0x8000); - // Reference phase and frequency are known. - let pll_phase = 0; + let pll_phase = 0i32; let pll_frequency = 1i32 << (32 - design_parameters::SAMPLE_BUFFER_SIZE_LOG2); - // Harmonic index of the LO: -1 to _de_modulate the fundamental - let harmonic: i32 = -1; // TODO: expose + // Harmonic index of the LO: -1 to _de_modulate the fundamental (complex conjugate) + let harmonic: i32 = -1; // Demodulation LO phase offset - let phase_offset: i32 = (0.25 * i32::MAX as f32) as i32; // TODO: expose + let phase_offset: i32 = 1 << 30; // Log2 lowpass time constant. let time_constant: u8 = 8; let sample_frequency = (pll_frequency as i32).wrapping_mul(harmonic); - let sample_phase = phase_offset - .wrapping_add((pll_phase as i32).wrapping_mul(harmonic)); + let sample_phase = + phase_offset.wrapping_add(pll_phase.wrapping_mul(harmonic)); let output: Complex = adc_samples .iter() @@ -110,15 +93,17 @@ const APP: () = { .unwrap() * 2; // Full scale assuming the 2f component is gone. - for value in dac_samples[1].iter_mut() { - *value = (output.arg() >> 16) as u16 ^ 0x8000; + // Convert to DAC data. + for i in 0..dac_samples[0].len() { + // DAC0 always generates a fixed sinusoidal output. + dac_samples[0][i] = DAC_SEQUENCE[i] as u16 ^ 0x8000; + dac_samples[1][i] = (output.arg() >> 16) as u16 ^ 0x8000; } } #[idle(resources=[afes])] fn idle(_: idle::Context) -> ! { loop { - // TODO: Implement network interface. cortex_m::asm::wfi(); } }