Skip to content

Commit

Permalink
STM32: Ensure we kick the WDT if auto kicking is enabled and in deep …
Browse files Browse the repository at this point in the history
…sleep (avoids having to do it manually and wait 30ms for USB to wake up/shut down)
  • Loading branch information
gfwilliams committed Nov 27, 2024
1 parent ffd7270 commit 529b396
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 75 deletions.
1 change: 1 addition & 0 deletions ChangeLog
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
Pixl.js: Remove Wiznet W5100 support from default build (there's now a espruino_#v##_pixljs_wiznet.zip without JIT enabled) to ensure we have enough flash to continue builds
Enable nostartfiles optimisation for Pixl,MDBT42 and nRF52DK
STM32F4: Add SDIO support
STM32: Ensure we kick the WDT if auto kicking is enabled and in deep sleep (avoids having to to it manually and wait 30ms for USB to wake up/shut down)

2v24 : Bangle.js2: Add 'Bangle.touchRd()', 'Bangle.touchWr()'
Bangle.js2: After Bangle.showTestScreen, put Bangle.js into a hard off state (not soft off)
Expand Down
7 changes: 4 additions & 3 deletions src/jshardware.h
Original file line number Diff line number Diff line change
Expand Up @@ -371,13 +371,14 @@ void jshResetRTCTimer();
void jshClearUSBIdleTimeout();
#endif

#if defined(NRF51_SERIES) || defined(NRF52_SERIES)
/// Called when we have had an event that means we should execute JS
extern void jshHadEvent();
/// set if we've had an event we need to deal with
extern volatile bool jshHadEventDuringSleep;

#if defined(NRF51_SERIES) || defined(NRF52_SERIES)
/// Enable/disable(if level==NAN) the LPCOMP comparator
bool jshSetComparator(Pin pin, JsVarFloat level);
#else
#define jshHadEvent() /* We should ensure we exit idle mode */
#endif

/// the temperature from the internal temperature sensor, in degrees C
Expand Down
8 changes: 8 additions & 0 deletions src/jshardware_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
#include "jsinteractive.h"
#include "platform_config.h"

/// set if we've had an event we need to deal with
volatile bool jshHadEventDuringSleep = false;

void jshUSARTInitInfo(JshUSARTInfo *inf) {
inf->baudRate = DEFAULT_BAUD_RATE;
inf->pinRX = PIN_UNDEFINED;
Expand Down Expand Up @@ -166,6 +169,11 @@ void jshKickSoftWatchDog() {
}
}

/// Called when we have had an event that means we should execute JS
void jshHadEvent() {
jshHadEventDuringSleep = true;
}

/* Returns the estimated power usage of the microcontroller */
__attribute__((weak)) void jsvGetProcessorPowerUsage(JsVar *devices) {
// not implemented by default
Expand Down
11 changes: 2 additions & 9 deletions targets/nrf5x/jshardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,6 @@ static uint8_t pwmClocks[PWM_COUNTERS];

/// For flash - whether it is busy or not...
volatile bool flashIsBusy = false;
volatile bool hadEvent = false; // set if we've had an event we need to deal with
unsigned int ticksSinceStart = 0;

#if GPIO_COUNT>1
Expand Down Expand Up @@ -626,12 +625,6 @@ const nrf_drv_twis_t *jshGetTWIS(IOEventFlags device) {
}
#endif


/// Called when we have had an event that means we should execute JS
void jshHadEvent() {
hadEvent = true;
}

void TIMER1_IRQHandler(void) {
nrf_timer_task_trigger(NRF_TIMER1, NRF_TIMER_TASK_CLEAR);
nrf_timer_event_clear(NRF_TIMER1, NRF_TIMER_EVENT_COMPARE0);
Expand Down Expand Up @@ -2746,7 +2739,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
#endif
}
jsiSetSleep(JSI_SLEEP_ASLEEP);
while (!hadEvent) {
while (!jshHadEventDuringSleep) {
#ifdef NRF52_SERIES
/*
* Clear FPU exceptions.
Expand All @@ -2765,7 +2758,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
while (app_usbd_event_queue_process()); /* Nothing to do */
#endif
}
hadEvent = false;
jshHadEventDuringSleep = false;
jsiSetSleep(JSI_SLEEP_AWAKE);
#ifdef BLUETOOTH
// we don't care about the return codes...
Expand Down
150 changes: 87 additions & 63 deletions targets/stm32/jshardware.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@ JsSysTime jshGetRTCSystemTime();

static JsSysTime jshGetTimeForSecond();

/// Max time we can sleep in JsSysTime units for the watchdog timer - we need this so we don't get rebooted it auto kicking is enabled
uint32_t watchdogSleepMax;

// The amount of systicks for one second depends on the clock speed
#define SYSTICKS_FOR_ONE_SECOND (1+(CLOCK_SPEED_MHZ*1000000/SYSTICK_RANGE))

Expand Down Expand Up @@ -2692,6 +2695,8 @@ void jshClearUSBIdleTimeout() {

/// Enter simple sleep mode (can be woken up by interrupts). Returns true on success
bool jshSleep(JsSysTime timeUntilWake) {
bool isAutoWDT = jsiStatus & JSIS_WATCHDOG_AUTO;

#ifdef USE_RTC
/* TODO:
Check jsiGetConsoleDevice to make sure we don't have to wake on USART (we can't do this fast enough)
Expand All @@ -2706,7 +2711,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
#else
(timeUntilWake > (jshGetTimeForSecond()*16*2/jshRTCPrescaler)) && // if there's less time that this then we can't go to sleep because we can't be sure we'll wake in time
#endif
!jstUtilTimerIsRunning() && // if the utility timer is running (eg. digitalPulse, Waveform output, etc) then that would stop
!jstUtilTimerIsRunning() && // if the utility timer is running (eg. digitalPulse, Waveform output, etc) then that would stop so we can't sleep
!jshHasTransmitData() && // if we're transmitting, we don't want USART/etc to get slowed down
#ifdef USB
!USB_IsConnected() &&
Expand All @@ -2729,93 +2734,104 @@ bool jshSleep(JsSysTime timeUntilWake) {
ADC_Cmd(ADC4, DISABLE); // ADC off
#endif
#ifdef USB
jshSetUSBPower(false);
jshSetUSBPower(false); // WARNING: takes 25ms
bool wokenByUSB = false;
#endif // USB

do { // we loop here so we can half-wake to kick the WDT without incurring wait for USB
JsSysTime timeToSleep = timeUntilWake;
if (isAutoWDT && timeToSleep>watchdogSleepMax)
timeToSleep = watchdogSleepMax;
if (timeUntilWake==JSSYSTIME_MAX) timeUntilWake = 0; // if we're just waiting for as long as possible
else timeUntilWake -= timeToSleep;
if (isAutoWDT) jshKickWatchDog();
/* Add EXTI for Serial port */
//jshPinWatch(JSH_PORTA_OFFSET+10, true);
/* add exti for USB */
#ifdef USB
#ifdef STM32F1
// USB has 15k pull-down resistors (and STM32 has 40k pull up)
Pin usbPin = JSH_PORTA_OFFSET+11;
jshPinSetState(usbPin, JSHPINSTATE_GPIO_IN_PULLUP);
Pin oldWatch = watchedPins[pinInfo[usbPin].pin];
jshPinWatch(usbPin, true, JSPW_NONE);
// USB has 15k pull-down resistors (and STM32 has 40k pull up)
Pin usbPin = JSH_PORTA_OFFSET+11;
jshPinSetState(usbPin, JSHPINSTATE_GPIO_IN_PULLUP);
Pin oldWatch = watchedPins[pinInfo[usbPin].pin];
jshPinWatch(usbPin, true, JSPW_NONE);
#endif
#ifdef USB_VSENSE_PIN
// USB_VSENSE_PIN is connected to USB 5v (and pulled down by a 100k resistor)
// ... so wake up if it goes high
Pin oldWatch = watchedPins[pinInfo[USB_VSENSE_PIN].pin];
jshPinWatch(USB_VSENSE_PIN, true, JSPW_NONE);
// USB_VSENSE_PIN is connected to USB 5v (and pulled down by a 100k resistor)
// ... so wake up if it goes high
Pin oldWatch = watchedPins[pinInfo[USB_VSENSE_PIN].pin];
jshPinWatch(USB_VSENSE_PIN, true, JSPW_NONE);
#endif
#endif // USB

if (timeUntilWake!=JSSYSTIME_MAX) { // set alarm
unsigned int ticks = (unsigned int)(timeUntilWake/jshGetTimeForSecond()); // ensure we round down and leave a little time
if (timeToSleep!=JSSYSTIME_MAX) { // set alarm
unsigned int ticks = (unsigned int)(timeToSleep/jshGetTimeForSecond()); // ensure we round down and leave a little time

#ifdef STM32F1
/* If we're going asleep for more than a few seconds,
* add one second to the sleep time so that when we
* wake up, we execute our timer immediately (even if it is a bit late)
* and don't waste power in shallow sleep. This is documented in setInterval */
if (ticks>3) ticks++; // sleep longer than we need

RTC_SetAlarm(RTC_GetCounter() + ticks);
RTC_ITConfig(RTC_IT_ALR, ENABLE);
//RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
RTC_WaitForLastTask();
/* If we're going asleep for more than a few seconds,
* add one second to the sleep time so that when we
* wake up, we execute our timer immediately (even if it is a bit late)
* and don't waste power in shallow sleep. This is documented in setInterval */
if (ticks>3) ticks++; // sleep longer than we need

RTC_SetAlarm(RTC_GetCounter() + ticks);
RTC_ITConfig(RTC_IT_ALR, ENABLE);
//RTC_AlarmCmd(RTC_Alarm_A, ENABLE);
RTC_WaitForLastTask();
#else // If available, just use the WakeUp counter
if (ticks < ((65536*16) / jshRTCPrescaler)) {
// if the delay is small enough, clock the WakeUp counter faster so we can sleep more accurately
RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16);
ticks = (unsigned int)((timeUntilWake*jshRTCPrescaler) / (jshGetTimeForSecond()*16));
} else { // wakeup in seconds
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);
if (ticks > 65535) ticks = 65535;
}
RTC_SetWakeUpCounter(ticks - 1); // 0 based
RTC_ITConfig(RTC_IT_WUT, ENABLE);
RTC_WakeUpCmd(ENABLE);
RTC_ClearFlag(RTC_FLAG_WUTF);
if (ticks < ((65536*16) / jshRTCPrescaler)) {
// if the delay is small enough, clock the WakeUp counter faster so we can sleep more accurately
RTC_WakeUpClockConfig(RTC_WakeUpClock_RTCCLK_Div16);
ticks = (unsigned int)((timeToSleep*jshRTCPrescaler) / (jshGetTimeForSecond()*16));
} else { // wakeup in seconds
RTC_WakeUpClockConfig(RTC_WakeUpClock_CK_SPRE_16bits);
if (ticks > 65535) ticks = 65535;
}
RTC_SetWakeUpCounter(ticks - 1); // 0 based
RTC_ITConfig(RTC_IT_WUT, ENABLE);
RTC_WakeUpCmd(ENABLE);
RTC_ClearFlag(RTC_FLAG_WUTF);
#endif
}
// set flag in case there happens to be a SysTick
hasSystemSlept = true;
// -----------------------------------------------
}
// set flag in case there happens to be a SysTick
hasSystemSlept = true;
// -----------------------------------------------
#ifdef STM32F4
/* FLASH Deep Power Down Mode enabled */
PWR_FlashPowerDownCmd(ENABLE);
/* FLASH Deep Power Down Mode enabled */
PWR_FlashPowerDownCmd(ENABLE);
#endif
/* Request to enter STOP mode with regulator in low power mode*/
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// -----------------------------------------------
if (timeUntilWake!=JSSYSTIME_MAX) { // disable alarm
/* Request to enter STOP mode with regulator in low power mode*/
PWR_EnterSTOPMode(PWR_Regulator_LowPower, PWR_STOPEntry_WFI);
// -----------------------------------------------
if (timeToSleep!=JSSYSTIME_MAX) { // disable alarm
#ifdef STM32F1
RTC_ITConfig(RTC_IT_ALR, DISABLE);
//RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
RTC_ITConfig(RTC_IT_ALR, DISABLE);
//RTC_AlarmCmd(RTC_Alarm_A, DISABLE);
#else
RTC_ITConfig(RTC_IT_WUT, DISABLE);
RTC_WakeUpCmd(DISABLE);
RTC_ITConfig(RTC_IT_WUT, DISABLE);
RTC_WakeUpCmd(DISABLE);
#endif
}
}
#ifdef USB
bool wokenByUSB = false;
wokenByUSB = false;
#ifdef STM32F1
wokenByUSB = jshPinGetValue(usbPin)==0;
// remove watches on pins
jshPinWatch(usbPin, false, JSPW_NONE);
if (oldWatch!=PIN_UNDEFINED) jshPinWatch(oldWatch, true, JSPW_NONE);
jshPinSetState(usbPin, JSHPINSTATE_GPIO_IN);
wokenByUSB = jshPinGetValue(usbPin)==0;
// remove watches on pins
jshPinWatch(usbPin, false, JSPW_NONE);
if (oldWatch!=PIN_UNDEFINED) jshPinWatch(oldWatch, true, JSPW_NONE);
jshPinSetState(usbPin, JSHPINSTATE_GPIO_IN);
#endif
#ifdef USB_VSENSE_PIN
// remove watch and restore old watch if there was one
// setting that we've woken lets the board stay awake
// until a USB connection can be established
if (jshPinGetValue(USB_VSENSE_PIN)) wokenByUSB=true;
jshPinWatch(USB_VSENSE_PIN, false, JSPW_NONE);
if (oldWatch!=PIN_UNDEFINED) jshPinWatch(oldWatch, true, JSPW_NONE);
// remove watch and restore old watch if there was one
// setting that we've woken lets the board stay awake
// until a USB connection can be established
if (jshPinGetValue(USB_VSENSE_PIN)) wokenByUSB=true;
jshPinWatch(USB_VSENSE_PIN, false, JSPW_NONE);
if (oldWatch!=PIN_UNDEFINED) jshPinWatch(oldWatch, true, JSPW_NONE);
#endif
} while (timeUntilWake>0 && !wokenByUSB && !jshHadEventDuringSleep);
jshHadEventDuringSleep = false;
if (isAutoWDT) jshKickWatchDog();
#endif
// recover oscillator
RCC_HSEConfig(RCC_HSE_ON);
Expand All @@ -2827,7 +2843,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
}
RTC_WaitForSynchro(); // make sure any RTC reads will be done
#ifdef USB
jshSetUSBPower(true);
jshSetUSBPower(true); // WARNING: takes 3ms
if (wokenByUSB)
jshLastWokenByUSB = jshGetRTCSystemTime();
#endif
Expand All @@ -2837,6 +2853,11 @@ bool jshSleep(JsSysTime timeUntilWake) {
if (timeUntilWake > jshGetTimeFromMilliseconds(ESPR_MIN_WFI_TIME_MS)) {
/* don't bother sleeping if the time period is so low we
* might miss the timer */

// Dont' sleep too long if auto WDT enabled (we'll kick when we go around idle loop)
if (isAutoWDT && timeUntilWake > watchdogSleepMax)
timeUntilWake = watchdogSleepMax;

JsSysTime sysTickTime;
#ifdef USE_RTC
sysTickTime = expectedSysTickTime*5/4;
Expand Down Expand Up @@ -3003,6 +3024,9 @@ void jshEnableWatchDog(JsVarFloat timeout) {

/* Enable IWDG (the LSI oscillator will be enabled by hardware) */
IWDG_Enable();

// save timeout so when we sleep we don't sleep so long we get rebooted (use wdt time / 2)
watchdogSleepMax = (uint32_t)jshGetTimeFromMilliseconds(timeout*1000 / 2);
}

// Kick the watchdog
Expand Down

0 comments on commit 529b396

Please sign in to comment.