diff --git a/src/bin/dual-iir.rs b/src/bin/dual-iir.rs index f681c9a..d5205d8 100644 --- a/src/bin/dual-iir.rs +++ b/src/bin/dual-iir.rs @@ -26,7 +26,9 @@ pub struct Settings { iir_ch: [[iir::IIR; IIR_CASCADE_LENGTH]; 2], allow_hold: bool, force_hold: bool, - telemetry_period_secs: u16, + + // The telemetry period in seconds. + telemetry_period: u16, } impl Default for Settings { @@ -44,7 +46,7 @@ impl Default for Settings { allow_hold: false, // Force suppress filter output updates. force_hold: false, - telemetry_period_secs: 10, + telemetry_period: 10, } } } @@ -130,9 +132,13 @@ const APP: () = { c.resources.dacs.1.acquire_buffer(), ]; + let digital_inputs = [ + c.resources.digital_inputs.0.is_high().unwrap(), + c.resources.digital_inputs.1.is_high().unwrap(), + ]; + let hold = c.resources.settings.force_hold - || (c.resources.digital_inputs.1.is_high().unwrap() - && c.resources.settings.allow_hold); + || (digital_inputs[1] && c.resources.settings.allow_hold); for channel in 0..adc_samples.len() { for sample in 0..adc_samples[0].len() { @@ -153,16 +159,12 @@ const APP: () = { } // Update telemetry measurements. - c.resources.telemetry.latest_samples = + c.resources.telemetry.adcs = [adc_samples[0][0] as i16, adc_samples[1][0] as i16]; - c.resources.telemetry.latest_outputs = - [dac_samples[0][0], dac_samples[1][0]]; + c.resources.telemetry.dacs = [dac_samples[0][0], dac_samples[1][0]]; - c.resources.telemetry.digital_inputs = [ - c.resources.digital_inputs.0.is_high().unwrap(), - c.resources.digital_inputs.1.is_high().unwrap(), - ]; + c.resources.telemetry.digital_inputs = digital_inputs; } #[idle(resources=[network], spawn=[settings_update])] @@ -202,7 +204,7 @@ const APP: () = { let telemetry_period = c .resources .settings - .lock(|settings| settings.telemetry_period_secs); + .lock(|settings| settings.telemetry_period); // Schedule the telemetry task in the future. c.schedule diff --git a/src/bin/lockin.rs b/src/bin/lockin.rs index 756e8ed..10534ba 100644 --- a/src/bin/lockin.rs +++ b/src/bin/lockin.rs @@ -56,7 +56,9 @@ pub struct Settings { lockin_phase: i32, output_conf: [Conf; 2], - telemetry_period_secs: u16, + + // The telemetry period in seconds. + telemetry_period: u16, } impl Default for Settings { @@ -73,7 +75,7 @@ impl Default for Settings { lockin_phase: 0, // Demodulation LO phase offset output_conf: [Conf::InPhase, Conf::Quadrature], - telemetry_period_secs: 10, + telemetry_period: 10, } } } @@ -237,11 +239,10 @@ const APP: () = { } // Update telemetry measurements. - c.resources.telemetry.latest_samples = + c.resources.telemetry.adcs = [adc_samples[0][0] as i16, adc_samples[1][0] as i16]; - c.resources.telemetry.latest_outputs = - [dac_samples[0][0], dac_samples[1][0]]; + c.resources.telemetry.dacs = [dac_samples[0][0], dac_samples[1][0]]; } #[idle(resources=[network], spawn=[settings_update])] @@ -285,7 +286,7 @@ const APP: () = { let telemetry_period = c .resources .settings - .lock(|settings| settings.telemetry_period_secs); + .lock(|settings| settings.telemetry_period); // Schedule the telemetry task in the future. c.schedule diff --git a/src/hardware/system_timer.rs b/src/hardware/system_timer.rs index 715cb9f..7b445c4 100644 --- a/src/hardware/system_timer.rs +++ b/src/hardware/system_timer.rs @@ -69,12 +69,12 @@ impl rtic::Monotonic for SystemTimer { // is taken when reading and modifying register values. let regs = unsafe { &*hal::device::TIM15::ptr() }; - loop { - // Checking for overflows of the current counter must be performed atomically. Any - // other task that is accessing the current time could potentially race for the - // registers. Note that this is only required for writing to global state (e.g. timer - // registers and overflow counter) - if let Some(time) = cortex_m::interrupt::free(|_cs| { + cortex_m::interrupt::free(|_cs| { + loop { + // Checking for overflows of the current counter must be performed atomically. Any + // other task that is accessing the current time could potentially race for the + // registers. Note that this is only required for writing to global state (e.g. timer + // registers and overflow counter) // Check for overflows and clear the overflow bit atomically. This must be done in // a critical section to prevent race conditions on the status register. if regs.sr.read().uif().bit_is_set() { @@ -91,14 +91,12 @@ impl rtic::Monotonic for SystemTimer { if regs.sr.read().uif().bit_is_clear() { // Note(unsafe): We are in a critical section, so it is safe to read the // global variable. - unsafe { Some((OVERFLOWS * 65535 + current_value) as i32) } - } else { - None + return unsafe { + ((OVERFLOWS << 16) + current_value) as i32 + }; } - }) { - return time; } - } + }) } /// Reset the timer count. diff --git a/src/net/telemetry.rs b/src/net/telemetry.rs index 57fc192..cf14f4f 100644 --- a/src/net/telemetry.rs +++ b/src/net/telemetry.rs @@ -33,9 +33,9 @@ pub struct TelemetryClient { #[derive(Copy, Clone)] pub struct TelemetryBuffer { /// The latest input sample on ADC0/ADC1. - pub latest_samples: [i16; 2], + pub adcs: [i16; 2], /// The latest output code on DAC0/DAC1. - pub latest_outputs: [u16; 2], + pub dacs: [u16; 2], /// The latest digital input states during processing. pub digital_inputs: [bool; 2], } @@ -47,16 +47,16 @@ pub struct TelemetryBuffer { /// overhead. #[derive(Serialize)] pub struct Telemetry { - input_levels: [f32; 2], - output_levels: [f32; 2], + adcs: [f32; 2], + dacs: [f32; 2], digital_inputs: [bool; 2], } impl Default for TelemetryBuffer { fn default() -> Self { Self { - latest_samples: [0, 0], - latest_outputs: [0, 0], + adcs: [0, 0], + dacs: [0, 0], digital_inputs: [false, false], } } @@ -79,30 +79,29 @@ impl TelemetryBuffer { // input signal has a fixed gain of 1/5 through a static input active filter. Finally, at // the very front-end of the signal, there's an analog input multiplier that is // configurable by the user. + let adc_volts_per_lsb = 5.0 * 4.096 / 2.0 / i16::MAX as f32; let in0_volts = - (self.latest_samples[0] as f32 / i16::MAX as f32) * 4.096 / 2.0 - * 5.0 - / afe0.as_multiplier(); + (adc_volts_per_lsb * self.adcs[0] as f32) / afe0.as_multiplier(); let in1_volts = - (self.latest_samples[1] as f32 / i16::MAX as f32) * 4.096 / 2.0 - * 5.0 - / afe1.as_multiplier(); + (adc_volts_per_lsb * self.adcs[1] as f32) / afe1.as_multiplier(); // The output voltage is generated by the DAC with an output range of +/- 4.096 V. This // signal then passes through a 2.5x gain stage. Note that the DAC operates using unsigned // integers, and u16::MAX / 2 is considered zero voltage output. Thus, the dynamic range of // the output stage is +/- 10.24 V. At a DAC code of zero, there is an output of -10.24 V, // and at a max DAC code, there is an output of 10.24 V. - let out0_volts = (10.24 * 2.0) - * (self.latest_outputs[0] as f32 / (u16::MAX as f32)) - - 10.24; - let out1_volts = (10.24 * 2.0) - * (self.latest_outputs[1] as f32 / (u16::MAX as f32)) - - 10.24; + // + // Note: The MAX code corresponding to +VREF is not programmable, as it is 1 bit larger + // than full-scale. + let dac_volts_per_lsb = 10.24 * 2.0 / (u16::MAX as u32 + 1) as f32; + let dac_offset = -10.24; + + let out0_volts = dac_volts_per_lsb * self.dacs[0] as f32 + dac_offset; + let out1_volts = dac_volts_per_lsb * self.dacs[1] as f32 + dac_offset; Telemetry { - input_levels: [in0_volts, in1_volts], - output_levels: [out0_volts, out1_volts], + adcs: [in0_volts, in1_volts], + dacs: [out0_volts, out1_volts], digital_inputs: self.digital_inputs, } }