Power.L.1N
Power.L.1N tile driver — Nordic nPM1300 PMIC.
Battery charger + 2 buck regulators + system supply (VSYS) + 3 indicator LEDs. Platform-agnostic: all bus access goes through tiles_pal_t.
The bucks come up at fixed boot voltages chosen by the tile's VSET pulldown resistors (no I2C needed): VSET1 = 47 kΩ → VOUT1 = 1.8 V, VSET2 = 330 kΩ → VOUT2 = 3.3 V. buck_set_mv() switches a buck to software control to override its VSET default at runtime.
Tile LEDs. Three discrete 0201 parts (Power-L1-N-a BOM), not an RGB package: U3 = APG015SURKKC-TT 631 nm red U4 = APG015SEKKC-TT 605 nm ORANGE (previously documented as "yellow") U5 = APG015CGKKC-TT 571 nm green
Which LED is which (confirmed 2026-09-24): red, orange, green sit left to right on the nPM1300's A1, A2, A3 balls, which are LED0, LED1, LED2 (WLCSP pin table). So LED0 = red (U3), LED1 = orange (U4), LED2 = green (U5).
Driver mode assignment made by init() (the chip's own reset assignment): LED0 red → ERROR mode (auto, on for charger faults) LED1 orange → CHARGING mode (auto, on while charging) LED2 green → HOST mode (firmware "ready"/status, via led_set())
Before 1.2.0 init() had this backwards (LED0 HOST, LED2 ERROR, from a misread schematic), so a charger fault lit the green LED and firmware status the red one.
Vibe Settings
What Studio’s Vibe interface lets you change on this tile, in plain language or from the tile inspector. Each one is an argument of a driver function below, so the same setting is available from Blocks, the DSL and C. Basic settings are shown by default; advanced ones sit behind the inspector’s Advanced toggle.
| Setting | Tier | Values | Default | Function |
|---|---|---|---|---|
| Charge the battery | basic | on / off | on | charger_enable(on) |
| USB input limit | basic | 100 to 1500 mA | 500 | set_vbus_limit_ma(ma) |
| Charge current | basic | 32 to 800 mA | 100 | set_charge_current_ma(ma) |
| Charge to | advanced | 3.5 to 4.45 V | 4.2 | set_term_mv(mv) |
| USB input limit from USB-C source | advanced | on / off | off | set_vbus_limit_auto(on) |
Examples
Quick start
#include "core_tiles.h"
tile_t pmic;
tile_power_l_1n_init(core_tiles_pal(&core_i2c1), 0, &pmic, NULL);
if (tile_is_ready(&pmic)) {
tile_power_l_1n_set_charge_current_ma(&pmic, 200);
tile_power_l_1n_charger_enable(&pmic, 1);
uint16_t vbat = tile_power_l_1n_get_vbat_mv(&pmic);
(void)vbat;
}API reference
Initialization
tile_power_l_1n_find
uint8_t tile_power_l_1n_find(tiles_pal_t* hal, uint8_t instance)Check whether an nPM1300 is present on the I2C bus.
- hal
- Platform HAL handle
- instance
- Instance index (0 = default, see mapping table)
Returns 1 if the device ACKs, 0 otherwise
tile_power_l_1n_init
void tile_power_l_1n_init(tiles_pal_t* hal, uint8_t instance, tile_t* tile, const power_l_1n_cfg_t* cfg)Sets the indicator LED modes (LED0 red = ERROR, LED1 orange = CHARGING, LED2 green = HOST), disables NTC monitoring (no thermistor on this tile), and applies the charger settings. The buck regulators are left at their boot voltages (1.8 V / 3.3 V, fixed by the VSET resistors) — they are already up. Pass cfg=NULL for defaults (500 mA USB limit, 100 mA, 4.20 V, charging enabled, USB-C auto limit off). A zero-initialised cfg is NOT the same as NULL: it leaves charging OFF (enable_charging = 0).
- hal
- Platform HAL handle
- instance
- Instance index (0 = default, see mapping table)
- tile
- Pointer to tile handle (populated by this function)
- cfg
- Optional config, or NULL for defaults
- Warning: The NULL defaults suit a single Li-ion / Li-poly cell rated 4.20 V and at least ~100 mAh (100 mA is 1C for a 100 mAh cell). They are NOT safe for a LiFePO4 cell (charge to 3.60 V: pass term_mv = 3600) or for a smaller cell (lower charge_current_ma to <= 1C). The chip itself powers up with charging disabled at 3.60 V / 32 mA; init() is what raises it.
Runtime
tile_power_l_1n_get_charge_status
Studiouint8_t tile_power_l_1n_get_charge_status(tile_t* tile)Read the raw charge-status register.
Returns BCHGCHARGESTATUS bits (NPM1300_CHG_* mask).
tile_power_l_1n_get_charge_error
Studiouint8_t tile_power_l_1n_get_charge_error(tile_t* tile)Read the charger error-reason register.
Returns BCHGERRREASON bits (0 = no error).
tile_power_l_1n_is_charging
Studiouint8_t tile_power_l_1n_is_charging(tile_t* tile)Whether the charger is actively charging (trickle / CC / CV).
Returns 1 if charging, 0 otherwise.
tile_power_l_1n_is_charge_complete
Studiouint8_t tile_power_l_1n_is_charge_complete(tile_t* tile)Whether charging has completed (battery full).
Returns 1 if charge complete, 0 otherwise.
tile_power_l_1n_battery_present
Studiouint8_t tile_power_l_1n_battery_present(tile_t* tile)Do NOT gate a charge-enable decision on this; that deadlocks. Enable charging first, poll this for a second or two, and disable again if nothing appears. Note also that get_vbat_mv() cannot substitute: an open battery terminal reads a plausible ~3 V once charger current has pushed the VBAT decoupling cap up.
Returns 1 if a battery is present, 0 otherwise.
- Warning: Only meaningful while charging is ENABLED. This reads BATTERYDETECTED in BCHGCHARGESTATUS, a charger-domain bit: the datasheet states "CHARGER waits until a battery is detected before charging", i.e. detection runs as part of the charge cycle. With the charger disabled the bit reads 0 whether or not a cell is fitted — measured on the bench with a battery physically attached (0 before enable, 1 after).
tile_power_l_1n_get_usbc_source
Studiopower_l_1n_usbc_t tile_power_l_1n_get_usbc_source(tile_t* tile)The nPM1300 has the Type-C sink pull-downs (Rd = 5.1 kOhm) on CC1 / CC2 inside the chip, and comparators that decode the CC voltage while VBUS is present (thresholds 0.2 / 0.66 / 1.23 V, debounced 15 ms; datasheet 6.1.3, 6.1.6). Only the CC line on the plug's side carries a level; the other stays at 0 V. This reads both fields of USBCDETECTSTATUS and returns the one that is set (if both ever are, the lower, as the safer of the two). The chip only reports; it never raises the input limit by itself. Use set_vbus_limit_auto() for that. NONE also covers a supply that is not Type-C at all (CC pads left open or grounded), so NONE with VBUS present means "unknown", not "no power".
Returns power_l_1n_usbc_t: 0 none, 1 default USB, 2 1.5 A, 3 3.0 A.
tile_power_l_1n_get_usbc_current_ma
Studiouint16_t tile_power_l_1n_get_usbc_current_ma(tile_t* tile)NONE gives 0; DEFAULT gives 500 (USB 2.0's configured level: the Rp level cannot tell a USB 3 port's 900 mA apart, and a strict USB 2.0 device draws only 100 mA until the host configures it); 1.5 A gives 1500; 3.0 A gives 3000. That is what the source offers, not what this tile draws: the input limit tops out at 1500 mA.
Returns Advertised source current in mA (0, 500, 1500 or 3000).
tile_power_l_1n_update_vbus_limit
Studiouint16_t tile_power_l_1n_update_vbus_limit(tile_t* tile)With the auto limit on, reads the CC status and applies the limit set_vbus_limit_auto() describes; call it after a re-plug. With it off, or with no VBUS present, it changes nothing. Cheap (a few register reads and two writes), so calling it from a main loop is fine.
Returns The input limit now in force, in mA.
tile_power_l_1n_get_vbat_mv
Studiouint16_t tile_power_l_1n_get_vbat_mv(tile_t* tile)Measure the battery voltage.
Returns VBAT in millivolts (0-5000).
tile_power_l_1n_get_vsys_mv
Studiouint16_t tile_power_l_1n_get_vsys_mv(tile_t* tile)Measure the system (VSYS) voltage.
Returns VSYS in millivolts (0-6375).
tile_power_l_1n_get_die_temp_c
Studioint16_t tile_power_l_1n_get_die_temp_c(tile_t* tile)Measure the PMIC die temperature.
Returns Die temperature in degrees Celsius.
tile_power_l_1n_led_set
Studiovoid tile_power_l_1n_led_set(tile_t* tile, uint8_t led, uint8_t on)Only effective when the LED is in HOST mode (see led_set_mode).
- led
- 0, 1 or 2.
- on
- 1 = on, 0 = off.
Events
tile_power_l_1n_process
Studiovoid tile_power_l_1n_process(tile_t* tile)Reads BCHGCHARGESTATUS (one I2C read) and compares it with the previous call. Fires the callback with NPM1300_CHG_COMPLETED when COMPLETED turns on, and with the phase bit when the charger goes from not charging to charging (trickle, CC or CV). A phase change inside one charge (trickle to CC to CV) does not fire again. The tile's INT pin is not used; this is polled.
tile_power_l_1n_on_event
Studiovoid tile_power_l_1n_on_event(tile_t* tile, power_l_1n_event_cb_t cb, void* ctx)Register or change the event callback.
- cb
- Callback to fire on a charge-state change. NULL to clear.
- ctx
- Opaque user pointer passed to the callback.
Config
tile_power_l_1n_charger_enable
Studiovoid tile_power_l_1n_charger_enable(tile_t* tile, uint8_t on)Enable or disable battery charging.
- on
- 1 = enable charging, 0 = disable.
tile_power_l_1n_set_vbus_limit_ma
Studiovoid tile_power_l_1n_set_vbus_limit_ma(tile_t* tile, uint16_t ma)The nPM1300 powers up with a 100 mA input limit; init() raises it to 500 mA (what any USB port gives) unless the config says otherwise. The limit caps what is drawn from USB for the system AND the charger together. It does not regulate VSYS: with a battery attached, asking for more than the limit cuts the charge back and lets VSYS fall to just above the battery voltage (measured: a 100 mA charge on the 100 mA limit took VSYS from 5.15 V to ~3.65 V; both bucks held, but with only ~350 mV of headroom on 3.3 V, which a load with a start-up surge can dip). With no battery, VSYS simply sags. The chip falls back to its START-UP limit whenever VBUS is removed, which matters for exactly the system that charges: one with a battery keeps running through an unplug, and would otherwise be back at 100 mA on re-plug. So this writes the start-up limit too, and the value holds until the chip is RESET (when it returns to 100 mA, and init() sets it again). Settable 100-1500 mA in 100 mA steps; a request is rounded DOWN to a step (never more than asked) and clamped to that range. 100 and 500 mA are the USB-compliant, accurately trimmed levels; 500 mA is safe for any USB port. More is only safe for a source known to deliver it: check get_usbc_source(), or let set_vbus_limit_auto() choose from what the USB-C source advertises. With the auto limit ON, this value is the fallback: it stays the start-up limit (what a re-plug starts at) and applies whenever no USB-C source is detected; a detected source overrides it (see set_vbus_limit_auto).
- ma
- [100..1500] mA Input current limit, in milliamps.
tile_power_l_1n_set_charge_current_ma
Studiovoid tile_power_l_1n_set_charge_current_ma(tile_t* tile, uint16_t ma)Programmable 32-800 mA in 2 mA steps (rounded down); out-of-range values clamp. The chip only accepts a new current while the charger is disabled (datasheet §6.2.4), so if charging is on this pauses it for the write and re-enables it. Keep it at or below 1C for the cell fitted.
- ma
- [32..800] mA Charge current in milliamps.
tile_power_l_1n_set_term_mv
Studiovoid tile_power_l_1n_set_term_mv(tile_t* tile, uint16_t mv)Selectable 3.50-3.65 V or 4.00-4.45 V in 50 mV steps; the 3.70-3.95 V gap is not supported and clamps to 3.65 V.
- mv
- [3500..4450] mV Termination voltage in millivolts (e.g. 4200).
tile_power_l_1n_set_vbus_limit_auto
Studiovoid tile_power_l_1n_set_vbus_limit_auto(tile_t* tile, uint8_t on)Off by default (init() writes 500 mA, or cfg->vbus_limit_ma, and leaves it). When on, the input limit follows the source: default USB 500 mA, 1.5 A and 3.0 A sources 1500 mA (the chip's maximum). With no USB-C source detected (no VBUS, or a supply without CC) it falls back to the set_vbus_limit_ma() value. Turning it off restores that value. The limit is applied now, and again each time update_vbus_limit() runs. The chip drops back to the start-up limit (the set_vbus_limit_ma() value) whenever VBUS is removed, so a system that stays up on its battery should call update_vbus_limit() after a re-plug (e.g. from its main loop), at least 15 ms after VBUS returns so the CC comparators have settled.
- on
- 1 = follow the USB-C source, 0 = use the set_vbus_limit_ma() value.
tile_power_l_1n_buck_enable
Studiovoid tile_power_l_1n_buck_enable(tile_t* tile, uint8_t buck, uint8_t on)Enable or disable a buck regulator.
- buck
- 1 (VOUT1) or 2 (VOUT2).
- on
- 1 = enable, 0 = disable.
tile_power_l_1n_buck_set_mv
Studiovoid tile_power_l_1n_buck_set_mv(tile_t* tile, uint8_t buck, uint16_t mv)Selects software voltage control for that buck (overriding its VSET resistor) and applies the new target.
- buck
- 1 (VOUT1) or 2 (VOUT2).
- mv
- [1000..3300] Output voltage in mV, 100 mV steps.
tile_power_l_1n_led_set_mode
Studiovoid tile_power_l_1n_led_set_mode(tile_t* tile, uint8_t led, power_l_1n_led_mode_t mode)In auto modes (ERROR/CHARGING) the charger drives the LED directly; HOST mode hands control to led_set(). LED0 is red, LED1 orange, LED2 green (see the file header). init() leaves LED2 in HOST mode for firmware status.
- led
- 0, 1 or 2.
- mode
- power_l_1n_led_mode_t.
Advanced
tile_power_l_1n_get_reset_cause
Studiouint8_t tile_power_l_1n_get_reset_cause(tile_t* tile)Read the reset-cause register (why the PMIC last reset).
Returns RSTCAUSE bits.
Driver gaps · 5
Chip capabilities this driver doesn’t expose yet.
Events
- charge_complete
- charging
Enums
power_l_1n_usbc_t
USB-C source capability (get_usbc_source).
- NPM1300_USBC_NONE
- No Type-C source: no VBUS, CC open/grounded, or a legacy supply
- NPM1300_USBC_DEFAULT
- Default USB power (USB 2.0: 500 mA once configured)
- NPM1300_USBC_1A5
- Type-C Current 1.5 A
- NPM1300_USBC_3A
- Type-C Current 3.0 A
power_l_1n_led_mode_t
LED indicator mode (LEDDRVxMODESEL).
- NPM1300_LED_ERROR
- auto: on for charger error
- NPM1300_LED_CHARGING
- auto: on while charging
- NPM1300_LED_HOST
- software-controlled via led_set()
- NPM1300_LED_NOTUSED
- disabled
Constants
| TILE_POWER_L_1N_VERSION_MAJOR | 1 | |
| TILE_POWER_L_1N_VERSION_MINOR | 4 | |
| TILE_POWER_L_1N_VERSION_PATCH | 0 | |
| NPM1300_I2C_ADDR | 0x6B |

