Master Thesis  V1.0
Research and Design of Sensor Node for NMSD Treatment
delay.c
Go to the documentation of this file.
1 /***************************************************************************/
63 #include <stdint.h> /* (u)intXX_t */
64 #include <stdbool.h> /* "bool", "true", "false" */
65 #include "em_device.h" /* Include necessary MCU-specific header file */
66 #include "em_cmu.h" /* Clock management unit */
67 #include "em_emu.h" /* Energy Management Unit */
68 #include "em_gpio.h" /* General Purpose IO */
69 #include "em_rtc.h" /* Real Time Counter (RTC) */
70 
71 #include "delay.h" /* Corresponding header file */
72 //#include "pin_mapping.h" /* PORT and PIN definitions */
73 #include "debug_dbprint.h" /* Enable or disable printing to UART */
74 //#include "util.h" /* Utility functionality */
75 
76 
77 /* Local definitions (for RTC compare interrupts) */
78 #define ULFRCOFREQ 1000
79 #define ULFRCOFREQ_MS 1.000
80 #define LFXOFREQ 32768
81 #define LFXOFREQ_MS 32.768
82 
83 
84 /* Local variables */
85 /* -> Volatile because it's modified by an interrupt service routine (@RAM)
86  * -> Static so it's always kept in memory (@data segment, space provided during compile time) */
87 static volatile bool RTC_sleep_wakeup = false;
88 
89 #if SYSTICKDELAY == 1 /* SysTick delay selected */
90 static volatile uint32_t msTicks;
91 #endif /* SysTick/RTC selection */
92 
93 
94 bool sleeping = false;
95 bool RTC_initialized = false;
96 
97 #if SYSTICKDELAY == 1 /* SysTick delay selected */
98 bool SysTick_initialized = false;
99 #endif /* SysTick/RTC selection */
100 
101 
102 /* Local prototype */
103 static void initRTC (void);
104 
105 
106 /**************************************************************************/
116 void delay (uint32_t msDelay)
117 {
118 
119 #if SYSTICKDELAY == 1 /* SysTick delay selected */
120 
121  /* Initialize SysTick if not already the case */
122  if (!SysTick_initialized)
123  {
124  /* Initialize and start SysTick
125  * Number of ticks between interrupt = cmuClock_CORE/1000 */
126  if (SysTick_Config(CMU_ClockFreqGet(cmuClock_CORE) / 1000)) while (1);
127 
128 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
129  dbinfo("SysTick initialized");
130 #endif /* DEBUG_DBPRINT */
131 
132  SysTick_initialized = true;
133  }
134  else
135  {
136  /* Enable SysTick interrupt and counter by setting their bits. */
137  SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
138  }
139 
140  /* Wait a certain amount of ticks */
141  uint32_t curTicks = msTicks;
142  while ((msTicks - curTicks) < msDelay);
143 
144  /* Disable SysTick interrupt and counter (needs to be done before entering EM2/3) by clearing their bits. */
145  SysTick->CTRL &= ~SysTick_CTRL_TICKINT_Msk & ~SysTick_CTRL_ENABLE_Msk;
146 
147 #else /* EM2/3 RTC delay selected */
148 
149 
150  /* Initialize RTC if not already the case */
151  if (!RTC_initialized) initRTC();
152  else
153  {
154  /* Enable necessary oscillator and clocks */
155 
156 #if ULFRCO == 1 /* ULFRCO selected */
157 
158  /* No specific code here */
159 
160 #else /* LFXO selected */
161 
162  /* Enable the low-frequency crystal oscillator for the RTC */
163  //CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
164 
165 #endif /* ULFRCO/LFXO selection */
166 
167  /* Enable the clock to the interface of the low energy modules
168  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
169  //CMU_ClockEnable(cmuClock_HFLE, true);
170 
171  /* Turn on the RTC clock */
172  CMU_ClockEnable(cmuClock_RTC, true);
173  }
174 
175  /* Set RTC compare value for RTC compare register 0 depending on ULFRCO/LFXO selection */
176 
177 #if ULFRCO == 1 /* ULFRCO selected */
178 
179  if ((ULFRCOFREQ_MS * msDelay) <= 0x00ffffff) RTC_CompareSet(0, (ULFRCOFREQ_MS * msDelay));
180  else
181  {
182 
183 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
184  dbcrit("Delay too long, can't fit in the field!");
185 #endif /* DEBUG_DBPRINT */
186 
187  /* Turn off the RTC clock */
188  CMU_ClockEnable(cmuClock_RTC, false);
189 
190  //error(14);
191 
192  /* Exit function */
193  return;
194  }
195 
196 #else /* LFXO selected */
197 
198  if ((LFXOFREQ_MS * msDelay) <= 0x00ffffff) RTC_CompareSet(0, (LFXOFREQ_MS * msDelay));
199  else
200  {
201 
202 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
203  dbcrit("Delay too long, can't fit in the field!");
204 #endif /* DEBUG_DBPRINT */
205 
206  /* Turn off the RTC clock */
207  CMU_ClockEnable(cmuClock_RTC, false);
208 
209  //error(15);
210 
211  /* Exit function */
212  return;
213  }
214 
215 #endif /* ULFRCO/LFXO selection */
216 
217 
218  /* Start the RTC */
219  RTC_Enable(true);
220 
221  /* Enter EM2/3 depending on ULFRCO/LFXO selection */
222 
223 #if ULFRCO == 1 /* ULFRCO selected */
224  /* In EM3, high and low frequency clocks are disabled. No oscillator (except the ULFRCO) is running.
225  * Furthermore, all unwanted oscillators are disabled in EM3. This means that nothing needs to be
226  * manually disabled before the statement EMU_EnterEM3(true); */
227  EMU_EnterEM3(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
228 #else /* LFXO selected */
229  EMU_EnterEM2(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
230 #endif /* ULFRCO/LFXO selection */
231 
232 
233  /* Disable used oscillator and clocks after wake-up */
234 
235 #if ULFRCO == 1 /* ULFRCO selected */
236 
237  /* No specific code here */
238 
239 #else /* LFXO selected */
240 
241  /* Disable the low-frequency crystal oscillator for the RTC */
242  //CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
243 
244 #endif /* ULFRCO/LFXO selection */
245 
246  /* Disable the clock to the interface of the low energy modules
247  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
248  //CMU_ClockEnable(cmuClock_HFLE, false);
249 
250  /* Turn off the RTC clock */
251  CMU_ClockEnable(cmuClock_RTC, false);
252 
253 #endif /* SysTick/RTC selection */
254 
255 }
256 
257 
258 /**************************************************************************/
268 void sleep (uint32_t sSleep)
269 {
270  /* Initialize RTC if not already the case */
271  if (!RTC_initialized) initRTC();
272  else
273  {
274  /* Enable necessary oscillator and clocks */
275 
276 #if ULFRCO == 1 /* ULFRCO selected */
277 
278  /* No specific code here */
279 
280 #else /* LFXO selected */
281 
282  /* Enable the low-frequency crystal oscillator for the RTC */
283  //CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
284 
285 #endif /* ULFRCO/LFXO selection */
286 
287  /* Enable the clock to the interface of the low energy modules
288  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
289  //CMU_ClockEnable(cmuClock_HFLE, true);
290 
291  /* Turn on the RTC clock */
292  CMU_ClockEnable(cmuClock_RTC, true);
293  }
294 
295 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
296 #if ULFRCO == 1 /* ULFRCO selected */
297  dbwarnInt("Sleeping in EM3 for ", sSleep, " s\n\r");
298 #else /* LFXO selected */
299  dbwarnInt("Sleeping in EM2 for ", sSleep, " s\n\r");
300 #endif /* ULFRCO/LFXO selection */
301 #endif /* DEBUG_DBPRINT */
302 
303  /* Set RTC compare value for RTC compare register 0 depending on ULFRCO/LFXO selection */
304 
305 #if ULFRCO == 1 /* ULFRCO selected */
306 
307  if ((ULFRCOFREQ * sSleep) <= 0x00ffffff) RTC_CompareSet(0, (ULFRCOFREQ * sSleep));
308  else
309  {
310 
311 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
312  dbcrit("Delay too long, can't fit in the field!");
313 #endif /* DEBUG_DBPRINT */
314 
315  /* Turn off the RTC clock */
316  CMU_ClockEnable(cmuClock_RTC, false);
317 
318  //error(16);
319 
320  /* Exit function */
321  return;
322  }
323 
324 #else /* LFXO selected */
325 
326  if ((LFXOFREQ * sSleep) <= 0x00ffffff) RTC_CompareSet(0, (LFXOFREQ * sSleep));
327  else
328  {
329 
330 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
331  dbcrit("Delay too long, can't fit in the field!");
332 #endif /* DEBUG_DBPRINT */
333 
334  /* Turn off the RTC clock */
335  CMU_ClockEnable(cmuClock_RTC, false);
336 
337  error(17);
338 
339  /* Exit function */
340  return;
341  }
342 
343 #endif /* ULFRCO/LFXO selection */
344 
345  /* Indicate that we're using the sleep method */
346  sleeping = true;
347 
348 
349  /* Start the RTC */
350  RTC_Enable(true);
351 
352  /* Enter EM2/3 depending on ULFRCO/LFXO selection */
353 
354 #if ULFRCO == 1 /* ULFRCO selected */
355  /* In EM3, high and low frequency clocks are disabled. No oscillator (except the ULFRCO) is running.
356  * Furthermore, all unwanted oscillators are disabled in EM3. This means that nothing needs to be
357  * manually disabled before the statement EMU_EnterEM3(true); */
358  EMU_EnterEM3(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
359 #else /* LFXO selected */
360  EMU_EnterEM2(true); /* "true" - Save and restore oscillators, clocks and voltage scaling */
361 #endif /* ULFRCO/LFXO selection */
362 
363 
364  /* Indicate that we're no longer sleeping */
365  sleeping = false;
366 
367  /* Disable used oscillator and clocks after wake-up */
368 
369 #if ULFRCO == 1 /* ULFRCO selected */
370 
371  /* No specific code here */
372 
373 #else /* LFXO selected */
374 
375  /* Disable the low-frequency crystal oscillator for the RTC */
376  //CMU_OscillatorEnable(cmuOsc_LFXO, false, true);
377 
378 #endif /* ULFRCO/LFXO selection */
379 
380  /* Disable the clock to the interface of the low energy modules
381  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
382  //CMU_ClockEnable(cmuClock_HFLE, false);
383 
384  /* Turn off the RTC clock */
385  CMU_ClockEnable(cmuClock_RTC, false);
386 }
387 
388 
389 /**************************************************************************/
396 bool RTC_checkWakeup (void)
397 {
398  return (RTC_sleep_wakeup);
399 }
400 
401 
402 /**************************************************************************/
406 void RTC_clearWakeup (void)
407 {
408  RTC_sleep_wakeup = false;
409 }
410 
411 
412 /**************************************************************************/
420 uint32_t RTC_getPassedSleeptime (void)
421 {
422  uint32_t sSleep = RTC_CounterGet();
423 
424  /* Disable the counter */
425  RTC_Enable(false);
426 
427 #if ULFRCO == 1 /* ULFRCO selected */
428  sSleep /= ULFRCOFREQ;
429 #else /* LFXO selected */
430  sSleep /= LFXOFREQ;
431 #endif /* ULFRCO/LFXO selection */
432 
433  return (sSleep);
434 }
435 
436 
437 /**************************************************************************/
445 static void initRTC (void)
446 {
447 
448 #if ULFRCO == 1 /* ULFRCO selected */
449 
450  /* Enable the ultra low-frequency RC oscillator for the RTC */
451  //CMU_OscillatorEnable(cmuOsc_ULFRCO, true, true); /* The ULFRCO is always on */
452 
453  /* Enable the clock to the interface of the low energy modules
454  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
455  CMU_ClockEnable(cmuClock_HFLE, true);
456 
457  /* Route the ULFRCO clock to the RTC */
458  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_ULFRCO);
459 
460 #else /* LFXO selected */
461 
462  /* Enable the low-frequency crystal oscillator for the RTC */
463  CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
464 
465  /* Enable the clock to the interface of the low energy modules
466  * cmuClock_CORELE = cmuClock_HFLE (deprecated) */
467  CMU_ClockEnable(cmuClock_HFLE, true);
468 
469  /* Route the LFXO clock to the RTC */
470  CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
471 
472 #endif /* ULFRCO/LFXO selection */
473 
474  /* Turn on the RTC clock */
475  CMU_ClockEnable(cmuClock_RTC, true);
476 
477  /* Allow channel 0 to cause an interrupt */
478  RTC_IntEnable(RTC_IEN_COMP0);
479  RTC_IntClear(RTC_IFC_COMP0); /* This statement was in the ULFRCO but not in the LFXO example. It's kept here just in case. */
480  NVIC_ClearPendingIRQ(RTC_IRQn);
481  NVIC_EnableIRQ(RTC_IRQn);
482 
483  /* Configure the RTC settings */
484  RTC_Init_TypeDef rtc = RTC_INIT_DEFAULT;
485  rtc.enable = false; /* Don't start counting when initialization is done */
486 
487  /* Initialize RTC with pre-defined settings */
488  RTC_Init(&rtc);
489 
490 #if DEBUG_DBPRINT == 1 /* DEBUG_DBPRINT */
491 #if ULFRCO == 1 /* ULFRCO selected */
492  dbinfo("RTC initialized with ULFRCO\n\r");
493 #else /* LFXO selected */
494  dbinfo("RTC initialized with LFXO\n\r");
495 #endif /* ULFRCO/LFXO selection */
496 #endif /* DEBUG_DBPRINT */
497 
498  RTC_initialized = true;
499 }
500 
501 
502 #if SYSTICKDELAY == 1 /* SysTick delay selected */
503 /**************************************************************************/
507 void SysTick_Handler (void)
508 {
509  msTicks++; /* Increment counter necessary by SysTick delay functionality */
510 }
511 #endif /* SysTick/RTC selection */
512 
513 
514 /**************************************************************************/
521 //void RTC_IRQHandler (void)
522 //{
523  /* Disable the counter */
524  //RTC_Enable(false);
525 
526  /* Clear the interrupt source */
527  //RTC_IntClear(RTC_IFC_COMP0);
528 
529  /* If the wakeup was caused by "sleeping" (not a delay), act accordingly */
530  //if (sleeping) RTC_sleep_wakeup = true;
531 //}
LFXOFREQ
#define LFXOFREQ
Definition: delay.c:80
RTC_initialized
bool RTC_initialized
Definition: delay.c:95
delay
void delay(uint32_t msDelay)
Wait for a certain amount of milliseconds in EM2/3.
Definition: delay.c:116
sleeping
bool sleeping
Definition: delay.c:94
sleep
void sleep(uint32_t sSleep)
Sleep for a certain amount of seconds in EM2/3.
Definition: delay.c:268
RTC_checkWakeup
bool RTC_checkWakeup(void)
Method to check if the wakeup was caused by the RTC.
Definition: delay.c:396
dbwarnInt
void dbwarnInt(char *message1, int32_t value, char *message2)
ULFRCOFREQ_MS
#define ULFRCOFREQ_MS
Definition: delay.c:79
RTC_getPassedSleeptime
uint32_t RTC_getPassedSleeptime(void)
Method to get the time spend sleeping (in seconds) in the case of GPIO wake-up.
Definition: delay.c:420
delay.h
Delay functionality.
SysTick_initialized
bool SysTick_initialized
Definition: delay.c:98
LFXOFREQ_MS
#define LFXOFREQ_MS
Definition: delay.c:81
SysTick_Handler
void SysTick_Handler(void)
Interrupt Service Routine for system tick counter.
Definition: delay.c:507
ULFRCOFREQ
#define ULFRCOFREQ
Definition: delay.c:78
dbcrit
void dbcrit(char *message)
RTC_clearWakeup
void RTC_clearWakeup(void)
Method to clear RTC_sleep_wakeup.
Definition: delay.c:406
dbinfo
void dbinfo(char *message)
debug_dbprint.h
Enable or disable printing to UART with dbprint.