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
platAdjustDevInSleepMode(uint32_t sleepDevID,uint32_t maxWakeupTime)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
platReleaseDevInSleepMode(uint32_t sleepDevID)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
platSetTimerAlarm(uint64_t delay)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
platSleepClockRequest(uint64_t wakeupTime,uint32_t maxJitterPpm,uint32_t maxDriftPpm,uint32_t maxErrTotalPpm)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
sleepClockRtcPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
sleepClockRtcWake(void * userData,uint64_t * savedData)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
sleepClockTmrPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
sleepClockTmrWake(void * userData,uint64_t * savedData)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
sleepClockJustWfiPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
platSleep(void)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
platGetPersistentRamStore(uint32_t * bytes)696 void* platGetPersistentRamStore(uint32_t *bytes)
697 {
698 *bytes = sizeof(uint32_t[RTC_NUM_BACKUP_REGS]);
699 return rtcGetBackupStorage();
700 }
701
platFreeResources(uint32_t tid)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
platPeriodic()710 void platPeriodic()
711 {
712 wdtPing();
713 }
714