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 || self.coeff.is_empty() {
96 0
97 } else {
98 let val_i64 = val as i64;
99 let mut poly = 0i64;
100
101 for &coeff in self.coeff.iter().rev() {
103 poly = poly * val_i64 + coeff;
104 }
105
106 (poly / COEFF_MUL) as i32
107 };
108
109 (val as i32 - err) as u16
110 }
111}
112
113macro_rules! coeff_tables {
114 ($($(#[$($meta:meta)*])* $name:ident [ $($att:ident => [ $($val:literal,)* ],)* ];)*) => {
115 $(
116 $(#[$($meta)*])*
117 const $name: CurvesCoeffs = &[
118 $(CurveCoeffs {
119 atten: Attenuation::$att,
120 coeff: &[
121 $(($val as f64 * COEFF_MUL as f64) as CurveCoeff,)*
122 ],
123 },)*
124 ];
125 )*
126 };
127}
128
129#[cfg(any(esp32c3, esp32c5, esp32c6, esp32h2, esp32s3))]
130mod impls {
131 use super::*;
132
133 impl AdcHasCurveCal for crate::peripherals::ADC1<'_> {
134 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
135 }
136
137 #[cfg(esp32c3)]
138 impl AdcHasCurveCal for crate::peripherals::ADC2<'_> {
139 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS1;
140 }
141
142 #[cfg(esp32s3)]
143 impl AdcHasCurveCal for crate::peripherals::ADC2<'_> {
144 const CURVES_COEFFS: CurvesCoeffs = CURVES_COEFFS2;
145 }
146
147 coeff_tables! {
148 #[cfg(esp32c3)]
150 CURVES_COEFFS1 [
151 _0dB => [
152 -0.225966470500043,
153 -0.0007265418501948,
154 0.0000109410402681,
155 ],
156 _2p5dB => [
157 0.4229623392600516,
158 -0.0000731527490903,
159 0.0000088166562521,
160 ],
161 _6dB => [
162 -1.017859239236435,
163 -0.0097159265299153,
164 0.0000149794028038,
165 ],
166 _11dB => [
167 -1.4912262772850453,
168 -0.0228549975564099,
169 0.0000356391935717,
170 -0.0000000179964582,
171 0.0000000000042046,
172 ],
173 ];
174
175 #[cfg(esp32c5)]
177 CURVES_COEFFS1 [
178 _0dB => [
179 -0.2941017829027464,
180 0.0007368674918527,
181 0.0,
182 ],
183 _2p5dB => [
184 -0.3224276125615327,
185 0.0005325658467636,
186 0.0,
187 ],
188 _6dB => [
189 -0.3307554632960901,
190 0.000409244304226,
191 0.0,
192 ],
193 _11dB => [
194 1.463642578413965,
195 -0.003349642363147,
196 0.0000011676836451,
197 ],
198 ];
199
200
201 #[cfg(esp32c6)]
203 CURVES_COEFFS1 [
204 _0dB => [
205 -0.0487166399931449,
206 0.0006436483033201,
207 0.0000030410131806,
208 ],
209 _2p5dB => [
210 -0.8665498165817785,
211 0.0015239070452946,
212 0.0000013818878844,
213 ],
214 _6dB => [
215 -1.2277821756674387,
216 0.0022275554717885,
217 0.0000005924302667,
218 ],
219 _11dB => [
220 -0.3801417550380255,
221 -0.0006020352420772,
222 0.0000012442478488,
223 ],
224 ];
225
226 #[cfg(esp32h2)]
228 CURVES_COEFFS1 [
229 _0dB => [
230 -0.5081991760658888,
231 0.0000007858995319,
232 0,
233 ],
234 _2p5dB => [
235 -0.8359230818901277,
236 0.0000009025419089,
237 0,
238 ],
239 _6dB => [
240 -1.165668771581976,
241 0.0000008294679249,
242 0,
243 ],
244 _11dB => [
245 -0.3637329628677273,
246 -0.0000196072597389,
247 0.0000007871689227,
248 ],
249 ];
250
251 #[cfg(esp32s3)]
253 CURVES_COEFFS1 [
254 _0dB => [
255 -2.7856531419538344,
256 -0.0050871540569528,
257 0.0000097982495890,
258 ],
259 _2p5dB => [
260 -2.9831022915028695,
261 -0.0049393185868806,
262 0.0000101379430548,
263 ],
264 _6dB => [
265 -2.3285545746296417,
266 -0.0147640181047414,
267 0.0000208385525314,
268 ],
269 _11dB => [
270 -0.644403418269478,
271 -0.0644334888647536,
272 0.0001297891447611,
273 -0.0000000707697180,
274 0.0000000000135150,
275 ],
276 ];
277
278 #[cfg(esp32s3)]
280 CURVES_COEFFS2 [
281 _0dB => [
282 -2.5668651654328927,
283 0.0001353548869615,
284 0.0000036615265189,
285 ],
286 _2p5dB => [
287 -2.3690184690298404,
288 -0.0066319894226185,
289 0.0000118964995959,
290 ],
291 _6dB => [
292 -0.9452499397020617,
293 -0.0200996773954387,
294 0.00000259011467956,
295 ],
296 _11dB => [
297 1.2247719764336924,
298 -0.0755717904943462,
299 0.0001478791187119,
300 -0.0000000796725280,
301 0.0000000000150380,
302 ],
303 ];
304 }
305}