Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

GPIOET interrupt and PPI in S110

Hi,

I want to measure the time of two signals to calculate the speed and sent the data with BLE.  I find the SD effect the GPIOTE_interrupt sometimes, when I try to use GPIOTE and timer to calcluate the time . So I use the PPI function, connect the NRF_GPIOTE->EVENTS_IN[ ] to the NRF_TIMER2->TASKS.  But the program can not boot up with PPI and  GPIOTE_interrupt and SD.  I debugged the program. Looks it go to the "System Reset".   

If I use PPI and GPIOTE interrupt without BLE SD, it works well. I can measure the time accurately.   If I use PPI with SD and disable the interrupt, it works well. If I use the GPIOTE interrupt with SD and disable the PPI, it works well too.  

void time1_init(void)  
{

    NRF_TIMER2->MODE        = TIMER_MODE_MODE_Timer;	
    NRF_TIMER2->PRESCALER   = 4;  
    NRF_TIMER2->CC[2]       = (50000U);  
    NRF_TIMER2->INTENSET    = TIMER_INTENSET_COMPARE2_Enabled << TIMER_INTENSET_COMPARE2_Pos;		
    NRF_TIMER2->SHORTS      = (TIMER_SHORTS_COMPARE2_CLEAR_Enabled << TIMER_SHORTS_COMPARE2_CLEAR_Pos);
		NVIC_ClearPendingIRQ(TIMER2_IRQn);			
    NVIC_SetPriority(TIMER2_IRQn,3);				
		NVIC_EnableIRQ(TIMER2_IRQn);  					
	//  NRF_TIMER2->TASKS_START = 1; 
}

 void ppi_init(void)
{
    // Configure PPI channel 0 to start Timer 2 
    NRF_PPI->CH[0].EEP = (uint32_t)(&NRF_GPIOTE->EVENTS_IN[0]);
		NRF_PPI->CH[0].TEP = (uint32_t)(&NRF_TIMER2->TASKS_START);

    // Configure PPI channel 1 to capture Timer2
    NRF_PPI->CH[1].EEP = (uint32_t)(&NRF_GPIOTE->EVENTS_IN[1]);
    NRF_PPI->CH[1].TEP = (uint32_t)(&NRF_TIMER2->TASKS_CAPTURE[0]);

    // Enable only PPI channels 0 and 1.
    NRF_PPI->CHEN = (PPI_CHEN_CH0_Enabled << PPI_CHEN_CH0_Pos) | (PPI_CHEN_CH1_Enabled << PPI_CHEN_CH1_Pos);
}

void EXIT_KEYS_Init(void)
{

		nrf_gpio_cfg_input(S1,GPIO_PIN_CNF_PULL_Pullup);
		nrf_gpio_cfg_input(S2,GPIO_PIN_CNF_PULL_Pullup);
//		NVIC_SetPriority(GPIOTE_IRQn,1);

	
    NRF_GPIOTE->CONFIG[0] =  (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)	
                           | (S1 << GPIOTE_CONFIG_PSEL_Pos)  																
                           | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);					
		NRF_GPIOTE->CONFIG[1] =  (GPIOTE_CONFIG_POLARITY_HiToLo << GPIOTE_CONFIG_POLARITY_Pos)
                           | (S2 << GPIOTE_CONFIG_PSEL_Pos)  
                           | (GPIOTE_CONFIG_MODE_Event << GPIOTE_CONFIG_MODE_Pos);

         NVIC_EnableIRQ(GPIOTE_IRQn);   //must disable GPIOTE interrupt or PPI
		NRF_GPIOTE->INTENSET  = GPIOTE_INTENSET_IN0_Set << GPIOTE_INTENSET_IN0_Pos;
		NRF_GPIOTE->INTENSET  = GPIOTE_INTENSET_IN1_Set << GPIOTE_INTENSET_IN1_Pos;
}

int main(void)
{
	
	uint16_t speeds;

	time1_init(); 
	EXIT_KEYS_Init(); 
	ppi_init();
    // Initialize
    leds_init();
    timers_init();
    buttons_init();
    uart_init();
	
    ble_stack_init();
    gap_params_init();
    services_init();
    advertising_init();
    conn_params_init();
    sec_params_init();
    
    simple_uart_putstring(START_STRING);	
    
    advertising_start();
	  LED_Init();
		capture_state=1;

    for (;;)
    {........}
}

I use the example  S110 \experimental\ble_app_uart. 

SofeDevices: S110  6.0.0

Board: PCA10001

IC: nRF51822 xxaa

Any idea about it? 

Parents
  • As Turbo said, you have to use the API's to assign and enable/disable PPI channels.  The SD uses PPI and thus will write over your settings.  You can set gpiote directly through the register if you wish.

    These are some of the API's.  You would find them all listed in the SD reference docs.

     sd_ppi_channel_assign
     sd_ppi_channel_enable_set
           

    You will find the PPI reserved channels on page 169 of the product spec.

Reply
  • As Turbo said, you have to use the API's to assign and enable/disable PPI channels.  The SD uses PPI and thus will write over your settings.  You can set gpiote directly through the register if you wish.

    These are some of the API's.  You would find them all listed in the SD reference docs.

     sd_ppi_channel_assign
     sd_ppi_channel_enable_set
           

    You will find the PPI reserved channels on page 169 of the product spec.

Children
  • Thank all of you. I find the table 22 and 24 in the S110_SDS_v2.pdf that about PPI and GPIOTE.  The SD uses the channel 14-15. The APP can use channel 0-13.  I think  the SDK I used is too old.  Now I am trying the SDK 10. But find I can not use GPIOTE  interrupt directly.  If I use bsp_event_handler, the delay is about 700us, it is too long.

    I want to measure the time from a signal on one pin to another.  About 200us-50ms.  Error should less than 5us. How can I do?

  • I can use PPI with the SDK 10.0. The errors of  the time datas were less than 10us, although they were a bit of volatility. But I can not use GPIOTE interrupt with SD. If I set the interrupt of GPIOTE, it can run at first time. After that, it looks the SD clear the interrupt of GPIOTE, I can see the GPIOTE events be on, but it doesn't respond to the interrupt of GPIOTE events.  

  • You only use the SD that comes with the SDK. So, not really an issue of using an old one, just using the correct one. SDK's and SD's are released in pairs.  The SD's are in the components folder.  Only by using the matching SD will the libraries and API calls work out. The API's are constantly changing and being improved on. Thus each new SD gets a new SDK. When one moves a project from one SDK to a later version (only if required for features, it is not normally necessary to do this) then you need to do some extensive reading of the SD release notes to make sure you are using the correct API's as they may be different.

  • I meant this as a general statement, your code shows you capture in gpiote: "For the timings you have specified you can't possibly do it in handlers.  Just pushing the registers to the stack and moving the program counter takes about 12 clocks, then depending on how many other things are queued up ahead of you will cause your ISR to be serviced later.

    APP ISR's have a much lower priority than the SD.  This is required to satisfy BLE radio protocol requirements. Advertisements alone will can cause delays of up to 1msec or more. Heavy BLE traffic will cause more frequent delays.

    The basic timing of the Pclk is 16MHz. Most activities take about 2 clocks so the min resolution of the timers is functionally 0.125usec."

    In order to achieve this you need to use PPI/GPIOTE to start and stop/capture the timers directly which I see you are doing in your code.  You don't want to have the shorts enabled since you are counting and it appears you have that correct.

    Your prescaler of 4 will give a 1MHz pclk or 1usec resolution.

    You need to make sure that HFCLK is on all the time. Offhand I can't remember if using a timer forces the HF_EXT to run. You should double check the nrf51 series reference manual on this. If not you can either start it manually whenever you are doing your timing events or you can tell the SD to keep it on all the time.  There are plenty of notes in the devzone on doing this just look it up. Otherwise the SD may put it on HFRC instead of HFEXT when your timer is running.

    The problem I see happening in your solution is that your external event happens, the timer starts, event stops timer stops and there is enough delay that your don't get into the ISR fast enough to get the counter register and instead you get into the isr while the timer is running again. If you don't mind throwing away some data points just look to see if the timer is running when you are in the handler to prevent this mistake.

  • Ambystomalabs, thank you very much for your answer.  Now, I am trying the SD8.0 . I know I use the new SD must match the API. I tested the example program "ble_app_uart",  because it is close to that I want. The example program works well on my board. 

    The APP is very simple. It get the time of signals on the two pins, calculate and send the datas out by Bluetooth and uart. So I don't worry about the bluetooth traffic will effect the measurement.  Now I can use the PPI,it can work. And I can set the interrupt of GPIOTE. I add my codes in the GPIOTE_IRQHandle()  in the nrf_drv_gpiote.c .  Looks, it can work well. 

    void GPIOTE_IRQHandler(void)
    {
        uint32_t status = 0;
        uint32_t input = 0;
        //these are my codes
    	if ((NRF_GPIOTE->EVENTS_IN[0] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN0_Msk))
        {
            NRF_GPIOTE->EVENTS_IN[0] = 0; //ÖжÏʼþÇåÁã.
    		if(capture_state==1)
    		{
    			//	NRF_TIMER2->TASKS_START = 1; 
    			//NRF_TIMER2->TASKS_CLEAR = 1; 
    		    capture_state=2; 
    		}		
    	}
    		
    	if ((NRF_GPIOTE->EVENTS_IN[1] == 1) && (NRF_GPIOTE->INTENSET & GPIOTE_INTENSET_IN1_Msk))
        {
    				
            NRF_GPIOTE->EVENTS_IN[1] = 0; //ÖжÏʼþÇåÁã.
    				if(capture_state==2)
    				{		
    					NRF_TIMER2->TASKS_CAPTURE[0] = 1;
    					shoot_flag=1;						
    					capture_time= NRF_TIMER2->CC[0];
    					nrf_gpio_pin_clear(20);
    					lock_time=10; 
    					capture_state=3;
    					NRF_TIMER2->TASKS_START = 1;					
    				}
    	//		  NRF_TIMER2->TASKS_STOP = 1;		//Í£Ö¹¶¨Ê±Æ÷
    	//		NRF_TIMER2->TASKS_CAPTURE[0] = 1;		//²¶×½ÈÎÎñ
    	//		capture_time= NRF_TIMER2->CC[0];		//»ñµÃʱ¼ä		
    	    }
    			if(capture_state==3) lock_time=10;
    			
    
        /* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/
        uint32_t i;
       nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_2;// nrf_gpiote_events_t event = NRF_GPIOTE_EVENTS_IN_0;			//´Óʼþ0¿ªÊ¼
        uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN2_MASK;//uint32_t mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;			//ÖжÏ0±ê־λ mask±êÖ¾£¬ÆðʼµÄµØÖ·
        for (i = 2; i < NUMBER_OF_GPIO_TE; i++)//for (i = 2; i < NUMBER_OF_GPIO_TE; i++)						//0-4
       ...............

Related