Hi
I am working with a microsemi cortex M3 ARM with uVision and ulink2 mdk 5.12 and I am getting a PRECISERR bus fault from a memory read during initialization by the scatterloader decompress routine. It is definitely trying to read a bad address. This code is created by the linker to initialize my memory/variables so its not something I have direct control over.
Here is the goofy thing, I found that I could get around getting a hard fault 1 time if after hitting the hard fault I get out of the debugger and right back in. Then I can run as long as I don't try to restart by clicking the reset button on uVision.
I don't understand why this would make any difference but it does and allowed me to work for the past few weeks although its slow and awkward.
This weekend my luck ran out and now I get that hard fault every single time I trying to run. My trick no longer works. All I did just before this started was to add 1 line of code and recompile and reload.
Here is a interesting clue. Out of desperation I recompiled my entire project and reflashed and I was able to get to Main! All I did was recompile. I did some testing and had to make one minor change to a index and recompiled and now I am back to getting that hard fault every time. None of my tricks work either.
Its still coming from the same loop in the decompress routine where it reads a address that is just below my DDR memory. 0x9FFFFEFF
It really sounds like some kind of memory alignment issue or something like that. But the clues do not seem to be related.
Why would adding or removing a few bytes from my code cause the decompress routine to hard fault? Why did recompiling the project allow me to get past the decompress problem once? Why does clicking reset and trying to run the same code cause the decompress to suddenly not work? Why would getting out the debugger and back in allow it to do the decompression correctly one time?
Arrrgg.
I am totally stopped from doing any more development because the decompression code always causes a hard fault from the same address and memory access.
Has anyone experienced anything like this before?
Moving the .data sections to nvm solved the problem. I can run to main every time now. Decompress does not even get called now. I could not see the forest because of the trees.
Thank you very much for you help in leading me to the answer.
Steve
Isn't 0xA0000000 the base of your DDR? Why the heck are you copying stuff there, or allowing the areas to conflict?
Stuff that gets unpacked by the linker/loader needs to reside INSIDE the ROM/FLASH LOAD REGION braces.
If you are remapping 0 <-> 0xA0000000 you need to carve that space out of the linkers view so it doesn't put data over the top of it.
for this build I am not remapping. We needed to get this out by our deadline this friday so I created a no remapped nvm smaller version of my code. So I am only using it for my variables and heap right now. Just a huge hunk of ram.
Once that delivery is done. I will go back and work on the remapped version and your right my code and that variables will both be in DDR memory. I have a different scatter file for that mapping.
In fixing this initialization problem by moving the .data sections to nvm my mallocs will no longer allocate memory. They were working ok before making this change.
Do you know if there is anything in the .data section that would affect malloc?
A LOAD REGION is like a box of furniture from IKEA, all the parts need to fit inside the box for it to be shipped to you, this would be the "linkers" job. The "loaders" job is then to unpack the parts and assemble the pieces where you want the final constructed piece of furniture to end up. The separate parts cannot fit in the same time/space as each other without distorting the fabric of the universe.
FLASH_LOAD 0x00000000 0x00080000 ; load region size_region { ER_RO 0x00000000 0x80000 ; load address = execution address { *.o (RESET, +First) *(InRoot$$Sections) ; startup_m2sxxx.o (.text) system_m2sxxx.o (.text) ; sys_config.o (.text) low_level_init.o (.text) retarget.o (.text) * (+RO) } ER_RW 0x20000000 UNINIT 0x10000 { startup_m2sxxx.o (STACK) } ; ER_DDR 0xA0080000 0xFF80000 ; RW data DDR (if FLASH gets copied into DDR space) ER_DDR 0xA0000000 0x10000000 ; RW data DDR (if DDR doesn't clash with code space) { * (+RW +ZI) * (HEAP) } }
Thanks. This is what my remap scatter file looks like.
This problem with initialized variables is still a problem unfortunately. I know that move the .data sections into nvm solves the problem of having the initial values in nonvolatile memory and it does work and does not depend upon the debugger to load the values because they are part of the nvm now.
But it seems that the linker is also placing the variable address in nvm when it must be in a RW area like esram or DDR. The linker is moving all variable address to nvm. Even if they are not initialized at boot time.
I found this out when very early one of my routines attempted to write to a variable and it got a hard fault because when I looked at the map it was located in the flash memory. It was part of the .data section. In fact all variables are part of the .data section.
But if I move the .data section back to DDR, I am back the the original problem because the initialized data is put back into DDR as well. I cannot see a way to separate the address of a variable from the values used to initialize it.
The values should be in nvm to be accessed by the scatter loader and copied into the DDR where the variable is located. The .data section seems to apply to both which is a problem and does not make sense either.
There is a .constdata but it does not include the initialed variables which are .data
How am I to get the initial data to nvm and the variable to RW DDR?
This is my current scatter file
FLASH_LOAD 0x00000000 0x00080000 ; load region size_region { ER_RO 0x00000000 0x40000 ; load address = execution address { *.o (RESET, +First) *(InRoot$$Sections) * (+RO) * (.data) } ER_RW 0x20000000 UNINIT 0x10000 { startup_m2sxxx.o (STACK) } } MDDR_RAM 0xA0000000 0x10000000 { ER_DDR 0xA0000000 UNINIT 0x10000000 ; RW data DDR { * (+RW +ZI) * (HEAP) } }
I'll have to ponder, but if your DDR is properly initialized prior to calling __main, the C runtime / scatter loader should be able to initialize the data there.
I don't understand why your platform is so broken that this isn't being done already. Or how getting this to work properly isn't going to solve both your Friday issue, and the shadow/remap issue.
Why do you still have MDDR_RAM, you need to package ALL of the released image components in the FLASH?
In case the IKEA concept isn't working for you www.keil.com/.../armlink_pge1362075661087.htm
yes I do understand this already. Thank you.
The problem that I still have is that my initialized const char* strings and my initialized global variables are all in the .data section.
If I located the .data section in the nvm, then my global variables are not writable and I get a hard fault. If I put the .data section into DDR memory, then the initial values for my const char* strings are read from (attempted to be read from DDR) but the initial data will not be there unless I run the debugger which loads it there. That will not work operationally. The initial data must be in nvm but that drags all of my global variables along with it.
I do not know how to get that initial data into nvm without having it take the initialized globals too.
from wiki: The data area contains global and static variables used by the program that are explicitly initialized with a non-zero (or non-NULL) value. This segment can be further classified into a read-only area and read-write area. For instance, the string defined by char s[] = "hello world" in C and a C statement like int debug=1 outside the "main" would be stored in initialized read-write area. And a C statement like const char* string = "hello world" makes the string literal "hello world" to be stored in initialized read-only area and the character pointer variable string in initialized read-write area.
This is a example of one of the structures that is causes the problem. this should be in nvm as a constant value. Instead it is being located the DDR along with its initialization information if I put the .data section in DDR so that I can use my global variables.
If I put .data in nvm then this works fine but all my globals are not writable.
If I can get these into a read only section, then I can locate them in nvm. I would think there is some directive or something I can add to the declaration to force to be in a specific section. Maybe.
const char* ProcessProfile_errors_Tran[END_PROCESSPROFILE_ERROR][40] = { {"MESSAGE_SUCCESS"}, {"FAILED_TO_PROCESS"}, {"FAILED_TO_SEND_MESSAGE"}, {"FAILED_TO_RECEIVE_MESSAGE"}, {"FAILED_INVALID_MESSAGE"}, {"FAILED_TO_SYNC"}, {"FAILED_NO_ACTUATOR"}, {"FAILED_ACTUATOR_SETUP"}, {"TEST_USER_TERMINATED"}, {"FAILED_TO_FIND_NODE_INDEX"} };
This will force it
__attribute__ ((section ("INITDATA")))
>>yes I do understand this already.
Yet we keep going in circles, evidently you don't.
Key thing to get straight, all the data delivered to the system needs to be in FLASH/ROM (Non-Volatile), from there it gets unpacked to it's final destination. If you have one memory to store the application, you only have one load region. To have two would suggest you have two ROMs.
It's not the job of the debugger to deliver two sections of data to the system. If the debugger is having to LOAD RAM, it's because you have multiple load regions, and one of them is in volatile memory. You need a single load region, which describes both the fixed code/consts, and the data/statics that go into RAM. Pay particular attention to how the scatter file description is nested. None of this stuff going into RAM needs to be UNINIT, the loader is quite capable of copying data out of FLASH to working RAM.
This is a scatter file from one of my projects. It doesn't have DRAM but it doesn't really matter if it uses external DRAM or internal SRAM (except for the need to configure a memory controller before the loader extracts initialized data, when using external RAM).
LR_IROM1 0x00008000 0x00018000 { ; load region size_region ER_IROM1 0x00008000 0x00018000 { ; load address = execution address *.o (RESET, +First) *(InRoot$$Sections) .ANY (+RO) } RW_IRAM1 0x40000080 0x00007F80 { ; RW data .ANY (+RW +ZI) } RW_IRAM2 0x7FE00000 0x00004000 { spimux.o (+ZI) .ANY (+RW +ZI) } }
So the load region in the single flash will store both the code that is expected to run in the flash, and all the initial data for the variables that during runtime exists in RAM.
With the single load region, a programming of the card will send everything to IROM1.
And the loader code linked into the application will then extract initial data and copy into IRAM1 and IRAM2 and also zero-initialize the remaining global data. So the processor has one non-volatile copy that survives power-off. And will get this data available in RAM so it can be modified. The amount of data double-stored and copied into RAM can be reduced by informing the compiler which data is read-only.
The 128 bytes reserved from IRAM1 allows a block for communication between boot loader and application.
Oh Ok so you are saying dump the second load region and put everything in one like below. this is what I had about a month ago. I believe I changed it because of problems with microsemi's rempping logical. but for what I need to get done by tomorrow, this is probably what I need to with with a non-remapped version of my code.
I try it now. My globals, as predicted, are not being initialized after a debugger reset/restart. Because the the initialization values are also in DDR and are lost after a restart.
FLASH_LOAD 0x00000000 0x00080000 ; load region size_region { ER_RO 0x00000000 0x40000 ; load address = execution address { *.o (RESET, +First) *(InRoot$$Sections) * (+RO) }
ER_RW 0x20000000 UNINIT 0x10000 { startup_m2sxxx.o (STACK) }
ER_DDR 0xA0000000 UNINIT 0x10000000 ; RW data DDR { * (+RW +ZI) * (HEAP) } }
Hmmm. After making that change to put everything into one region when I start the debugger and it downloads the symbols I get a Out Of Memory error.
I have never seen this before. It must be caused by my moving basically the heap and my variables into the same region. If I put the DDR section back into its own region the problem goes away.
The only thing I can think of that it is now trying to do is download the heap to DDR. Its very large and would probably cause a memory problem on the pc.
I don't know why it would want to do that. But this out of memory error cause the debugger to crash and close.
Have you ever seen that happen before?
The heap isn't downloaded anywhere.
The download only contains the code and the initial data.
It's only when the program starts to run, that the program will allocate any stack and heap and copy+zero-initialize global data.
But with a single download region, all nonvolatile data (code + initial variable values) must fit in your nonvolatile memory. By downloading the initialized variables directly into RAM, you cheat about the maximum program size supported by your processor. And you fail, because the program doesn't support a reset - all non-volatile information just has to fit in the available non-volatile memory.
If the program is too large, you have to consider if there are static information that doesn't need to be part of the program but that can instead be seen as "database content" that you can store in some EEPROM or on a SD-card or similar. Else, life will quickly get more interesting - you might have to create a loader and place the application directly to some memory card or serial flash and have the loader retrieve it directly into DDR memory on startup.
But whatever you do, you can not have a setup where the debugger places some of the nonvolatile data directly into RAM, since your RAM is not nonvolatile. You just get a situation where it "almost" works when running from the debugger. But that fails badly in real life.