Adding initial working proof of concept

This commit is contained in:
Ryan Summers 2021-06-28 13:40:59 +02:00
parent 9cca1497b7
commit 68859c387a
3 changed files with 65 additions and 30 deletions

View File

@ -14,9 +14,9 @@ use stabilizer::{
dac::{Dac0Output, Dac1Output, DacCode}, dac::{Dac0Output, Dac1Output, DacCode},
embedded_hal::digital::v2::InputPin, embedded_hal::digital::v2::InputPin,
hal, hal,
signal_generator::{self, SignalGenerator},
system_timer::SystemTimer, system_timer::SystemTimer,
DigitalInput0, DigitalInput1, AFE0, AFE1, DigitalInput0, DigitalInput1, AFE0, AFE1,
signal_generator::SignalGenerator,
}, },
net::{ net::{
data_stream::{BlockGenerator, StreamTarget}, data_stream::{BlockGenerator, StreamTarget},
@ -40,11 +40,12 @@ pub struct Settings {
force_hold: bool, force_hold: bool,
telemetry_period: u16, telemetry_period: u16,
stream_target: StreamTarget, stream_target: StreamTarget,
signal_generator: signal_generator::Config; signal_generator: signal_generator::Config,
output_mode: [OutputMode; 2], output_mode: [OutputMode; 2],
} }
pub struct OutputMode { #[derive(Copy, Clone, Debug, PartialEq, Deserialize, Miniconf)]
pub enum OutputMode {
IirFilter, IirFilter,
SignalGenerator, SignalGenerator,
} }
@ -70,6 +71,7 @@ impl Default for Settings {
signal_generator: signal_generator::Config::default(), signal_generator: signal_generator::Config::default(),
stream_target: StreamTarget::default(), stream_target: StreamTarget::default(),
output_mode: [OutputMode::IirFilter, OutputMode::IirFilter],
} }
} }
} }
@ -83,6 +85,7 @@ const APP: () = {
dacs: (Dac0Output, Dac1Output), dacs: (Dac0Output, Dac1Output),
network: NetworkUsers<Settings, Telemetry>, network: NetworkUsers<Settings, Telemetry>,
generator: BlockGenerator, generator: BlockGenerator,
signal_generator: SignalGenerator,
settings: Settings, settings: Settings,
telemetry: TelemetryBuffer, telemetry: TelemetryBuffer,
@ -123,6 +126,8 @@ const APP: () = {
// Start sampling ADCs. // Start sampling ADCs.
stabilizer.adc_dac_timer.start(); stabilizer.adc_dac_timer.start();
let settings = Settings::default();
init::LateResources { init::LateResources {
afes: stabilizer.afes, afes: stabilizer.afes,
adcs: stabilizer.adcs, adcs: stabilizer.adcs,
@ -131,7 +136,8 @@ const APP: () = {
network, network,
digital_inputs: stabilizer.digital_inputs, digital_inputs: stabilizer.digital_inputs,
telemetry: TelemetryBuffer::default(), telemetry: TelemetryBuffer::default(),
settings: Settings::default(), settings,
signal_generator: SignalGenerator::new(settings.signal_generator),
} }
} }
@ -151,7 +157,7 @@ const APP: () = {
/// ///
/// Because the ADC and DAC operate at the same rate, these two constraints actually implement /// 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. /// the same time bounds, meeting one also means the other is also met.
#[task(binds=DMA1_STR4, resources=[adcs, digital_inputs, dacs, iir_state, settings, telemetry, generator], priority=2)] #[task(binds=DMA1_STR4, resources=[adcs, digital_inputs, dacs, iir_state, settings, signal_generator, telemetry, generator], priority=2)]
#[inline(never)] #[inline(never)]
#[link_section = ".itcm.process"] #[link_section = ".itcm.process"]
fn process(mut c: process::Context) { fn process(mut c: process::Context) {
@ -163,6 +169,7 @@ const APP: () = {
ref mut iir_state, ref mut iir_state,
ref mut telemetry, ref mut telemetry,
ref mut generator, ref mut generator,
ref mut signal_generator,
} = c.resources; } = c.resources;
let digital_inputs = [ let digital_inputs = [
@ -207,17 +214,25 @@ const APP: () = {
// Do not generate the samples twice, or we may mess up phasing of the // Do not generate the samples twice, or we may mess up phasing of the
// signal generator. Instead, copy the previously-generated signal. // signal generator. Instead, copy the previously-generated signal.
// TODO: Is there a nicer way we can handle this edge case? // TODO: Is there a nicer way we can handle this edge case?
if (channel == 1) && settings.output_mode[0] == OutputMode::SignalGenerator { if (channel == 1)
adc_samples[1].copy_from_slice(adc_samples[0]); && settings.output_mode[0]
== OutputMode::SignalGenerator
{
*dac_samples[1] = *dac_samples[0];
} else { } else {
signal_generator.generate(&mut adc_samples[channel]); signal_generator
.generate(&mut dac_samples[channel][..]);
} }
} }
} }
} }
if !settings.output_mode.iter().any(|&mode| mode == OutputMode::SignalGenerator) { if !settings
signal_generator.skip(adc_samples[0].len()); .output_mode
.iter()
.any(|&mode| mode == OutputMode::SignalGenerator)
{
signal_generator.skip(adc_samples[0].len() as u32);
} }
// Stream the data. // Stream the data.
@ -248,7 +263,7 @@ const APP: () = {
} }
} }
#[task(priority = 1, resources=[network, afes, settings])] #[task(priority = 1, resources=[network, afes, settings, signal_generator])]
fn settings_update(mut c: settings_update::Context) { fn settings_update(mut c: settings_update::Context) {
// Update the IIR channels. // Update the IIR channels.
let settings = c.resources.network.miniconf.settings(); let settings = c.resources.network.miniconf.settings();
@ -259,7 +274,9 @@ const APP: () = {
c.resources.afes.1.set_gain(settings.afe[1]); c.resources.afes.1.set_gain(settings.afe[1]);
// Update the signal generator // Update the signal generator
c.resources.signal_generator.update_waveform(settings.signal_generator); c.resources.signal_generator.lock(|generator| {
generator.update_waveform(settings.signal_generator)
});
let target = settings.stream_target.into(); let target = settings.stream_target.into();
c.resources.network.direct_stream(target); c.resources.network.direct_stream(target);

View File

@ -96,7 +96,7 @@ const APP: () = {
telemetry: TelemetryBuffer, telemetry: TelemetryBuffer,
digital_inputs: (DigitalInput0, DigitalInput1), digital_inputs: (DigitalInput0, DigitalInput1),
generator: BlockGenerator, generator: BlockGenerator,
signal_generator: signal_generator::Generator, signal_generator: signal_generator::SignalGenerator,
timestamper: InputStamper, timestamper: InputStamper,
pll: RPLL, pll: RPLL,
@ -156,7 +156,7 @@ const APP: () = {
digital_inputs: stabilizer.digital_inputs, digital_inputs: stabilizer.digital_inputs,
timestamper: stabilizer.timestamper, timestamper: stabilizer.timestamper,
telemetry: TelemetryBuffer::default(), telemetry: TelemetryBuffer::default(),
signal_generator: signal_generator::Generator::new( signal_generator: signal_generator::SignalGenerator::new(
signal_generator::Config { signal_generator::Config {
period: design_parameters::SAMPLE_BUFFER_SIZE as u32, period: design_parameters::SAMPLE_BUFFER_SIZE as u32,
symmetry: 0.5, symmetry: 0.5,

View File

@ -1,11 +1,15 @@
#[derive(Copy, Clone, Debug)] use crate::hardware::dac::DacCode;
use miniconf::Miniconf;
use serde::Deserialize;
#[derive(Copy, Clone, Debug, Deserialize, Miniconf)]
pub enum Signal { pub enum Signal {
Sine, Sine,
Square, Square,
Triangle, Triangle,
} }
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, Miniconf, Deserialize)]
pub struct Config { pub struct Config {
// TODO: Should period be specified in Hz? // TODO: Should period be specified in Hz?
pub period: u32, pub period: u32,
@ -102,19 +106,21 @@ impl SignalGenerator {
/// ///
/// # Args /// # Args
/// * `samples` - The location to store generated values into. /// * `samples` - The location to store generated values into.
pub fn generate(&mut self, samples: &mut [i16]) { pub fn generate(&mut self, samples: &mut [u16]) {
for sample in samples.iter_mut() { for sample in samples.iter_mut() {
*sample = self.next(); *sample = DacCode::from(self.next()).0;
} }
} }
/// Skip `count` elements of the generator /// Skip `count` elements of the generator
pub fn skip(&mut self, count: usize) { pub fn skip(&mut self, count: u32) {
let index = self.index.wrapping_add(count); let index = self.index.wrapping_add(count);
// If we skip past the period of the signal, apply any pending config. // If we skip past the period of the signal, apply any pending config.
if index > self.config.period && let Some(config) = self.pendig_config.take() { if index > self.config.period {
self.config = config; if let Some(config) = self.pending_config.take() {
self.config = config;
}
} }
self.index = index % self.config.period; self.index = index % self.config.period;
@ -140,25 +146,37 @@ impl SignalGenerator {
} }
Signal::Triangle => { Signal::Triangle => {
if phase < self.config.phase_symmetry { if phase < self.config.phase_symmetry {
let duration_of_phase = (self.config.phase_symmetry.wrapping_sub(i32::MIN) >> 16) as u16; let duration_of_phase =
let phase_progress = (phase.wrapping_sub(i32::MIN) >> 16) as u16; (self.config.phase_symmetry.wrapping_sub(i32::MIN)
>> 16) as u16;
let phase_progress =
(phase.wrapping_sub(i32::MIN) >> 16) as u16;
if duration_of_phase == 0 { if duration_of_phase == 0 {
i16::MIN i16::MIN
} else { } else {
i16::MIN.wrapping_add((u16::MAX as u32 * phase_progress as u32 / i16::MIN.wrapping_add(
duration_of_phase as u32) as i16) (u16::MAX as u32 * phase_progress as u32
/ duration_of_phase as u32)
as i16,
)
} }
} else { } else {
let duration_of_phase =
let duration_of_phase = (i32::MAX.wrapping_sub(self.config.phase_symmetry) >> 16) as u16; (i32::MAX.wrapping_sub(self.config.phase_symmetry)
let phase_progress = (phase.wrapping_sub(self.config.phase_symmetry) >> 16) as >> 16) as u16;
u16; let phase_progress = (phase
.wrapping_sub(self.config.phase_symmetry)
>> 16) as u16;
if duration_of_phase == 0 { if duration_of_phase == 0 {
i16::MAX i16::MAX
} else { } else {
i16::MAX.wrapping_sub((u16::MAX as u32 * phase_progress as u32 / duration_of_phase as u32) as i16) i16::MAX.wrapping_sub(
(u16::MAX as u32 * phase_progress as u32
/ duration_of_phase as u32)
as i16,
)
} }
} }
} }