nPM1300 BUCK enable fails on power-on reset — intermittent init failure for BUCK, LDO, and LIS2DW12 (nRF9151, NCS 2.9.0)

Title: nPM1300 BUCK enable fails on power-on reset — intermittent init failure for BUCK, LDO, and LIS2DW12 (nRF9151, NCS 2.9.0)


Board: Custom board — nRF9151 + nPM1300 + LIS2DW12 + RTC (all on same I2C bus) NCS Version: 2.9.0 Toolchain: nRF Connect for VS Code


Problem Description

I am experiencing intermittent initialization failures on power-on reset (POR) when the battery is connected. The failures include:

  • BUCK1 and/or BUCK2 regulator_enable() returning an error
  • LDO1 / LDO2 enable failing
  • nPM1300 charger / fuel gauge device not ready
  • LIS2DW12 accelerometer device_is_ready() returning false

Key observation: If I remove the battery and wait 30–40 seconds before reconnecting, all devices initialize successfully every time. If I reconnect the battery immediately or within a few seconds, the failures occur intermittently.


Hardware Setup
  • nRF9151 SoC as host
  • nPM1300 PMIC connected via I2C
  • BUCK1 → 1.8V (nRF9151 core supply)
  • BUCK2 → 3.3V (peripheral supply)
  • LDO1 / LDO2 → 1.8V (load switches in LDSW mode)
  • LIS2DW12 accelerometer, RTC — all on the same I2C bus as nPM1300

Initialization Flow

The nPM1300 MFD and regulator drivers initialize automatically before main() via Zephyr's POST_KERNEL init (priorities 51/52). Application-level regulator configuration happens inside peripheral_init() called from main():

static void peripheral_init(void)
{

set_and_print_active_discharge();
k_msleep(200);
// Set and verify BUCK1 and BUCK2 voltages
printk("Setting BUCK1 to 1.8V\n");
int err = regulator_set_voltage(buck1, 1800000, 1800000);
if (err < 0)
{
printk("Error: Could not set BUCK1 voltage: %d\n", err);
set_dev_led(0, 0);
return;
}

err = regulator_set_voltage(buck2, 3300000, 3300000);
if (err < 0)
{
printk("Error: Could not set BUCK2 voltage: %d\n", err);
set_dev_led(0, 0);
return;
}

// Enable regulators
printk("Enabling BUCK1, BUCK2, LDO1, LDO2\n");
err = regulator_enable(buck1);
if (err < 0)
{
printk("Error: Could not enable BUCK1: %d\n", err);
set_dev_led(0, 0);
return;
}
k_msleep(200);

.....


}

Sensor init runs after peripheral_init():

void sensor_init(void) { check_lis2dw12(); check_max30001g(); }

The nPM1300 charger and fuel gauge are accessed from a separate thread (dev_battery_level()), which runs concurrently with the main thread after 20 seconds.


Root Cause Hypothesis

The 30–40 second wait resolves the issue, which strongly suggests residual charge on the BUCK output capacitors from the previous session is preventing a clean BUCK restart on the next power-on reset. This matches the nPM1300 product specification behavior where active output capacitor discharge is disabled by default for the BUCK regulators. [nPM1300 BUCK]


What I Have Tried

1. Adding active-discharge to the devicetree overlay

npm1300_ek_buck1: BUCK1 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-init-microvolt = <1800000>; active-discharge; };

Result: Build error in NCS 2.9.0:

'active-discharge' appears in BUCK1 but is not declared in 'properties:' in nordic,npm1300-regulator.yaml

The property is not supported in the NCS 2.9.0 binding for nordic,npm1300-regulator.


2. Using the Zephyr Regulator API at runtime

regulator_set_active_discharge(buck1, true); regulator_set_active_discharge(buck2, true); regulator_set_active_discharge(ldo1, true); regulator_set_active_discharge(ldo2, true);

Result: All four calls return -88 (-ENOSYS), meaning the set_active_discharge driver op is not implemented in the nPM1300 regulator driver in NCS 2.9.0. [Regulator API]


Questions
  1. Is there a supported way to enable active discharge for the nPM1300 BUCK and LDO/LDSW outputs in NCS 2.9.0 (e.g., via direct I2C register write to BUCKCTRL0 RDISCH bit)?
  2. Which NCS version first introduced set_active_discharge support for the nPM1300 regulator driver?
  3. Is there a recommended workaround for the power-on reset BUCK enable failure caused by residual capacitor charge, within NCS 2.9.0?
  4. Is this related to any known nPM1300 anomaly (e.g., BUCK restart failure after reset with VBAT connected)?

Any guidance would be appreciated. Thank you.

Parents
  • I dont understand what means build code you want?


    I want also explain one more thing is

    i also tried with modular example code there also this issue occur

    my npm1300 modular code 

    int main(void)
    {
    	int8_t err = 0;
    	// set_active_discharge(buck2, true);
        // set_active_discharge(ldo1,  true);
        // set_active_discharge(ldo2,  true);
    	printk("Start Application\n");
    	
    	// // Ensure PMIC and charger devices are ready
    	if (!device_is_ready(pmic))
    	{
    		printk("Pmic device not ready.\n");
    		return 0;
    	}
    
    	if (!device_is_ready(charger))
    	{
    		printk("Charger device not ready.\n");
    		return 0;
    	}
    
    	// Initialize fuel gauge
    	if (fuel_gauge_init(charger) < 0)
    	{
    		printk("Could not initialise fuel gauge.\n");
    		return 0;
    	}
    
    	// Register VBUS event callback
    	static struct gpio_callback vbus_event_cb;
    	gpio_init_callback(&vbus_event_cb, vbus_event_callback,
    					   BIT(NPM1300_EVENT_VBUS_DETECTED) |
    					   BIT(NPM1300_EVENT_VBUS_REMOVED));
    
    	err = mfd_npm1300_add_callback(pmic, &vbus_event_cb);
    	if (err)
    	{
    		printk("Failed to add pmic callback.\n");
    		return 0;
    	}
    
    	// Initialize VBUS status
    	struct sensor_value val;
    	int ret = sensor_attr_get(charger, SENSOR_CHAN_CURRENT, SENSOR_ATTR_UPPER_THRESH, &val);
    	if (ret < 0)
    	{
    		return false;
    	}
    	vbus_connected = (val.val1 != 0) || (val.val2 != 0);
    
    	printk("PMIC device ok\n");
    
    	// Get handle to PMIC LEDs
    	const struct device *led_dev = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_leds));
    	if (!device_is_ready(led_dev))
    	{
    		printk("LED device not ready\n");
    		return -1;
    	}
    
    	// Turn off LED 0 initially
    	led_off(led_dev, 0);
    
    	while (1)
    	{
    		// Update fuel gauge metrics
    		// fuel_gauge_update(charger, vbus_connected);
    		
    		// // Enable regulators
    		printk("buck, ldo1, ldo2 = on\n");
    
    		err = regulator_enable(buck2);
    		if (err < 0)
    		{
    			printk("Error: Could not enable buck2\n");
    			return err;
    		}
    		k_msleep(50);
    
    		err = regulator_enable(ldo1);
    		if (err < 0)
    		{
    			printk("Error: Could not enable ldo1\n");
    			return err;
    		}
    		k_msleep(50);
    
    		err = regulator_enable(ldo2);
    		if (err < 0)
    		{
    			printk("Error: Could not enable ldo2\n");
    			return err;
    		}
    		k_msleep(50);
    
    		k_msleep(SLEEP_TIME_MS);
    
    		// // Disable regulators (repeat to ensure successful disablement)
    		printk("buck, ldo1, ldo2 = off\n");
    
    		for (int i = 0; i < 5; i++)
    		{
    			err = regulator_disable(buck2);
    			if (err < 0)
    			{
    				printk("Error: Could not disable buck2\n");
    				return err;
    			}
    			k_msleep(50);
    
    			err = regulator_disable(ldo1);
    			if (err < 0)
    			{
    				printk("Error: Could not disable ldo1\n");
    				return err;
    			}
    			k_msleep(50);
    
    			err = regulator_disable(ldo2);
    			if (err < 0)
    			{
    				printk("Error: Could not disable ldo2\n");
    				return err;
    			}
    			k_msleep(50);
    		}
    
    		k_msleep(SLEEP_TIME_MS);
    	}
    
    	return 0;
    }


    overlay

    #include <dt-bindings/regulator/npm1300.h>
    #include <zephyr/dt-bindings/input/input-event-codes.h>
    #define NPM1300_BUCK_MODE_PFM 0x04U
    
    &arduino_i2c {
        npm1300_ek_pmic: pmic@6b {
            compatible = "nordic,npm1300";
            reg = <0x6b>;
    
            npm1300_ek_gpio: gpio-controller {
                compatible = "nordic,npm1300-gpio";
                gpio-controller;
                #gpio-cells = <2>;
                ngpios = <5>;
            };
    
            npm1300_ek_regulators: regulators {
                compatible = "nordic,npm1300-regulator";
    
                npm1300_ek_buck1: BUCK1 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    // regulator-always-on; // Optional: Keeps BUCK1 on
                };
    
                npm1300_ek_buck2: BUCK2 {
                    regulator-min-microvolt = <1000000>;
                    regulator-max-microvolt = <3300000>;
                    regulator-init-microvolt = <3300000>;
                    // regulator-always-on; // Optional: Keeps BUCK2 on
                    /delete-property/ enable-gpios;
                    /delete-property/ retention-gpios;
                    /delete-property/ pwm-gpios;
                };
    
                npm1300_ek_ldo1: LDO1 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
                    /delete-property/ enable-gpios;
                };
    
                npm1300_ek_ldo2: LDO2 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
                    /delete-property/ enable-gpios
                };
            };
    
        npm1300_ek_charger: charger {
            compatible = "nordic,npm1300-charger";
            // Corrected charging parameters
            term-microvolt = <4100000>;          // 4.2V - Standard Li-ion termination
            term-warm-microvolt = <4000000>;     // 4.1V - Slightly lower for warm conditions
            current-microamp = <500000>;         // 500mA - Reasonable charging current
            dischg-limit-microamp = <1000000>;
            vbus-limit-microamp = <1000000>;     // 1A USB input limit
            thermistor-ohms = <10000>;
            thermistor-beta = <3380>;
            charging-enable;
        };
    
            npm1300_ek_buttons: buttons {
                status = "disabled";
                compatible = "gpio-keys";
                pmic_button0: pmic_button_0 {
                    status = "disabled";
                    gpios = <&npm1300_ek_gpio 0 GPIO_ACTIVE_HIGH>;
                    label = "Pmic button switch 0";
                    zephyr,code = <INPUT_KEY_0>;
                };
            };
    
            npm1300_ek_leds: leds {
                compatible = "nordic,npm1300-led";
                nordic,led0-mode = "charging";
                nordic,led1-mode = "host";
                nordic,led2-mode = "host";
            };
        };
    };


    my also question is

    1. Adding active-discharge to the devicetree overlay

    npm1300_ek_buck1: BUCK1 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-init-microvolt = <1800000>; active-discharge; };

    Result: Build error in NCS 2.9.0:

    'active-discharge' appears in BUCK1 but is not declared in 'properties:' in nordic,npm1300-regulator.yaml

    The property is not supported in the NCS 2.9.0 binding for nordic,npm1300-regulator.


    2. Using the Zephyr Regulator API at runtime

    regulator_set_active_discharge(buck1, true); regulator_set_active_discharge(buck2, true); regulator_set_active_discharge(ldo1, true); regulator_set_active_discharge(ldo2, true);

    Result: All four calls return -88 (-ENOSYS), meaning the set_active_discharge driver op is not implemented in the nPM1300 regulator driver in NCS 2.9.0. [Regulator API]


    this 2 is help us to solve issue

    and this is not working in sdk 2.9.0 and also explain what is alternative of this?

    best regards

    Milan

Reply
  • I dont understand what means build code you want?


    I want also explain one more thing is

    i also tried with modular example code there also this issue occur

    my npm1300 modular code 

    int main(void)
    {
    	int8_t err = 0;
    	// set_active_discharge(buck2, true);
        // set_active_discharge(ldo1,  true);
        // set_active_discharge(ldo2,  true);
    	printk("Start Application\n");
    	
    	// // Ensure PMIC and charger devices are ready
    	if (!device_is_ready(pmic))
    	{
    		printk("Pmic device not ready.\n");
    		return 0;
    	}
    
    	if (!device_is_ready(charger))
    	{
    		printk("Charger device not ready.\n");
    		return 0;
    	}
    
    	// Initialize fuel gauge
    	if (fuel_gauge_init(charger) < 0)
    	{
    		printk("Could not initialise fuel gauge.\n");
    		return 0;
    	}
    
    	// Register VBUS event callback
    	static struct gpio_callback vbus_event_cb;
    	gpio_init_callback(&vbus_event_cb, vbus_event_callback,
    					   BIT(NPM1300_EVENT_VBUS_DETECTED) |
    					   BIT(NPM1300_EVENT_VBUS_REMOVED));
    
    	err = mfd_npm1300_add_callback(pmic, &vbus_event_cb);
    	if (err)
    	{
    		printk("Failed to add pmic callback.\n");
    		return 0;
    	}
    
    	// Initialize VBUS status
    	struct sensor_value val;
    	int ret = sensor_attr_get(charger, SENSOR_CHAN_CURRENT, SENSOR_ATTR_UPPER_THRESH, &val);
    	if (ret < 0)
    	{
    		return false;
    	}
    	vbus_connected = (val.val1 != 0) || (val.val2 != 0);
    
    	printk("PMIC device ok\n");
    
    	// Get handle to PMIC LEDs
    	const struct device *led_dev = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_leds));
    	if (!device_is_ready(led_dev))
    	{
    		printk("LED device not ready\n");
    		return -1;
    	}
    
    	// Turn off LED 0 initially
    	led_off(led_dev, 0);
    
    	while (1)
    	{
    		// Update fuel gauge metrics
    		// fuel_gauge_update(charger, vbus_connected);
    		
    		// // Enable regulators
    		printk("buck, ldo1, ldo2 = on\n");
    
    		err = regulator_enable(buck2);
    		if (err < 0)
    		{
    			printk("Error: Could not enable buck2\n");
    			return err;
    		}
    		k_msleep(50);
    
    		err = regulator_enable(ldo1);
    		if (err < 0)
    		{
    			printk("Error: Could not enable ldo1\n");
    			return err;
    		}
    		k_msleep(50);
    
    		err = regulator_enable(ldo2);
    		if (err < 0)
    		{
    			printk("Error: Could not enable ldo2\n");
    			return err;
    		}
    		k_msleep(50);
    
    		k_msleep(SLEEP_TIME_MS);
    
    		// // Disable regulators (repeat to ensure successful disablement)
    		printk("buck, ldo1, ldo2 = off\n");
    
    		for (int i = 0; i < 5; i++)
    		{
    			err = regulator_disable(buck2);
    			if (err < 0)
    			{
    				printk("Error: Could not disable buck2\n");
    				return err;
    			}
    			k_msleep(50);
    
    			err = regulator_disable(ldo1);
    			if (err < 0)
    			{
    				printk("Error: Could not disable ldo1\n");
    				return err;
    			}
    			k_msleep(50);
    
    			err = regulator_disable(ldo2);
    			if (err < 0)
    			{
    				printk("Error: Could not disable ldo2\n");
    				return err;
    			}
    			k_msleep(50);
    		}
    
    		k_msleep(SLEEP_TIME_MS);
    	}
    
    	return 0;
    }


    overlay

    #include <dt-bindings/regulator/npm1300.h>
    #include <zephyr/dt-bindings/input/input-event-codes.h>
    #define NPM1300_BUCK_MODE_PFM 0x04U
    
    &arduino_i2c {
        npm1300_ek_pmic: pmic@6b {
            compatible = "nordic,npm1300";
            reg = <0x6b>;
    
            npm1300_ek_gpio: gpio-controller {
                compatible = "nordic,npm1300-gpio";
                gpio-controller;
                #gpio-cells = <2>;
                ngpios = <5>;
            };
    
            npm1300_ek_regulators: regulators {
                compatible = "nordic,npm1300-regulator";
    
                npm1300_ek_buck1: BUCK1 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    // regulator-always-on; // Optional: Keeps BUCK1 on
                };
    
                npm1300_ek_buck2: BUCK2 {
                    regulator-min-microvolt = <1000000>;
                    regulator-max-microvolt = <3300000>;
                    regulator-init-microvolt = <3300000>;
                    // regulator-always-on; // Optional: Keeps BUCK2 on
                    /delete-property/ enable-gpios;
                    /delete-property/ retention-gpios;
                    /delete-property/ pwm-gpios;
                };
    
                npm1300_ek_ldo1: LDO1 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
                    /delete-property/ enable-gpios;
                };
    
                npm1300_ek_ldo2: LDO2 {
                    regulator-min-microvolt = <1800000>;
                    regulator-max-microvolt = <1800000>;
                    regulator-init-microvolt = <1800000>;
                    regulator-initial-mode = <NPM1300_LDSW_MODE_LDSW>;
                    /delete-property/ enable-gpios
                };
            };
    
        npm1300_ek_charger: charger {
            compatible = "nordic,npm1300-charger";
            // Corrected charging parameters
            term-microvolt = <4100000>;          // 4.2V - Standard Li-ion termination
            term-warm-microvolt = <4000000>;     // 4.1V - Slightly lower for warm conditions
            current-microamp = <500000>;         // 500mA - Reasonable charging current
            dischg-limit-microamp = <1000000>;
            vbus-limit-microamp = <1000000>;     // 1A USB input limit
            thermistor-ohms = <10000>;
            thermistor-beta = <3380>;
            charging-enable;
        };
    
            npm1300_ek_buttons: buttons {
                status = "disabled";
                compatible = "gpio-keys";
                pmic_button0: pmic_button_0 {
                    status = "disabled";
                    gpios = <&npm1300_ek_gpio 0 GPIO_ACTIVE_HIGH>;
                    label = "Pmic button switch 0";
                    zephyr,code = <INPUT_KEY_0>;
                };
            };
    
            npm1300_ek_leds: leds {
                compatible = "nordic,npm1300-led";
                nordic,led0-mode = "charging";
                nordic,led1-mode = "host";
                nordic,led2-mode = "host";
            };
        };
    };


    my also question is

    1. Adding active-discharge to the devicetree overlay

    npm1300_ek_buck1: BUCK1 { regulator-min-microvolt = <1800000>; regulator-max-microvolt = <1800000>; regulator-init-microvolt = <1800000>; active-discharge; };

    Result: Build error in NCS 2.9.0:

    'active-discharge' appears in BUCK1 but is not declared in 'properties:' in nordic,npm1300-regulator.yaml

    The property is not supported in the NCS 2.9.0 binding for nordic,npm1300-regulator.


    2. Using the Zephyr Regulator API at runtime

    regulator_set_active_discharge(buck1, true); regulator_set_active_discharge(buck2, true); regulator_set_active_discharge(ldo1, true); regulator_set_active_discharge(ldo2, true);

    Result: All four calls return -88 (-ENOSYS), meaning the set_active_discharge driver op is not implemented in the nPM1300 regulator driver in NCS 2.9.0. [Regulator API]


    this 2 is help us to solve issue

    and this is not working in sdk 2.9.0 and also explain what is alternative of this?

    best regards

    Milan

Children
No Data
Related