1.8 PRIME Service Bootloader
The PRIME Service Bootloader application implements a bootloader designed to manage firmware images. These images are received through the PRIME upgrade protocol defined in the PRIME specification, but the Bootloader application is not aware of that.
| Name | Path | Boards | 
|---|---|---|
| Service Bootloader | \smartenergy_prime_apps\apps\prime_apps\prime_service_bootloader\bootloader_pic32cxmtg.X | PIC32CXMTG-EK | 
| Service Bootloader | \smartenergy_prime_apps\apps\prime_apps\prime_service_bootloader\bootloader_pic32cxmtsh.X | PIC32CXMTSH-DB | 
Application Example
The PRIME Service Bootloader application implements a bootloader designed to manage firmware images. These images are received through the PRIME upgrade protocol defined in the PRIME specification, but the Bootloader application is not aware of that.
- Non-volatile data storage.
                        The PRIME Service Bootloader needs it to manage the bootloading process and
                        the boot configuration.
- For PIC32CXMT it is implemented using the User
                                Signature.
static void lAPP_BOOTLOADER_UpdateUserSignature(uint8_t pagesCnt, BOOT_STATE state) { /* Update values */ bootConfig[16] = pagesCnt; bootConfig[17] = (uint8_t) state; /* Erase the user signature */ SEFC0_UserSignatureErase(BOOT_USER_SIGNATURE_BLOCK); /* Update the user signature */ (void) SEFC0_UserSignatureWrite((void*) userSignBuf, (uint32_t) BOOT_USER_SIGNATURE_SIZE_64, (SEFC_USERSIGNATURE_BLOCK) BOOT_USER_SIGNATURE_BLOCK, (SEFC_USERSIGNATURE_PAGE) BOOT_USER_SIGNATURE_PAGE); } 
 - For PIC32CXMT it is implemented using the User
                                Signature.
 
- Memory handling. The PRIME Service Bootloader needs to delete, copy and
                        verify pages.
- For PIC32CXMTG it is implemented using the SEFC0
                                peripheral.
static uint8_t lAPP_BOOTLOADER_DeletePage(uint32_t addr) { SEFC0_RegionUnlock(addr); while (SEFC0_IsBusy()) { ; } SEFC0_PageErase(addr); // Function erases 16 pages while (SEFC0_IsBusy()) { ; } return 1; } static uint8_t lAPP_BOOTLOADER_CopyPage(uint32_t srcAddr, uint32_t dstAddr) { uint8_t *page; uint8_t i; (void) memcpy(pageBlock, (uint8_t *) (srcAddr), BOOT_FLASH_16PAGE_SIZE); page = &pageBlock[0]; for (i = 0; i < BOOT_FLASH_PAGES_NUMBER; i++) { if (SEFC0_PageWrite((uint32_t *) page, dstAddr) == false) { return 0; } while (SEFC0_IsBusy()) { ; } page += BOOT_FLASH_PAGE_SIZE; dstAddr += BOOT_FLASH_PAGE_SIZE; } return 1; } static uint8_t lAPP_BOOTLOADER_VerifyPage(uint8_t *ramPage, uint8_t *flashPage, uint16_t pageSize) { uint16_t i = 0; while (i < pageSize) { if (ramPage[i] != flashPage[i]) { return 0; } i++; } return 1; } 
 - For PIC32CXMTG it is implemented using the SEFC0
                                peripheral.
 
Application Functionality
The PRIME Service Bootloader application functionality is very simple as it just reads and writes memory pages according to the information that has been stored previously in the User Signature.
case APP_BOOTLOADER_STATE_INIT:
{
    bool appInitialized = true;
    if (appInitialized) {
        /* Ensure all priority bits are assigned as preemption */
        /* priority bits. */
        NVIC_SetPriorityGrouping(__NVIC_PRIO_BITS);
        __set_BASEPRI(0);
        /* Disable User Signature write protection */
        SEFC0_WriteProtectionSet(0);
        /* Enable write and read User Signature rights */
        /* (block 0 / area 1)  */
        SEFC0_UserSignatureRightsSet(
                SEFC_EEFC_USR_RDENUSB1_Msk | SEFC_EEFC_USR_WRENUSB1_Msk);
        app_bootloaderData.state = APP_BOOTLOADER_STATE_SERVICE_TASKS;
    }
    break;
}- Extract the boot configuration from the User
                        Signature:
/* Read the boot configuration from user signature */ (void) SEFC0_UserSignatureRead((void*) userSignBuf, (uint32_t) BOOT_USER_SIGNATURE_SIZE_64, (SEFC_USERSIGNATURE_BLOCK) BOOT_USER_SIGNATURE_BLOCK, (SEFC_USERSIGNATURE_PAGE) BOOT_USER_SIGNATURE_PAGE); /* Get boot configuration */ bootConfig = userSignBuf + BOOT_CONFIG_OFFSET_USER_SIGN; cfgKey = ((uint32_t) bootConfig[3]) << 24; cfgKey += ((uint32_t) bootConfig[2]) << 16; cfgKey += ((uint32_t) bootConfig[1]) << 8; cfgKey += (uint32_t) bootConfig[0]; 
- Extract the boot information, if the boot configuration is
                        valid:
/* Get boot information */ imageSize = (uint32_t) (bootConfig[7]) << 24; imageSize += (uint32_t) (bootConfig[6]) << 16; imageSize += (uint32_t) (bootConfig[5]) << 8; imageSize += (uint32_t) (bootConfig[4]); origAddr = (uint32_t) (bootConfig[11]) << 24; origAddr += (uint32_t) (bootConfig[10]) << 16; origAddr += (uint32_t) (bootConfig[9]) << 8; origAddr += (uint32_t) (bootConfig[8]); destAddr = (uint32_t) (bootConfig[15]) << 24; destAddr += (uint32_t) (bootConfig[14]) << 16; destAddr += (uint32_t) (bootConfig[13]) << 8; destAddr += (uint32_t) (bootConfig[12]); pagesCounter = bootConfig[16]; bootState = bootConfig[17]; 
- Trigger the firmware swap, if
                        needed:
/* Check if swap fw is needed. If not, load defaults. */ if (lAPP_BOOTLOADER_IsSwapCmd(imageSize, origAddr, destAddr) == true) { /* Swap fw */ (void) lAPP_BOOTLOADER_SwapFwVersion(imageSize, origAddr, destAddr); /* Clear boot configuration (leave configuration key) */ (void) memset(&bootConfig[4], 0, 16); /* Update user signature */ lAPP_BOOTLOADER_UpdateUserSignature(0, BOOT_IDLE); } 
- Start the user
                        application:
/* Set the stack pointer to the start of the firmware application */ __set_MSP(*(int *) (BOOT_FLASH_APP_FIRMWARE_START_ADDRESS)); /* Offset the start of the vector table (first 6 bits must be * zero) */ /* The register containing the offset, from 0x00000000, is at * 0xE000ED08 */ SCB->VTOR = ((uint32_t) BOOT_FLASH_APP_FIRMWARE_START_ADDRESS & SCB_VTOR_TBLOFF_Msk); __DSB(); __ISB(); __enable_irq(); /* * (int *) 0xE000ED08 = FIRMWARE_START_ADDRESS; */ /* Jump to the start of the firmware, casting the address as * function pointer to the start of the firmware. We want to jump * to the address of the reset. */ /* Handler function, that is the value that is being pointed at * position FIRMWARE_RESET_ADDRESS */ void (*runFirmware)(void) = NULL; runFirmware = (void (*)(void))(*(uint32_t *) BOOT_FLASH_APP_FIRMWARE_RESET_ADDRESS); runFirmware(); while (1) { ; } 
