Modifying the nPM1300 one button example

Hi.

I want to modify the "nPM1300 One Button" example.

I need the Ship mode to be activated after pressing and holding the SHPHLD button for longer than 3 seconds. The Ship mode should activate before I release the SHPHLD button.

I plan to implement this function using the nRF52 timer, but for some reason the function regulator_parent_ship_mode() is not executed inside the timer function (timer0_handler).

#include <zephyr/drivers/mfd/npm1300.h>
#include <zephyr/drivers/regulator.h>

static const struct device *pmic = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_pmic));
static const struct device *regulators = DEVICE_DT_GET(DT_NODELABEL(npm1300_ek_regulators));

static int press_t;

static void timer0_handler(struct k_timer *dummy)
{
    /*Interrupt Context - System Timer ISR */
	press_t = k_uptime_get() - press_t;
	LOG_INF("timer0_handler function started. Press_time = %d", press_t);
	if (vbus_connected) {
		LOG_INF("Ship mode entry not possible with USB connected\n");
		} else {
			LOG_INF("SHIP MODE");
			regulator_parent_ship_mode(regulators);
		}
}

K_TIMER_DEFINE(timer0, timer0_handler, NULL);

static void event_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
{
	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_PRESS)) {
		LOG_INF("SHPHLD press");
		press_t = k_uptime_get();
		/* start timer */
		k_timer_start(&timer0, K_MSEC(3000), K_NO_WAIT);
	}

	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_RELEASE)) {
		LOG_INF("SHPHLD release");
		/* stop timer */
		k_timer_stop(&timer0);
	}

	if (pins & BIT(NPM1300_EVENT_VBUS_DETECTED)) {
		LOG_INF("Vbus connected\n");
		vbus_connected = true;
	}

	if (pins & BIT(NPM1300_EVENT_VBUS_REMOVED)) {
		LOG_INF("Vbus removed\n");
		vbus_connected = false;
	}
}

bool configure_events(void) ...

int main(void)
{
	LOG_INF("PMIC device ok");

	while (1) {
		led_on(leds, 2U);
		k_msleep(1000);
		led_off(leds, 2U);
		k_msleep(1000);
		fuel_gauge_update(charger);
	}
}

The result of the program is on the screenshot -->

As you can see, the program executes the code inside the function timer0_handler, but for some reason it does not switch to the Ship mode and continues to execute the code in the main function.

Please tell me why this is happening and where I am making a mistake?

Thank you.

Parents
  • Hi!

    1) Do you see the same with the default, unmodified sample?

    2) Can you check the return code of regulator_parent_ship_mode() ?

  • Hi Sigurd!

    1. In the default example (when the function regulator_parent_ship_mode() is inside event_callback()) everything works fine. 

    2. The return code is -5. But I don't know what it means.

    static void timer0_handler(struct k_timer *dummy)
    {
    	int ret;
        /*Interrupt Context - System Timer ISR */
    	press_t = k_uptime_get() - press_t;
    	LOG_INF("timer0_handler function started. Press_time = %d", press_t);
    	if (vbus_connected) {
    		LOG_INF("Ship mode entry not possible with USB connected\n");
    		} else {
    			LOG_INF("SHIP MODE");
    			ret = regulator_parent_ship_mode(regulators);
    			LOG_INF("ret = %d", ret);
    		}
    }

    Screen -->

    I'm hoping for your help.
    Thank you.

  • I don't think you can do this inside an ISR as it requires TWI comms.
    You will have to set a flag and poll it in the background task, or setup a worker thread.

  • Hi Andy.

    I don’t know what the reason is, but I also can’t enter ship mode from the work queue.

    #define WORKQ_THREAD_STACK_SIZE   1024
    #define WORKQ_PRIORITY             5
    
    K_THREAD_STACK_DEFINE(ship_mode_stack_area, WORKQ_THREAD_STACK_SIZE);
    
    struct k_work_q ship_mode_work_q = {0};
    
    static void ship_mode_work_cb (struct k_work *work){
    	/* Enter to Ship mode*/
    	LOG_INF("Enter to SHIP MODE");
    	regulator_parent_ship_mode(regulators);
    }
    
    K_WORK_DEFINE(ship_mode_work, ship_mode_work_cb);
    
    static void timer0_handler(struct k_timer *dummy)
    {
    	int ret;
        /*Interrupt Context - System Timer ISR */
    	press_t = k_uptime_get() - press_t;
    	LOG_INF("timer0_handler function started. Press_time = %d", press_t);
    	if (vbus_connected) {
    		LOG_INF("Ship mode entry not possible with USB connected\n");
    		} else {
    			k_work_submit(&ship_mode_work);
    		}
    }
    
    K_TIMER_DEFINE(timer0, timer0_handler, NULL);
    
    static void event_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
    	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_PRESS)) {
    		LOG_INF("SHPHLD press");
    		press_t = k_uptime_get();
    		/* start timer */
    		k_timer_start(&timer0, K_MSEC(3000), K_NO_WAIT);
    	}
    
    	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_RELEASE)) {
    		LOG_INF("SHPHLD release");
    		/* stop timer */
    		k_timer_stop(&timer0);
    	}
    
    	if (pins & BIT(NPM1300_EVENT_VBUS_DETECTED)) {
    		LOG_INF("Vbus connected\n");
    		vbus_connected = true;
    	}
    
    	if (pins & BIT(NPM1300_EVENT_VBUS_REMOVED)) {
    		LOG_INF("Vbus removed\n");
    		vbus_connected = false;
    	}
    }
    
    bool configure_events(void)...
    
    int main(void)
    {
        k_work_queue_init(&ship_mode_work_q);
        
        k_work_queue_start(&ship_mode_work_q, ship_mode_stack_area,
                        K_THREAD_STACK_SIZEOF(ship_mode_stack_area), WORKQ_PRIORITY, NULL);
    
    	LOG_INF("PMIC device ok");
    
    while (1) {
    		led_on(leds, 2U);
    		k_msleep(1000);
    		led_off(leds, 2U);
    		k_msleep(1000);
    		fuel_gauge_update(charger);
    	}
    }

    Here's the output on the terminal -->

    Perhaps the program enters ship mode, but immediately exits it, because the SHPHLD Press event is triggered (although I did not release the SHPHLD button).

    Logic level screen -->

    I don't know if it's even possible to implement a function to enter ship mode and still keep the SHPHLD button pressed.

Reply
  • Hi Andy.

    I don’t know what the reason is, but I also can’t enter ship mode from the work queue.

    #define WORKQ_THREAD_STACK_SIZE   1024
    #define WORKQ_PRIORITY             5
    
    K_THREAD_STACK_DEFINE(ship_mode_stack_area, WORKQ_THREAD_STACK_SIZE);
    
    struct k_work_q ship_mode_work_q = {0};
    
    static void ship_mode_work_cb (struct k_work *work){
    	/* Enter to Ship mode*/
    	LOG_INF("Enter to SHIP MODE");
    	regulator_parent_ship_mode(regulators);
    }
    
    K_WORK_DEFINE(ship_mode_work, ship_mode_work_cb);
    
    static void timer0_handler(struct k_timer *dummy)
    {
    	int ret;
        /*Interrupt Context - System Timer ISR */
    	press_t = k_uptime_get() - press_t;
    	LOG_INF("timer0_handler function started. Press_time = %d", press_t);
    	if (vbus_connected) {
    		LOG_INF("Ship mode entry not possible with USB connected\n");
    		} else {
    			k_work_submit(&ship_mode_work);
    		}
    }
    
    K_TIMER_DEFINE(timer0, timer0_handler, NULL);
    
    static void event_callback(const struct device *dev, struct gpio_callback *cb, uint32_t pins)
    {
    	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_PRESS)) {
    		LOG_INF("SHPHLD press");
    		press_t = k_uptime_get();
    		/* start timer */
    		k_timer_start(&timer0, K_MSEC(3000), K_NO_WAIT);
    	}
    
    	if (pins & BIT(NPM1300_EVENT_SHIPHOLD_RELEASE)) {
    		LOG_INF("SHPHLD release");
    		/* stop timer */
    		k_timer_stop(&timer0);
    	}
    
    	if (pins & BIT(NPM1300_EVENT_VBUS_DETECTED)) {
    		LOG_INF("Vbus connected\n");
    		vbus_connected = true;
    	}
    
    	if (pins & BIT(NPM1300_EVENT_VBUS_REMOVED)) {
    		LOG_INF("Vbus removed\n");
    		vbus_connected = false;
    	}
    }
    
    bool configure_events(void)...
    
    int main(void)
    {
        k_work_queue_init(&ship_mode_work_q);
        
        k_work_queue_start(&ship_mode_work_q, ship_mode_stack_area,
                        K_THREAD_STACK_SIZEOF(ship_mode_stack_area), WORKQ_PRIORITY, NULL);
    
    	LOG_INF("PMIC device ok");
    
    while (1) {
    		led_on(leds, 2U);
    		k_msleep(1000);
    		led_off(leds, 2U);
    		k_msleep(1000);
    		fuel_gauge_update(charger);
    	}
    }

    Here's the output on the terminal -->

    Perhaps the program enters ship mode, but immediately exits it, because the SHPHLD Press event is triggered (although I did not release the SHPHLD button).

    Logic level screen -->

    I don't know if it's even possible to implement a function to enter ship mode and still keep the SHPHLD button pressed.

Children
Related