How does sd_app_evt_wait() work when the Event Register is set on exception exit?

I've disassembled sd_app_evt_wait() in SoftDevice S140 v7.0.1 and clearly see that inside a loop, it calls WFE -> SEV -> WFE. (It also manipulates the MWU and looks at interrupts to decide whether to loop again or return).

The ARMv7-M Architecture Reference Manual version "ARM DDI 0403E" page B1-561 (see https://developer.arm.com/documentation/ddi0403/latest) clearly states that "the execution of an exception return function" sets the Event Register.

 

My question is this- calling sd_app_evt_wait() invokes a SVC, which is one of the core ARM exceptions. When sd_app_evt_wait returns from the SVC back to my code, that sets the Event Register, right? So, when I call sd_app_evt_wait() again, doesn't the WFE -> SEV -> WFE just fall through without sleeping, because the first WFE clears the Event Register without sleeping?

I'm certainly misunderstanding something, or sd_app_evt_wait() would never sleep, and it does sleep most of the time. (I'm debugging a situation where it doesn't)

What machinery am I missing here?

Thanks in advance!

Charles

  • Hi,

    From the docs we have:

    When waiting for application events using the API, the CPU goes to an IDLE state whenever the SoftDevice is not using the CPU, and interrupts handled directly by the SoftDevice do not wake the application.
    Application interrupts will wake the application as expected.
    sd_app_evt_wait() calls wait in the sequence of __WFE() __SEV() __WFE(). sd_app_evt_wait() is looping until an application interrupt happens. And it's run in thread mode, i.e. it's no longer in SVC when the wait sequence is called.

  • I'm not sure what you mean when you say it's run in "thread mode" and "no longer in SVC".

    My understanding of Cortex-M4 is as follows- please correct me if you spot my error because I do want to understand this thoroughly!

    When the user-app "Thread" mode side code calls "SVC x", that raises the SVCALL exception. From that point on, the CPU is in "Handler" mode as it processes the SVCALL exception, which happens inside of the SoftDevice binary blob.

    During this time, the CPU is inside the SVCALL exception handler until the SoftDevice handler returns. This happens by way of the compiler emitting code that pops LR from the stack into the PC register; the CPU explicitly sets LR to 0xFFFFFFF1 upon entering the SVCALL exception, and the CPU sees that it's exiting the exception handler when, during the SoftDevice SVCALL handler epilogue, the PC register is assigned this special LR value. At this point, the CPU also sets the Event Register, per the architecture manual reference I provided in my initial post.

    My hunch is that the Event Register is simply _always_ set upon returning from the SoftDevice SVCALL, but because sd_app_evt_wait() runs in a WFE/SEV/WFE loop, the first spin through that loop doesn't actually sleep. The first spin through the loop instead just serves to clear the event flag, then the loop sees that none of the user interrupts are pending, so it jumps back to the top of the loop, and the second WFE is what actually causes the CPU to sleep.

    Is this right? I don't understand what you mean by "it's no longer in SVC when the wait sequence is called"- if it's not in SVC, then it's back in my application code, and it's definitely not back in my application code because this wfe/sev/wfe loop is part of the SoftDevice binary!

    Thanks,

    Charles

Related