1.5.2 Bootloader Multi Partition Demo Project

Provides a description of the code generated by the MCC bootloader library for a Multi Partition Project.

Demo Overview:

This section will walk through the high-level operation of the bootloader from a user perspective. It will focus on the high-level interfaces and not go into the low level operation of the application. In a multi-partition or A/B bootloader, the bootloader needs to check multiple items before running the application. Among other things, the bootloader must check if is required, when to verify the application, when to actually copy the code from the download location to the execution location, when to enter bootloader mode and when to actually run the application. These items are outlined in flowchart below and are implemented in main.c and mcc_generated_files\boot\boot_demo.c.

Figure 1-9.  Application Configuration Screen

Starting with the file main.c, after device reset, the first bootloader code called is BOOT_DEMO_Initialize(). This purpose of this code is to initialize anything the bootloader may need to run like extra GPIO or peripheral configuration that is not done in SYSTEM_Initialize(). Following this, the while(1) loop in main() will repeatedly call BOOT_DEMO_Tasks() in a loop as shown below.

int main(void)
{
    // initialize the device
    SYSTEM_Initialize();
    BOOT_DEMO_Initialize();

    while (1)
    {
    // Add your application code
    BOOT_DEMO_Tasks();
    }

    return 1;
}

The implementation of the flow chart is implemented in the code below. It is in no way a complete implementation, but implements the basic features intended as a starting point to build upon. The key functions BOOT_DEMO_Tasks(), UpdateFromDownload() and IsUpdateRequired() are shown below. These three functions implement a majority of the flow chart above. They keep track of state by using the three variables, inBootloadMode, and executionImageRequiresValidation, executionImageValid at the top of the file. Other items that the customer may want to check are described at the top of the code for IsUpdateRequired() below.

Some of the key sections of the below code are discussed in more details in Version Number and Anti Rollback Example Code.

static bool inBootloadMode = false;
static bool executionImageRequiresValidation = true;
static bool executionImageValid = false;

static bool EnterBootloadMode(void)
{
    #warning "Update this function to return 'true' when you want to stay in the bootloader, and 'false' when you want to
    allow a release to the application code"

    /* NOTE: This might be a a push button status on power up, a command from a peripheral,
     * or whatever is specific to your bootloader implementation */

    return false;
}


/*
 The check to see if you want to update or not is somewhat complex. Below
 is a list of the conditions when an update is required:

 #1) The download image is valid and the execution image is invalid.

 #2) Both images are valid, both images have version numbers, and the
 download image version is newer than the execution image version.

 #3) Both images are valid, if the download image has a version and the
 execution image doesn't have a version number (legacy image)

 In all other situations, we shouldn't do an update. Here are some examples,
 but might not be a complete list:

 #1) Download image is invalid

 #2) Both images are valid, but the download image doesn't have a version
 number. You can't confirm the download image is newer, thus we can't
 update.

 #3) Both images are valid, both have version numbers, and the execution
 image version number is newer or the same as the download image version
 number.
*/
static bool IsUpdateRequired(void)
{
    bool downloadVersionPresent;
    bool downloadImageValid;
    uint32_t downloadVersion;

    bool executionVersionPresent;
    uint32_t executionVersion;

    bool updateRequired = false;

    executionVersionPresent = BOOT_VersionNumberGet(EXECUTION_IMAGE, &executionVersion);
    downloadVersionPresent = BOOT_VersionNumberGet(DOWNLOADED_IMAGE, &downloadVersion);

    downloadImageValid = BOOT_ImageVerify(DOWNLOADED_IMAGE);
    executionImageValid = BOOT_ImageVerify(EXECUTION_IMAGE);

    /* We don't need to validate the execution image unless we update it. */
    executionImageRequiresValidation = false;

    if(downloadImageValid == true)
    {
        if(executionImageValid == false)
        {
                /* the download image is valid and
                 * the execution image is not valid = update. In this case we don't
                 * care about the version numbers since the download image is the
                 * only valid image available. */
                updateRequired = true;
            }
            else
            {
            if(downloadVersionPresent == true )
            {
                if(executionVersionPresent == true)
                {
                    if(downloadVersion > executionVersion)
                    {
                        /* both images are valid, both have version numbers, and
                         * the download has a newer version number = update */
                        updateRequired = true;
                    }
                }
                else
                {
                    /* both images are valid, the download has a version number,
                     * the executable does not (legacy - thus older) = update*/
                    updateRequired = true;
                }
            }
        }
    }

    return updateRequired;
}

static void UpdateFromDownload(void)
{
    BOOT_CopyUnlock();
    if( IsUpdateRequired() == true )
    {
        /* We've updated the application image and now it needs to be copied to the execution space.
           It needs to be re-verified after being copied. */
        executionImageRequiresValidation = true;

        BOOT_ImageCopy(EXECUTION_IMAGE, DOWNLOADED_IMAGE);
    }
    BOOT_CopyLock();
}


void BOOT_DEMO_Tasks(void)
{
    if(inBootloadMode == false)
    {
        /* If the user is requesting entry into the bootloader, enter immediately */
        if( EnterBootloadMode() == true )
        {
            inBootloadMode = true;
            }
            else
            {
                /* Check to see if we need to update the execution image and if so, update it */
                UpdateFromDownload();

            if( executionImageRequiresValidation == true )
            {
                executionImageValid = BOOT_ImageVerify(EXECUTION_IMAGE);
            }

            if(executionImageValid == false)
            {
                inBootloadMode = true;
            }

            if(inBootloadMode == false)
            {
                BOOT_StartApplication();
            }
        }
    }

    (void)BOOT_ProcessCommand();
}