STM32 Risparmio energetico: sveglia da sorgente esterna – 7


Dopo il risveglio temporizzato, l’allarme e il risveglio seriale, quello più utilizzato è il risveglio tramite una fonte esterna. In questo caso, dobbiamo prestare attenzione al pinout del nostro dispositivo per selezionare il pin corretto nella situazione corretta.

Risparmio energetico STM32: risveglio da fonte esterna
Risparmio energetico STM32: risveglio da fonte esterna

Una delle situazioni più comuni è il risveglio da una fonte esterna. In questo caso, configuriamo un pulsante.

STM32 STM32F411 STM32F411CEU6 pinout a bassa risoluzione
STM32 STM32F411 STM32F411CEU6 pinout a bassa risoluzione

Per il primo test, configuriamo il pin PB12 come ingresso INPUT_PULLUP con un semplice pulsante con una resistenza di pull-up, quindi funziona al rilascio del pulsante (interruzione RAISING).

Controllore di interruzione esterna STM32 (risveglio da deep-sleep)

Ogni IO dell’STM32 può essere utilizzato come ingresso di interruzione esterna. EXTI (Controller di interruzione/evento esterno) gestisce 20 linee di interruzione/evento del controller. Ogni linea di interruzione/evento corrisponde a un rilevatore di edge, che può rilevare il rising edge e falling edge del segnale in ingresso. EXTI può configurare ogni linea di interruzione/evento separatamente, come un’interruzione o un evento, e gli attributi dell’evento di trigger.

Linea di interruzione esterna

Pinout STM32 STM32F1 STM32F103 STM32F103C8 bassa risoluzione
Pinout STM32 STM32F1 STM32F103 STM32F103C8 bassa risoluzione

Il controller di interruzione dell’STM32 supporta 19 interruzioni esterne e richieste di eventi (cioè, 19 linee di interruzione esterna). Ogni interruzione è dotata di bit di stato, e ogni interruzione/evento ha impostazioni di trigger e maschera indipendenti. Le 19 interruzioni esterne di STM32 corrispondono a 19 linee di interruzione medie:

  • Linea 0~15: interruzione di ingresso corrispondente alla porta IO esterna;
  • Linea 16: collegata all’uscita PVD;
  • Linea 17: collegata all’evento dell’orologio di allarme RTC;
  • Linea 18: collegata all’evento di risveglio USB.

Caratteristiche del Controller EXTI

Le principali caratteristiche del controller EXTI sono le seguenti:

  • Trigger e maschera indipendenti su ogni linea di interruzione/evento
  • Bit di stato dedicato per ogni linea di interruzione
  • Generazione di fino a 20 richieste di evento/interruzione software
  • Rilevazione del segnale esterno con larghezza di impulso inferiore al periodo dell’orologio APB2.

Diagramma a blocchi EXTI

STM32: Diagramma a blocchi EXTI
STM32: Diagramma a blocchi EXTI

Cablaggio del pin di risveglio

Qui 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


Qui il mio multimetro Aneng SZ18

STM32F1 Blue-pill: pin di risveglio con pulsante dalla modalità sleep
STM32F1 Blue-pill: pin di risveglio con pulsante dalla modalità sleep

Risveglio da Deep Sleep

Ora un semplice sketch:

/**
 *	External wake up
 *
 *	In this sketch we put the STM32 on Deep Sleep than wake up It via
 *	a button.
 *	If present we use on board PB12 button, not suitable for shutdown
 *
 *	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"

volatile int wakeUpCount = 1;

const int pin = PB12;

void wakedUp();

void setup() {
  Serial.begin(115200);

  pinMode(pin, INPUT_PULLUP);

  // 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, DEEP_SLEEP_MODE);

  Serial.println("Start low-power mode!");
  delay(1000);

  LowPower.deepSleep();

  delay(1000);
  Serial.print("Exit low-power mode! ");
  Serial.println(wakeUpCount);
}

void loop() {
	delay(100);
}

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("Waked!");

	wakeUpCount ++;
}

L’output seriale è:

Start low-power mode!
Waked!
Exit low-power mode! 2

Dove la parte evidenziata è prima del rilascio del tasto del pulsante.

È necessario prestare attenzione al parametro della funzione attachInterruptWakeup.

  LowPower.attachInterruptWakeup(pin, wakedUp, RISING, DEEP_SLEEP_MODE);

È importante impostare l’ultimo parametro con la corrente modalità LowPower selezionata, i valori possibili sono:

enum LP_Mode : uint8_t {
  IDLE_MODE,
  SLEEP_MODE,
  DEEP_SLEEP_MODE,
  SHUTDOWN_MODE
};

Presta attenzione, se usi un STM32F4 Black-Pill il pulsante edge non ha la resistenza di pull-up.

Se vuoi, puoi sostituire LowPower.deepSleep(); con le altre modalità LowPower.

  • LowPower.idle();
  • LowPower.sleep();
  • LowPower.shutdown();

Risveglio da Shutdown/Standby

Pinout STM32 STM32F1 STM32F103 STM32F103C8 bassa risoluzione
Pinout STM32 STM32F1 STM32F103 STM32F103C8 bassa risoluzione

Se provi ad utilizzare il codice sopra con lo shutdown otterrai una brutta sorpresa, Non si sveglia. Per lo shutdown (o Standby) non puoi utilizzare il pin standard, devi utilizzare il pin di wake-up.

STM32F1 Blue-Pill: pin di risveglio con pulsante per standby/shutdown
STM32F1 Blue-Pill: pin di risveglio con pulsante per standby/shutdown

Per STM32F1 e STM32F4 è PA0, ma puoi farvi riferimento con SYS_WKUP1. Stiamo per fare alcune modifiche allo sketch per eseguire lo stesso controllo e fix.

/**
 *	External wake up
 *
 *	In this sketch we put the STM32 on shutdown than wake up It via
 *	a button.
 *	If present we use on board PA0 button (add pull-up), else set the primary
 *	System Wake Up button.
 *
 *	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;

void wakedUp();
bool isWakeUpPin(uint32_t pin, uint32_t mode = RISING);

void setup() {
  Serial.begin(115200);
  delay(1000);

  Serial.println("START PROGRAM!");

  pinMode(pin, INPUT_PULLUP);

  if (!isWakeUpPin(pin)) {
	  Serial.println("For Shutdown we need a wake-up pin! Check the pinout!");
	  while (true) { delay(1000); }
  }

  // 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);

  Serial.println("Start shutdown mode in ");
  for (int i = 10;i>0;i--) { Serial.print(i); Serial.print(" "); } Serial.println( "OK!" );
  delay(1000);

  LowPower.shutdown();

  delay(1000);
}

void loop() {
	delay(100);
}

void wakedUp() {
	// randomly you can read this, but normally reset block every time the execution
	Serial.println("Wake-Up callback!");
}

bool isWakeUpPin(uint32_t pin, uint32_t mode)
{
  uint32_t wkup_pin = 0;
  PinName p = digitalPinToPinName(pin);
  if (p != NC) {
#ifdef PWR_WAKEUP_PIN1
    if ((p == SYS_WKUP1)
#ifdef PWR_WAKEUP_PIN1_1
        || (p == SYS_WKUP1_1)
#endif
#ifdef PWR_WAKEUP_PIN1_2
        || (p == SYS_WKUP1_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN1;
#ifdef PWR_WAKEUP_PIN1_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN1_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN1 */
#ifdef PWR_WAKEUP_PIN2
    if ((p == SYS_WKUP2)
#ifdef PWR_WAKEUP_PIN2_1
        || (p == SYS_WKUP2_1)
#endif
#ifdef PWR_WAKEUP_PIN2_2
        || (p == SYS_WKUP2_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN2;
#ifdef PWR_WAKEUP_PIN2_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN2_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN2 */
#ifdef PWR_WAKEUP_PIN3
    if ((p == SYS_WKUP3)
#ifdef PWR_WAKEUP_PIN3_1
        || (p == SYS_WKUP3_1)
#endif
#ifdef PWR_WAKEUP_PIN3_2
        || (p == SYS_WKUP3_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN3;
#ifdef PWR_WAKEUP_PIN3_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN3_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN3 */
#ifdef PWR_WAKEUP_PIN4
    if ((p == SYS_WKUP4)
#ifdef PWR_WAKEUP_PIN4_1
        || (p == SYS_WKUP4_1)
#endif
#ifdef PWR_WAKEUP_PIN4_2
        || (p == SYS_WKUP4_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN4;
#ifdef PWR_WAKEUP_PIN4_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN4_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN4 */
#ifdef PWR_WAKEUP_PIN5
    if ((p == SYS_WKUP5)
#ifdef PWR_WAKEUP_PIN5_1
        || (p == SYS_WKUP5_1)
#endif
#ifdef PWR_WAKEUP_PIN5_2
        || (p == SYS_WKUP5_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN5;
#ifdef PWR_WAKEUP_PIN5_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN5_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN5 */
#ifdef PWR_WAKEUP_PIN6
    if ((p == SYS_WKUP6)
#ifdef PWR_WAKEUP_PIN6_1
        || (p == SYS_WKUP6_1)
#endif
#ifdef PWR_WAKEUP_PIN6_2
        || (p == SYS_WKUP6_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN6;
#ifdef PWR_WAKEUP_PIN6_HIGH
      if (mode != RISING) {
        wkup_pin = PWR_WAKEUP_PIN6_LOW;
      }
#endif
    }
#endif /* PWR_WAKEUP_PIN6 */
#ifdef PWR_WAKEUP_PIN7
    if ((p == SYS_WKUP7)
#ifdef PWR_WAKEUP_PIN7_1
        || (p == SYS_WKUP7_1)
#endif
#ifdef PWR_WAKEUP_PIN7_2
        || (p == SYS_WKUP7_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN7;
    }
#endif /* PWR_WAKEUP_PIN7 */
#ifdef PWR_WAKEUP_PIN8
    if ((p == SYS_WKUP8)
#ifdef PWR_WAKEUP_PIN8_1
        || (p == SYS_WKUP8_1)
#endif
#ifdef PWR_WAKEUP_PIN8_2
        || (p == SYS_WKUP8_2)
#endif
       ) {
      wkup_pin = PWR_WAKEUP_PIN8;
    }
#endif /* PWR_WAKEUP_PIN8 */
    return (IS_PWR_WAKEUP_PIN(wkup_pin));
  }
  return false;
}

In questo sketch, ho anche aggiunto una funzione per verificare se il pin selezionato è un pin di risveglio e, se è tutto ok, puoi risvegliare il microcontrollore.

L’output è il seguente:

START PROGRAM!
Start shutdown mode in 
10 9 8 7 6 5 4 3 2 1 OK!
START PROGRAM!
Start shutdown mode in 
10 9 8 7 6 5 4 3 2 1 OK!

La parte evidenziata dell’output viene scritta prima della pressione del pulsante; dopo aver premuto, il microcontrollore si riavvia dall’inizio.

Grazie

  1. STM32F1 Blue Pill: piedinatura, specifiche e configurazione IDE Arduino (STM32duino e STMicroelectronics)
  2. STM32: programmazione (STM32F1) via USB con bootloader STM32duino
  3. STM32: programmazione (STM32F1 STM32F4) tramite USB con bootloader HID
  4. STM32F4 Black Pill: pinout, specifiche e configurazione IDE Arduino
  5. STM32: ethernet w5500 standard (HTTP) e SSL (HTTPS)
  6. STM32: ethernet enc28j60 standard (HTTP) e SSL (HTTPS)
  7. STM32: WiFiNINA con un ESP32 come WiFi Co-Processor
    1. STM32F1 Blue-pill: shield WiFi (WiFiNINA)
    2. STM32F4 Black-pill: shield WiFi (WiFiNINA)
  8. Come utilizzare la scheda SD con l’stm32 e la libreria SdFat
  9. STM32: memoria flash SPI FAT FS
  10. STM32: RTC interno, sistema orario e backup batteria (VBAT)
  11. STM32 LoRa
  1. STM32 Risparmio energetico
    1. STM32F1 Blue-Pill gestione clock e frequenza
    2. STM32F4 Black-Pill gestione clock e frequenza
    3. Introduzione e framework Arduino vs STM
    4. Libreria LowPower, cablaggio e Idle (STM Sleep).
    5. Sleep, deep sleep, shutdown e consumo energetico
    6. Sveglia da allarme RTC e Seriale
    7. Sveglia da sorgente esterna
    8. Introduzione al dominio di backup e conservazione delle variabili durante il RESET
    9. Registro di backup RTC e conservazione della SRAM
  2. STM32 invia email con allegati e SSL (come Gmail): w5500, enc28j60, SD e SPI Flash

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *