top of page
Search
  • Writer's pictureIfrim Ciprian

System - Battery Checks

Updated: May 20, 2022

An important part of any wearable is to be able to output the battery and to inform the user is the battery is very low and it needs to be recharged.


So I have used the Battery Sense library, available here: https://github.com/rlogiacco/BatterySense


This is a simple Arduino library to monitor battery consumption of your battery powered projects, being LiPo, LiIon, NiCd or any other battery type, single or multiple cells: if it can power your Arduino you can monitor it!

The principle is simple: we are going to measure our battery capacity by measuring the voltage across the battery terminals.


The actual drain of a LiPo battery (which is what the system is using) is not linear, and has a very specific curve.



The above plot it represents the battery percentage (Y axis) as a function of the difference between the current battery voltage and the minimum value (X axis): the graph represents a battery with a voltage swing of 1200mV from full to empty, but the functions scale accordingly to the minVoltage and maxVoltage parameters. These 2 parameters are part of the library and can be set.


In my case I have noticed that the system will not work accordingly if the battery is lower than 3.3 volts, and on the upper side, the max voltage the battery can hold is 4.15v. Nominal voltage 3.7v.


In order to reduce the power cosnumption I have used a voltage divider with a P-mosfet to only activate the voltage divider outputing the voltage when needed.

Here's the actual circuit:

In this figure it can be seen how the power consumption when the circuit is off is equal to 420 microvolts and 42 nanoAmps.


Moreover, when the circuit is activated, it looks as follows:

Here it can be seen how the maximum output of a 4.2v battery is 3.2 volts (maximum circuit voltage is 3.3 volts) with a power consumption of 2.1 milliAmps.


Here is the plot of the oscilloscope on the SENSE pin, which represents the output:

Working on the voltage divider:



Here is the code used in the system:

#include "Nicla_System.h"
#include <Battery.h>

#define battery_pin A1
Battery battery = Battery(3000, 4150, battery_pin);

void setup() {
  Serial.begin(115200);
  while (!Serial);
  
  battery.onDemand(8, HIGH);
  battery.begin(3300, 2.14, &asigmoidal);
  
}

void loop() {
  while (Serial.available() > 0) {
    char incomingCharacter = Serial.read();
    if (incomingCharacter == '1') {
      Serial.print("Battery voltage is ");
      Serial.print(battery.voltage());
      Serial.print(" (");
      Serial.print(battery.level());
      Serial.println("%)");
    }
    delay(50);
  }
}

It can print the voltage in mv and the percentage from 0 to 100% based on the draining curve.



Videos demoing the system:


Here I charged the battery to try with the battery half empty as well as full to check the readings.


One issue that I encountered was how the library was made to work with a 10bit ADC, but the Nicla Sense ME has a 12 bit ADC. So in order to fix that I had to change the voltage divider ration from 1.3 to 2.14.


Moreover, the Nicla Sense ME has an embedded chip in the form of the BQ25120A, which is used to charge the battery, however, as per info in the forums of Bosch, which I have contacted, they said, you cannot actually check the chip and any information on the battery. The post can be found here: https://community.bosch-sensortec.com/t5/MEMS-sensors-forum/NICLA-Sense-Me-Step-Counter-Reset-and-Battery-Level-Readout/m-p/54214#M10553

They replied: "At present, there is no code that checks the battery level. You can see whether there is such code on Arduino forum."


However, by checking the datasheet there is a way by writing to the correct address in the I2C, we can get the battery level, status and faults. And the nicla does have a library file in the core folder, where the memory addresses are all defined.

Moreover, the chip is connected with the internal I2C to the nicla, which can be used.


By going on the Arduino Forums, I have noticed someone already tried to work on this, link:


Using bq25120A

1. BMON register returns specially encoded value, which is battery voltage as % of reference battery voltage


2. BMON is set once after powerup, if you want it to make subsequent measure, you need to "start measurement" by writing "0x80" to the same register.


3. if you are on external power, then you have to disable charging before starting measurement, otherwise you will get higher voltage influenced by charging process.


4 .default battery settings of bq25120 in Nicla assume LiPo battery with 3.7V max voltage. If you use LiOn battery you would like to set VBATREG to proper voltage - which could be 4.2V


5 .Finally you need to translate % voltage to % of battery capacity.


Saying all this, I wrote handy library to handle most of these functions and also resolve the issue that CD bit (p25) have different function while on external power and on battery. I will post more details and code in other reply.

Charging via USB

1. it works once by disabling pin25


2 .yes charge cycle is reported in bits of status register


A person called Martin that was working on getting a library done for this, and I was able to get the library when it wasn't complete and to contribute with suggestions, solutions to problems and simplying some processes. After modifying it, I applied it to my system, as follows:

#include "Nicla_System.h"
#include <bq25120a_nicla.h>                              // NICLA library for BQ25120A

byte battery_status;
byte battery_fault;
uint8_t battery_level;

void setup() {
  Serial.begin(9600);
  nicla::begin();
  //Wire1.begin();                                          // internal I2C communication to BHI260/PWM/LEDS/CHARGER IC

  pwmCDHigh();                                            // make sure we can talk to BQ25120A
  bq25120_setMaxCurrentMinVoltage(150, 3.0, true);        // set max current to 150mA, min voltage before fast recharge to 3.0V
  bq25120_setBatteryVoltage(4.2);                         // set battery voltage to 4.2V
  bq25120_setChargeCurrent(70);                           // set charge current to 110mA (lower then recomended C/2)
  bq25120_setTerminationCurrent(5);                       // set termination current to 5mA (lower then recomended C/30)
  bq25120_disableVinDPM();
  pwmCDLow();                                             // back to charge or highz mode
}

void loop() {
  //if the serial is available and a 1 is received then proceed
  while (Serial.available() > 0) {
    char incomingCharacter = Serial.read();
    if (incomingCharacter == '1') {
      update_battery_info();

      Serial.println("\n-----------------------------------------------------");
      Serial.println("The battery level is equal to: " + String(battery_level));
      Serial.println("The battery status is equal to: " + String(battery_status));
      Serial.println("The battery fault is equal to: " + String(battery_fault));
      Serial.println("-----------------------------------------------------");
    }
  }
  delay(1000);
}

void update_battery_info(void) {
  battery_level = bq25120_getLevel();
  battery_status = bq25120_getStatus();
  battery_fault = bq25120_getFaults();
}

Serial Output:


There is however an issue with the Nicla Sense ME, with the bootloader, that causes it to not work directly with the battery power, without the USB. So every time the battery gets drained the watch has to be reflashed.

Here is the demo of the video:


Here is a github issue ticket about the bootloader issues of the Nicla Sense ME: https://github.com/arduino/ArduinoCore-mbed/issues/421

3 views0 comments

Recent Posts

See All
bottom of page