XIAO nrf52840 battery voltage not readable on PlatformIO

Hey community!

I can’t get a voltage reading from PIN_VBAT in PlatformIO no matter what. However it’s working just fine in the Arduino IDE… I already isolated the problem and created two minimal repro projects.
I’m using the XIAO nrf52840 v1.0

Working Arduino project:
ReadBattery.ino

#include "Adafruit_TinyUSB.h"

#define VREF 3.6
#define ADC_MAX 4096

void setup() {
  analogReadResolution(ADC_RESOLUTION);
  pinMode(PIN_VBAT, INPUT);
  pinMode(VBAT_ENABLE, OUTPUT);
  digitalWrite(VBAT_ENABLE, LOW);
}

void loop() {
  Serial.print("V Bat: ");
  Serial.println(getBatteryVoltage());
}

float getBatteryVoltage() {
  unsigned int adcCount = analogRead(PIN_VBAT);
  float adcVoltage = adcCount * VREF / ADC_MAX;
  return adcVoltage * 1510 / 510;
}

Non-working PlatformIO project:
platformio.ini

[env]
platform = https://github.com/maxgerhardt/platform-nordicnrf52

[env:xiaoble]
board = xiaoble
framework = arduino
monitor_speed = 115200

main.cpp

#include <Arduino.h>

#define VBAT_ENABLE 14 <-- not auto-defined in PlatformIO
#define VREF 3.6
#define ADC_MAX 4096

float getBatteryVoltage();

void setup() {
  analogReadResolution(ADC_RESOLUTION);
  pinMode(PIN_VBAT, INPUT);
  pinMode(VBAT_ENABLE, OUTPUT);
  digitalWrite(VBAT_ENABLE, LOW);
}

void loop() {
  Serial.print("V Bat: ");
  Serial.println(getBatteryVoltage());
}

float getBatteryVoltage() {
  unsigned int adcCount = analogRead(PIN_VBAT);
  float adcVoltage = adcCount * VREF / ADC_MAX;
  return adcVoltage * 1510 / 510;
}

As you can see there is no native support for the XIAO nrf52840 by PlatformIO, so I have to use the community implementation.
The issue arose from a ported Arduino project, everything ported fine except the battery monitoring. In the analogRead(PIN_VBAT) I only get 4095 as a result no matter what.

As I checked out the schematics I also saw that PIN_VBAT is marked as P0.31_AIN7_BAT which indicates pin 31, but in Arduino and PlatformIO PIN_VBAT is defined as 32.
I only find that strange and don’t understand it, but it still works on Arduino, so thats fine I guess.
I don’t have the expert knowladge to determine which parts may cause this behaviour on PlatformIO, all I did to this point is to compare all #defines if they are the same and I can say that they all match.

Hope someone can help me, since I already wasted my whole Sunday on this!

Greetings from Germany,
Nils Ole

I don’t see this sin your sketch?
analogReadResolution(12); //12bits
my 02
HTH
GL :non-potable_water:

Hey Glasso,

thx for the suggestion! But analogReadResolution(ADC_RESOLUTION); does exactly that. ADC_RESOLUTION seems to be a default define that evaluates to 12.

Maybe somone else has a suggestion? Its a basic sketch, so the issue probably has to be some config stuff that I know nothing about?

Best,
Nils Ole

Ah’ I didn’t see it…LOL ok well here is my .ini that works from this topic.

https://forum.seeedstudio.com/t/upload-working-great-in-arduino-no-device-found-on-com5-error-in-platformio/267696/7?u=pj_glasso

; PlatformIO Project Configuration File
;
;   Build options: build flags, source filter
;   Upload options: custom upload port, speed and extra flags
;   Library options: dependencies, extra library storages
;   Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html

[env:xiaoblesense]
platform = https://github.com/maxgerhardt/platform-nordicnrf52
board = xiaoblesense
framework = arduino
debug_tool = jlink

lib_extra_dirs = ~/Documents/Arduino/libraries
lib_deps = seeed-studio/Seeed Arduino LSM6DS3@^2.0.3
   arduino-libraries/ArduinoBLE@^1.3.2
   ;adafruit/Adafruit GFX Library
   adafruit/Adafruit BusIO
   Wire
   olikraus/U8g2@^2.34.4
   ;SPI

HTH
GL :-p

Thank you for providing your ini!
I tested it, but unfortunately got the same result: analogRead(PIN_VBAT) still reads 4095 :frowning:

Also I’m using the base nrf52840 not the sense, but it was worth a try. Also my board version is 1.0 instead of 1.1 for any future readers.

I stumbled upon this thread because I was having a similar issue. The issue with with the mbed framework. I’ll let this thread where speak for itself: XIAO_BLE_Sense(mbed 2.7.2) battery charge and voltage monitor, analogRead(P0_31) does not work - #2 by JeonLab

Actually, VBAT_ENABLE is defined in PlatformIO, it’s just called PIN_LSM6DS3TR_C_POWER (intuitive, I know). There’s also a pin for reading charge status, PIN_LSM6DS3TR_C_INT1. These are defined in something like “.platformio\packages\framework-arduino-mbed\variants\SEEED_XIAO_NRF52840_SENSE\pins_arduinio.h”:

#define PIN_VBAT (32u)
...
#define PIN_LSM6DS3TR_C_POWER (14u)
#define PIN_LSM6DS3TR_C_INT1 (17u)

The fun thing is, all of them except PIN_VBAT don’t work. The other forum thread explains it in detail but basically the integer value of the pins is not the same as their label (P0.14 =/= 14). My solution is to replace them with the proper value corresponding to an index from variant.cpp in the same folder:

#define VBAT_ENABLE (31u) // digital output: battery voltage enable
#define VBAT_CHG (22u) // digital input: charging status

Copy the above snippet into your code and you should be good to go.

Thanks for getting back to this, really!

But I already tried it all, I also found this thread and even though I didn’t understand fully, I changed the variables g_APinDescription to g_AAnalogPinDescription in the pinDefinitions. This didn’t work at all.

I was happy as I read your “hacky” approach without fixing the otherwise downloaded library files (which I prefer, since I’m using git). I tried it and it seemed to work, the battery voltage finally changed the value! I thought I can finally proceed, but then I realized that it won’t read lower than 3.5 volts.

I’m not sure how this is possible, I even tested the arduino code again because I thought I may fried my hardware, but still: It was all working perfectly with arduino IDE. It even displayed below 2 volts and until the display finally died due to under-voltage.

Still hitting a wall here, adding two definesis something where I couldn’t do anything wrong.
And yes, I deleted the libraries that had my changes in it an redownloaded them.

Still, much appreciated! Maybe someday someone will find this thread and has an idea whats wrong with this stuff.

Best,
Nils Ole

A friend finally found out what caused this behaviour!

You have to set the analog reference voltage lower in order to get a correct read (in my case here lower than ~3.5V).
So I added this line: analogReference(AR_INTERNAL2V4);
AND IT FINALLY WORKS!