Hi,
I recently upgraded from FreeRTOS 6.1.1 to FreeRTOS 8.0.1. In FreeRTOS 6.1.1, I had issues with the "invalid literal constant: pool needs to be closer" error, which was solved by applying a "patch" to portRESTORE and portSAVE. When I use the same code in FreeRTOS 8.0.1, the code compiles fine - but I get a prefetch abort.
I've never used assembly so I have no clue what's going on here! Without JTAG, how can I troubleshoot this? Is there an obvious fix?
The patched code is here:
~~~~~~
define portRESTORE_CONTEXT()
{
extern volatile void * volatile pxCurrentTCB;
extern volatile unsigned portLONG ulCriticalNesting;
\
asm volatile ( \
/* Set the LR to the task stack. */ \
"LDR R0, 1f /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"LDR LR, [R0] \n\t" \
\
/* The critical nesting depth is the first item on the stack. */ \
/* Load it into the ulCriticalNesting variable. */ \
"LDR R0, 2f /* =ulCriticalNesting */ \n\t" \
"LDMFD LR!, {R1} \n\t" \
"STR R1, [R0] \n\t" \
\
/* Get the SPSR from the stack. */ \
"LDMFD LR!, {R0} \n\t" \
"MSR SPSR, R0 \n\t" \
\
/* Restore all system mode registers for the task. */ \
"LDMFD LR, {R0-R14}^ \n\t" \
"NOP \n\t" \
\
/* Restore the return address. */ \
"LDR LR, [LR, #+60] \n\t" \
\
/* And return - correcting the offset in the LR to obtain the */ \
/* correct address. */ \
"SUBS PC, LR, #4 \n\t" \
\
/* Place the pool behind the code. This is never reached. */ \
"1: .word pxCurrentTCB \n\t" \
"2: .word ulCriticalNesting \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}
/-----------------------------------------------------------/
define portSAVE_CONTEXT()
{
extern volatile void * volatile pxCurrentTCB;
extern volatile unsigned portLONG ulCriticalNesting;
\
asm volatile ( \
"b 3f /* skip data */ \n\t" \
"1: .word pxCurrentTCB \n\t" \
"2: .word ulCriticalNesting \n\t" \
"3: \n\t" \
/* Push R0 as we are going to use the register. */ \
"STMDB SP!, {R0} \n\t" \
\
/* Set R0 to point to the task stack pointer. */ \
"STMDB SP,{SP}^ \n\t" \
"NOP \n\t" \
"SUB SP, SP, #4 \n\t" \
"LDMIA SP!,{R0} \n\t" \
\
/* Push the return address onto the stack. */ \
"STMDB R0!, {LR} \n\t" \
\
/* Now we have saved LR we can use it instead of R0. */ \
"MOV LR, R0 \n\t" \
\
/* Pop R0 so we can save it onto the system mode stack. */ \
"LDMIA SP!, {R0} \n\t" \
\
/* Push all the system mode registers onto the task stack. */ \
"STMDB LR,{R0-LR}^ \n\t" \
"NOP \n\t" \
"SUB LR, LR, #60 \n\t" \
\
/* Push the SPSR onto the task stack. */ \
"MRS R0, SPSR \n\t" \
"STMDB LR!, {R0} \n\t" \
\
"LDR R0, 2b /* =ulCriticalNesting */ \n\t" \
"LDR R0, [R0] \n\t" \
"STMDB LR!, {R0} \n\t" \
\
/* Store the new top of stack for the task. */ \
"LDR R0, 1b /* =pxCurrentTCB */ \n\t" \
"LDR R0, [R0] \n\t" \
"STR LR, [R0] \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}
~~~~~~
Instead of:
~~~~~~
define portRESTORE_CONTEXT()
{
extern volatile void * volatile pxCurrentTCB;
extern volatile uint32_t ulCriticalNesting;
\
/* Set the LR to the task stack. */ \
__asm volatile ( \
"LDR R0, =pxCurrentTCB \n\t" \
"LDR R0, [R0] \n\t" \
"LDR LR, [R0] \n\t" \
\
/* The critical nesting depth is the first item on the stack. */ \
/* Load it into the ulCriticalNesting variable. */ \
"LDR R0, =ulCriticalNesting \n\t" \
"LDMFD LR!, {R1} \n\t" \
"STR R1, [R0] \n\t" \
\
/* Get the SPSR from the stack. */ \
"LDMFD LR!, {R0} \n\t" \
"MSR SPSR, R0 \n\t" \
\
/* Restore all system mode registers for the task. */ \
"LDMFD LR, {R0-R14}^ \n\t" \
"NOP \n\t" \
\
/* Restore the return address. */ \
"LDR LR, [LR, #+60] \n\t" \
\
/* And return - correcting the offset in the LR to obtain the */ \
/* correct address. */ \
"SUBS PC, LR, #4 \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}
/-----------------------------------------------------------/
define portSAVE_CONTEXT()
{
extern volatile void * volatile pxCurrentTCB;
extern volatile uint32_t ulCriticalNesting;
\
/* Push R0 as we are going to use the register. */ \
__asm volatile ( \
"STMDB SP!, {R0} \n\t" \
\
/* Set R0 to point to the task stack pointer. */ \
"STMDB SP,{SP}^ \n\t" \
"NOP \n\t" \
"SUB SP, SP, #4 \n\t" \
"LDMIA SP!,{R0} \n\t" \
\
/* Push the return address onto the stack. */ \
"STMDB R0!, {LR} \n\t" \
\
/* Now we have saved LR we can use it instead of R0. */ \
"MOV LR, R0 \n\t" \
\
/* Pop R0 so we can save it onto the system mode stack. */ \
"LDMIA SP!, {R0} \n\t" \
\
/* Push all the system mode registers onto the task stack. */ \
"STMDB LR,{R0-LR}^ \n\t" \
"NOP \n\t" \
"SUB LR, LR, #60 \n\t" \
\
/* Push the SPSR onto the task stack. */ \
"MRS R0, SPSR \n\t" \
"STMDB LR!, {R0} \n\t" \
\
"LDR R0, =ulCriticalNesting \n\t" \
"LDR R0, [R0] \n\t" \
"STMDB LR!, {R0} \n\t" \
\
/* Store the new top of stack for the task. */ \
"LDR R0, =pxCurrentTCB \n\t" \
"LDR R0, [R0] \n\t" \
"STR LR, [R0] \n\t" \
); \
( void ) ulCriticalNesting; \
( void ) pxCurrentTCB; \
}
~~~~~~
I think you have done sort of the right thing in loading the constant addresses from close b memory, but normally the constants would go at the end. Something like
__asm volatile (
LDR R0, _CurrentTCB
LDR R0, [R0]
LDR LR, [R0]
/* etc. */
/* The rest of the Asm here, then at the end, define the constants /
_CurrentTCB: .word pxCurrentTCB
/ Other constants here. */
}
The syntax might not be quite right but you see the idea. Having the consts at the end means you don't have to do the jumps so won't end up on a bad alignment.