This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
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:
I am using the bootloader example provided from TI.
The steps I have taken so far:
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 */ }
.... ; 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
; 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
/** - Setup flash read mode, address wait states and data wait states */ flashWREG->FRDCNTL = 0x00000000U | (uint32)((uint32)3U << 8U) | (uint32)((uint32)1U << 4U) | 1U;
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
To clarify further, the SYS_CLK_FREQ is set to 160
//***************************************************************************** // // The frequency (MHz) of the crystal used to clock the microcontroller. // // This defines the crystal frequency used by the microcontroller running the // boot loader. // // Depends on: None // Exclusive of: None // Requires: None // //***************************************************************************** #define CRYSTAL_FREQ 16 //MHz #define SYS_CLK_FREQ 160 //MHz
Hello and thank you for the response. I believe that the function is run from RAM too!
An excerpt from sys_startup.c:
/* Configure system response to error conditions signaled to the ESM group1 */ /* This function can be configured from the ESM tab of HALCoGen */ esmInit(); /* initialize copy table */ __TI_auto_init(); /* USER CODE BEGIN (75) */ /* USER CODE END */ /* call the application */ /*SAFETYMCUSW 296 S MR:8.6 <APPROVED> "Startup code(library functions at block scope)" */ /*SAFETYMCUSW 326 S MR:8.2 <APPROVED> "Startup code(Declaration for main in library)" */ /*SAFETYMCUSW 60 D MR:8.8 <APPROVED> "Startup code(Declaration for main in library;Only doing an extern for the same)" */ fn_updater_util(); /* USER CODE BEGIN (76) */ /* USER CODE END */ /*SAFETYMCUSW 122 S MR:20.11 <APPROVED> "Startup code(exit and abort need to be present)" */ exit(0); /* USER CODE BEGIN (77) */ /* USER CODE END */ }
Hello,
Is fn_updater_util() fapi_usr_func()? I don't find fn_updater_util() in your linker command file.
Hello once more!
I have modified the Linker file to include the file in which the fn_updater_util() function resides. It is the bl_main.obj :
boot_ldr : {sys_core_afw.obj (.text)} > BOOT_LOAD eabi_start : {sys_startup_afw.obj (.text)} > BOOT_LOAD /* The linker allocates the sections to a single memory range for running, ** but different memory ranges for loading. */ flash_api : { fapi_usr_func.obj (.text) bl_flash.obj (.text) bl_main.obj (.text) -l F021_API_CortexR4_BE_V3D16.lib (.text) } load = FLASH_API, /* Where to load the section */ run = RAM, /* Where to run the section */ LOAD_START(api_load), /* api_load holds the load addr of the flashAPI section */ RUN_START(api_run), /* api_run holds the run addr of the flashAPI section */ LOAD_SIZE(api_size) /* api_size holds the size of the flashAPI section */ /* api_load, api_run, api_size can be referenced from the copy table. */
Now I am calling the function fn_copy_api_to_ram() directly in sys_startup.c, as in the TI Bootloader example. Excerpt from sys_startup.c:
/* USER CODE BEGIN (74) */ /* USER CODE END */ /* Configure system response to error conditions signaled to the ESM group1 */ /* This function can be configured from the ESM tab of HALCoGen */ esmInit(); /* initialize copy table */ __TI_auto_init(); /* USER CODE BEGIN (75) */ /* USER CODE END */ /* call the application */ /*SAFETYMCUSW 296 S MR:8.6 <APPROVED> "Startup code(library functions at block scope)" */ /*SAFETYMCUSW 326 S MR:8.2 <APPROVED> "Startup code(Declaration for main in library)" */ /*SAFETYMCUSW 60 D MR:8.8 <APPROVED> "Startup code(Declaration for main in library;Only doing an extern for the same)" */ fn_copy_api_to_ram( (uint8_t*)&api_load, (uint8_t*)&api_run, (uint32_t)&api_size); fn_updater_util(); /* USER CODE BEGIN (76) */ /* USER CODE END */ /*SAFETYMCUSW 122 S MR:20.11 <APPROVED> "Startup code(exit and abort need to be present)" */ exit(0); /* USER CODE BEGIN (77) */ /* USER CODE END */ }
Now I am able to step over both functions ( Fapi_issueAsyncCommandWithAddress() and Fapi_issueProgrammingCommand() ) and they do not generate a prefetchEntry.
If I set a breakpoint at the end of the fn_updater_util() function and press Resume after a System reset, it goes into prefetchEntry!
I seem to have stumbled upon the exact problem discussed in this topic:
Prefetch entry when using flash api - Arm-based microcontrollers forum - Arm-based microcontrollers ...
Interrupts are not enabled for our Microcontroller, as it is not foreseen to be so by our architecture!
Kind Regards,
Mihail
A very helpful answer that might be pointing in the correct direction is the one by Anthony F. Seely in this thread: undef entry when using flash api - Arm-based microcontrollers forum - Arm-based microcontrollers - TI...
Could you please explain the reason why in the provided bootloader example, in the sys_intvecs.asm, the Interrupts branch to the application image? Excerpt from sys_intvecs.asm from the TI Bootloader example:
;------------------------------------------------------------------------------- ; interrupt vectors ; Please change the #0x???? for your specified image location defined in bl_config.h b _c_int00 ;0x00 b #0x1FFF8 ;0x04 b #0x1FFF8 ;0x08, Software interrupt b #0x1FFF8 ;0x0C, Abort (prefetch) b #0x1FFF8 ;0x10, Abort (data) reservedEntry b reservedEntry ;0x14 ldr pc,[pc, #-0x1b0] ;0x18 ldr pc,[pc, #-0x1b0] ;0x1C
I believe the solution is around the corner, but assistance from the TI team would be greatly appreciated!
I will use this platform to record my findings so that anybody who is facing a similar issue can refer to the steps I have taken to try to resolve this issue.
After looking at the forum thread posted which I referenced in the comment above (), I set a breakpoint at the prefetchEntry in the interrupt vectors table (sys_intvecs.asm) and Resumed the application so that it causes the abort.
The breakpoint was reached and I could observe the Registers of the MCU using the Register view in CCS. Of interest are the CP15_INSTRUCTION_FAULT_STATUS in this case. The comment by Anthony F. Seely pointed this out (link: Jun 1, 2015 10:41 PM)
Using the CortexR4F Technical Reference Manual (ARM DDI 0363G ID041111) on Page 4-47, in Table 4-27, the value of bits [10, 3-0] of the CP15_INSTRUCTION_FAULT_STATUS suggest a "Synchronous Parity/ECC Error"
Disabling the RAM ECC using _coreDisableRamEcc_(); and disabling Parity using disableParity(); also did not solve the issue.
Setting the interrupt vectors to be identical to the ones in the bootloader example is not optimal, since the function that checks the TCRAMM ECC generates a data abort (DABT), which causes a jump into the interrupt vectors.
I cloned the Hercules examples git repository () locally and checked out the branch named "qjwang_hercules_examples" (commit hash: 2ec9e6f9f8a09932f1d6455ab3c101c6efa27711).
In this repository, I found the sys_link.cmd linker file which is very different than the provided Bootloader examples on the TI webpage. I modified my linker file accordingly. ECC generation is invoked now for every flash area from the Linker file.
In the readme.txt from the bootloader examples I found the following (under the "New features" topic): "Generates flash ECC using Linker CMD file to avoid speculative fetch ECC error."
This is further discussed in the "Linker CMD file to generate Flash ECC" topic of the readme.txt. I followed all the steps pointed out:
(excerpt from readme.txt)
Do following changes under Flash Settings. CCS Project properties --> Debug -->Flash Settings:
1. Check "System Reset on Connect"
2. Uncheck "Auto ECC Generation"
3. Check "Align program segments to 64-bit memory regions"
4. Select "None" for "Flash Verification Settings"
5. Uncheck "Perform Blank Check before Program Load"
6. Press "APPLY" to save your changes!
With all of this done too, I am still getting the prefetchEntry abort!
QJ,
I haven’t resolved all of my Flash issues, although I have now sorted this specific issue.
A trap for new users is the speculative branching.
I had a section of Test Code in one of the sectors that I was erasing and was relying on that during firmware updates I would not be accessing the test code.
As it turns out this is not the case and the CPU must have been accessing the erased section for speculative branching from time to time, giving me inconsistent results.
I have now moved the test code out of this area for now which creates another issue with running out of code space.
So I think I am now on top of that issue.
I now have one more problem to resolve but I think it would be best to start a new thread as it is related to writing to FLASH fail. I am in the middle of another debug session and will create a new thread if I can’t resolve before too long.
Thank you for your help.
Regards
Robert
Hello!
Sorry for my delayed reply, I was out of office and with limited access to source code!
Here is the source code. It is a minimum working example exhibiting the issues I am still facing!
Thank you in advance!
Hello!
Could you please post a reference link to your new thread please!
Kind regards
Hello Mihail,
Fapi_flushPipeline() is used to flushes the FMC pipeline buffers. Please call this function after the status checking. But you call it before the status checking.
void fn_updater_util(void)
{
uint32_t u32_fapi_res = (uint32_t)0U;
u32_fapi_res = Fapi_initializeFlashBanks(SYS_CLK_FREQ);
Fapi_flushPipeline();
if( (Fapi_initializeFlashBanks((uint32_t)SYS_CLK_FREQ)) == Fapi_Status_Success)
{
(void)Fapi_setActiveFlashBank((Fapi_FlashBankType)BANK_0);
(void)Fapi_enableMainBankSectors(0xFFFF);
}
else
{
return ;
}
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 );
Fapi_flushPipeline();
u32_fapi_res = FAPI_GET_FSM_STATUS;
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);
//Fapi_flushPipeline();
while( FAPI_CHECK_FSM_READY_BUSY == Fapi_Status_FsmBusy );
Fapi_flushPipeline();
u32_fapi_res = FAPI_GET_FSM_STATUS;
return;
}
Thank you very much,
This resolved the issue completely!
The application software does not jump into the interrupt vectors anymore!
Kind regards,
Mihail