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

Parents
  • Thanks for the quick response, but that post doesn't quite answer what I'm asking-

    I'll try to restate it more clearly, sorry if it was opaque Slight smile

    1. I call sd_app_evt_wait(), which is SVC into SoftDevice.

    2. Inside SVC, sd_app_evt_wait() calls WFE/SEV/WFE. This sleeps if Event Register is 0, or it doesn't sleep.

    3. Either way, sd_app_evt_wait() exits eventually. The SVC exits, which sets Event Register to 1.

    4. I do my work, then goto #1, but Event Register is set to 1!

    The ARMv7 doc says that returning from exceptions sets Event Register to 1. So, Event Register is 1 the _next_ time I call sd_app_evt_wait(). So, WFE/SEV/WFE clears Event Register, but does not sleep, then returns to me. Returning to me exits SVC, which sets Event Register to 1. So, Event Register is 1 the _next_ time I call sd_app_evt_wait(), So, WFE/SEV/WFE clears Event Register, but does not sleep, then returns to me..... 

    This does not always happen, though, so I'm wondering what part of my logic is incorrect. The post you linked doesn't quite explain what I'm asking.

    Thanks,

    Charles

  • Hi,

    charles_fi said:
    3. Either way, sd_app_evt_wait() exits eventually. The SVC exits, which sets Event Register to 1.

    No, it does not behave like that, as the sleep done by sd_app_evt_wait() is in thread mode.

    I'm debugging a situation where it doesn't

    I see my colleague Hung is covering that in  RE: nRF52840 app not sleeping, SoftDevice seems involved 

  • Thanks for the response, Sigurd. Yup, Hung is helping me dig in about that; I filed this thread because I was curious about the event register behavior separately.

    Sorry if I'm being dense and not understanding the system well, but I'm still confused-

    Why does it matter what mode the sleep is done in, if sd_app_evt_wait() is defined as a macro that does "SVC <x>; BX LR;"? It's coming back from the SVC instruction that sets the event register, right?

    Thanks for taking the time to walk me through this detail; I appreciate it a lot.

  • Hello- If anyone has any information on this I'd really love to understand it better!

    tl;dr: sd_app_evt_wait() is defined via SVCALL like this:

     

    The ARMv7M manual says that returning from SVC sets the event flag. If the event flag is then already set the next time I call sd_app_evt_wait(), what mechanism clears it so that the nRF52840 can sleep?

    Does the loop inside the SoftDevice's SVC implementation of sd_app_evt_wait() always run at least twice or something; once to clear the event flag from the previous exit, then again to actually sleep?

  • 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

Reply
  • 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

Children
No Data
Related