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