Embedded System Design 2 - Project
delay.c File Reference

Delay functionality. More...

#include <stdint.h>
#include <stdbool.h>
#include "em_device.h"
#include "em_cmu.h"
#include "em_emu.h"
#include "em_gpio.h"
#include "em_rtc.h"
#include "delay.h"
#include "pin_mapping.h"
#include "debug_dbprint.h"
#include "util.h"

Go to the source code of this file.

Macros

#define ULFRCOFREQ   1000
 
#define ULFRCOFREQ_MS   1.000
 
#define LFXOFREQ   32768
 
#define LFXOFREQ_MS   32.768
 

Functions

static void initRTC (void)
 RTC initialization. More...
 
void delay (uint32_t msDelay)
 Wait for a certain amount of milliseconds in EM2/3. More...
 
void sleep (uint32_t sSleep)
 Sleep for a certain amount of seconds in EM2/3. More...
 
bool RTC_checkWakeup (void)
 Method to check if the wakeup was caused by the RTC. More...
 
void RTC_clearWakeup (void)
 Method to clear RTC_sleep_wakeup. More...
 
uint32_t RTC_getPassedSleeptime (void)
 Method to get the time spend sleeping (in seconds) in the case of GPIO wake-up. More...
 
void RTC_IRQHandler (void)
 Interrupt Service Routine for the RTC. More...
 

Variables

static volatile bool RTC_sleep_wakeup = false
 
bool sleeping = false
 
bool RTC_initialized = false
 

Detailed Description

Delay functionality.

Version
3.2
Author
Brecht Van Eeckhoudt

Versions

  • v1.0: Moved delay functionality from util.c to this file.
  • v1.1: Changed global variables to be static (~hidden) and added dbprint \ n \ r fixes.
  • v1.2: Removed EM1 delay method (see note in delayRTCC_EM2).
  • v1.3: Cleaned up includes, added option to select SysTick/EM2 delay functionality and moved all of the logic in one delay method. Renamed sleep method.
  • v1.4: Changed names of static variables, made initRTCcomp static.
  • v1.5: Updated documentation.
  • v1.6: Changed RTCcomp names to RTC.
  • v1.7: Moved IRQ handler of RTC to this file.
  • v1.8: Added ULFRCO logic.
  • v1.9: Updated code with new DEFINE checks.
  • v2.0: Added functionality to enable/disable the clocks only when necessary.
  • v2.1: Added functionality to check if a wakeup was caused by the RTC.
  • v2.2: Removed some clock disabling statements.
  • v2.3: Changed error numbering.
  • v2.4: Moved definitions from header to source file.
  • v2.5: Added functionality to the time spend sleeping.
  • v3.0: Disabled peripheral clock before entering an error function, added functionality to exit methods after error call and updated version number.
  • v3.1: Removed static before some local variables (not necessary).
  • v3.2: Moved msTicks variable and systick handler in #if check.

Todo:
Future improvements:
  • Split definition to use the ULFRCO for the delay and sleep method separately.
    • This isn't that easy because of the common INIT method.
    • Don't forget to update documentation.h if this functionality is changed.
  • Enable/disable clock functionality? (see comments using //)

License

Copyright (C) 2019 - Brecht Van Eeckhoudt

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

A copy of the GNU General Public License can be found in the LICENSE file along with this source code.


Some methods use code obtained from examples from Silicon Labs' GitHub. These sections are licensed under the Silabs License Agreement. See the file "Silabs_License_Agreement.txt" for details. Before using this software for any purpose, you must agree to the terms of that agreement.

Definition in file delay.c.

Macro Definition Documentation

◆ LFXOFREQ

#define LFXOFREQ   32768

Definition at line 88 of file delay.c.

◆ LFXOFREQ_MS

#define LFXOFREQ_MS   32.768

Definition at line 89 of file delay.c.

◆ ULFRCOFREQ

#define ULFRCOFREQ   1000

Definition at line 86 of file delay.c.

◆ ULFRCOFREQ_MS

#define ULFRCOFREQ_MS   1.000

Definition at line 87 of file delay.c.

Function Documentation

◆ delay()

void delay ( uint32_t  msDelay)

Wait for a certain amount of milliseconds in EM2/3.

This method also initializes SysTick/RTC if necessary.

Parameters
[in]msDelayThe delay time in milliseconds.

Definition at line 124 of file delay.c.

125 {
126 
127 #if SYSTICKDELAY == 1 /* SysTick delay selected */
128 
129  /* Initialize SysTick if not already the case */
130  if (!SysTick_initialized)
131  {
132  /* Initialize and start SysTick
133  * Number of ticks between interrupt = cmuClock_CORE/1000 */
134  if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1);
135 
136 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
137  dbinfo("SysTick initialized");
138 #endif /* DEBUG_DBPRINT */
139 
140  SysTick_initialized = true;
141  }
142  else
143  {
144  /* Enable SysTick interrupt and counter by setting their bits. */
145  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
146  }
147 
148  /* Wait a certain amount of ticks */
149  uint32_t curTicks = msTicks;
150  while ((msTicks - curTicks) < msDelay);
151 
152  /* Disable SysTick interrupt and counter (needs to be done before entering EM2/3) by clearing their bits. */
153  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk & ~SysTick_CTRL_ENABLE_Msk;
154 
155 #else /* EM2/3 RTC delay selected */
156 
157 
158  /* Initialize RTC if not already the case */
159  if (!RTC_initialized) initRTC();
160  else
161  {
162  /* Enable necessary oscillator and clocks */
163 
164 #if ULFRCO == 1 /* ULFRCO selected */
165 
166  /* No specific code here */
167 
168 #else /* LFXO selected */
169 
170  /* Enable the low-frequency crystal oscillator for the RTC */
171  //CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
172 
173 #endif /* ULFRCO/LFXO selection */
174 
175  /* Enable the clock to the interface of the low energy modules
176  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
177  //CMU_ClockEnable(cmuClock_HFLE, true);
178 
179  /* Turn on the RTC clock */
180  CMU_ClockEnable(cmuClock_RTC, true);
181  }
182 
183  /* Set RTC compare value for RTC compare register 0 depending on ULFRCO/LFXO selection */
184 
185 #if ULFRCO == 1 /* ULFRCO selected */
186 
187  if ((ULFRCOFREQ_MS * msDelay) <= 0x00ffffff) RTC_CompareSet(0, (ULFRCOFREQ_MS * msDelay));
188  else
189  {
190 
191 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
192  dbcrit("Delay too long, can't fit in the field!");
193 #endif /* DEBUG_DBPRINT */
194 
195  /* Turn off the RTC clock */
196  CMU_ClockEnable(cmuClock_RTC, false);
197 
198  error(14);
199 
200  /* Exit function */
201  return;
202  }
203 
204 #else /* LFXO selected */
205 
206  if ((LFXOFREQ_MS * msDelay) <= 0x00ffffff) RTC_CompareSet(0, (LFXOFREQ_MS * msDelay));
207  else
208  {
209 
210 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
211  dbcrit("Delay too long, can't fit in the field!");
212 #endif /* DEBUG_DBPRINT */
213 
214  /* Turn off the RTC clock */
215  CMU_ClockEnable(cmuClock_RTC, false);
216 
217  error(15);
218 
219  /* Exit function */
220  return;
221  }
222 
223 #endif /* ULFRCO/LFXO selection */
224 
225 
226  /* Start the RTC */
227  RTC_Enable(true);
228 
229  /* Enter EM2/3 depending on ULFRCO/LFXO selection */
230 
231 #if ULFRCO == 1 /* ULFRCO selected */
232  /* In EM3, high and low frequency clocks are disabled. No oscillator (except the ULFRCO) is running.
233  * Furthermore, all unwanted oscillators are disabled in EM3. This means that nothing needs to be
234  * manually disabled before the statement EMU_EnterEM3(true); */
235  EMU_EnterEM3(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
236 #else /* LFXO selected */
237  EMU_EnterEM2(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
238 #endif /* ULFRCO/LFXO selection */
239 
240 
241  /* Disable used oscillator and clocks after wake-up */
242 
243 #if ULFRCO == 1 /* ULFRCO selected */
244 
245  /* No specific code here */
246 
247 #else /* LFXO selected */
248 
249  /* Disable the low-frequency crystal oscillator for the RTC */
250  //CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
251 
252 #endif /* ULFRCO/LFXO selection */
253 
254  /* Disable the clock to the interface of the low energy modules
255  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
256  //CMU_ClockEnable(cmuClock_HFLE, false);
257 
258  /* Turn off the RTC clock */
259  CMU_ClockEnable(cmuClock_RTC, false);
260 
261 #endif /* SysTick/RTC selection */
262 
263 }
static void initRTC(void)
RTC initialization.
Definition: delay.c:453
bool RTC_initialized
Definition: delay.c:103
void dbinfo(char *message)
Print an info string (char array) to USARTx and go to the next line.
Definition: dbprint.c:503
void error(uint8_t number)
Error method.
Definition: util.c:131
#define LFXOFREQ_MS
Definition: delay.c:89
#define ULFRCOFREQ_MS
Definition: delay.c:87
void dbcrit(char *message)
Print a critical error string (char array) in red to USARTx and go to the next line.
Definition: dbprint.c:539

◆ initRTC()

static void initRTC ( void  )
static

RTC initialization.

Note
This is a static method because it's only internally used in this file and called by other methods if necessary.

Definition at line 453 of file delay.c.

454 {
455 
456 #if ULFRCO == 1 /* ULFRCO selected */
457 
458  /* Enable the ultra low-frequency RC oscillator for the RTC */
459  //CMU_OscillatorEnable(cmuOsc_ULFRCO, true, true); /* The ULFRCO is always on */
460 
461  /* Enable the clock to the interface of the low energy modules
462  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
463  CMU_ClockEnable(cmuClock_HFLE, true);
464 
465  /* Route the ULFRCO clock to the RTC */
466  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO);
467 
468 #else /* LFXO selected */
469 
470  /* Enable the low-frequency crystal oscillator for the RTC */
471  CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
472 
473  /* Enable the clock to the interface of the low energy modules
474  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
475  CMU_ClockEnable(cmuClock_HFLE, true);
476 
477  /* Route the LFXO clock to the RTC */
478  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
479 
480 #endif /* ULFRCO/LFXO selection */
481 
482  /* Turn on the RTC clock */
483  CMU_ClockEnable(cmuClock_RTC, true);
484 
485  /* Allow channel 0 to cause an interrupt */
486  RTC_IntEnable(RTC_IEN_COMP0);
487  RTC_IntClear(RTC_IFC_COMP0); /* This statement was in the ULFRCO but not in the LFXO example. It's kept here just in case. */
488  NVIC_ClearPendingIRQ(RTC_IRQn);
489  NVIC_EnableIRQ(RTC_IRQn);
490 
491  /* Configure the RTC settings */
492  RTC_Init_TypeDef rtc = RTC_INIT_DEFAULT;
493  rtc.enable = false; /* Don't start counting when initialization is done */
494 
495  /* Initialize RTC with pre-defined settings */
496  RTC_Init(&rtc);
497 
498 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
499 #if ULFRCO == 1 /* ULFRCO selected */
500  dbinfo("RTC initialized with ULFRCO\n\r");
501 #else /* LFXO selected */
502  dbinfo("RTC initialized with LFXO\n\r");
503 #endif /* ULFRCO/LFXO selection */
504 #endif /* DEBUG_DBPRINT */
505 
506  RTC_initialized = true;
507 }
bool RTC_initialized
Definition: delay.c:103
void dbinfo(char *message)
Print an info string (char array) to USARTx and go to the next line.
Definition: dbprint.c:503

◆ RTC_checkWakeup()

bool RTC_checkWakeup ( void  )

Method to check if the wakeup was caused by the RTC.

Returns
The value of RTC_sleep_wakeup.

Definition at line 404 of file delay.c.

405 {
406  return (RTC_sleep_wakeup);
407 }
static volatile bool RTC_sleep_wakeup
Definition: delay.c:95

◆ RTC_clearWakeup()

void RTC_clearWakeup ( void  )

Method to clear RTC_sleep_wakeup.

Definition at line 414 of file delay.c.

415 {
416  RTC_sleep_wakeup = false;
417 }
static volatile bool RTC_sleep_wakeup
Definition: delay.c:95

◆ RTC_getPassedSleeptime()

uint32_t RTC_getPassedSleeptime ( void  )

Method to get the time spend sleeping (in seconds) in the case of GPIO wake-up.

Returns
The time spend sleeping in seconds.

Definition at line 428 of file delay.c.

429 {
430  uint32_t sSleep = RTC_CounterGet();
431 
432  /* Disable the counter */
433  RTC_Enable(false);
434 
435 #if ULFRCO == 1 /* ULFRCO selected */
436  sSleep /= ULFRCOFREQ;
437 #else /* LFXO selected */
438  sSleep /= LFXOFREQ;
439 #endif /* ULFRCO/LFXO selection */
440 
441  return (sSleep);
442 }
#define ULFRCOFREQ
Definition: delay.c:86
#define LFXOFREQ
Definition: delay.c:88

◆ RTC_IRQHandler()

void RTC_IRQHandler ( void  )

Interrupt Service Routine for the RTC.

Note
The weak definition for this method is located in system_efm32hg.h.

Definition at line 529 of file delay.c.

530 {
531  /* Disable the counter */
532  RTC_Enable(false);
533 
534  /* Clear the interrupt source */
535  RTC_IntClear(RTC_IFC_COMP0);
536 
537  /* If the wakeup was caused by "sleeping" (not a delay), act accordingly */
538  if (sleeping) RTC_sleep_wakeup = true;
539 }
static volatile bool RTC_sleep_wakeup
Definition: delay.c:95
bool sleeping
Definition: delay.c:102

◆ sleep()

void sleep ( uint32_t  sSleep)

Sleep for a certain amount of seconds in EM2/3.

This method also initializes the RTC if necessary.

Parameters
[in]sSleepThe sleep time in seconds.

Definition at line 276 of file delay.c.

277 {
278  /* Initialize RTC if not already the case */
279  if (!RTC_initialized) initRTC();
280  else
281  {
282  /* Enable necessary oscillator and clocks */
283 
284 #if ULFRCO == 1 /* ULFRCO selected */
285 
286  /* No specific code here */
287 
288 #else /* LFXO selected */
289 
290  /* Enable the low-frequency crystal oscillator for the RTC */
291  //CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
292 
293 #endif /* ULFRCO/LFXO selection */
294 
295  /* Enable the clock to the interface of the low energy modules
296  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
297  //CMU_ClockEnable(cmuClock_HFLE, true);
298 
299  /* Turn on the RTC clock */
300  CMU_ClockEnable(cmuClock_RTC, true);
301  }
302 
303 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
304 #if ULFRCO == 1 /* ULFRCO selected */
305  dbwarnInt("Sleeping in EM3 for ", sSleep, " s\n\r");
306 #else /* LFXO selected */
307  dbwarnInt("Sleeping in EM2 for ", sSleep, " s\n\r");
308 #endif /* ULFRCO/LFXO selection */
309 #endif /* DEBUG_DBPRINT */
310 
311  /* Set RTC compare value for RTC compare register 0 depending on ULFRCO/LFXO selection */
312 
313 #if ULFRCO == 1 /* ULFRCO selected */
314 
315  if ((ULFRCOFREQ * sSleep) <= 0x00ffffff) RTC_CompareSet(0, (ULFRCOFREQ * sSleep));
316  else
317  {
318 
319 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
320  dbcrit("Delay too long, can't fit in the field!");
321 #endif /* DEBUG_DBPRINT */
322 
323  /* Turn off the RTC clock */
324  CMU_ClockEnable(cmuClock_RTC, false);
325 
326  error(16);
327 
328  /* Exit function */
329  return;
330  }
331 
332 #else /* LFXO selected */
333 
334  if ((LFXOFREQ * sSleep) <= 0x00ffffff) RTC_CompareSet(0, (LFXOFREQ * sSleep));
335  else
336  {
337 
338 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
339  dbcrit("Delay too long, can't fit in the field!");
340 #endif /* DEBUG_DBPRINT */
341 
342  /* Turn off the RTC clock */
343  CMU_ClockEnable(cmuClock_RTC, false);
344 
345  error(17);
346 
347  /* Exit function */
348  return;
349  }
350 
351 #endif /* ULFRCO/LFXO selection */
352 
353  /* Indicate that we're using the sleep method */
354  sleeping = true;
355 
356 
357  /* Start the RTC */
358  RTC_Enable(true);
359 
360  /* Enter EM2/3 depending on ULFRCO/LFXO selection */
361 
362 #if ULFRCO == 1 /* ULFRCO selected */
363  /* In EM3, high and low frequency clocks are disabled. No oscillator (except the ULFRCO) is running.
364  * Furthermore, all unwanted oscillators are disabled in EM3. This means that nothing needs to be
365  * manually disabled before the statement EMU_EnterEM3(true); */
366  EMU_EnterEM3(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
367 #else /* LFXO selected */
368  EMU_EnterEM2(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
369 #endif /* ULFRCO/LFXO selection */
370 
371 
372  /* Indicate that we're no longer sleeping */
373  sleeping = false;
374 
375  /* Disable used oscillator and clocks after wake-up */
376 
377 #if ULFRCO == 1 /* ULFRCO selected */
378 
379  /* No specific code here */
380 
381 #else /* LFXO selected */
382 
383  /* Disable the low-frequency crystal oscillator for the RTC */
384  //CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
385 
386 #endif /* ULFRCO/LFXO selection */
387 
388  /* Disable the clock to the interface of the low energy modules
389  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
390  //CMU_ClockEnable(cmuClock_HFLE, false);
391 
392  /* Turn off the RTC clock */
393  CMU_ClockEnable(cmuClock_RTC, false);
394 }
#define ULFRCOFREQ
Definition: delay.c:86
static void initRTC(void)
RTC initialization.
Definition: delay.c:453
void dbwarnInt(char *message1, int32_t value, char *message2)
Print a warning value surrounded by two strings (char array) to USARTx.
Definition: dbprint.c:598
bool RTC_initialized
Definition: delay.c:103
void error(uint8_t number)
Error method.
Definition: util.c:131
void dbcrit(char *message)
Print a critical error string (char array) in red to USARTx and go to the next line.
Definition: dbprint.c:539
#define LFXOFREQ
Definition: delay.c:88
bool sleeping
Definition: delay.c:102

Variable Documentation

◆ RTC_initialized

bool RTC_initialized = false

Definition at line 103 of file delay.c.

◆ RTC_sleep_wakeup

volatile bool RTC_sleep_wakeup = false
static

Definition at line 95 of file delay.c.

◆ sleeping

bool sleeping = false

Definition at line 102 of file delay.c.