FS_REGISTER_CFG sets my fs_config_t with incorrect values

I am using the example on sdk12.3/examples/ble_peripheral/experimental_ble_app_buttonless_dfu and copied the relevant parts to my app.

It is now apparently working. The bootloader settings are deleted when I connect top the device, subscribe to the dfu characteristic and then write "request" to it. The only problem is that I need to reset the device manually by turning off/on the power and when it boots, the bootloader fails the crc check and goes into dfu mode.

While trying to understand why the reason for the reset not being called on ble_dfu:on_disconnect():

static void on_disconnect(ble_dfu_t * p_dfu, ble_evt_t const * p_ble_evt)
{
    if (p_dfu->conn_handle != p_ble_evt->evt.gatts_evt.conn_handle)
    {
        return;
    }

    p_dfu->conn_handle = BLE_CONN_HANDLE_INVALID;

    if (p_dfu->is_waiting_for_disconnection)
    {
        NVIC_SystemReset();
    }
}

And that is because p_dfu->is_waiting_for_disconnection is false when I disconnect the android app, after executing the steps explained above.

The reason is that the flash_callback is not called. I tracked this to fs_sys_event_handler(sys_evt) not being called, so I uncommented the call to "fs_sys_event_handler(sys_evt)" on main.c:sys_evt_dispatch(), and then I got a bit further: the result of the fs operation is now being reported, but on:

static void send_event(fs_op_t const * const p_op, fs_ret_t result)
{
    fs_evt_t evt;
    memset(&evt, 0x00, sizeof(fs_evt_t));

    switch (p_op->op_code)
    {
        case FS_OP_STORE:
            evt.id                 = FS_EVT_STORE;
            evt.store.p_data       = p_op->store.p_dest;
            evt.store.length_words = p_op->store.length_words;
            break;

        case FS_OP_ERASE:
            evt.id               = FS_EVT_ERASE;
            evt.erase.first_page = p_op->erase.page - p_op->erase.pages_erased;
            evt.erase.last_page  = p_op->erase.page;
            break;

        default: 
            // Should not happen.
            break;
    }
    evt.p_context = p_op->p_context;

    p_op->p_config->callback(&evt, result);
}

the call to p_op->p_config->callback(&evt, result); is failing, because the address of p_op->p_config->callback is 0x1040fff7, instead of 0x00022875.

More on this bellow...

I noticed that the call to FS_REGISTER_CFG:

FS_REGISTER_CFG(fs_config_t fs_dfu_config) =
{
    .callback       = fs_evt_handler,            // Function for event callbacks.
    .p_start_addr   = (uint32_t*)MBR_SIZE,
    .p_end_addr     = (uint32_t*)(BOOTLOADER_SETTINGS_ADDRESS + CODE_PAGE_SIZE)
};

Apparently the correct values are not being set.

Initially the p_start_addr and p_end_addr were being set incorrecly, and I "fixed" that by adding code to nrf_dfu_flash_init() on nrf_dfu_flash_buttonless.c (this is code from the example)

Original:

uint32_t nrf_dfu_flash_init(bool sd_enabled)
{
    m_flags = FLASH_FLAG_SD_ENABLED;
    return NRF_SUCCESS;
}

My changes:

uint32_t nrf_dfu_flash_init(bool sd_enabled)
{
    fs_dfu_config.p_start_addr   = (uint32_t*)MBR_SIZE;
    fs_dfu_config.p_end_addr     = (uint32_t*)(BOOTLOADER_SETTINGS_ADDRESS + CODE_PAGE_SIZE);

    m_flags = FLASH_FLAG_SD_ENABLED;
    return NRF_SUCCESS;
}

But for some reason, and without me having changed anything that I can think of that might have made the correct values being assigned to p_start_addr and p_end_addr, these changes are no longer needed. This is intriguing.

But on reporting the status of the fstorage operations, the executing is hanging. I tracked this down to the value of .callback on the same structure.

I added the following:

uint32_t nrf_dfu_flash_init(bool sd_enabled)
{
    fs_config_t x = {
      .callback = fs_evt_handler
    };
    
    m_flags = FLASH_FLAG_SD_ENABLED;
    return NRF_SUCCESS;
}

And by placing a breakpoint on "m_flags = FLASH_FLAG_SD_ENABLED;", i can see that:

x.callback = 0x00022875

while:

fs_dfu_config.callback = 0x1040fff7

The execution is hanging at 0x1040fff6, which has no code.

I am wondering what is going on here? I still don't understand why FS_REGISTER_CFG sets the wrong values, first to the start and end addresses and now to the callback function pointer. Can you provide some suggestions on how to fix this?

Best regards,

Ricardo

  • I got it working now.

    I found out that the wrong values assigned when declaring the fs_dfu_config variable by calling the FS_REGISTER_CFG macro, as seen above, seem to keep the correct values if the override is done once, even after it is removed, but they go back to the wrong values after a device reset, so I added it back.

    I changed the function nrf_dfu_flash_init() in crf_dfu_flash_buttonless.c from the experimental_ble_app_buttonless_dfu example in SDK12.3 to look like:

    uint32_t nrf_dfu_flash_init(bool sd_enabled)
    {
        // NOTE: added by me
        uint32_t * override_const_p = &fs_dfu_config.callback;
        *override_const_p = fs_evt_handler;
        fs_dfu_config.p_start_addr   = (uint32_t*)MBR_SIZE;
        fs_dfu_config.p_end_addr     = (uint32_t*)(BOOTLOADER_SETTINGS_ADDRESS + CODE_PAGE_SIZE);
    
        // NOTE: added by me
        fs_init();
    
        m_flags = FLASH_FLAG_SD_ENABLED;
        return NRF_SUCCESS;
    }
    

    After this p_start_addr, p_end_addr and calback struct fields have the correct values, and the callback can be called after erasing the bootloader settings.

    There is just one thing missing, which is to actually send the fs event back to fsstorage, so that all the callbacks can be called, triggering the setting of

    p_dfu->is_waiting_for_disconnection = true in ble_dfu.c:flash_callback(),

    which is to uncomment the call to:

    fs_sys_event_handler(sys_evt) on main.c:sys_evt_dispatch().

    This way all is prepared to trigger a boot from app to DFU mode.

    To achieve this, all one needs to do is (I am using nrf connect android app as it is the easier way to explain the steps):

    1. open nrf connect android app and find your device

    2. connect to your device

    3. expand the dfu characteristic

    4. press the enable notifications icon for this charaxcteristic

    5. press the write icon and select "request"

    6. the bootloader settings region will be erased. wait for the confirmation, bellow the botifications and write icons

    7. disconnect from your device

    8. done. the device booted to DfuTarg. you can now connect to it and upload your new binaries.

    Here is nice how-to, explaining all about packaging your app, with a newly generated settings.hex.

    Hope this saves someone else some time. It sure would have saved me a couple of days!

Related