Skip to content

Commit ebb469b

Browse files
committed
STM32: Ensure setDeepSleep(1) will only sleep if there are no active PWM outputs
1 parent 066c601 commit ebb469b

File tree

1 file changed

+50
-16
lines changed

1 file changed

+50
-16
lines changed

targets/stm32/jshardware.c

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,8 @@ Pin watchedPins[16];
9292

9393
// Whether a pin is being used for soft PWM or not
9494
BITFIELD_DECL(jshPinSoftPWM, JSH_PIN_COUNT);
95+
// Whether a pin is being used for hard PWM or not
96+
BITFIELD_DECL(jshPinHardPWM, JSH_PIN_COUNT);
9597

9698
#ifdef STM32F1
9799
// F1 can't do opendrain pullup, so we do it manually!
@@ -135,6 +137,12 @@ void jshSetIsSerial7Bit(IOEventFlags device, bool is7Bit) {
135137
}
136138
#endif
137139

140+
bool jshIsHWPWMActive() {
141+
for (unsigned int i=0;i<(sizeof(jshPinHardPWM)>>2);i++) // it's a uint32
142+
if (jshPinHardPWM[i]) return true;
143+
return false;
144+
}
145+
138146
// ----------------------------------------------------------------------------
139147
// PINS
140148

@@ -958,14 +966,12 @@ void jshDelayMicroseconds(int microsec) {
958966
while (iter--) __NOP();
959967
}
960968

961-
void jshPinSetState(Pin pin, JshPinState state) {
969+
/// Internal implementation (does not call jshPinUpdateFunction as this is itself called from jshPinSetFunction)
970+
static void jshPinSetState_intl(Pin pin, JshPinState state) {
962971
if (pinInfo[pin].port & JSH_PIN_NEGATED) {
963972
if (state==JSHPINSTATE_GPIO_IN_PULLUP) state=JSHPINSTATE_GPIO_IN_PULLDOWN;
964973
else if (state==JSHPINSTATE_GPIO_IN_PULLDOWN) state=JSHPINSTATE_GPIO_IN_PULLUP;
965974
}
966-
// if this is about to mess up the neopixel output, so reset our var so we know to re-init
967-
if (pin == jshNeoPixelPin)
968-
jshNeoPixelPin = PIN_UNDEFINED;
969975
/* Make sure we kill software PWM if we set the pin state
970976
* after we've started it */
971977
if (BITFIELD_GET(jshPinSoftPWM, pin)) {
@@ -1057,21 +1063,31 @@ JshPinState jshPinGetState(Pin pin) {
10571063
// GPIO_ReadOutputDataBit(port, pinn);
10581064
}
10591065

1066+
static NO_INLINE void jshPinUpdateFunction(Pin pin, JshPinFunction func) {
1067+
// keep track of whether we are doing PWM or not
1068+
if (JSH_PINFUNCTION_IS_TIMER(func)) {
1069+
BITFIELD_SET(jshPinHardPWM, pin, true);
1070+
} else {
1071+
BITFIELD_SET(jshPinHardPWM, pin, false);
1072+
}
1073+
}
1074+
10601075
static NO_INLINE void jshPinSetFunction(Pin pin, JshPinFunction func) {
1076+
jshPinUpdateFunction(pin, func);
10611077
if (JSH_PINFUNCTION_IS_USART(func)) {
10621078
if ((func&JSH_MASK_INFO)==JSH_USART_RX)
1063-
jshPinSetState(pin, JSHPINSTATE_USART_IN);
1079+
jshPinSetState_intl(pin, JSHPINSTATE_USART_IN);
10641080
else
1065-
jshPinSetState(pin,JSHPINSTATE_USART_OUT);
1081+
jshPinSetState_intl(pin, JSHPINSTATE_USART_OUT);
10661082
} else if (JSH_PINFUNCTION_IS_I2C(func)) {
1067-
jshPinSetState(pin, JSHPINSTATE_I2C);
1083+
jshPinSetState_intl(pin, JSHPINSTATE_I2C);
10681084
#ifdef STM32F1 // F4 needs SPI MOSI to be set as AF out
10691085
} else if (JSH_PINFUNCTION_IS_SPI(func) && ((func&JSH_MASK_INFO)==JSH_SPI_MISO)) {
1070-
jshPinSetState(pin, JSHPINSTATE_GPIO_IN_PULLUP); // input pullup for MISO
1086+
jshPinSetState_intl(pin, JSHPINSTATE_GPIO_IN_PULLUP); // input pullup for MISO
10711087
#endif
10721088
} else {
10731089
bool opendrain = JSHPINSTATE_IS_OPENDRAIN(jshPinGetState(pin)&JSHPINSTATE_MASK);
1074-
jshPinSetState(pin, opendrain ? JSHPINSTATE_AF_OUT_OPENDRAIN : JSHPINSTATE_AF_OUT); // otherwise general AF out!
1090+
jshPinSetState_intl(pin, opendrain ? JSHPINSTATE_AF_OUT_OPENDRAIN : JSHPINSTATE_AF_OUT); // otherwise general AF out!
10751091
}
10761092
// now 'connect' the pin up
10771093
#if defined(STM32F2) || defined(STM32F3) || defined(STM32F4)
@@ -1108,10 +1124,16 @@ static NO_INLINE void jshPinSetFunction(Pin pin, JshPinFunction func) {
11081124
}
11091125
#endif
11101126
else if (remap) jsError("(internal) Remap needed, but unknown device %d", func&JSH_MASK_TYPE);
1111-
11121127
#endif
11131128
}
11141129

1130+
void jshPinSetState(Pin pin, JshPinState state) {
1131+
// If this was set to be some kind of AF (USART, etc), reset it.
1132+
jshPinUpdateFunction(pin, JSH_NOTHING);
1133+
// Now set the state properly
1134+
jshPinSetState_intl(pin, state);
1135+
}
1136+
11151137
void jshPinSetValue(Pin pin, bool value) {
11161138
if (pinInfo[pin].port & JSH_PIN_NEGATED) value=!value;
11171139
#ifdef STM32API2
@@ -1244,7 +1266,7 @@ void jshInit() {
12441266
we detect that (with RTC_BKP_DR0_TURN_OFF written into RTC_BKP_DR0) and turn ourselves back off quickly */
12451267
if (RTC_ReadBackupRegister(RTC_BKP_DR0)==RTC_BKP_DR0_TURN_OFF) {
12461268
PWR_BackupAccessCmd(ENABLE);
1247-
jshDelayMicroseconds(10); // Some devices seem to need a delay
1269+
jshDelayMicroseconds(10); // Some devices seem to need a delay
12481270
RTC_WriteBackupRegister(RTC_BKP_DR0, RTC_BKP_DR0_NULL);
12491271
if (RCC_GetFlagStatus(RCC_FLAG_IWDGRST)) {
12501272
PWR_WakeUpPinCmd(ENABLE);
@@ -1265,6 +1287,7 @@ void jshInit() {
12651287
for (i=0;i<16;i++)
12661288
watchedPins[i] = PIN_UNDEFINED;
12671289
BITFIELD_CLEAR(jshPinSoftPWM);
1290+
BITFIELD_CLEAR(jshPinHardPWM);
12681291
#ifdef STM32F1
12691292
BITFIELD_CLEAR(jshPinOpendrainPullup);
12701293
#endif
@@ -2209,10 +2232,9 @@ void *NO_INLINE checkPinsForDevice(JshPinFunction device, int count, Pin *pins,
22092232
void *ptr = setDeviceClockCmd(device, ENABLE);
22102233
// now set up correct states
22112234
for (i=0;i<count;i++)
2212-
if (jshIsPinValid(pins[i])) {
2213-
//pinState[pins[i]] = functions[i];
2214-
jshPinSetFunction(pins[i], functions[i]);
2215-
}
2235+
if (jshIsPinValid(pins[i])) {
2236+
jshPinSetFunction(pins[i], functions[i]);
2237+
}
22162238
// all ok
22172239
return ptr;
22182240
}
@@ -2706,7 +2728,6 @@ bool jshSleep(JsSysTime timeUntilWake) {
27062728
/* TODO:
27072729
Check jsiGetConsoleDevice to make sure we don't have to wake on USART (we can't do this fast enough)
27082730
Check that we're not using EXTI 11 for something else
2709-
Check we're not using PWM as this will stop
27102731
What about EXTI line 18 - USB Wakeup event
27112732
Check time until wake against where we are in the RTC counter - we can sleep for 0.1 sec if we're 90% of the way through the counter...
27122733
*/
@@ -2717,6 +2738,7 @@ bool jshSleep(JsSysTime timeUntilWake) {
27172738
(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
27182739
#endif
27192740
!jstUtilTimerIsRunning() && // if the utility timer is running (eg. digitalPulse, Waveform output, etc) then that would stop so we can't sleep
2741+
!jshIsHWPWMActive() && // Check we're not using PWM as this will stop
27202742
!jshHasTransmitData() && // if we're transmitting, we don't want USART/etc to get slowed down
27212743
#ifdef USB
27222744
!USB_IsConnected() &&
@@ -3343,5 +3365,17 @@ void jshReboot() {
33433365
/* Adds the estimated power usage of the microcontroller in uA to the 'devices' object. The CPU should be called 'CPU' */
33443366
void jsvGetProcessorPowerUsage(JsVar *devices) {
33453367
jsvObjectSetChildAndUnLock(devices, "CPU", jsvNewFromInteger(15000));
3368+
if (jshIsHWPWMActive()) {
3369+
jsvObjectSetChildAndUnLock(devices, "PWM", jsvNewFromInteger(1000)); // Guess
3370+
// report names of pins with PWM to aid debugging
3371+
char pwmPin[13] = "PWM";
3372+
for (Pin i=0;i<JSH_PIN_COUNT;i++) {
3373+
if (BITFIELD_GET(jshPinHardPWM,i)) {
3374+
jshGetPinString(&pwmPin[3], i);
3375+
jsvObjectSetChildAndUnLock(devices, pwmPin, jsvNewFromInteger(0));
3376+
}
3377+
}
3378+
}
33463379
// we're not in deep sleep now (should we be able to figure out how long we were sleeping for?)
33473380
}
3381+

0 commit comments

Comments
 (0)