esp_hal/analog/adc/calibration/line/
s2.rs1use core::marker::PhantomData;
2
3use super::AdcHasLineCal;
4use crate::analog::adc::{AdcCalBasic, AdcCalEfuse, AdcCalScheme, Attenuation, CalibrationAccess};
5
6const COEFF_A_SCALING: i64 = 65536;
7const COEFF_B_SCALING: i64 = 1024;
8const V_HIGH: [i64; 4] = [600, 800, 1000, 2000];
9const V_LOW: i64 = 250;
10
11#[derive(Clone, Copy)]
20pub struct AdcCalLine<ADCX> {
21 basic: AdcCalBasic<ADCX>,
22 coeff_a: u32,
23 coeff_b: i32,
24 _phantom: PhantomData<ADCX>,
25}
26
27fn characterize_two_point(atten: Attenuation, high: i64, low: i64) -> (u32, i32) {
28 let v_high = V_HIGH[atten as usize];
29 let denom = (high - low).max(1);
30 let coeff_a = (COEFF_A_SCALING * (v_high - V_LOW) / denom) as u32;
31 let coeff_b = (COEFF_B_SCALING * (V_LOW * high - v_high * low) / denom) as i32;
32 (coeff_a, coeff_b)
33}
34
35impl<ADCX> crate::private::Sealed for AdcCalLine<ADCX> {}
36
37impl<ADCX> AdcCalScheme<ADCX> for AdcCalLine<ADCX>
38where
39 ADCX: AdcCalEfuse + AdcHasLineCal + CalibrationAccess,
40{
41 fn new_cal(atten: Attenuation) -> Self {
42 Self::new_cal_with_channel(atten, 0)
43 }
44
45 fn new_cal_with_channel(atten: Attenuation, channel: u8) -> Self {
46 let basic = AdcCalBasic::<ADCX>::new_cal_with_channel(atten, channel);
47 let version = crate::efuse::rtc_calib_version();
48
49 let (coeff_a, coeff_b) = match version {
50 1 => {
51 let low = crate::efuse::rtc_calib_reading(
52 version,
53 ADCX::UNIT,
54 atten,
55 crate::efuse::RtcCalibParam::Vlow,
56 );
57 let high = crate::efuse::rtc_calib_reading(
58 version,
59 ADCX::UNIT,
60 atten,
61 crate::efuse::RtcCalibParam::Vhigh,
62 );
63 characterize_two_point(atten, high as i64, low as i64)
64 }
65 2 => {
66 let high = ADCX::cal_code(atten).unwrap_or(1).max(1) as i64;
67 let mv = ADCX::cal_mv(atten) as i64;
68 (((COEFF_A_SCALING * mv) / high) as u32, 0)
69 }
70 _ => {
71 let low = crate::efuse::rtc_calib_reading_inner(
72 1,
73 ADCX::UNIT,
74 atten,
75 crate::efuse::RtcCalibParam::Vlow,
76 true,
77 );
78 let high = crate::efuse::rtc_calib_reading_inner(
79 1,
80 ADCX::UNIT,
81 atten,
82 crate::efuse::RtcCalibParam::Vhigh,
83 true,
84 );
85 characterize_two_point(atten, high as i64, low as i64)
86 }
87 };
88
89 Self {
90 basic,
91 coeff_a,
92 coeff_b,
93 _phantom: PhantomData,
94 }
95 }
96
97 fn adc_cal(&self) -> u16 {
98 self.basic.adc_cal()
99 }
100
101 fn adc_val(&self, val: u16) -> u16 {
102 let val = self.basic.adc_val(val) as i64;
103 let voltage = (val * self.coeff_a as i64 / (COEFF_A_SCALING / COEFF_B_SCALING)
104 + self.coeff_b as i64)
105 / COEFF_B_SCALING;
106 voltage.clamp(0, u16::MAX as i64) as u16
107 }
108}