KW36 - Storing an OTAP software update for other MCU's

Showing results for 
Search instead for 
Did you mean: 

KW36 - Storing an OTAP software update for other MCU's

KW36 - Storing an OTAP software update for other MCU's


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 to store code for another MCU and later send the software update to this device as depicted in the figure below. 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:pastedImage_53.png
    2. For internal storage:pastedImage_2.png
  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"))) =
       #error "Compiler unknown!"
       {0x00, 0x02},
      #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1)
      #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. */
       uint32_t value;
      #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1)
       uint8_t defaultSBKEK[SBKEK_SIZE] = {DEFAULT_DEMO_SBKEK};
       uint32_t status;
      if( mNewImageReady )
      bootFlag.value = gBootValueForTRUE_c;
      status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.newBootImageAvailable,
       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,
      #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,
       if( status == kStatus_FLASH_Success )
       mNewImageReady = FALSE;

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 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 should 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 to send the software update to the "MCU X" (as well as the bootloader for the MCU X). The handling your protocol can be integrated into the OTAP client code replacing "ResetMCU()" (The same code removed in step 4) in the code by "APISendSoftwareUpdateToMCUX()" for instance, since at this point the image was successfully sent over the air and stored in the memory of the KW36. 

Labels (3)
Version history
Revision #:
3 of 3
Last update:
a week ago
Updated by: