1 Introduction
RT1060 MCUXpresso SDK provide the ota_bootloader project, download link:
https://mcuxpresso.nxp.com/en/welcome
ota_bootloader path:
SDK_2_10_0_EVK-MIMXRT1060\boards\evkmimxrt1060\bootloader_examples\ota_bootloader
this ota_bootloader can let the customer realize the on board app update, the RT1060 OTA bootloader mainly have the two functions:
ISP method is from the flashloader, the flashloader put the code in the internal RAM, when use it, normally RT chip need to enter the serial download mode, and use the sdphost download the flashloader to the internal RAM, then run it to realize the ISP function. But OTA_bootloader will put the code in the flash directly, RT chip can run it in the internal boot mode directly, each time after chip reset, the code will run the ota_bootloader at first, this time, customer can use the blhost to communicate the RT chip with UART/USB HID directly to download the APP code. So, to the ISP function in the OTA_bootloader, customer also can use it as the ISP secondary bootloader to update the APP directly. Then reset after the 5 seconds timeout, if the APP area is valid, code will jump to the APP and run APP.
To the ota_bootloader swap and rollback function, customer can use the provided API in the APP directly to realize the APP update, run the different APP, swap and rollback to the old APP.
This document will give the details about how to use the ota_bootloader ISP function to update the APP, how to modify the customer application to match the ota_bootloader, how to resolve the customer APP issues which need to use the SDRAM with the ota_bootloader, how to use the ota_bootloader API to realize the swap and rollback function, and the related APP prepare.
2 OTA bootloader ISP usage
Some customers need the ISP secondary bootloader function, as the flashloader need to put in the internal RAM, so customer can use the ota_bootloader ISP function realize the secondary bootloader requirement, to this method, customer mainly need to note two points:
1) APP need to add the ota_header to meet the ota_bootloader demand.
2) APP use the SDRAM, ota_bootloader need to add DCD memory
2.1 application modification
OTA_bootloader located in the flash from 0x60000000, APP locate from 0x60040000. We can find this from the ota_bootloader bootloader_config.h file:
#define BL_APP_VECTOR_TABLE_ADDRESS (0x60040000u)
From 0x60040000, the first 0X400 should put the ota_header, then the real APP code is put from 0x60040400.
Now, take the SDK evkmimxrt1060_iled_blinky project as an example, to modify it to match the ota_bootloader.
Application code need to add these files:
ota_bootloader_hdr.c,
ota_bootloader_board.h,
ota_bootloader_supp.c,
ota_bootloader_supp.h
These files can be found from the evkmimxrt1060_lwip_httpssrv_ota project, put the above files in the led_blinky source folder.
2.1.1 memory modification
APP memory start address modify from 0x60000000 to 0x60040000, which is the ota_bootloader defined address。
Fig 1
2.1.2 ota_hdr related files add
In the led_blinky project source folder, add the mentioned ota_bootloader related files.
Fig 2
2.1.3 linker file modification
In the evkmimxrt1060_iled_blinky_debug.ld, add boot_hdr, length is 0X400.
We can use the MCUXpresso IDE linkscripts folder, add the .ldt files to modify the linker file.
Here, in the project, add one linkscripts folder, add the boot_hdr_MIMXRT1060.ldt file, build .
Fig 3
After the build, we can find the ld file already add the ota_header in the first 0x400 range.
Fig 4
The above is the generated evkmimxrt1060_iled_blinky_ota_0x60040000.bin file, we can find already contains the boot_hdr.
From offset 0x400, will put the real APP code.
2.2 ISP test related command
Test board is MIMXRT1060-EVK, download the evkmimxrt1060_ota_bootloader project at first, can use the mcuxpresso IDE download it directly, then press the reset button, put the blhost and evkmimxrt1060_iled_blinky_ota_0x60040000.bin in the same folder, use the following command:
blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
blhost.exe -t 2048000 -u 0x15a2,0x0073 -j -- flash-erase-region 0x60040000 0x6000 9
blhost.exe -t 5242000 -u 0x15a2,0x0073 -j -- write-memory 0x60040000 evkmimxrt1060_iled_blinky_ota_0x60040000.bin
blhost.exe -t 5242000 -u 0x15a2,0x0073 -j -- read-memory 0x60040000 0x6000 flexspiNorCfg.dat 9
Fig 5
After the download is finished, press the reset, wait 5 seconds, it will jump to the app, we can find the MIMXRT1060-EVK on board led is blinking. This method realize the flash ISP bootloader downloading and the app working.
The above command is using the USB HID to download, if need to use the UART, also can use command like this:
blhost.exe -t 50000 -p COM45,19200 -j -- get-property 1 0
blhost.exe -t 50000 -p COM45,19200 -j -- flash-erase-region 0x60040000 0x6000 9
blhost.exe -t 50000 -p COM45,19200 -j -- write-memory 0x60040000 evkmimxrt1060_iled_blinky_ota_0x60040000.bin
blhost.exe -t 50000 -p COM45,19200 -j -- read-memory 0x60040000 0x6000 flexspiNorCfg.dat 9
To the UART communication, as the ota_bootloader auto baud detect issues, it’s better to use the baudrate not larger than 19200bps, or in the ota_bootloader code, define the fixed baudrate, eg, 115200.
2.3 Bootloader DCD consideration
Some customer use the ota_bootloader to associate with their own application, which is used the external SDRAM, and find although the downloading works, but after boot, the app didn’t run successfully. In the APP code, it add the DCD configuration, but as the ota_bootloader already put in the front of the QSPI, app will use the ota_hdr, which will delete the dcd part, so, to this situation, customer can add the dcd in the ota_bootloader. The SDK ota_bootloader didn’t add the dcd part in default.
Now, modify the ota_bootloader at first, then prepare the sdram app and test it.
2.3.1 Ota_bootloader add dcd
2.3.1.1 add dcd files
ota_bootloader add dcd.c dcd.h, these two files can be found from the SDK hello_world project. Copy these two files to the ota_bootloader board folder. From the dcd.c code, we can see, dcd_data[] array is put in the “.boot_hdr.dcd_data” area, and it need to define the preprocessor:
XIP_BOOT_HEADER_DCD_ENABLE=1
2.3.1.2 add dcd linker code
Modify the mcuxpresso IDE ld files, and add the dcd range.
.ivt : AT(ivt_begin)
{
. = 0x0000 ;
KEEP(* (.boot_hdr.ivt)) /* ivt section */
. = 0x0020 ;
KEEP(* (.boot_hdr.boot_data)) /* boot section */
. = 0x0030 ;
KEEP(*(.boot_hdr.dcd_data))
__boot_hdr_end__ = ABSOLUTE(.) ;
. = 0x1000 ;
} > m_ivt
Fig 6
0x60001000 : IVT
0x6000100c : DCD entry point
0x60001020 : boot data
0x60001030 : DCD detail data
2.3.1.3 add IVT dcd entry point
ota_bootloader->MIMXRT1062 folder->hardware_init_MIMXRT1062.c,modify the image_vector_table, fill the DCD address to the dcdc_data array address as the dcd entry point.
Fig 7
Until now, we finish the ota_bootloader dcd add, build the project, generate the image, we can find, DCD already be added to the ota_bootloader image.
Fig 8
DCD entry point in the IVT and the DCD data is correct, we can burn this modified ota_bootloader to the MIMXRT1060-EVK board.
2.3.2 SDRAM app prepare
Still based on the evkmimxrt1060_iled_blinky project, just put some function in the SDRAM. From memory, we can find, the SRAM is in the RAM4:
Fig 9
In the led_blinky.c, add this header:
#include <cr_section_macros.h>
Then, put the systick delay code to the RAM4 which is the SDRAM area.
__RAMFUNC(RAM4) void SysTick_DelayTicks(uint32_t n)
{
g_systickCounter = n;
while (g_systickCounter != 0U)
{
}
}
Now, we already finish the simple SDRAM app, we also can test it, and put the breakpoint in the SysTick_DelayTicks, we can find the address is also the SDRAM related address, generate the evkmimxrt1060_iled_blinky1_SDRAM_0x60040000.bin.
If use the old ota_bootloader to download this .bin, we can find the led is not blinking.
2.3.3 Test result
Command refer to chapter 2.2 ISP test related command, download the evkmimxrt1060_iled_blinky1_SDRAM_0x60040000.bin with the new modified ota_bootloader project, we can find, after reset, the led will blink. So the SDRAM app works with the modified ota_bootloader.
3 OTA bootloader swap and rollback
OTA bootloader can realize the swap and rollback function, this part will test the ota_bootloader swap and rollback, prepare two apps and download to the different partition area, then use the UART input char to select the swap or rollback function, to check the which app is running.
3.1 memory map
ota bootloader memory information.
Fig 10
The above map is based on the external 8Mbyte QSPI flash.
OTA bootloader: RT SDK ota bootloader code
Boot meta 0: contains 3 partition start address, size etc. information, ISP peripheral information.
Boot meta 1: contains 3 partition start address, size etc. information, ISP peripheral information.
Swap meta 0: bootloader will use meta data to do the swap operation
Swap meta 1: bootloader will use meta data to do the swap operation
Partition 1: APP1 location
Partition 2: APP2 location
Scratch part: APP1 backup location, start point is before 0x60441000, which is enough to put APP1 and multiple sector size, eg, APP1 is 0X5410, sector size is 0x1000, APP1 need 6 sectors, so the scratch start address is 0x60441000-0x6000=0x43b000.
User data: user used data area
3.2 swap and rollback basic
Fig11
The APP1 and APP2 put in the partition1 and partition2 need to contains the ota_header which meet the bootloader demand, bootloader will check the APP CRC, if it passed, then will boot the app, otherwise, it will enter the ISP mode. Partition2 image need to has the valid header, otherwise, swap will be failed.
Swap function will erase partition2 scratch area, then put the partition1 code to the scratch, erase the partition 1 position, and write the partition 2 image to the partition1 position.
Rollback function will run the previous APP1, erase the partition 2 position, copy the parititon 1 image back to the partition 2, erase partition 1 position, copy partition 2 scratch image back to partition 1.
3.2.1 boot meta
boot_meta 0: 0x0x6003c000 size: 0x20c
boot_meta 1: 0x0x6003d000 size: 0x20c
OTA bootloader can read boot meta from the two different address, when the two address meta are valid(tag is 'B', 'L', 'M', 'T'), bootloader will choose the bigger version meta. If both meta is not valid, bootloader will copy default boot meta data to the boot meta 0 address.
Boot meta contains 3 partition start address, size information. SDK demo can call bootloader API to find the partition information, then do the image program.
Boot meta also contains the ISP peripheral information, the timeout(5s) information, the structure is:
//!@brief Partition information table definitions
typedef struct
{
uint32_t start; //!< Start address of the partition
uint32_t size; //!< Size of the partition
uint32_t image_state; //!< Active/ReadyForTest/UnderTest
uint32_t attribute; //!< Partition Attribute - Defined for futher use
uint32_t reserved[12]; //!< Reserved for future use
} partition_t;
//!@brief Bootloader meta data structure
typedef struct
{
struct
{
uint32_t wdTimeout;
uint32_t periphDetectTimeout;
uint32_t enabledPeripherals;
uint32_t reserved[12];
} features;
partition_t partition[kPartition_Max];//16*4*7 bytes
uint32_t meta_version;
uint32_t patition_entries;
uint32_t reserved0;
uint32_t tag;
} bootloader_meta_t;
3.2.2 swap meta
Swap meta 0 : 0x6003e000, size 0x50
Swap meta 1 : 0x6003f000, size 0x50
OTA bootloader will read the swap meta from 2 different place, if it is not valid, bootloader will set the default data to swap meta 0(0x6003e000). If both image are valid, bootloader will choose the bigger version meta.
Bootloader will refer to the meta data to do the swap operation, sometimes, after reset, meta data will be modified automatically. It mainly relay on the swap_type:
Modify meta swap_type to kSwapType_Test.
Reset, as the meta data is kSwapType_Test, bootloader can do the rollback.
after operation, swap_type change to kSwapType_None.
bootloader will write kSwapType_Test to the meta, after reset, bootloader will refer to kSwapType_Test to do the operation.
After reset, modify meta data to kSwapType_Permanent, then the APP will boot with partition 1.
Swap structure:
//!@brief Swap progress definitions
typedef struct
{
uint32_t swap_offset; //!< Current swap offset
uint32_t scratch_size; //!< The scratch area size during current swapping
uint32_t swap_status; // 1 : A -> B scratch, 2 : B -> A
uint32_t remaining_size; //!< Remaining size to be swapped
} swap_progress_t;
typedef struct
{
uint32_t size;
uint32_t active_flag;
} image_info_t;
//!@brief Swap meta information, used for the swapping operation
typedef struct
{
image_info_t image_info[2]; //!< Image info table
#if !defined(BL_FEATURE_HARDWARE_SWAP_SUPPORTED) || (BL_FEATURE_HARDWARE_SWAP_SUPPORTED == 0)
swap_progress_t swap_progress; //!< Swap progress
#endif
uint32_t swap_type; //!< Swap type
uint32_t copy_status; //!< Copy status
uint32_t confirm_info; //!< Confirm Information
uint32_t meta_version; //!< Meta version
uint32_t reserved[7]; //!< Reserved for future use
uint32_t tag;
} swap_meta_t;
3.3 Common used API
Bootloader provide the API for the customer to use it, the common used API are:
3.3.1 update_image_state
update swap meta data, before update, it will check the partition1 image valid or not, if image is not valid, swap meta data will not be updated, and return failure.
3.3.2 get_update_partition_info
get partition information, then define the image program address.
3.3.3 get_image_state
get the current boot image status.
None/permanent/UnderTest
3.4 Swap rollback APP prepare
Prepare two APPs: APP1 and APP2 bin file, and use the USB HID download to the partition1 and paritition 2. After reset, run APP1 in default, then use the COM input to select the swap and rollback function.
Code is:
int main(void)
{
char ch;
status_t status;
/* Board pin init */
BOARD_InitPins();
BOARD_InitBootClocks();
/* Update the core clock */
SystemCoreClockUpdate();
BOARD_InitDebugConsole();
PRINTF("\r\n------------------hello world + led blinky demo 2.------------------\r\n");
PRINTF("\r\nOTA bootloader test...\r\n"
"1 - ReadyForTest\r\n"
"3 - kSwapType_Permanent\r\n"
"4 - kSwapType_Rollback\r\n"
"5 - show image state\r\n"
"6 - led blinking for 5times\r\n"
"r - NVIC reset\r\n");
// show swap state in swap meta
get_image_swap_state();
/* Set systick reload value to generate 1ms interrupt */
if (SysTick_Config(SystemCoreClock / 1000U))
{
while (1)
{
}
}
while(1)
{
ch = GETCHAR();
switch(ch)
{
case '1':
status = bl_update_image_state(kSwapType_ReadyForTest);
PRINTF("update_image_state to kSwapType_ReadyForTest status: %i\n", status);
if (status != 0)
PRINTF("update_image_state(kSwapType_ReadyForTest): failed\n");
else
NVIC_SystemReset();
break;
case '3':
status = bl_update_image_state(kSwapType_Permanent);
PRINTF("update_image_state to kSwapType_Permanent status: %i\n", status);
if (status != 0)
PRINTF("update_image_state(kSwapType_Permanent): failed\n");
else
NVIC_SystemReset();
break;
case '4':
status = bl_update_image_state(4); //
PRINTF("update_image_state to kSwapType_Rollback status: %i\n", status);
if (status != 0)
PRINTF("update_image_state(kSwapType_Rollback): failed\n");
else
NVIC_SystemReset();
break;
case '5':
// show swap state in swap meta
get_image_swap_state();
break;
case '6':
Led_blink10times();
break;
case 'r':
NVIC_SystemReset();
break;
}
}
}
When download the APP, need to use the correct ota_header in the first 0x400 area, otherwise, swap will failed.
const boot_image_header_t ota_header = {
.tag = IMG_HDR_TAG,
.load_addr = ((uint32_t)&ota_header) + BL_IMG_HEADER_SIZE,
.image_type = IMG_TYPE_XIP,
.image_size = 0,
.algorithm = IMG_CHK_ALG_CRC32,
.header_size = BL_IMG_HEADER_SIZE,
.image_version = 0,
.checksum = {0xFFFFFFFF},
};
This is a correct sample:
Fig 12
Image size and checksum need to use the real APP image information, in the attached file, provide one image_header_padding.exe, it can input the none ota header image, then it will output the whole image which add the ota_header contains the image size and the image crc data in the first 0x400 range.
3.5 Test steps and result
Prepare the none header APP1 evkmimxrt1060_APP1_0X60040400.bin, APP2 image evkmimxrt1060_APP2_0X60240400.bin, and put blhost.exe, image_header_padding.exe in the same folder. APP1 and APP2 just the printf version is different, one is version1, another is version2.
Printf result:
hello world + led blinky demo 1
hello world + led blinky demo 2
Attached OTAtest folder is used for test, but need to download the blhost.exe from the below link, and copy the blhost.exe to the OTAtest folder.
Then run the following bat command:
image_header_padding.exe evkmimxrt1060_APP1_0X60040400.bin 0x60040400
sleep 20
blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
sleep 20
blhost.exe -u -t 1000000 -- flash-erase-region 0x6003c000 0x4000
sleep 50
blhost -u -t 5000 -- flash-erase-region 0x60040000 0x10000
sleep 50
blhost -u -t 5000 -- write-memory 0x60040000 boot_img_crc32.bin
sleep 100
image_header_padding.exe evkmimxrt1060_APP2_0X60240400.bin 0x60040400
sleep 20
blhost -u -t 5000 -- flash-erase-region 0x60240000 0x10000
sleep 50
blhost -u -t 5000 -- flash-erase-region 0x6043b000 0x10000
sleep 50
blhost -u -t 5000 -- write-memory 0x60240000 boot_img_crc32.bin
sleep 100
pause
The function is to generate the APP1 with the correct ota_header, erase parititon 1,program APP1 to partition 1, generate the APP2 with the correct ota_header, erase partition 2 and scratch area, program APP2 to partition 2,
Run the .bat file should in 5 seconds after reset, then use the ISP to connect it:
blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
ota_bootloader can use the ota_bootloader project download directly to the 0X60000000 area.
After downloading, reset the chip, and wait for 5 seconds, the APP will run.
This is the test result:
Fig 13
From the test result, we can find, in the first time boot, APP1 running, image state: none
Input 1, do the swap, will find the APP2 running, image state: undertest
Input 3, select permanent, reset will find, still APP2 running, image state: permanent
Input 4, choose rollback, reset will find APP1 running, image states: none
Until now, finish the swap and rollback function.
Input 6, will find the APP contains the SDRAM led blinky is working.
Some customer also need the IAR version, so here attach the iar app version.
Based on the led_blinky iar project, the modification is:
1. Copy the ota_bootlaoder_board.h, ota_bootloader_hrd.c, ota_bootloader_supp.c, ota_bootloader_supp.h to the source folder
2. delete the XIP folder
3. led_blinky.c add:
#include "ota_bootloader_supp.h"
4. the MIMXRT1062xxxxx_flexspi_nor.icf modified like this:
/*
** ###################################################################
** Processors: MIMXRT1062CVJ5A
** MIMXRT1062CVL5A
** MIMXRT1062DVJ6A
** MIMXRT1062DVL6A
**
** Compiler: IAR ANSI C/C++ Compiler for ARM
** Reference manual: IMXRT1060RM Rev.1, 12/2018 | IMXRT1060SRM Rev.3
** Version: rev. 0.1, 2017-01-10
** Build: b210227
**
** Abstract:
** Linker file for the IAR ANSI C/C++ Compiler for ARM
**
** Copyright 2016 Freescale Semiconductor, Inc.
** Copyright 2016-2021 NXP
** All rights reserved.
**
** SPDX-License-Identifier: BSD-3-Clause
**
** http: www.nxp.com
** mail: support@nxp.com
**
** ###################################################################
*/
define symbol m_ota_boot_hdr_start = 0x60040000;
define symbol __ram_vector_table_size__ = isdefinedsymbol(__ram_vector_table__) ? 0x00000400 : 0;
define symbol __ram_vector_table_offset__ = isdefinedsymbol(__ram_vector_table__) ? 0x000003FF : 0;
define symbol m_interrupts_start = 0x60040400;
define symbol m_interrupts_end = 0x600407FF;
define symbol m_text_start = 0x60040800;
define symbol m_text_end = 0x6023FFFF;
define symbol m_interrupts_ram_start = 0x20000000;
define symbol m_interrupts_ram_end = 0x20000000 + __ram_vector_table_offset__;
define symbol m_data_start = m_interrupts_ram_start + __ram_vector_table_size__;
define symbol m_data_end = 0x2001FFFF;
define symbol m_data2_start = 0x20200000;
define symbol m_data2_end = 0x202BFFFF;
define symbol m_qacode_start = 0x00000000;
define symbol m_qacode_end = 0x0001FFFF;
/* Sizes */
if (isdefinedsymbol(__stack_size__)) {
define symbol __size_cstack__ = __stack_size__;
} else {
define symbol __size_cstack__ = 0x0400;
}
if (isdefinedsymbol(__heap_size__)) {
define symbol __size_heap__ = __heap_size__;
} else {
define symbol __size_heap__ = 0x0400;
}
define exported symbol __NCACHE_REGION_START = m_data2_start;
define exported symbol __NCACHE_REGION_SIZE = 0x0;
define exported symbol __VECTOR_TABLE = m_interrupts_start;
define exported symbol __VECTOR_RAM = isdefinedsymbol(__ram_vector_table__) ? m_interrupts_ram_start : m_interrupts_start;
define exported symbol __RAM_VECTOR_TABLE_SIZE = __ram_vector_table_size__;
define memory mem with size = 4G;
define region TEXT_region = mem:[from m_interrupts_start to m_interrupts_end]
| mem:[from m_text_start to m_text_end];
define region QACODE_region = mem:[from m_qacode_start to m_qacode_end];
define region DATA_region = mem:[from m_data_start to m_data_end-__size_cstack__];
define region DATA2_region = mem:[from m_data2_start to m_data2_end];
define region CSTACK_region = mem:[from m_data_end-__size_cstack__+1 to m_data_end];
define block CSTACK with alignment = 8, size = __size_cstack__ { };
define block HEAP with alignment = 8, size = __size_heap__ { };
define block RW { readwrite };
define block ZI { zi };
define block NCACHE_VAR { section NonCacheable , section NonCacheable.init };
define block QACCESS_CODE { section CodeQuickAccess };
initialize by copy { readwrite, section .textrw, section CodeQuickAccess };
do not initialize { section .noinit };
place at address mem: m_interrupts_start { readonly section .intvec };
place at address mem:m_ota_boot_hdr_start { object ota_bootloader_hdr.o };
keep { object ota_bootloader_hdr.o };
place in TEXT_region { readonly };
place in DATA_region { block RW };
place in DATA_region { block ZI };
place in DATA_region { last block HEAP };
place in DATA_region { block NCACHE_VAR };
place in CSTACK_region { block CSTACK };
place in QACODE_region { section .textrw};
place in QACODE_region { block QACCESS_CODE };
Then build the project, to get the evkmixrt1060_iled_blinky_ota_0x60040000_iar.bin
After download the ota_bootloader, use the blhost to connect it after board reset:
C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost.exe -t 50000 -u 0x15a2,0x0073 -j -- get-property 1 0
{
"command" : "get-property",
"response" : [ 1258424320 ],
"status" : {
"description" : "0 (0x0) Success.",
"value" : 0
}
}
C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost.exe -t 2048000 -u 0x15a2,0x0073 -j -- flash-erase-region 0x60040000 0x6000 9
{
"command" : "flash-erase-region",
"response" : [],
"status" : {
"description" : "0 (0x0) Success.",
"value" : 0
}
}
C:\KerryPC\IMXRTCode\Question\RT1060\bootloader\AN12604\kerry\OTAtest>blhost.exe -t 5242000 -u 0x15a2,0x0073 -j -- write-memory 0x60040000 evkmixrt1060_iled_blinky_ota_0x60040000_iar.bin
{
"command" : "write-memory",
"response" : [],
"status" : {
"description" : "0 (0x0) Success.",
"value" : 0
}
}
Find the iar app in the original post.