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

Simultaneous GPIOTE interrupt event not being generated

I'm running FreeRTOS with SDK version 15.0 on nrf52 custom board.

I have two sensors, say A and B, on two separate SPIM bus instances. Sensor B utilizes PPI to trigger data transfer on Low-to-High transition of its interrupt pin. The PPI is also forked to increment a timer module working as counter to keep track of received samples. The counter is configured for a compare interrupt to know if all samples are received.

Sensor A does the Data transfer on the GPIOTE handler for Low-to-High transition of its respective interrupt pin.

Both sensors' data acquisition happens simultaneously.

When both sensors are working in low frequencies, things are working fine. But when they are working on high and nearly equal frequencies, the controller fails to process the data ready event from sensor B. i.e. the counter is not getting incremented and thus the compare event is not happening.

To debug, I provided a callback for the sensor B's nrf_drv_gpiote_in_init function and the function gets called only once even though the pin's state transitions continuously.

I went through examples and threads to see if the PPI configurations are correct and everything looks OK.

What could be the problem???

Parents
  • Hi AGJ,

    Since you have a GPIOTE handler to start data transfer for sensor A, it is possible that this handler is taking too much time in itself at high frequencies.

    Nevertheless, if the new interrupt from Sensor B, is connected to PPI and which starts the transfer as well as increments the timer in counter mode, then it seems to be done purely in hardware and the software latencies should not have affected it.

    Just as an experiment, can comment the contents in the GPIOTE handler that is triggered by sensor A to see if this is the culprit. If this effects the sensor B data transfer, then something is wrong with the configuration of Sensor B as it somehow depends on CPU availability. 

    It is hard to say more than this without looking into your initialization functions 

  • Hi Susheel,

    These are my initialization and data transfer functions.

    /*   Sensor A FIFO data fetch complete callback. */
    static void SensorA_SPIXferCallback( nrf_drv_spi_evt_t const * p_event, void * p_context )
    {
        // Updating the remaining samples' count
        totSamples = totSamples - rxDataCount; 
    
        // If all samples are received,
        if( !totSamples )
        {
            xferComplete = true;
    
            nrfx_gpiote_in_event_disable( SENSOR_A_INT1_PIN );
            nrfx_gpiote_in_uninit( SENSOR_A_INT1_PIN ); 
        }
        else
        {
            // Calculating watermark level
            watermark = ( totSamples <= MAX_WATERMARK_LEVEL ) ? totSamples : MID_WATERMARK_LEVEL; 
    
            // Setting the calculated watermark level if it is different from the previous value
            if( prevWatermark != watermark )
            {
                if( WordWrite( FIFO_CTRL, watermark ))     
                {
                    return ; 
                }
                
                // Saving the new watermark
                prevWatermark = watermark; 
            }
        }
    
        xferPending = false; // No transfer is pending at this point
    }
    
    
    
    
    /*   Sensor A FIFO data fetch initiate. Non-blocking   */
    static int32_t FIFODataFetchStart( void )
    {
        uint16_t unreadDataCount = watermark; 
    
        // Reading contents of FIFO Status Reg
        if( WordRead( FIFO_STATUS, &unreadDataCount ))    
        {
            return -ERR_IO; 
        }
        
        // Extracting unread data count from the contents in FIFO status register
        unreadDataCount = unreadDataCount & FIFO_UNREAD_COUNT_MASK; 
           
          
        // If the calculated number of samples to read is greater than number of samples left,
        // read only the remaining number of samples
        if( rxDataCount > totSamples )
        {
            rxDataCount = totSamples; 
        }
        
        // Start SPI read
        if( MultiReadStart( FIFO_OUTPUT_ADR, ( uint8_t * )outDataBuf, rxDataCount ))
        {
            return -ERR_IO; 
        }
    
        xferPending = true;            // A new data transfer is pending
    
        return 0; 
    }
    
    /*   Sensor A Data Ready Int Callback    */
    static void SensorA_IntHandler( nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action )
    {       
        // Trigger a new transfer only if there is no other transfer pending.
        if( !xferPending )
        {
            FIFODataFetchStart(); 
        }
    }
    
    static int32_t SensorB_DRIntConfig( IntTransition_t transition, IntCallback_t intCallback )
    {
        int32_t ret;
    
        if( transition == LOW_TO_HI )
        {
            SensorAPinConfig.sense = NRF_GPIOTE_POLARITY_LOTOHI; 
        }
        else if( transition == HI_TO_LOW )
        {
            SensorAPinConfig.sense = NRF_GPIOTE_POLARITY_HITOLO; 
        }
        else if( transition == TOGGLE )
        {
            SensorAPinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE; 
        }
    
        
        SensorA_IntCallback = intCallback; 
    
        ret = nrfx_gpiote_in_init( SENSOR_A_INT1_PIN, &SensorAPinConfig, SensorA_IntHandler );
        APP_ERROR_CHECK( ret ); 
        if ( ret )
        {
            return ret;
        }
    
        nrfx_gpiote_in_event_enable( SENSOR_A_INT1_PIN, true );
        
    
        return 0; 
    }
    
    
    /*   Sensor B Data Ready Int Callback    */
    static void SensorB_IntHandler( nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action )
    {
        if( SensorB_IntCallback )
        {
            SensorB_IntCallback(( void * )action ); 
        }
    }
    
    /*   Function to configure Data Ready Pin for Sensor B     */
    static int32_t SensorB_DRIntConfig( IntTransition_t transition, IntCallback_t intCallback )
    {
        int32_t ret;
    
        if( transition == LOW_TO_HI )
        {
            SensorBIntPinConfig.sense = NRF_GPIOTE_POLARITY_LOTOHI; 
        }
        else if( transition == HI_TO_LOW )
        {
            SensorBIntPinConfig.sense = NRF_GPIOTE_POLARITY_HITOLO; 
        }
        else if( transition == TOGGLE )
        {
            SensorBIntPinConfig.sense = NRF_GPIOTE_POLARITY_TOGGLE; 
        }
    
        SensorB_IntCallback = intCallback; 
        
    	
    	ret = nrfx_gpiote_in_init( SENSOR_B_DRDY_PIN, &SensorBIntPinConfig, IntHandler );
        if ( ret )
        {
            return ret;
        }
    
        nrfx_gpiote_in_event_enable( SENSOR_B_DRDY_PIN, true );
    
        return 0; 
    }
    
    /*   Function to configure PPI for Sensor B     */
    static int32_t SensorB_TransferInit( uint32_t sampleCount, callback_t callback )
    {
        int32_t err_code; 
    
        // Finding available Transfer module
        XferInst_t * tempXferInst = FindAvailXferInst();
        if( !tempXferInst )
        {
            return -ERR_NXIO; 
        }
    
        // Configuring the Transfer module
        tempXferInst->avail    = false; 
        tempXferInst->name     = device.name; 
        tempXferInst->trigPin  = SENSOR_B_DRDY_PIN; 
        tempXferInst->callback = callback;
    
        // Configurations for the timer instance
        nrf_drv_timer_config_t timer_cfg = NRF_DRV_TIMER_DEFAULT_CONFIG; 
        timer_cfg.interrupt_priority     = 7; 
        
        // Initialising timer (as counter -> sdk_config -> NRFX_TIMER_DEFAULT_CONFIG_MODE)
        err_code = nrf_drv_timer_init( &tempXferInst->timerInst, &timer_cfg, tempXferInst->event_handler );
        APP_ERROR_CHECK( err_code );
        
        // Allocating PPI channel
        err_code = nrf_drv_ppi_channel_alloc( &tempXferInst->ppiChannel );
        APP_ERROR_CHECK( err_code );
           
        // Set up PPI Channel for triggering of SPIM start when an event occurs on the provided pin.
        err_code = nrf_drv_ppi_channel_assign( tempXferInst->ppiChannel,
                                               nrf_drv_gpiote_in_event_addr_get( tempXferInst->trigPin ),
                                               nrf_spim_task_address_get( busIdentifier.u.spim.p_reg, NRF_SPIM_TASK_START ) );
        APP_ERROR_CHECK( err_code );
    
        // Fork PPI to also trigger count on timer to keep track of number of samples.
        err_code = nrf_drv_ppi_channel_fork_assign( tempXferInst->ppiChannel,
                                                    nrf_drv_timer_task_address_get( &tempXferInst->timerInst, NRF_TIMER_TASK_COUNT ));
        APP_ERROR_CHECK( err_code );
    
        // Setting counter compare event
        nrf_drv_timer_extended_compare( &tempXferInst->timerInst, NRF_TIMER_CC_CHANNEL1, sampleCount, NRF_TIMER_SHORT_COMPARE1_CLEAR_MASK, true );
           
        // Enabling allocated PPI channel
        err_code = nrf_drv_ppi_channel_enable( tempXferInst->ppiChannel );
        APP_ERROR_CHECK( err_code );
    
        // Enabling counter compare interrupt and counter
        nrf_drv_timer_enable( &tempXferInst->timerInst );
    
        return 0;
    }
    

    I tried commenting out the Sensor A GPIOTE handler contents and sensor B didn't hang.

    What would the dependency be???

  • Thanks for your time.

    I was not able to find any conflict in any kind of resource used by Sensors A and B...

    I have another question,

    During initialization of a GPIO, to be used as an event for PPI, instead of

    nrfx_gpiote_in_init( SENSOR_B_DRDY_PIN, &SensorBIntPinConfig, NULL );

    if I use

    nrfx_gpiote_in_init( SENSOR_B_DRDY_PIN, &SensorBIntPinConfig, IntHandler );

    and when there is a transition in SENSOR_B_DRDY_PIN, what will be executed first, the 'IntHandler' or the PPI task that was configured?

    And will the execution of 'IntHandler' affect the PPI task execution in any way provided that the contents of  'IntHandler' will not conflict with the PPI task?

  • The IntHandler will not be executed fast enough. On ARM cortex, it takes atleast 12 cpu cycles run the interrupt handler (after the interrupt is triggered). The IntHandler in your code will take way more CPU cycles as this is a callback from the GPIOTE ISR. The PPI task will take atmost 2 HFCLK cycles to be triggered. So for sure the PPI task will be triggered first in this case.

  • OK, thanks.

    And will the execution of 'IntHandler' affect the PPI task execution in any way provided that the contents of  'IntHandler' will not conflict with the PPI task?

    And this?

  • I thought i replied to this message, but somehow my reply seems to have been sent to void. sorry about that.

    The PPI task is configured to work purely in the hardware once the channel is enabled and has no dependency on the availability on the CPU. The PPI will trigger the task in time no matter which context CPU is executing. That is the whole purpose of PPI/GPIOTE combo

Reply Children
No Data
Related