MAX17048 Question on charge level percentage readings

Breakout boards, sensors, other Adafruit kits, etc.

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
User avatar
xanatos
 
Posts: 110
Joined: Thu Jun 18, 2009 3:09 pm

MAX17048 Question on charge level percentage readings

Post by xanatos »

I am using these three cool items in concert:

3.7V 2500 mAh LiPo - Product ID: 328

Adafruit Universal USB / DC / Solar Lithium Ion/Polymer charger - bq24074 - Product ID: 4755

Adafruit MAX17048 LiPoly / LiIon Fuel Gauge and Battery Monitor - STEMMA JST PH & QT / Qwiic - Product ID: 5580

As usual, everything works well, but in this case there's a little quirk I'm trying to understand with the "Fuel Gauge".

The charge level reads apparently fine, and when I plug in the USB-C connector, the charge level increases as you would expect. But it doesn't stop at "100%" as I would expect. It continues until the Fuel Gauge reads ~ 124%.

If I unplug the USB-C cable, it remains at ~ 124% and discharges very slowly (my project runs about 18 hours on a charge), *BUT* - and here's the weird part - if, while the fuel gauge is reading that high, I switch the project off, and back on, it immediately shows the charge level as being ~ 86%, and discharges normally from there.

Is there some calibration/setup thing I missed somewhere?
IMG_20221117_125803191.jpg
IMG_20221117_125803191.jpg (113.04 KiB) Viewed 177 times
IMG_20221117_143816394.jpg
IMG_20221117_143816394.jpg (113.22 KiB) Viewed 177 times
IMG_20221117_143850909.jpg
IMG_20221117_143850909.jpg (112.96 KiB) Viewed 177 times

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: MAX17048 Question on charge level percentage readings

Post by mikeysklar »

What else are you powering through the battery (controller board, CO2 sensor, TFT model, etc)? The model of processor on your controller board could be related to the skewed readings.

The CO2 sensor is likely turning on a significant load on reset (turn on heating element).

User avatar
xanatos
 
Posts: 110
Joined: Thu Jun 18, 2009 3:09 pm

Re: MAX17048 Question on charge level percentage readings

Post by xanatos »

I'm using the CircuitBrains Deluxe (SAMD51 I believe).

As you state I'm using the CO2 sensor, the temp/humidity/pressure sensor, a hi-precision RTC, and the display. For now - about to add an O2 sensor, VOC, H2, H2SO4 and other sensors

The CO2 sensor draws a relatively higher current, but not enough to take the battery from 124% to 83% in ten seconds. The project runs normally at least 18 hours with everything running. If the CO2 sensor was drawing that much current, it would die in 50 seconds :)

It is notable that my "power trio" itself, with only the display and RTC hooked up, exhibited the same behavior before the rest of the I2C chain was ever hooked up.

It's an odd one...

Dave

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: MAX17048 Question on charge level percentage readings

Post by mikeysklar »

Interesting project with so many gas sensors.

Can you post some of the MAX17048 related code you are running?

User avatar
xanatos
 
Posts: 110
Joined: Thu Jun 18, 2009 3:09 pm

Re: MAX17048 Question on charge level percentage readings

Post by xanatos »

Sure - here's the complete code I'm running now:

Code: Select all


# Environmental Monitor Display & Control, updated 2022-11-15, Time, Date, CO2, Humidity, Temperature, Pressure; Bar Graph for radiation level data eventually, etc.
# Adafruit CircuitBrains PID 4802 https://www.adafruit.com/product/4802
# Adafruit 1.9" 240x135 Color TFT Display ST7789 PID 5394 https://www.adafruit.com/product/5394
# Adafruit SCD-41 - True CO2 Temperature and Humidity Sensor PID: 5190 https://www.adafruit.com/product/5190
# Adafruit LPS22 Pressure Sensor PID: 4633 https://www.adafruit.com/product/4633
# I2C addresses found: ['0x36', '0x5d', '0x62', '0x68', '0x73'] includes O2 Sensor

import board
import terminalio
import displayio
from adafruit_display_text import label
from adafruit_st7789 import ST7789
import adafruit_imageload
from digitalio import DigitalInOut, Direction, Pull
from analogio import AnalogOut, AnalogIn
import sdcardio
import storage
import pwmio
import time
import adafruit_ds3231 # RTC, Hi Precision  I2C 0x68
import adafruit_scd4x # Temp, Humid, True CO2 ppm  I2C 0x62 (12 bit DAC?)
import adafruit_lps2x # Pressure (hPa), Temp   I2C 0x5d
import gc # For memory space checks
import microcontroller  # for uP temp measurements
import adafruit_max1704x #Battery Fuel Gauge
import sys
import math
sys.path.append("../..")
from DFRobot_Oxygen import *

COLLECT_NUMBER   = 10              # O2: collect number, the collection range is 1-100
IIC_MODE         = 0x01            # O2: default use IIC1
oxygen = DFRobot_Oxygen_IIC(IIC_MODE ,ADDRESS_3)

def setBright(lvl):  # 0 to 100
    bgLevel = min(max(lvl, 0), 100)
    backlight.duty_cycle = int(bgLevel * 65535 / 100) # Up

i2c = board.I2C()

ds3231 = adafruit_ds3231.DS3231(i2c)
scd4x = adafruit_scd4x.SCD4X(i2c)
#print("SCD4x Serial numbers:", [hex(i) for i in scd4x.serial_number])
lps = adafruit_lps2x.LPS22(i2c)
max17 = adafruit_max1704x.MAX17048(i2c) # Battery must be connected else I2C addr will not show up

days = ("Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun")

#ds3231.datetime = time.struct_time((2022, 8, 3, 13, 39, 00, 2, 1, -1))

current = ds3231.datetime
#print('The current time is: {}/{}/{} {:02}:{:02}:{:02}'.format(current.tm_mon, current.tm_mday, current.tm_year, current.tm_hour, current.tm_min, current.tm_sec))

# Release any resources currently in use for the displays
displayio.release_displays()

spi = board.SPI()
tft_cs = board.D11
tft_dc = board.D13
tft_rst = board.D12
sd_cs = board.D14

sdcard = sdcardio.SDCard(spi, sd_cs)
vfs = storage.VfsFat(sdcard)

storage.mount(vfs, "/sd")

#Light Level Sensing via CDS cell on A1
lightlevel = AnalogIn(board.A0)

# Analog input on A1-3
analog1in = AnalogIn(board.A1)  #
analog2in = AnalogIn(board.A2)  #
analog3in = AnalogIn(board.A3)  #

backlight = pwmio.PWMOut(board.D10, frequency=5000, duty_cycle=0)

display_bus = displayio.FourWire(spi, command=tft_dc, chip_select=tft_cs, reset=tft_rst)

display = ST7789(display_bus, width=320, height=170, colstart=35, rotation=270)

BORDER = 2
FONTSCALE = 2
BACKGROUND_COLOR = 0x550000 # Red
FOREGROUND_COLOR = 0x000055 # Blue
TEXT_COLOR = 0xCCCCFF

# Settings are adjusted for specific CdS Cell used
minBright = 10  #Minimum display brightness in dark conditions
maxBright = 99  #Maximum display brightness in light conditions

group = displayio.Group(scale=1)
# Add the Group to the Display
display.show(group)

#Start of Reading Table
initPos = 10
lineSpace = 27
screenPage = 1
pageLeft = 5

# Draw a label
text_area = label.Label(
    terminalio.FONT,
    text="Init",
    color=TEXT_COLOR,
    scale=1,
    x = pageLeft, # x = Horizontal, y = Vertical
    y = 158,
    #anchor_point=(0.5, 0.5),
    #anchored_position=(display.width // 2, display.height // 2),
)  # Use x & Y for left-aligned text, use anchor_point=(0.5, 0.5) for centered text
group.append(text_area)

# Draw a label
text_area2 = label.Label(
    terminalio.FONT,
    text=" ",
    color=0xffffff,
    scale=1,
    x = pageLeft + 90, # x = Horizontal, y = Vertical
    y = 158,
    #anchor_point=(0.5, 0.5),
    #anchored_position=(display.width // 2, display.height // 2),
)  # Use x & Y for left-aligned text, use anchor_point=(0.5, 0.5) for centered text
group.append(text_area2)

# Draw a label for PAGE ID (data field only here)
text_pageID = label.Label(
    terminalio.FONT,
    text="01",
    color=0xff0000,
    scale=1,
    x = 310, # x = Horizontal, y = Vertical
    y = 158,
    #anchor_point=(0.5, 0.5),
    #anchored_position=(display.width // 2, display.height // 2),
)  # Use x & Y for left-aligned text, use anchor_point=(0.5, 0.5) for centered text
group.append(text_pageID)

# Draw a label for Time, Date & Environmental Conditions
text_time = label.Label(
    terminalio.FONT,
    text="XXXX/XX/XX XX:XX:XX",
    color=0xffffff,
    scale=2,
    x = pageLeft,
    y = initPos,
)  # Use x & Y for left-aligned text, use anchor_point for centered text
group.append(text_time)

text_THP = label.Label(
    terminalio.FONT,
    text="00F  00%  00.00 InHg",
    color=TEXT_COLOR,
    scale=2,
    x = pageLeft, # x = Horizontal, y = Vertical
    y = initPos + lineSpace,
    #anchor_point=(0.5, 0.5),
    #anchored_position=(display.width // 2, display.height // 2),
)  # Use x & Y for left-aligned text, use anchor_point=(0.5, 0.5) for centered text
group.append(text_THP)

# Draw a label for CO2 & CO
text_CO2CO = label.Label(
    terminalio.FONT,
    text="CO2:  ",
    color=TEXT_COLOR,
    scale=3,
    x = pageLeft, # x = Horizontal, y = Vertical
    y = initPos + (lineSpace*2),
    #anchor_point=(0.5, 0.5),
    #anchored_position=(display.width // 2, display.height // 2),
)  # Use x & Y for left-aligned text, use anchor_point=(0.5, 0.5) for centered text
group.append(text_CO2CO)

bar_bitmap = dict()
bar_palette = dict()
bar_sprite = dict()
numBars = 10

def drawPowerBar():
    xpos = pageLeft
    xspace = 10
    ypos = 128
    barx = 6
    bary = 20

    for b in range(1, 21):
        bar_bitmap[b] = displayio.Bitmap(barx, bary, 1)
        bar_palette[b] = displayio.Palette(1)
        if (b<5):
            bcolor = 0x00CC00 # Green
        elif ((b>=5) and (b<9)):
            bcolor=0x40FF00  # Yellow-Green
        elif ((b>=9) and (b<13)):
            bcolor = 0xFFFF00 # Yellow
        elif ((b>=13) and (b<17)):
            bcolor = 0xFF7700 # Yellow
        elif (b>=16):
            bcolor = 0xFF0000 # Red

        bar_palette[b][0] = bcolor
        bar_sprite[b] = displayio.TileGrid(bar_bitmap[b], pixel_shader=bar_palette[b], x=xpos, y=ypos)
        group.append(bar_sprite[b])
        xpos = xpos + xspace

def adjustPowerBar(numBars):
    for b in range(1, 21):
        if (b<=numBars):
            if (b<5):
                bcolor = 0x00CC00 # Green
            elif ((b>=5) and (b<9)):
                bcolor=0x40FF00  # Yellow-Green
            elif ((b>=9) and (b<13)):
                bcolor = 0xFFFF00 # Yellow
            elif ((b>=13) and (b<17)):
                bcolor = 0xFF7700 # Yellow
            elif (b>=16):
                bcolor = 0xFF0000 # Red
        else:
            bcolor = 0x000044
        bar_palette[b][0] = bcolor

drawPowerBar()

# Add the Group to the Display
display.show(group)

# Set sprite location
group.x = 0
group.y = 0

scd4x.start_periodic_measurement()

Count = 0
subCount = 0
setBright(100)
currentPage = 1
scd41TempF = "0"
scd41RHpct = "0"
lpsPressInHg = "0"
scd41TempCs = "0"
lpsPressmBar = "0"
lpsPressPSI = "0"
scd41CO2ppm = "0"

while True:
    if (currentPage == 1):
        text_pageID.text = "01"
        text_area.text = ("Scanning " + str(Count))
        Count = Count + 1
        if (Count % 10 == 0):
            t = ds3231.datetime
            DateText = "{} {}/{:02}/{:02}".format(days[int(t.tm_wday)], t.tm_year, t.tm_mon, t.tm_mday)
            TimeText = "{}:{:02}:{:02}".format(t.tm_hour, t.tm_min, t.tm_sec)
            text_time.text = DateText + " " + TimeText
            Bv = str(round(max17.cell_voltage,1))
            Bs = str(round(max17.cell_percent,1))
            gc.collect()
            uCT = str(round(microcontroller.cpu.temperature, 1))
            freeS = str(gc.mem_free())
            text_area2.text = "uCT: " + uCT + " " + Bv + "V " + Bs + "% FS: " + freeS

            if scd4x.data_ready:  #These will update 1x/second: Temp, Humid, Press:
                scd41CO2ppm = scd4x.CO2
                scd41TempC = scd4x.temperature  #23.81  #TESTING ONLY
                scd41RHpct = scd4x.relative_humidity  #"34"  #TESTING ONLY
                scd41TempF = (scd41TempC*1.8)+32
                scd41TempF = str(round(scd41TempF,1))
                scd41TempCs = str(round(scd41TempC,1))
                scd41RHpct = str(round(scd41RHpct))  #TESTING ONLY
                lpsPresshPa = lps.pressure
                lpsPressInHg = lpsPresshPa/33.864
                lpsPressInHg = str(round(lpsPressInHg,2))
                lpsPressmBar = str(round(lpsPresshPa))
                lpsPressPSI = lpsPresshPa * 0.0145
                lpsPressPSI = str(round(lpsPressPSI,2))

        #Display Sensor Data:
            if (subCount == 0):
                text_THP.text = scd41TempF + "F " + scd41RHpct + "% " + lpsPressInHg + " InHg"
            elif (subCount == 1):
                text_THP.text = scd41TempCs + "C " + scd41RHpct + "% " + lpsPressmBar + " mBar"
            elif (subCount == 2):
                text_THP.text = scd41TempF + "F " + scd41RHpct + "% " + lpsPressInHg + " InHg"
            elif (subCount == 3):
                text_THP.text = scd41TempCs + "C " + scd41RHpct + "% " + lpsPressPSI + " PSI"
            if (len(str(scd41CO2ppm)) == 3):
                if (int(scd41CO2ppm) > 999):
                    text_CO2CO.color = 0xFFFF00
                elif (int(scd41CO2ppm) > 1999):
                    text_CO2CO.color = 0xFF0000
                else:
                    text_CO2CO.color = TEXT_COLOR
                text_CO2CO.text = "CO2: " + str(scd41CO2ppm)
            else:
                if (int(scd41CO2ppm) > 999):
                    text_CO2CO.color = 0xFFFF00
                elif (int(scd41CO2ppm) > 1999):
                    text_CO2CO.color = 0xFF0000
                else:
                    text_CO2CO.color = TEXT_COLOR
                text_CO2CO.text = "CO2: " + str(scd41CO2ppm)

            subCount = subCount + 1
            if (subCount > 3):
                subCount = 0

            #oxygen_data = oxygen.get_oxygen_data(COLLECT_NUMBER)
            #print("oxygen concentration is %4.2f %%vol"%oxygen_data)

    elif(currentPage == 2):
        text_pageID.text = "02"

    time.sleep(.1)


User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: MAX17048 Question on charge level percentage readings

Post by mikeysklar »

Thank you for sharing the code. It is clear how you are gathering the data and displaying the sensor / battery stats. Nice code.

Can you post a photo of how you are using the BQ24074 with the MAX17048 and LiPo?

It would be a good idea to setup a voltage_alert_max value of 4.2v to prevent overcharging. Then scan the active_alert for when you hit it. Since this could be a false value you have the ability to reset() the MAX17048 when you hit the charge limit and you could see if it comes with the "real" voltage.

I know the above is a hack, but the idea is to better understand what is going on.

User avatar
xanatos
 
Posts: 110
Joined: Thu Jun 18, 2009 3:09 pm

Re: MAX17048 Question on charge level percentage readings

Post by xanatos »

Here's a shot of the layout:
Circuitry.jpg
Circuitry.jpg (185.44 KiB) Viewed 147 times
Battery ---> Charge Module ---> Fuel Gauge ---> rest of circuitry

Power switch located on positive rail between Charge Module and Fuel Gauge.

The white-striped wires coming from just behind the USB-C connector are the data lines that go to the Microcontroller for programming, etc.

All data with the exception of the display is I2C. Display is SPI.

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: MAX17048 Question on charge level percentage readings

Post by mikeysklar »

Are you using two LiPo packs?

The Max17048 guide has the battery connected directly to either JST. Have you tried that scenario?

User avatar
xanatos
 
Posts: 110
Joined: Thu Jun 18, 2009 3:09 pm

Re: MAX17048 Question on charge level percentage readings

Post by xanatos »

Single LiPo.

Do you mean try reversing which jack the battery is going into?

User avatar
mikeysklar
 
Posts: 13936
Joined: Mon Aug 01, 2016 8:10 pm

Re: MAX17048 Question on charge level percentage readings

Post by mikeysklar »

Taking the BQ24074 out of the equation (disconnect the JSTs) and check the battery readings. Does the MAX17048 report the correct values?

Locked
Please be positive and constructive with your questions and comments.

Return to “Other Products from Adafruit”