ustimer.c

Go to the documentation of this file.
00001 /**************************************************************************/
00016 #include <stdbool.h>
00017 #include "em_device.h"
00018 #include "em_common.h"
00019 #include "em_cmu.h"
00020 #include "em_emu.h"
00021 #include "em_int.h"
00022 #include "em_timer.h"
00023 
00024 #include "ustimer.h"
00025 
00028 #ifndef USTIMER_TIMER
00029 #define USTIMER_TIMER USTIMER_TIMER0
00030 #endif
00031 
00032 #if ( USTIMER_TIMER == USTIMER_TIMER0 ) && ( TIMER_COUNT >= 1 )
00033   #define TIMER             TIMER0
00034   #define TIMER_CLK         cmuClock_TIMER0
00035   #define TIMER_IRQ         TIMER0_IRQn
00036   #define TIMER_IRQHandler  TIMER0_IRQHandler
00037 
00038 #elif ( USTIMER_TIMER == USTIMER_TIMER1 ) && ( TIMER_COUNT >= 2 )
00039   #define TIMER             TIMER1
00040   #define TIMER_CLK         cmuClock_TIMER1
00041   #define TIMER_IRQ         TIMER1_IRQn
00042   #define TIMER_IRQHandler  TIMER1_IRQHandler
00043 
00044 #elif ( USTIMER_TIMER == USTIMER_TIMER2 ) && ( TIMER_COUNT >= 3 )
00045   #define TIMER             TIMER2
00046   #define TIMER_CLK         cmuClock_TIMER2
00047   #define TIMER_IRQ         TIMER2_IRQn
00048   #define TIMER_IRQHandler  TIMER2_IRQHandler
00049 
00050 #elif ( USTIMER_TIMER == USTIMER_TIMER3 ) && ( TIMER_COUNT == 4 )
00051   #define TIMER             TIMER3
00052   #define TIMER_CLK         cmuClock_TIMER3
00053   #define TIMER_IRQ         TIMER3_IRQn
00054   #define TIMER_IRQHandler  TIMER3_IRQHandler
00055 
00056 #else
00057 #error "Illegal USTIMER TIMER selection"
00058 #endif
00059 
00060 static uint32_t freq;
00061 static uint32_t minTicks;
00062 static volatile bool timeElapsed = false;
00063 
00064 static void DelayTicksEM1( uint16_t ticks );
00065 static void DelayTicksPolled( uint16_t ticks );
00066 
00069 /***************************************************************************/
00081 Ecode_t USTIMER_Init( void )
00082 {
00083   TIMER_Init_TypeDef timerInit     = TIMER_INIT_DEFAULT;
00084   TIMER_InitCC_TypeDef timerCCInit = TIMER_INITCC_DEFAULT;
00085   uint32_t coreClockScale;
00086 
00087   timerCCInit.mode = timerCCModeCompare;
00088   CMU_ClockEnable( TIMER_CLK, true );
00089   TIMER_TopSet( TIMER, 0xFFFF );
00090   TIMER_InitCC( TIMER, 0, &timerCCInit );
00091 
00092   /* Run timer at slowest frequency that still gives less than 1 us per tick */
00093   timerInit.prescale = (TIMER_Prescale_TypeDef)_TIMER_CTRL_PRESC_DIV1;
00094   do
00095   {
00096     TIMER_Init( TIMER, &timerInit );
00097 
00098     freq = CMU_ClockFreqGet( cmuClock_HFPER );
00099     freq /= 1 << timerInit.prescale;
00100     timerInit.prescale++;
00101   }
00102   while ( ( timerInit.prescale <= _TIMER_CTRL_PRESC_DIV1024 )
00103           && ( freq > 2000000 ) );
00104 
00105   /* Figure out the minimum delay we can have when using timer interrupt
00106    * to avoid that actual delay become a full timer counter lap.
00107    * We are assuming that this number scales with mcu core clock.
00108    * The number is found by trial and err on a GG running at 14MHz.
00109    */
00110   coreClockScale = ( 4 * 48000000 ) / CMU_ClockFreqGet( cmuClock_CORE );
00111   minTicks = ( ( (uint64_t)freq * coreClockScale ) + 500000 ) / 1000000;
00112   timeElapsed = false;
00113 
00114   TIMER_IntDisable( TIMER, TIMER_IEN_CC0 );
00115   NVIC_ClearPendingIRQ( TIMER_IRQ );
00116   NVIC_EnableIRQ( TIMER_IRQ );
00117 
00118   return ECODE_EMDRV_USTIMER_OK;
00119 }
00120 
00121 /***************************************************************************/
00132 Ecode_t USTIMER_DeInit( void )
00133 {
00134   NVIC_DisableIRQ( TIMER_IRQ );
00135   TIMER_IntDisable( TIMER, TIMER_IEN_CC0 );
00136 
00137   TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
00138   NVIC_ClearPendingIRQ( TIMER_IRQ );
00139 
00140   TIMER_Enable( TIMER, false );
00141   CMU_ClockEnable( TIMER_CLK, false );
00142 
00143   return ECODE_EMDRV_USTIMER_OK;
00144 }
00145 
00146 /***************************************************************************/
00163 Ecode_t USTIMER_Delay( uint32_t usec )
00164 {
00165   uint64_t totalTicks;
00166 
00167   totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
00168 
00169   /* The timer counter is 16 bits wide, split the total wait up in chunks */
00170   /* of a little less than 2^16.                                          */
00171   while ( totalTicks > 65000 )
00172   {
00173     DelayTicksEM1( 65000 );
00174     totalTicks -= 65000;
00175   }
00176   DelayTicksEM1( (uint16_t)totalTicks );
00177 
00178   return ECODE_EMDRV_USTIMER_OK;
00179 }
00180 
00181 /***************************************************************************/
00198 Ecode_t USTIMER_DelayIntSafe( uint32_t usec )
00199 {
00200   uint64_t totalTicks;
00201 
00202   totalTicks = ( ( (uint64_t)freq * usec ) + 500000 ) / 1000000;
00203 
00204   /* The timer counter is 16 bits wide, split the total wait up in chunks */
00205   /* of a little less than 2^16.                                          */
00206   while ( totalTicks > 65000 )
00207   {
00208     DelayTicksPolled( 65000 );
00209     totalTicks -= 65000;
00210   }
00211   DelayTicksPolled( (uint16_t)totalTicks );
00212 
00213   return ECODE_EMDRV_USTIMER_OK;
00214 }
00215 
00216 
00219 void TIMER_IRQHandler( void )
00220 {
00221   uint32_t flags;
00222 
00223   flags = TIMER_IntGet( TIMER );
00224 
00225   if ( flags & TIMER_IF_CC0 )
00226   {
00227     TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
00228     timeElapsed = true;
00229   }
00230 }
00231 
00232 static void DelayTicksPolled( uint16_t ticks )
00233 {
00234   uint16_t startTime;
00235   volatile uint16_t now;
00236 
00237   if ( ticks )
00238   {
00239     startTime = TIMER_CounterGet( TIMER );
00240     do
00241     {
00242       now = TIMER_CounterGet( TIMER );
00243     } while ( (uint16_t)( now - startTime ) < ticks );
00244   }
00245 }
00246 
00247 static void DelayTicksEM1( uint16_t ticks )
00248 {
00249   if ( ticks )
00250   {
00251     /* Arm TIMER compare interrupt */
00252 
00253     INT_Disable();
00254 
00255     /* The following lines costs 2.7us@48MHz and 7.5us@14MHz (measured with GG)*/
00256     TIMER_CompareSet( TIMER, 0,
00257                       TIMER_CounterGet( TIMER ) + EFM32_MAX( minTicks, ticks ) );
00258     TIMER_IntClear( TIMER, TIMER_IFC_CC0 );
00259     TIMER_IntEnable( TIMER, TIMER_IEN_CC0 );
00260 
00261     INT_Enable();
00262 
00263     while ( ! timeElapsed )
00264     {
00265       EMU_EnterEM1();
00266     }
00267     timeElapsed = false;
00268 
00269     TIMER_IntDisable( TIMER, TIMER_IEN_CC0 );
00270   }
00271 }
00272 
00275 /******** THE REST OF THE FILE IS DOCUMENTATION ONLY !**********************/
00315