cpu: at91sam7x256
I have in my project some global objects, they are by default placed at address 0x200000. My program seems to work properly but occasionally beginning of RAM is filled with zeros by Keil library function at label: __decompress1 in deassembly window. It makes some my variables and pointers are useles and program stops responding. The worst is, that pointers are defined as const and they are not expected to change.
Any idea how to solve this error?
OK. I changed some things in my code and now in also jumps to __main: but in LR is always 0xfffe0000 (AT91C_BASE_SPI0).
Is there any way to set breakpoint when LR is written with 0xfffe0000?
OMG :( The same thing sometimes happens inside assembly code of printf... (if value in LR is correct).
With a stack overwrite, you may see a lot of funny addresses all-over. I you jump the processor into the middle of perfectly working code, it doesn't matter that the code is working.
After all, it's contracts programming. The supplier of a function guarantees that the function will do the intended task, as long as you guarantee that you will supply the function with the expected runtime environment and the correct input parameters.
Maybe I found source of problem...
volatile unsigned int uiCriticalNesting = 0; extern "C" void __SWI_0 ( void ); extern "C" void __SWI_1 ( void ); void __swi(0) vEnterCritical( void ); void __SWI_0 ( void ) { int R0; __asm{ MRS R0, CPSR }; __asm{ ORR R0, R0, #0xC0 }; __asm{ MSR CPSR_CXSF, R0 }; ++uiCriticalNesting; } void __swi(1) vExitCritical( void ); void __SWI_1 ( void ) { if( uiCriticalNesting ) { --uiCriticalNesting; if( uiCriticalNesting == 0 ) { int R0; __asm{ MRS R0, CPSR }; __asm{ BIC R0, R0, #0xC0 }; __asm{ MSR CPSR_CXSF, R0 }; } } }
It seems to be OK, but before bad jump to __main: program is inside interrupt function and uiCriticalNesting is != 0. It should never happen, so what's wrong with my critical sections?
What SWI handler are you using. The one from MDK startup folder overwrites the CPSR on exit. This is because it allows nested interrupts and nested SWI function calls.
Can you post your SWI handler here?
T_Bit EQU 0x20 PRESERVE8 ; 8-Byte aligned Stack AREA SWI_Area, CODE, READONLY ARM EXPORT SWI_Handler SWI_Handler STMFD SP!, {R12, LR} ; Store R12, LR MRS R12, SPSR ; Get SPSR STMFD SP!, {R8, R12} ; Store R8, SPSR TST R12, #T_Bit ; Check Thumb Bit LDRNEH R12, [LR,#-2] ; Thumb:Load Halfword BICNE R12, R12, #0xFF00 ; Extract SWI Number LDREQ R12, [LR,#-4] ; ARM: Load Word BICEQ R12, R12, #0xFF000000 ; Extract SWI Number LDR R8, SWI_Count CMP R12, R8 BHS SWI_Dead ; Overflow ADR R8, SWI_Table LDR R12, [R8,R12,LSL #2] ; Load SWI Function Address MOV LR, PC ; Return Address BX R12 ; Call SWI Function LDMFD SP!, {R8, R12} ; Load R8, SPSR MSR SPSR_cxsf, R12 ; Set SPSR LDMFD SP!, {R12, PC}^ ; Restore R12 and Return SWI_Dead B SWI_Dead ; None Existing SWI SWI_Cnt EQU (SWI_End-SWI_Table)/4 SWI_Count DCD SWI_Cnt IMPORT __SWI_0 IMPORT __SWI_1 SWI_Table DCD __SWI_0 ; SWI 0 Function Entry DCD __SWI_1 ; SWI 1 Function Entry SWI_End END
Do you think I should change something? This code touches SPSR to switch beetwen ARM and Thumb... Maybe I missed it touches int falgs...
Thank you very much :) I changed in code CPSR to SPSR and removed line with MSR SPSR_cxsf, R12. And now everything works :) The most crazy is that my project has worked OK for 2 months with no real critical section.
Here is updated SWI handler. This one does not allow nested interrupts, but solves your interrupt disable problem.
SWI_Handler STMFD SP!, {R8, LR} ; Store R8, LR MRS R12, SPSR ; Get SPSR TST R12, #T_Bit ; Check Thumb Bit LDRNEH R12, [LR,#-2] ; Thumb: Load Halfword BICNE R12, R12, #0xFF00 ; Extract SWI Number LDREQ R12, [LR,#-4] ; ARM: Load Word BICEQ R12, R12, #0xFF000000 ; Extract SWI Number LDR R8, SWI_Count CMP R12, R8 BHS SWI_Dead ; Overflow ADR R8, SWI_Table LDR R12, [R8,R12,LSL #2] ; Load SWI Function Address MOV LR, PC ; Return Address BX R12 ; Call SWI Function LDMFD SP!, {R8, PC}^ ; Restore R8 and Return SWI_Dead B SWI_Dead ; None Existing SWI
Why don't you 'push' and 'pop' R12 ?
Because r12 is a scratch register that may be modified by the callee. The caller is responsible for saving it. The SVC (formerly known as SWI) is a synchronous call (unlike an IRQ for instance), i.e. the compiler has to apply the same rules as for a normal function call.
Regards Marcus http://www.doulos.com/arm/