Home | History | Annotate | Download | only in stm32f4xx
      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