1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include <cpu/inc/cpuMath.h> 18 #include <plat/inc/gpio.h> 19 #include <plat/inc/usart.h> 20 #include <plat/inc/cmsis.h> 21 #include <plat/inc/pwr.h> 22 #include <plat/inc/rtc.h> 23 #include <plat/inc/plat.h> 24 #include <plat/inc/exti.h> 25 #include <plat/inc/syscfg.h> 26 #include <plat/inc/wdt.h> 27 #include <plat/inc/dma.h> 28 #include <stdbool.h> 29 #include <stdio.h> 30 #include <string.h> 31 #include <pthread.h> 32 #include <unistd.h> 33 #include <platform.h> 34 #include <seos.h> 35 #include <heap.h> 36 #include <timer.h> 37 #include <usart.h> 38 #include <gpio.h> 39 #include <mpu.h> 40 #include <cpu.h> 41 #include <hostIntf.h> 42 #include <atomic.h> 43 #include <hostIntf.h> 44 #include <nanohubPacket.h> 45 #include <sensType.h> 46 #include <variant/inc/variant.h> 47 48 49 struct StmDbg { 50 volatile uint32_t IDCODE; 51 volatile uint32_t CR; 52 volatile uint32_t APB1FZ; 53 volatile uint32_t APB2FZ; 54 }; 55 56 struct StmTim { 57 58 volatile uint16_t CR1; 59 uint8_t unused0[2]; 60 volatile uint16_t CR2; 61 uint8_t unused1[2]; 62 volatile uint16_t SMCR; 63 uint8_t unused2[2]; 64 volatile uint16_t DIER; 65 uint8_t unused3[2]; 66 volatile uint16_t SR; 67 uint8_t unused4[2]; 68 volatile uint16_t EGR; 69 uint8_t unused5[2]; 70 volatile uint16_t CCMR1; 71 uint8_t unused6[2]; 72 volatile uint16_t CCMR2; 73 uint8_t unused7[2]; 74 volatile uint16_t CCER; 75 uint8_t unused8[2]; 76 volatile uint32_t CNT; 77 volatile uint16_t PSC; 78 uint8_t unused9[2]; 79 volatile uint32_t ARR; 80 volatile uint16_t RCR; 81 uint8_t unused10[2]; 82 volatile uint32_t CCR1; 83 volatile uint32_t CCR2; 84 volatile uint32_t CCR3; 85 volatile uint32_t CCR4; 86 volatile uint16_t BDTR; 87 uint8_t unused11[2]; 88 volatile uint16_t DCR; 89 uint8_t unused12[2]; 90 volatile uint16_t DMAR; 91 uint8_t unused13[2]; 92 volatile uint16_t OR; 93 uint8_t unused14[2]; 94 }; 95 96 /* RTC bit defintions */ 97 #define TIM_EGR_UG 0x0001 98 99 100 #ifdef DEBUG_UART_UNITNO 101 static struct usart mDbgUart; 102 #endif 103 104 #ifdef DEBUG_LOG_EVT 105 #define EARLY_LOG_BUF_SIZE 1024 106 #define HOSTINTF_HEADER_SIZE 4 107 uint8_t *mEarlyLogBuffer; 108 uint16_t mEarlyLogBufferCnt; 109 uint16_t mEarlyLogBufferOffset; 110 bool mLateBoot; 111 #endif 112 113 static uint64_t mTimeAccumulated = 0; 114 static uint32_t mMaxJitterPpm = 0, mMaxDriftPpm = 0, mMaxErrTotalPpm = 0; 115 static uint32_t mSleepDevsToKeepAlive = 0; 116 static uint64_t mWakeupTime = 0; 117 static uint32_t mDevsMaxWakeTime[PLAT_MAX_SLEEP_DEVS] = {0,}; 118 static struct Gpio *mShWakeupGpio; 119 static struct ChainedIsr mShWakeupIsr; 120 121 122 void platUninitialize(void) 123 { 124 #ifdef DEBUG_UART_UNITNO 125 usartClose(&mDbgUart); 126 #endif 127 } 128 129 void *platLogAllocUserData() 130 { 131 #if defined(DEBUG_LOG_EVT) 132 struct HostIntfDataBuffer *userData = NULL; 133 134 if (mLateBoot) { 135 userData = heapAlloc(sizeof(struct HostIntfDataBuffer)); 136 } else if (mEarlyLogBufferOffset < EARLY_LOG_BUF_SIZE - HOSTINTF_HEADER_SIZE) { 137 userData = (struct HostIntfDataBuffer *)(mEarlyLogBuffer + mEarlyLogBufferOffset); 138 mEarlyLogBufferOffset += HOSTINTF_HEADER_SIZE; 139 } 140 if (userData) { 141 userData->sensType = SENS_TYPE_INVALID; 142 userData->length = 0; 143 userData->dataType = HOSTINTF_DATA_TYPE_LOG; 144 userData->interrupt = NANOHUB_INT_NONWAKEUP; 145 } 146 return userData; 147 #else 148 return NULL; 149 #endif 150 } 151 152 #if defined(DEBUG_LOG_EVT) 153 static void platEarlyLogFree(void *buf) 154 { 155 struct HostIntfDataBuffer *userData = (struct HostIntfDataBuffer *)buf; 156 mEarlyLogBufferCnt += userData->length + HOSTINTF_HEADER_SIZE; 157 if (mEarlyLogBufferCnt >= mEarlyLogBufferOffset) { 158 heapFree(mEarlyLogBuffer); 159 } 160 } 161 #endif 162 163 void platEarlyLogFlush(void) 164 { 165 #if defined(DEBUG_LOG_EVT) 166 uint16_t i = 0; 167 struct HostIntfDataBuffer *userData; 168 169 mLateBoot = true; 170 171 while (i < mEarlyLogBufferOffset) { 172 userData = (struct HostIntfDataBuffer *)(mEarlyLogBuffer + i); 173 osEnqueueEvt(EVENT_TYPE_BIT_DISCARDABLE | EVT_DEBUG_LOG, userData, platEarlyLogFree); 174 i += HOSTINTF_HEADER_SIZE + userData->length; 175 } 176 #endif 177 } 178 179 void platLogFlush(void *userData) 180 { 181 #if defined(DEBUG_LOG_EVT) 182 if (userData && mLateBoot) 183 osEnqueueEvtOrFree(EVENT_TYPE_BIT_DISCARDABLE | EVT_DEBUG_LOG, userData, heapFree); 184 #endif 185 } 186 187 bool platLogPutcharF(void *userData, char ch) 188 { 189 #if defined(DEBUG) && defined(DEBUG_UART_PIN) 190 if (ch == '\n') 191 gpioBitbangedUartOut('\r'); 192 gpioBitbangedUartOut(ch); 193 #endif 194 #if defined(DEBUG_UART_UNITNO) 195 usartPutchar(&mDbgUart, ch); 196 #endif 197 #if defined(DEBUG_LOG_EVT) 198 struct HostIntfDataBuffer *buffer; 199 200 if (userData) { 201 buffer = userData; 202 size_t maxSize = sizeof(buffer->buffer); 203 204 // if doing early logging, and early log buffer is full, ignore the rest of early output 205 if (!mLateBoot && mEarlyLogBufferOffset >= EARLY_LOG_BUF_SIZE && buffer->length < maxSize) 206 maxSize = buffer->length; 207 208 if (buffer->length < maxSize) { 209 buffer->buffer[buffer->length++] = ch; 210 if (!mLateBoot) 211 mEarlyLogBufferOffset++; 212 } else { 213 buffer->buffer[maxSize - 1] = '\n'; 214 return false; 215 } 216 } 217 #endif 218 return true; 219 } 220 221 static bool platWakeupIsr(struct ChainedIsr *isr) 222 { 223 if (!extiIsPendingGpio(mShWakeupGpio)) 224 return false; 225 226 extiClearPendingGpio(mShWakeupGpio); 227 228 hostIntfRxPacket(!gpioGet(mShWakeupGpio)); 229 230 return true; 231 } 232 233 void platInitialize(void) 234 { 235 const uint32_t debugStateInSleepMode = 0x00000007; /* debug in all modes */ 236 struct StmTim *tim = (struct StmTim*)TIM2_BASE; 237 struct StmDbg *dbg = (struct StmDbg*)DBG_BASE; 238 uint32_t i; 239 240 pwrSystemInit(); 241 242 //prepare for sleep mode(s) 243 SCB->SCR &=~ SCB_SCR_SLEEPONEXIT_Msk; 244 245 //set ints up for a sane state 246 //3 bits preemptPriority, 1 bit subPriority 247 NVIC_SetPriorityGrouping(4); 248 for (i = 0; i < NUM_INTERRUPTS; i++) { 249 NVIC_SetPriority(i, NVIC_EncodePriority(4, 2, 1)); 250 NVIC_DisableIRQ(i); 251 NVIC_ClearPendingIRQ(i); 252 } 253 254 /* disable pins */ 255 for (i = 0; i < 16; i++) { 256 #if defined(DEBUG) && defined(DEBUG_SWD) 257 /* pins PA13 and PA14 are used for SWD */ 258 if ((i != 13) && (i != 14)) 259 gpioConfigAnalog(gpioRequest(GPIO_PA(i))); 260 #else 261 gpioConfigAnalog(gpioRequest(GPIO_PA(i))); 262 #endif 263 gpioConfigAnalog(gpioRequest(GPIO_PB(i))); 264 gpioConfigAnalog(gpioRequest(GPIO_PC(i))); 265 gpioConfigAnalog(gpioRequest(GPIO_PD(i))); 266 gpioConfigAnalog(gpioRequest(GPIO_PE(i))); 267 gpioConfigAnalog(gpioRequest(GPIO_PH(i))); 268 } 269 270 #ifdef DEBUG_UART_UNITNO 271 /* Open mDbgUart on PA2 and PA3 */ 272 usartOpen(&mDbgUart, DEBUG_UART_UNITNO, DEBUG_UART_GPIO_TX, DEBUG_UART_GPIO_RX, 273 115200, USART_DATA_BITS_8, 274 USART_STOP_BITS_1_0, USART_PARITY_NONE, 275 USART_FLOW_CONTROL_NONE); 276 #endif 277 278 /* set up debugging */ 279 #if defined(DEBUG) && defined(DEBUG_SWD) 280 dbg->CR |= debugStateInSleepMode; 281 #else 282 dbg->CR &=~ debugStateInSleepMode; 283 #endif 284 285 /* enable MPU */ 286 mpuStart(); 287 288 /* set up timer used for alarms */ 289 pwrUnitClock(PERIPH_BUS_APB1, PERIPH_APB1_TIM2, true); 290 tim->CR1 = (tim->CR1 &~ 0x03E1) | 0x0010; //count down mode with no clock division, disabled 291 tim->PSC = 15; // prescale by 16, so that at 16MHz CPU clock, we get 1MHz timer 292 tim->DIER |= 1; // interrupt when updated (underflowed) 293 tim->ARR = 0xffffffff; 294 tim->EGR = TIM_EGR_UG; // force a reload of the prescaler 295 NVIC_EnableIRQ(TIM2_IRQn); 296 297 rtcInit(); 298 299 /* bring up systick */ 300 SysTick->CTRL = 0; 301 SysTick->LOAD = 0x00FFFFFF; 302 SysTick->VAL = 0; 303 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; 304 305 mShWakeupGpio = gpioRequest(SH_INT_WAKEUP); 306 gpioConfigInput(mShWakeupGpio, GPIO_SPEED_LOW, GPIO_PULL_NONE); 307 syscfgSetExtiPort(mShWakeupGpio); 308 extiEnableIntGpio(mShWakeupGpio, EXTI_TRIGGER_BOTH); 309 mShWakeupIsr.func = platWakeupIsr; 310 extiChainIsr(SH_EXTI_WAKEUP_IRQ, &mShWakeupIsr); 311 312 #ifdef DEBUG_LOG_EVT 313 /* allocate buffer for early boot log message*/ 314 mEarlyLogBuffer = heapAlloc(EARLY_LOG_BUF_SIZE); 315 #endif 316 317 } 318 319 static uint64_t platsystickTicksToNs(uint32_t systickTicks) 320 { 321 return (uint64_t)systickTicks * 125 / 2; 322 } 323 324 uint64_t platGetTicks(void) 325 { 326 uint64_t ret; 327 uint32_t val; 328 329 do { 330 mem_reorder_barrier(); //mTimeAccumulated may change since it was read in condition check 331 332 ret = mTimeAccumulated; 333 val = SysTick->VAL; 334 335 mem_reorder_barrier(); //mTimeAccumulated may change since it was read above 336 337 } while (mTimeAccumulated != ret || SysTick->VAL > val); 338 339 return platsystickTicksToNs(0x01000000 - val) + ret; 340 } 341 342 /* Timer interrupt handler */ 343 void TIM2_IRQHandler(void); 344 void TIM2_IRQHandler(void) 345 { 346 struct StmTim *tim = (struct StmTim*)TIM2_BASE; 347 348 /* int clear */ 349 tim->SR &=~ 1; 350 351 /* timer off */ 352 tim->CR1 &=~ 1; 353 354 /* call timer handler since it might need to reschedule an interrupt (eg: in case where initial delay was too far off & we were limited by timer length) */ 355 timIntHandler(); 356 } 357 358 /* SysTick interrupt handler */ 359 void SysTick_Handler(void); 360 void SysTick_Handler(void) 361 { 362 mTimeAccumulated += platsystickTicksToNs(SysTick->LOAD + 1); //todo - incremenet by actual elapsed nanoseconds and not just "1" 363 } 364 365 bool platRequestDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime) 366 { 367 if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum) 368 return false; 369 370 mDevsMaxWakeTime[sleepDevID] = maxWakeupTime; 371 while (!atomicCmpXchg32bits(&mSleepDevsToKeepAlive, mSleepDevsToKeepAlive, mSleepDevsToKeepAlive | (1UL << sleepDevID))); 372 373 return true; 374 } 375 376 bool platAdjustDevInSleepMode(uint32_t sleepDevID, uint32_t maxWakeupTime) 377 { 378 if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum) 379 return false; 380 381 mDevsMaxWakeTime[sleepDevID] = maxWakeupTime; 382 383 return true; 384 } 385 386 bool platReleaseDevInSleepMode(uint32_t sleepDevID) 387 { 388 if (sleepDevID >= PLAT_MAX_SLEEP_DEVS || sleepDevID >= Stm32sleepDevNum) 389 return false; 390 391 while (!atomicCmpXchg32bits(&mSleepDevsToKeepAlive, mSleepDevsToKeepAlive, mSleepDevsToKeepAlive &~ (1UL << sleepDevID))); 392 393 return true; 394 } 395 396 static uint64_t platSetTimerAlarm(uint64_t delay) //delay at most that many nsec 397 { 398 struct StmTim *tim = (struct StmTim*)TIM2_BASE; 399 uint32_t delayInUsecs; 400 401 //turn off timer to prevent interrupts now 402 tim->CR1 &=~ 1; 403 404 if (delay >= (1000ULL << 32)) //it is only a 32-bit counter - we cannot set delays bigger than that 405 delayInUsecs = 0xffffffff; 406 else 407 delayInUsecs = cpuMathUint44Div1000ToUint32(delay); 408 409 tim->CNT = delayInUsecs; 410 tim->SR &=~ 1; //clear int 411 tim->CR1 |= 1; 412 413 return delayInUsecs; 414 } 415 416 bool platSleepClockRequest(uint64_t wakeupTime, uint32_t maxJitterPpm, uint32_t maxDriftPpm, uint32_t maxErrTotalPpm) 417 { 418 uint64_t intState, curTime = timGetTime(); 419 420 if (wakeupTime && curTime >= wakeupTime) 421 return false; 422 423 intState = cpuIntsOff(); 424 425 mMaxJitterPpm = maxJitterPpm; 426 mMaxDriftPpm = maxDriftPpm; 427 mMaxErrTotalPpm = maxErrTotalPpm; 428 mWakeupTime = wakeupTime; 429 430 //TODO: set an actual alarm here so that if we keep running and do not sleep till this is due, we still fire an interrupt for it! 431 if (wakeupTime) 432 platSetTimerAlarm(wakeupTime - curTime); 433 434 cpuIntsRestore(intState); 435 436 return true; 437 } 438 439 static bool sleepClockRtcPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData) 440 { 441 pwrSetSleepType((uint32_t)userData); 442 *savedData = rtcGetTime(); 443 444 if (delay && rtcSetWakeupTimer(delay) < 0) 445 return false; 446 447 //sleep with systick off (for timing) and interrupts off (for power due to HWR errata) 448 SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); 449 return true; 450 } 451 452 static void sleepClockRtcWake(void *userData, uint64_t *savedData) 453 { 454 //re-enable Systic and its interrupt 455 SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; 456 457 mTimeAccumulated += rtcGetTime() - *savedData; 458 } 459 460 461 static bool sleepClockTmrPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData) 462 { 463 pwrSetSleepType(stm32f411SleepModeSleep); 464 platRequestDevInSleepMode(Stm32sleepDevTim2, 0); 465 466 *savedData = platSetTimerAlarm(delay ?: ~0ull); 467 468 //sleep with systick off (for timing) and interrupts off (for power due to HWR errata) 469 SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk); 470 return true; 471 } 472 473 static void sleepClockTmrWake(void *userData, uint64_t *savedData) 474 { 475 struct StmTim *tim = (struct StmTim*)TIM2_BASE; 476 uint32_t cnt; 477 uint16_t sr; 478 uint64_t leftTicks; 479 480 //re-enable Systic and its interrupt 481 SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; 482 483 //stop the timer counting; 484 tim->CR1 &=~ 1; 485 486 //If we are within one time tick of overflow, it is possible for SR to 487 //not indicate a pending overflow, but CNT contain 0xFFFFFFFF or vice versa, 488 //depending on the read order of SR and CNT 489 //read both values until they are stable 490 do { 491 sr = tim->SR; 492 cnt = tim->CNT; 493 } while (sr != tim->SR || cnt != tim->CNT); 494 495 leftTicks = cnt; //if we wake NOT from timer, only count the ticks that actually ticked as "time passed" 496 if (sr & 1) //if there was an overflow, account for it 497 leftTicks -= 0x100000000ull; 498 499 mTimeAccumulated += (*savedData - leftTicks) * 1000; //this clock runs at 1MHz 500 501 platReleaseDevInSleepMode(Stm32sleepDevTim2); 502 } 503 504 505 static bool sleepClockJustWfiPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData) 506 { 507 pwrSetSleepType(stm32f411SleepModeSleep); 508 509 return true; 510 } 511 512 struct PlatSleepAndClockInfo { 513 uint64_t resolution; 514 uint64_t resolutionReciprocal; // speed up runtime by using 48 more code bytes? yes please! 515 uint32_t maxCounter; 516 uint32_t jitterPpm; 517 uint32_t driftPpm; 518 uint32_t maxWakeupTime; 519 uint32_t devsAvail; //what is available in sleep mode? 520 bool (*prepare)(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData); 521 void (*wake)(void *userData, uint64_t *savedData); 522 void *userData; 523 } static const platSleepClocks[] = { 524 #ifndef STM32F4xx_DISABLE_LPLV_SLEEP 525 { /* RTC + LPLV STOP MODE */ 526 .resolution = 1000000000ull/32768, 527 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768), 528 .maxCounter = 0xffffffff, 529 .jitterPpm = 0, 530 .driftPpm = 50, 531 .maxWakeupTime = 407000ull, 532 .devsAvail = (1 << Stm32sleepDevExti), 533 .prepare = sleepClockRtcPrepare, 534 .wake = sleepClockRtcWake, 535 .userData = (void*)stm32f411SleepModeStopLPLV, 536 }, 537 #endif 538 #ifndef STM32F4xx_DISABLE_LPFD_SLEEP 539 { /* RTC + LPFD STOP MODE */ 540 .resolution = 1000000000ull/32768, 541 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768), 542 .maxCounter = 0xffffffff, 543 .jitterPpm = 0, 544 .driftPpm = 50, 545 .maxWakeupTime = 130000ull, 546 .devsAvail = (1 << Stm32sleepDevExti), 547 .prepare = sleepClockRtcPrepare, 548 .wake = sleepClockRtcWake, 549 .userData = (void*)stm32f411SleepModeStopLPFD, 550 }, 551 #endif 552 #ifndef STM32F4xx_DISABLE_MRFPD_SLEEP 553 { /* RTC + MRFPD STOP MODE */ 554 .resolution = 1000000000ull/32768, 555 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768), 556 .maxCounter = 0xffffffff, 557 .jitterPpm = 0, 558 .driftPpm = 50, 559 .maxWakeupTime = 111000ull, 560 .devsAvail = (1 << Stm32sleepDevExti), 561 .prepare = sleepClockRtcPrepare, 562 .wake = sleepClockRtcWake, 563 .userData = (void*)stm32f411SleepModeStopMRFPD, 564 }, 565 #endif 566 #ifndef STM32F4xx_DISABLE_MR_SLEEP 567 { /* RTC + MR STOP MODE */ 568 .resolution = 1000000000ull/32768, 569 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768), 570 .maxCounter = 0xffffffff, 571 .jitterPpm = 0, 572 .driftPpm = 50, 573 .maxWakeupTime = 14500ull, 574 .devsAvail = (1 << Stm32sleepDevExti), 575 .prepare = sleepClockRtcPrepare, 576 .wake = sleepClockRtcWake, 577 .userData = (void*)stm32f411SleepModeStopMR, 578 }, 579 #endif 580 #ifndef STM32F4xx_DISABLE_TIM2_SLEEP 581 { /* TIM2 + SLEEP MODE */ 582 .resolution = 1000000000ull/1000000, 583 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/1000000), 584 .maxCounter = 0xffffffff, 585 .jitterPpm = 0, 586 .driftPpm = 30, 587 .maxWakeupTime = 12ull, 588 .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevExti), 589 .prepare = sleepClockTmrPrepare, 590 .wake = sleepClockTmrWake, 591 }, 592 #endif 593 { /* just WFI */ 594 .resolution = 16000000000ull/1000000, 595 .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(16000000000ull/1000000), 596 .maxCounter = 0xffffffff, 597 .jitterPpm = 0, 598 .driftPpm = 0, 599 .maxWakeupTime = 0, 600 .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevExti), 601 .prepare = sleepClockJustWfiPrepare, 602 }, 603 604 /* terminator */ 605 {0}, 606 }; 607 608 void platSleep(void) 609 { 610 uint64_t predecrement = 0, curTime = timGetTime(), length = mWakeupTime - curTime, intState; 611 const struct PlatSleepAndClockInfo *sleepClock, *leastBadOption = NULL; 612 uint64_t savedData; 613 uint32_t i; 614 615 //shortcut the sleep if it is time to wake up already 616 if (mWakeupTime && mWakeupTime < curTime) 617 return; 618 619 for (sleepClock = platSleepClocks; sleepClock->maxCounter; sleepClock++) { 620 621 bool potentialLeastBadOption = false; 622 623 //if we have timers, consider them 624 if (mWakeupTime) { 625 626 //calculate how much we WOULD predecerement by 627 predecrement = sleepClock->resolution + sleepClock->maxWakeupTime; 628 629 //skip options with too much jitter (after accounting for error 630 if (sleepClock->jitterPpm > mMaxJitterPpm) 631 continue; 632 633 //skip options that will take too long to wake up to be of use 634 if (predecrement > length) 635 continue; 636 637 //skip options with too much drift 638 if (sleepClock->driftPpm > mMaxDriftPpm) 639 continue; 640 641 //skip options that do not let us sleep enough, but save them for later if we simply must pick something 642 if (cpuMathRecipAssistedUdiv64by64(length, sleepClock->resolution, sleepClock->resolutionReciprocal) > sleepClock->maxCounter && !leastBadOption) 643 potentialLeastBadOption = true; 644 } 645 646 //skip all options that do not keep enough deviceas awake 647 if ((sleepClock->devsAvail & mSleepDevsToKeepAlive) != mSleepDevsToKeepAlive) 648 continue; 649 650 //skip all options that wake up too slowly 651 for (i = 0; i < Stm32sleepDevNum; i++) { 652 if (!(mSleepDevsToKeepAlive & (1 << i))) 653 continue; 654 if (mDevsMaxWakeTime[i] < sleepClock->maxWakeupTime) 655 break; 656 } 657 if (i != Stm32sleepDevNum) 658 continue; 659 660 //if it will not let us sleep long enough save it as a possibility and go on 661 if (potentialLeastBadOption && !leastBadOption) 662 leastBadOption = sleepClock; 663 else //if it fits us perfectly, pick it 664 break; 665 } 666 if (!sleepClock->maxCounter) 667 sleepClock = leastBadOption; 668 669 if (!sleepClock) { 670 //should never happen - this will spin the CPU and be bad, but it WILL work in all cases 671 return; 672 } 673 674 //turn ints off in prep for sleep 675 wdtDisableClk(); 676 intState = cpuIntsOff(); 677 678 //options? config it 679 if (sleepClock->prepare && 680 sleepClock->prepare(mWakeupTime ? length - sleepClock->maxWakeupTime : 0, 681 mMaxJitterPpm, mMaxDriftPpm, mMaxErrTotalPpm, 682 sleepClock->userData, &savedData)) { 683 684 asm volatile ("wfi\n" 685 "nop" :::"memory"); 686 687 //wakeup 688 if (sleepClock->wake) 689 sleepClock->wake(sleepClock->userData, &savedData); 690 } 691 //re-enable interrupts and let the handlers run 692 cpuIntsRestore(intState); 693 wdtEnableClk(); 694 } 695 696 void* platGetPersistentRamStore(uint32_t *bytes) 697 { 698 *bytes = sizeof(uint32_t[RTC_NUM_BACKUP_REGS]); 699 return rtcGetBackupStorage(); 700 } 701 702 uint32_t platFreeResources(uint32_t tid) 703 { 704 uint32_t dmaCount = dmaStopAll(tid); 705 uint32_t irqCount = extiUnchainAll(tid); 706 707 return (dmaCount << 8) | irqCount; 708 } 709 710 void platPeriodic() 711 { 712 wdtPing(); 713 } 714