00001
00017 #include "em_device.h"
00018 #include "em_cmu.h"
00019 #include "em_int.h"
00020 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00021 #include "em_rtcc.h"
00022 #else
00023 #include "em_rtc.h"
00024 #endif
00025
00026 #include "udelay.h"
00027
00028
00052
00053
00054 volatile unsigned long loops_per_jiffy = (1<<12);
00055
00056
00057
00058
00059 #define LPS_PREC 8
00060
00061 static void calibrate_delay(void);
00062 __STATIC_INLINE uint32_t clock(void);
00063 static void _delay( uint32_t delay);
00064
00067
00071 void UDELAY_Calibrate(void)
00072 {
00073 CMU_Select_TypeDef lfaClkSel;
00074 CMU_ClkDiv_TypeDef rtcClkDiv;
00075 bool rtcRestore = false;
00076 bool leClkTurnoff = false;
00077 bool rtcClkTurnoff = false;
00078 bool lfaClkSrcRestore = false;
00079 bool lfaClkTurnoff = false;
00080 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00081 RTCC_Init_TypeDef init = RTCC_INIT_DEFAULT;
00082 uint32_t rtcCtrl=0, rtcIen=0;
00083 #else
00084 RTC_Init_TypeDef init = RTC_INIT_DEFAULT;
00085 uint32_t rtcCtrl=0, rtcComp0=0, rtcComp1=0, rtcIen=0;
00086 #endif
00087
00088
00089 #if defined (_CMU_HFBUSCLKEN0_MASK)
00090 if ( !( CMU->HFBUSCLKEN0 & CMU_HFBUSCLKEN0_LE) )
00091 #else
00092 if ( !( CMU->HFCORECLKEN0 & CMU_HFCORECLKEN0_LE) )
00093 #endif
00094 {
00095 CMU_ClockEnable(cmuClock_CORELE, true);
00096 leClkTurnoff = true;
00097 }
00098
00099 #if defined (CMU_LFECLKEN0_RTCC)
00100 lfaClkSel = CMU_ClockSelectGet(cmuClock_LFE);
00101 #else
00102 lfaClkSel = CMU_ClockSelectGet(cmuClock_LFA);
00103 #endif
00104
00105 #if defined( UDELAY_LFXO )
00106 if ( !(CMU->STATUS & CMU_STATUS_LFXOENS) )
00107 {
00108 lfaClkTurnoff = true;
00109 CMU_OscillatorEnable(cmuOsc_LFXO, true, true);
00110 }
00111
00112 if ( lfaClkSel != cmuSelect_LFXO )
00113 {
00114 lfaClkSrcRestore = true;
00115 #if defined (CMU_LFECLKEN0_RTCC)
00116 CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_LFXO);
00117 #else
00118 CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFXO);
00119 #endif
00120 }
00121
00122 #else
00123 if ( lfaClkSel != cmuSelect_LFRCO )
00124 {
00125 lfaClkSrcRestore = true;
00126 }
00127 if ( !(CMU->STATUS & CMU_STATUS_LFRCOENS) )
00128 {
00129 lfaClkTurnoff = true;
00130 }
00131
00132 #if defined (CMU_LFECLKEN0_RTCC)
00133 CMU_ClockSelectSet(cmuClock_LFE, cmuSelect_LFRCO);
00134 #else
00135 CMU_ClockSelectSet(cmuClock_LFA, cmuSelect_LFRCO);
00136 #endif
00137 #endif
00138
00139
00140 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00141 rtcClkDiv = CMU_ClockDivGet(cmuClock_RTCC);
00142 CMU_ClockDivSet(cmuClock_RTCC, cmuClkDiv_256);
00143 if ( !(CMU->LFECLKEN0 & CMU_LFECLKEN0_RTCC) )
00144 {
00145
00146 CMU_ClockEnable(cmuClock_RTCC, true);
00147 rtcClkTurnoff = true;
00148 }
00149 #else
00150 rtcClkDiv = CMU_ClockDivGet(cmuClock_RTC);
00151 CMU_ClockDivSet(cmuClock_RTC, cmuClkDiv_256);
00152 if ( !(CMU->LFACLKEN0 & CMU_LFACLKEN0_RTC) )
00153 {
00154
00155 CMU_ClockEnable(cmuClock_RTC, true);
00156 rtcClkTurnoff = true;
00157 }
00158 #endif
00159
00160
00161 INT_Disable();
00162
00163 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00164 if ( RTCC->CTRL & RTCC_CTRL_ENABLE )
00165 {
00166
00167 rtcCtrl = RTCC->CTRL;
00168 #if 0
00169 rtcComp0 = RTCC->COMP0;
00170 rtcComp1 = RTCC->COMP1;
00171 #endif
00172 rtcIen = RTCC->IEN;
00173
00174 RTCC->CTRL = _RTCC_CTRL_RESETVALUE;
00175 RTCC->IEN = 0;
00176 RTCC->IFC = _RTCC_IEN_MASK;
00177
00178 NVIC_ClearPendingIRQ( RTCC_IRQn );
00179
00180 rtcRestore = true;
00181 }
00182 init.precntWrapOnCCV0 = false;
00183 init.cntWrapOnCCV1 = false;
00184
00185 RTCC_Init(&init);
00186
00187 #else
00188 if ( RTC->CTRL & RTC_CTRL_EN )
00189 {
00190
00191 rtcCtrl = RTC->CTRL;
00192 rtcComp0 = RTC->COMP0;
00193 rtcComp1 = RTC->COMP1;
00194 rtcIen = RTC->IEN;
00195
00196 RTC->CTRL = _RTC_CTRL_RESETVALUE;
00197 RTC->IEN = 0;
00198 RTC->IFC = _RTC_IEN_MASK;
00199
00200 NVIC_ClearPendingIRQ( RTC_IRQn );
00201
00202 rtcRestore = true;
00203 }
00204 init.comp0Top = false;
00205
00206 RTC_Init(&init);
00207
00208 #endif
00209
00210 calibrate_delay();
00211
00212 INT_Enable();
00213
00214
00215 if ( rtcRestore )
00216 {
00217 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00218 CMU_ClockDivSet(cmuClock_RTCC, rtcClkDiv);
00219 RTCC->CTRL = rtcCtrl;
00220 RTCC->IEN = rtcIen;
00221 #else
00222 CMU_ClockDivSet(cmuClock_RTC, rtcClkDiv);
00223 RTC_FreezeEnable(true);
00224 #if defined(_EFM32_GECKO_FAMILY)
00225 RTC_Sync(RTC_SYNCBUSY_COMP0 | RTC_SYNCBUSY_COMP1 | RTC_SYNCBUSY_CTRL);
00226 #endif
00227 RTC->COMP0 = rtcComp0;
00228 RTC->COMP1 = rtcComp1;
00229 RTC->CTRL = rtcCtrl;
00230 RTC->IEN = rtcIen;
00231 RTC_FreezeEnable(false);
00232 #endif
00233 }
00234 else
00235 {
00236 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00237 RTCC_Enable(false);
00238 #else
00239 RTC_Enable(false);
00240 #endif
00241 }
00242
00243 if ( rtcClkTurnoff )
00244 {
00245 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00246 CMU_ClockEnable(cmuClock_RTCC, false);
00247 #else
00248 CMU_ClockEnable(cmuClock_RTC, false);
00249 #endif
00250 }
00251
00252 if ( lfaClkSrcRestore )
00253 {
00254 #if defined (CMU_LFECLKEN0_RTCC)
00255 CMU_ClockSelectSet(cmuClock_LFE, lfaClkSel);
00256 #else
00257 CMU_ClockSelectSet(cmuClock_LFA, lfaClkSel);
00258 #endif
00259 }
00260
00261 if ( lfaClkTurnoff )
00262 {
00263 #if defined( UDELAY_LFXO )
00264 CMU_OscillatorEnable(cmuOsc_LFXO, false, false);
00265 #else
00266 CMU_OscillatorEnable(cmuOsc_LFRCO, false, false);
00267 #endif
00268 }
00269
00270 if ( leClkTurnoff )
00271 {
00272 CMU_ClockEnable(cmuClock_CORELE, false);
00273 }
00274 }
00275
00276 #if defined(__GNUC__)
00277
00288 void UDELAY_Delay( uint32_t usecs )
00289 {
00290 __ASM volatile (
00291 #if ( __CORTEX_M == 0x00 )
00292 " .syntax unified \n"
00293 " .arch armv6-m \n"
00294 #endif
00295 " cmp %0, #0 \n"
00296 " beq.n 2f \n"
00297 " subs %0, #1 \n"
00298 " movs r2, #0x88 \n"
00299 " lsls r2, r2, #8 \n"
00300 " adds r2, #0x00 \n"
00301 " muls %0, r2 \n"
00302 " \n"
00303 " ldr r2, [%1] \n"
00304 " movs r0, %0, lsr #11 \n"
00305 " movs r2, r2, lsr #11 \n"
00306 " \n"
00307 " muls r0, r2 \n"
00308 " movs r0, r0, lsr #6 \n"
00309 " \n"
00310 " beq.n 2f \n"
00311 " \n"
00312 "1: subs r0, #1 \n"
00313 " bhi 1b \n"
00314 #if ( __CORTEX_M == 0x00 )
00315 "2: \n"
00316 " .syntax divided \n" : : "r" (usecs), "r" (&loops_per_jiffy) : "r0", "r2", "cc" );
00317 #else
00318 "2: \n" : : "r" (usecs), "r" (&loops_per_jiffy) : "r0", "r2", "cc" );
00319 #endif
00320 }
00321 #endif
00322
00325 static void calibrate_delay(void)
00326 {
00327
00328 unsigned long loopbit;
00329 unsigned long ticks;
00330 int lps_precision = LPS_PREC;
00331
00332 loops_per_jiffy = (1<<12);
00333
00334 while (loops_per_jiffy <<= 1) {
00335
00336 ticks = clock();
00337 while (ticks == clock())
00338 ;
00339
00340 ticks = clock();
00341 _delay(loops_per_jiffy);
00342 ticks = clock() - ticks;
00343 if (ticks)
00344 break;
00345 }
00346
00347
00348
00349
00350 loops_per_jiffy >>= 1;
00351 loopbit = loops_per_jiffy;
00352 while ( lps_precision-- && (loopbit >>= 1) ) {
00353 loops_per_jiffy |= loopbit;
00354 ticks = clock();
00355 while (ticks == clock());
00356 ticks = clock();
00357 _delay(loops_per_jiffy);
00358 if (clock() != ticks)
00359 loops_per_jiffy &= ~loopbit;
00360 }
00361 }
00362
00363 __STATIC_INLINE uint32_t clock(void)
00364 {
00365 #if defined( RTCC_PRESENT ) && ( RTCC_COUNT == 1 )
00366 return RTCC_CounterGet();
00367 #else
00368 return RTC_CounterGet();
00369 #endif
00370 }
00371
00372 #if defined(__ICCARM__)
00373 static void _delay( uint32_t delay)
00374 {
00375 __ASM volatile (
00376 "_delay_1: \n"
00377 " subs r0, #1 \n"
00378 " bhi.n _delay_1 \n" );
00379 }
00380
00381 void UDELAY_Delay( uint32_t usecs )
00382 {
00383 __ASM volatile (
00384 " cmp %0, #0 \n"
00385 " beq.n udelay_2 \n"
00386 " subs %0, #1 \n"
00387 " movs r2, #0x88 \n"
00388 " lsls r2, r2, #8 \n"
00389 " adds r2, #0x00 \n"
00390 " muls %0, r2 \n"
00391 " \n"
00392 " ldr r2, [%1] \n"
00393 " movs r0, %0, lsr #11 \n"
00394 " movs r2, r2, lsr #11 \n"
00395 " \n"
00396 " muls r0, r2 \n"
00397 " movs r0, r0, lsr #6 \n"
00398 " \n"
00399 " beq.n udelay_2 \n"
00400 " \n"
00401 "udelay_1: \n"
00402 " subs r0, #1 \n"
00403 " bhi.n udelay_1 \n"
00404 "udelay_2: \n" : : "r" (usecs), "r" (&loops_per_jiffy) : "r0", "r2", "cc");
00405 }
00406 #endif
00407
00408 #if defined(__GNUC__)
00409 static void _delay( uint32_t delay )
00410 {
00411 __ASM volatile (
00412 #if ( __CORTEX_M == 0x00 )
00413 " .syntax unified \n"
00414 " .arch armv6-m \n"
00415 #endif
00416 "1: subs %0, #1 \n"
00417 #if ( __CORTEX_M == 0x00 )
00418 " bhi.n 1b \n"
00419 " .syntax divided \n" : : "r" (delay) );
00420 #else
00421 " bhi.n 1b \n" : : "r" (delay) );
00422 #endif
00423 }
00424 #endif
00425
00426 #if defined(__CC_ARM)
00427 static __ASM void _delay( uint32_t delay)
00428 {
00429 _delay_1
00430 subs r0, #1
00431 bhi _delay_1
00432 bx lr
00433 }
00434
00435 __ASM void UDELAY_Delay( uint32_t usecs __attribute__ ((unused)) )
00436 {
00437 IMPORT loops_per_jiffy
00438
00439 cmp r0, #0
00440 beq.n udelay_2
00441 subs r0, #1
00442 movs r2, #0x88
00443 lsls r2, r2, #8
00444 adds r2, #0x00
00445 muls r0, r2, r0
00446
00447 ldr r2, =loops_per_jiffy
00448 ldr r2, [r2]
00449 movs r0, r0, lsr #11
00450 movs r2, r2, lsr #11
00451
00452 muls r0, r2, r0
00453 movs r0, r0, lsr #6
00454 beq udelay_2
00455 udelay_1
00456 subs r0, #1
00457 bhi udelay_1
00458 udelay_2
00459 bx lr
00460 }
00461 #endif
00462