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