STM32 Clock Security System (CSS):
Rilevare e Recuperare un Guasto HSE

2026-06-16 · Davide Carrese
STM32 · RCC · CSS · HSE · NMI · Safety

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:

  1. Azzerra i bit HSEON e CSSON in RCC->CR
  2. Commuta automaticamente la sorgente del clock di sistema su HSI
  3. Imposta il flag CSSF in RCC->CIR
  4. 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

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:

Fonti e Riferimenti

💬 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.