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

FS_ERR_UNALIGNED_ADDR with Buttonless DFU

Hi, I'm working on porting my application from SDK 11.0 to 12.2.0 and I have a problem initializing the buttonless DFU service. I've flashed the secure bootloader and appropriate settings. The bootloader itself is working correctly (I can upload a Nordic test image just fine).

If I add the BLE DFU service during services_init() the device resets. I've narrowed the fault down to this portion of the nrf_dfu_settings.c:

void nrf_dfu_settings_init(void)
{
    NRF_LOG_INFO("running nrf_dfu_settings_init\r\n");

    volatile uint32_t crc;

    flash_operation_pending = false;

    // Copy the DFU settings out of flash and into a buffer in RAM.
    memcpy((void*)&s_dfu_settings, &m_dfu_settings_buffer[0], sizeof(nrf_dfu_settings_t));

    if(s_dfu_settings.crc != 0xFFFFFFFF)
    {
        // CRC is set. Content must be valid
        crc = nrf_dfu_settings_calculate_crc();
        if(crc == s_dfu_settings.crc)
        {
            return;
        }
    }

    // Reached if nothing is configured or if CRC was wrong
    NRF_LOG_INFO("!!!!!!!!!!!!!!! Resetting bootloader settings !!!!!!!!!!!\r\n");
    memset(&s_dfu_settings, 0x00, sizeof(nrf_dfu_settings_t));
    s_dfu_settings.settings_version = NRF_DFU_SETTINGS_VERSION;
    APP_ERROR_CHECK(nrf_dfu_settings_write(NULL));
}


ret_code_t nrf_dfu_settings_write(dfu_flash_callback_t callback)
{
    ret_code_t err_code = FS_SUCCESS;
    NRF_LOG_INFO("Erasing old settings at: 0x%08x\r\n", (uint32_t)&m_dfu_settings_buffer[0]);

    // Wait for any ongoing operation (because of multiple calls to nrf_dfu_settings_write)
    wait_for_pending();
    
    flash_operation_pending = true;
    m_callback = callback;
    
    do 
    {
        wait_for_queue();
        
        // Not setting the callback function because ERASE is required before STORE
        // Only report completion on successful STORE.
        err_code = nrf_dfu_flash_erase((uint32_t*)&m_dfu_settings_buffer[0], 1, NULL);
        
    } while (err_code == FS_ERR_QUEUE_FULL);
    
    
    if (err_code != FS_SUCCESS)
    {
        NRF_LOG_ERROR("Erasing from flash memory failed.\r\n");
        flash_operation_pending = false;
        return NRF_ERROR_INTERNAL;
    }

    s_dfu_settings.crc = nrf_dfu_settings_calculate_crc();

    NRF_LOG_INFO("Writing 0x%08x words\r\n", sizeof(nrf_dfu_settings_t)/4);

    static nrf_dfu_settings_t temp_dfu_settings;
    memcpy(&temp_dfu_settings, &s_dfu_settings, sizeof(nrf_dfu_settings_t));

    do 
    {
        wait_for_queue();
        
        err_code = nrf_dfu_flash_store((uint32_t*)&m_dfu_settings_buffer[0],
                                       (uint32_t*)&temp_dfu_settings,
                                       sizeof(nrf_dfu_settings_t)/4,
                                       dfu_settings_write_callback);

    } while (err_code == FS_ERR_QUEUE_FULL);
    
    if (err_code != FS_SUCCESS)
    {
        NRF_LOG_ERROR("Storing to flash memory failed.\r\n");
        flash_operation_pending = false;
        return NRF_ERROR_INTERNAL;
    }

    NRF_LOG_INFO("Writing settings...\r\n");
    return NRF_SUCCESS;
}

The stored CRC is just 0, so it does not match the calculated one. Thus the application resets the bootloader settings. This alarms me since nrfutil reports a CRC when I generate the settings hex file.

But anyway, the value returned by this line:

err_code = nrf_dfu_flash_erase((uint32_t*)&m_dfu_settings_buffer[0], 1, NULL);

is FS_ERR_UNALIGNED_ADDR, and I'm not quite sure what's going on. The bootloader settings address is configured as 0x0007F000, which should be aligned with a a page boundary.

  • So, with Hung Bui's help, I've figured out the problem.

    I'm using GCC to compile my application. I followed the experimental_ble_app_buttonless_dfu closely. The linker script provided with the example doesn't declare the .bootloaderSettings section so when the compiler reaches this part of nrf_dfu_settings.c

    /** @brief  This variable reserves a codepage for bootloader specific settings,
     *          to ensure the compiler doesn't locate any code or variables at his location.
     */
    #if defined (__CC_ARM )
    
        uint8_t  m_dfu_settings_buffer[CODE_PAGE_SIZE] __attribute__((at(BOOTLOADER_SETTINGS_ADDRESS)))
                                                       __attribute__((used));
    
    #elif defined ( __GNUC__ )
    
        uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE] __attribute__ ((section(".bootloaderSettings")))
                                                      __attribute__((used));
    
    #elif defined ( __ICCARM__ )
    
        __no_init __root uint8_t m_dfu_settings_buffer[CODE_PAGE_SIZE] @ BOOTLOADER_SETTINGS_ADDRESS;
    
    #else
    
        #error Not a valid compiler/linker for m_dfu_settings placement.
    
    #endif
    

    where it allocates m_dfu_settings_buffer, it can't find the section. I was also naively under the impression that the compiler was entering the __CC_ARM section, but instead it enters the __GNUC__ section.

    Declaring the section in the application linker script like so:

    /* Linker script to configure memory regions. */
    
    SEARCH_DIR(.)
    GROUP(-lgcc -lc -lnosys)
    
    MEMORY
    {
      FLASH (rx) : ORIGIN = 0x1f000, LENGTH = 0x59000
      RAM (rwx) :  ORIGIN = 0x20002c48, LENGTH = 0xd3b8
    
      /** Location of bootloader setting in flash. */
      BOOTLOADER_SETTINGS (rw) : ORIGIN = 0x0007F000, LENGTH = 0x1000
    }
    
    SECTIONS
    {
      /* Place the bootloader settings page in flash. */
      .bootloaderSettings(NOLOAD) :
      {
    
      } > BOOTLOADER_SETTINGS
    }
    
    SECTIONS
    {
      .fs_data :
      {
        PROVIDE(__start_fs_data = .);
        KEEP(*(.fs_data))
        PROVIDE(__stop_fs_data = .);
      } > RAM
      .pwr_mgmt_data :
      {
        PROVIDE(__start_pwr_mgmt_data = .);
        KEEP(*(.pwr_mgmt_data))
        PROVIDE(__stop_pwr_mgmt_data = .);
      } > RAM
    } INSERT AFTER .data;
    
    INCLUDE "nrf5x_common.ld"
    

    the application boots normally. This was also what was causing the CRC to be zero on boot.

Related