Vbat ──[R1 = 243 kΩ]──┬──[R2 = 10 kΩ]── GND
│
GPIO_45 / ADC0_CH3
&adc0 {
status = "okay";
/delete-property/ nxp,input-buffer; /* try to disable INBUF via DT */
channel@3 {
reg = <3>;
zephyr,gain = "ADC_GAIN_1";
zephyr,reference = "ADC_REF_INTERNAL"; /* maps to VREF_SEL=01 (1.2V) */
zephyr,vref-mv = <1200>;
zephyr,acquisition-time = ;
zephyr,resolution = <12>;
zephyr,input-positive = ;
};
};
static struct adc_channel_cfg channel_cfg = {
.gain = ADC_GAIN_1,
.reference = ADC_REF_INTERNAL,
.acquisition_time = ADC_ACQ_TIME_DEFAULT,
.channel_id = 3,
.input_positive = 3, /* GAU_ADC_CH3 */
};
static int16_t adc_buffer;
static struct adc_sequence adc_seq = {
.channels = BIT(3),
.buffer = &adc_buffer,
.buffer_size = sizeof(adc_buffer),
.resolution = 12,
.calibrate = true,
.oversampling = 4, /* 16x HW averaging */
};
These are issues we encountered and worked around — listed here in case any of them point to a real bug or a misuse:
The Zephyr driver does not propagate /delete-property/ nxp,input-buffer; from the DT into the hardware on this SoC, so we cleared ADC_REG_ANA[14] directly:
/* GAU_GPADC0 base 0x40038000, ADC_REG_ANA at offset 0x10 */ volatile uint32_t *p = (volatile uint32_t *)0x40038010; *p &= ~(1U << 14); /* clear INBUF_EN */
Without this, the input buffer biases the high-impedance divider and gives a systematic offset.
At reset, SOCCIU_PAD_PU_PD_EN2 (offset 0x78 of SOCCTRL non-secure base 0x45001000) had bits [27:26] = 01 → ~100 kΩ pull-up to VDDIO active on GPIO_45. On a 9.6 kΩ Thevenin source this offsets Vadc by ~200 mV.
The nxp,mci-io-mux Zephyr pinctrl driver does not expose a bias-disable property for analog pins, so we clear the bits manually at boot:
/* Clear GPIO_45 pad pull (PAD_PU_PD_EN2 bits [27:26]) */ volatile uint32_t *p = (volatile uint32_t *)0x45001078; *p &= ~(0x3U << 26);
After this, the multimeter at the pad reads exactly Vbat × 10 / 253 (within ~2 %, consistent with resistor tolerance), so the divider itself and the pad biasing are now clean.
For diagnostic purposes, the divider is now permanently powered (instead of being switched via a MOSFET) so settling is not an issue. The pad voltage is verified stable with a multimeter before each ADC sample.
GAU_GPADC0 (0x40038000):
ADC_REG_ANA [0x40038010] = 0x0000A810 → INBUF_EN=0, VREF_SEL=01 (1.2 V),
INBUF_GAIN=01, INBUF_CHOP_EN=1,
ADC_CHOP_EN=1, RES_SEL=00 (12-bit)
ADC_REG_CONFIG [0x40038014] = 0x00000000
MCI_IO_MUX (0x40004000):
GPIO_GRP0 [0x40004030] = 0x001C1C02
GPIO_GRP1 [0x40004034] = 0x201EDBD8
SOCCIU PAD_PU_PD_EN2:
[0x45001078] = 0x01152400 → GPIO_45 PU/PD bits = 00 (no pull)
All combinations below were tested with the divider permanently powered, multimeter confirming the analog input is the steady-state expected value:
Knob Values tried Effect on RAW
| VREF_SEL (reference) | 1.2 V (01) → 1.8 V (00) | RAW scales by ~1.2/1.8 as expected, but the mismatch with the multimeter persists with the same factor |
| INBUF_GAIN (gain) | gain=1 (01), gain=0.5 (00), gain=2 (10) | No effect — suggests INBUF_GAIN does nothing while INBUF_EN=0 |
| BYPASS_WARMUP / WARMUP_TIME | 0 (bypass) up to 32 (max) cycles | No measurable effect on RAW |
| ADC_CHOP_EN & INBUF_CHOP_EN | both ON, both OFF | No effect |
| Zephyr .calibrate | true / false | No effect |
Even with everything above looking correct, RAW does not track the input voltage in a sensible way. Sequence of measurements (Vbat fed by a stable bench supply, divider verified by multimeter at each point):
| Vbat (V) | Pad (multimeter, mV) | Pad expected = Vbat·10/253 (mV) | RAW from adc_read() |
| 22 | 848 | 869 | 1682 |
| 24 | 928 | 949 | 1708 |
| 26 | 1007 | 1028 | 2413 |
| 28 | 1084 | 1107 | 1745 |
| 29 | 1122 | 1146 | 1860 |
Thanks!
Hello @_arthur_, hope you are doing well.
Would you please confirm in which Zephyr version have you done these tests? Regarding the Zephyr version, there is now available the release of Zephyr 4.4.0 of our downstream repository, would you please confirm if the behavior that you are observing is also present in this version?
Additionally, have you been doing these tests on a custom application? Or is it from a repository example?