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

FDS garbage collection preventing app timer from feeding watchdog

When my program starts, I set up a watchdog timer for 100 milliseconds and I start a repeated app timer that runs every 90 milliseconds to feed the watchdog. I use the app scheduler for other interrupt handling so that normal operation does not interfere with the watchdog feed timer. It seems that whenever I call fds_gc(), if there is garbage collection to be done, it causes the watchdog to trigger. Presumably something in the garbage collection is not allowing app timer interrupts to happen. Code to reproduce this issue is below. Thank you in advance for your help.

I am using SDK 15.3.0 and SoftDevice 6.1.1 on an nRF52840 chip.

FDS code:

static ret_code_t datastorage_set_record(uint16_t file_id, uint16_t record_key, uint32_t *value, uint32_t words)
{
    ret_code_t err_code;
    fds_record_desc_t desc = {0};
    fds_find_token_t tok  = {0};
    fds_record_t write_record = {0};

    write_record.file_id = file_id;
    write_record.key = record_key;
    write_record.data.length_words = words;
    write_record.data.p_data = value;

    err_code = fds_record_find(file_id, record_key, &desc, &tok);
    if (err_code == FDS_SUCCESS)
    {
        err_code = fds_record_update(&desc, &write_record);
    }
    else if(err_code == FDS_ERR_NOT_FOUND)
    {
        err_code = fds_record_write(&desc, &write_record);
    }

    APP_ERROR_CHECK(err_code);
    return err_code;
}

static uint32_t count = 1;
static void datastorage_sched_fds_handler(void *p_event_data, uint16_t event_size)
{
    ret_code_t err_code;
    fds_evt_t const * p_evt = (fds_evt_t const *)p_event_data;

    APP_ERROR_CHECK(p_evt->result);

    switch(p_evt->id)
    {
        case FDS_EVT_INIT:
            datastorage_set_record(1, 1, &count, 1);
            break;

        case FDS_EVT_WRITE:
        case FDS_EVT_UPDATE:
            if(count < 10)
            {
                NRF_LOG_INFO("Updating...");
                count++;
                datastorage_set_record(1, 1, &count, 1);
            }
            else
            {
                NRF_LOG_INFO("Garbage collecting...");
                fds_gc();
            }
            break;
        
        case FDS_EVT_GC:
            NRF_LOG_INFO("Garbage collection done");
            break;
    }
}

static void datastorage_fds_handler(fds_evt_t const * p_evt)
{
    app_sched_event_put(p_evt, sizeof(fds_evt_t), datastorage_sched_fds_handler);
}

void datastorage_init(void)
{
    ret_code_t err_code;

    err_code = fds_register(datastorage_fds_handler);
    APP_ERROR_CHECK(err_code);

    err_code = fds_init();
    APP_ERROR_CHECK(err_code);
}

Watchdog code:

static void watchdog_handler(void)
{
    //reboot occurs
}

static void watchdog_feed(void * p_context)
{
    nrf_drv_wdt_channel_feed(watchdog_id);
}

static void watchdog_init(void)
{
    ret_code_t err_code;
    const nrf_drv_wdt_config_t wdt_config = {
       .behaviour           = NRF_WDT_BEHAVIOUR_RUN_SLEEP,
       .reload_value        = 100, //milliseconds
       .interrupt_priority  = APP_IRQ_PRIORITY_HIGH,
    };

    err_code = nrf_drv_wdt_init(&wdt_config, watchdog_handler);
    APP_ERROR_CHECK(err_code);
    err_code = nrf_drv_wdt_channel_alloc(&watchdog_id);
    APP_ERROR_CHECK(err_code);

    err_code = app_timer_create(&watchdog_feed_id,
                                APP_TIMER_MODE_REPEATED,
                                watchdog_feed);
    APP_ERROR_CHECK(err_code);

    nrf_drv_wdt_enable();
    err_code = app_timer_start(watchdog_feed_id, APP_TIMER_TICKS(90), NULL);
    APP_ERROR_CHECK(err_code);
}

  • Hi,

    Could you try to increase the Watchdog timer a bit and see if it helps? It might be to strict as the typical time it takes to erase one page is 85 ms.

  • Increasing the watchdog timer seems to lessen how often the problem occurs but does not solve it entirely. I modified the code above to loop after garbage collection succeeds. With the watchdog timer set at 500 milliseconds, it successfully loops anywhere between 100 and 200 times, but still trips the watchdog at some point.

  • I think that this confirms your assumption in that it's the garbage collection that prevents the app timer to reset the WD timer. You could try to queue the garbage collection right after the timer is reset in the app timer handler. This along with a no too strict timer requirement should give FDS enough time to complete the garbage collection before you have to feed the watchdog timer again. This will of course queue a lot of gc operations if you schedule them every time you reset the WD timer. Instead, you should figure out how often your application is in need of garbage collection based on your FDS operations. For example scheduling a garbage collection every 100th time you call the WD timer... Not sure if this is the best solution but might be a good start :) 

Related