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