RTOS Application DFU

This document is intended to help you use the RTOS DFU driver and RTOS QSPI flash driver in an application.

DFU Driver Overview

This driver provides the application with the boot partition and data partition layout of the flash used by the second stage bootloader. The driver provides a subset of the functionality of libquadflash enabling the application to use any transport method and the RTOS qspi flash driver to read the factory image, read/write a single upgrade image, and read/write the data partition.

Reading the Factory Image

To read back the factory image:

unsigned addr = rtos_dfu_image_get_factory_addr(dfu_image_ctx);
unsigned size = rtos_dfu_image_get_factory_size(dfu_image_ctx);

unsigned char *buf = pvPortMalloc(sizeof(unsigned char) * size);

rtos_qspi_flash_read(
      qspi_flash_ctx,
      (uint8_t *)buf,
      addr,
      size);

// buf now contains the factory image contents

It is advised to perform this operation in blocks rather than full image size to reduce memory usage. Once the buffer is populated from flash, it can be sent over the desired transport method, such as USB, I2C, etc.

Reading the Upgrade Image

To read back the upgrade image:

unsigned addr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx);
unsigned size = rtos_dfu_image_get_upgrade_size(dfu_image_ctx);

unsigned char *buf = pvPortMalloc(sizeof(unsigned char) * size);

rtos_qspi_flash_read(
      qspi_flash_ctx,
      (uint8_t *)buf,
      addr,
      size);

// buf now contains the upgrade image contents

It is advised to perform this operation in blocks rather than full image size to reduce memory usage. Once the buffer is populated from flash, it can be sent over the desired transport method, such as USB, I2C, etc.

Writing the Upgrade Image

To overwrite the current upgrade image:

// Assuming buf contains the image data
// and size contains the size in bytes

unsigned addr = rtos_dfu_image_get_upgrade_addr(dfu_image_ctx);
unsigned data_partition_base_addr = rtos_dfu_image_get_data_partition_addr(dfu_image_ctx);
unsigned bytes_avail = data_partition_base_addr - addr;

size_t sector_size = rtos_qspi_flash_sector_size_get(qspi_flash_ctx);

if(size < bytes_avail) {
   unsigned char *tmp_buf = pvPortMalloc(sizeof(unsigned char) * sector_size);
   unsigned cur_offset = 0;
   do {
      unsigned length = (size - (cur_offset - addr)) >= sector_size ? sector_size : (size - (cur_offset - addr));
      rtos_qspi_flash_lock(qspi_flash_ctx);
      {
         rtos_qspi_flash_read(
                  qspi_flash_ctx,
                  tmp_buf,
                  addr + cur_offset,
                  sector_size);
         memcpy(tmp_buf, data + cur_offset, length);
         rtos_qspi_flash_erase(
                  qspi_flash_ctx,
                  addr + cur_offset,
                  sector_size);
         rtos_qspi_flash_write(
                  qspi_flash_ctx,
                  (uint8_t *) tmp_buf,
                  addr + cur_offset,
                  sector_size);
      }
      rtos_qspi_flash_unlock(qspi_flash_ctx);
      cur_offset += length;
   } while(cur_offset < (size - 1));

   vPortFree(tmp_buf);
} else {
   rtos_printf("Insufficient space for upgrade image\n");
}

It is advised to perform this operation in blocks rather than full image size to reduce memory usage. The buffer can be populated over the desired transport method, such as USB, I2C, etc.

Reading the Data Partition Image

To read back the data partition image:

unsigned addr = rtos_dfu_image_get_data_partition_addr(dfu_image_ctx);
unsigned size = rtos_qspi_flash_size_get(qspi_flash_ctx);

unsigned char *buf = pvPortMalloc(sizeof(unsigned char) * size);

rtos_qspi_flash_read(
      qspi_flash_ctx,
      (uint8_t *)buf,
      addr,
      size);

// buf now contains the data partition image contents

It is advised to perform this operation in blocks rather than full image size to reduce memory usage. The data partition will likely be too large to read into SRAM in a read single operation. Once the buffer is populated from flash, it can be sent over the desired transport method, such as USB, I2C, etc.

Writing the Data Partition Image

To overwrite the current data partition image:

// Assuming buf contains the image data
// and size contains the size in bytes

unsigned addr = rtos_dfu_image_get_data_partition_addr(dfu_image_ctx);
unsigned end_addr = rtos_qspi_flash_size_get(qspi_flash_ctx);
unsigned bytes_avail = end_addr - addr;

size_t sector_size = rtos_qspi_flash_sector_size_get(qspi_flash_ctx);

if(size < bytes_avail) {
   unsigned char *tmp_buf = pvPortMalloc(sizeof(unsigned char) * sector_size);
   unsigned cur_offset = 0;
   do {
      unsigned length = (size - (cur_offset - addr)) >= sector_size ? sector_size : (size - (cur_offset - addr));
      rtos_qspi_flash_lock(qspi_flash_ctx);
      {
         rtos_qspi_flash_read(
                  qspi_flash_ctx,
                  tmp_buf,
                  addr + cur_offset,
                  sector_size);
         memcpy(tmp_buf, data + cur_offset, length);
         rtos_qspi_flash_erase(
                  qspi_flash_ctx,
                  addr + cur_offset,
                  sector_size);
         rtos_qspi_flash_write(
                  qspi_flash_ctx,
                  (uint8_t *) tmp_buf,
                  addr + cur_offset,
                  sector_size);
      }
      rtos_qspi_flash_unlock(qspi_flash_ctx);
      cur_offset += length;
   } while(cur_offset < (size - 1));

   vPortFree(tmp_buf);
} else {
   rtos_printf("Insufficient space for data partition image\n");
}

It is advised to perform this operation in blocks rather than full image size to reduce memory usage. The buffer can be populated over the desired transport method, such as USB, I2C, etc.