Incorrect battery voltage measurements

There is a mismatch between the actual voltage and measured voltage of the connected battery.
Especially when the battery is not charging.

Results

while charging:
Measured with voltage meter: 3,75v
Computed from the analogRead measurement: 3,8v
without charging:
Measured with voltage meter: 3,73v
Computed from the analogRead measurement: 3,42v

Formula:
expected voltage: (raw/1023)3,3(1+0,51)/0,51
With:

  • 1023: 2^10-1
  • 3,3: reference voltage
  • (1+0,51)/0,51: the voltage divider (1M ohm and 510k ohm)

Measurements

Without BLE connected (while charging):

  • Terminal: 398
  • Volt meter: 3.75v

BLE connected (while charging):

  • 398
  • Volt meter: 3,75v

BLE connected (while not charging):

  • 358
  • 3,73v

Code

int BatteryController::getBatteryVoltage()
{
    // Enable divider
    pinMode(VBAT_ENABLE, OUTPUT);
    digitalWrite(VBAT_ENABLE, LOW);
    delay(5); // allow voltage to stabilize

    // Read ADC
    int raw = analogRead(PIN_VBAT);

    // Disable divider to save power
    pinMode(VBAT_ENABLE, INPUT);
    Serial.println(raw);
    return raw;
}

variants hpp file (Seeed_XIAO_nRF52840_Sense):

#define PIN_VBAT             (32)
#define VBAT_ENABLE          (14)

Please verify the connection to the battery pad on the back of the board. Are you measuring the voltage at the pad?
Try this schetch.

//----------------------------------------------------------------------------------------------
//Board Library : Seeed nRF52 Borads 1.1.8
//Board Select  : Seeed nRF52 Borads / Seeed XIAO nRF52840 Sense
//----------------------------------------------------------------------------------------------
#include <Arduino.h>
#include <Adafruit_TinyUSB.h>   // for Serial.print()

//Arduino15\packages\Seeeduino\hardware\nrf52\1.1.8\variants\Seeed_XIAO_nRF52840_Sense\variant.cpp
#define PIN_VBAT        (32)  // D32 battery voltage
#define PIN_VBAT_ENABLE (14)  // D14 LOW:read anable
#define PIN_HICHG       (22)  // D22 charge current setting LOW:100mA OPEN:50mA
#define PIN_CHG         (23)  // D23 charge indicatore LOW:charge HIGH:no charge

void setup() 
{
  Serial.begin(115200);
  while(!Serial);
  
  pinMode(PIN_VBAT_ENABLE, OUTPUT);
  digitalWrite(PIN_VBAT_ENABLE, LOW); // VBAT read enable

//  pinMode(PIN_HICHG, OUTPUT);         // charge current 100mA
//  digitalWrite(PIN_HICHG, LOW);       // charge current 100mA
  pinMode(PIN_HICHG, INPUT);          // charge current 50mA

  pinMode(PIN_CHG, INPUT);            // charge indicatore LOW:charge HIGH:discharge
  
  // initialise ADC wireing_analog_nRF52.c:73
  analogReference(AR_DEFAULT);        // default 0.6V*6=3.6V  wireing_analog_nRF52.c:73
  analogReadResolution(12);           // wireing_analog_nRF52.c:39
}

void loop() 
{
  int vbatt = analogRead(PIN_VBAT);
  Serial.print(vbatt, HEX);
  Serial.print("    ");
  Serial.print(2.961 * 3.6 * vbatt / 4096);   // Resistance ratio 2.961, Vref = 3.6V 
  Serial.print("    ");
  Serial.println(digitalRead(PIN_CHG));       // 0:charge, 1:discharge 

  delay(1000);
}