This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

PORT event interupt while sensed pin is active

Hello!

I am using the PORT event interupt sense handler to wake up the device from various pin interupts. We have in total 6 pins that need to do that.

This works fine, except for when a current pin generated an event that stays in this detected state for a while. For example, see these scope images:

The green line is a 1 hz signal from an external RTC. This sometimes needs to wakeup the device once a second (hence the interupt sense method choosen is HI to LO).

The yellow line is an interupt that needs to wakeup the device as well, but needs only to trigger an interupt when something is near (IR detection).

The problem i am facing is that during the RTC interupt from HI to LO, this IR detection interupt gets ignored, because the PORT sense event only can generate an interupt if the current pin that generated the interupt goes back to the non triggered state (AFAIK and is during debugging very apparant).

We also have a pin that is pulled LO and stays low as long as a certain cable is connected to our device, which needs to prevent the device to sleep during this event. In this case, ALL interupts from the other PORT event pins get ingnored for the set interupt event.

I tried the IN EVENT mode. That works fine for what we need, but uses way too much current during the sleep period of the device.

I tried to switch from the PORT event to the IN EVENT during wake times, but thats not ideal and gave me errors during switching.

Is there a way I can "reset" the current pin state, that generated the interupt in the PORT event, so that I can receive other interupts?

It is very important that we always have every 6 of these pins generate the interupt and that we know what pin did it.

(part of) my code:

void PIN_WAKE_ON_FTDI_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) // FTDI connect
{	if(pin == INTERFACE_CABLE_DETECT_PIN)
	{	PM_WakedBy |= WAKE_ON_FTDI;
	}
}

void PIN_WAKE_ON_CARDDT_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) //EM = Toetsen of IR
{	if(pin == EM_IRQ_PIN)
	{	PM_WakedBy |= WAKE_ON_CARDDT;
	}
}

void PIN_WAKE_ON_RTC_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) // WAKE_ON_RTC
{	if(pin == RTC_PCF2123_CLKOUT_PIN)
	{	PM_WakedBy |= WAKE_ON_RTC;
	}
}


void PM_Init(void)
{	ret_code_t err_code;
	nrfx_gpiote_in_config_t nrfx_gpiote_in_config;
	err_code = nrfx_gpiote_init(); // init de GPIOTE module
	APP_ERROR_CHECK(err_code);

	nrfx_gpiote_in_config.hi_accuracy = false; // Set hi_accu to false for PORT event
	
	// WAKE_ON_FTDI this is a pin that stays low during placement of the cable and needs to prevent the device from sleep
	nrfx_gpiote_in_uninit(INTERFACE_CABLE_DETECT_PIN);
	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)INTERFACE_CABLE_DETECT_PIN_PULL_CFG;
	err_code = nrfx_gpiote_in_init(INTERFACE_CABLE_DETECT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_FTDI_IRQHandler);  
	APP_ERROR_CHECK(err_code);
	nrfx_gpiote_in_event_enable(INTERFACE_CABLE_DETECT_PIN, true);
	
	// WAKE_ON_CARDDT this is a pin that needs to detect a near detection at all times
	nrfx_gpiote_in_uninit(EM_IRQ_PIN);
	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)EM_IRQ_PIN_PULL_CFG;
	err_code = nrfx_gpiote_in_init(EM_IRQ_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_CARDDT_IRQHandler);
	APP_ERROR_CHECK(err_code);
	nrfx_gpiote_in_event_enable(EM_IRQ_PIN, true);	
	
	// WAKE_ON_RTC this is a 1 hz interupt pin that sometimes needs to wake the device every second for a few seconds
	nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN);
	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
	err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
	APP_ERROR_CHECK(err_code);
	nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, true);
}

	

Parents
  • Hi,

    You cannot get multiple port events (interrupts) unless the firs pin(s) is deasserted before the next is asserted. The reason is that the common DETECT signal, which generates the event is a simple logical OR of each pins detect signal (PINx.DETECT). You can see this from Figure 2. DETECT signal behavior.

    The only other option I can think of is to poll the LATCH register to see if more pins have been asserted. From GPIO chapter in PS:

    The CPU can read the LATCH register at any time to check if a SENSE condition has been met on one or more of the the GPIO pins even if that condition is no longer met at the time the CPU queries the LATCH register. This mechanism will work even if the LDETECT signal is not used as the DETECT signal.

  • Thank you.

    Polling the LATCH register is not realy an option.

    I tried however to use the TOGGLE sense option for the 1 hz pin and the cable detect pin. This seems to work a bit, as the other interupt pins can be handled now while a toggled sense pin is HI or LO. This seems to indicate that it should be possible to sort of "reset" the PORT event, cause using TOGGLE seems to reset the triggered state of these pins.

    I cant however find what the TOGGLE mode does that makes the pin not blocking the other interupts while it is in the state when it generated the interupt...

  • Ah, yes. In any case what you are trying to do is not really supported by the HW. You will not be able to get reliable low power interrupts for specific pins.

  • I think the only reliable method would be to switch to high accuracy mode (IN_EVENT) when waking up from any PORT event to get interupts from any pin.

    and then going back to PORT mode just before going back to sleep, am I correct? Or is this not possible?

  • You are right. I was under the impression that you did not want to do that, but it is how it is normally done. If you require interrupts for each pin and this could occur on more pins simultaneously, then switching to pin events is the only way. You can always switch back to port event afterwards.

  • Its not ideal and I couldnt get it to work reliably (I got some errors during debugging from switching between PORT and IN_EVENT mode). But I will focus on that now I guess, cause toggling and waking on every level change is not very much ideal either. Thanks for your time!

  • Its been a few days of struggling, but I can not make it work as I want to and about to loose my mind on this issue... I want to configure the pins for a PORT sense event just before sleeping and once the chip wakes up because of a PORT event, I want to switch over to the IN_EVENT on the same pins. But whatever I try to do, switching the sense mechanism of these pins, triggers the interupts for these pins. What am I doing wrong?

    Below a (simplified) example of what I am currently stranded on:

    #define RTC_PCF2123_CLKOUT_PIN 11
    #define RTC_PCF2123_CLKOUT_PIN_PULL_CFG 0
    
    
    void PIN_WAKE_ON_RTC_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) // WAKE_ON_RTC
    {	if(pin == RTC_PCF2123_CLKOUT_PIN)
    	{	BuzzerTimed(BUZZER_TONE_OK,10); // make a beep sound for testing IRQ
    	}
    }
    
    void power_management(void)
    {	ret_code_t err_code;
    	nrfx_gpiote_in_config_t nrfx_gpiote_in_config;
    	nrfx_gpiote_in_config.is_watcher = false; // True when the input pin is tracking an output pin.
    	
    	nrfx_gpiote_in_config.hi_accuracy = false; // Set hi_accu to false for PORT event
    	nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN); // uninit this pin, else we get error
    	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    	err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    	APP_ERROR_CHECK(err_code);	
    	nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz PORT event
    	
    	// going to sleep
    	
    	nrf_pwr_mgmt_run(); // Sleeping
    	
    	// woken up due to PORT event
    	
    	nrfx_gpiote_in_config.hi_accuracy = true; // Set hi_accu to true for IN_EVENT event
    	nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN);
    	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    	err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    	APP_ERROR_CHECK(err_code);	
    	nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz IN_EVENT
    }

    Please help me

Reply
  • Its been a few days of struggling, but I can not make it work as I want to and about to loose my mind on this issue... I want to configure the pins for a PORT sense event just before sleeping and once the chip wakes up because of a PORT event, I want to switch over to the IN_EVENT on the same pins. But whatever I try to do, switching the sense mechanism of these pins, triggers the interupts for these pins. What am I doing wrong?

    Below a (simplified) example of what I am currently stranded on:

    #define RTC_PCF2123_CLKOUT_PIN 11
    #define RTC_PCF2123_CLKOUT_PIN_PULL_CFG 0
    
    
    void PIN_WAKE_ON_RTC_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) // WAKE_ON_RTC
    {	if(pin == RTC_PCF2123_CLKOUT_PIN)
    	{	BuzzerTimed(BUZZER_TONE_OK,10); // make a beep sound for testing IRQ
    	}
    }
    
    void power_management(void)
    {	ret_code_t err_code;
    	nrfx_gpiote_in_config_t nrfx_gpiote_in_config;
    	nrfx_gpiote_in_config.is_watcher = false; // True when the input pin is tracking an output pin.
    	
    	nrfx_gpiote_in_config.hi_accuracy = false; // Set hi_accu to false for PORT event
    	nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN); // uninit this pin, else we get error
    	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    	err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    	APP_ERROR_CHECK(err_code);	
    	nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz PORT event
    	
    	// going to sleep
    	
    	nrf_pwr_mgmt_run(); // Sleeping
    	
    	// woken up due to PORT event
    	
    	nrfx_gpiote_in_config.hi_accuracy = true; // Set hi_accu to true for IN_EVENT event
    	nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN);
    	nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    	nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    	err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    	APP_ERROR_CHECK(err_code);	
    	nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz IN_EVENT
    }

    Please help me

Children
  • Hi,

    It seems like this quote from the GPIOTE chapter in the Product Specification is relevant for you:

    In order to prevent spurious interrupts from the PORT event while configuring the sources, the user shall first disable interrupts on the PORT event (through INTENCLR.PORT), then configure the sources (PIN_CNF[n].SENSE), clear any potential event that could have occurred during configuration (write '1' to EVENTS_PORT), and finally enable interrupts (through INTENSET.PORT).

    However, that should be covered by your call to nrfx_gpiote_in_uninit(). Do you have multiple pins configured, or only one? Do you see this issue if you only use one GPIO pin? Can you upload code that reproduces this behaviour on a DK?

  • At the moment I am testing with this one pin with the above code. I can try to make an example code for DK, but that needs to receive a 1hz signal with 50/50 duty cycle on a pin, to represent the wanted behaviour on our PCB. I dont know if you can supply that to test?

    I will try it for myself anyways to test if its the same behaviour on the DK.

  • Hi,

    If this happens more or less instantaneous it should probably be possible to reproduce the same behavior using one of the buttons instead? (It would not be a nice 1 Hz signal, but I would not expect that to be significant). If not, getting a 1 Hz signal for testing should not be a problem anyway.

  • I tried with the DK now, same behaviour. I used pin P0.11 for the input of the function generator (1hz, 50/50 duty cycle). I used the example \nRF5_SDK_15.2.0_9412b96\examples\ble_peripheral\ble_app_uart\pca10040\s132\arm5_no_packs and replaced the idle_state_handle() function with the below code:

    /**@brief Function for handling the idle state (main loop).
     *
     * @details If there is no pending log operation, then sleep until next the next event occurs.
     */
    #include <nrfx_gpiote.h>
    #define RTC_PCF2123_CLKOUT_PIN 11
    #define RTC_PCF2123_CLKOUT_PIN_PULL_CFG 0
    void PIN_WAKE_ON_RTC_IRQHandler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) // WAKE_ON_RTC
    {	if(pin == RTC_PCF2123_CLKOUT_PIN)
    	{	bsp_board_led_invert(BSP_BOARD_LED_3);
    	}
    }
    static void idle_state_handle(void)
    {    
    		ret_code_t err_code;
    		nrfx_gpiote_in_config_t nrfx_gpiote_in_config;
    		nrfx_gpiote_in_config.is_watcher = false; // True when the input pin is tracking an output pin.
    		
    		nrfx_gpiote_in_config.hi_accuracy = false; // Set hi_accu to false for PORT event
    		nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN); // uninit this pin, else we get error
    		nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    		nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    		err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    		APP_ERROR_CHECK(err_code);	
    		nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz PORT event    
    		UNUSED_RETURN_VALUE(NRF_LOG_PROCESS());
    	
    		nrf_pwr_mgmt_run();
    	
    		nrfx_gpiote_in_config.hi_accuracy = true; // Set hi_accu to true for IN_EVENT event
    		nrfx_gpiote_in_uninit(RTC_PCF2123_CLKOUT_PIN);
    		nrfx_gpiote_in_config.sense = NRF_GPIOTE_POLARITY_HITOLO;
    		nrfx_gpiote_in_config.pull = (nrf_gpio_pin_pull_t)RTC_PCF2123_CLKOUT_PIN_PULL_CFG;
    		err_code = nrfx_gpiote_in_init(RTC_PCF2123_CLKOUT_PIN, &nrfx_gpiote_in_config, PIN_WAKE_ON_RTC_IRQHandler);
    		APP_ERROR_CHECK(err_code);	
    		nrfx_gpiote_in_event_enable(RTC_PCF2123_CLKOUT_PIN, false);	// enable het 1 hz IN_EVENT	
    }

    Also changed the GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS - Number of lower power input pins in SDK config to 5 (from 4).

  • Perfect. Can you upload the full project here so that we can test it directly?

Related