Kode Dot

Power and battery

What charges a Kode Dot and what feeds it: the charger, the fuel gauge, the 5 V it can give out, what each part of the board costs, and the code to read the battery.

What it is

Three parts keep a Kode Dot running: a lithium cell, a charger and a fuel gauge. The BQ25896 is the charger and the power path: USB-C comes in, the battery charges, and the board runs from whichever is there. It also reports which source is feeding the device and how a charge is going. The CW2217 is the fuel gauge, on a shunt in series with the cell, so it sees everything the board draws and can tell you the level.

The charger also works backwards. With no USB attached it can boost the cell to 5 V on the expansion header, so a module plugged in there runs from the battery.

How it is connected

flowchart LR
usb["USB-C, 5 V"] --> pmic["BQ25896"]
bat["LiPo cell"] <--> pmic
pmic --> sys["System rail"]
pmic -. "boost, on request" .-> hdr["Header 5 V"]
bat --> gauge["CW2217 on the shunt"]
p4["ESP32-P4"] -- "I2C, 0x6B / 0x64" --> pmic
p4 -- "I2C" --> gauge
Charger and gauge on the I2C bus; the charger feeds the board and, on request, the header

Both chips answer on the shared I2C bus: the charger at 0x6B, the gauge at 0x64. The gauge is powered from the cell, so with no battery fitted it does not answer at all. The bottom button is wired to the charger's power-on line, which is how a fully-off Kode Dot starts with a long press.

Specifications

ThingValue
ChargerBQ25896, U13, at 0x6B. Power path from USB-C, charge control, ADC for VBUS, VSYS, battery and charge current
Fuel gaugeCW2217, U14, at 0x64, on a 10 mΩ shunt. Powered from the cell
Charge limit850 mA, set by the charger's ILIM pin, not by a register
5 V outThe charger's boost onto the header's 5 V pins, about 5.00 V, on request. Fused at 2 A
Power onBottom button held 2 to 3 s, or USB-C plugged in
Power offA firmware action. kodeOS's Turn off card puts the board in deep sleep, and BOT held about a second wakes it. Ship mode, only from the console verb ship_mode, opens the battery switch, and nothing is preserved (internals/power-and-sleep)
Kode driverkode_battery_init, then kode_battery_read for volts, percent, charging and USB present
CellTBD: the capacity Kode ships
ValidatedKode-Dot-Val/12-POWER: charge, gauge, boost and a consumption profile on a board

What the parts cost, measured one at a time on a validation board with no C5 fitted and no speaker. Use it to rank the parts against each other; do not add it up into a battery life.

PartCurrent
NFC fieldAbout 109 mA, and a floor while it is up
Display, white, full brightnessAbout 76 mA
Status LED, all three at maximumAbout 71 mA
Both cores at 100 %About 46 mA
RFID carrierAbout 17 mA
Infrared, averaged over a frameAbout 12 mA
Display at 25 % brightnessAbout 3 mA
Wi-Fi and BluetoothTBD: not in the profile, no C5 on that board

Gotchas

Apps that use it

On the marketplace, apps that put this part to work. Install one from start/first-app and see it before you write a line.

Example code

Read the battery once a second and log it. On USB you see the charging flag set; unplug and the voltage starts to fall.

/*
 * battery_log.c - 2026-09-18 - from Kode with love
 *
 * Logs the Kode Dot's battery once a second: volts, an estimated percent,
 * whether it is charging and whether USB is present. Brings the board up,
 * wakes the charger and the gauge through the Kode driver, then reads.
 * With no battery fitted the init fails: the gauge runs from the cell.
 */
#include "esp_log.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "kode.h"
 
/* Board, then both chips, then one reading per second. */
void app_main(void)
{
    ESP_ERROR_CHECK(kode_bsp_init());
    ESP_ERROR_CHECK(kode_battery_init());   /* blocks about a third of a second */
 
    while (1) {
        kode_battery_t b;
        if (kode_battery_read(&b) == ESP_OK) {
            ESP_LOGI("battery", "%.2f V  %3u %%  %s  %s", b.volts, b.percent,
                     b.charging ? "charging" : "not charging", b.usb_present ? "usb" : "battery");
        }
        vTaskDelay(pdMS_TO_TICKS(1000));
    }
}

Compiled on the date in the header against the kode component with ESP-IDF v6.1. TBD: a run on a V1 board.

In the SDK