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

Issue with gpio interrupt and idle_state_handle

Dear All,

I am experimenting with the nRF52840 DK and the ble_app_template.

Based on that project, I am trying to configure a pin interrupt on Button 1 (pin 0.11).

This is my configuration:

void in_pin_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
    NRF_LOG_INFO("Interrupt triggered");
}

static void gpio_init(void)
{
    ret_code_t err_code;

    err_code = nrf_drv_gpiote_init();
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_config_t in_config = GPIOTE_CONFIG_IN_SENSE_TOGGLE(false);
    in_config.pull = NRF_GPIO_PIN_PULLUP;

    err_code = nrf_drv_gpiote_in_init(PIN_IN, &in_config, in_pin_handler);
    APP_ERROR_CHECK(err_code);

    nrf_drv_gpiote_in_event_enable(PIN_IN, true);
}

It is mostly inspired by the ...\examples\peripheral\pin_change_int.

In the same code, I reading out also to ADC values from AIN0 and AIN1.
Finally I am also configuring and using a watchdog.

My main looks like this:

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();
    peer_manager_init();
    gpio_init();

    print_reset_reason();

    // Start execution.
    NRF_LOG_INFO("Template example started.");
    application_timers_start();
    wdt_init(WATCHDOG_TIMEOUT);

    advertising_start(erase_bonds);
    saadc_init();
    static nrf_saadc_value_t adc_value_0;
	static nrf_saadc_value_t adc_value_1;
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
        // Sample SAADC on two channels
        nrf_drv_saadc_sample_convert(0, &adc_value_0);
        nrf_drv_saadc_sample_convert(1, &adc_value_1);
        
        NRF_LOG_INFO("Sample channel 0: %d", ADC_RESULT_IN_MILLI_VOLTS(adc_value_0));
        NRF_LOG_INFO("Sample channel 1: %d", ADC_RESULT_IN_MILLI_VOLTS(adc_value_1));
        wtd_feed();
    
        nrf_delay_ms(1000);
    }
}


What I see is that the program will start and it will hang at idle_state_handle. If I do not press the button for more than the watchdog timeout, the device resets due to the watchdog.

If I press the button the interrupt is fired (I see the debug message) as well as a pair of ADC measurements from the 2 channels.

What I understand is that the interrupt that I am configuring is messing with the device going to System On Idle state. What I noticed on the pin_change_int example is that there the while loop does nothing (is empty), but I think that because I need my application to be low power, I need to do something like the idle_state_handle, correct?

Can anyone make some suggestions on how to properly configure my application?

Parents
  • Hello,

    What I see is that the program will start and it will hang at idle_state_handle. If I do not press the button for more than the watchdog timeout, the device resets due to the watchdog.

    Yes, the idle_state_handle(if you are using it as-is from the ble_template_project) places the device in a low-power mode, waiting to be awoken by an event. If no event is generated, it will stay here until terminated by the watchdog, as you have observed.

    If I press the button the interrupt is fired (I see the debug message) as well as a pair of ADC measurements from the 2 channels.

    Yes, but is this as intended? Do you intend to have to press the button to perform SAADC sampling? If not, you may want to connect the sampling trigger to another event that you do not have to generate manually every time, for example a timer.

    I need my application to be low power, I need to do something like the idle_state_handle, correct?

     Yes, this is correct. I would advice against running empty loops or wasting clock cycles(such as with your call to nrf_delay_ms(1000)), because both of these have dramatically higher power consumption than entering sleepmode and waiting for an event to trigger.

    Can anyone make some suggestions on how to properly configure my application?

    Could you tell me some more about how you would like you application to function?
    What is the purpose of the watchdog you have added?

    As for suggestions for improvements, the idle_state_handle may very well be the only thing in your main loop - having everything else connected to events/peripherals.
    So, in your case, say you would like the device to wake up to perform an SAADC measurement every 200 ms while it is connected to another device.
    For this to happen, you would need to create a 200 ms timer, configured to generate compare events every 200 ms. Then you would have to connect the SAADC sampling task to the timer's compare event. Following this, you will have to start the timer when the BLE_GAP_EVT_CONNECTED event is passed to the ble_evt_handler, and likewise stop the timer if the BLE_GAP_EVT_DISCONNECTED event is passed to the handler.
    The timer setup and linking to the SAADC sample task might here be the challenging part - but this is all demonstrated in the SAADC Example from the SDK. 

    This way, you device will stay sleeping until connected, and also in-between connection intervals when it is not sampling the SAADC.

    Let me know if this did not answer your question, or if any of this still is unclear.

    Best regards,
    Karl

  • Dear ,

    Thank you for your response and the comments.

    What I need to do is to attach an interrupt to a pin. When I press the button the device should print a message or toggle a LED.

    At the same time I need to have the watchdog running at all times, so that it can reset the board if the code gets stuck at any point.

    From your answer, it seems that I cannot use the watchdog the way I do. The way I had it in my mind is to have in the while loop the idle_state_handle and the wtd_feed.

    Also, from your answer, what I get is that after running the idle_state_handle the device should go to sleep and the subsequent lines should not execute, except if the cpu is interrupted somehow.

    But from running the code, what I saw is that the ADC measurement and the printing where taking place every second. Once I enabled the interrupt on the pin the application would hang at that point.

    I am curious why is that happening?

    Also, how could I use the watchdog to make sure that if the device is stuck it will at least reset itself?

  • Hello again,

    Sorry for my late reply.

    Giannis Anastasopoulos said:
    Thank you for your response and the comments.

    No problem at all, I am happy to help!

    Giannis Anastasopoulos said:
    What I need to do is to attach an interrupt to a pin. When I press the button the device should print a message or toggle a LED.

    Yes, for this you could use the same approach as in the pin_change_int example - just change the in_pin_handler function to print your message or toggle your led.

    Giannis Anastasopoulos said:
    At the same time I need to have the watchdog running at all times, so that it can reset the board if the code gets stuck at any point.

    Is there a certain function or place in the code that you are worried might get stuck? Such as a waiting while-loop or the likes?
    Be advised that it is also possible to pause the watchdog countdown when the CPU is sleeping, using the CONFIG register.

    Giannis Anastasopoulos said:
    From your answer, it seems that I cannot use the watchdog the way I do. The way I had it in my mind is to have in the while loop the idle_state_handle and the wtd_feed.

    I see now that I might have been inaccurate in my last reply.
    You may very well feed it during the while loop, even if the only other contents of the while loop is the power manage run function. This should work just fine, since the pwr_manage function _will_ return on any events or interrupts generated - such as the compare event of your SAADC timers. This way, you will feed the watchdog at the very least as often as the timers trigger. My apologies for any confusion this might have caused.

    Giannis Anastasopoulos said:

    But from running the code, what I saw is that the ADC measurement and the printing where taking place every second. Once I enabled the interrupt on the pin the application would hang at that point.

    I am curious why is that happening?



    Yes, as mentioned above the main loop will complete a round every time an event is generated.
    I would still suggest using PPI to connect your timer to the sample task, so that you do not need to use the CPU to trigger each sample.

    I am not sure I understood that last part correct - are you saying that the device gets stuck in the main loop(no saadc sampling happening) when you enable your pin_interrupt(from your gpio_init function)?

    Best regards,
    Karl

  • Dear ,

    I am not sure I understood that last part correct - are you saying that the device gets stuck in the main loop(no saadc sampling happening) when you enable your pin_interrupt(from your gpio_init function)?

    After removing the ADC from the the loop in the main and placing these measurements in the rtc_handler, the application seems to work just fine, so I guess the issue has been resolved.

  • Hello,

    After removing the ADC from the the loop in the main and placing these measurements in the rtc_handler, the application seems to work just fine

    I am happy to hear that the issue is resolved!
    For further development, I would recommend keeping the main-loop very minimalistic(sticking to just the power_manage is fine), and I will once again recommend looking into using PPI to trigger your sampling - so you will not require any interaction from the CPU everytime a sample is to be taken.

    Please do not hesitate to open a new ticket if you should encounter any issues or questions in the future,

    Good luck with your development!

    Best regards,
    Karl

Reply
  • Hello,

    After removing the ADC from the the loop in the main and placing these measurements in the rtc_handler, the application seems to work just fine

    I am happy to hear that the issue is resolved!
    For further development, I would recommend keeping the main-loop very minimalistic(sticking to just the power_manage is fine), and I will once again recommend looking into using PPI to trigger your sampling - so you will not require any interaction from the CPU everytime a sample is to be taken.

    Please do not hesitate to open a new ticket if you should encounter any issues or questions in the future,

    Good luck with your development!

    Best regards,
    Karl

Children
No Data
Related