@@ -5,10 +5,11 @@ package machine
55import (
66 "device/esp"
77 "errors"
8- "runtime/volatile"
9- "unsafe"
108)
119
10+ // newRegI2C returns the regI2C configured for ESP32-C3: hostID=0, drefInit=1.
11+ func newRegI2C () regI2C { return regI2C {hostID : 0 , drefInit : 1 } }
12+
1213const (
1314 // ADC attenuation values for ESP32-C3 APB_SARADC.
1415 // 0 dB : ~0 .. 1.1 V
@@ -34,8 +35,7 @@ func InitADC() {
3435 esp .APB_SARADC .SetCLKM_CONF_CLKM_DIV_A (0 )
3536 esp .APB_SARADC .SetCLKM_CONF_CLK_EN (1 )
3637
37- var c adcSelfCalibration
38- c .calibrate ()
38+ adcSelfCalibrate ()
3939}
4040
4141// ESP32-C3: ADC1 = GPIO0–GPIO4 (ch 0–4), ADC2 = GPIO5 (ch 0). ADC2 shares with Wi‑Fi;
@@ -88,51 +88,51 @@ func (a ADC) Get() uint16 {
8888
8989// adcSelfCalibration
9090const (
91- adcCalTimesC3 = 15
92- adcCalOffsetRangeC3 = uint32 (4096 )
93- adcCalRtcMagicC3 = uint32 (0xADC1C401 )
94- adcCalInitMinC3 = uint32 (1000 )
95- adcCalInitMaxC3 = uint32 (4096 )
96- adcGndOffsetCompC3 = uint32 (0 )
91+ adcCalTimesC3 = 15
92+ adcCalRtcMagicC3 = uint32 (0xADC1C401 )
93+ adcCalInitMinC3 = uint32 (1000 )
94+ adcCalInitMaxC3 = uint32 (4096 )
9795)
9896
99- type adcSelfCalibration struct {
100- digiRefMv uint32
101- }
102-
103- // calibrate sets ADC1/ADC2 init code from RTC or runs self-calibration (GND).
97+ // selfCalibrate sets ADC1/ADC2 init code from RTC or runs self-calibration (GND).
10498// eFuse is not used: on ESP32-C3 the ADC calibration fields in BLK2 are often unprogrammed.
105- func ( c * adcSelfCalibration ) calibrate () {
106- reg := regI2C {}
99+ func adcSelfCalibrate () {
100+ reg := newRegI2C ()
107101 reg .sarEnable ()
108102
109103 var adc1Code uint32
110- if saved , ok := c . restoreFromRTC (); ok {
104+ if saved , ok := restoreFromRTC (); ok {
111105 adc1Code = saved
112106 } else {
113- c .calSetupADC1 ()
114- reg .adc1CalibrationInit (0 )
115- reg .adc1CalibrationPrepare (0 )
116- adc1Code = c .calibrateUnit (reg , 0 , c .readADC1 )
117- c .saveToRTC (adc1Code )
118- reg .adc1CalibrationFinish (0 )
107+ calSetupADC1 ()
108+ reg .calibrationInit (0 )
109+ reg .calibrationPrepare (0 )
110+ adc1Code = reg .calibrateBinarySearch (0 , adcCalTimesC3 , readADC1 )
111+ if adc1Code < adcCalInitMinC3 {
112+ adc1Code = adcCalInitMinC3
113+ }
114+ if adc1Code > adcCalInitMaxC3 {
115+ adc1Code = adcCalInitMaxC3
116+ }
117+ saveToRTC (adc1Code )
118+ reg .calibrationFinish (0 )
119119 }
120120
121- c . applyADC1Code (reg , adc1Code )
122- c . applyADC2Code (reg , adc1Code )
121+ applyADC1Code (reg , adc1Code )
122+ applyADC2Code (reg , adc1Code )
123123}
124124
125125// calSetupADC1 configures APB_SARADC for oneshot sampling on ADC1 channel 0
126126// with fixed attenuation. This is used only during self‑calibration.
127- func ( c * adcSelfCalibration ) calSetupADC1 () {
127+ func calSetupADC1 () {
128128 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_ATTEN (atten11dB )
129129 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL (0 )
130130 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC1_ONETIME_SAMPLE (1 )
131131}
132132
133133// calSetupADC2 configures APB_SARADC for oneshot sampling on ADC2 (GPIO5, ch 0).
134134// On C3, onetime_channel = (unit<<3)|channel → ADC2 ch0 = 8.
135- func ( c * adcSelfCalibration ) calSetupADC2 () {
135+ func calSetupADC2 () {
136136 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_ATTEN (atten11dB )
137137 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_CHANNEL (8 ) // (1<<3)|0 for ADC2
138138 esp .APB_SARADC .SetARB_CTRL_ADC_ARB_APB_FORCE (1 )
@@ -142,7 +142,7 @@ func (c *adcSelfCalibration) calSetupADC2() {
142142
143143// readADC1 performs a single ADC1 conversion using the APB_SARADC
144144// oneshot path and returns the raw 12‑bit result (0..4095).
145- func ( c * adcSelfCalibration ) readADC1 () uint32 {
145+ func readADC1 () uint32 {
146146 esp .APB_SARADC .SetINT_CLR_APB_SARADC1_DONE_INT_CLR (1 )
147147 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_START (0 )
148148 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_START (1 )
@@ -154,7 +154,7 @@ func (c *adcSelfCalibration) readADC1() uint32 {
154154}
155155
156156// readADC2 performs a single ADC2 conversion and returns the raw 12‑bit result (0..4095).
157- func ( c * adcSelfCalibration ) readADC2 () uint32 {
157+ func readADC2 () uint32 {
158158 esp .APB_SARADC .SetINT_CLR_APB_SARADC2_DONE_INT_CLR (1 )
159159 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_START (0 )
160160 esp .APB_SARADC .SetONETIME_SAMPLE_SARADC_ONETIME_START (1 )
@@ -167,7 +167,7 @@ func (c *adcSelfCalibration) readADC2() uint32 {
167167 return uint32 (raw )
168168}
169169
170- func ( c * adcSelfCalibration ) restoreFromRTC () (uint32 , bool ) {
170+ func restoreFromRTC () (uint32 , bool ) {
171171 if esp .RTC_CNTL .GetSTORE0 () != adcCalRtcMagicC3 {
172172 return 0 , false
173173 }
@@ -178,7 +178,7 @@ func (c *adcSelfCalibration) restoreFromRTC() (uint32, bool) {
178178 return code , true
179179}
180180
181- func ( c * adcSelfCalibration ) saveToRTC (code uint32 ) {
181+ func saveToRTC (code uint32 ) {
182182 if code < adcCalInitMinC3 || code > adcCalInitMaxC3 {
183183 return
184184 }
@@ -187,228 +187,19 @@ func (c *adcSelfCalibration) saveToRTC(code uint32) {
187187}
188188
189189// applyADC1Code sets ADC1 init code and finishes calibration.
190- func ( c * adcSelfCalibration ) applyADC1Code (reg regI2C , code uint32 ) {
191- c . calSetupADC1 ()
192- reg .adc1CalibrationInit (0 )
193- reg .adc1CalibrationPrepare (0 )
194- reg .adc1SetCalibrationParam (0 , code )
195- reg .adc1CalibrationFinish (0 )
190+ func applyADC1Code (reg regI2C , code uint32 ) {
191+ calSetupADC1 ()
192+ reg .calibrationInit (0 )
193+ reg .calibrationPrepare (0 )
194+ reg .setCalibrationParam (0 , code )
195+ reg .calibrationFinish (0 )
196196}
197197
198198// applyADC2Code sets ADC2 init code and finishes calibration. On C3 eFuse V1
199199// there is no separate ADC2 calibration; IDF uses ADC1 init code for both units.
200- func (c * adcSelfCalibration ) applyADC2Code (reg regI2C , code uint32 ) {
201- reg .adc1CalibrationInit (1 )
202- reg .adc1CalibrationPrepare (1 )
203- reg .adc1SetCalibrationParam (1 , code )
204- reg .adc1CalibrationFinish (1 )
205- }
206-
207- func (c * adcSelfCalibration ) calibrateUnit (reg regI2C , adcN uint8 , readADC func () uint32 ) uint32 {
208- var codeList [adcCalTimesC3 ]uint32
209- var codeSum uint32
210-
211- for rpt := 0 ; rpt < adcCalTimesC3 ; rpt ++ {
212- codeH := adcCalOffsetRangeC3
213- codeL := uint32 (0 )
214- chkCode := (codeH + codeL ) / 2
215- reg .adc1SetCalibrationParam (adcN , chkCode )
216- selfCal := readADC ()
217-
218- for codeH - codeL > 1 {
219- if selfCal == 0 {
220- codeH = chkCode
221- } else {
222- codeL = chkCode
223- }
224- chkCode = (codeH + codeL ) / 2
225- reg .adc1SetCalibrationParam (adcN , chkCode )
226- selfCal = readADC ()
227- if codeH - codeL == 1 {
228- chkCode ++
229- reg .adc1SetCalibrationParam (adcN , chkCode )
230- selfCal = readADC ()
231- }
232- }
233- codeList [rpt ] = chkCode
234- codeSum += chkCode
235- }
236-
237- codeL := codeList [0 ]
238- codeH := codeList [0 ]
239- for i := 0 ; i < adcCalTimesC3 ; i ++ {
240- if codeList [i ] < codeL {
241- codeL = codeList [i ]
242- }
243- if codeList [i ] > codeH {
244- codeH = codeList [i ]
245- }
246- }
247- excluded := codeH + codeL
248- remaining := codeSum - excluded
249- finalCode := remaining / (adcCalTimesC3 - 2 )
250- if remaining % (adcCalTimesC3 - 2 ) >= 4 {
251- finalCode ++
252- }
253- if finalCode < adcCalInitMinC3 {
254- finalCode = adcCalInitMinC3
255- }
256- if finalCode > adcCalInitMaxC3 {
257- finalCode = adcCalInitMaxC3
258- }
259-
260- reg .adc1SetCalibrationParam (adcN , finalCode )
261- return finalCode
262- }
263-
264- // regi2c
265-
266- // regI2C on ESP32‑C3 exposes the internal analog I2C bus that controls
267- // SAR ADC trim registers. Constants below mirror the layout from
268- // ESP‑IDF's soc/regi2c_saradc.h and TRM (I2C_RTC_CONFIG2 block).
269- const (
270- // i2cSarADC/i2cSarADCHostID select the SAR ADC block on the internal bus.
271- i2cSarADC = uint8 (0x69 )
272- i2cSarADCHostID = uint8 (0 )
273-
274- // adc*_Dref* define the DREF (reference) bitfields for ADC1/ADC2.
275- adc1DrefAddr = uint8 (0x2 )
276- adc1DrefMSB = uint8 (6 )
277- adc1DrefLSB = uint8 (4 )
278-
279- adc2DrefAddr = uint8 (0x5 )
280- adc2DrefMSB = uint8 (6 )
281- adc2DrefLSB = uint8 (4 )
282-
283- // adc*_EncalGnd* control ENCAL_GND: route internal ground to ADC input
284- // during self‑calibration so that the pin is effectively disconnected.
285- adc1EncalGndAddr = uint8 (0x7 )
286- adc1EncalGndMSB = uint8 (5 )
287- adc1EncalGndLSB = uint8 (5 )
288-
289- adc2EncalGndAddr = uint8 (0x7 )
290- adc2EncalGndMSB = uint8 (7 )
291- adc2EncalGndLSB = uint8 (7 )
292-
293- // adc*_InitCode* hold the INIT_CODE (offset) that hardware uses to
294- // compensate ADC1/ADC2 offset error.
295- adc1InitCodeHighAddr = uint8 (0x1 )
296- adc1InitCodeHighMSB = uint8 (3 )
297- adc1InitCodeHighLSB = uint8 (0 )
298- adc1InitCodeLowAddr = uint8 (0x0 )
299- adc1InitCodeLowMSB = uint8 (7 )
300- adc1InitCodeLowLSB = uint8 (0 )
301-
302- adc2InitCodeHighAddr = uint8 (0x4 )
303- adc2InitCodeHighMSB = uint8 (3 )
304- adc2InitCodeHighLSB = uint8 (0 )
305- adc2InitCodeLowAddr = uint8 (0x3 )
306- adc2InitCodeLowMSB = uint8 (7 )
307- adc2InitCodeLowLSB = uint8 (0 )
308-
309- // ANA_CONFIG/ANA_CONFIG2: enable analog SAR I2C domain before regI2C access.
310- anaConfigReg = uintptr (0x6000E044 )
311- i2cSarEnMask = uint32 (1 << 18 )
312- anaConfig2Reg = uintptr (0x6000E048 )
313- anaSarCfg2En = uint32 (1 << 16 )
314-
315- // I2C_RTC_CONFIG2 master control register used by regI2C operations.
316- i2cMstCtrlHost = uintptr (0x6000E000 )
317- i2cMstBusyBit = uint32 (1 << 25 )
318- i2cMstWrCntl = uint32 (1 << 24 )
319- i2cMstDataMask = uint32 (0xFF << 16 )
320- i2cMstDataShift = 16
321- i2cMstTimeout = 10000
322- )
323-
324- type regI2C struct {}
325-
326- // sarEnable enables the SAR analog I2C domain before any regI2C access.
327- func (r * regI2C ) sarEnable () {
328- cfg := (* volatile .Register32 )(unsafe .Pointer (anaConfigReg ))
329- cfg2 := (* volatile .Register32 )(unsafe .Pointer (anaConfig2Reg ))
330- esp .RTC_CNTL .SetANA_CONF_SAR_I2C_PU (1 )
331- cfg .Set (cfg .Get () &^ i2cSarEnMask )
332- cfg2 .Set (cfg2 .Get () | anaSarCfg2En )
333- }
334-
335- // adc1CalibrationInit sets DREF for the selected ADC unit
336- // before running the self‑calibration procedure.
337- func (r * regI2C ) adc1CalibrationInit (adcN uint8 ) {
338- if adcN == 0 {
339- r .writeMask (i2cSarADC , i2cSarADCHostID , adc1DrefAddr , adc1DrefMSB , adc1DrefLSB , 1 )
340- } else {
341- r .writeMask (i2cSarADC , i2cSarADCHostID , adc2DrefAddr , adc2DrefMSB , adc2DrefLSB , 1 )
342- }
343- }
344-
345- // adc1CalibrationPrepare enables ENCAL_GND so that the ADC input
346- // is internally shorted to ground during self‑calibration.
347- func (r * regI2C ) adc1CalibrationPrepare (adcN uint8 ) {
348- if adcN == 0 {
349- r .writeMask (i2cSarADC , i2cSarADCHostID , adc1EncalGndAddr , adc1EncalGndMSB , adc1EncalGndLSB , 1 )
350- } else {
351- r .writeMask (i2cSarADC , i2cSarADCHostID , adc2EncalGndAddr , adc2EncalGndMSB , adc2EncalGndLSB , 1 )
352- }
353- }
354-
355- // adc1CalibrationFinish clears ENCAL_GND and reconnects the ADC
356- // input back to the external pad after self‑calibration.
357- func (r * regI2C ) adc1CalibrationFinish (adcN uint8 ) {
358- if adcN == 0 {
359- r .writeMask (i2cSarADC , i2cSarADCHostID , adc1EncalGndAddr , adc1EncalGndMSB , adc1EncalGndLSB , 0 )
360- } else {
361- r .writeMask (i2cSarADC , i2cSarADCHostID , adc2EncalGndAddr , adc2EncalGndMSB , adc2EncalGndLSB , 0 )
362- }
363- }
364-
365- // adc1SetCalibrationParam writes the INIT_CODE (offset trim) for
366- // the selected ADC unit using the regI2C bitfields.
367- func (r * regI2C ) adc1SetCalibrationParam (adcN uint8 , param uint32 ) {
368- msb := uint8 (param >> 8 )
369- lsb := uint8 (param & 0xFF )
370- if adcN == 0 {
371- r .writeMask (i2cSarADC , i2cSarADCHostID , adc1InitCodeHighAddr , adc1InitCodeHighMSB , adc1InitCodeHighLSB , msb )
372- r .writeMask (i2cSarADC , i2cSarADCHostID , adc1InitCodeLowAddr , adc1InitCodeLowMSB , adc1InitCodeLowLSB , lsb )
373- } else {
374- r .writeMask (i2cSarADC , i2cSarADCHostID , adc2InitCodeHighAddr , adc2InitCodeHighMSB , adc2InitCodeHighLSB , msb )
375- r .writeMask (i2cSarADC , i2cSarADCHostID , adc2InitCodeLowAddr , adc2InitCodeLowMSB , adc2InitCodeLowLSB , lsb )
376- }
377- }
378-
379- // waitIdle polls the REGI2C master BUSY bit until it clears or the
380- // simple software timeout expires. This matches the busy‑wait helper
381- // used in ESP‑IDF's regi2c_ctrl.c.
382- func (r * regI2C ) waitIdle (reg * volatile.Register32 ) bool {
383- for i := 0 ; i < i2cMstTimeout ; i ++ {
384- if reg .Get ()& i2cMstBusyBit == 0 {
385- return true
386- }
387- }
388- return false
389- }
390-
391- // writeMask is a software implementation of REGI2C_WRITE_MASK macro:
392- // 1. select block + regAddr,
393- // 2. read current byte,
394- // 3. update only [msb:lsb] bitfield,
395- // 4. write it back via internal I2C master.
396- func (r * regI2C ) writeMask (block , hostID , regAddr , msb , lsb , data uint8 ) {
397- if hostID != i2cSarADCHostID {
398- return
399- }
400- reg := (* volatile .Register32 )(unsafe .Pointer (i2cMstCtrlHost ))
401- if ! r .waitIdle (reg ) {
402- return
403- }
404- reg .Set (uint32 (block ) | uint32 (regAddr )<< 8 )
405- if ! r .waitIdle (reg ) {
406- return
407- }
408- cur := (reg .Get () & i2cMstDataMask ) >> i2cMstDataShift
409- mask := uint32 (1 << (msb - lsb + 1 )- 1 ) << lsb
410- cur &^= mask
411- cur |= uint32 (data & (1 << (msb - lsb + 1 )- 1 )) << lsb
412- reg .Set (uint32 (block ) | uint32 (regAddr )<< 8 | i2cMstWrCntl | (cur << i2cMstDataShift )& i2cMstDataMask )
413- r .waitIdle (reg )
200+ func applyADC2Code (reg regI2C , code uint32 ) {
201+ reg .calibrationInit (1 )
202+ reg .calibrationPrepare (1 )
203+ reg .setCalibrationParam (1 , code )
204+ reg .calibrationFinish (1 )
414205}
0 commit comments