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? 

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

  • When I send signals to the pins,  I can get the datas that I want. But  then the bluetooth will disconnect , if the phone connect the board with BLE. And I cannot connect again. Looks the GPIOTE interrupt that I add in the GPIOTE_IRQHandle in the nrf_drv_gpiote.c  cause the SD run out.  How should I use the GPIOTE interrupt  and does not affect the SD to run??

    void GPIOTE_IRQHandler(void)
    {
        uint32_t status = 0;
        uint32_t input = 0;
    //I add the GPIOTE IN[0]and[1]
    		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_PPI->CHENCLR = (PPI_CHEN_CH4_Enabled << PPI_CHEN_CH4_Pos) ;
    					capture_state=2; 
    					nrf_gpio_pin_clear(20); 
    				}		
    	   }
    		
    		 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_PPI->CHENCLR = (PPI_CHEN_CH5_Enabled << PPI_CHEN_CH5_Pos) ;
    					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;
    //the end of my code
    
        /* collect status of all GPIOTE pin events. Processing is done once all are collected and cleared.*/
        uint32_t i;
        
        //I modified the events 0-3 to 2-3
       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
        {
            if (nrf_gpiote_event_is_set(event) && nrf_gpiote_int_is_enabled(mask))			//Èç¹ûʼþÒѾ­ÉèÖã¬ÖжÏʹÄÜ£¬Çå³ý±êÖ¾£¬×´Ì¬¼Ç¼ÄÇЩÉ趨ÁËʼþ
            {
                nrf_gpiote_event_clear(event);
                status |= mask;
            }
            mask <<= 1;
            /* Incrementing to next event, utilizing the fact that events are grouped together
             * in ascending order. */
           event = (nrf_gpiote_events_t)((uint32_t)event + sizeof(uint32_t));		//ʼþµØÖ·ÒÆÎ»
        }
    
        /* collect PORT status event, if event is set read pins state. Processing is postponed to the
         * end of interrupt. */
        if (nrf_gpiote_event_is_set(NRF_GPIOTE_EVENTS_PORT))		//Èç¹û¶Ë¿ÚʼþÉ趨
        {
            nrf_gpiote_event_clear(NRF_GPIOTE_EVENTS_PORT);			//Çå³ý
            status |= (uint32_t)NRF_GPIOTE_INT_PORT_MASK;				//״̬¼Ç¼
            input = nrf_gpio_pins_read();												//Òý½Å¶ÁÈ¡
        }
    
        // Process pin events. 
        if (status & NRF_GPIOTE_INT_IN_MASK)										//ÖжÏÊäÈë±êÖ¾ÓëÖжÏÊäÈë±êÖ¾½øÐбȽϣ¬Èç¹ûÓÐÊäÈë±êÖ¾
        {
            mask = (uint32_t)NRF_GPIOTE_INT_IN2_MASK;//mask = (uint32_t)NRF_GPIOTE_INT_IN0_MASK;						//´ÓIN0µÄÖжϿªÊ¼£¬ÂÖѯ4´Î
            for (i = 2; i < NUMBER_OF_GPIO_TE; i++)//for (i = 0; i < NUMBER_OF_GPIO_TE; i++)
            {
                if (mask & status)															//Èç¹ûÖжϱêÖ¾ºÍʹÄÜ״̬
                {
                    nrf_drv_gpiote_pin_t pin = nrf_gpiote_event_pin_get(i);				//		¶ÁÈ¡GPIOTE[i]¶ÔÓ¦µÄÊÇÄĸöÒý½Å
                    nrf_gpiote_polarity_t polarity = nrf_gpiote_event_polarity_get(i);			//  ¶ÁÈ¡GPIOTE[i]ÉèÖõÄÊÇʲô¼«ÐÔ 
                    nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(i);					//m_cb.handlers[channel]
                    handler(pin,polarity);											//´¦ÀíÒý½Å£¬¼«ÐÔ  
                }
                mask <<= 1;																			//ÒÆÎ»£¬´¦ÀíÏÂÒ»¸ö
            }
        }
    
        if (status & (uint32_t)NRF_GPIOTE_INT_PORT_MASK)				//Åж϶˿ڱêÖ¾ÊÇ·ñʹÄÜ
        {
            // Process port event. 												//´¦Àí¶Ë¿Úʼþ
            for (i = 0; i < GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS; i++)
            {
                if (m_cb.port_handlers_pins[i] != PIN_NOT_USED)
                {
                    uint8_t pin_and_sense = m_cb.port_handlers_pins[i];
                    nrf_drv_gpiote_pin_t pin = (pin_and_sense & ~SENSE_FIELD_MASK);
                    nrf_drv_gpiote_evt_handler_t handler = channel_handler_get(channel_port_get(pin));
                    if (handler)
                    {
                        nrf_gpiote_polarity_t polarity =
                                (nrf_gpiote_polarity_t)((pin_and_sense & SENSE_FIELD_MASK) >> SENSE_FIELD_POS);
                        mask = 1 << pin;
                        nrf_gpio_pin_sense_t sense = nrf_gpio_pin_sense_get(pin);
                        if (((mask & input) && (sense==NRF_GPIO_PIN_SENSE_HIGH)) ||
                           (!(mask & input) && (sense==NRF_GPIO_PIN_SENSE_LOW))  )
                        {
                            if (polarity == NRF_GPIOTE_POLARITY_TOGGLE)
                            {
                                nrf_gpio_pin_sense_t next_sense = (sense == NRF_GPIO_PIN_SENSE_HIGH) ?
                                        NRF_GPIO_PIN_SENSE_LOW : NRF_GPIO_PIN_SENSE_HIGH;
                                nrf_gpio_cfg_sense_set(pin, next_sense);
                            }
                            handler(pin, polarity);
                        }
                    }
                }
            }
        }
    }

  • So to be clear, what you are saying is that you are getting the correct timing values now but the SD stops working, correct?

    So I don't have to read through your code and guess, how many gpiote ISR's are you generating per second?

Related