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 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 #if !(defined(STM32F4xx_DISABLE_LPLV_SLEEP) && defined(STM32F4xx_DISABLE_LPFD_SLEEP) \
    430     && defined(STM32F4xx_DISABLE_MRFPD_SLEEP) && defined(STM32F4xx_DISABLE_MR_SLEEP))
    431 static bool sleepClockRtcPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
    432 {
    433     pwrSetSleepType((uint32_t)userData);
    434     *savedData = rtcGetTime();
    435 
    436     if (delay && rtcSetWakeupTimer(delay) < 0)
    437         return false;
    438 
    439     //sleep with systick off (for timing) and interrupts off (for power due to HWR errata)
    440     SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
    441     return true;
    442 }
    443 
    444 static void sleepClockRtcWake(void *userData, uint64_t *savedData)
    445 {
    446     //re-enable Systic and its interrupt
    447     SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
    448 
    449     mTimeAccumulated += rtcGetTime() - *savedData;
    450 }
    451 #endif
    452 
    453 static bool sleepClockTmrPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
    454 {
    455     pwrSetSleepType(stm32f411SleepModeSleep);
    456     platRequestDevInSleepMode(Stm32sleepDevTim2, 0);
    457 
    458     *savedData = platSetTimerAlarm(delay ?: ~0ull);
    459 
    460     //sleep with systick off (for timing) and interrupts off (for power due to HWR errata)
    461     SysTick->CTRL &= ~(SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk);
    462     return true;
    463 }
    464 
    465 static void sleepClockTmrWake(void *userData, uint64_t *savedData)
    466 {
    467     struct StmTim *tim = (struct StmTim*)TIM2_BASE;
    468     uint32_t cnt;
    469     uint16_t sr;
    470     uint64_t leftTicks;
    471 
    472     //re-enable Systic and its interrupt
    473     SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk;
    474 
    475     //stop the timer counting;
    476     tim->CR1 &=~ 1;
    477 
    478     //If we are within one time tick of overflow, it is possible for SR to
    479     //not indicate a pending overflow, but CNT contain 0xFFFFFFFF or vice versa,
    480     //depending on the read order of SR and CNT
    481     //read both values until they are stable
    482     do {
    483         sr = tim->SR;
    484         cnt = tim->CNT;
    485     } while (sr != tim->SR || cnt != tim->CNT);
    486 
    487     leftTicks = cnt; //if we wake NOT from timer, only count the ticks that actually ticked as "time passed"
    488     if (sr & 1) //if there was an overflow, account for it
    489         leftTicks -= 0x100000000ull;
    490 
    491     mTimeAccumulated += (*savedData - leftTicks) * 1000; //this clock runs at 1MHz
    492 
    493     platReleaseDevInSleepMode(Stm32sleepDevTim2);
    494 }
    495 
    496 
    497 static bool sleepClockJustWfiPrepare(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData)
    498 {
    499     pwrSetSleepType(stm32f411SleepModeSleep);
    500 
    501     return true;
    502 }
    503 
    504 struct PlatSleepAndClockInfo {
    505     uint64_t resolution;
    506     uint64_t resolutionReciprocal; // speed up runtime by using 48 more code bytes? yes please!
    507     uint32_t maxCounter;
    508     uint32_t jitterPpm;
    509     uint32_t driftPpm;
    510     uint32_t maxWakeupTime;
    511     uint32_t devsAvail; //what is available in sleep mode?
    512     bool (*prepare)(uint64_t delay, uint32_t acceptableJitter, uint32_t acceptableDrift, uint32_t maxAcceptableError, void *userData, uint64_t *savedData);
    513     void (*wake)(void *userData, uint64_t *savedData);
    514     void *userData;
    515 } static const platSleepClocks[] = {
    516 #ifndef STM32F4xx_DISABLE_LPLV_SLEEP
    517     { /* RTC + LPLV STOP MODE */
    518         .resolution = 1000000000ull/32768,
    519         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
    520         .maxCounter = 0xffffffff,
    521         .jitterPpm = 0,
    522         .driftPpm = 50,
    523         .maxWakeupTime = 407000ull,
    524         .devsAvail = (1 << Stm32sleepDevExti),
    525         .prepare = sleepClockRtcPrepare,
    526         .wake = sleepClockRtcWake,
    527         .userData = (void*)stm32f411SleepModeStopLPLV,
    528     },
    529 #endif
    530 #ifndef STM32F4xx_DISABLE_LPFD_SLEEP
    531     { /* RTC + LPFD STOP MODE */
    532         .resolution = 1000000000ull/32768,
    533         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
    534         .maxCounter = 0xffffffff,
    535         .jitterPpm = 0,
    536         .driftPpm = 50,
    537         .maxWakeupTime = 130000ull,
    538         .devsAvail = (1 << Stm32sleepDevExti),
    539         .prepare = sleepClockRtcPrepare,
    540         .wake = sleepClockRtcWake,
    541         .userData = (void*)stm32f411SleepModeStopLPFD,
    542     },
    543 #endif
    544 #ifndef STM32F4xx_DISABLE_MRFPD_SLEEP
    545     { /* RTC + MRFPD STOP MODE */
    546         .resolution = 1000000000ull/32768,
    547         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
    548         .maxCounter = 0xffffffff,
    549         .jitterPpm = 0,
    550         .driftPpm = 50,
    551         .maxWakeupTime = 111000ull,
    552         .devsAvail = (1 << Stm32sleepDevExti),
    553         .prepare = sleepClockRtcPrepare,
    554         .wake = sleepClockRtcWake,
    555         .userData = (void*)stm32f411SleepModeStopMRFPD,
    556     },
    557 #endif
    558 #ifndef STM32F4xx_DISABLE_MR_SLEEP
    559     { /* RTC + MR STOP MODE */
    560         .resolution = 1000000000ull/32768,
    561         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/32768),
    562         .maxCounter = 0xffffffff,
    563         .jitterPpm = 0,
    564         .driftPpm = 50,
    565         .maxWakeupTime = 14500ull,
    566         .devsAvail = (1 << Stm32sleepDevExti),
    567         .prepare = sleepClockRtcPrepare,
    568         .wake = sleepClockRtcWake,
    569         .userData = (void*)stm32f411SleepModeStopMR,
    570     },
    571 #endif
    572 #ifndef STM32F4xx_DISABLE_TIM2_SLEEP
    573     { /* TIM2 + SLEEP MODE */
    574         .resolution = 1000000000ull/1000000,
    575         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(1000000000ull/1000000),
    576         .maxCounter = 0xffffffff,
    577         .jitterPpm = 0,
    578         .driftPpm = 30,
    579         .maxWakeupTime = 12ull,
    580         .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevI2c2) | (1 << Stm32sleepDevI2c3) | (1 << Stm32sleepDevExti),
    581         .prepare = sleepClockTmrPrepare,
    582         .wake = sleepClockTmrWake,
    583     },
    584 #endif
    585     { /* just WFI */
    586         .resolution = 16000000000ull/1000000,
    587         .resolutionReciprocal = U64_RECIPROCAL_CALCULATE(16000000000ull/1000000),
    588         .maxCounter = 0xffffffff,
    589         .jitterPpm = 0,
    590         .driftPpm = 0,
    591         .maxWakeupTime = 0,
    592         .devsAvail = (1 << Stm32sleepDevTim2) | (1 << Stm32sleepDevTim4) | (1 << Stm32sleepDevTim5) | (1 << Stm32sleepDevTim9) | (1 << Stm32sleepWakeup) | (1 << Stm32sleepDevSpi2) | (1 << Stm32sleepDevSpi3) | (1 << Stm32sleepDevI2c1) | (1 << Stm32sleepDevI2c2) | (1 << Stm32sleepDevI2c3) | (1 << Stm32sleepDevExti),
    593         .prepare = sleepClockJustWfiPrepare,
    594     },
    595 
    596     /* terminator */
    597     {0},
    598 };
    599 
    600 void platSleep(void)
    601 {
    602     uint64_t predecrement = 0, curTime = timGetTime(), length = mWakeupTime - curTime, intState;
    603     const struct PlatSleepAndClockInfo *sleepClock, *leastBadOption = NULL;
    604     uint64_t savedData;
    605     uint32_t i;
    606 
    607     //shortcut the sleep if it is time to wake up already
    608     if (mWakeupTime && mWakeupTime < curTime)
    609         return;
    610 
    611     for (sleepClock = platSleepClocks; sleepClock->maxCounter; sleepClock++) {
    612 
    613         bool potentialLeastBadOption = false;
    614 
    615         //if we have timers, consider them
    616         if (mWakeupTime) {
    617 
    618             //calculate how much we WOULD predecerement by
    619             predecrement = sleepClock->resolution + sleepClock->maxWakeupTime;
    620 
    621             //skip options with too much jitter (after accounting for error
    622             if (sleepClock->jitterPpm > mMaxJitterPpm)
    623                 continue;
    624 
    625             //skip options that will take too long to wake up to be of use
    626             if (predecrement > length)
    627                 continue;
    628 
    629             //skip options with too much drift
    630             if (sleepClock->driftPpm > mMaxDriftPpm)
    631                 continue;
    632 
    633             //skip options that do not let us sleep enough, but save them for later if we simply must pick something
    634             if (cpuMathRecipAssistedUdiv64by64(length, sleepClock->resolution, sleepClock->resolutionReciprocal) > sleepClock->maxCounter && !leastBadOption)
    635                 potentialLeastBadOption = true;
    636         }
    637 
    638         //skip all options that do not keep enough deviceas awake
    639         if ((sleepClock->devsAvail & mSleepDevsToKeepAlive) != mSleepDevsToKeepAlive)
    640             continue;
    641 
    642         //skip all options that wake up too slowly
    643         for (i = 0; i < Stm32sleepDevNum; i++) {
    644             if (!(mSleepDevsToKeepAlive & (1 << i)))
    645                 continue;
    646             if (mDevsMaxWakeTime[i] < sleepClock->maxWakeupTime)
    647                 break;
    648         }
    649         if (i != Stm32sleepDevNum)
    650             continue;
    651 
    652         //if it will not let us sleep long enough save it as a possibility and go on
    653         if (potentialLeastBadOption && !leastBadOption)
    654             leastBadOption = sleepClock;
    655         else //if it fits us perfectly, pick it
    656             break;
    657     }
    658     if (!sleepClock->maxCounter)
    659         sleepClock = leastBadOption;
    660 
    661     if (!sleepClock) {
    662         //should never happen - this will spin the CPU and be bad, but it WILL work in all cases
    663         return;
    664     }
    665 
    666     //turn ints off in prep for sleep
    667     wdtDisableClk();
    668     intState = cpuIntsOff();
    669 
    670     //options? config it
    671     if (sleepClock->prepare &&
    672         sleepClock->prepare(mWakeupTime ? length - sleepClock->maxWakeupTime : 0,
    673                             mMaxJitterPpm, mMaxDriftPpm, mMaxErrTotalPpm,
    674                             sleepClock->userData, &savedData)) {
    675 
    676         asm volatile ("wfi\n"
    677             "nop" :::"memory");
    678 
    679         //wakeup
    680         if (sleepClock->wake)
    681             sleepClock->wake(sleepClock->userData, &savedData);
    682     }
    683     //re-enable interrupts and let the handlers run
    684     cpuIntsRestore(intState);
    685     wdtEnableClk();
    686 }
    687 
    688 void* platGetPersistentRamStore(uint32_t *bytes)
    689 {
    690     *bytes = sizeof(uint32_t[RTC_NUM_BACKUP_REGS]);
    691     return rtcGetBackupStorage();
    692 }
    693 
    694 uint32_t platFreeResources(uint32_t tid)
    695 {
    696     uint32_t dmaCount = dmaStopAll(tid);
    697     uint32_t irqCount = extiUnchainAll(tid);
    698 
    699     return (dmaCount << 8) | irqCount;
    700 }
    701 
    702 void platPeriodic()
    703 {
    704     wdtPing();
    705 }
    706