Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Power] Option to reduce charging limit for increased battery longevity #1158

Open
digitalcircuit opened this issue Apr 24, 2022 · 13 comments
Open
Assignees
Labels
Core+Services HAL, furi & core system services Feature Request New feature or user-story you wanna add to flipper USB BadUSB + physical USB interface

Comments

@digitalcircuit
Copy link
Contributor

digitalcircuit commented Apr 24, 2022

Is your feature request related to a problem? Please describe.
From what I understand, lithium batteries wear out over time, and using and storing lithium batteries at full charge (e.g. 4.2v) can result in the battery wearing out faster.

Since the Flipper Zero's battery is not easily replaceable (requires disassembly), I'd like to take steps to ensure it degrades as little as possible when I don't need the full battery capacity.

Describe the solution you'd like
Provide an option in SettingsPower to reduce the maximum allowed battery charge for sake of battery longevity.

For example, Charge limit: 100%, adjustable down to 60% or so in 10% decrements.

Alternatively, just provide a few charging profiles (Full Charge, Balanced, Max Lifespan) corresponding to 100%, 80%, and 60% or so (see System76's UI in additional context).

Implementation details:
Flipper's firmware currently can pause charging with furi_hal_power_suppress_charge_enter() and furi_hal_power_suppress_charge_exit().

Alternatively, it appears there may be a way to adjust the bq25896 regulator's voltage limit via VREG in REG06. If feasible, lowering that may avoid requiring having the Flipper firmware actively toggle suppressing the charging circuitry.

Either way, the Desktop UI's battery indicator should probably show that the battery charge is limited to avoid potentially confusing folks.

Describe alternatives you've considered

  • Simply unplugging the Flipper Zero before it fully charges
    • Pros: free, no development effort required
    • Cons: easy to forget, doesn't work when plugged into a computer for USB features
  • Hardware charge limiting device
    • Pros: can be automated, no changes to Flipper required
    • Cons: requires power measuring or coordination with Flipper firmware, needs an extra dongle, may interfere with USB usage
  • Letting Flipper charge to 100% / not caring
    • Pros: easiest, no changes or effort required, battery replacement is at least possible (screws etc, no glue in assembly)
    • Cons: may wear out the battery faster through higher charge cycles

Additional context
There's ongoing research around battery charge thresholds and various devices and software exists to control this on other platforms. It'd be nice if Flipper could integrate this without needing a third-party workaround.

@digitalcircuit digitalcircuit added the Feature Request New feature or user-story you wanna add to flipper label Apr 24, 2022
@skotopes
Copy link
Member

Hi.

It is possible to limit target battery voltage(with charger settings) and make another set of params for gauge(or leave gauge with current params).
But in my opinion it's not worth it, but you are welcome to implement it. Shouldn't be very difficult.

@digitalcircuit
Copy link
Contributor Author

Thank you for your feedback!

I understand it not being a priority. Knowing you're not opposed to accepting a pull request of sufficient quality, this might be a good opportunity for me to try to learn a manageable subset of every layer in the Flipper firmware (UI, abstractions, hardware control, etc).

Meanwhile, if anyone else sees this open issue, feel free to experiment - it likely will be a long while before I have the time to dig into this.

@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Apr 30, 2022

Minor design update

I've been pondering how to implement this in a way that reduces support requests from folks turning on the feature and forgetting about it.

So far, I've drafted the following change to the battery icon design when charge limiting is enabled:

  • The "limited" portion of charge will be grayed out in a checkerboard pattern

Screenshot of Flipper desktop UI, with the battery icon charging and the top 20% showing a checkerboard pattern instead of being filled in

In the above example, the charge is limited to 80% (i.e. 20% of the battery is "grayed out"). This would be drawn inside power_draw_battery_callback() alongside the call to canvas_draw_box() whenever charge limiting is turned on using something similar to view_display_test_draw_callback_check().

I'll dig into the code side when I have time to set up the build environment and tinker - I'm expecting to change the charging profile (translating the percentage limit into a reduced battery voltage limit), but not change the charge gauge.

@digitalcircuit
Copy link
Contributor Author

Feedback request - preferred charge limit method?

There's two reasonable methods I've managed to come up with to implement battery charge limiting:

  1. Set charge voltage for bq25896 and adjust charge voltage in bq27220 to know when charging is done

    • ℹ Works well with setting charge limit in terms of battery charging voltage (requires Li-Ion knowledge)
    • ➕ After configuration, doesn't need the Flipper Zero firmware to intervene
    • ➕ Unlikely to result in desync issues (where Flipper firmware thinks charging is paused when it isn't)
    • ➖ Specific to the current ICs used (more work if future production batches need to change parts)
    • ➖ More complicated implementation, especially with changing charge limit at runtime
    • ➖ Possible risk of overcharging if a wrong/corrupted voltage charge limit is sent
  2. Pause charging in Flipper firmware upon reaching limit, adjust code to detect when charge is complete

    • ℹ Works well with setting charge limit in terms of percentage
    • ➕ Simpler logic with precise user-facing charge percentage limit (set to 60% = 60% is shown in UI)
    • ➕ Doesn't involve mapping voltages to percentages to determine what percent charge equals the charge limit
    • ➕ Fairly generic across battery charge and gauge hardware
    • ➖ More background work for Flipper Zero firmware (un/pausing charging), potentially more code
    • ➖ Will need to be careful to ensure that the actual charge state remains in sync with Flipper firmware

Flipper developer team - what would you prefer?

I'm leaning towards option #2 given the complexity of #1 involving coordinating the charge limit via both the charging chip and the battery gauge chip, but I'm happy to try that option if preferred. I'm open to other methods, too.

It's quite possible I overlooked pros and cons in either solution!

Additional context - Linux battery charge limit

The Linux kernel battery charge limit interface operates on start/stop percentages via charge_control_start_threshold and charge_control_end_threshold (the exact hardware implementation isn't specified).

System76 have implemented battery charge limiting in their open embedded controller firmware for their Linux laptops using battery charge percentage rather than directly setting the battery charge voltage.

This most closely matches option #2 - software/firmware charge limiting instead of hardware (IC) limiting.

Details for battery charge/gauge chips

NOTE: This does not apply for method #2, where the Flipper Zero firmware intervenes to limit charging below 100%.

ℹ Click/tap to show all the details about the bq25896 and bq27220

I've finally gotten a local firmware build set up using Podman instead of Docker (no daemon running as root), so I've looked into this more…

bq25896 - battery charging control

This chip controls when and how much to charge the Flipper Zero's internal battery, and provides the power-off shipping mode, short-circuit protection, and other functionality.

Flipper currently interacts with this chip to pause charging when using the SubGhz app via furi_hal_power_suppress_charge_enter() and furi_hal_power_suppress_charge_exit().

Digging into the datasheet for Texas Instrument's bq25896 ("I²C Controlled Single Cell 3-A Fast Charger with MaxCharge Technology for High Input Voltage and Adjustable Voltage USB On-the-Go Boost Mode"), section 9.4.7 REG06 on page 38 describes the possible Charge Voltage Limits:

Datasheet on Charge Voltage Limit

Table 12. REG06 (partial)

Bit Field Type Reset Description
7 VREG[5] R/W by REG_RST & Watchdog 512mV
6 VREG[4] R/W by REG_RST & Watchdog 256mV
5 VREG[3] R/W by REG_RST & Watchdog 128mV
4 VREG[2] R/W by REG_RST & Watchdog 64mV
3 VREG[1] R/W by REG_RST & Watchdog 32mV
2 VREG[0] R/W by REG_RST & Watchdog 16mV

Charge Voltage Limit

Offset: 3.840V
Range: 3.840V - 4.608V (110000)
Default: 4.208V (010111)
Note:
VREG > 110000 (4.608V) is clamped to register value 110000 (4.608V)

Interpretation

The bq25896 defaults to a charge voltage limit of 4.208V (010111) as noted above. The charge voltage limit gets set by taking the binary components and adding them up.

NOTE: If you're tinkering with the charging voltage limit, do not exceed 4.2V without taking precautions should the lithium battery fail and/or catch fire. I am not yet sure what additional protective circuitry, if any, is included in the Flipper Zero, so it is possible you could start a fire with toxic fumes.

Charge Voltage Limit register

Decimal = Binary VREG[5] (512mV) VREG[4] (256mV) VREG[3] (128mV) VREG[2] (64mV) VREG[1] (32mV) VREG[0] (16mV) Resulting charge limit
0 = 000000 (minimum) 0 0 0 0 0 0 3.840V
6 = 000110 (an example) 0 0 0 1 1 0 3.936V
23 = 010111 (bq25896 default) 0 1 0 1 1 1 4.208V

Calculation:
3.840 + 0.512×VREG[5] + 0.256×VREG[4] + 0.128×VREG[3] + 0.064×VREG[2] + 0.032×VREG[1] + 0.016×VREG[0]

It's not possible to reduce the charge voltage limit below 3.840V without having the Flipper Zero actively monitor and pause charging (currently, the charge voltage limit appears to be completely handled by the bq25896 IC).

Lithium-Ion Capacity vs Longevity

This is copied from the Battery University page on prolonging lithium-based batteries.

Table 4: Discharge cycles and capacity as a function of charge voltage limit

Charge Level* (V/cell) Discharge Cycles Available Stored Energy** Editor's note
[4.30] [150-250] [110%-115%] Potentially unsafe, do not use
4.25 200-350 105-110%
4.20 300-500 100% Flipper Zero, most smartphones, etc
4.15 400-700 90-95%
4.10 600-1,000 85-90%
4.05 850-1,500 80-85%
4.00 1,200-2,000 70-75%
3.90 2,400-4,000 60-65%
3.80 See note 35-40%
3.70 See note 30% and less

Every 0.10V drop below 4.20V/cell doubles the cycle but holds less capacity. Raising the voltage above 4.20V/cell would shorten the life. The readings reflect regular Li-ion charging to 4.20V/cell.

Guideline: Every 70mV drop in charge voltage lowers the usable capacity by about 10%.
Note: Partial charging negates the benefit of Li-ion in terms of high specific energy.

* Similar life cycles apply for batteries with different voltage levels on full charge.
** Based on a new battery with 100% capacity when charged to the full voltage.

Most chargers for mobile phones, laptops, tablets and digital cameras charge Li-ion to 4.20V/cell. This allows maximum capacity, because the consumer wants nothing less than optimal runtime. Industry, on the other hand, is more concerned about longevity and may choose lower voltage thresholds. Satellites and electric vehicles are such examples.

For safety reasons, many lithium-ions cannot exceed 4.20V/cell. (Some NMC are the exception.) While a higher voltage boosts capacity, exceeding the voltage shortens service life and compromises safety. Figure 5 demonstrates cycle count as a function of charge voltage. At 4.35V, the cycle count of a regular Li-ion is cut in half.

bq27220 - battery gauge/health

This chip measures the battery capacity, health, and tracks the current flowing in and out of the battery to provide a percentage remaining.

Of note, Flipper relies on the bq27220's RelativeStateOfCharge() (0x2C) to get the battery charge percentage from 0-100%.

The datasheet for Texas Instrument's bq27220 ("Single-Cell CEDV Fuel Gauge") goes into the electrical and design considerations of the chip. To see the actual commands for interacting with the chip, one must turn to the bq27220 Technical Reference Manual. Section 4.4.1 Detecting Charge Termination on page 49 describes how to determine whether the battery is charged:

Datasheet on Detecting Charge Termination

For proper fuel gauge operation, the cell Charging Voltage must be specified by the user.

The fuel gauge detects charge termination when:

  • During two consecutive periods of 40 seconds, the AverageCurrent() < Taper Current.
  • During the same two periods, the accumulated change in capacity must be > 0.25 mAh.
  • Voltage() > Charging Voltage – Taper Voltage.

When this occurs, the BatteryStatus()[FC] and [TCA] bits are set depending on the SOC Flag Config A [FCSETVCT] and [TCSETVCT] options. Also, if the CEDV Configuration [CSYNC] bit is set, then RemainingCapacity() is set equal to FullChargeCapacity().

Interpretation

Flipper does not set CSYNC, so RemainingCapacity() is not being set equal to FullChargeCapacity() on reaching the charge limit.

Instead, Flipper waits for RelativeStateOfCharge() to reach 100%.

To keep this working with a voltage-based battery charge limit:

  1. The battery gauge's Charging Voltage would need updated and CSYNC would need enabled

  2. Flipper would need to manually map the charging voltage limit to the relevant state of charge percentage.

Datasheet on Charging Voltage

If going for option #1 above, adjusting the battery gauge's Charging Voltage, section 2.21 Charging Voltage on page 24 describes some detail:

ChargingVoltage(): 0x30 and 0x31

This read-only function returns an unsigned integer value of the desired charging voltage of the battery. A
value of 65,535 indicates that the battery is requesting the maximum voltage from the battery charger.

As this value is read-only, the configuration must be specified as part of the Flipper's bq27220_init() function within Control_ENTER_CFG_UPDATE/Control_EXIT_CFG_UPDATE_REINIT, involving resetting the battery gauge chip whenever the charging voltage limit is adjusted and when the Flipper Zero loads settings from internal storage.

Section 3.4 Data Memory Summary on page 29 provides the Charging Voltage configuration parameter:

Class Subclass Address Name Type Min Value Default Units
Configuration Charge 0x91FD Charging Voltage I2 0 4600 4200

Of note, this is separate from the gauge configuration and requires additional initialization code.

How to reconfigure charging voltage

…as this was already getting quite long, I stopped looking at this point. I'm happy to continue if this is the preferred method.

@skotopes
Copy link
Member

skotopes commented Jul 6, 2022

Couple things:

  • battery is guaranteed to last more than 6 years, in real life it should be closer to 10+
  • our battery vendor never did undercharge tests, we can not tell how long battery life will be if undercharged
  • biggest impact on battery health is keeping it discharged, which is much harder to control
  • if I'd implement it I'll change charger configuration, that gives more predictable results
  • gauge data is not very reliable, in some cases it may give offseted values

In my opinion battery life prolongation in that way is not worth it.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 7, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Jul 7, 2022

Firstly, thank you for taking the time to read and respond! I appreciate all of you are very busy and the work y'all have done is awesome!

I've experimented further, successfully tested changing the charger configuration, and tried to better explain myself. I expected to be doing the work to implement this, I just want to make sure I'm pursuing the right path.

Usefulness of charge limiting

Rationale

I agree with you for folks who are carrying their Flipper with them everywhere (akin to a mobile phone), and/or not paying as close attention to the battery level. The bigger concern for them is discharging the battery too far.

The current behavior is a good default!

In my case, though, I don't travel much, so I'd find it easier to leave the Flipper connected to USB power (via a charger or my computer for the serial console) and just disconnect when I go somewhere, ensuring I never have to think about keeping the battery from discharging too much.

However, with the current battery charging behavior, keeping the Flipper plugged in would try to continually keep the battery at near full charge - 4108mV to 4208mV (based on bq25896's default strict 100mV recharge threshold with VRECHG = 0). This does not seem to follow the typical usage pattern most cells are optimized for.

6+ years is a long time, but I tend to use electronic devices longer than average (e.g. I daily-drive a 2014 laptop where the battery has degraded to "70% health", which actually means "about 45 minutes usage at low brightness with little warning before hard shutdown"). If the Flipper battery was easily replaceable, I wouldn't be as concerned, but from watching a teardown video the battery appears to be buried in the middle of the device, with delicate components, plastic clips, tiny screws, and a bit of adhesive in the way.

Battery manufacturer/model?

Can you share the battery manufacturer and model so I may look up the cell datasheet? I couldn't find the details in the Flipper hardware documentation.

(I recognize you might not be allowed to share the actual datasheet, but I might be able to find it online.)

Optional context

Cell manufacturers

I ask since the datasheets for some well-regarded high capacity lithium-ion cells (see "18650 The good cells") make note of reducing charging voltage for use cases where staying charged is more common:

  • The datasheet for the Samsung 35E (found via a web store), suggests on page 14 limiting the charging voltage to 4.00v for when the battery is usually connected to power long term (UPS situation), and 4.10v for electric vehicles (a situation where capacity is critical - the limit might be for battery longevity or for safety reasons).
    • Samsung also suggests on page 11 to store at a lower charge for long-term storage "because storage at higher voltage may cause loss of characteristics." This would apply to long-term primarily keeping the battery fully charged versus partially charged. Elsewhere in the datasheet suggests even as low as the ex-factory charge (30%, 3.49v - 3.69v) would maintain capacity.
  • The Sanyo/Panasonic NCR18650GA cell datasheet (also found via a web store) recommends lowering the charging voltage to 4.15v from 4.20v if charging voltage isn't adjusted according to State of Health, advising on page 10 under "6. Charging Control for Life End" that "Safety and cycle characteristics of Lithium-ion batteries can be improved by reducing the voltage lower than the rated charging voltage."
    • As on page 16, Sanyo also recommends a partially charged state for long term storage (30% / as shipped from factory).

"As shipped from factory" storage charge is too low for daily use, but even a 3.8v charge - the lowest the bq25896 will allow - seems to provide over a full day of Flipper usage before it even reaches factory voltage.

Higher-end round cell chargers do have a "storage" mode that charges to about 3.8v - see "Store" near bottom.

With this in mind, and considering Table 4 on the more general Battery University page, it seems that limiting the charge to 4.00v or so if one frequently connects (or stays connected) to a charger could meaningfully increase the battery longevity.

Device manufacturers using cells

Other device manufacturers have implemented methods to try to adapt to folks who tend to leave things plugged in:

Dell implemented an adaptive charging algorithm that tracks whether one tends to keep a Dell laptop plugged in versus unplugging and discharging often, and it will reduce the maximum charge if it's normally plugged in: Reddit link with linked photos, Dell support forums.

Apple implemented an automatic 80% charge limit that keeps their devices from charging to 100% overnight until right before when it'd normally be unplugged. Google implemented a less intelligent version that operates by scheduled alarms - see "Charge steadily overnight". Both Apple and Google also automatically detect when their devices are plugged in for a few days and limit the maximum charge.

An automatically adapting charging algorithm might be complicated to implement in the Flipper Zero firmware, but a simple way to express "I frequently leave my Flipper connected to the charger/USB so it's kept topped up" versus "I primarily use my Flipper on the go and frequently drain the battery" might be straightforward enough.

Method of charge limiting: changing charger configuration

Your preference makes sense, and I'll focus on that.

In hindsight, I was overcomplicating matters. If combined with a generally applicable pull request to also check the charging IC if it says charging is done, it's very straightforward for me to hard-code a charging voltage limit:

lib/drivers/bq25896.c:

@@ -56,6 +56,12 @@ void bq25896_init(FuriHalI2cBusHandle* handle) {
     furi_hal_i2c_write_reg_8(
         handle, BQ25896_ADDRESS, 0x02, *(uint8_t*)&bq25896_regs.r02, BQ25896_I2C_TIMEOUT);
 
+    // FIXME: Hard-coded hack to test, move this to an actual function later
+    // WARNING: Do NOT go above 0x17 (23 decimal) - that will overcharge the battery!
+    bq25896_regs.r06.VREG = 0x00; // Charge Voltage Limit: 3840 mV (offset: +3840mV)
+    furi_hal_i2c_write_reg_8(
+        handle, BQ25896_ADDRESS, 0x06, *(uint8_t*)&bq25896_regs.r06, BQ25896_I2C_TIMEOUT);
+
     bq25896_regs.r07.WATCHDOG = WatchdogDisable;
     furi_hal_i2c_write_reg_8(
         handle, BQ25896_ADDRESS, 0x07, *(uint8_t*)&bq25896_regs.r07, BQ25896_I2C_TIMEOUT);

(Without the aforementioned pull request, this method of implementing the charging limit works, but the charging LED stays red instead of turning green to signal that the bq25896 chip has stopped charging.)

The question then becomes if enough folks prefer to keep their Flippers on a charger/controlled via USB for integrating this into the Flipper firmware.

I'm happy to put in the effort to add a setting, UI to control it, and some "charge voltage is limited" graphical interface indicator to minimize support hassle, plus going back-and-forth to ensure the code meets all standards.

However, I'd understand if you/Flipper team are not open to accepting any code that implements this - all code does have a maintenance burden.

EDIT 2022-7-7

It may also be reasonable to automatically disable the charging limit if the battery level ever reaches shutdown levels (power_check_low_battery() in applications/power/power_service/power.c). That way, if someone enables this feature then forgets to stay on top of charging, it'll revert back to a full charge the next time they plug in.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 8, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@skotopes skotopes self-assigned this Jul 10, 2022
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 14, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 17, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 20, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@hedger hedger added USB BadUSB + physical USB interface Core+Services HAL, furi & core system services labels Jul 20, 2022
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 23, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 25, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 27, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 28, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Jul 31, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 2, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 3, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 4, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 7, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 11, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 12, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Aug 13, 2022

Design version 2

I'm taking another look at this since, after recent firmware changes, charge limiting is now the only reason I'm building my own firmware instead of using the official builds.

Following @skotopes 's advice, I've focused on adjusting the bq25896's charging voltage. As such, it's not possible (nor desired) to match this up to specific battery charge percentages in the UI, so I've reworked my design drafts.

I'm open to feedback or suggestions.

I'll look at incrementally implementing this as a new pull request built on top of my pull request to also check the charging IC if it says charging is done.

Desktop/battery icon when charging is limited

Screenshot of the Flipper Desktop, showing the usual status bar, including a modified battery charge gauge

If the battery charge voltage is modified, the charged portion of the battery bar will have a cross-hatch pattern in the middle.

This will indicate to anyone trying to provide support that charge limiting is activated (if they know), or something about the battery is modified (if they don't know).

NOTE: This was changed from the initial design as it's not possible to reliably determine what percentage of the battery is unavailable when limiting via reducing battery charging voltage.

Power menu adds configuration

EDIT 2022-8-18: This has been replaced with a new scene with explanatory text and graphics.
Please see the following comment with design 2.1.

Screenshot of the "Power" menu, showing a new configuration item called "Limit charging"

Battery Info
Reboot
Power OFF
Limit charging: < OFF >

In SettingsPower, there will be a new menu option titled Limit charging with the following settings:

  • OFF
    • This is the default setting and corresponds to 4.2v
  • 4.1v
  • 4.0v
  • 3.9v
  • 3.8v

NOTE: Alternatively, this could be made into a new scene with explanatory text, graphics, and a warning to not let the battery fully discharge.

Handling low battery situations

If the battery ever reaches a critical point (0% capacity remaining), Limit charging will be automatically reset to OFF so the next charge will go up to 4.2 volts as usual.

This helps ensure that if someone enables this feature then neglects to keep their Flipper charged, it won't risk damaging the battery further.

If someone enables this feature, it is expected that they will be charging their Flipper frequently.

Battery Info reminds of charge limit when charged

Screenshot of the "Battery Info" menu, showing a charged battery at 3.8v and the text "Charged!  Limited to 3.8v"

Charged!
Limited to 3.8v

If charge limiting is enabled, the Battery Info screen will add an additional line saying Limited to [charge voltage] when charging is complete to remind the user that they enabled charge limiting.

This helps avoid confusion when the battery shows as charged despite not being 100% full.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 16, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Aug 16, 2022

Work-in-progress firmware build

I have implemented all the non-configuration graphical changes in my ft-batt-charge-config branch on my flipperzero-firmware fork.

As the settings aren't yet implemented, it is currently hard-coded to 3.888v for testing purposes.

I'll try to look into creating a power settings configuration soon (it's more complicated than I initially expected). I'll also want to add the automatic disabling of charge limiting if the battery level ever drops to critical.

Here's some live screenshots:

Desktop/battery icon when charging is limited

Screenshot of the Flipper Desktop, showing the usual status bar, including a modified battery charge gauge

The cross-hatch pattern only applies when the battery charging voltage is modified.

Battery Info reminds of charge limit when charged

Screenshot of the "Battery Info" menu, showing a charged battery at 3.8v and the text "Charged!  Limited to 3.8v"

Charged!
Limited to
3.8V

If charge limiting is enabled, the Battery Info screen adds an additional line saying Limited to [charge voltage] when charging is complete to remind the user that they enabled charge limiting.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 19, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Aug 19, 2022

Design revision 2.1

After further thought, this is a confusing setting to expose as just Limit charging: < voltage >. I've drafted up a new configuration screen that better explains what this setting does and how to set it.

NOTE₁: I have not yet implemented this; the ft-batt-charge-config branch on my fork still only implements the non-configuration UI.

Modifying the Power application to implement settings involves significant changes to the application (e.g. using a message queue, mimicking the Notification app which manages LED/LCD brightness), so I want to check if I'm going the right direction first.

I welcome any feedback on the preferred way to modify the Power app to support loading/saving /int/.power.settings, especially if it differs from copying the Notification app implementation.

Power menu adds configuration, revised

Limit battery charging:
[slider with 4 selectable values] 3.9V 4.0V 4.1V 4.2V
[icon of an AC power cord] « — » [icon of a battery]
Always on charger — Full charge, portable use

NOTE₂: The Limit battery charging: text will be bold, like the text for Primary favorite app: in the Desktop settings UI. I don't currently have a good computer approximation of the bold pixel font used by Flipper.

The Left/Right arrows will change the charging voltage. OK will save changes and exit this menu, and Back will exit this menu without saving changes (similar to the Primary favorite app setting).

The AC power cord icon will be added as a new asset. The battery icon is copied from the Battery Info screen. This scene/view will involve custom canvas drawing calls, similar to the Battery Info screen.

I removed the 3.8V setting, so the lowest configurable charge level of 3.9V ensures that half (40-60%) of the lithium-ion battery capacity will be available at minimum while still providing an estimated 6-8× increase in battery charge cycles.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 23, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 23, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

Brief update for those following along

Another contributor has already refactored the Power application to support saving/loading settings. If merged, their work would simplify my task as I'd just need to focus on the new UI and the new setting.

However, if the Flipper team decides that the minimum 4Kb internal storage cost to add two settings (that pull request plus my future pull request) is too expensive for the Flipper's limited internal storage, then this feature might not be practical for me to add. Without settings, it would only be a temporary change (being reset to 4.2v on every reboot).

I'll continue to plan and implement, but I might wait for the Flipper developer team to decide on whether they'll allow the storage cost of adding the /int/.power.settings file before I get too far along.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 25, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Aug 28, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 2, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 14, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 14, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

This adds a new function to the API:
furi_hal_power_is_charging_done()

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 14, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

This adds a new function to the API:
furi_hal_power_is_charging_done()

Helps with flipperdevices#1158.
@D0han
Copy link

D0han commented Sep 17, 2022

Awesome work!
Can you also add easy to trigger one-off option to charge Flipper fully?
The use case would be pretty much same as yours, but also to easily prepare for a field trip with more battery time.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 17, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

This adds a new function to the API:
furi_hal_power_is_charging_done()

Helps with flipperdevices#1158.
digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 19, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

This adds a new function to the API:
furi_hal_power_is_charging_done()

Helps with flipperdevices#1158.
@digitalcircuit
Copy link
Contributor Author

@D0han I think a one-off option to fully charge the Flipper while keeping charge limiting enabled is a good idea.

However, to help keep this task manageable, I don't think I'll be implementing that in my initial pull request.

When I've implemented the current design, it will be possible to manually set the charge limit to 4.2v to fully charge, then when you head off on the trip, set the limit back down when unplugging - no need to wait for the Flipper to discharge. Hopefully, the lack of the crosshatch pattern on the desktop battery capacity bar will help with remembering that the charge limit is not enabled.

digitalcircuit added a commit to digitalcircuit/flipperzero-firmware that referenced this issue Sep 23, 2022
Also check the actual charge controller bq25896's CHRG_STAT to see if
charging is complete.  Don't only rely on the battery fuel gauge
bq27220 reaching 100% to indicate charging is finished.

This more accurately reflects the actual charging status and
simplifies optionally reducing the battery charging voltage limit.
Keeping the fuel gauge check ensures that dis/connecting from USB will
still show as fully charged at default settings (no charge limit),
since the bq25896 takes a few seconds to detect charging is complete.

This adds a new function to the API:
furi_hal_power_is_charging_done()

Helps with flipperdevices#1158.

# Conflicts:
#	firmware/targets/f7/api_symbols.csv
@digitalcircuit
Copy link
Contributor Author

digitalcircuit commented Nov 30, 2022

For anyone following along, I've gotten everything except for the actual configuration UI implemented in PR #2063, "power: Add API to get/set battery charging voltage".

EDIT: the API pull request has been merged! Now the Power settings UI needs implemented.

If you build that pull request, you can then add and build your own custom tiny Flipper application or service (as described in the verification steps) to set the battery charging voltage limit. I'll add the integrated settings UI once PR #1647, "Automatic shutdown on idle" is merged, providing the settings loading/saving backend.

If you have the know-how to build the firmware yourself, help with testing would be appreciated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Core+Services HAL, furi & core system services Feature Request New feature or user-story you wanna add to flipper USB BadUSB + physical USB interface
Projects
None yet
Development

No branches or pull requests

4 participants