Skip to content

Commit 985ab14

Browse files
cameledgmarull
authored andcommitted
fw/driver/lptim_systick: improve stop mode stability
Set RC32K as LP clock, which will reduce the deepsleep wakeup time. Signed-off-by: HaiLong Yang <cameled@outlook.com>
1 parent 17f89bb commit 985ab14

4 files changed

Lines changed: 111 additions & 46 deletions

File tree

src/fw/board/boards/board_obelix.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -647,13 +647,11 @@ void board_early_init(void) {
647647
BSP_System_Config();
648648

649649
HAL_HPAON_StartGTimer();
650-
#ifdef SF32LB52_USE_LXT
650+
651651
HAL_PMU_EnableRC32K(1);
652652

653653
HAL_PMU_LpCLockSelect(PMU_LPCLK_RC32);
654-
#else
655-
HAL_PMU_LpCLockSelect(PMU_LPCLK_RC10);
656-
#endif
654+
657655
HAL_PMU_EnableDLL(1);
658656
#ifdef SF32LB52_USE_LXT
659657
HAL_PMU_EnableXTAL32();
@@ -693,4 +691,10 @@ void board_init(void) {
693691
i2c_init(I2C3_BUS);
694692

695693
mic_init(MIC);
694+
695+
/* Enable user buttons as AON wakeup source */
696+
HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_PIN10, AON_PIN_MODE_HIGH);
697+
HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_PIN11, AON_PIN_MODE_LOW);
698+
HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_PIN12, AON_PIN_MODE_LOW);
699+
HAL_HPAON_EnableWakeupSrc(HPAON_WAKEUP_SRC_PIN13, AON_PIN_MODE_LOW);
696700
}

src/fw/drivers/sf32lb52/lptim_systick.c

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525
#include "bf0_hal_lptim.h"
2626
#include "bf0_hal_aon.h"
2727

28-
/* LPRC10K frequency nearly 8~9 KHz, fixed to 8KHz for systick */
29-
#define SYSTICK_CLOCK_HZ 8000
28+
/* LPRC10K frequency nearly 9 KHz, fixed to 9KHz for systick */
29+
#define SYSTICK_CLOCK_HZ 9000
3030
#define SYSTICK_ONE_TICK_HZ (SYSTICK_CLOCK_HZ / RTC_TICKS_HZ)
3131

3232
#if !defined(configUSE_TICKLESS_IDLE) || (configUSE_TICKLESS_IDLE != 2)
@@ -79,16 +79,6 @@ void lptim_systick_enable(void)
7979
NVIC_EnableIRQ(LPTIM1_IRQn);
8080
}
8181

82-
void lptim_systick_pause(void)
83-
{
84-
/* NOP */
85-
}
86-
87-
void lptim_systick_resume(void)
88-
{
89-
/* NOP */
90-
}
91-
9282
void lptim_systick_tickless_idle(uint32_t ticks_from_now)
9383
{
9484
// In tickless idle mode, use OCWE instead.
@@ -159,5 +149,7 @@ void AON_IRQHandler(void)
159149
NVIC_DisableIRQ(AON_IRQn);
160150
HAL_HPAON_CLEAR_POWER_MODE();
161151

162-
HAL_HPAON_CLEAR_WSR(0);
152+
uint32_t status = HAL_HPAON_GET_WSR();
153+
status &= ~HPSYS_AON_WSR_PIN_ALL;
154+
HAL_HPAON_CLEAR_WSR(status);
163155
}

src/fw/freertos_application.c

Lines changed: 92 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -84,31 +84,24 @@ static const RtcTicks EARLY_WAKEUP_TICKS = 2;
8484
static 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.
9595
static 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+
241308
void vApplicationStackOverflowHook(TaskHandle_t task_handle, signed char *name) {
242309
PebbleTask task = pebble_task_get_task_for_handle(task_handle);
243310

src/fw/kernel/util/stop.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,8 +107,6 @@ void enter_stop_mode(void) {
107107
uint32_t dll2_freq;
108108
int clk_src;
109109

110-
lptim_systick_pause();
111-
112110
clear_interrupt_setting();
113111

114112
/* Wait flash cache idle */
@@ -125,6 +123,9 @@ void enter_stop_mode(void) {
125123
HAL_RCC_HCPU_DisableDLL1();
126124
HAL_RCC_HCPU_DisableDLL2();
127125

126+
HAL_HPAON_DISABLE_PAD();
127+
HAL_HPAON_DISABLE_VHP();
128+
128129
HAL_HPAON_CLEAR_HP_ACTIVE();
129130
HAL_HPAON_SET_POWER_MODE(AON_PMR_DEEP_SLEEP);
130131

@@ -139,6 +140,9 @@ void enter_stop_mode(void) {
139140
__NOP();
140141
__NOP();
141142
__NOP();
143+
144+
HAL_HPAON_ENABLE_PAD();
145+
HAL_HPAON_ENABLE_VHP();
142146

143147
HAL_HPAON_SET_HP_ACTIVE();
144148
HAL_HPAON_CLEAR_POWER_MODE();
@@ -157,8 +161,6 @@ void enter_stop_mode(void) {
157161
HAL_Delay_us(0);
158162

159163
restore_interrupt_setting();
160-
161-
lptim_systick_resume();
162164
}
163165
#else /* STM32 */
164166
void enter_stop_mode(void) {

0 commit comments

Comments
 (0)