Hello,
I am trying to implement a bootloader application.
In order to start understanding how bootloading can be done, a use case is devised. After successfully having completed this simple use case, the basic functionality can be augmented and scaled for external memory or for the emulated EEPROM. The possibilities are there.
The use case:
- Load the F021 Flash API into RAM to gain erase/reprogram access to Flash Bank 0 (main flash).
- Erase a sector in the flash bank 0 in order to verify that the F021 is loaded in RAM.
- Use the F021 to reprogram the sector with data from another sector in the same flash bank.
I am using the bootloader example provided from TI.
The steps I have taken so far:
- In the linker file (sys_link.cmd)
-
- I have used SPNU515C for the memory layout. The origin of each memory section is aligned with the beginning addresss of a Flash sector, as specified in SPNU515C (page 113), and noted as important by Joe Josn in .
- The F021 Flash API resides in its own memory section (FLASH_API).
- The memory section which I want to erase and program is called FLASH_COPY.
-
MEMORY { /* Sector 0 */ VECTORS (X) : o=0x00000000 l=0x00001000 BOOT_LOAD (RX) : o=0x00001000 l=0x00001000 /* Bootloader resides here */ FLASH_API (RX) : o=0x00002000 l=0x00002000 /* F021 API resides here */ /* Sectors 1..14 */ FLASH0 (RX) : o=0x00004000 l=0x0011BFFF /* Sector 15 */ FLASH_COPY (RX) : o=0x00120000 l=0x0001FFFF f=0x5A5A5A STACKS (RW) : o=0x08000000 l=0x00010500 RAM (RW) : o=0x08010500 l=0x0001fb00 /* USER CODE BEGIN (2) */ /* USER CODE END */ }
SECTIONS { .intvecs : {} > VECTORS .text : {} > FLASH0 .const : {} > FLASH0 .cinit : {} > FLASH0 .pinit : {} > FLASH0 .bss : {} > RAM .data : {} > RAM .sysmem : {} > RAM /* USER CODE BEGIN (4) */ boot_ldr : {sys_core_afw.obj (.text)} > BOOT_LOAD eabi_start : {sys_startup_afw.obj (.text)} > BOOT_LOAD flash_api : { fapi_usr_func.obj (.text) bl_flash.obj (.text) -l F021_API_CortexR4_BE_V3D16.lib (.text) } load = FLASH_API, run = RAM, LOAD_START(api_load), RUN_START(api_run), LOAD_SIZE(api_size) /* USER CODE END */ }
- In the startup sequence (sys_startup.c & sys_core.asm)
-
- The CPU is switched back to Supervisor Mode at the end of the _coreInitRegisters_ function.
-
.... ; Switch to Undefined Instruction Mode (M = 11011) cps #27 mov lr, r0 mrs r1,cpsr msr spsr_cxsf, r1 ; Switch to System Mode ( Shares User Mode registers ) (M = 11111) cps #31 mov lr, r0 mrs r1,cpsr msr spsr_cxsf, r1 ; Switch back to Supervisor Mode (M = 10011) - Bootloader cps #19 mov lr, r0 mrs r1,cpsr msr spsr_cxsf, r1 ; ARM Modes - cortex r4 manual ARM DDI 0363G p.56
-
-
- Afterwards, I give full read/write data permission using the MPU access control registers, as mentioned in the Cortex-R4F techincal reference manual on page 126 (ARM DDI 0363G, ID041111; p.126/436)
-
; MPU cortex r4 ARM DDI 0363G p.184 mrc p15, #0x00, r2, c1, c0, #0x02 orr r2, r2, #0xF00000 mcr p15, #0x00, r2, c1, c0, #0x02 mov r2, #0x40000000 fmxr fpexc, r2 ; Read/Write full access ARM DDI 0363G p.126 mrc p15, #0x00, r2, c6, c1, #0x04 mov r2, #0x03 mcr p15, #0x00, r2, c6, c1, #0x04 mov r2, #0x40000000 fmxr fpexc, r2
-
- The Flash is initialized in Pipeline mode to enable read/write at 160MHz (SPNU515C; p.288).
- The Flash is initialized in Pipeline mode to enable read/write at 160MHz (SPNU515C; p.288).
/** - Setup flash read mode, address wait states and data wait states */ flashWREG->FRDCNTL = 0x00000000U | (uint32)((uint32)3U << 8U) | (uint32)((uint32)1U << 4U) | 1U;
- The "Bootloader"
-
- To copy the flash API in RAM, I opted for a C function instead of assembly. The CI Pipeline in our company can analyze C code but not Assembly code. The code I found on another E2E Thread, which I have not noted down!
- I use the linker symbols following SPNU118W, Section 8.6.1 Using Linker Symbols in C/C++ Applications
- I flush the Pipeline after every function call even though it is not necessary.
-
extern uint8_t api_load; extern uint8_t api_run; extern uint8_t api_size; /* Size of F021 API in u32 words */ #define API_U32_WORD_COUNT (uint32_t)((uint32_t)(&api_size) / sizeof(uint32_t) ) /* The Flash address to write to */ #define ADDR_FLASH_COPY 0x00120000 #define ADDR_FLASH_API 0x00002000 /* Flash - Bank 0, EEPROM - Bank 7 */ #define BANK_0 0U #define BANK_7 7U #define BANK_0_SECTOR_15 0x8000U void fn_copy_api_to_ram(uint8_t *p_load, uint8_t *p_start, uint32_t u32_size) { do { *p_start = *p_load; p_start++; p_load++; } while (--u32_size); return; } void fn_updater_util(void) { /* First copy the FLASH API to RAM ** in order to write to FLASH Bank 0 */ fn_copy_api_to_ram( (uint8_t*)&api_load, (uint8_t*)&api_run, (uint32_t)&api_size); uint32_t u32_fapi_res = (uint32_t)0U; u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ); u32_fapi_res = Fapi_setActiveFlashBank(BANK_0); u32_fapi_res = Fapi_enableMainBankSectors(BANK_0_SECTOR_15); while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady ); while( FAPI_GET_FSM_STATUS != Fapi_Status_Success ); u32_fapi_res = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector, (uint32_t*)ADDR_FLASH_COPY); Fapi_flushPipeline(); while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy ); while( FAPI_GET_FSM_STATUS != Fapi_Status_Success ); u32_fapi_res = FAPI_GET_FSM_STATUS; u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ); u32_fapi_res = Fapi_setActiveFlashBank(BANK_0); u32_fapi_res = Fapi_enableMainBankSectors(BANK_0_SECTOR_15); while( FAPI_CHECK_FSM_READY_BUSY != Fapi_Status_FsmReady ); while( FAPI_GET_FSM_STATUS != Fapi_Status_Success ); uint8_t u8_dummy_buff[4] = { 0xBA, 0xD0, 0xBA, 0xD0 }; u32_fapi_res = Fapi_issueProgrammingCommand((uint32_t *)ADDR_FLASH_COPY, &u8_dummy_buff[0], 4, 0U, 0U, Fapi_AutoEccGeneration); while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy ); u32_fapi_res = FAPI_GET_FSM_STATUS; return; }
The problem I am facing:
1. When using the debugger, if I step over the Fapi_issueAsyncCommandWithAddress() function, It works without any problems, and I can see the erased Flash in the Memory browser. If I set a breakpoint after the function and press Resume Execution at program begin, it causes a prefetchEntry.
2. When I step into the assembly code of Fapi_issueProgrammingCommand(), it works without any problems and reprograms the newly erased Flash! When I try to step over the function, it causes a prefetchEntry.
I do not know how to proceed further and this is proving to be a blocker. Thank you in advance!
Kind Regards,
Mihail