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.
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.
extern uint16_t gBootFlagsSectorBitNo;
void OTA_SetNewImageFlag(void);
extern uint32_t __BootFlags_Start__[];
#define gBootImageFlagsAddress_c ((uint32_t)__BootFlags_Start__)
#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) */
uint16_t gBootFlagsSectorBitNo;
gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);
gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PAGE_SIZE_BYTES);
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.
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.