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,
    I would dare to rephrase my question in more general form.
    I simply want to flush/discard all active pending (preempted) exceptions and go to Thread mode.

    I believe I solve common scenario for embedded system which must have some solution in Cortex:
    The main battery is disconnected/discharged and system has to switch to small backup battery ASAP.
    This is signaled by highest-priority IRQ. Backup battery cannot run full-load of system, hence the switch time is critical.
    What I do in "battery disconnected" ISR is minimizing consumption by turning-off all unnecesary peripherials and exceptions.
    Then I would like to leave all active/active pending exceptions back to thread mode where the system continues running only a few critical tasks, being powered from backup battery.
    Note that active and pending (preempted) exceptions cannot be serviced "standard" way, because their peripherials are not powered anymore.

    Thats why I decided to mock the stack frame of preempted exceptions and use it repeatedly for leaving Handler Mode.
    Problem is that PSR register in the frame should contain ISR_NUMBER "of the current exception" (i.e. preempted exception at the time of creating the frame).
    How to get the number? The only information I have found is "active interrupts" in NVIC->IABR, but the bits only show active interrupts without information of their priority.
    So that I would have to search for all active exceptions, then search for their priorities to get the exception with highest priority for PSR.
    It seems rather complicated (and time consuming).
    Is there an information of "currently preempted exception" ?

    Or-maybe there is some other easier solution of leaving the Handler mode?

    Thank You for Your opinions/comments.
    Best Regards
    Ondrej

Reply
  • Hello,
    I would dare to rephrase my question in more general form.
    I simply want to flush/discard all active pending (preempted) exceptions and go to Thread mode.

    I believe I solve common scenario for embedded system which must have some solution in Cortex:
    The main battery is disconnected/discharged and system has to switch to small backup battery ASAP.
    This is signaled by highest-priority IRQ. Backup battery cannot run full-load of system, hence the switch time is critical.
    What I do in "battery disconnected" ISR is minimizing consumption by turning-off all unnecesary peripherials and exceptions.
    Then I would like to leave all active/active pending exceptions back to thread mode where the system continues running only a few critical tasks, being powered from backup battery.
    Note that active and pending (preempted) exceptions cannot be serviced "standard" way, because their peripherials are not powered anymore.

    Thats why I decided to mock the stack frame of preempted exceptions and use it repeatedly for leaving Handler Mode.
    Problem is that PSR register in the frame should contain ISR_NUMBER "of the current exception" (i.e. preempted exception at the time of creating the frame).
    How to get the number? The only information I have found is "active interrupts" in NVIC->IABR, but the bits only show active interrupts without information of their priority.
    So that I would have to search for all active exceptions, then search for their priorities to get the exception with highest priority for PSR.
    It seems rather complicated (and time consuming).
    Is there an information of "currently preempted exception" ?

    Or-maybe there is some other easier solution of leaving the Handler mode?

    Thank You for Your opinions/comments.
    Best Regards
    Ondrej

Children
No data