Help with SHIPHOLD Pressed and Released Events on NPM1300 + STM32L4 + npmx

Hi All, 

I'm currently working with a custom board using the NPM1300 and STM32L4, alongside the npmx drivers. I'm trying to capture both pressed and released events from the SHIPHOLD button, but I'm running into an issue.

If only one of the events is enabled, all works as expected:

  • The NPM1300 drives its interrupt GPIO high.
  • This triggers an interrupt on the STM32L4 (rising edge).
  • In the ISR, I call npmx_core_interrupt(&m_pmic);
  • Then in the main loop, I call npmx_core_proc(&m_pmic);
  • This successfully clears the NPM1300 interrupt and invokes the appropriate callback.

However, when both events are enabled simultaneously:

pmx_core_event_interrupt_enable(&m_pmic, NPMX_EVENT_GROUP_SHIPHOLD, 
                                 NPMX_EVENT_GROUP_SHIPHOLD_PRESSED_MASK | 
                                 NPMX_EVENT_GROUP_SHIPHOLD_RELEASED_MASK);

The first button press works correctly: the interrupt pin goes high, npmx_core_interrupt() is called, followed by npmx_core_proc(), and the callback is triggered as expected.

But after that, the NPM1300 interrupt pin remains high, preventing further interrupts from being registered on the STM32 side (interrupt on rising edge). It seems like the interrupt flag on the PMIC isn't being cleared properly after the first event when both are enabled.

As I understand it, npmx_core_proc() should clear all the pending interrupt flags and report back the mask— is that correct?

I’ve reviewed the one-button example, but it uses gpio_init_callback() instead of the interrupt-handling functions from npmx_core.c, so it’s hard to compare directly.

For reference, here’s my callback and initialization code:


static void button_callback(npmx_instance_t *p_pm, npmx_callback_type_t type, uint8_t mask)
{
    // Toggle LED
    HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin);
}

void configure_pmic()
{
	if (npmx_core_init(&m_pmic, &backend, NULL, false) != NPMX_SUCCESS) {
		// Initialization failed
		while (1) {
			HAL_GPIO_TogglePin(LED_R_GPIO_Port, LED_R_Pin);
			HAL_Delay(200);
		}
	}

	// Ship hold configuration
	npmx_ship_config_t ship_config = {
		.time = NPMX_SHIP_TIME_3008_MS, /* SHPHLD must be held low for 3008 ms to exit from the ship or hibernate mode. */
		.inverted_polarity = false /* Button is active in the LOW state. */
	};

	// Get the ship hold instance
	m_ship_inst = npmx_ship_get(&m_pmic, 0);

	// Set the configuration
	npmx_ship_config_set(m_ship_inst, &ship_config);

	// Register button_callback to NPMX_CALLBACK_TYPE_EVENT_SHIPHOLD event
	npmx_core_register_cb(&m_pmic, button_callback, NPMX_CALLBACK_TYPE_EVENT_SHIPHOLD);

	// Inti PMIC GPIO01 as an interrupt output pin
	m_gpio_init = npmx_gpio_get(&m_pmic, 1);
	npmx_gpio_mode_set(m_gpio_init, NPMX_GPIO_MODE_OUTPUT_IRQ);


	//npmx_core_event_interrupt_enable(&pmic, NPMX_EVENT_GROUP_SHIPHOLD, ((1<<NPMX_EVENT_GROUP_SHIPHOLD_PRESSED_MASK) | (1<<NPMX_EVENT_GROUP_SHIPHOLD_RELEASED_MASK)));
	// If only pressed or release set works as expected
	npmx_core_event_interrupt_enable(&m_pmic, NPMX_EVENT_GROUP_SHIPHOLD, NPMX_EVENT_GROUP_SHIPHOLD_PRESSED_MASK);
	npmx_core_event_interrupt_enable(&m_pmic, NPMX_EVENT_GROUP_SHIPHOLD, NPMX_EVENT_GROUP_SHIPHOLD_RELEASED_MASK);
}

// Called form the STM32 ISR
void pmic_post_int()
{
	npmx_core_interrupt(&m_pmic);
}

int main(void) {
  configure_pmic();
  
  while (1) {
	  npmx_core_proc(&m_pmic);
	  ...
	  }
}


Any insights, suggestions, or examples on how to handle both SHIPHOLD events correctly would be greatly appreciated.

Many thanks for considering my request.

Parents
  • Hi again,

    I got some feedback.

    pmx_core_event_interrupt_enable(&m_pmic, NPMX_EVENT_GROUP_SHIPHOLD, 
                                    NPMX_EVENT_GROUP_SHIPHOLD_PRESSED_MASK | 
                                    NPMX_EVENT_GROUP_SHIPHOLD_RELEASED_MASK);

    This is the correct way of enabling the interrupt. Call this function once per event group. The masks should be OR'ed together to enable the interrupts you want within that group. 

    If you call this function multiple times in a row with the same event group, the new event mask will overwrite the old one in the driver state logic, but the driver will not disable this event from being generated by the PMIC. So you can get into situations such as the one described. 

    As I understand it, npmx_core_proc() should clear all the pending interrupt flags and report back the mask— is that correct?

    This is correct. As long as npmx is informed that the interrupt signal pin is asserted via npmx_core_interrupt(), which seems to be the case in this code.

    Could you try calling npmx_core_interrupt(&m_pmic) for every iteration of the main loop? This will force npmx to keep checking the event registers.

    Kenneth

Reply
  • Hi again,

    I got some feedback.

    pmx_core_event_interrupt_enable(&m_pmic, NPMX_EVENT_GROUP_SHIPHOLD, 
                                    NPMX_EVENT_GROUP_SHIPHOLD_PRESSED_MASK | 
                                    NPMX_EVENT_GROUP_SHIPHOLD_RELEASED_MASK);

    This is the correct way of enabling the interrupt. Call this function once per event group. The masks should be OR'ed together to enable the interrupts you want within that group. 

    If you call this function multiple times in a row with the same event group, the new event mask will overwrite the old one in the driver state logic, but the driver will not disable this event from being generated by the PMIC. So you can get into situations such as the one described. 

    As I understand it, npmx_core_proc() should clear all the pending interrupt flags and report back the mask— is that correct?

    This is correct. As long as npmx is informed that the interrupt signal pin is asserted via npmx_core_interrupt(), which seems to be the case in this code.

    Could you try calling npmx_core_interrupt(&m_pmic) for every iteration of the main loop? This will force npmx to keep checking the event registers.

    Kenneth

Children
No Data
Related