Reply
Posts: 13
Registered: ‎08-02-2017
Accepted Solution

RTC For Generic Delay

Trying to leverage the RTC on an EFR32BG to allow an arbitrary small amount of time to pass before returning, while sleeping to save power. If I fall down to EM2 everything seems to work fine, but if I sleep to EM1 the delay function never returns even though adding a breakpoint to the callback it is successfully executed setting "timer_finished" to true.

 

 

bool timer_finished;

// Never returns
void EM1_Delay(int ms)
{
timer_finished = false;
RTCDRV_StartTimer(delay_timer, rtcdrvTimerTypeOneshot, ms, Timer_Expired, NULL);
while (!timer_finished) {
EMU_EnterEM1(); // never returns from "__WFI"
}
}

// Works fine
void EM2_Delay(int ms)
{
timer_finished = false;
RTCDRV_StartTimer(delay_timer, rtcdrvTimerTypeOneshot, ms, Timer_Expired, NULL);
while (!timer_finished) {
EMU_EnterEM2(false);
}
}

// Timer Callback
void Timer_Expired(RTCDRV_TimerID_t id, void* user)
{
timer_finished = true; // breakpoint here is always hit
}

 

I did see the note in the RTC documentation that:

>> "The callback function is called from within an interrupt handler with interrupts disabled."

and am thinking that the "with interrupts disabled" part is what's causing me grief since there is no "I" what I am "__WF"ing. Is there a way to manually exit "__WFI" that I could call from within Timer_Expired, or is there a better way to handle this?

 

Alternatively I could also just use EM2, but since I'm just getting started with the Gecko I didn't want to cause any clock configuration issues for myself and was going to start with just EM1 sleeping where possible.

 

Thanks,
Jeremy

 

Posts: 579
Registered: ‎09-18-2015

Re: RTC For Generic Delay

Hi @JeremyJass,

 

How small of a delay are you trying to generate?

 

The timing functions in emdrv are not particularly accurate for small delays.

 

Also, you should not be entering EM1 or EM2 directly if you are using RTCDRV. This is what the SLEEP driver in emdrv is for.

 

John

Posts: 13
Registered: ‎08-02-2017

Re: RTC For Generic Delay

@JohnB,

 

I'm currently trying to create a delay between 6ms and 1000ms, and I'm adding a bit of padding to the minimum necessary delays so they don't need to be that precise. I have been trying to replicate some RTC example code I found that didn't use the SLEEP driver; however, after initializing SLEEP and replacing the "EMU_..." calls with "SLEEP_sleep" seems to make everything work the same as when using the EM2 call.

 

Even if I call "SLEEP_SleepBlockBegin(sleepEM2);" before the sleep (which is forcing an EM1 sleep I believe), it still works great, and as long as I get all my blocks in the right place I don't have to worry about accidentally sleeping too deep and breaking another process.

 

Thanks,

Jeremy

Highlighted
Posts: 3,142
Registered: ‎02-07-2002

Re: RTC For Generic Delay

I'm sorry @JohnB that I had to unmark your response as being the solution.

 

But I'm pretty sure the problem here is the lack of volatile keyword on timer_finished. And thus the compiler makes an optimization you do not want.

 

This code

while (!timer_finished) {
EMU_EnterEM1(); // never returns from "__WFI"
}

can be optimized by the compiler to

if (!timer_finished) {
while (true) {
EMU_EnterEM1(); // never returns from "__WFI"
}
}

because the compiler can deduce that timer_finished is not modified. How can it do that? Because EMU_EnterEM1 is inlined.

 

And since EMU_EnterEM2() is not inlined the compiler can no longer make assumptions about its use of global variables.

 

The solution is to make the flag volatile to tell the compiler it is not allowed to make such an optimization.

Posts: 579
Registered: ‎09-18-2015

Re: RTC For Generic Delay

Hi @vanmierlo,

 

That makes sense to me, but do you think GCC or IAR will extrapolate that from just the one function to the entirety of his code?

 

Hmmnnn... time permitting, this seems like an experiment worth running Smiley Frustrated

 

John

Posts: 3,142
Registered: ‎02-07-2002

Re: RTC For Generic Delay

Each function is usually compiled on its own by a compiler after inlined functions have been replaced inside. So at that moment there is no 'entirety of his code'. The fact that the function never returns is what triggers me to believe this is what is happening.

 

But doing the experiment will give you more insight, so if you can spare the time I can only recommend it.

 

Maarten

Posts: 13
Registered: ‎08-02-2017

Re: RTC For Generic Delay

A quick test shows that @vanmierlo's idea about compiler optimization seems to be the root cause of my original troubles. Declaring timer_finished to be volatile allows both the EM1 and EM2 EMU functions to be called without issue.

 

Since this is a compiler thing, I'm sure it's possible to recreate from scratch and a volatile declaration is the best fix, but to anyone in my exact situation trying to work with the EMDRV modules, I think @JohnB's advice to pull in the SLEEP driver and call "SLEEP_Sleep()" is still a good idea.