arduino / ArduinoCore-mbed

330 stars 195 forks source link

Arduino Nicla Sense Me: VIN UVLO fault flag in BQ25120A register doesn't trigger correctly when read using I2C #933

Open frankl83 opened 1 month ago

frankl83 commented 1 month ago

Hi, I'd like to report a issue that I'm having with framework-arduino-mbed@4.1.3 on Arduino Nicla Sense Me.

I'm using a battery with the Arduino Nicla Sense Me and I want to implement some battery charging/monitoring functionalities in my code. After setting up the BQ25120A in the setup phase I call in the main() a function that is executed every 5s to update the battery stats.

This function also read the faults register and if the second bit associated with the VIN UVLO fault is 1, it means that the USB cable has been disconneted and I keep trace of the number of disconnections. This is also used to understand when to re-enable the charger and restart a new battery recharge cycle after a previous one is done.

This is the simple code piece that updates the global variable fault_triggered that I defined elsewhere.

uint8_t faults = nicla::_pmic.readByte(BQ25120A_ADDRESS, BQ25120A_FAULTS);
        // print USB disconnections counter for debug purpose
        Serial.print("USB disconnections counter: ");
        Serial.println(fault_triggered, HEX);
        if (faults & 0b01000000)
        {
            //only for debug
            fault_triggered++;
            // Re-enable the charger for the next cycle, charging was previously disabled if charge-done status was detected
            nicla::enableCharging(130);
        } 

**Expected behaviour: The PMIC BQ25120A detects that the USB cable was unplugged, B6 of BQ25120A_FAULTS is automatically put to 1 by the PMIC, when my code reads the register, the counter is updated, charger is re-enabled, B6 flag is cleared but a new 1 is written as long as the USB cable is disconnected so the counter is updated at every read as long as the USB cable is disconnected**

image

Actual behaviour When I disconnect the USB cable the first read from BQ25120A_FAULTS doesn't seem to generate a counter increase. It triggers a B6 clear though and immediatly after that the fault flag is put to 1 and I catch that on the next BQ25120A_FAULTS read. Basically the VIN UVLO flag seems to be put correctly to 1 immediatly after the first read from BQ25120A_FAULTS after the USB cable was disconnected. The practical impact of this is that if I remove the USB cable and I plug it quickly I don't detect the disconnection with a counter update. To make sure this always happens I need to disconnect the cable and wait the polling interval of the function, in my case 5s, to plug it in again.

Why do you think this happens? The BQ25120A datasheet doesn't seem to suggest that you necessarily need to read the fault register first to trigger its update. I've also checked that the fault generation is indeed enabled. Could it be a issue with the way the I2C library reads from the register or something that happens in background?

Thanks!

frankl83 commented 1 month ago

I've done more digging and it seems the issue is caused by the fact that the basic read/write functions:

uint8_t BQ25120A::writeByte(uint8_t address, uint8_t subAddress, uint8_t data); unit8_t BQ25120A::readByteUnprotected(uint8_t address, uint8_t subAddress);

always read the fault register using the bool BQ25120A::runsOnBattery(uint8_t address) function.

So in my code if before reading the fault register I read from other PMIC registers (like it happened in my case), the original VIN UVLO fault flag is lost and another one is generated but only as long as VIN =0. If I disconnect and reconnect the USB cable before a series of reads from the PMIC registers is done, the flag associated with the disconnection is cleared at the first read and when I actually want to read from the FAULT register, the VIN UVLO flag is not there anymore because it was previously cleared and now the USB cable is connected.

So in conclusion the way the basic read byte function is written: unit8_t BQ25120A::readByteUnprotected(uint8_t address, uint8_t subAddress); can cause bugs and issues if it is assumed that only the user code is reading from the BQ25120A_FAULTS register.**