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 could use some hints, ideas, suggestions. I'm writing a bootloader, that resides in the first flash sector and should accept a firmware over CAN and store it in the remaining sectors. The bootloader erases the flash sectors that are reserved for the firmware and then flashed the firmware with data coming from the CAN bus. This works quite well!
I build the software, using make (CMake) and load the resulting bootloader.out file with CSS and a XDS200 into the TMS320F28379Ds first CPU (all other CPUs are idle). I start the software and everything works fine.
When I now power down the hardware and power it up again, the software crashed with an illegal operation. So far, it seems that the crash steams from the returning of the function that contains calls to the F021 API (which resides in RAM). If I comment out the calls to the F021 API functions, the bootloader does not crash. When I single step through the code, the API calls are not crashing, but the returning from the RAM resided calling function back to the function in flash seems to be the problem. (Function is busy waiting for Fapi_checkFsmForReady() to return Fapi_Status_FsmReady).
To me it looks like, the loading of the bootloader.out file does have some required side effects that does not take place, when power reseting the software. I've tried to set a Range Avoidance Settings: 0x00-0x80000, 0x82000-0xffffffff to prevent the debug probe (XDS200) from writing to anything else beside the flash sector of the bootloader. But this doesn't changed anything.
Is there something, I could use to see the memory range the debug probe is writing to?
best regards,
Torsten
Torsten,
There should not be any read or fetch access from the Flash bank/OTP when an erase or program operation is in progress. Therefore, the Flash API functions, the user application functions that call the Flash API functions, and any ISRs (Interrupt service routines,) must be executed from RAM. For example, the entire code snippet shown below should be executed from RAM and not just the Flash API functions. The reason for this is because the Fapi_issueAsyncCommandWithAddress() function issues the erase command to the FSM, but it does not wait until the erase operation is over. As long as the FSM is busy with the current operation, there should not be a Flash access.
//
// Erase a Sector
//
oReturnCheck = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector,(uint32*)0x0080000);
//
// Wait until the erase operation is over
//
while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady){}
Thanks and regards,
Vamsi
Vamsi Gudivada said:There should not be any read or fetch access from the Flash bank/OTP when an erase or program operation is in progress. Therefore, the Flash API functions, the user application functions that call the Flash API functions, and any ISRs (Interrupt service routines,) must be executed from RAM.
Yes, that is the case. I think otherwise, the code wouldn't even execute correctly, if execute after loaded via CCS. Second error source that comes to mind, would be a missing copying of the F021 library code and the code that calls this code from flash to RAM. But I think, if that copying was missing, the code would already crash when I try to call one of the F021 library functions.
That's my code:
#pragma FUNCTION_OPTIONS ( flash_memory_words, "--opt_level=0" ); RAMFUNC bool flash_memory_words(uint16_t* buffer, uint16_t size, uint32_t addr) { EALLOW; bool result = true; for ( ; size != 0 && result; ) { // Flashing 0xffffs to the flash memory sets also the ECC portion of the flash, // which then can not be altered if ( !empty_portion(buffer, FLASH_PORTION) ) { result = Fapi_issueProgrammingCommand( (uint32 *)addr, (uint16*)buffer, FLASH_PORTION, 0, 0, Fapi_AutoEccGeneration) == Fapi_Status_Success; while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady) ; result = result && Fapi_getFsmStatus() == 0; } addr += FLASH_PORTION; buffer += FLASH_PORTION; size -= FLASH_PORTION; } EDIS; return result; }
The crash occurs after the return. Interesting enough, I'm not able to set a break point in that function, but I have to set it before and then step through that function. But maybe this is just a CCS debugger issue. I once observed that the flash memory content of the addresses behind the call to this function where all zero:
08088e: 56BF02C1 MOVB *+XAR1[0], #0x02, UNC 267 return flash_memory_words(block_buffer, MAX_DATA_BLOCK_WORD_SIZE, block_address - block_address % MAX_DATA_BLOCK_SIZE); 080890: 060A MOVL ACC, @0xa 080891: 8F00C200 MOVL XAR4, #0x00c200 080893: D580 MOVB XAR5, #0x80 080894: 18A9FF00 AND @AL, #0xff00 080896: 76408729 LCR flash_memory_words 268 } C$L11: 080898: 0000 ITRAP0 080899: 0000 ITRAP0 08089a: 0000 ITRAP0 339 { Device_configureTMXAnalogTrim():
Which would make perfectly sense, that this would cause a ITRAP. But was never able to observe this a second time, so I would think that this was a debugger issue too. Interesting enough, erasing the flash memory, where the firmware is supposed to be flashed to, works.
The .TI.ramfunc contains all Fapi_xxx functions according to the map file and also all functions that do call that API functions and also all relevant ISRs:
.TI.ramfunc * 0 00081528 000009dd RUN ADDR = 00008000 00081528 00000259 F021_API_F2837xD_FPU32.lib : FlashStateMachine.obj (.text:__Fapi_setupFlashStateMachine) 00081781 0000019d : Program.obj (.text:_Fapi_issueProgrammingCommand) 0008191e 00000088 : Read.obj (.text:__Fapi_loopRegionForValue) 000819a6 00000042 : BlankCheck.obj (.text:_Fapi_doBlankCheck) 000819e8 00000034 : Init.obj (.text:_Fapi_initializeAPI) 00081a1c 0000002e : Utilities.obj (.text:_Fapi_calculateFletcherChecksum) 00081a4a 0000002d : FlashStateMachine.obj (.text:__Fapi_issueFsmCommand) 00081a77 0000002c : Utilities.obj (.text:__Fapi_divideUnsignedLong) 00081aa3 00000025 : FlashStateMachine.obj (.text:_Fapi_setActiveFlashBank) 00081ac8 00000022 : FlashStateMachine.obj (.text:_Fapi_isAddressEcc) 00081aea 00000022 : FlashStateMachine.obj (.text:__Fapi_setupSectorsForWrite) 00081b0c 00000020 : Async.obj (.text:_Fapi_issueAsyncCommandWithAddress) 00081b2c 0000001a : Utilities.obj (.text:_Fapi_waitDelay) 00081b46 00000016 : Read.obj (.text:_Fapi_flushPipeline) 00081b5c 0000000d : Utilities.obj (.text:__Fapi_scaleCycleValues) 00081b69 00000001 --HOLE-- [fill = 0] 00081b6a 0000000c : Init.obj (.ebss) [fill = 0] 00081b76 0000000b : Utilities.obj (.text:__Fapi_calculateOtpChecksum) 00081b81 0000000a : FlashStateMachine.obj (.text:_Fapi_checkFsmForReady) 00081b8b 00000006 : FlashStateMachine.obj (.text:_Fapi_getFsmStatus) 00081b91 00000077 Fapi_UserDefinedFunctions.c.obj (.TI.ramfunc:_Fapi_setupEepromSectorEnable) 00081c08 00000076 can_adapter.c.obj (.TI.ramfunc:_can_interrupt) 00081c7e 00000064 main.c.obj (.TI.ramfunc:_bootloader_timer_isr) 00081ce2 0000005c flash_driver.c.obj (.TI.ramfunc:_flash_memory_words) 00081d3e 0000004b flash_driver.c.obj (.TI.ramfunc:_flash_write_and_check_meta_data) 00081d89 00000043 libc2000ware.a : flash.c.obj (.TI.ramfunc:_Flash_initModule) 00081dcc 0000002f Fapi_UserDefinedFunctions.c.obj (.TI.ramfunc:_Fapi_setupBankSectorEnable) 00081dfb 0000002d libc2000ware.a : flash.c.obj (.TI.ramfunc:_Flash_setBankPowerMode) 00081e28 00000026 : flash.c.obj (.TI.ramfunc:_Flash_setWaitstates) 00081e4e 0000001e : flash.c.obj (.TI.ramfunc:_Flash_setPumpPowerMode) 00081e6c 0000001a : flash.c.obj (.TI.ramfunc:_Flash_disableCache) 00081e86 0000001a : flash.c.obj (.TI.ramfunc:_Flash_disablePrefetch) 00081ea0 00000019 : flash.c.obj (.TI.ramfunc:_Flash_enableCache) 00081eb9 00000019 : flash.c.obj (.TI.ramfunc:_Flash_enablePrefetch) 00081ed2 00000017 : flash.c.obj (.TI.ramfunc:_Flash_enableECC) 00081ee9 00000016 flash_driver.c.obj (.TI.ramfunc:_erase_sector) 00081eff 00000004 libc2000ware.a : sysctl.c.obj (.TI.ramfunc) 00081f03 00000002 Fapi_UserDefinedFunctions.c.obj (.TI.ramfunc:_Fapi_serviceWatchdogTimer)
The code to copy that segment from the load address to the run address looks like this:
memcpy(&RamfuncsRunStart, &RamfuncsLoadStart, (size_t)&RamfuncsLoadSize);
The corresponding sniped of the linker script looks like this:
GROUP { .TI.ramfunc /* All functions from the F021 API are running from RAM */ # ifdef TARGET_MC_FAMILY_F2837xD { -l F021_API_F2837xD_FPU32.lib} # elif defined TARGET_MC_FAMILY_F2837xS { -l F021_API_F2837xS_FPU32.lib} # else # error "Unsupported Device!" # endif } LOAD = FLASH, RUN = RAMLS0_1, LOAD_START(_RamfuncsLoadStart), LOAD_SIZE(_RamfuncsLoadSize), LOAD_END(_RamfuncsLoadEnd), RUN_START(_RamfuncsRunStart), RUN_SIZE(_RamfuncsRunSize), RUN_END(_RamfuncsRunEnd), PAGE = 0, ALIGN(8)
But I think is that mapping or copying is correct, as otherwise the application should not run after loaded from the debugger. I think there might be something, that the debugger is initializing the the normal boot procedure is not doing. Copying the code to RAM is done, as the timer ISR is correctly executed after POR as I see a LED blinking.
Any idea?
Kind regards,
Torsten
Torsten,
1. Are you erasing the flash to where the RAM function would return after completing the execution of this function?
2. When the application returns back to flash, do you see valid code in that flash location?
3. What are the load and run addresses of flash_memory_words() as per the map file?
4. Is watchdog disabled in your application Or do you service it regularly in your application? In debugger case, gel file disables it.
5. When the application lands in illegal ISR, did you notice any flash ECC error as well?
6. In the snap that you shared, address 0x80898 shows up as all 0s. Is that expected?
Thanks and regards,
Vamsi
1) No. I debugged the situation multiple times now. Wenn debugging on source level, I receive the ITRAP when returning from the function above. If I try to return from that function on assembler code level, I do not experience an ITRAP. Either it's a Heisenbug or it's related to timings. I tried to debug through the assembler code quite fast, but I'm not able to cause the ITRAP, when debugging in assembler (Assembler Step Into).
2) Yes.
3) 0x00081ce2 and 0x000087ba
4) Watchdog is disabled.
5) I don't think so. Please find attached a screenshot of the FLASH_ECC_REGS Registers
6) I observed that only once. And I've never observed it again. From the intended program flow, it would not be expected. But if I would observe that reproducible, it would probably be the culprit I'm looking for. I guess it was a glitch in CCS.
I made an other observation: The flashing fails due to the flash not being erased. The bootloader should have erased the flash. It does so, by calling the following function for all sectors of the firmware flash range:
RAMFUNC bool erase_sector(uint32_t start_address) { bool result = Fapi_issueAsyncCommandWithAddress(Fapi_EraseSector,(uint32*)start_address) == Fapi_Status_Success; while (Fapi_checkFsmForReady() != Fapi_Status_FsmReady) ; Fapi_FlashStatusType status = Fapi_getFsmStatus(); result = result && status == 0; return result; }
The function is called and does _not_ report an error (Fapi_getFsmStatus() returns 0). But it does _not_ erase the given sector! And _again_ this only happens, when the bootloader runs from POR. If the bootloader runs after loading the bootloader.out file into the target, everything went fine.
Is there a chance that I could get the source code of the F021 library?
Is there something else to initialize the F021 library beside calls to Fapi_initializeAPI() and Fapi_setActiveFlashBank()?
Any other idea in what direction, I could investigate?
best regards,
Torsten
Further investigating into the failing flash erase in the bootloader POW case:
When I run the bootloader in CCS after loading the bootloader.out into the target. Fapi_getFsmStatus() after the Fapi_issueAsyncCommandWithAddress() returns 0, no matter if the flash area of the bootloader was already erased or not.
When I power reset the target and then connect to the target with the debugger, I can observe that Fapi_getFsmStatus() returns 0xC10 when the flash area is not empty and 0x810 when the flash is empty. Both error codes have bit 11 being set, which is RESERVED according to Table 3-327 in SPRUHM8I Revised September 2019.
Torsten,
Thank you for the update that erase is failing.
Regarding the Flash API source code: Please see https://e2e.ti.com/support/microcontrollers/c2000/f/171/t/780927?-FAQ-F05-Flash-Does-TI-distribute-the-API-source-code-
Regarding the FMSTAT reserved bit: That tells me that the erase did not succeed. Please try above FAQ suggestions and then we can analyze this further based on your reply.
Thanks and regards,
Vamsi
Hi Vamsi,
looks like I was missing an EALLOW in front of Fapi_initializeAPI() and Fapi_setActiveFlashBank(). Does this makes sense to you? I mean it worked when being executed after loaded from CCS but not after POR.
Anyhow: thanks a lot and have a nice weekend,
Torsten
Torsten,
Glad it helped to fix. Yes, that makes sense.
After loading the code to flash in CCS, if you do a reset/restart in debugger (helps to bring the device to reset state after code is loaded via flash plugin) and then execute your application, you will notice the same with debugger as well.
Have a nice weekend. I will close this post.
Thanks and regards,
Vamsi