EFM32 Giant Gecko Software Documentation  efm32gg-doc-4.2.1
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_int.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 
33 #ifndef USTIMER_TIMER
34 #define USTIMER_TIMER USTIMER_TIMER0
35 #endif
36 
37 #if ( USTIMER_TIMER == USTIMER_TIMER0 ) && ( TIMER_COUNT >= 1 )
38  #define TIMER TIMER0
39  #define TIMER_CLK cmuClock_TIMER0
40  #define TIMER_IRQ TIMER0_IRQn
41  #define TIMER_IRQHandler TIMER0_IRQHandler
42 
43 #elif ( USTIMER_TIMER == USTIMER_TIMER1 ) && ( TIMER_COUNT >= 2 )
44  #define TIMER TIMER1
45  #define TIMER_CLK cmuClock_TIMER1
46  #define TIMER_IRQ TIMER1_IRQn
47  #define TIMER_IRQHandler TIMER1_IRQHandler
48 
49 #elif ( USTIMER_TIMER == USTIMER_TIMER2 ) && ( TIMER_COUNT >= 3 )
50  #define TIMER TIMER2
51  #define TIMER_CLK cmuClock_TIMER2
52  #define TIMER_IRQ TIMER2_IRQn
53  #define TIMER_IRQHandler TIMER2_IRQHandler
54 
55 #elif ( USTIMER_TIMER == USTIMER_TIMER3 ) && ( TIMER_COUNT == 4 )
56  #define TIMER TIMER3
57  #define TIMER_CLK cmuClock_TIMER3
58  #define TIMER_IRQ TIMER3_IRQn
59  #define TIMER_IRQHandler TIMER3_IRQHandler
60 
61 #else
62 #error "Illegal USTIMER TIMER selection"
63 #endif
64 
65 static uint32_t freq;
66 static uint32_t minTicks;
67 static volatile bool timeElapsed = false;
68 
69 static void DelayTicksEM1( uint16_t ticks );
70 static void DelayTicksPolled( uint16_t ticks );
71 
74 /***************************************************************************/
87 {
90  uint32_t coreClockScale;
91 
92  timerCCInit.mode = timerCCModeCompare;
93  CMU_ClockEnable( TIMER_CLK, true );
94  TIMER_TopSet( TIMER, 0xFFFF );
95  TIMER_InitCC( TIMER, 0, &timerCCInit );
96 
97  /* Run timer at slowest frequency that still gives less than 1 us per tick */
99  do
100  {
101  TIMER_Init( TIMER, &timerInit );
102 
104  freq /= 1 << timerInit.prescale;
105  timerInit.prescale++;
106  }
107  while ( ( timerInit.prescale <= _TIMER_CTRL_PRESC_DIV1024 )
108  && ( freq > 2000000 ) );
109 
110  /* Figure out the minimum delay we can have when using timer interrupt
111  * to avoid that actual delay become a full timer counter lap.
112  * We are assuming that this number scales with mcu core clock.
113  * The number is found by trial and err on a GG running at 14MHz.
114  */
115  coreClockScale = ( 4 * 48000000 ) / CMU_ClockFreqGet( cmuClock_CORE );
116  minTicks = ( ( (uint64_t)freq * coreClockScale ) + 500000 ) / 1000000;
117  timeElapsed = false;
118 
120  NVIC_ClearPendingIRQ( TIMER_IRQ );
121  NVIC_EnableIRQ( TIMER_IRQ );
122 
123  return ECODE_EMDRV_USTIMER_OK;
124 }
125 
126 /***************************************************************************/
138 {
139  NVIC_DisableIRQ( TIMER_IRQ );
141 
142  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
143  NVIC_ClearPendingIRQ( TIMER_IRQ );
144 
145  TIMER_Enable( TIMER, false );
146  CMU_ClockEnable( TIMER_CLK, false );
147 
148  return ECODE_EMDRV_USTIMER_OK;
149 }
150 
151 /***************************************************************************/
168 Ecode_t USTIMER_Delay( uint32_t usec )
169 {
170  uint64_t totalTicks;
171 
172  totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
173 
174  /* The timer counter is 16 bits wide, split the total wait up in chunks */
175  /* of a little less than 2^16. */
176  while ( totalTicks > 65000 )
177  {
178  DelayTicksEM1( 65000 );
179  totalTicks -= 65000;
180  }
181  DelayTicksEM1( (uint16_t)totalTicks );
182 
183  return ECODE_EMDRV_USTIMER_OK;
184 }
185 
186 /***************************************************************************/
204 {
205  uint64_t totalTicks;
206 
207  totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
208 
209  /* The timer counter is 16 bits wide, split the total wait up in chunks */
210  /* of a little less than 2^16. */
211  while ( totalTicks > 65000 )
212  {
213  DelayTicksPolled( 65000 );
214  totalTicks -= 65000;
215  }
216  DelayTicksPolled( (uint16_t)totalTicks );
217 
218  return ECODE_EMDRV_USTIMER_OK;
219 }
220 
221 
224 void TIMER_IRQHandler( void )
225 {
226  uint32_t flags;
227 
228  flags = TIMER_IntGet( TIMER );
229 
230  if ( flags & TIMER_IF_CC0 )
231  {
232  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
233  timeElapsed = true;
234  }
235 }
236 
237 static void DelayTicksPolled( uint16_t ticks )
238 {
239  uint16_t startTime;
240  volatile uint16_t now;
241 
242  if ( ticks )
243  {
244  startTime = TIMER_CounterGet( TIMER );
245  do
246  {
247  now = TIMER_CounterGet( TIMER );
248  } while ( (uint16_t)( now - startTime ) < ticks );
249  }
250 }
251 
252 static void DelayTicksEM1( uint16_t ticks )
253 {
254  if ( ticks )
255  {
256  /* Arm TIMER compare interrupt */
257 
258  INT_Disable();
259 
260  /* The following lines costs 2.7us@48MHz and 7.5us@14MHz (measured with GG)*/
261  TIMER_CompareSet( TIMER, 0,
262  TIMER_CounterGet( TIMER ) + EFM32_MAX( minTicks, ticks ) );
263  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
264  TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
265 
266  INT_Enable();
267 
268  while ( ! timeElapsed )
269  {
270  EMU_EnterEM1();
271  }
272  timeElapsed = false;
273 
275  }
276 }
277 
280 /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************/
321 
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:730
__STATIC_INLINE void TIMER_TopSet(TIMER_TypeDef *timer, uint32_t val)
Set top value for timer.
Definition: em_timer.h:900
#define TIMER_IFC_CC0
__STATIC_INLINE void TIMER_Enable(TIMER_TypeDef *timer, bool enable)
Start/stop TIMER.
Definition: em_timer.h:613
#define EFM32_MAX(a, b)
Definition: em_common.h:81
#define TIMER_INITCC_DEFAULT
Definition: em_timer.h:397
__STATIC_INLINE uint32_t INT_Enable(void)
Enable interrupts.
Definition: em_int.h:94
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:713
CMSIS Cortex-M Peripheral Access Layer for Silicon Laboratories microcontroller devices.
#define TIMER_IF_CC0
TIMER_CCMode_TypeDef mode
Definition: em_timer.h:375
#define _TIMER_CTRL_PRESC_DIV1024
#define TIMER_IEN_CC0
__STATIC_INLINE void TIMER_IntEnable(TIMER_TypeDef *timer, uint32_t flags)
Enable one or more TIMER interrupts.
Definition: em_timer.h:752
Emlib 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:86
Interrupt enable/disable unit API.
__STATIC_INLINE void EMU_EnterEM1(void)
Enter energy mode 1 (EM1).
Definition: em_emu.h:448
__STATIC_INLINE uint32_t TIMER_IntGet(TIMER_TypeDef *timer)
Get pending TIMER interrupt flags.
Definition: em_timer.h:772
#define TIMER_INIT_DEFAULT
Definition: em_timer.h:317
void CMU_ClockEnable(CMU_Clock_TypeDef clock, bool enable)
Enable/disable a clock.
Definition: em_cmu.c:1369
Ecode_t USTIMER_DeInit(void)
Deinitialize USTIMER driver.
Definition: ustimer.c:137
__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:563
__STATIC_INLINE uint32_t TIMER_CounterGet(TIMER_TypeDef *timer)
Get TIMER counter value.
Definition: em_timer.h:581
TIMER_Prescale_TypeDef prescale
Definition: em_timer.h:279
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:203
#define ECODE_EMDRV_USTIMER_OK
Success return value.
Definition: ustimer.h:38
#define _TIMER_CTRL_PRESC_DIV1
uint32_t Ecode_t
Typedef for API function errorcode return values.
Definition: ecode.h:31
__STATIC_INLINE uint32_t INT_Disable(void)
Disable interrupts.
Definition: em_int.h:71
Microsecond delay function API definition.
Ecode_t USTIMER_Delay(uint32_t usec)
Delay a given number of microseconds.
Definition: ustimer.c:168
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:1482
TIMER_Prescale_TypeDef
Definition: em_timer.h:205