Economizando bateria com Deep Sleep!



Quer usar bateria com o ESP32? Pois, trago informações técnicas importantes sobre esse assunto. Sabemos que esse microcontrolador, quando está transmitindo informações, ele gasta bastante energia, ou seja, ele consome perto de 190 miliampères. Neste vídeo, então, quero te mostrar como economizar energia do ESP32 com o chamado “DEEP SLEEP”. Vamos configurar o chip para entrar neste modo, conhecer as maneiras de sair deste modo e criar um exemplo envolvendo três maneiras diferentes de despertar o ESP32.


Vale lembrar, pessoal, que não é processador dele que gasta muita energia, mas, sim, o radio. E a economia de energia é muito importante. Isso, porque, não raro, os Endpoints, que são os circuitos que ficam enviando informação, eles são alimentados por bateria e precisam durar até cinco anos. Lembrando que tem alguns fabricantes que prometem até dez anos de duração e isso é válido quando a bateria é de boa qualidade e o Endpoint precisa trabalhar pouco. Do contrário, aconselho que você use o Deep Sleep para economizar energia do seu circuito.


Introdução

O ESP32 possui, portanto, um modo de economia de energia, chamado “Deep Sleep”. Nesse modo, as CPUs, a maior parte da RAM e todos os periféricos digitais com clock estão desligados. As únicas partes do chip que ainda podem ser ligadas são: controlador RTC, periféricos RTC (incluindo o coprocessador ULP) e memórias RTC.
Temos várias maneiras de despertar o ESP32 quando está adormecido, sendo que as fontes de despertar podem ser configuradas a qualquer momento antes de entrar no modo Deep Sleep.


Maneiras de despertar o ESP32

São cinco as maneiras de despertar o ESP32:
·         Timer
·         External wakeup (ext0)
·         External wakeup (ext1)
·         ULP coprocessor wakeup
·         Touchpad




Timer

O controlador RTC possui um cronômetro incorporado que pode ser usado para ativar o chip após um período de tempo predefinido. O tempo é especificado com precisão de microssegundos.

esp_deep_sleep_enable_timer_wakeup( uint64_t time_in_us )

time_in_us > é o tempo em microssegundos



External wakeup (ext0)

O módulo RTC IO contém lógica para acionar o despertador quando um dos GPIOs RTC entra em um nível lógico predefinido. O RTC IO faz parte do domínio de energia dos periféricos RTC, portanto, os periféricos RTC serão mantidos ligados durante o Deep Sleep se essa fonte de ativação for solicitada.

esp_deep_sleep_enable_ext0_wakeup( gpio_num_t gpio_num , int level)

gpio_num > número do GPIO usado como fonte de ativação. Apenas os GPIOs com funcionalidade RTC podem ser usados: 0,2,4,12-15,25-27,32-39.

level > nível de entrada que acionará o despertador (0 = LOW, 1 = HIGH)



External wakeup (ext1)

O controlador RTC contém lógica para acionar o despertador usando vários GPIOs RTC. 

esp_deep_sleep_enable_ext1_wakeup(uint64_t mask, esp_ext1_wakeup_mode_t mode)

mask > máscara de bits de números GPIO que causará ativação. Apenas os GPIOs com funcionalidade RTC podem ser usados ​​neste mapa de bits: 0,2,4,12-15,25-27,32-39.

mode > selecione a função lógica usada para determinar a condição de ativação:

·         ESP_EXT1_WAKEUP_ALL_LOW: desperta quando todos os GPIOs selecionados estão em LOW

·         ESP_EXT1_WAKEUP_ANY_HIGH: desperta quando qualquer um dos GPIOs selecionados está em HIGH



ULP coprocessor wakeup

O coprocessador ULP pode funcionar enquanto o chip está em Deep Sleep e pode ser usado para pesquisar sensores, monitorar ADC ou valores do sensor de toque capacitivo e ativar o chip quando um evento específico for detectado
O coprocessador ULP faz parte do domínio de energia dos periféricos RTC e executa o programa armazenado em memória lenta RTC. Portanto, os periféricos RTC e a memória lenta RTC serão ativados durante o Deep Sleep se esse modo de ativação for solicitado.



Touchpad

O controlador RTC contém lógica para acionar o despertador utilizando os sensores de toque capacitivo. A definição do pino de toque, no entanto, é diferente. Devemos utilizar a interrupção por toque (touchInterrupt) para cada um dos pinos desejados.
Após configurar as interrupções, habilitamos o modo de despertar para utilizar os sensores.

 //Configure Touchpad as wakeup source
      esp_sleep_enable_touchpad_wakeup();



Entrando no modo Deep Sleep

Após configurarmos algum modo para despertar, basta um único comando para colocar o ESP32 em modo Deep Sleep, gastando 2.5 µA ou menos. Destaco aqui que esse gasto é do chip do ESP e não da placa, pois esta última gasta mais.

esp_deep_sleep_start();

A partir desse comando, o ESP32 adormece e não executa as próximas linhas de código por exemplo.

Importante: Todas as configurações de despertar devem ser feitas antes de executar o comando acima.



Mais algumas informações importantes:

A chamada abaixo retorna a causa do despertar do ESP32.
1: EXT0                 2: EXT1                 3: TIMER              4: TOUCHPAD                   5: ULP

esp_sleep_get_wakeup_cause();

Caso configuremos o despertar pelo touchpad, podemos recuperar qual o GPIO que ocorreu o toque, através do comando:

esp_sleep_get_touchpad_wakeup_status();



Toda vez que o ESP32 despertar, ele passará no setup novamente. Sendo assim todas as variáveis que não estão definidas na memória do RTC, voltarão ao seu estado de origem.
Para manter as variáveis em memória mesmo após adormecer, utilize a declaração da variável como o exemplo abaixo:

//RTC_DATA_ATTR aloca a variável na memória RTC
RTC_DATA_ATTR int bootCount = 0;



Demonstração

No vídeo você vê o programa funcionando, conforme a imagem.





WiFi NodeMCU-32S ESP-WROOM-32




Montagem

Deixo aqui o esquemático do projeto.




Programa

Faremos agora um programa no qual configuraremos o ESP32 para entrar em modo Deep Sleep. Este será despertado de três maneiras diferentes: uma por External wakeup (ext0), outra por Timer e outra por Touchpad. Elas não podem funcionar juntas, portanto, utilizaremos uma variável que será um contador de quantas vezes o ESP32 deu Boot para configurar a maneira de despertar.



Biblioteca Necessária

Para controlar o display oled necessitamos de uma biblioteca externa. Para isso vamos fazer o download da biblioteca U8g2.

Na Arduino IDE, acesse o menu Sketch >> Incluir Biblioteca >> Gerenciar Bibliotecas....




Bibliotecas e Variáveis

Incluímos a biblioteca para controle do display oled, bem como um construtor da instância do controlador do display. Ainda, alocamos a variável na memória RTC. Definimos a sensibilidade para aceitação do toque, o fator de conversão de microsegundos para segundos e o tempo que o ESP32 ficará em modo sleep (em segundos).

#include <U8x8lib.h> //biblioteca para controle do display oled

//construtor da instancia do controlador do display
//SDA = 21 e SCL = 22
U8X8_SSD1306_128X64_NONAME_SW_I2C display(SCL, SDA, U8X8_PIN_NONE);

//RTC_DATA_ATTR aloca a variável na memoria RTC
RTC_DATA_ATTR int bootCount = 0;

//sensibilidade para aceitação do toque
#define Threshold 40

//fator de conversão de microsegundos para segundos
#define uS_TO_S_FACTOR 1000000
//tempo que o ESP32 ficará em modo sleep (em segundos)
#define TIME_TO_SLEEP 3




Setup

No Setup, incrementamos o número de vezes que o Boot ocorreu. Chamamos a função para imprimir o motivo do Boot. Se o número de Boot for PAR, configuramos o ESP32 para despertar através do botão (EXT0). Já se for múltiplo de 3, configuramos o ESP32 para despertar depois de um tempo definido. Caso contrário, configuramos os pinos de touch capacitivo para despertar o ESP32. Por fim, configuramos o Touchpad como wakeup source e forçamos o ESP32 entrar em modo Sleep.

void setup() {
     Serial.begin(115200);
     delay(1000); 
     //incrementa o numero de vezes que o BOOT ocorreu
     ++bootCount;
     configureDisplay();
     //chama a função para imprimir o motivo do BOOT
     print_wakeup_reason();
     //se o numero de boot for PAR configuramos o ESP32 para despertar através do botão (EXT0)
     if(bootCount % 2 == 0) {
   esp_sleep_enable_ext0_wakeup(GPIO_NUM_39,1); //1 = High, 0 = Low
     }
     //se for multiplo de 3 configuramos o ESP32 para despertar depois de um tempo definido
     else if(bootCount % 3 == 0) {
   esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
     }
     //caso contrario configuramos os pinos de touch capacitivo para despertar o ESP32
     else {
          //Setup interrupt on Touch Pad 5 (GPIO12)
          touchAttachInterrupt(T5, callback, Threshold);
          //Configure Touchpad as wakeup source
          esp_sleep_enable_touchpad_wakeup();
     }
     Serial.println(“entrando em modo sleep"); 
     esp_deep_sleep_start(); //força o ESP32 entrar em modo SLEEP
}


Loop, callback & configureDisplay

No Loop não temos nada a fazer. Seguimos, então, para o callback das interrupções caso tenhamos algo a fazer quando ocorrer a interrupção. Quanto ao configureDisplay, inicializamos o display e configuramos alguns parâmetros. Imprimimos na tela o número de vezes que aconteceu o Boot.

//nada a se fazer no loop
void loop() {
}

//callback das interrupções
void callback(){
//caso queira fazer algo ao ocorrer a interrupção
}

void configureDisplay()
{
     //inicializa o display e configura alguns parametros
     display.begin();
     display.setPowerSave(0); //modo powerSave (0-Off ? 1-On)
     display.setFont(u8x8_font_torussansbold8_u); //fonte utilizada

     //imprime no display os numero de vezes que aconteceu o BOOT
     display.drawString(0,0, "BOOT NUM:");
     display.drawString(0,2,String(bootCount).c_str());
     display.drawString(0,4, "MOTIVO:");
}


print_wakeup_reason (conhecer a causa do despertar)

Temos aqui a função para imprimir a causa do ESP32 despertar. Verificamos o pino e imprimimos no display.

//função para imprimir a causa do ESP32 despertar
void print_wakeup_reason( ){
     esp_sleep_wakeup_cause_t wakeup_reason;
     String reason = "";

     wakeup_reason = esp_sleep_get_wakeup_cause(); //recupera a causa do despertar

     switch(wakeup_reason)
     {
          case 1 :reason = "EXT0 RTC_IO BTN"; break;
          case 2 :reason = "EXT1 RTC_CNTL";   break;
          case 3 :reason = "TIMER";           break;
          case 4 :reason = "TOUCHPAD";        break;
          case 5 :reason = "ULP PROGRAM";     break;
          default :reason = "NO DS CAUSE";    break;
     }
     Serial.println(reason);
     display.clearLine(6); //apaga a linha 6 do display
     display.drawString(0,6, reason.c_str()); //imprime a causa do despertar no display
     //se despertou por TOUCHPAD, então vamos verificar em qual dos pinos ocorreu
     if(wakeup_reason == 4) {
 print_wakeup_touchpad(); //verifica o pino e imprime no display
     } 
}


print_wakeup_touchpad (conhecer o GPIO do toque)

Já, nesta etapa, temos a função para imprimir o pino que foi tocado. Recuperamos o GPIO que despertou o ESP32 e o imprimimos no display.

//função para imprimir o pino que foi tocado
void print_wakeup_touchpad() {
     touch_pad_t touchPin;
     touchPin = esp_sleep_get_touchpad_wakeup_status(); //recupera o GPIO que despertou o ESP32
     String GPIO = "";

     switch(touchPin) 
     {
   case 0 : GPIO = "4";  break;
         case 1 : GPIO = "0";  break;
         case 2 : GPIO = "2";  break;
         case 3 : GPIO = "15"; break;
         case 4 : GPIO = "13"; break;
         case 5 : GPIO = "12"; break;
         case 6 : GPIO = "14"; break;
         case 7 : GPIO = "27"; break;
         case 8 : GPIO = "33"; break;
         case 9 : GPIO = "32"; break;
         default : Serial.println("Wakeup not by touchpad"); break;
     }
     Serial.println("GPIO: "+GPIO);
     display.clearLine(7);//apaga a linha 7 do display
     display.drawString(0,7, "GPIO: ");
     display.drawString(6,7, GPIO.c_str()); //imprime o GPIO 
}




Faça o download dos arquivos


5 comentários:

  1. Boa tarde. Estava tudo indo muito bem com o ESP32, porém, ao conectar o WiFi, ele passou a exibir a mensagem "Brownout detector was triggered". Nem sei mais o que fazer. Já troquei o cabo USB, a fonte, coloquei capacitor na alimentação... Nada funciona.

    ResponderExcluir
    Respostas
    1. Até hj não sei se o motivo disso é software ou hardware. Digo isso pq alterei algumas funções no código e esse erro sumiu. Após um tempo voltou a aparecer. Substituindo a alimentação USB por uma fonte de 5V, pareceu ter resolvido o problema, mas dps tornou a aparecer. Enfim, não sei. Por enquanto eu utilizo apenas a fonte de 5V e programo via OTA.

      Excluir
  2. Olá Fernando, parabéns pela aula! Gostei bastante, era exatamente isso que vinha tentando fazer, minha dúvida é se no NodeMCU 12-e também vai funcionar estas funções de deep sleep. Uma outra dúvida é na pinagem e no software, você colocou o botão na GPIO04 e no código configurou o wakeup do ext0 no pino 39, o que significa este 39? você teria uma tabela de conversão a GPIO04 corresponde ao pino 39? Não seria ao RTCIO10 como mostra no pinout do ESP32? Desde já agradeço muito pela sua atenção e seu trabalho.

    ResponderExcluir
  3. Olá Fernando Parabéns pelo seu trabalho, gostaria de tirar uma duvida é possivel fazer o LORA ativar o STM32 pelo pino 26 IRQ ou outro pino, é algo muito util e não consegui encontrar em lugar nenhum, se puder me dar pelo menos uma dica já agradeço

    ResponderExcluir

Tecnologia do Blogger.