From e6e150dac391e39b3992109e20c18d75ec2cbab4 Mon Sep 17 00:00:00 2001 From: Astro Date: Tue, 19 May 2020 00:15:39 +0200 Subject: [PATCH] add Channels::calibrate_dac_value() --- src/ad5680.rs | 5 +---- src/channel.rs | 9 ++++++--- src/channels.rs | 54 +++++++++++++++++++++++++++++++++++++++++++++++-- src/main.rs | 2 ++ 4 files changed, 61 insertions(+), 9 deletions(-) diff --git a/src/ad5680.rs b/src/ad5680.rs index f8b4b77..a20e294 100644 --- a/src/ad5680.rs +++ b/src/ad5680.rs @@ -6,7 +6,6 @@ use stm32f4xx_hal::{ time::MegaHertz, spi, }; -use crate::units::Volts; /// SPI Mode 1 pub const SPI_MODE: spi::Mode = spi::Mode { @@ -45,9 +44,7 @@ impl, S: OutputPin> Dac { Ok(()) } - pub fn set(&mut self, voltage: Volts) -> Result<(), SPI::Error> { - let value = ((voltage.0 * (MAX_VALUE as f64) / 5.0) as u32) - .min(MAX_VALUE); + pub fn set(&mut self, value: u32) -> Result<(), SPI::Error> { let buf = [ (value >> 14) as u8, (value >> 6) as u8, diff --git a/src/channel.rs b/src/channel.rs index c0b72a2..fb4022c 100644 --- a/src/channel.rs +++ b/src/channel.rs @@ -2,7 +2,6 @@ use crate::{ ad5680, channel_state::ChannelState, pins::{ChannelPins, ChannelPinSet}, - units::Volts, }; /// Marker type for the first channel @@ -16,6 +15,8 @@ pub struct Channel { pub state: ChannelState, /// for `i_set` pub dac: ad5680::Dac, + /// 1 / Volts + pub dac_factor: f64, pub shdn: C::Shdn, /// stm32f4 integrated adc pub adc: C::Adc, @@ -30,11 +31,13 @@ impl Channel { pub fn new(pins: ChannelPinSet) -> Self { let state = ChannelState::default(); let mut dac = ad5680::Dac::new(pins.dac_spi, pins.dac_sync); - let _ = dac.set(Volts(0.0)); + let _ = dac.set(0); + // sensible dummy preset. calibrate_i_set() must be used. + let dac_factor = ad5680::MAX_VALUE as f64 / 5.0; Channel { state, - dac, + dac, dac_factor, shdn: pins.shdn, adc: pins.adc, vref_pin: pins.vref_pin, diff --git a/src/channels.rs b/src/channels.rs index 459c5cf..d4e839e 100644 --- a/src/channels.rs +++ b/src/channels.rs @@ -1,6 +1,8 @@ use stm32f4xx_hal::hal::digital::v2::OutputPin; use smoltcp::time::Instant; +use log::info; use crate::{ + ad5680, ad7172, channel::{Channel, Channel0, Channel1}, channel_state::ChannelState, @@ -83,14 +85,21 @@ impl Channels { /// i_set DAC pub fn set_dac(&mut self, channel: usize, voltage: Volts) { + let dac_factor = match channel.into() { + 0 => self.channel0.dac_factor, + 1 => self.channel1.dac_factor, + _ => unreachable!(), + }; + let value = (voltage.0 * dac_factor) as u32; + info!("set_dac {} {}", voltage, value); match channel { 0 => { - self.channel0.dac.set(voltage).unwrap(); + self.channel0.dac.set(value).unwrap(); self.channel0.state.dac_value = voltage; self.channel0.shdn.set_high().unwrap(); } 1 => { - self.channel1.dac.set(voltage).unwrap(); + self.channel1.dac.set(value).unwrap(); self.channel1.state.dac_value = voltage; self.channel1.shdn.set_high().unwrap(); } @@ -142,6 +151,7 @@ impl Channels { } } + /// should be 1.5V pub fn read_vref(&mut self, channel: usize) -> Volts { match channel { 0 => { @@ -185,4 +195,44 @@ impl Channels { _ => unreachable!(), } } + + /// for i_set + pub fn calibrate_dac_value(&mut self, channel: usize) { + let vref = self.read_vref(channel); + let mut best_value = 0; + let mut best_error = Volts(100.0); + for value in 1..=ad5680::MAX_VALUE { + match channel { + 0 => { + self.channel0.dac.set(value).unwrap(); + self.channel0.shdn.set_high().unwrap(); + } + 1 => { + self.channel1.dac.set(value).unwrap(); + self.channel1.shdn.set_high().unwrap(); + } + _ => unreachable!(), + } + + let dac_feedback = self.read_dac_feedback(channel); + let error = vref - dac_feedback; + if error < Volts(0.0) { + info!("calibration done at {} > {}", dac_feedback, vref); + break; + } else if error < best_error { + best_value = value; + best_error = error; + } + } + + self.set_dac(channel, Volts(0.0)); + info!("best dac value for {}: {}, itec={}", vref, best_value, self.read_itec(channel)); + + let dac_factor = best_value as f64 / vref.0; + match channel { + 0 => self.channel0.dac_factor = dac_factor, + 1 => self.channel1.dac_factor = dac_factor, + _ => unreachable!(), + } + } } diff --git a/src/main.rs b/src/main.rs index d70b68a..84642c5 100644 --- a/src/main.rs +++ b/src/main.rs @@ -96,6 +96,8 @@ fn main() -> ! { dp.ADC1, dp.ADC2, dp.ADC3, ); let mut channels = Channels::new(pins); + channels.calibrate_dac_value(0); + timer::setup(cp.SYST, clocks); #[cfg(not(feature = "generate-hwaddr"))]