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