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