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

Application times out after a while

I have an application where the nrf52840 dongle is hooked to a sensor.  The sensor drives a pin high, the mcu grabs data from the FIFO (SPI) and puts it in a buffer.  So far it works great, I see the interrupt pin go high, the device reads the entire sensor FIFO, then repeat.  However, after a while - several minutes, but it isn't consistent - I see the interrupt pin go high, and the mcu doesn't respond.  Since the sensor won't bring the line low until the data are read, the system stops at that point.  I don't see any error, the system is just waiting.  Is this ever expected behavior?  I'm wondering if the idle process is causing an issue randomly?

  • Thank you for your question, I will be looking into this tomorrow. In the mean time, would you be able to share some more background to your project?

    Is this ever expected behavior? 

    This of course depends on what you want to achieve. Here are a few questions: Is your application based on an example? Which SDK are you using? What happens when your buffer is full? Have you tried any debugging so far?

  • In this case, I am using the ble_app_template example (SDK 17.0.2) and in order to test the SPI (SPIM) functionality, I'm not using the BLE functionality at all yet.  I can debug the pins on a scope, but the dongle doesn't have a debugger.  I do have a nRF52840-Preview-DK that I can try to debug with when I get a shot.  My main() is pretty much from the example, but with some init calls for the GPIO/SPI/sensor:

    int main(void)
    {
        bool erase_bonds;
    
        // Initialize.
        log_init();
        timers_init();
        power_management_init();
        ble_stack_init();
        gap_params_init();
        gatt_init();
        advertising_init();
        services_init();
        conn_params_init();
    
        advertising_start();
    
        gpio_init();
        spi_init();
        lsm_init();
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }
    }

    I added code from the pin_change_int example to handle the pin sense of the interrupt pin from the sensor:

    void in_pin_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
    {
        if (m_notification_enabled)
        {
            //NRF_SPI0->ENABLE = 1;
            lsm_get_data(fifo_data_read_mode);
        }
    }

    I also have a pretty gnarly spi handler, but it works great while it works - and this is building out a prototype so we can work on making it pretty later.  I can dump the data from my FIFO buffer in a small fraction of what it took using only the interrupt-based processing.  I do nothing with the buffer for now, just overwrite it next time I get an interrupt:

    static void spi_event_handler(nrfx_spim_evt_t const * p_event, void * p_context)
    {
        nrf_gpio_pin_set(SPIM_CS);
        spi_xfer_done = true;
        nrf_gpio_pin_clear(SPIM_CS);
        
        if (ns_lsm_fn == READ && ns_lsm_reg != WHO_AM_I)
        {
            // Get buffer cardinality from FIFO_STATUS1 and 2
            fifo_buffer_size = (((rx_buff[2] & 0x0F) << 8 ) | rx_buff[1]);
    
            // put data in ble_buffer (H then L)
            ble_buff[ble_idx++] = rx_buff[6];
            ble_buff[ble_idx++] = rx_buff[5];
            
            while (ble_idx < (fifo_buffer_size * 2))
            {
                //NRF_SPI0->EVENTS_READY = 0;
                NRF_SPI0->TXD = FIFO_DATA_OUT_L | 0x80;
                rx_buff[7] = NRF_SPI0->RXD;
                NRF_SPI0->TXD = 0xFF;
                ble_buff[ble_idx++] = NRF_SPI0->RXD;
                NRF_SPI0->TXD = 0xFF;
                ble_buff[ble_idx++] = NRF_SPI0->RXD;
                nrf_delay_us(3);
                NRF_GPIO->OUTSET = 1 << SPIM_CS;
                __NOP();
                __NOP();
                __NOP();
                __NOP();
                NRF_GPIO->OUTCLR = 1 << SPIM_CS;
                __NOP();
                __NOP();
                __NOP();
                __NOP();
            }
            // reset fifo read variables
            fifo_buffer_size = 0;
            ble_idx = 0;
            nrf_gpio_pin_clear(SPIM_CS);
            //NRF_SPI0->ENABLE = 0; // TODO: Breaks functionality, why?
        }
    }

    From the scope, I see things working great while they work.  When it breaks, I see the MOSI line change high to low well before the interrupt pin goes high.  This seems to indicate that I'm in the idle_state_handle() process, but the pin changes anyway.  Then nothing when the sensor drives the interrupt pin high.  Then I see a reset after a few hundred ms:

    Scope capture

    Like I said, I have measured this at anywhere from 3 to 5 minutes, but it always happens.  Clearly, the expected behavior from my end is that this should work forever.

  • Thank you for the details.

    I had a brief chat with a colleague on this case and he asked why you were accessing the NRF_SPI0 register directly when using the SPI driver? He said this is not recommended and that one should either do everything by using hardware registers, or, one should let the driver take care of things. Using the driver is highly recommended. The driver could be detecting that the IC is in an unexpected state and could cause things to happen.

    Adding the debug-connector to your dongle could be a useful tool for you. Then you might see what state your code is in when things stop working.

Related