EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
ustimer.c
Go to the documentation of this file.
1 /**************************************************************************/
16 #include <stdbool.h>
17 #include "em_device.h"
18 #include "em_common.h"
19 #include "em_cmu.h"
20 #include "em_emu.h"
21 #include "em_core.h"
22 #include "em_timer.h"
23 
24 #include "ustimer.h"
25 
28 #define USTIMER_TIMER0 0
29 #define USTIMER_TIMER1 1
30 #define USTIMER_TIMER2 2
31 #define USTIMER_TIMER3 3
32 #define USTIMER_TIMER4 4
33 #define USTIMER_TIMER5 5
34 #define USTIMER_TIMER6 6
35 
36 #define USTIMER_WTIMER0 10
37 #define USTIMER_WTIMER1 11
38 #define USTIMER_WTIMER2 12
39 #define USTIMER_WTIMER3 13
40 
41 #ifndef USTIMER_TIMER
42 #define USTIMER_TIMER USTIMER_TIMER0
43 #endif
44 
45 #if ( USTIMER_TIMER == USTIMER_TIMER0 ) && ( TIMER_COUNT >= 1 )
46  #define TIMER TIMER0
47  #define TIMER_CLK cmuClock_TIMER0
48  #define TIMER_IRQ TIMER0_IRQn
49  #define TIMER_IRQHandler TIMER0_IRQHandler
50 
51 #elif ( USTIMER_TIMER == USTIMER_TIMER1 ) && ( TIMER_COUNT >= 2 )
52  #define TIMER TIMER1
53  #define TIMER_CLK cmuClock_TIMER1
54  #define TIMER_IRQ TIMER1_IRQn
55  #define TIMER_IRQHandler TIMER1_IRQHandler
56 
57 #elif ( USTIMER_TIMER == USTIMER_TIMER2 ) && ( TIMER_COUNT >= 3 )
58  #define TIMER TIMER2
59  #define TIMER_CLK cmuClock_TIMER2
60  #define TIMER_IRQ TIMER2_IRQn
61  #define TIMER_IRQHandler TIMER2_IRQHandler
62 
63 #elif ( USTIMER_TIMER == USTIMER_TIMER3 ) && ( TIMER_COUNT >= 4 )
64  #define TIMER TIMER3
65  #define TIMER_CLK cmuClock_TIMER3
66  #define TIMER_IRQ TIMER3_IRQn
67  #define TIMER_IRQHandler TIMER3_IRQHandler
68 
69 #elif ( USTIMER_TIMER == USTIMER_TIMER4 ) && ( TIMER_COUNT >= 5 )
70  #define TIMER TIMER4
71  #define TIMER_CLK cmuClock_TIMER4
72  #define TIMER_IRQ TIMER4_IRQn
73  #define TIMER_IRQHandler TIMER4_IRQHandler
74 
75 #elif ( USTIMER_TIMER == USTIMER_TIMER5 ) && ( TIMER_COUNT >= 6 )
76  #define TIMER TIMER5
77  #define TIMER_CLK cmuClock_TIMER5
78  #define TIMER_IRQ TIMER5_IRQn
79  #define TIMER_IRQHandler TIMER5_IRQHandler
80 
81 #elif ( USTIMER_TIMER == USTIMER_TIMER6 ) && ( TIMER_COUNT >= 7 )
82  #define TIMER TIMER6
83  #define TIMER_CLK cmuClock_TIMER6
84  #define TIMER_IRQ TIMER6_IRQn
85  #define TIMER_IRQHandler TIMER6_IRQHandler
86 
87 #elif ( USTIMER_TIMER == USTIMER_WTIMER0 ) && ( WTIMER_COUNT >= 1 )
88  #define TIMER WTIMER0
89  #define TIMER_CLK cmuClock_WTIMER0
90  #define TIMER_IRQ WTIMER0_IRQn
91  #define TIMER_IRQHandler WTIMER0_IRQHandler
92 
93 #elif ( USTIMER_TIMER == USTIMER_WTIMER1 ) && ( WTIMER_COUNT >= 2 )
94  #define TIMER WTIMER1
95  #define TIMER_CLK cmuClock_WTIMER1
96  #define TIMER_IRQ WTIMER1_IRQn
97  #define TIMER_IRQHandler WTIMER1_IRQHandler
98 
99 #elif ( USTIMER_TIMER == USTIMER_WTIMER2 ) && ( WTIMER_COUNT >= 3 )
100  #define TIMER WTIMER2
101  #define TIMER_CLK cmuClock_WTIMER2
102  #define TIMER_IRQ WTIMER2_IRQn
103  #define TIMER_IRQHandler WTIMER2_IRQHandler
104 
105 #elif ( USTIMER_TIMER == USTIMER_WTIMER3 ) && ( WTIMER_COUNT >= 4 )
106  #define TIMER WTIMER3
107  #define TIMER_CLK cmuClock_WTIMER3
108  #define TIMER_IRQ WTIMER3_IRQn
109  #define TIMER_IRQHandler WTIMER3_IRQHandler
110 
111 #else
112 #error "Illegal USTIMER TIMER selection"
113 #endif
114 
115 // Use 16-bit TOP value for timer, independent of the width of the timer
116 #define TIMER_MAX 0xFFFF
117 
118 static uint32_t freq;
119 static uint32_t minTicks;
120 static volatile bool timeElapsed = false;
121 
122 static void DelayTicksEM1( uint16_t ticks );
123 static void DelayTicksPolled( uint16_t ticks );
124 
127 /***************************************************************************/
140 {
143  uint32_t coreClockScale;
144 
145  timerCCInit.mode = timerCCModeCompare;
146  CMU_ClockEnable( TIMER_CLK, true );
147  TIMER_TopSet( TIMER, TIMER_MAX );
148  TIMER_InitCC( TIMER, 0, &timerCCInit );
149 
150  /* Run timer at slowest frequency that still gives less than 1 us per tick */
152  do
153  {
154  TIMER_Init( TIMER, &timerInit );
155 
157  freq /= 1 << timerInit.prescale;
158  timerInit.prescale++;
159  }
160  while ( ( timerInit.prescale <= _TIMER_CTRL_PRESC_DIV1024 )
161  && ( freq > 2000000 ) );
162 
163  /* Figure out the minimum delay we can have when using timer interrupt
164  * to avoid that actual delay become a full timer counter lap.
165  * We are assuming that this number scales with mcu core clock.
166  * The number is found by trial and err on a GG running at 14MHz.
167  */
168  coreClockScale = ( 4 * 48000000 ) / CMU_ClockFreqGet( cmuClock_CORE );
169  minTicks = ( ( (uint64_t)freq * coreClockScale ) + 500000 ) / 1000000;
170  timeElapsed = false;
171 
173  NVIC_ClearPendingIRQ( TIMER_IRQ );
174  NVIC_EnableIRQ( TIMER_IRQ );
175 
176  return ECODE_EMDRV_USTIMER_OK;
177 }
178 
179 /***************************************************************************/
191 {
192  NVIC_DisableIRQ( TIMER_IRQ );
194 
195  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
196  NVIC_ClearPendingIRQ( TIMER_IRQ );
197 
198  TIMER_Enable( TIMER, false );
199  CMU_ClockEnable( TIMER_CLK, false );
200 
201  return ECODE_EMDRV_USTIMER_OK;
202 }
203 
204 /***************************************************************************/
221 Ecode_t USTIMER_Delay( uint32_t usec )
222 {
223  uint64_t totalTicks;
224 
225  totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
226 
227  /* The timer counter is 16 bits wide, split the total wait up in chunks */
228  /* of a little less than 2^16. */
229  while ( totalTicks > 65000 )
230  {
231  DelayTicksEM1( 65000 );
232  totalTicks -= 65000;
233  }
234  DelayTicksEM1( (uint16_t)totalTicks );
235 
236  return ECODE_EMDRV_USTIMER_OK;
237 }
238 
239 /***************************************************************************/
257 {
258  uint64_t totalTicks;
259 
260  totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
261 
262  /* The timer counter is 16 bits wide, split the total wait up in chunks */
263  /* of a little less than 2^16. */
264  while ( totalTicks > 65000 )
265  {
266  DelayTicksPolled( 65000 );
267  totalTicks -= 65000;
268  }
269  DelayTicksPolled( (uint16_t)totalTicks );
270 
271  return ECODE_EMDRV_USTIMER_OK;
272 }
273 
274 
277 void TIMER_IRQHandler( void )
278 {
279  uint32_t flags;
280 
281  flags = TIMER_IntGet( TIMER );
282 
283  if ( flags & TIMER_IF_CC0 )
284  {
285  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
286  timeElapsed = true;
287  }
288 }
289 
290 static void DelayTicksPolled( uint16_t ticks )
291 {
292  uint16_t startTime;
293  volatile uint16_t now;
294 
295  if ( ticks )
296  {
297  startTime = TIMER_CounterGet( TIMER );
298  do
299  {
300  now = TIMER_CounterGet( TIMER );
301  } while ( (uint16_t)( now - startTime ) < ticks );
302  }
303 }
304 
305 static void DelayTicksEM1( uint16_t ticks )
306 {
307  uint32_t cmp;
308 
309  if ( ticks )
310  {
311  /* Arm TIMER compare interrupt */
312 
314  /* The following lines costs 2.7us@48MHz and 7.5us@14MHz (measured with GG)*/
315  cmp = (TIMER_CounterGet( TIMER ) + SL_MAX( minTicks, ticks )) & TIMER_MAX;
316  TIMER_CompareSet( TIMER, 0, cmp );
317  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
318  TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
319  )
320 
321  while ( ! timeElapsed )
322  {
323  EMU_EnterEM1();
324  }
325  timeElapsed = false;
326 
328  }
329 }
330 
333 /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************/
376 
Clock management unit (CMU) API.
__STATIC_INLINE void TIMER_IntDisable(TIMER_TypeDef *timer, uint32_t flags)
Disable one or more TIMER interrupts.
Definition: em_timer.h:777
__STATIC_INLINE void TIMER_TopSet(TIMER_TypeDef *timer, uint32_t val)
Set top value for timer.
Definition: em_timer.h:948
__STATIC_INLINE void TIMER_Enable(TIMER_TypeDef *timer, bool enable)
Start/stop TIMER.
Definition: em_timer.h:660
#define TIMER_INITCC_DEFAULT
Definition: em_timer.h:381
#define _TIMER_CTRL_PRESC_DIV1024
#define TIMER_IEN_CC0
Timer/counter (TIMER) peripheral API.
__STATIC_INLINE void TIMER_IntClear(TIMER_TypeDef *timer, uint32_t flags)
Clear one or more pending TIMER interrupts.
Definition: em_timer.h:760
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
TIMER_CCMode_TypeDef mode
Definition: em_timer.h:359
__STATIC_INLINE void TIMER_IntEnable(TIMER_TypeDef *timer, uint32_t flags)
Enable one or more TIMER interrupts.
Definition: em_timer.h:799
General purpose utilities.
Ecode_t USTIMER_Init(void)
Activate and initialize the hardware timer used to pace the 1 microsecond delay functions.
Definition: ustimer.c:139
#define CORE_ATOMIC_SECTION(yourcode)
Definition: em_core.h:126
#define TIMER_IFC_CC0
__STATIC_INLINE void EMU_EnterEM1(void)
Enter energy mode 1 (EM1).
Definition: em_emu.h:713
__STATIC_INLINE uint32_t TIMER_IntGet(TIMER_TypeDef *timer)
Get pending TIMER interrupt flags.
Definition: em_timer.h:819
#define TIMER_INIT_DEFAULT
Definition: em_timer.h:301
uint32_t Ecode_t
Typedef for API function error code return values.
Definition: ecode.h:51
Core interrupt handling API.
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1453
#define TIMER_IF_CC0
Ecode_t USTIMER_DeInit(void)
Deinitialize USTIMER driver.
Definition: ustimer.c:190
__STATIC_INLINE void TIMER_CompareSet(TIMER_TypeDef *timer, unsigned int ch, uint32_t val)
Set compare value for compare/capture channel when operating in compare or PWM mode.
Definition: em_timer.h:608
__STATIC_INLINE uint32_t TIMER_CounterGet(TIMER_TypeDef *timer)
Get TIMER counter value.
Definition: em_timer.h:627
TIMER_Prescale_TypeDef prescale
Definition: em_timer.h:263
#define _TIMER_CTRL_PRESC_DIV1
void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
Initialize TIMER.
Definition: em_timer.c:76
Energy management unit (EMU) peripheral API.
Ecode_t USTIMER_DelayIntSafe(uint32_t usec)
Delay a given number of microseconds.
Definition: ustimer.c:256
#define ECODE_EMDRV_USTIMER_OK
Success return value.
Definition: ustimer.h:36
#define SL_MAX(a, b)
Macro for getting maximum value. No sideeffects, a and b are evaluated once only. ...
Definition: em_common.h:140
Microsecond delay function API definition.
Ecode_t USTIMER_Delay(uint32_t usec)
Delay a given number of microseconds.
Definition: ustimer.c:221
void TIMER_InitCC(TIMER_TypeDef *timer, unsigned int ch, const TIMER_InitCC_TypeDef *init)
Initialize TIMER compare/capture channel.
Definition: em_timer.c:130
uint32_t CMU_ClockFreqGet(CMU_Clock_TypeDef clock)
Get clock frequency for a clock point.
Definition: em_cmu.c:1550
TIMER_Prescale_TypeDef
Definition: em_timer.h:189