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...

  • 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?

Reply Children
  • I finaly got it working...

    Seems calling nrfx_gpiote_in_event_enable always seem to trigger the PORT event, even when it was already handled before.

    I fixed it by using NRFX_IRQ_DISABLE(GPIOTE_IRQn); before unit the pin and calling nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);  after enabling the event. closing with NRFX_IRQ_ENABLE(GPIOTE_IRQn); // enable the GPIOTE IRQs

    		nrfx_gpiote_in_config.hi_accuracy = false; // Set hi_accu to false for PORT event
    		NRFX_IRQ_DISABLE(GPIOTE_IRQn); // disable the GPIOTE IRQs
    		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   
    		nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT); // clear the spontanious interrupt that was triggered from calling nrfx_gpiote_in_event_enable()
    		NRFX_IRQ_ENABLE(GPIOTE_IRQn); // enable the GPIOTE IRQs		

    So basicly your answer from above, but using the library instead of directly writing to registers.

Related