EFM32 Happy Gecko Software Documentation  efm32hg-doc-5.1.2
em_usbtimer.c
Go to the documentation of this file.
1 /***************************************************************************/
16 #include "em_device.h"
17 #if defined( USB_PRESENT ) && ( USB_COUNT == 1 )
18 #include "em_usb.h"
19 #if defined( USB_DEVICE ) || defined( USB_HOST )
20 
21 #include "em_cmu.h"
22 #include "em_core.h"
23 #include "em_timer.h"
24 #include "em_usbtypes.h"
25 #include "em_usbhal.h"
26 
27 /*
28  * Use one HW timer to serve n software milisecond timers.
29  * A timer is, when running, in a linked list of timers.
30  * A given timers timeout period is the acculmulated timeout
31  * of all timers preceeding it in the queue.
32  * This makes timer start (linked list insertion) computing intensive,
33  * but the checking of the queue at each tick very effective.
34  * ______ ______ ______
35  * | | --->| | --->| |
36  * head --> | | | | | | | |
37  * |______|--- |______|--- |______|---/ NULL
38  */
39 
42 #ifndef USB_TIMER
43 #define USB_TIMER USB_TIMER0
44 #endif
45 
46 #if ( USB_TIMER == USB_TIMER0 ) && ( TIMER_COUNT >= 1 )
47  #define TIMER TIMER0
48  #define TIMER_CLK cmuClock_TIMER0
49  #define TIMER_IRQ TIMER0_IRQn
50  #define TIMER_IRQHandler TIMER0_IRQHandler
51 
52 #elif ( USB_TIMER == USB_TIMER1 ) && ( TIMER_COUNT >= 2 )
53  #define TIMER TIMER1
54  #define TIMER_CLK cmuClock_TIMER1
55  #define TIMER_IRQ TIMER1_IRQn
56  #define TIMER_IRQHandler TIMER1_IRQHandler
57 
58 #elif ( USB_TIMER == USB_TIMER2 ) && ( TIMER_COUNT >= 3 )
59  #define TIMER TIMER2
60  #define TIMER_CLK cmuClock_TIMER2
61  #define TIMER_IRQ TIMER2_IRQn
62  #define TIMER_IRQHandler TIMER2_IRQHandler
63 
64 #elif ( USB_TIMER == USB_TIMER3 ) && ( TIMER_COUNT == 4 )
65  #define TIMER TIMER3
66  #define TIMER_CLK cmuClock_TIMER3
67  #define TIMER_IRQ TIMER3_IRQn
68  #define TIMER_IRQHandler TIMER3_IRQHandler
69 
70 #else
71 #error "Illegal USB TIMER definition"
72 #endif
73 
74 typedef struct _timer
75 {
76  uint32_t timeout; /* Delta value relative to prev. timer */
77  struct _timer *next;
79  bool running;
80 } USBTIMER_Timer_TypeDef;
81 
82 #if ( NUM_QTIMERS > 0 )
83 static USBTIMER_Timer_TypeDef timers[ NUM_QTIMERS ];
84 static USBTIMER_Timer_TypeDef *head = NULL;
85 #endif
86 
87 static uint32_t ticksPrMs, ticksPr1us, ticksPr10us, ticksPr100us;
88 
89 #if ( NUM_QTIMERS > 0 )
90 
91 static void TimerTick( void );
92 
93 void TIMER_IRQHandler( void )
94 {
95  uint32_t flags;
96 
97  flags = TIMER_IntGet( TIMER );
98 
99  if ( flags & TIMER_IF_CC0 )
100  {
101  TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
102  TIMER_CompareSet(TIMER, 0,
103  (TIMER_CaptureGet(TIMER, 0) + ticksPrMs)
104  & TIMER_MaxCount(TIMER));
105  TimerTick();
106  }
107 }
108 #endif /* ( NUM_QTIMERS > 0 ) */
109 
110 static void DelayTicks( uint16_t ticks )
111 {
112  uint16_t startTime;
113  volatile uint16_t now;
114 
115  if ( ticks )
116  {
117  startTime = TIMER_CounterGet( TIMER );
118  do
119  {
120  now = TIMER_CounterGet(TIMER);
121  } while ( (uint16_t)( now - startTime ) < ticks );
122  }
123 }
124 
130 /***************************************************************************/
138 void USBTIMER_DelayMs( uint32_t msec )
139 {
140  uint64_t totalTicks;
141 
142  totalTicks = (uint64_t)ticksPrMs * msec;
143  while ( totalTicks > 20000 )
144  {
145  DelayTicks( 20000 );
146  totalTicks -= 20000;
147  }
148  DelayTicks( (uint16_t)totalTicks );
149 }
150 
151 /***************************************************************************/
159 void USBTIMER_DelayUs( uint32_t usec )
160 {
161  uint64_t totalTicks;
162 
163  totalTicks = (uint64_t)ticksPr1us * usec;
164  if ( totalTicks == 0 )
165  {
166  usec /= 10;
167  totalTicks = (uint64_t)ticksPr10us * usec;
168 
169  if ( totalTicks == 0 )
170  {
171  usec /= 10;
172  totalTicks = (uint64_t)ticksPr100us * usec;
173  }
174  }
175 
176  while ( totalTicks > 60000 )
177  {
178  DelayTicks( 60000 );
179  totalTicks -= 60000;
180  }
181  DelayTicks( (uint16_t)totalTicks );
182 }
183 
184 /***************************************************************************/
193 void USBTIMER_Init( void )
194 {
195  uint32_t freq;
198 
200  ticksPrMs = ( freq + 500 ) / 1000;
201  ticksPr1us = ( freq + 500000 ) / 1000000;
202  ticksPr10us = ( freq + 50000 ) / 100000;
203  ticksPr100us = ( freq + 5000 ) / 10000;
204 
205  timerCCInit.mode = timerCCModeCompare;
206  CMU_ClockEnable( TIMER_CLK, true );
207  TIMER_TopSet( TIMER, 0xFFFF );
208  TIMER_InitCC( TIMER, 0, &timerCCInit );
209  TIMER_Init( TIMER, &timerInit );
210 
211 #if ( NUM_QTIMERS > 0 )
212  TIMER_IntClear( TIMER, 0xFFFFFFFF );
213  TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
214  TIMER_CompareSet( TIMER, 0, TIMER_CounterGet( TIMER ) + ticksPrMs );
215  NVIC_ClearPendingIRQ( TIMER_IRQ );
216  NVIC_EnableIRQ( TIMER_IRQ );
217 #endif /* ( NUM_QTIMERS > 0 ) */
218 }
219 
220 #if ( NUM_QTIMERS > 0 ) || defined( DOXY_DOC_ONLY )
221 /***************************************************************************/
237 void USBTIMER_Start( uint32_t id, uint32_t timeout,
238  USBTIMER_Callback_TypeDef callback )
239 {
240  uint32_t accumulated;
241  USBTIMER_Timer_TypeDef *this, **last;
243 
245 
246  if ( timers[ id ].running )
247  {
248  USBTIMER_Stop( id );
249  }
250 
251  if ( timeout == 0 )
252  {
253  callback();
255  return;
256  }
257 
258  timers[ id ].running = true;
259  timers[ id ].callback = callback;
260  timers[ id ].next = NULL;
261 
262  if ( !head ) /* Queue empty ? */
263  {
264  timers[ id ].timeout = timeout;
265  head = &timers[ id ];
266  }
267  else
268  {
269  this = head;
270  last = &head;
271  accumulated = 0;
272 
273  /* Do a sorted insert */
274  while ( this )
275  {
276  if ( timeout < accumulated + this->timeout ) /* Insert before "this" ? */
277  {
278  timers[ id ].timeout = timeout - accumulated;
279  timers[ id ].next = this;
280  *last = &timers[ id ];
281  this->timeout -= timers[ id ].timeout; /* Adjust timeout */
282  break;
283  }
284  else if ( this->next == NULL ) /* At end of queue ? */
285  {
286  timers[ id ].timeout = timeout - accumulated - this->timeout;
287  this->next = &timers[ id ];
288  break;
289  }
290  accumulated += this->timeout;
291  last = &this->next;
292  this = this->next;
293  }
294  }
295 
297 }
298 
299 /***************************************************************************/
306 void USBTIMER_Stop( uint32_t id )
307 {
308  USBTIMER_Timer_TypeDef *this, **last;
310 
312 
313  if ( head ) /* Queue empty ? */
314  {
315  this = head;
316  last = &head;
317  timers[ id ].running = false;
318 
319  while ( this )
320  {
321  if ( this == &timers[ id ] ) /* Correct timer ? */
322  {
323  if ( this->next )
324  {
325  this->next->timeout += timers[ id ].timeout; /* Adjust timeout */
326  }
327  *last = this->next;
328  break;
329  }
330  last = &this->next;
331  this = this->next;
332  }
333  }
334 
336 }
337 #endif /* ( NUM_QTIMERS > 0 ) */
338 
341 #if ( NUM_QTIMERS > 0 )
342 
344 static void TimerTick( void )
345 {
348 
350 
351  if ( head )
352  {
353  head->timeout--;
354 
355  while ( head )
356  {
357  if ( head->timeout == 0 )
358  {
359  cb = head->callback;
360  head->running = false;
361  head = head->next;
362  /* The callback may place new items in the queue !!! */
363  if ( cb )
364  {
365  (cb)();
366  }
367  continue; /* There might be more than one timeout pr. tick */
368  }
369  break;
370  }
371  }
372 
374 }
376 #endif /* ( NUM_QTIMERS > 0 ) */
377 
378 #endif /* defined( USB_DEVICE ) || defined( USB_HOST ) */
379 #endif /* defined( USB_PRESENT ) && ( USB_COUNT == 1 ) */
Clock management unit (CMU) API.
__STATIC_INLINE void TIMER_TopSet(TIMER_TypeDef *timer, uint32_t val)
Set top value for timer.
Definition: em_timer.h:948
#define CORE_DECLARE_IRQ_STATE
Definition: em_core.h:85
void USBTIMER_Stop(uint32_t id)
Stop a timer.
Definition: em_usbtimer.c:306
#define TIMER_INITCC_DEFAULT
Definition: em_timer.h:381
#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
void(* USBTIMER_Callback_TypeDef)(void)
USBTIMER callback function.
Definition: em_usb.h:673
__STATIC_INLINE void TIMER_IntEnable(TIMER_TypeDef *timer, uint32_t flags)
Enable one or more TIMER interrupts.
Definition: em_timer.h:799
void USBTIMER_DelayMs(uint32_t msec)
Active wait millisecond delay function. Can also be used inside interrupt handlers.
Definition: em_usbtimer.c:138
#define CORE_ENTER_ATOMIC()
Definition: em_core.h:138
#define TIMER_IFC_CC0
__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
USB protocol stack library API for EFM32/EZR32.
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
__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
__STATIC_INLINE uint32_t TIMER_CaptureGet(TIMER_TypeDef *timer, unsigned int ch)
Get capture value for compare/capture channel when operating in capture mode.
Definition: em_timer.h:560
#define CORE_EXIT_ATOMIC()
Definition: em_core.h:142
__STATIC_INLINE uint32_t TIMER_MaxCount(const TIMER_TypeDef *ref)
Get the Max count of the timer.
Definition: em_timer.h:529
void TIMER_Init(TIMER_TypeDef *timer, const TIMER_Init_TypeDef *init)
Initialize TIMER.
Definition: em_timer.c:76
USB protocol stack library, low level USB peripheral access.
void USBTIMER_Init(void)
Activate the hardware timer used to pace the 1 millisecond timer system.
Definition: em_usbtimer.c:193
USB protocol stack library, internal type definitions.
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
void USBTIMER_Start(uint32_t id, uint32_t timeout, USBTIMER_Callback_TypeDef callback)
Start a timer.
Definition: em_usbtimer.c:237
void USBTIMER_DelayUs(uint32_t usec)
Active wait microsecond delay function. Can also be used inside interrupt handlers.
Definition: em_usbtimer.c:159