STM32 Clock Security System (CSS):
Rilevare e Recuperare un Guasto HSE
Niente è peggio di un reso in campo dove il microcontrollore è vivo ma il firmware sta silenziosamente funzionando con la sorgente di clock sbagliata. Il cristallo esterno — il cuore della temporizzazione del sistema — può guastarsi per molte ragioni: shock meccanico, ESD, una saldatura fredda sul PCB, o semplicemente un risonatore invecchiato che smette di oscillare. Senza un meccanismo di rilevamento, il sistema continua a eseguire codice alla velocità sbagliata o si blocca del tutto, spesso corrompendo i link di comunicazione o violando le scadenze real-time.
Il Clock Security System (CSS) degli STM32 è una funzionalità hardware di sicurezza che monitora l'oscillatore esterno HSE e passa automaticamente all'oscillatore interno HSI quando viene rilevato un guasto. In questo articolo vedremo come funziona il CSS a livello di registro, come configurarlo correttamente, come implementare una strategia di recupero sicura nell'NMI handler e quali insidie evitare nel firmware di produzione.
Come Funziona il CSS
Il CSS è disponibile sulla maggior parte delle famiglie STM32, incluse STM32F0/F1/F3/F4/F7/G0/G4/L0/L4/L5/U5/H7 e successive. Si tratta di un contatore hardware che conta i cicli del clock HSE rispetto a un riferimento (tipicamente l'oscillatore HSI). Se HSE smette di commutare per un numero predefinito di cicli, l'hardware:
- Azzerra i bit HSEON e CSSON in RCC->CR
- Commuta automaticamente la sorgente del clock di sistema su HSI
- Imposta il flag CSSF in RCC->CIR
- Attiva una NMI (Non-Maskable Interrupt) hard-coded
L'intera transizione richiede circa 1–2 cicli di clock HSI. Il sistema non si resetta — continua semplicemente a eseguire codice su HSI, a una frequenza nota e sicura (tipicamente 8 MHz o 16 MHz, a seconda della famiglia). Questo dà al firmware l'opportunità di intraprendere un'azione correttiva.
Abilitazione del CSS
Il CSS si abilita impostando il bit CSSON nel registro RCC control register. La procedura è semplice, ma l'ordine è importante:
/* 1. Configura e abilita HSE come al solito */
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)) { /* attendi */ }
/* 2. Configura PLL e clock di sistema da HSE */
/* ... impostazioni PLL, flash wait states, ecc. ... */
/* 3. Abilita CSS dopo che il clock di sistema è stabile su HSE */
RCC->CR |= RCC_CR_CSSON;
Il CSS deve essere abilitato dopo che il clock di sistema si è stabilizzato su HSE. Abilitarlo durante la commutazione del clock può causare falsi trigger. Una volta attivato, il CSS funziona continuamente in hardware — nessun polling necessario.
NMI Handler CSS — Il Codice di Recupero
Quando il CSS scatta, il processore entra nell'NMI handler. Questo non è l'HardFault handler — la NMI è un'eccezione separata con priorità superiore a qualsiasi interrupt configurabile. Il vettore NMI deve essere definito nel file di startup.
La sequenza di recupero tipica all'interno dell'NMI handler:
void NMI_Handler(void)
{
/* 1. Leggi e cancella il flag CSS */
if (RCC->CIR & RCC_CIR_CSSF) {
RCC->CIR |= RCC_CIR_CSSC; /* scrivi 1 per cancellare */
}
/* 2. L'hardware ha già commutato su HSI.
* Verifica la sorgente del clock di sistema. */
uint32_t sw = RCC->CFGR & RCC_CFGR_SWS;
if (sw != RCC_CFGR_SWS_HSI) {
/* Forza la commutazione su HSI se l'hardware non l'ha fatto */
RCC->CFGR = (RCC->CFGR & ~RCC_CFGR_SW) | RCC_CFGR_SW_HSI;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_HSI) { }
}
/* 3. Disabilita PLL (era pilotata da HSE) */
RCC->CR &= ~RCC_CR_PLLON;
while (RCC->CR & RCC_CR_PLLRDY) { /* attendi reset PLL */ }
/* 4. Disabilita CSS (one-shot — va riabilitato in seguito) */
RCC->CR &= ~RCC_CR_CSSON;
/* 5. Riconfigura flash wait states per la frequenza HSI */
FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY) | FLASH_ACR_LATENCY_0;
/* 6. Riconfigura i clock delle periferiche, baud rate, timer
* che dipendono dalla frequenza del clock di sistema.
* Questa parte è specifica dell'applicazione. */
reconfigure_peripherals_for_hsi();
/* 7. Segnala il guasto al livello applicativo */
system_fault_flags.css_hse_failure = 1;
/* 8. Opzionale: entra in modalità sicura o prova a riabilitare HSE */
/* L'NMI handler ritorna al codice interrotto. */
}
Esempio Pratico: Simulazione Guasto HSE su STM32F4
Implementiamo un esempio completo di recupero CSS su una scheda STM32F401 Nucleo. La scheda ha un cristallo HSE da 8 MHz. Configuriamo il sistema a 84 MHz da HSE + PLL, abilitiamo il CSS, e simuliamo un guasto mettendo a massa il pin HSE (o tramite test via software).
#include "stm32f4xx.h"
volatile uint32_t css_triggered = 0;
void NMI_Handler(void)
{
if (RCC->CIR & RCC_CIR_CSSF) {
RCC->CIR = RCC_CIR_CSSC; /* cancella flag */
css_triggered = 1;
}
/* HSE guastato — hardware già commutato su HSI (16 MHz) */
RCC->CR &= ~(RCC_CR_PLLON | RCC_CR_CSSON);
/* Flash wait states: 0 WS per 16 MHz HSI */
FLASH->ACR = (FLASH->ACR & ~FLASH_ACR_LATENCY)
| FLASH_ACR_LATENCY_0;
/* Riconfigura USART2 baud per 16 MHz */
USART2->BRR = 16000000 / 115200;
/* Notifica al loop principale */
__DSB();
}
int main(void)
{
/* Abilita HSE */
RCC->CR |= RCC_CR_HSEON;
while (!(RCC->CR & RCC_CR_HSERDY)) { }
/* Configura PLL principale: 8 MHz HSE → 84 MHz */
RCC->PLLCFGR = (8 << 24) | (336 << 6) | (1 << 16) | (4 << 28);
RCC->CR |= RCC_CR_PLLON;
while (!(RCC->CR & RCC_CR_PLLRDY)) { }
/* Configura flash: 5 WS per 84 MHz */
FLASH->ACR = FLASH_ACR_PRFTEN | FLASH_ACR_ICEN | FLASH_ACR_DCEN
| FLASH_ACR_LATENCY_5WS;
/* Commuta clock di sistema su PLL */
RCC->CFGR |= RCC_CFGR_SW_PLL;
while ((RCC->CFGR & RCC_CFGR_SWS) != RCC_CFGR_SWS_PLL) { }
/* Abilita CSS dopo che il clock è stabile */
RCC->CR |= RCC_CR_CSSON;
/* Codice applicativo principale */
while (1) {
if (css_triggered) {
/* In produzione: salva log guasto, modalità sicura,
* o tenta riavvio HSE (con debounce) */
__WFI();
}
}
}
Checklist Pratica per il CSS in Produzione
- Verifica che il vettore NMI esista: Il file di startup deve avere un NMI_Handler non predefinito. Molti progetti lasciano NMI collegato al loop infinito di default — questo significa che il CSS scatta e il sistema si blocca silenziosamente.
- Non riabilitare CSS dalla NMI: Il CSS è one-shot. Abilitare CSSON dentro l'NMI handler mentre la condizione di guasto persiste causa una cascata di NMI. Riabilita CSS solo dopo che HSE è stato confermato stabile.
- Controlla la velocità del clock di sistema: Dopo il recupero CSS, tutte le periferiche che dipendono dalla frequenza (baud rate USART, SCK SPI, temporizzazioni I2C, frequenze timer, tempo di campionamento ADC) vanno riconfigurate per la frequenza HSI. L'NMI handler deve gestirlo.
- Testa il CSS nel firmware di produzione: Non dare per scontato che il CSS funzioni perché hai impostato il bit. Testa cortocircuitando i pin del cristallo HSE (con una resistenza!) in ambiente controllato e verifica che la NMI scatti e il recupero sia completo.
- Documenta il comportamento di recupero: Cosa fa il prodotto dopo un guasto HSE? Registra un errore? Lampeggia un LED? Entra in uno stato sicuro? Questa è una decisione a livello di sistema, non solo firmware.
- Attenzione alle modalità STOP e STANDBY: Il CSS è disabilitato durante STOP. Al risveglio, se HSE era la causa del guasto, il CSS ti protegge solo se lo riabiliti dopo che il clock di sistema si è stabilizzato su HSE.
- Su parti dual-core e M33: Il CSS può essere instradato al security monitor su STM32H5/U5. Controlla il partizionamento TrustZone — il CSS potrebbe essere un interrupt secure-only.
Come Lo Affronterei Su un Progetto Cliente
Su un progetto medicale o industriale in produzione, tratto il CSS come una funzionalità di sicurezza obbligatoria, non un diagnostico opzionale. L'NMI handler viene scritto prima di qualsiasi codice applicativo, e la strategia di recupero è documentata nell'analisi di sicurezza del sistema.
Il mio approccio standard:
- Definisco una struct
system_fault_flagscon flag individuali per CSS, perdita lock PLL, guasto LSE, brown-out e reset watchdog. Questa struct è posizionata in una sezione SRAM dedicata che sopravvive ai reset software (bypassando l'inizializzazione all'avvio). - L'NMI handler imposta il flag CSS, disabilita PLL, commuta su HSI, aggiorna tutti i divisori di clock delle periferiche, e ritorna. L'applicazione controlla i flag di guasto nel loop principale e decide se continuare in modalità degradata o richiedere uno spegnimento sicuro.
- Un task periodico tenta di riavviare HSE in background (con un cooldown di 10 secondi) e, in caso di successo, riabilita CSS e torna su PLL. Questo permette il recupero automatico da glitch HSE transitori senza un reset completo.
- Aggiungo una voce nel log di salute del sistema con timestamp, in modo che i resi in campo possano essere correlati ai dati di produzione.
Fonti e Riferimenti
- ST Application Note AN4907 — Clock Security System for STM32 MCUs
- ST RM0090 — Reference Manual STM32F405/415, STM32F407/417, STM32F427/437 and STM32F429/439 (capitolo RCC, sezione CSS)
- ST RM0399 — Reference Manual STM32H742, STM32H743/753 and STM32H750
- STM32CubeF4 Esempio:
RCC/RCC_ClockSecuritySystem - Cortex-M3/M4/M7 Generic User Guide — gestione eccezioni NMI
💬 Commenta via email
Se hai domande, correzioni, o vuoi condividere la tua esperienza con il CSS su STM32, scrivimi a blog-comments@carrese.eu. Includi lo slug dell'articolo nell'oggetto.