@@ -84,31 +84,24 @@ static const RtcTicks EARLY_WAKEUP_TICKS = 2;
8484static const RtcTicks MIN_STOP_TICKS = 5 ;
8585#elif defined(MICRO_FAMILY_SF32LB52 )
8686//! Stop mode until this number of ticks before the next scheduled task
87- static const RtcTicks EARLY_WAKEUP_TICKS = 10 ; // relative large to avid tasks.c:1960 assert
87+ static const RtcTicks EARLY_WAKEUP_TICKS = 4 ;
8888//! Stop mode until this number of ticks before the next scheduled task
89- static const RtcTicks MIN_STOP_TICKS = 15 ;
89+ static const RtcTicks MIN_STOP_TICKS = 8 ;
9090#else
9191#error "Unknown micro family"
9292#endif
9393
9494// 1 second ticks so that we only wake up once every regular timer interval.
9595static const RtcTicks MAX_STOP_TICKS = RTC_TICKS_HZ ;
9696
97- extern void vPortSuppressTicksAndSleep ( TickType_t xExpectedIdleTime ) {
9897#if !defined(MICRO_FAMILY_SF32LB52 )
98+ extern void vPortSuppressTicksAndSleep ( TickType_t xExpectedIdleTime ) {
9999 if (!rtc_alarm_is_initialized () || !sleep_mode_is_allowed ()) {
100100 // the RTC is not yet initialized to the point where it can wake us from sleep or sleep/stop
101101 // is disabled. Just returning will cause a busy loop where the caller thought we slept for
102102 // 0 ticks and will reevaluate what to do next (probably just try again).
103103 return ;
104104 }
105- #else
106- if (!lptim_systick_is_initialized () || !sleep_mode_is_allowed () ||
107- !ipc_queue_check_idle ()) {
108- // To avoid LCPU enter incorrect state, make sure ipc queue is empty before enter stop mode.
109- return ;
110- }
111- #endif
112105
113106 // Note: all tasks are suspended at this point, but we can still be interrupted
114107 // so the critical section is necessary. taskENTER_CRITICAL() is not used here
@@ -155,8 +148,6 @@ extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
155148 // (and RTC0 is shut down), then we just end up measuring 0 here -- no
156149 // harm, no foul.
157150 uint32_t rtc_start = NRF_RTC0 -> COUNTER ;
158- #elif defined(MICRO_FAMILY_SF32LB52 )
159- uint32_t counter_start = LPTIM1 -> CNT ;
160151#else
161152 // We assume that a WFI to trigger sleep mode will not last longer than 1
162153 // SysTick. (The SysTick INT doesn't automatically get suppressed) Thus,
@@ -181,13 +172,6 @@ extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
181172 rtc_end += 0x1000000 ;
182173 uint32_t rtc_elapsed = rtc_end - rtc_start ;
183174 uint32_t cycles_elapsed = rtc_elapsed * SystemCoreClock / 32768 ;
184- #elif defined(MICRO_FAMILY_SF32LB52 )
185- uint32_t counter_stop = LPTIM1 -> CNT ;
186- if (counter_stop < counter_start ) {
187- counter_stop += 0x10000 ;
188- }
189- uint32_t counter_elapsed = counter_stop - counter_start ;
190- uint32_t cycles_elapsed = (counter_elapsed * RTC_TICKS_HZ ) / 8000 ;
191175#else
192176 uint32_t systick_stop = SysTick -> VAL ;
193177 uint32_t cycles_elapsed ;
@@ -205,17 +189,12 @@ extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
205189
206190 // Go into stop mode until the wakeup_tick.
207191 s_last_ticks_commanded_in_stop = stop_duration ;
208- #if !defined( MICRO_FAMILY_SF32LB52 )
192+
209193 rtc_alarm_set (stop_duration );
210194 enter_stop_mode ();
211195
212196 RtcTicks ticks_elapsed = rtc_alarm_get_elapsed_ticks ();
213- #else
214- lptim_systick_tickless_idle ((uint32_t )stop_duration );
215- enter_stop_mode ();
216197
217- uint32_t ticks_elapsed = lptim_systick_get_elapsed_ticks ();
218- #endif
219198 s_last_ticks_elapsed_in_stop = ticks_elapsed ;
220199 vTaskStepTick (ticks_elapsed );
221200
@@ -238,6 +217,94 @@ extern void vPortSuppressTicksAndSleep( TickType_t xExpectedIdleTime ) {
238217 __enable_irq ();
239218}
240219
220+ #else
221+ extern void vPortSuppressTicksAndSleep ( TickType_t xExpectedIdleTime ) {
222+ if (!lptim_systick_is_initialized () || !sleep_mode_is_allowed () ||
223+ !ipc_queue_check_idle ()) {
224+ // To avoid LCPU enter incorrect state, make sure ipc queue is empty before enter stop mode.
225+ return ;
226+ }
227+
228+ // Note: all tasks are suspended at this point, but we can still be interrupted
229+ // so the critical section is necessary. taskENTER_CRITICAL() is not used here
230+ // as that method would mask interrupts that should exit the low-power mode.
231+ // The __disable_irq() function sets the PRIMASK bit which globally prevents
232+ // interrupt execution while still allowing interrupts to wake the processor
233+ // from WFI.
234+ // Conversely, taskEnter_CRITICAL() sets the BASEPRI register, which masks
235+ // interrupts with priorities lower than configMAX_SYSCALL_INTERRUPT_PRIORITY
236+ // from executing and from waking the processor.
237+ // See: http://infocenter.arm.com/help/topic/com.arm.doc.dui0552a/BABGGICD.html#BGBHDHAI
238+ __disable_irq ();
239+
240+ power_tracking_stop (PowerSystemMcuCoreRun );
241+
242+ if (eTaskConfirmSleepModeStatus () != eAbortSleep ) {
243+ if (xExpectedIdleTime < MIN_STOP_TICKS || !stop_mode_is_allowed ()) {
244+ uint32_t counter_start = LPTIM1 -> CNT ;
245+
246+ power_tracking_start (PowerSystemMcuCoreSleep );
247+ // HAL_GPIO_WritePin(DEBUG_PIN_CONFIG.gpio, DEBUG_PIN_CONFIG.gpio_pin, false);
248+
249+ __DSB (); // Drain any pending memory writes before entering sleep.
250+
251+ __WFI ();
252+ __NOP ();
253+ __NOP ();
254+ __NOP ();
255+ __NOP ();
256+ __NOP ();
257+ __NOP ();
258+ __NOP ();
259+ __NOP ();
260+ __NOP ();
261+ __NOP ();
262+
263+ __ISB (); // Let the pipeline catch up (force the WFI to activate before moving on).
264+
265+ // HAL_GPIO_WritePin(DEBUG_PIN_CONFIG.gpio, DEBUG_PIN_CONFIG.gpio_pin, true);
266+ power_tracking_stop (PowerSystemMcuCoreSleep );
267+
268+ uint32_t counter_stop = LPTIM1 -> CNT ;
269+ if (counter_stop < counter_start ) {
270+ counter_stop += 0x10000 ;
271+ }
272+ uint32_t counter_elapsed = counter_stop - counter_start ;
273+ uint32_t cycles_elapsed = (counter_elapsed * RTC_TICKS_HZ ) / 9000 ;
274+
275+ s_analytics_device_sleep_cpu_cycles += cycles_elapsed ;
276+ s_analytics_app_sleep_cpu_cycles += cycles_elapsed ;
277+ } else {
278+ const RtcTicks stop_duration = MIN (xExpectedIdleTime - EARLY_WAKEUP_TICKS , MAX_STOP_TICKS );
279+
280+ // Go into stop mode until the wakeup_tick.
281+ s_last_ticks_commanded_in_stop = stop_duration ;
282+
283+ lptim_systick_tickless_idle ((uint32_t )stop_duration );
284+
285+ enter_stop_mode ();
286+
287+ uint32_t ticks_elapsed = lptim_systick_get_elapsed_ticks ();
288+
289+ s_last_ticks_elapsed_in_stop = ticks_elapsed ;
290+ vTaskStepTick (ticks_elapsed );
291+
292+ // Update the task watchdog every time we come out of STOP mode (which is
293+ // at least once/second) since the timer peripheral will not have been
294+ // incremented
295+ task_watchdog_step_elapsed_time_ms ((ticks_elapsed * 1000 ) / RTC_TICKS_HZ );
296+
297+ s_analytics_device_stop_ticks += ticks_elapsed ;
298+ s_analytics_app_stop_ticks += ticks_elapsed ;
299+ }
300+ }
301+
302+ power_tracking_start (PowerSystemMcuCoreRun );
303+
304+ __enable_irq ();
305+ }
306+ #endif
307+
241308void vApplicationStackOverflowHook (TaskHandle_t task_handle , signed char * name ) {
242309 PebbleTask task = pebble_task_get_task_for_handle (task_handle );
243310
0 commit comments