esp_hal/analog/adc/calibration/
curve.rs1use core::marker::PhantomData;
2
3use crate::analog::adc::{
4 AdcCalEfuse,
5 AdcCalLine,
6 AdcCalScheme,
7 AdcHasLineCal,
8 Attenuation,
9 CalibrationAccess,
10};
11
12const COEFF_MUL: i64 = 1 << 52;
13
14type CurveCoeff = i64;
17
18pub struct CurveCoeffs {
20 atten: Attenuation,
22 coeff: &'static [CurveCoeff],
24}
25
26type CurvesCoeffs = &'static [CurveCoeffs];
27
28pub trait AdcHasCurveCal {
32 const CURVES_COEFFS: CurvesCoeffs;
36}
37
38#[derive(Clone, Copy)]
46pub struct AdcCalCurve<ADCI> {
47 line: AdcCalLine<ADCI>,
48
49 coeff: &'static [CurveCoeff],
59
60 _phantom: PhantomData<ADCI>,
61}
62
63impl<ADCI> crate::private::Sealed for AdcCalCurve<ADCI> {}
64
65impl<ADCI> AdcCalScheme<ADCI> for AdcCalCurve<ADCI>
66where
67 ADCI: AdcCalEfuse + AdcHasLineCal + AdcHasCurveCal + CalibrationAccess,
68{
69 fn new_cal(atten: Attenuation) -> Self {
70 let line = AdcCalLine::<ADCI>::new_cal(atten);
71
72 let coeff = ADCI::CURVES_COEFFS
73 .iter()
74 .find(|item| item.atten == atten)
75 .expect("No curve coefficients for given attenuation")
76 .coeff;
77
78 Self {
79 line,
80 coeff,
81 _phantom: PhantomData,
82 }
83 }
84
85 fn adc_cal(&self) -> u16 {
86 self.line.adc_cal()
87 }
88
89 fn adc_val(&self, val: u16) -> u16 {
90 let val = self.line.adc_val(val);
91
92 let err = if val == 0 {
93 0
94 } else {
95 let mut var = 1i64;
97 let mut err = (var * self.coeff[0] / COEFF_MUL) as i32;
98
99 for coeff in &self.coeff[1..] {
100 var *= val as i64;
101 err += (var * *coeff / COEFF_MUL) as i32;
102 }
103
104 err
105 };
106
107 (val as i32 - err) as u16
108 }
109}
110
111macro_rules! coeff_tables {
112 ($($(#[$($meta:meta)*])* $name:ident [ $($att:ident => [ $($val:literal,)* ],)* ];)*) => {
113 $(
114 $(#[$($meta)*])*
115 const $name: CurvesCoeffs = &[
116 $(CurveCoeffs {
117 atten: Attenuation::$att,
118 coeff: &[
119 $(($val as f64 * COEFF_MUL as f64) as CurveCoeff,)*
120 ],
121 },)*
122 ];
123 )*
124 };
125}
126
127#[cfg(any(esp32c3, esp32c6, esp32h2, esp32s3))]
128mod impls {
129 use super::*;
130
131 impl AdcHasCurveCal for crate::peripherals::ADC1<'_> {
132 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
133 }
134
135 #[cfg(esp32c3)]
136 impl AdcHasCurveCal for crate::peripherals::ADC2<'_> {
137 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
138 }
139
140 #[cfg(esp32s3)]
141 impl AdcHasCurveCal for crate::peripherals::ADC2<'_> {
142 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS2;
143 }
144
145 coeff_tables! {
146 #[cfg(esp32c3)]
148 CURVES_COEFFS1 [
149 _0dB => [
150 -0.225966470500043,
151 -0.0007265418501948,
152 0.0000109410402681,
153 ],
154 _2p5dB => [
155 0.4229623392600516,
156 -0.0000731527490903,
157 0.0000088166562521,
158 ],
159 _6dB => [
160 -1.017859239236435,
161 -0.0097159265299153,
162 0.0000149794028038,
163 ],
164 _11dB => [
165 -1.4912262772850453,
166 -0.0228549975564099,
167 0.0000356391935717,
168 -0.0000000179964582,
169 0.0000000000042046,
170 ],
171 ];
172
173 #[cfg(esp32c6)]
175 CURVES_COEFFS1 [
176 _0dB => [
177 -0.0487166399931449,
178 0.0006436483033201,
179 0.0000030410131806,
180 ],
181 _2p5dB => [
182 -0.8665498165817785,
183 0.0015239070452946,
184 0.0000013818878844,
185 ],
186 _6dB => [
187 -1.2277821756674387,
188 0.0022275554717885,
189 0.0000005924302667,
190 ],
191 _11dB => [
192 -0.3801417550380255,
193 -0.0006020352420772,
194 0.0000012442478488,
195 ],
196 ];
197
198 #[cfg(esp32h2)]
200 CURVES_COEFFS1 [
201 _0dB => [
202 -0.5081991760658888,
203 0.0000007858995319,
204 0,
205 ],
206 _2p5dB => [
207 -0.8359230818901277,
208 0.0000009025419089,
209 0,
210 ],
211 _6dB => [
212 -1.165668771581976,
213 0.0000008294679249,
214 0,
215 ],
216 _11dB => [
217 -0.3637329628677273,
218 -0.0000196072597389,
219 0.0000007871689227,
220 ],
221 ];
222
223 #[cfg(esp32s3)]
225 CURVES_COEFFS1 [
226 _0dB => [
227 -2.7856531419538344,
228 -0.0050871540569528,
229 0.0000097982495890,
230 ],
231 _2p5dB => [
232 -2.9831022915028695,
233 -0.0049393185868806,
234 0.0000101379430548,
235 ],
236 _6dB => [
237 -2.3285545746296417,
238 -0.0147640181047414,
239 0.0000208385525314,
240 ],
241 _11dB => [
242 -0.644403418269478,
243 -0.0644334888647536,
244 0.0001297891447611,
245 -0.0000000707697180,
246 0.0000000000135150,
247 ],
248 ];
249
250 #[cfg(esp32s3)]
252 CURVES_COEFFS2 [
253 _0dB => [
254 -2.5668651654328927,
255 0.0001353548869615,
256 0.0000036615265189,
257 ],
258 _2p5dB => [
259 -2.3690184690298404,
260 -0.0066319894226185,
261 0.0000118964995959,
262 ],
263 _6dB => [
264 -0.9452499397020617,
265 -0.0200996773954387,
266 0.00000259011467956,
267 ],
268 _11dB => [
269 1.2247719764336924,
270 -0.0755717904943462,
271 0.0001478791187119,
272 -0.0000000796725280,
273 0.0000000000150380,
274 ],
275 ];
276 }
277}