STM32 Risparmio energetico: registro di backup RTC e conservazione della SRAM – 9
Infine, esaminiamo il dominio di backup per risolvere il problema della conservazione dello stato attraverso le modalità di sospensione, prima il registro di backup RTC e poi il backup della memoria SRAM.
Verifica quale tipo di backup è disponibile su STM32
Per conservare lo stato in spegnimento/standby puoi utilizzare (come descritto nell’introduzione) il registro RTC/TAMP o la SRAM.
Ecco lo STM32 e ST-Link V2 utilizzati in questo test STM32F103C8T6 STM32F401 STM32F411 ST-Link v2 ST-Link v2 official
Qui l'FTDI USB to TTL CH340G - USB to TTL FT232RL
Ecco il mio multimetro Aneng SZ18
Ecco un semplice sketch per verificare il tuo STM32.
/**
* A simple sketch to check witch kind of backup you can use
* on your device
*
* 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"
void printBackupRegisterType();
void printSRAMAvailability();
void setup()
{
Serial.begin(115200);
delay(1000);
Serial.println(F("------------------------------------------------"));
printBackupRegisterType();
printSRAMAvailability();
Serial.println(F("------------------------------------------------"));
}
void loop()
{
delay(1000);
}
void printBackupRegisterType() {
#if defined(BKP_BASE)
Serial.println(F("Backup base enabled!"));
#elif defined(RTC_BKP0R)
Serial.println(F("Backup RTC enabled!"));
#elif defined(TAMP_BKP0R)
#if defined(STM32G4xx) || defined(STM32L5xx) || defined(STM32U5xx) ||\
defined(STM32MP1xx) || defined(STM32WLxx)
/* For those series this API requires RTC even if it is not used
and TAMP is used instead */
Serial.println(F("Backup RTC and TAMP enabled! TAMP busy use RTC!"));
#else
Serial.println(F("Backup RTC and TAMP enabled! Use TAMP!"));
#endif
#else
Serial.println(F("Backup not available!"));
#endif
}
void printSRAMAvailability() {
#if defined(BKPSRAM_BASE)
Serial.println(F("SRAM available!"));
#else
Serial.println(F("SRAM not available!"));
#endif
}
Nel mio caso con un STM32F401 ottengo questo risultato :(.
------------------------------------------------
Backup RTC enabled!
SRAM not available!
------------------------------------------------
Quindi posso usare solo il registro RTC, ma provo a darti un esempio SRAM.
Utilizzo di un registro di backup per preservare i dati durante lo spegnimento/standby
Ora aggiungeremo i dati nella struttura dati sotto l’area di backup. Come descritto è possibile utilizzare (se presente) RTC Backup Register o SRAM; controlla il paragrafo con lo schizzo per verificare quale ha il tuo microcontrollore.
/**
* A simple sketch that set the time to
* 2022-04-20 at 16:00:00 and an alarm at 16:00:10
* the result is the interrupt after 10 secs
* We use RTC backup register to preserve state of a variable
* across the shutdown and count the restart
* The valiable is resetted every time you disconnect the power.
*
* Renzo Mischianti <www.mischianti.org>
* https://mischianti.org
*
*/
#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 printBackupRegisterType();
void printClockReady();
void setup()
{
Serial.begin(115200);
Serial.println(F("------------------------------------------------"));
printWakeSource();
printBackupRegisterType();
printClockReady();
Serial.println(F("------------------------------------------------"));
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
enableBackupDomain();
resetBackupDomain();
setBackupRegister(LL_RTC_BKP_DR0, 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 RTC backup register: ");
// uint32_t boot_count_RTC_back = rtc_read_backup_reg(RTC_BKP_DR1);
uint32_t boot_count_RTC_back = getBackupRegister(LL_RTC_BKP_DR0);
Serial.println(boot_count_RTC_back);
boot_count_RTC_back = boot_count_RTC_back + 1;
// rtc_write_backup_reg(RTC_BKP_DR1, boot_count_RTC_back);
setBackupRegister(LL_RTC_BKP_DR0, boot_count_RTC_back);
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: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 printClockReady() {
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."));
}
}
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("-----------------------------------"));
}
void printBackupRegisterType() {
#if defined(BKP_BASE)
Serial.println(F("Backup base enabled!"));
#elif defined(RTC_BKP0R)
Serial.println(F("Backup RTC enabled!"));
#elif defined(TAMP_BKP0R)
#if defined(STM32G4xx) || defined(STM32L5xx) || defined(STM32U5xx) ||\
defined(STM32MP1xx) || defined(STM32WLxx)
/* For those series this API requires RTC even if it is not used
and TAMP is used instead */
Serial.println(F("Backup RTC and TAMP enabled! TAMP busy use RTC!"));
#else
Serial.println(F("Backup RTC and TAMP enabled! Use TAMP!"));
#endif
#else
Serial.println(F("Backup not available!"));
#endif
}
Puoi vedere che ripristiniamo la variabile ogni volta che scolleghiamo il dispositivo dall’alimentazione.
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
enableBackupDomain();
resetBackupDomain();
setBackupRegister(LL_RTC_BKP_DR0, 0);
}
__HAL_RCC_CLEAR_RESET_FLAGS();
Quando il dispositivo viene ricollegato all’alimentazione (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)
) abilitiamo il backup (enableBackupDomain();
puoi usarlo disableBackupDomain();
per disabilitarlo) e inizializziamo la variabile a 0 (setBackupRegister(LL_RTC_BKP_DR0, 0);
).
Quindi leggiamo i dati dal registro, stampiamo i dati, aggiungiamo uno alla variabile e lo impostiamo nel registro.
Serial.print("Boot number RTC backup register: ");
// uint32_t boot_count_RTC_back = rtc_read_backup_reg(RTC_BKP_DR1);
uint32_t boot_count_RTC_back = getBackupRegister(LL_RTC_BKP_DR0);
Serial.println(boot_count_RTC_back);
boot_count_RTC_back = boot_count_RTC_back + 1;
// rtc_write_backup_reg(RTC_BKP_DR1, boot_count_RTC_back);
setBackupRegister(LL_RTC_BKP_DR0, boot_count_RTC_back);
Per ottenere il valore dal registro utilizziamo uint32_t boot_count_RTC_back = getBackupRegister(LL_RTC_BKP_DR0);
.
L’uscita seriale dopo la prima interruzione dell’alimentazione è:
------------------------------------------------
-----------------------------------
Wake from POR/PDR or BOR reset.
Wake from Pin reset.
Wake from POR/PDR reset.
-----------------------------------
Backup RTC enabled!
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
------------------------------------------------
Boot number RTC backup register: 0
Start shutdown mode in
10 9 8 7 6 5 4 3 2 1 OK!
Now is 20/04/22 16:00:10.408 and we set the wake at 16:10! So wait 10secs!
------------------------------------------------
-----------------------------------
-----------------------------------
Backup RTC enabled!
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
LSI oscillator clock ready.
------------------------------------------------
Boot number RTC backup register: 1
Start shutdown mode in
10 9 8 7 6 5 4 3 2 1 OK!
Now is 20/04/22 16:00:10.404 and we set the wake at 16:10! So wait 10secs!
------------------------------------------------
-----------------------------------
-----------------------------------
Backup RTC enabled!
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
LSI oscillator clock ready.
------------------------------------------------
Boot number RTC backup register: 2
Start shutdown mode in
10 9 8 7 6 5 4 3 2 1 OK!
Now is 20/04/22 16:00:10.388 and we set the wake at 16:10! So wait 10secs!
------------------------------------------------
-----------------------------------
-----------------------------------
Backup RTC enabled!
HSI oscillator clock ready.
HSE oscillator clock ready.
Main PLL clock ready.
LSI oscillator clock ready.
------------------------------------------------
Boot number RTC backup register: 3
Start shutdown mode in
10 9 8 7 6 5 4 3 2 1 OK!
Now is 20/04/22 16:00:10.400 and we set the wake at 16:10! So wait 10secs!
Utilizzo della memoria SRAM per preservare i dati durante lo spegnimento/standby
Come già descritto non ho un dispositivo che supporti SRAM, quindi provo a fare un esempio solo con documentazione senza test.
/**
* A simple sketch that set the time to
* 2022-04-20 at 16:00:00 and an alarm at 16:00:10
* the result is the interrupt after 10 secs
* We use SRAM to preserve state of a structure
* across the shutdown and count the restart
* The structure is resetted every time you disconnect the power.
*
* Renzo Mischianti <www.mischianti.org>
* https://mischianti.org
*
*/
#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 printSRAMAvailability();
typedef struct Info
{
char url[19]; // Change
int deviceID;
int count;
};
void setup()
{
Serial.begin(115200);
Serial.println(F("------------------------------------------------"));
printWakeSource();
printSRAMAvailability();
Serial.println(F("------------------------------------------------"));
// Initialize the variable only on first power-on reset
if (__HAL_RCC_GET_FLAG(RCC_FLAG_BORRST)) {
enableBackupDomain();
resetBackupDomain();
struct Info info = {"www.mischianti.org", 1, 0};
writeBackupSRAM(0, (uint32_t*)&info, sizeof(info));
}
__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 SRAM: ");
struct Info info;
readBackupSRAM(0, (uint32_t*)&info, sizeof(info));
Serial.println(info.count);
info.count = info.count + 1;
writeBackupSRAM(0, (uint32_t*)&info, sizeof(info));
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: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 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("-----------------------------------"));
}
void printSRAMAvailability() {
#if defined(BKPSRAM_BASE)
Serial.println(F("SRAM available!"));
#else
Serial.println(F("SRAM not available!"));
#endif
}
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