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
platUninitialize(void)121 void platUninitialize(void)
122 {
123 #ifdef DEBUG_UART_UNITNO
124 usartClose(&mDbgUart);
125 #endif
126 }
127
platLogAllocUserData()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)
platEarlyLogFree(void * buf)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
platEarlyLogFlush(void)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
platLogFlush(void * userData)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
platLogPutcharF(void * userData,char ch)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
platWakeupIsr(struct ChainedIsr * isr)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
platInitialize(void)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
platsystickTicksToNs(uint32_t systickTicks)318 static uint64_t platsystickTicksToNs(uint32_t systickTicks)
319 {
320 return (uint64_t)systickTicks * 125 / 2;
321 }
322
platGetTicks(void)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);
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);
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
platRequestDevInSleepMode(uint32_t sleepDevID,uint32_t maxWakeupTime)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
platReleaseDevInSleepMode(uint32_t sleepDevID)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
platSetTimerAlarm(uint64_t delay)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
platSleepClockRequest(uint64_t wakeupTime,uint32_t maxJitterPpm,uint32_t maxDriftPpm,uint32_t maxErrTotalPpm)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
sleepClockRtcPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
sleepClockRtcWake(void * userData,uint64_t * savedData)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
sleepClockTmrPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
sleepClockTmrWake(void * userData,uint64_t * savedData)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
sleepClockJustWfiPrepare(uint64_t delay,uint32_t acceptableJitter,uint32_t acceptableDrift,uint32_t maxAcceptableError,void * userData,uint64_t * savedData)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
platSleep(void)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
platGetPersistentRamStore(uint32_t * bytes)677 void* platGetPersistentRamStore(uint32_t *bytes)
678 {
679 *bytes = sizeof(uint32_t[RTC_NUM_BACKUP_REGS]);
680 return rtcGetBackupStorage();
681 }
682
platFreeResources(uint32_t tid)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