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