This issue relates to uVision 4.0 compiling for the ARM9, however it is probably relevant for other devices as well. We had a problem with our device locking up intermittently inside the while(1) loop of the pre-fetch exception handler. The problem was eventually traced to the optimization the compiler was applying to a switch statement. The switch statement used an enum value as parameter. Because the enum values were sequential, the compiler was able to implement an optimization as shown below:
ADDCC PC,PC,R12,LSL #2 B Ox0000BF58 B Ox0000B618 B Ox0000B64C B OxOD0036AC B Ox0000B7D8 B Ox0000BF58 B Ox0000B828 B Ox0000BAEO
The code calculates a value for the PC register and advances code execution to one of the branch instructions that take the processor to the appropriate case code. The problem here is that register R12 is not saved and restored as part of the context in the interrupt exception handler before the user ISR is called, only registers R0-R3 are saved. In our case a USB ISR was triggering and corrupting R12 and so the above calculation resulted in an invalid PC value which triggered the pre-fetch exception in the processor. Interestingly, adding just a few lines of code before the switch statement produced the same disassembly as above except that one of registers R0 to R3 were used instead of R12, resulting in code that worked. Therefore, this problem may exhibit itself for certain project compilations and not others.
I am certain that this is in fact the root cause because any one of the following items caused the code to work properly:
1. Randomizing the enum values for the switch statement to prevent the compiler from making the optimization. 2. Turning off compiler optimization in the project settings. 3. Implementing a small assembly routine to save register R12 before and after the USB ISR.
In the end I implemented item 3 as a solution but saved all registers R4-R12 for the USB ISR, just in case. This isn't an optimal solution as it wastes cycles saving and restoring the extra registers. Hopefully this will be fixed in a future release of the compiler.