Optymalizacja watchdogów w modułach AGD (STM32)
/pomiary/watchdog-optymalizacja-stm32-agd • STM32F1/F4 • IWDG/WWDG • jitter i recovery
1. Zakres i cel
Konfiguracja i rozmieszczenie kicka IWDG/WWDG, ograniczenie jitteru i unikanie fałszywych resetów przy intensywnych ISR/DMA. Zawiera wzorce logów, kod inicjalizacji i politykę odzyskiwania.
2. Objawy i sygnatury
2.1 Telemetria
[00:12.417] WDG: IWDG timeout (Δt kick=2.060 s) [00:12.418] RCC_CSR: IWDGRSTF=1 BORRSTF=0 SFTRSTF=0 [00:12.700] SysTick jitter RMS=3.1 ms (próg 1.5 ms)
2.2 Wzorce
- Kick wykonywany w ISR o niskim priorytecie — ryzyko opóźnień.
- WWDG reset po zbyt wczesnym/za późnym odświeżeniu (naruszenie okna).
- Skoki jitteru podczas burstów DMA/EXTI.
3. IWDG — konfiguracja i kick
| Parametr | F1 (typowo) | F4 (typowo) | Uwagi |
|---|---|---|---|
| LSI | ~40 kHz | ~32 kHz | kalibracja zależna od partii |
| Prescaler | 64 | 64 | przykład: timeout ≈ 1.6–2.1 s |
| Reload | ~1000–1300 | ~1200–1500 | dobrać do najgorszego jitteru |
| Kick źródło | SysTick/Timer | SysTick/Timer | poza sekcjami krytycznymi |
// Inicjalizacja IWDG (szkic)
static void iwdg_init(uint16_t presc, uint16_t reload){
IWDG->KR = 0x5555;
IWDG->PR = presc; // 0..6
IWDG->RLR = reload; // 0..0x0FFF
IWDG->KR = 0xCCCC; // start
}
static inline void iwdg_kick(void){
IWDG->KR = 0xAAAA;
}
// Kick z SysTick (priorytet ustaw zgodnie z profilem NVIC)
void SysTick_Handler(void){
systick_tick();
static uint32_t acc; acc++;
if((acc % 8) == 0){ iwdg_kick(); } // np. co 8 ms przy 1 kHz
}
4. WWDG — okno i prewencja zakleszczeń
WWDG wykrywa odświeżenia zbyt wczesne/późne. Stosować jako strażnika „tempa” pętli, gdy ISR mogą wahać czas cyklu.
| Parametr | Wartość startowa | Uwagi |
|---|---|---|
| Prescaler | DIV8 | krok czasu okienka |
| Window | 0x50–0x70 | akceptowalne okno odświeżenia |
| Counter | 0x7F | licznik malejący |
| Early Wakeup | EWIE=1 | IRQ ostrzegające o progu |
// Konfiguracja WWDG (F1/F4 z rejestrami per rodzina)
void wwdg_init(void){
// clock enable wg. rodziny
WWDG->CFR = (WWDG_CFR_W_6 | WWDG_CFR_WDGTB_1) | WWDG_CFR_EWI; // okno + preskaler + EWI
WWDG->CR = 0x7F | WWDG_CR_WDGA; // start z maks. licznikiem
}
void WWDG_IRQHandler(void){
// flaga EWI — odśwież okienkowo
(void)WWDG->SR; // czyść zgodnie z RM
wwdg_refresh_in_window();
}
5. Jitter, SysTick i sekcje krytyczne
// Pomiar jitteru ticka (RMS) w ms
static void jitter_update(uint32_t now_ms){
static uint32_t last_ms, n;
static int64_t sum, sum2;
if(last_ms){ int32_t d = (int32_t)(now_ms - last_ms) - 1; sum += d; sum2 += (int64_t)d*d; n++; }
last_ms = now_ms;
}
static float jitter_rms(void){
extern int64_t sum, sum2; extern uint32_t n;
if(n<2) return 0;
double mean = (double)sum/n;
return (float)sqrt(((double)sum2/n) - mean*mean);
}
// Sekcja krytyczna dla swapów DMA/WSKAŹNIKÓW — BASEPRI uint32_t b = __get_BASEPRI(); __set_BASEPRI(0x30); // próg wg. profilu // operacje atomowe __DSB(); __ISB(); __set_BASEPRI(b);
Kick watchdogów poza sekcjami krytycznymi; skracaj ISR i unikaj kopiowania dużych buforów w przerwaniach.
6. Polityka recovery i logowanie
- Logowanie przyczyny resetu:
RCC->CSR, licznik bootów awaryjnych, znacznik czasu. - Po starcie: czyszczenie flag
RCC_CSR_RMVF, zapis histogramu opóźnień kicka. - Tryb bezpieczny po ≥N resetach w horyzoncie T (ograniczenie funkcji obciążających).
// Odczyt i czyszczenie przyczyn resetu uint32_t csr = RCC->CSR; log_reset_csr(csr); RCC->CSR |= RCC_CSR_RMVF;
// Polityka awaryjna
if(reset_counter_in_window() >= 3){
enter_safe_mode(); // ogranicz PWM/kompresor, minimalny profil ISR
}
7. Kryteria akceptacji
| Kryterium | Cel | Po korektach |
|---|---|---|
| Jitter kick IWDG (RMS) | <1.5 ms | 0.6–1.0 ms |
| Fałszywe resety IWDG / tydzień | 0 | 0 |
| Naruszenia okna WWDG / 10⁶ cykli | <0.01% | ≤0.004% |
| Resety łączone (IWDG+BOR) / tydzień | ≤1 | 0–1 |
8. Uwagi serwisowe
Kick nie powinien występować w tej samej sekcji co swap buforów DMA. Zalecane pomiary jitteru w testach regresyjnych oraz logowanie histogramu odstępów między odświeżeniami. W środowisku z falownikiem rozważyć wydłużenie timeoutu IWDG o 10–20% względem wartości nominalnej LSI.