00001
00017 #include "em_device.h"
00018 #include "em_cmu.h"
00019 #include "em_int.h"
00020 #include "em_rtc.h"
00021
00022 #include "udelay.h"
00023
00024
00046
00047
00048 volatile unsigned long loops_per_jiffy = (1<<12);
00049
00050
00051
00052
00053 #define LPS_PREC 8
00054
00055 static void calibrate_delay(void);
00056 __STATIC_INLINE uint32_t clock(void);
00057 static void _delay( uint32_t delay);
00058
00061
00065 void UDELAY_Calibrate(void)
00066 {
00067 CMU_Select_TypeDef lfaClkSel;
00068 CMU_ClkDiv_TypeDef rtcClkDiv;
00069 bool rtcRestore = false;
00070 bool leClkTurnoff = false;
00071 bool rtcClkTurnoff = false;
00072 bool lfaClkSrcRestore = false;
00073 bool lfaClkTurnoff = false;
00074 RTC_Init_TypeDef init = RTC_INIT_DEFAULT;
00075 uint32_t rtcCtrl=0, rtcComp0=0, rtcComp1=0, rtcIen=0;
00076
00077
00078 if ( !( CMU->HFCORECLKEN0 & CMU_HFCORECLKEN0_LE) )
00079 {
00080 CMU_ClockEnable(cmuClock_CORELE, true);
00081 leClkTurnoff = true;
00082 }
00083
00084 lfaClkSel = CMU_ClockSelectGet(cmuClock_LFA);
00085
00086 #if defined( UDELAY_LFXO )
00087 if ( !(CMU->STATUS & CMU_STATUS_LFXOENS) )
00088 {
00089 lfaClkTurnoff = true;
00090 CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
00091 }
00092
00093 if ( lfaClkSel != cmuSelect_LFXO )
00094 {
00095 lfaClkSrcRestore = true;
00096 CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
00097 }
00098
00099 #else
00100 if ( lfaClkSel != cmuSelect_LFRCO )
00101 {
00102 lfaClkSrcRestore = true;
00103 }
00104 if ( !(CMU->STATUS & CMU_STATUS_LFRCOENS) )
00105 {
00106 lfaClkTurnoff = true;
00107 }
00108
00109 CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
00110 #endif
00111
00112
00113 rtcClkDiv = CMU_ClockDivGet(cmuClock_RTC);
00114 CMU_ClockDivSet(cmuClock_RTC, cmuClkDiv_256);
00115
00116 if ( !(CMU->LFACLKEN0 & CMU_LFACLKEN0_RTC) )
00117 {
00118
00119 CMU_ClockEnable(cmuClock_RTC, true);
00120 rtcClkTurnoff = true;
00121 }
00122
00123 INT_Disable();
00124
00125 if ( RTC->CTRL & RTC_CTRL_EN )
00126 {
00127
00128 rtcCtrl = RTC->CTRL;
00129 rtcComp0 = RTC->COMP0;
00130 rtcComp1 = RTC->COMP1;
00131 rtcIen = RTC->IEN;
00132
00133 RTC->CTRL = _RTC_CTRL_RESETVALUE;
00134 RTC->IEN = 0;
00135 RTC->IFC = _RTC_IEN_MASK;
00136
00137 NVIC_ClearPendingIRQ( RTC_IRQn );
00138
00139 rtcRestore = true;
00140 }
00141
00142 init.comp0Top = false;
00143 RTC_Init(&init);
00144
00145 calibrate_delay();
00146
00147 INT_Enable();
00148
00149
00150 if ( rtcRestore )
00151 {
00152 CMU_ClockDivSet(cmuClock_RTC, rtcClkDiv);
00153
00154 RTC_FreezeEnable(true);
00155 #if defined(_EFM32_GECKO_FAMILY)
00156 RTC_Sync(RTC_SYNCBUSY_COMP0 | RTC_SYNCBUSY_COMP1 | RTC_SYNCBUSY_CTRL);
00157 #endif
00158 RTC->COMP0 = rtcComp0;
00159 RTC->COMP1 = rtcComp1;
00160 RTC->CTRL = rtcCtrl;
00161 RTC->IEN = rtcIen;
00162 RTC_FreezeEnable(false);
00163 }
00164 else
00165 {
00166 RTC_Enable(false);
00167 }
00168
00169 if ( rtcClkTurnoff )
00170 {
00171 CMU_ClockEnable(cmuClock_RTC, false);
00172 }
00173
00174 if ( lfaClkSrcRestore )
00175 {
00176 CMU_ClockSelectSet(cmuClock_LFA, lfaClkSel);
00177 }
00178
00179 if ( lfaClkTurnoff )
00180 {
00181 #if defined( UDELAY_LFXO )
00182 CMU_OscillatorEnable(cmuOsc_LFXO, false, false);
00183 #else
00184 CMU_OscillatorEnable(cmuOsc_LFRCO, false, false);
00185 #endif
00186 }
00187
00188 if ( leClkTurnoff )
00189 {
00190 CMU_ClockEnable(cmuClock_CORELE, false);
00191 }
00192 }
00193
00194 #if defined(__GNUC__)
00195
00202 void UDELAY_Delay( uint32_t usecs )
00203 {
00204 __ASM volatile (
00205 #if defined(_EFM32_ZERO_FAMILY)
00206 " .syntax unified \n"
00207 " .arch armv6-m \n"
00208 #endif
00209 " movs r2, #0x88 \n"
00210 " lsls r2, r2, #8 \n"
00211 " adds r2, #0x00 \n"
00212 " muls %0, r2 \n"
00213 " \n"
00214 " ldr r2, [%1] \n"
00215 " movs r0, %0, lsr #11 \n"
00216 " movs r2, r2, lsr #11 \n"
00217 " \n"
00218 " muls r0, r2 \n"
00219 " movs r0, r0, lsr #6 \n"
00220 " \n"
00221 " beq.n 2f \n"
00222 " \n"
00223 "1: subs r0, #1 \n"
00224 " bhi 1b \n"
00225 #if defined(_EFM32_ZERO_FAMILY)
00226 "2: \n"
00227 " .syntax divided \n" : : "r" (usecs), "r" (&loops_per_jiffy) );
00228 #else
00229 "2: \n" : : "r" (usecs), "r" (&loops_per_jiffy) );
00230 #endif
00231 }
00232 #endif
00233
00236 static void calibrate_delay(void)
00237 {
00238
00239 unsigned long loopbit;
00240 unsigned long ticks;
00241 int lps_precision = LPS_PREC;
00242
00243 loops_per_jiffy = (1<<12);
00244
00245 while (loops_per_jiffy <<= 1) {
00246
00247 ticks = clock();
00248 while (ticks == clock())
00249 ;
00250
00251 ticks = clock();
00252 _delay(loops_per_jiffy);
00253 ticks = clock() - ticks;
00254 if (ticks)
00255 break;
00256 }
00257
00258
00259
00260
00261 loops_per_jiffy >>= 1;
00262 loopbit = loops_per_jiffy;
00263 while ( lps_precision-- && (loopbit >>= 1) ) {
00264 loops_per_jiffy |= loopbit;
00265 ticks = clock();
00266 while (ticks == clock());
00267 ticks = clock();
00268 _delay(loops_per_jiffy);
00269 if (clock() != ticks)
00270 loops_per_jiffy &= ~loopbit;
00271 }
00272 }
00273
00274 __STATIC_INLINE uint32_t clock(void)
00275 {
00276 return RTC_CounterGet();
00277 }
00278
00279 #if defined(__ICCARM__)
00280 static void _delay( uint32_t delay)
00281 {
00282 __ASM volatile (
00283 "_delay_1: \n"
00284 " subs r0, #1 \n"
00285 " bhi.n _delay_1 \n" );
00286 }
00287
00288 void UDELAY_Delay( uint32_t usecs )
00289 {
00290 __ASM volatile (
00291 " movs r2, #0x88 \n"
00292 " lsls r2, r2, #8 \n"
00293 " adds r2, #0x00 \n"
00294 " muls r0, r2 \n"
00295 " \n"
00296 " ldr r2, [%0] \n"
00297 " movs r0, r0, lsr #11 \n"
00298 " movs r2, r2, lsr #11 \n"
00299 " \n"
00300 " muls r0, r2 \n"
00301 " movs r0, r0, lsr #6 \n"
00302 " \n"
00303 " bne.n udelay_1 \n"
00304 " bx lr \n"
00305 " \n"
00306 "udelay_1: \n"
00307 " subs r0, #1 \n"
00308 " bhi.n udelay_1 \n" : : "r" (&loops_per_jiffy) );
00309 }
00310 #endif
00311
00312 #if defined(__GNUC__)
00313 static void _delay( uint32_t delay )
00314 {
00315 __ASM volatile (
00316 #if defined(_EFM32_ZERO_FAMILY)
00317 " .syntax unified \n"
00318 " .arch armv6-m \n"
00319 #endif
00320 "1: subs %0, #1 \n"
00321 #if defined(_EFM32_ZERO_FAMILY)
00322 " bhi.n 1b \n"
00323 " .syntax divided \n" : : "r" (delay) );
00324 #else
00325 " bhi.n 1b \n" : : "r" (delay) );
00326 #endif
00327 }
00328 #endif
00329
00330 #if defined(__CC_ARM)
00331 static __ASM void _delay( uint32_t delay)
00332 {
00333 _delay_1
00334 subs r0, #1
00335 bhi _delay_1
00336 bx lr
00337 }
00338
00339 __ASM void UDELAY_Delay( uint32_t usecs __attribute__ ((unused)) )
00340 {
00341 IMPORT loops_per_jiffy
00342
00343 movs r2, #0x88
00344 lsls r2, r2, #8
00345 adds r2, #0x00
00346 muls r0, r2, r0
00347
00348 ldr r2, =loops_per_jiffy
00349 ldr r2, [r2]
00350 movs r0, r0, lsr #11
00351 movs r2, r2, lsr #11
00352
00353 muls r0, r2, r0
00354 movs r0, r0, lsr #6
00355
00356 bne udelay_1
00357 bx lr
00358
00359 udelay_1
00360 subs r0, #1
00361 bhi udelay_1
00362 bx lr
00363 }
00364 #endif
00365