Storing code for a different MCU using OTAP with FRDM-KW36

Document created by Edgar Eduardo Lomeli Gonzalez Employee on Jan 3, 2020Last modified by Edgar Eduardo Lomeli Gonzalez Employee on Jan 6, 2020
Version 5Show Document
  • View in full screen mode

Introduction

In some applications, is it necessary to keep updated the software running in many MCU's that take part in the system, fortunately, Over The Air Programming, it's a custom Bluetooth LE service developed to send "over the air" software updates for the KW MCU series. FRDM-KW36 SDK already provides the "otap_client" software, that can be used together with the "otap_bootloader" such as it is described in the following community post: Reprogramming a KW36 device using the OTAP Client Software to reprogram the KW36. This example can be modified as well to store the code for another MCU and later send the software update to this device. This post guides you on modifying the OTAP client software to support software updates for other MCU's.

 

Preparing the OTAP client software

The starting point of the following modifications is supposing that there is no need to perform over the air updates for the KW36 MCU, so the use of the "otap_bootloader" is obsolete and will be removed in this example. In other words, KW36 will be programmed only with the "otap_client" code.

 

  1. Open the MCUXpresso settings window (Project->Properties->"C/C++ Build->MCU settings") and configure the following fields. Save the changes.
    1. For external storage:
    2. For internal storage:
  2. Locate the "app_preinclude.h" file, and set the storage method, as follows:
    1. For external storage: #define gEepromType_d       gEepromDevice_AT45DB041E_c
    2. For internal storage: #define gEepromType_d        gEepromDevice_InternalFlash_c
  3. Locate the "main_text_section.ldt" linker script into the "linkscripts" folder, and delete it from the project. 
  4. Search in the project for "OTA_SetNewImageFlag();" and "ResetMCU();" functions in the "otap_client.c" file (source->common->otap_client->otap_client.c) and delete or comment. (For reference, there are 4 in total).
  5. Locate the following code in "OtaSupport.h" (framework->OtaSupport->Interface) and delete or comment.
    1. extern uint16_t gBootFlagsSectorBitNo;
    2. void OTA_SetNewImageFlag(void);
  6. Locate the following code in "OtaSupport.c" (framework->OtaSupport->Source) and delete or comment.
    1. extern uint32_t __BootFlags_Start__[];
      #define gBootImageFlagsAddress_c ((uint32_t)__BootFlags_Start__)
    2. #if !gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d)
      /*! Variables used by the Bootloader */
      #if defined(__IAR_SYSTEMS_ICC__)
      #pragma location = "BootloaderFlags"
      const bootInfo_t gBootFlags =
      #elif defined(__GNUC__)
      const bootInfo_t gBootFlags __attribute__ ((section(".BootloaderFlags"))) =
      #elif defined(__CC_ARM)
      volatile const bootInfo_t gBootFlags __attribute__ ((section(".BootloaderFlags"))) =
      #else
      #error "Compiler unknown!"
      #endif
      {
      {gBootFlagUnprogrammed_c},
      {gBootValueForTRUE_c},
      {0x00, 0x02},
      {gBootFlagUnprogrammed_c},
      #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1)
      {PLACEHOLDER_SBKEK},
      {BOOT_MAGIC_WORD}
      #endif
      };
      #endif /* !gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d) */

       

    3. uint16_t gBootFlagsSectorBitNo;
    4. gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);
    5. gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PAGE_SIZE_BYTES);
    6. void OTA_SetNewImageFlag(void)
      {
      #if (gEepromType_d != gEepromDevice_None_c) && (!gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d))
      /* OTA image successfully written into the non-volatile storage.
      Set the boot flag to trigger the Bootloader at the next CPU Reset. */

      union{
      uint32_t value;
      uint8_t aValue[FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE];
      }bootFlag;
      #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1)
      uint8_t defaultSBKEK[SBKEK_SIZE] = {DEFAULT_DEMO_SBKEK};
      #endif
      uint32_t status;
      if( mNewImageReady )
      {
      NV_Init();
      bootFlag.value = gBootValueForTRUE_c;
      status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.newBootImageAvailable,
      sizeof(bootFlag),
      bootFlag.aValue);

      if( (status == kStatus_FLASH_Success) &&
      FLib_MemCmpToVal(gBootFlags.internalStorageAddr, 0xFF, sizeof(gBootFlags.internalStorageAddr)) )
      {
      bootFlag.value = gEepromParams_StartOffset_c + gBootData_ImageLength_Offset_c;
      status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.internalStorageAddr,
      sizeof(bootFlag),
      bootFlag.aValue);
      }
      #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1)
      if( status == kStatus_FLASH_Success )
      {
      /* Write the default SBKEK for secured OTA */
      status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.sbkek,
      SBKEK_SIZE,
      defaultSBKEK);
      }
      #endif

      if( status == kStatus_FLASH_Success )
      {
      mNewImageReady = FALSE;
      }
      }
      #endif
      }
       

At this point, the FRDM-KW36 can receive and store any image for any MCU and can request a further software update from the OTAP server device. 

 

Adding the API's to reprogram the "MCU X" on OTAP client software

Once the software update has been downloaded from the OTAP Server into the OTAP Client, the developer could request the software update from the OTAP Client to the "MCU X" through a serial protocol such as UART, SPI, CAN, etc. You should develop the API's and the protocol according to the requirements for your system, which will be used to send the software update to the "MCU X" (as well as the bootloader for the MCU X). The handling of the last protocol could be integrated into the OTAP client code replacing "ResetMCU()" (The same code removed in step 4) lines in the code by "APISendSoftwareUpdateToMCUX()" for instance, since at this point the image was successfully sent over the air and stored either in the internal or external memory of the "FRDM-KW36". 

Attachments

    Outcomes