Architettura del Dominio di Backup

Il dominio di backup comprende:

  • RTC — calendario (ore/minuti/secondi + data/giorno/mese/anno) alimentato da LSE (32.768 kHz) o LSI (~32 kHz)
  • 20 registri di backup da 32 bit (BKPxR su F4, RTC_BKPxR sulle serie recenti) — mantengono i dati durante la sola alimentazione VBAT
  • Rilevamento tamper — fino a 3 pin tamper con sensibilità di fronte/livello configurabile, cattura timestamp opzionale
  • Wake-up timer — un contatore alla rovescia indipendente che può risvegliare il sistema da STOP 0/1/2 e STANDBY
  • Allarmi RTC — due allarmi configurabili (A e B) che attivano l'uscita RTC_ALARM

Il commutatore di alimentazione tra VDD e VBAT è interno: quando VDD scende sotto la soglia VBAT, il dominio di backup passa trasparentemente a VBAT. Su STM32L4/U5, il dominio di backup include anche LPTIM e i GPIO PC13–PC15 configurati come uscite RTC.

Accesso e Protezione da Scrittura

I registri del dominio di backup risiedono sul bus APB1 ma sono protetti in scrittura per impostazione predefinita. Scrivere nei registri RTC, registri di backup o registri di controllo RTC richiede lo sblocco del Power Control e del Backup Domain:

// Step 1: Abilita l'interfaccia PWR e il clock RTC
RCC->APB1ENR |= RCC_APB1ENR_PWREN;  // abilita interfaccia PWR
PWR->CR1 |= PWR_CR1_DBP;            // abilita accesso scrittura backup domain
while (!(PWR->CR1 & PWR_CR1_DBP));

// Step 2: Abilita clock RTC, seleziona LSE come sorgente
RCC->BDCR |= RCC_BDCR_RTCEN;        // abilita clock RTC
RCC->BDCR |= RCC_BDCR_RTCSEL;       // seleziona LSE come sorgente

L'ordine conta. Scrivere nei registri RTC prima di impostare DBP viene silenziosamente ignorato — nessun errore, nessun effetto. È una delle trappole di debug RTC più comuni.

Inizializzazione del Calendario RTC

Su STM32F4 e successivi, il periferico RTC usa un set di registri unificato. Il calendario viene configurato attraverso la modalità di inizializzazione, uno stato protetto che può essere inserito solo quando l'RTC non è inizializzato o dopo un reset di sistema.

// Entra in modalità init
RTC->ISR |= RTC_ISR_INIT;
while (!(RTC->ISR & RTC_ISR_INITF));

// Configura prescaler (LSE = 32768 Hz)
RTC->PRER = (0x7F << 16)          // prescaler async = 128 → 256 Hz
          | (0xFF << 0);          // prescaler sync = 256 → 1 Hz

// Imposta ora iniziale: 14:30:00
RTC->TR = (0 << RTC_TR_PM_Pos)
        | (0x14 << RTC_TR_HT_Pos)
        | (4 << RTC_TR_HU_Pos)
        | (3 << RTC_TR_MNT_Pos)
        | (0 << RTC_TR_MNU_Pos)
        | (0 << RTC_TR_ST_Pos)
        | (0 << RTC_TR_SU_Pos);

// Imposta data iniziale: 2026-06-20
RTC->DR = (0 << RTC_DR_YT_Pos)
        | (6 << RTC_DR_YU_Pos)
        | (0 << RTC_DR_WDU_Pos)
        | (6 << RTC_DR_MU_Pos)    // giugno
        | (2 << RTC_DR_DT_Pos)
        | (0 << RTC_DR_DU_Pos);   // 20

RTC->CR &= ~RTC_CR_FMT;           // formato 24 ore

// Esci da modalità init
RTC->ISR &= ~RTC_ISR_INIT;

// Attendi sincronizzazione registri (~2 cicli RTCCLK)
RTC->ISR &= ~RTC_ISR_RSF;
while (!(RTC->ISR & RTC_ISR_RSF));

I registri shadow (RTC_TR, RTC_DR) vengono aggiornati asincronamente dal contatore RTC. Leggerli immediatamente dopo la scrittura può restituire dati obsoleti. Il flag RSF garantisce che i registri shadow siano sincronizzati.

Registri di Backup: Persistenza dello Stato tra i Reset

I 20 registri di backup (RTC_BKP0R...RTC_BKP19R su L4/G4/U5, o BKPxR su F4 con un periferico BKP separato) sopravvivono al reset di sistema, al wake-up da STANDBY e all'alimentazione solo VBAT. Sono il modo più semplice per rilevare se il software si è avviato per la prima volta dopo una perdita completa di alimentazione:

// All'avvio, controlla un valore magico nel registro di backup 0
if (RTC->BKP0R != 0xDEADBEEF) {
    // Primo avvio dopo perdita completa di alimentazione
    init_rtc_calendar();
    RTC->BKP0R = 0xDEADBEEF;      // segna come inizializzato
    RTC->BKP1R = conteggio_avvii;  // traccia eventi di accensione
} else {
    // RTC funziona da VBAT — non serve reinizializzare
    leggi_contatore_backup();
}

// Salva un evento con timestamp prima dello spegnimento
RTC->BKP2R = codice_evento;
RTC->BKP3R = RTC->TR;
RTC->BKP4R = RTC->DR;

I registri di backup sono anche il modo più semplice per comunicare tra la CPU principale e un firmware updater in esecuzione dalla memoria di sistema, poiché sopravvivono a un reset software.

Rilevamento Tamper con Timestamp

Il periferico tamper RTC monitora fino a 3 pin esterni (TAMP1–TAMP3). Quando rileva un evento tamper (fronte di salita, fronte di discesa o livello basso), può:

  • Cancellare i registri di backup (funzione anti-forense)
  • Catturare il timestamp esatto in RTC_TSTR / RTC_TSDR
  • Generare un interrupt
  • Attivare l'uscita RTC_ALARM su PC13
// Configura TAMP1 su PC13
RTC->TAMPCR |= RTC_TAMPCR_TAMP1E;          // abilita tamper 1
RTC->TAMPCR |= RTC_TAMPCR_TAMP1TRG;        // fronte di discesa
RTC->TAMPCR |= RTC_TAMPCR_TAMPIE;          // abilita interrupt
RTC->TAMPCR |= RTC_TAMPCR_TSIE;            // abilita interrupt timestamp

RTC->TAMPCR |= RTC_TAMPCR_TAMPFLT_0;       // 2 campioni consecutivi

RTC->CR |= RTC_CR_TSE;                     // abilita timestamp
RTC->CR |= RTC_CR_TSIE;                    // interrupt timestamp

void RTC_IRQHandler(void) {
    if (RTC->ISR & RTC_ISR_TAMP1F) {
        uint32_t ora_tamper = RTC->TSTR;
        uint32_t data_tamper = RTC->TSDR;
        RTC->ISR &= ~RTC_ISR_TAMP1F;
    }
    if (RTC->ISR & RTC_ISR_TSF) {
        RTC->ISR &= ~RTC_ISR_TSF;
    }
}

Su STM32L4+/U5, il tamper è migliorato con contatore monotono e tamper attivo — l'RTC guida attivamente un pattern sul pin tamper e verifica la risposta attesa, rilevando cortocircuiti e tagli delle tracce. Disponibile su U575 e L4P5/L4Q5.

Wake-up da STOP/STANDBY con l'RTC

Il wake-up timer RTC è un contatore alla rovescia a 16 bit che conta i cicli di clock RTC (o i suoi derivati prescalati) e genera un evento di wake-up quando raggiunge zero. È il metodo standard per ottenere wake-up periodici in prodotti a batteria.

// Configura wake-up timer per intervallo di 10 secondi
// WUCKSEL = 3 → CK_SPRE (1 Hz)
// Tempo di wake-up = (WUT + 1) * 1 secondo

RTC->ISR |= RTC_ISR_INIT;
while (!(RTC->ISR & RTC_ISR_INITF));

RTC->WUTR = 9999;
RTC->CR = (RTC->CR & ~RTC_CR_WUCKSEL_Msk)
        | (3 << RTC_CR_WUCKSEL_Pos)
        | RTC_CR_WUTE;

RTC->CR |= RTC_CR_WUTIE;

RTC->ISR &= ~RTC_ISR_INIT;

// Entra in STOP mode
PWR->CR1 |= PWR_CR1_LPDS;
PWR->CR1 |= PWR_CR1_PDDS;
SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
__WFI();

Il wake-up timer funziona da LSE o LSI indipendentemente dallo stato del clock di sistema. Funziona anche quando HSI/HSE/PLL è fermo durante STOP. Per STANDBY, il wake-up timer è l'unica opzione basata su RTC (gli allarmi non sono disponibili in STANDBY su F4).

Esempio Pratico: Ciclo di Risveglio ogni 15 Minuti per Nodo IoT

Un pattern comune per nodi IoT a batteria: dormi 15 minuti, leggi sensore, trasmetti dati, dormi di nuovo. Il dominio di backup RTC è l'abilitatore chiave.

#define INTERVALLO_WAKEUP_S  900  // 15 minuti

void entra_ciclo_basso_consumo(void) {
    RTC->BKP2R = ultimo_valore_sensore;
    RTC->BKP3R = RTC->TR;

    RTC->ISR |= RTC_ISR_INIT;
    while (!(RTC->ISR & RTC_ISR_INITF));

    RTC->WUTR = INTERVALLO_WAKEUP_S - 1;
    RTC->CR = (RTC->CR & ~RTC_CR_WUCKSEL_Msk)
            | (3 << RTC_CR_WUCKSEL_Pos)
            | RTC_CR_WUTE
            | RTC_CR_WUTIE;

    RTC->ISR &= ~RTC_ISR_INIT;

    RTC->TAMPCR |= RTC_TAMPCR_TAMP1E
                 | RTC_TAMPCR_TAMP1TRG
                 | RTC_TAMPCR_TAMPIE;

    SCB->SCR |= SCB_SCR_SLEEPDEEP_Msk;
    __WFI();
}

void RTC_WKUP_IRQHandler(void) {
    if (RTC->ISR & RTC_ISR_WUTF) {
        RTC->ISR &= ~RTC_ISR_WUTF;
        EXTI->PR1 |= EXTI_PR1_PR20;
    }
}

Checklist Pratica

CheckPerché
Bit DBP impostato prima di scrivere registri di backup?Tutte le scritture vengono ignorate senza accesso al dominio di backup
LSE stabile prima di selezionare clock RTC?L'RTC potrebbe funzionare alla frequenza sbagliata
Flag RSF controllato prima di leggere il calendario?I registri shadow potrebbero contenere dati obsoleti
Valore magico nel registro di backup all'avvio?Previene la reinizializzazione dell'RTC a ogni reset
Pull sul pin tamper configurato?Un pin tamper flottante causa falsi eventi
WUCKSEL corrisponde all'intervallo desiderato?Prescaler sbagliato = secondi o minuti fuori di un fattore 256
Linea EXTI wake-up abilitata in SYSCFG?L'interrupt RTC wake-up deve passare attraverso EXTI per svegliarsi da STOP
Wake-up STANDBY vs STOP?Gli allarmi non svegliano da STANDBY su F4; solo WUT lo fa
Pin VBAT connesso a batteria o supercap?Senza VBAT, il dominio di backup perde stato quando VDD viene rimosso

Come lo Affronterei su un Progetto Cliente

Su un recente prodotto STM32L4 per sensori ambientali, dovevamo mantenere l'ora UTC accurata per mesi di funzionamento a batteria con la CPU in STOP 2 per il 99.8% del tempo. Il dominio di backup RTC era la spina dorsale:

  • I registri di backup contenevano un contatore di avvii monotono, l'ultimo offset di calibrazione e un seed nonce AES-GCM — tutti sopravvissuti ai reset di sistema.
  • Il wake-up timer ciclava il sistema ogni 15 minuti per lettura sensore + trasmissione LoRa, usando l'uscita LSE calibrata a 1 Hz come WUCKSEL.
  • Il tamper su TAMP1 (connesso a un interruttore reed sull'involucro) cancellava i registri di backup all'apertura del contenitore — soddisfacendo il requisito anti-manomissione per un'applicazione di meter reading.

Il problema che ci costa un giorno: il wake-up timer occasionalmente si attivava 1–2 secondi prima. Causa: l'uscita CK_SPRE deriva dalla cascata di prescaler asincroni, e l'ingresso in RTC_ISR_INIT fermava brevemente i divisori di clock, resettando la fase del prescaler. La soluzione: configurare il wake-up timer senza entrare in init mode quando si cambia solo WUTRWUTR può essere scritto con WUTE = 1 usando RTC_ISR_WUTWF.

Su STM32U5, il dominio di backup guadagna tre importanti miglioramenti: tamper attivo (basato su pattern), contatore monotono (rilevamento rollback) e alimentazione VBAT dedicata per la ritenzione SRAM2. Se il cliente richiede certificazione di sicurezza, le funzionalità del dominio di backup U5 valgono il premium rispetto a L4.

Fonti consultate:

  • STM32F4 Reference Manual (RM0090) — Chapter 14: RTC, Chapter 5: Reset and clock control (RCC)
  • STM32L4 Reference Manual (RM0351) — Chapter 14: RTC, Chapter 6.4: Backup domain
  • STM32G4 Reference Manual (RM0440) — Chapter 16: RTC
  • STM32U5 Reference Manual (RM0456) — Chapter 19: RTC
  • ST Application Note AN4759 — RTC tamper and timestamp configuration
  • ST Application Note AN3371 — Using the STM32 real-time clock
  • CMSIS-Core 5.6.0 — stm32l4xx.h register definitions
  • STMicroelectronics — LSE crystal tuning and RTC calibration (AN2867)