diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index d9942c16572..03b9d9622ab 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -45,8 +45,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - `DmaDescriptor` is now `#[repr(C)]` (#2988) - Fixed an issue that caused LCD_CAM drivers to turn off their clocks unexpectedly (#3007) - Fixed an issue where DMA-driver peripherals started transferring before the data was ready (#3003) +- Fixed an issue where ADC Curve Calibration overflows when converting from a value > 3095 (#3061) - Fixed an issue on ESP32 and S2 where short asynchronous Timer delays would never resolve (#3093) - - ESP32-S2: Fixed linker script (#3096) ### Removed diff --git a/esp-hal/src/analog/adc/calibration/curve.rs b/esp-hal/src/analog/adc/calibration/curve.rs index ce60626d605..d58f9f5c004 100644 --- a/esp-hal/src/analog/adc/calibration/curve.rs +++ b/esp-hal/src/analog/adc/calibration/curve.rs @@ -92,16 +92,12 @@ where let err = if val == 0 { 0 } else { - // err = coeff[0] + coeff[1] * val + coeff[2] * val^2 + ... + coeff[n] * val^n - let mut var = 1i64; - let mut err = (var * self.coeff[0] / COEFF_MUL) as i32; - - for coeff in &self.coeff[1..] { - var *= val as i64; - err += (var * *coeff / COEFF_MUL) as i32; + let x = val as i64; + let mut poly = 0_i64; + for &c in self.coeff.iter().rev() { + poly = poly * x + c; } - - err + (poly / COEFF_MUL) as i32 }; (val as i32 - err) as u16 diff --git a/qa-test/src/bin/adc_calibration.rs b/qa-test/src/bin/adc_calibration.rs new file mode 100644 index 00000000000..43d82727821 --- /dev/null +++ b/qa-test/src/bin/adc_calibration.rs @@ -0,0 +1,105 @@ +//! This example tests all calibration types with all Attenuations +//! and continuosly read and print ADC read pin values. +//! +//! Following pins are used: +//! - ADC read pin => GPIO3 + +//% CHIPS: esp32s3 + +#![no_std] +#![no_main] + +use esp_backtrace as _; +use esp_hal::{analog::adc::*, delay::Delay, gpio::GpioPin, main, peripherals::ADC1}; +use esp_println::*; + +// Samples per second +const SAMPLES: usize = 100; + +#[main] +fn main() -> ! { + esp_println::logger::init_logger_from_env(); + + println!("\nStarting adc overflow check"); + + let ph = esp_hal::init(esp_hal::Config::default()); + + let atenuattion: &[Attenuation] = &[ + Attenuation::_0dB, + #[cfg(not(feature = "esp32c2"))] + Attenuation::_2p5dB, + #[cfg(not(feature = "esp32c2"))] + Attenuation::_6dB, + Attenuation::_11dB, + ]; + + // check for overflow + for atn in atenuattion { + println!(); + println!("Starting Test with {:?} Attenuation:", atn); + println!(); + + let basic = AdcCalBasic::::new_cal(*atn); + + // only resolution its 13b + for value in 0..4096 { + basic.adc_val(value); + } + + println!("Passed basic calibration."); + + let line = AdcCalLine::::new_cal(*atn); + + // only resolution its 13b + for value in 0..4096 { + line.adc_val(value); + } + + println!("Passed line calibration."); + + cfg_if::cfg_if! { + if #[cfg(not(feature = "esp32c2"))] + { + let curve = AdcCalCurve::::new_cal(*atn); + + //only resolution its 13b + for value in 0..4096 { + curve.adc_val(value); + } + + println!( + "Passed curve calibration." + ); + } + } + } + + let mut adc1_config = AdcConfig::new(); + + // this need to be called to calibrate the esp + AdcConfig::::adc_calibrate(Attenuation::_11dB, AdcCalSource::Ref); + + // Instead of create a new calibration and convert outside, attach the pin with + // a calibration scheme + let mut pin = adc1_config + .enable_pin_with_cal::, AdcCalCurve>(ph.GPIO3, Attenuation::_11dB); + + let mut adc = Adc::new(ph.ADC1, adc1_config); + + let delay = Delay::new(); + + loop { + // Taking the arithmetic average over 1 Second + let average = { + let mut val = 0.0; + for _ in 1..SAMPLES { + val += (adc.read_blocking(&mut pin) as f32) / 1000.0; + + delay.delay_millis(1000 / SAMPLES as u32); + } + val + } / SAMPLES as f32; + + println!("Value: {:?}", average); + } +}