STM32 Risparmio energetico: introduzione al dominio di backup e conservazione delle variabili durante il RESET – 8
Un elemento importante degli STM32 è il dominio di backup, ma dopo una breve introduzione valuteremo e testeremo la soluzione standard per il RESET, praticamente l’uso delle variabili nelle aree di memoria “noinit” e “persistent”, funzionalità molto interessanti. E per un uso specifico, scriveremo alcune semplici funzioni per verificare le caratteristiche dei nostri dispositivi.
Variabili, registro RTC e conservazione SRAM
Una delle cose più utili di cui potresti aver bisogno quando utilizzi le funzioni a basso consumo energetico è la conservazione dello stato, e prima di tutto faremo un veloce riassunto della principale modalità Low-Power.
I dispositivi presentano quattro principali modalità a basso consumo:
- Modalità Sleep
- Solo l’orologio della CPU è fermato.
L’orologio del Cortex-M è fermato e i periferici continuano a funzionare. Il consumo di corrente aumenta con la frequenza dell’orologio. Come in modalità Run, l’utente dovrebbe essere a conoscenza delle regole di configurazione del sistema riguardanti le scale dell’orologio di sistema e del regolatore di tensione.
- Solo l’orologio della CPU è fermato.
- Modalità Stop:
- Il consumo di energia più basso mentre tutta la SRAM e i registri sono conservati.
- Il core Cortex-M è fermato. PLL, HSI, HSE sono disabilitati.
- Tutti i pin I/O mantengono lo stesso stato della modalità Run.
- Tutti gli orologi nel dominio 1.2V sono spenti.
- Il regolatore principale e il regolatore a bassa potenza possono essere in modalità normale o in modalità sottotensione.
- La memoria Flash funziona in modalità Stop o in modalità Deep-power down per risparmiare più potenza statica.
- Modalità Standby:
- Questa modalità ha il consumo di corrente più basso.
- Il core Cortex-M è fermato e gli orologi sono spenti.
- Il dominio 1.2V è spento (il regolatore è disabilitato).
- I contenuti della SRAM e dei registri vengono persi tranne per i registri nel dominio di backup (registri RTC, registro di backup RTC e SRAM di backup) e circuiti di standby.
- Tutti i pin I/O sono ad alta impedenza tranne per:
- Pad di reset
- PC13 se configurato per tamper, timestamp, allarme RTC out, o calibrazione dell’orologio RTC
- Pin WKUP (PA0/PA2/PC1/PC13/PI8/PI11), se abilitati
- Questa modalità viene utilizzata solo quando l’alimentazione digitale principale (VDD) è spenta.
- Il circuito è alimentato attraverso il pin VBAT che dovrebbe essere collegato a una tensione di alimentazione esterna (una batteria o qualsiasi altra fonte).
- Il pin VBAT alimenta il dominio di backup (registri RTC, registro di backup RTC e SRAM di backup)
Nome modalità |
Ingresso |
Risveglio |
Effetto sugli orologi del dominio VCORE |
Effetto sugli orologi del dominio VDD |
Regolatore di tensione |
Funzionamento a basso consumo |
Bit LPSDSR e LPRUN + Impostazione orologio |
Il regolatore è forzato nel regolatore principale (1,8 V) |
Nessuno |
Nessuno |
In modalità a basso consumo |
Sleep (Sleep immediato o Sleep-all’uscita) |
WFI |
Qualsiasi interruzione |
CPU CLK OFF nessun effetto sugli altri orologi o sorgenti di orologio analogiche |
Nessuno |
ON |
WFE |
Evento di risveglio |
||||
Low-power sleep (Sleep immediato o Sleep-all’uscita) |
Bit LPSDSR + WFI |
Qualsiasi interruzione |
CPU CLK OFF nessun effetto sugli altri orologi o sorgenti di orologio analogiche, Flash CLK OFF |
Nessuno |
In modalità a basso consumo |
Bit LPSDSR + WFE |
Evento di risveglio |
||||
Stop |
Bit PDDS, LPSDSR + bit SLEEPDEEP + WFI o WFE |
Qualsiasi linea EXTI (configurata nei registri EXTI, linee interne ed esterne) |
Tutti gli orologi del dominio VCORE OFF |
Oscillatori HSI, HSE e MSI OFF |
In modalità a basso consumo |
Standby |
Bit PDDS + bit SLEEPDEEP + WFI o WFE |
Rising edge del pin WKUP, allarme RTC (Allarme A o Allarme B), evento di risveglio RTC, evento tamper RTC, evento timestamp RTC, reset esterno nel pin NRST, reset IWDG |
OFF |
Per le modalità Sleep e Stop (Idle e Sleep) la ritenzione è abbastanza semplice, ma se si desidera utilizzare la modalità Standby (spegnimento) per salvare i dati, bisogna utilizzare il registro RTC e la memoria SRAM.
In questo scenario, è necessario comprendere come alcune parti interagiscono con il sistema:
Regolatore di Tensione
Il regolatore di tensione è sempre abilitato dopo il Reset e funziona in tre diverse modalità a seconda delle modalità dell’applicazione:
- Modalità Run: il regolatore fornisce alimentazione completa al dominio 1,8 V (core, memorie e periferiche digitali)
- Modalità Stop: il regolatore fornisce bassa potenza al dominio 1,8 V, preservando il contenuto dei registri e della SRAM
- Modalità Standby: il regolatore è spento. Il contenuto dei registri e della SRAM viene perso tranne per i circuiti di Standby e il Dominio di Backup
Dominio di Backup della Batteria
Per conservare il contenuto dei registri di backup e alimentare la funzione RTC quando VDD è spento, il pin VBAT può essere collegato a una tensione di standby opzionale fornita da una batteria o da un’altra fonte.
Il pin VBAT alimenta l’unità RTC, l’oscillatore LSE e gli IO PC13 a PC15, permettendo al RTC di funzionare anche quando l’alimentazione digitale principale (VDD) è spenta.
Il passaggio all’alimentazione VBAT è controllato dal Reset di Spegnimento incorporato nel blocco di Reset
Registri di Backup (BKP)
- I registri di backup sono dieci registri da 16-bit nei dispositivi di bassa e media densità per immagazzinare 20 byte di dati dell’applicazione utente
- Sono implementati nel dominio di backup che rimane alimentato da VBAT quando l’alimentazione VDD è spenta.
- Non vengono resettati quando il dispositivo si risveglia dalla modalità Standby o da un reset di sistema o reset di alimentazione
- Inoltre, i registri di controllo BKP sono utilizzati per gestire la funzione di rilevamento del Tamper e la calibrazione dell’RTC.
- Dopo il reset, l’accesso ai registri di backup e all’RTC è disabilitato e il dominio di backup (BKP) è protetto contro possibili accessi in scrittura parassiti
- Per abilitare l’accesso ai registri di backup e all’RTC, procedere come segue:
- Abilitare gli orologi dell’interfaccia di alimentazione e di backup impostando i bit PWREN e BKPEN nel registro RCC_APB1ENR
- Impostare il bit DBP nel Registro di Controllo dell’Alimentazione (PWR_CR) per abilitare l’accesso ai registri di backup e all’RTC.
E può essere utile comprendere i diversi sistemi di reset:
Reset di Sistema
- Un reset di sistema imposta tutti i registri ai loro valori di reset ad eccezione dei flag di reset nel registro CSR del controller dell’orologio e dei registri nel Dominio di Backup
- Un reset di sistema viene generato quando si verifica uno dei seguenti eventi:
- Livello basso sul pin NRST (reset esterno)
- Condizione di fine conteggio del watchdog a finestra (reset WWDG)
- Condizione di fine conteggio del watchdog indipendente (reset IWDG)
- Reset software (reset SW)
- Reset della gestione dell’energia
- Reset software
- Il bit SYSRESETREQ nel Registro di Controllo Interrupt e Reset dell’Applicazione Cortex™-M3 deve essere impostato per forzare un reset software sul dispositivo
- Reset della gestione dell’energia a bassa potenza:
- Metodo 1: Reset generato quando si entra in modalità Standby: Questo tipo di reset viene abilitato resettando il bit nRST_STDBY nei Byte Opzione Utente. In questo caso, ogni volta che viene eseguita con successo una sequenza di ingresso in modalità Standby, il dispositivo viene resettato invece di entrare in modalità Standby.
- Metodo 2: Reset quando si entra in modalità Stop: Questo tipo di reset è abilitato resettando il bit NRST_STOP nei Byte Opzione Utente. In questo caso, ogni volta che viene eseguita con successo una sequenza di ingresso in modalità Stop, il dispositivo viene resettato invece di entrare in modalità Stop.
Reset di Alimentazione
- Un reset di alimentazione viene generato quando si verifica uno dei seguenti eventi:
- Reset di accensione/spegnimento (reset POR/PDR)
- All’uscita dalla modalità Standby
- Un reset di alimentazione imposta tutti i registri ai loro valori di reset ad eccezione del Dominio di Backup
- Queste fonti agiscono sul pin NRST ed è sempre mantenuto basso durante la fase di ritardo. Il
- Il vettore di RESET è fisso all’indirizzo 0x00000004 nella mappa di memoria
Reset del Dominio di Backup
- Il dominio di backup ha due specifici reset che influenzano solo il dominio di backup
- Un reset del dominio di backup viene generato quando si verifica uno dei seguenti eventi:
- Reset software, innescato impostando il bit BDRST nel registro di controllo del dominio di backup (RCC_BDCR)
- VDD o VBAT accesi, se entrambi sono stati precedentemente spenti
Ora possiamo iniziare a fare alcuni test.
Identificare il tipo di reset
Quindi, ci sono alcuni tipi di reset e per il nostro test può essere utile capire come riconoscerli. Uso lo sketch di basso consumo energetico (consulta l’articolo relativo se non capisci alcune parti) e aggiungo 2 funzioni che identificano la fonte del reset e quali orologi sono pronti.
/**
* I add to a simple sketch
* that set the time to 2022-04-20 at 16:00:00 and an alarm at 16:00:10 wake-up after 10 secs
* 2 function that identify the reset source and witch clocks are ready
*
* Renzo Mischianti <www.mischianti.org>
* en: https://mischianti.org/category/tutorial/stm32-tutorial/
* it: https://mischianti.org/it/category/guide/guida-alla-linea-di-microcontrollori-stm32/
*/
#include "STM32LowPower.h"
#include <STM32RTC.h>
// Pin used to trigger a wakeup
#ifndef USER_BTN
#define USER_BTN SYS_WKUP1
#endif
const int pin = USER_BTN;
/* Get the rtc object */
STM32RTC& rtc = STM32RTC::getInstance();
/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 16;
/* Change these values to set the current initial date */
const byte day = 20;
const byte month = 4;
const byte year = 22;
void wakedUp();
void alarmMatch(void *data);
void printWakeSource();
void printClockReady();
void setup()
{
Serial.begin(115200);
pinMode(pin, INPUT_PULLUP);
printWakeSource();
printClockReady();
__HAL_RCC_CLEAR_RESET_FLAGS();
// Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK.
// By default the LSI is selected as source.
// rtc.setClockSource(STM32RTC::LSI_CLOCK);
rtc.begin(); // initialize RTC 24H format
// we set the time at 2022-04-20 at 16:00:00
rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);
delay(1000);
String someRandomData = "www.mischianti.org";
// Configure low power
LowPower.begin();
// Attach a wakeup interrupt on pin, calling repetitionsIncrease when the device is woken up
// Last parameter (LowPowerMode) should match with the low power state used: in this example LowPower.sleep()
// LowPower.attachInterruptWakeup(pin, wakedUp, RISING, SHUTDOWN_MODE);
LowPower.enableWakeupFrom(&rtc, alarmMatch, &someRandomData);
// Now we set an alert at 16:00:10
// pratically 10 secs after the start
// (check the initialization of clock)
rtc.setAlarmDay(day);
rtc.setAlarmTime(16, 0, 10, 0);
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
// Print date...
Serial.printf("Now is %02d/%02d/%02d %02d:%02d:%02d.%03d and we set the wake at 16:10! So wait 10secs! \n",
rtc.getDay(), rtc.getMonth(), rtc.getYear(),
rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds());
delay(1000);
LowPower.shutdown();
}
void loop()
{
// Print date...
Serial.printf("%02d/%02d/%02d ", rtc.getDay(), rtc.getMonth(), rtc.getYear());
// ...and time
Serial.printf("%02d:%02d:%02d.%03d\n", rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds());
delay(1000);
}
void alarmMatch(void *data)
{
String myData = *(String*)data;
Serial.println("Alarm Match!");
Serial.println(myData);
}
void wakedUp() {
// This function will be called once on device wakeup
// You can do some little operations here (like changing variables which will be used in the loop)
// Remember to avoid calling delay() and long running functions since this functions executes in interrupt context
Serial.println("Wake UP pin!");
}
void printClockReady() {
Serial.println(F("--------- CLOCK Ready -------------"));
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSIRDY)) {
Serial.println(F("HSI oscillator clock ready."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_HSERDY)) {
Serial.println(F("HSE oscillator clock ready."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLRDY)) {
Serial.println(F("Main PLL clock ready."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PLLI2SRDY)) {
Serial.println(F("PLLI2S clock ready."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSERDY)) {
Serial.println(F("LSE oscillator clock ready."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LSIRDY)) {
Serial.println(F("LSI oscillator clock ready."));
}
Serial.println(F("-----------------------------------"));
}
void printWakeSource() {
Serial.println(F("--------- RESET Source ----------"));
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
Serial.println(F("Wake from POR/PDR or BOR reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) {
Serial.println(F("Wake from Pin reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) {
Serial.println(F("Wake from POR/PDR reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) {
Serial.println(F("Wake from Software reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
Serial.println(F("Wake from Independent Watchdog reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) {
Serial.println(F("Wake from Window Watchdog reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) {
Serial.println(F("Wake from Low Power reset."));
}
Serial.println(F("-----------------------------------"));
}
Consiglio di effettuare questo cablaggio in modo da poter collegare il monitor seriale all’FTDI e ricevere tutti i messaggi Seriali.
Ecco lo STM32 e ST-Link V2 usati in questo test STM32F103C8T6 STM32F401 STM32F411 ST-Link v2 ST-Link v2 official
Ecco l'FTDI USB to TTL CH340G - USB to TTL FT232RL
Ecco il mio multimetro Aneng SZ18
Reset software
Ora, quando carichi il codice, ottieni questa uscita:
--------- RESET Source ----------
Wake from Pin reset.
Wake from Software reset.
-----------------------------------
--------- CLOCK Ready -------------
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
-----------------------------------
Now is 20/04/22 16:00:00.944 and we set the wake at 16:10! So wait 10secs!
Interrupt di risveglio
Quando il dispositivo viene risvegliato dallo spegnimento, ottieni:
--------- RESET Source ----------
-----------------------------------
--------- CLOCK Ready -------------
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
LSI oscillator clock ready.
-----------------------------------
Now is 20/04/22 16:00:00.944 and we set the wake at 16:10! So wait 10secs!
Quindi nessuna informazione a riguardo.
Pulsante RESET
Se fai clic sul pulsante RESET (pin di reset), ottieni questo risultato.
--------- RESET Source ----------
Wake from Pin reset.
-----------------------------------
--------- CLOCK Ready -------------
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
-----------------------------------
Now is 20/04/22 16:00:00.940 and we set the wake at 16:10! So wait 10secs!
In questo caso, usa un pin di reset ma non attivato tramite software come nella situazione precedente (quando si carica il codice).
Scollegare dall’alimentazione
Ora l’ultimo test interessante è rimuovere il dispositivo dall’alimentazione, il risultato è questo.
--------- RESET Source ----------
Wake from POR/PDR or BOR reset.
Wake from Pin reset.
Wake from POR/PDR reset.
-----------------------------------
--------- CLOCK Ready -------------
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
-----------------------------------
Now is 20/04/22 16:00:00.944 and we set the wake at 16:10! So wait 10secs!
Preservare il valore delle variabili attraverso il RESET
Prima di iniziare ad analizzare il registro RTC e la SRAM, vorrei mostrare alcuni sistemi per preservare i valori attraverso il RESET.
Possiamo usare l’attributo __attribute__((__section__(".noinit")));
e __attribute__((__section__(".persistent")));
Questo semplice attributo sposta la posizione di archiviazione della variabile in una sezione “noinit” e “persistent”.
Ma puoi capire il comportamento con questo semplice sketch:
/**
* A simple sketch to evaluate noinit and persistent variable pragma
*
* Renzo Mischianti <www.mischianti.org>
* https://mischianti.org
*
*/
unsigned boot_count __attribute__((__section__(".noinit")));
unsigned boot_count_persistent __attribute__((section(".persistent")));
void setup()
{
Serial.begin(115200);
delay(1000);
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
boot_count = 0;
boot_count_persistent = 0;
Serial.println("START: First boot!");
} else {
Serial.println("START!");
}
__HAL_RCC_CLEAR_RESET_FLAGS();
Serial.print("Boot number: ");
Serial.println(boot_count);
boot_count = boot_count + 1;
Serial.print("Boot number persistent: ");
Serial.println(boot_count_persistent);
boot_count_persistent = boot_count_persistent + 1;
}
void loop()
{
delay(1000);
}
Here It’s the serial output:
START!
Boot number: 4122089554
Boot number persistent: 587262422
START: First boot!
Boot number: 0
Boot number persistent: 0
START!
Boot number: 1
Boot number persistent: 1
START!
Boot number: 2
Boot number persistent: 2
START!
Boot number: 3
Boot number persistent: 3
START!
Boot number: 4
Boot number persistent: 4
Alla prima avviata, carica il valore in memoria delle variabili inizializzate, alla riga 4 scollego l’alimentazione e quando la riconnetto intercetto il primo avvio e resetto il valore della variabile.
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
boot_count = 0;
boot_count_persistent = 0;
Serial.println("START: First boot!");
} else {
Serial.println("START!");
}
Ora, ogni volta che clicco sul reset (quando viene stampata la stringa START!
), il codice mi mostra il valore corrente della variabile.
Ma cosa succede se provo a utilizzare questo sistema con uno spegnimento?
/**
* A simple sketch that set the time to
* 2022-04-20 at 16:00:00
* and an alarm at
* 16:00:20
* the result is the interrupt after 10 secs
*
* I initialize the variables in noinit and persistent area, if
* you click the reset button the values are persisted but on shutdown/standby
* the values are losts
*
* Renzo Mischianti <www.mischianti.org>
* https://mischianti.org
*
*/
unsigned boot_count __attribute__((__section__(".noinit")));
unsigned boot_count_persistent __attribute__((section(".persistent")));
#include "STM32LowPower.h"
#include <STM32RTC.h>
/* Get the rtc object */
STM32RTC& rtc = STM32RTC::getInstance();
/* Change these values to set the current initial time */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 16;
/* Change these values to set the current initial date */
const byte day = 20;
const byte month = 4;
const byte year = 22;
void alarmMatch(void *data);
void printWakeSource();
void setup()
{
Serial.begin(115200);
printWakeSource();
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
boot_count = 0;
boot_count_persistent = 0;
}
__HAL_RCC_CLEAR_RESET_FLAGS();
// Select RTC clock source: LSI_CLOCK, LSE_CLOCK or HSE_CLOCK.
// By default the LSI is selected as source.
// rtc.setClockSource(STM32RTC::LSI_CLOCK);
rtc.begin(); // initialize RTC 24H format
// we set the time at 2022-04-20 at 16:00:00
rtc.setTime(hours, minutes, seconds);
rtc.setDate(day, month, year);
delay(1000);
String someRandomData = "www.mischianti.org";
// Configure low power
LowPower.begin();
LowPower.enableWakeupFrom(&rtc, alarmMatch, &someRandomData);
int wakeSeconds = rtc.getSeconds()+20;
// Now we set an alert at 16:00:10
// pratically 10 secs after the start
// (check the initialization of clock)
rtc.setAlarmDay(day);
rtc.setAlarmTime(16, 0, wakeSeconds, 0);
rtc.enableAlarm(rtc.MATCH_DHHMMSS);
Serial.print("Boot number: ");
Serial.println(boot_count);
boot_count = boot_count + 1;
Serial.print("Boot number persistent: ");
Serial.println(boot_count_persistent);
boot_count_persistent = boot_count_persistent + 1;
Serial.println("Start shutdown mode in ");
for (int i = 10;i>0;i--) { Serial.print(i); Serial.print(" "); delay(1000); } Serial.println( "OK!" );
// Print date...
Serial.printf("Now is %02d/%02d/%02d %02d:%02d:%02d.%03d and we set the wake at 16:%02d! So wait 10secs! \n",
rtc.getDay(), rtc.getMonth(), rtc.getYear(),
rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds(), wakeSeconds);
delay(1000);
LowPower.shutdown();
}
void loop()
{
// Print date...
Serial.printf("%02d/%02d/%02d ", rtc.getDay(), rtc.getMonth(), rtc.getYear());
// ...and time
Serial.printf("%02d:%02d:%02d.%03d\n", rtc.getHours(), rtc.getMinutes(), rtc.getSeconds(), rtc.getSubSeconds());
delay(1000);
}
void alarmMatch(void *data)
{
String myData = *(String*)data;
Serial.println("Alarm Match!");
Serial.println(myData);
}
void printWakeSource() {
Serial.println(F("-----------------------------------"));
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
Serial.println(F("Wake from POR/PDR or BOR reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PINRST)) {
Serial.println(F("Wake from Pin reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)) {
Serial.println(F("Wake from POR/PDR reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_SFTRST)) {
Serial.println(F("Wake from Software reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_IWDGRST)) {
Serial.println(F("Wake from Independent Watchdog reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_WWDGRST)) {
Serial.println(F("Wake from Window Watchdog reset."));
}
if (__HAL_RCC_GET_FLAG(RCC_FLAG_LPWRRST)) {
Serial.println(F("Wake from Low Power reset."));
}
Serial.println(F("-----------------------------------"));
}
Il risultato si trova in questa uscita seriale:
-----------------------------------
Wake from POR/PDR or BOR reset.
Wake from Pin reset.
Wake from POR/PDR reset.
-----------------------------------
Boot number: 0
Boot number persistent: 0
Start shutdown mode in
10 9 8 -----------------------------------
Wake from Pin reset.
-----------------------------------
Boot number: 1
Boot number persistent: 1
Start shutdown mode in
10 9 8 7 6 5 4 3 2 1 OK!
Now is 20/04/22 16:00:10.396 and we set the wake at 16:20! So wait 10secs!
-----------------------------------
-----------------------------------
Boot number: 3475117321
Boot number persistent: 1065079675
Start shutdown mode in
10 9 8 7 6
Puoi vedere che la prima volta premo il pulsante di reset e poi aspetto lo spegnimento. Lo spegnimento spegne e interrompe tutte le aree non di backup, quindi perdi il valore della variabile.
Grazie
- STM32F1 Blue Pill: piedinatura, specifiche e configurazione IDE Arduino (STM32duino e STMicroelectronics)
- STM32: programmazione (STM32F1) via USB con bootloader STM32duino
- STM32: programmazione (STM32F1 STM32F4) tramite USB con bootloader HID
- STM32F4 Black Pill: pinout, specifiche e configurazione IDE Arduino
- STM32: ethernet w5500 standard (HTTP) e SSL (HTTPS)
- STM32: ethernet enc28j60 standard (HTTP) e SSL (HTTPS)
- STM32: WiFiNINA con un ESP32 come WiFi Co-Processor
- Come utilizzare la scheda SD con l’stm32 e la libreria SdFat
- STM32: memoria flash SPI FAT FS
- STM32: RTC interno, sistema orario e backup batteria (VBAT)
- STM32 LoRa
- STM32 Risparmio energetico
- STM32F1 Blue-Pill gestione clock e frequenza
- STM32F4 Black-Pill gestione clock e frequenza
- Introduzione e framework Arduino vs STM
- Libreria LowPower, cablaggio e Idle (STM Sleep).
- Sleep, deep sleep, shutdown e consumo energetico
- Sveglia da allarme RTC e Seriale
- Sveglia da sorgente esterna
- Introduzione al dominio di backup e conservazione delle variabili durante il RESET
- Registro di backup RTC e conservazione della SRAM
- STM32 invia email con allegati e SSL (come Gmail): w5500, enc28j60, SD e SPI Flash
- Server FTP su STM32 con W5500, ENC28J60, scheda SD e memoria flash SPI
- Collegamento dell’EByte E70 ai dispositivi STM32 (black/blue pill) e un semplice sketch di esempio