Skip to content

Commit 3992aae

Browse files
committed
updated STM32 README
1 parent 3ea1633 commit 3992aae

File tree

1 file changed

+298
-21
lines changed

1 file changed

+298
-21
lines changed

hal/architecture/STM32/README.md

Lines changed: 298 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,10 @@ Should work on any STM32 board supported by the STM32duino core.
2727
- [x] Serial communication (USB CDC and Hardware UART)
2828
- [x] SPI interface for radios (nRF24L01+, RFM69, RFM95)
2929
- [x] EEPROM emulation using Flash memory
30-
- [x] Watchdog support (requires explicit initialization)
30+
- [x] Watchdog support (Independent Watchdog - IWDG)
31+
- [x] **Low-power sleep modes** (STOP mode with RTC wake-up)
32+
- [x] **RTC-based timekeeping** (wake-up timer for sleep intervals)
33+
- [x] **Interrupt-based wake from sleep** (GPIO EXTI on any pin)
3134
- [x] System reboot
3235
- [x] Random number generation (using internal temperature sensor)
3336
- [x] Unique device ID (96-bit STM32 UID)
@@ -38,10 +41,9 @@ Should work on any STM32 board supported by the STM32duino core.
3841
- [x] RAM routing table support
3942

4043
### Planned 🔄
41-
- [ ] Low-power sleep modes (STOP, STANDBY)
42-
- [ ] RTC-based timekeeping
43-
- [ ] Interrupt-based wake from sleep
4444
- [ ] Free memory reporting (heap analysis)
45+
- [ ] STANDBY mode support (optional, for ultra-low-power applications)
46+
- [ ] STM32L4-specific STOP2 mode optimization
4547

4648
## Pin Mapping
4749

@@ -234,21 +236,283 @@ The STM32 HAL uses the STM32duino EEPROM library, which provides Flash-based EEP
234236

235237
Configuration is automatic. EEPROM size can be adjusted in the STM32duino menu or via build flags.
236238

237-
## Low-Power Considerations
239+
## Watchdog Support
238240

239-
### Current Status
240-
Sleep modes are **NOT YET IMPLEMENTED** in this initial release. Calling `sleep()` functions will return `MY_SLEEP_NOT_POSSIBLE`.
241+
The STM32 HAL supports the Independent Watchdog (IWDG) for system reliability and crash recovery.
241242

242-
### Future Implementation
243-
The STM32 supports several low-power modes:
244-
- **Sleep mode**: ~10mA (CPU stopped, peripherals running)
245-
- **Stop mode**: ~10-100µA (CPU and most peripherals stopped)
246-
- **Standby mode**: ~1-10µA (only backup domain active)
243+
### Overview
247244

248-
Implementation will use:
249-
- RTC for timed wake-up
250-
- EXTI for interrupt wake-up
251-
- Backup SRAM for state retention
245+
- **Hardware watchdog** using STM32 IWDG peripheral
246+
- **Maximum timeout**: ~32 seconds (hardware limitation)
247+
- **Clock source**: Internal LSI oscillator (~32 kHz, ±40% accuracy)
248+
- **No external components** required
249+
- Works on all STM32 boards
250+
251+
### Important Notes
252+
253+
⚠️ **Watchdog is NOT automatically initialized** by MySensors. You must explicitly initialize and manage it in your sketch.
254+
255+
⚠️ **Maximum timeout is ~32 seconds**. For longer intervals (e.g., low-power sensors with 1-hour wake cycles), you must periodically wake and feed the watchdog during sleep.
256+
257+
⚠️ **Initialize watchdog LAST** in `setup()` after all delays and initialization to prevent premature timeout during startup.
258+
259+
### Timeout Calculation
260+
261+
The watchdog timeout depends on prescaler and reload value:
262+
263+
```
264+
Timeout (seconds) = (Prescaler / 32000) × Reload
265+
```
266+
267+
**Common configurations:**
268+
269+
| Prescaler | Reload | Timeout | Use Case |
270+
|-----------|--------|---------|----------|
271+
| `IWDG_PRESCALER_32` | 4000 | ~4 seconds | Normal operation |
272+
| `IWDG_PRESCALER_128` | 4095 | ~16 seconds | Slower tasks |
273+
| `IWDG_PRESCALER_256` | 2500 | ~20 seconds | Recommended for sleep |
274+
| `IWDG_PRESCALER_256` | 4095 | ~32 seconds | Maximum timeout |
275+
276+
### Usage Example
277+
278+
```cpp
279+
#include <MySensors.h>
280+
#include "stm32f4xx_hal.h"
281+
282+
IWDG_HandleTypeDef hiwdg;
283+
284+
void initWatchdog() {
285+
hiwdg.Instance = IWDG;
286+
hiwdg.Init.Prescaler = IWDG_PRESCALER_256;
287+
hiwdg.Init.Reload = 2500; // ~20 second timeout (256/32000 * 2500 = 20s)
288+
HAL_IWDG_Init(&hiwdg);
289+
}
290+
291+
void setup() {
292+
// Initialize everything first
293+
// ...
294+
295+
// Initialize watchdog LAST (after all delays)
296+
initWatchdog();
297+
}
298+
299+
void loop() {
300+
// Feed watchdog at start of loop
301+
hwWatchdogReset(); // or: IWDG->KR = 0xAAAA;
302+
303+
// Your sensor code
304+
readSensor();
305+
sendData();
306+
307+
// Sleep in chunks, feeding watchdog during sleep
308+
// Must wake every <20 seconds to feed the watchdog
309+
watchdogSafeSleep(60000); // Sleep for 1 minute total
310+
}
311+
312+
void watchdogSafeSleep(uint32_t ms) {
313+
uint32_t remaining = ms;
314+
while (remaining > 0) {
315+
uint32_t chunk = min(15000, remaining); // 15-second chunks (< 20-second timeout)
316+
sleep(chunk);
317+
hwWatchdogReset(); // Feed watchdog after each chunk
318+
remaining -= chunk;
319+
}
320+
}
321+
```
322+
323+
### Long Sleep Intervals with Watchdog
324+
325+
For battery-powered sensors with long sleep intervals (e.g., 1 hour), you must wake periodically to feed the watchdog:
326+
327+
```cpp
328+
void loop() {
329+
hwWatchdogReset();
330+
331+
readSensor();
332+
sendData();
333+
334+
// Sleep for 1 hour in chunks, feeding watchdog every 15 seconds
335+
watchdogSafeSleep(3600000);
336+
}
337+
338+
void watchdogSafeSleep(uint32_t ms) {
339+
uint32_t remaining = ms;
340+
while (remaining > 0) {
341+
uint32_t chunk = min(15000, remaining); // 15s chunks (< 20s timeout)
342+
sleep(chunk);
343+
hwWatchdogReset(); // Feed watchdog after each chunk
344+
remaining -= chunk;
345+
}
346+
}
347+
```
348+
349+
**Key points:**
350+
- Sleep in chunks smaller than watchdog timeout
351+
- Feed watchdog between sleep chunks
352+
- This adds brief wake-ups (~1ms every 15 seconds) but provides crash protection
353+
354+
**Alternative:** For ultra-low-power applications where watchdog wake-ups are unacceptable, consider:
355+
- External watchdog IC (e.g., TPL5010 with up to 2-hour timeout)
356+
- Software counter: Only trigger watchdog reset after N failed wake cycles
357+
358+
### Build Configuration
359+
360+
Add to `platformio.ini`:
361+
362+
```ini
363+
build_flags =
364+
-D HAL_IWDG_MODULE_ENABLED ; Required to enable IWDG HAL module
365+
```
366+
367+
**Note**: This build flag is **required** and cannot be defined in source code. The STM32 HAL framework needs this flag during compilation.
368+
369+
### Detecting Watchdog Resets
370+
371+
Check if the last reset was caused by the watchdog:
372+
373+
```cpp
374+
void setup() {
375+
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
376+
// System was reset by watchdog
377+
__HAL_RCC_CLEAR_RESET_FLAGS();
378+
// Handle watchdog reset (e.g., log error, send alert)
379+
}
380+
381+
// ... rest of setup
382+
initWatchdog(); // Initialize watchdog LAST
383+
}
384+
```
385+
386+
## Low-Power Sleep Support
387+
388+
### Overview
389+
390+
The STM32 HAL implements **STOP mode** for battery-powered sensor nodes, providing multi-year battery life while maintaining MySensors compatibility.
391+
392+
### Sleep Modes
393+
394+
| Mode | Sleep Current | Wake-up Time | Features | Battery Life* |
395+
|------|---------------|--------------|----------|---------------|
396+
| **STOP**| 10-50 µA | 1-3 ms | GPIO EXTI wake, RTC timer, state retained | **5-10 years** |
397+
| STANDBY 🔄 | 2-4 µA | 5-10 ms | RTC timer only, state lost | 10+ years |
398+
399+
*Based on 2x AA batteries (2000 mAh), 5-minute reporting interval
400+
401+
**Currently Implemented**: STOP mode (recommended for all battery-powered MySensors nodes)
402+
403+
### Power Consumption
404+
405+
**Typical Battery-Powered Sensor** (5-minute reporting interval):
406+
407+
```
408+
Average current: 30-50 µA
409+
Battery life (2x AA): 5-10 years
410+
Sleep current (STM32F4): 30 µA
411+
Sleep current (STM32L4): 2-5 µA
412+
```
413+
414+
### Sleep API Usage
415+
416+
#### Timer-Based Sleep
417+
```cpp
418+
void loop() {
419+
float temp = readTemperature();
420+
send(msgTemp.set(temp, 1));
421+
422+
sleep(300000); // Sleep for 5 minutes
423+
}
424+
```
425+
426+
#### Interrupt Wake-Up (Event-Driven Sensors)
427+
```cpp
428+
#define BUTTON_PIN PA0
429+
430+
void loop() {
431+
// Sleep until button pressed
432+
sleep(digitalPinToInterrupt(BUTTON_PIN), CHANGE, 0);
433+
434+
// Button was pressed
435+
send(msgButton.set(1));
436+
}
437+
```
438+
439+
#### Combined Timer + Interrupt Wake-Up
440+
```cpp
441+
void loop() {
442+
// Sleep until button press OR 1 hour timeout
443+
int8_t wakeReason = sleep(digitalPinToInterrupt(BUTTON_PIN), CHANGE, 3600000);
444+
445+
if (wakeReason == MY_WAKE_UP_BY_TIMER) {
446+
// Timed wake-up - send periodic report
447+
sendPeriodicReport();
448+
} else {
449+
// Button press wake-up
450+
handleButtonPress();
451+
}
452+
}
453+
```
454+
455+
### Sleep Implementation Details
456+
457+
**STOP Mode Characteristics**:
458+
-**GPIO EXTI wake-up** on any pin (supports radio IRQ, sensors, buttons)
459+
-**RTC wake-up timer** for periodic operation (1 ms to ~18 hours)
460+
-**State retention** (SRAM and registers preserved)
461+
-**Fast wake-up** (1-3 ms, compatible with radio timing)
462+
-**Low power** (10-50 µA on STM32F4, 2-5 µA on STM32L4)
463+
464+
**Wake-up Sources**:
465+
- RTC wake-up timer (configured automatically by `sleep(ms)`)
466+
- GPIO EXTI interrupts (any pin, any edge)
467+
- Watchdog timeout (if enabled)
468+
469+
**System Behavior**:
470+
1. Before sleep: RTC configured, interrupts attached, SysTick suspended
471+
2. During sleep: MCU in STOP mode (10-50 µA), peripherals stopped
472+
3. After wake-up: System clock restored, SysTick resumed, wake source identified
473+
4. State preserved: No reinitialization required
474+
475+
### Configuration Options
476+
477+
#### Sleep Configuration (MyConfig.h)
478+
```cpp
479+
// Stay on HSI (16 MHz) after wake-up for faster wake-up (default)
480+
// Uncomment to restore full speed (84 MHz) at cost of +2 ms wake-up time
481+
// #define MY_STM32_USE_HSE_AFTER_WAKEUP
482+
483+
// RTC clock source (LSE recommended for accuracy)
484+
#define MY_STM32_RTC_CLOCK_SOURCE LSE // Or LSI if no 32kHz crystal
485+
```
486+
487+
#### Power Optimization Build Flags
488+
```ini
489+
[env:battery_sensor]
490+
build_flags =
491+
-D MY_DISABLED_SERIAL ; Disable serial for low power
492+
-D MY_TRANSPORT_WAIT_READY_MS=1 ; Don't wait for gateway
493+
-D MY_SLEEP_TRANSPORT_RECONNECT_TIMEOUT_MS=2000
494+
```
495+
496+
### Hardware Considerations
497+
498+
**For Best Battery Life**:
499+
1. **Use STM32L4** series for ultra-low-power (2-5 µA sleep vs 30 µA on STM32F4)
500+
2. **Add LSE crystal** (32.768 kHz) for accurate RTC timing
501+
3. **Disable unused peripherals** (USB, debug, unused UARTs)
502+
4. **Configure GPIO properly** (no floating pins, use pull-ups/downs)
503+
5. **Choose efficient regulator** (low quiescent current LDO <10 µA)
504+
505+
**Compatible Radios**:
506+
- **nRF24L01+**: Radio can sleep (0.9 µA), IRQ pin wakes MCU
507+
- **RFM69/RFM95**: Radio can sleep (1-5 µA), DIO pins wake MCU
508+
509+
### Known Limitations
510+
511+
1. **Maximum sleep time**: ~18 hours (RTC wake-up timer limitation)
512+
- For longer intervals, use multiple sleep cycles
513+
2. **Debug interface**: Disable in sleep for lowest power (debug keeps ~2 mA active)
514+
3. **USB CDC**: Not compatible with sleep (use hardware UART or disable serial)
515+
4. **STANDBY mode**: Not yet implemented (state loss, no GPIO EXTI support)
252516

253517
## Troubleshooting
254518

@@ -301,14 +565,19 @@ Implementation will use:
301565
- **CPU**: 100 MHz ARM Cortex-M4F
302566
- **Flash**: 512KB
303567
- **RAM**: 128KB
304-
- **Current**: ~50mA active, <1µA standby (when implemented)
568+
- **Current (active)**: ~30-50 mA
569+
- **Current (STOP mode)**: 30-50 µA (STM32F4), 2-5 µA (STM32L4)
305570
- **MySensors overhead**: ~30KB Flash, ~4KB RAM
571+
- **Battery life**: 5-10 years (2x AA, 5-min reporting)
306572

307-
### Benchmarks (preliminary)
308-
- **Radio message latency**: <10ms (similar to AVR)
573+
### Benchmarks
574+
- **Radio message latency**: <10ms (comparable to AVR)
575+
- **Wake-up time**: 1-3 ms (STOP mode)
309576
- **EEPROM read**: ~50µs per byte
310577
- **EEPROM write**: ~5ms per byte (Flash write)
311578
- **Temperature reading**: ~100µs
579+
- **Sleep current**: 30 µA typical (STM32F4 STOP mode)
580+
- **Average current** (5-min sensor): 30-50 µA
312581

313582
## Contributing
314583

@@ -333,8 +602,16 @@ This code is part of the MySensors project and is licensed under the GNU General
333602

334603
## Version History
335604

605+
- **v1.1.0** (2025-01-23) - Sleep mode and watchdog support
606+
- ✅ STOP mode sleep implementation
607+
- ✅ RTC wake-up timer (1 ms to ~18 hours)
608+
- ✅ GPIO EXTI interrupt wake-up (any pin, any edge)
609+
- ✅ Dual interrupt wake-up support
610+
- ✅ Independent Watchdog (IWDG) support
611+
- ✅ System clock reconfiguration after wake-up
612+
336613
- **v1.0.0** (2025-01-17) - Initial STM32 HAL implementation
337614
- Basic functionality (GPIO, SPI, EEPROM, Serial)
338-
- Tested on STM32F401/F411 Black Pill
339615
- Gateway and sensor node support
340-
- No sleep mode yet (planned for v1.1.0)
616+
- CPU voltage and temperature reading
617+
- Watchdog reset function (initialization required in user sketch)

0 commit comments

Comments
 (0)