This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Cortex M4- leaving handler mode.

Dear ARM experts,
we use following code in supply voltage drop interrupt to leave Handler mode for Thread mode and launch "battery-saving" routine.
I am not low-level expert, the code was compiled from different resources.
The function should keep calling itself as ISR and when in Thread mode, it should run "goTo" function.
It works as expected in case of single interrupt (SCB->ICSR bit RETTOBASE is 1).
In case of nested interrupt (SCB->ICSR bit RETTOBASE is 0), in other words when voltage drop comes when another interrupt is being processed, code runs into Hard Fault.
SCB->CFSR is 0x40000 "Invalid PC load usage fault, caused by an invalid PC load by EXC_RETURN: the processor has attempted an illegal load of EXC_RETURN to the PC, as a result of an
invalid context, or an invalid EXC_RETURN value."
Microcontroller is EFM32GG1B320 (Cortex M4).
"
static hw_stack_frame_t * process_frame;
static void (*RidOfIRQ_callback)(void);

static void fn_getRidOfIRQ_goTo(void* goTo)
{
if(goTo != NULL) /* Is it the first call? */
{
RidOfIRQ_callback = goTo; /* Backup callback function from stack to global variable. */
}

/* Start from the very beginning, all nesting will be lost. */
process_frame = (hw_stack_frame_t *)((uint32_t)&_estack - sizeof(hw_stack_frame_t));

/* Are we inside of any ISR? */
if(isInsideISR() == true_t)
{
process_frame->r0 = (uint32_t)NULL; /* New input parameter "goTo" for re-entering the function. */
process_frame->r1 = 0U;
process_frame->r2 = 0U;
process_frame->r3 = 0U;
process_frame->r12 = 0U;
process_frame->lr = (uint32_t)fn_getRidOfIRQ_goTo; /* Jump to itself. */
process_frame->pc = (uint32_t)fn_getRidOfIRQ_goTo; /* Jump to itself. */
process_frame->psr = 0x21000000; /* Default PSR value. */
asm volatile ("MSR psp, %0\n\t" : : "r" (process_frame) ); /* Set back to beginning, at the end of return structure. */
asm volatile ("MSR msp, %0\n\t" : : "r" (process_frame) ); /* Set back to beginning, at the end of return structure. */
__asm volatile
(
" mov r0, #0 \n"
" msr basepri, r0 \n"
" mov lr, #0xFFFFFFF9 \n" /* Tells the handler to return using the MSP. */
" isb \n"
" bx lr \n"
);
}
else
{
asm volatile ("MSR psp, %0\n\t" : : "r" (process_frame) ); /* Set back to beginning, at the end of return structure. */
asm volatile ("MSR msp, %0\n\t" : : "r" (process_frame) ); /* Set back to beginning, at the end of return structure. */
RidOfIRQ_callback(); /* Continue with callback function. */
/* Never returns here. */
while(1);
}

}
"

I have suspected the constant 0xFFFFFFF9 which means "return to Thread mode using MSP". So I have replaced it with variable saved at interrupt entry from lr (its value was 0xFFFFFFF1 "return to Handler mode using MSP" in case of nested interrupt). But the behaviour is the same.

I would be grateful for any hint.
Thank You.
Best Regards
Ondrej

Parents
  • Hello rubber duck :-),

    the key is in both lr and psr value must be variable depending on simple/ nested interrupt. Lr values have to be as mentioned above, psr has to contain preempted exception number. 

    Does anybody have suggestion, how to get peemted exception number? Currently I read it from NVIC->IABR, but there must be some more elegant way?

Reply
  • Hello rubber duck :-),

    the key is in both lr and psr value must be variable depending on simple/ nested interrupt. Lr values have to be as mentioned above, psr has to contain preempted exception number. 

    Does anybody have suggestion, how to get peemted exception number? Currently I read it from NVIC->IABR, but there must be some more elegant way?

Children
No data