12 de abril de 2021

Do bit Ao Byte

Embarcados, Linux e programação

UART wakeup com ESP32

modem sleep | UART wakeup | sleep modes com ESP32

Essa tem sido uma extensa série sobre os modos de sleep no ESP32, cada qual servindo a seu propósito, conforme a aplicação. E enfim, chegamos ao (provável) último artigo da série com a implementação de UART wakeup com ESP32 – mas sem falsas ilusões, a coisa não foi bem na configuração desse modo. Esse artigo complementará informações que já foram (ou não) citadas em um dos outros artigos relacionados, além dessa implementação ainda não vista por aqui. Divirta-se com a leitura!

WiFi e BLE: Desabilitar ou não desabilitar?

Uma recomendação é que, antes de entrar em deep ou light sleep, desligue-se o RF através das chamadas esp_bluedroid_disable(), esp_bt_controller_disable() e esp_wifi_stop(). Bem, a informação é que sem essas chamadas ambos não entrarão no sleep state, mas em “todos” os exemplos dos artigos anteriores não usei essas chamadas e os modos sleep funcionaram sem problemas. E testei por longos períodos, sem apresentar problemas.

“Pode ser que” na IDE do Arduino todas as coisas relacionadas ao ESP32 sejam diferentes das coisas utilizadas no VS Code com PlatformIO, pode ser que o ESP-IDF tenha sido compilado de forma diferente, pode ser, pode ser, pode ser…

Por essa razão, caso tenha algum problema na implementação, verifique se há necessidade de algum dos (ou todos os) procedimentos anteriores.

Relação dos modos de sleep com o hardware

Uma pesquisada de leve no google deve retornar uma série de representações sobre os recursos que são desabilitados para economizar energia em cada modo de sleep. A melhor representação que achei após 6 artigos relacionados, foi essa:

Active normal

Quando operando com todos os recursos, o consumo do ESP32 pode variar entre 95 e 240mA. Isso vai depender de N fatores, como a utilização de WiFi, bluetooth, clock (que pode ser de 80MHz, 160MHz ou 240MHz), processamento da aplicação e utilização dos núcleos.

UART wakeup - normal mode

Modem sleep

Me permita sugerir que leia tranquilamente. Ao final do artigo você terá os links de referência para cada um dos modos e suas variantes, caso não tenha acompanhado a série. Essas informações que estou dispondo nesse momento são complementares. No artigo do modem sleep tem inclusive vídeo demonstrando a eficácia em relação à redução de consumo.

Para fazer a parada do bluetooth e wifi:

esp_bluedroid_disable();
#ou:
esp_bt_controller_disable();
#e wifi:
esp_wifi_stop();
UART wakeup - modem sleep

Light sleep

No modo light sleep o processador é pausado. Ficam ativos o coprocessador (ULP) e o RTC completo. Nesse modo, qualquer evento como MAC, host, timer pelo RTC ou interrupções externas pode levantar a CPU. No artigo relacionado ao light sleep tem outras considerações importantes.

Ao chamar a função esp_light_sleep_start() teremos um esquema similar a esse:

UART wakeup - light sleep

Deep sleep

No deep sleep somente o RTC e a memória do RTC são alimentadas. Os dados de WiFi e bluetooth são armazenados na memória do RTC. Se precisar armazenar algum dado, precisa fazê-lo antes do deep sleep, na memória do RTC. No respectivo artigo mostrei como proceder, os links de todos esses meios estão dispostos mais abaixo.

UART wakeup - deep sleep

Hibernation

Esse é um modo que eu não sabia que existia, mas basicamente é um deep sleep mais “radical”. A única coisa que fica ligada nesse modo é o RTC e os GPIOs do RTC, para que seja possível retornar desse profundíssimo “sono”.

UART wakeup - hibernation

No datasheet do ESP32 tem toda a informação sobre os consumos em cada modo e cada clock. Basicamente:

tabela de consumo dos sleep modes

Modos de wakeup

No ESP32 temos que definir o modo do wakeup, sendo sete possibilidades.

  • Por timer, usando esp_sleep_enable_timer_wakeup().
  • Por toque capacitivo, usando esp_sleep_enable_touchpad_wakeup().
  • Por interrupção. Aí a coisa fica mais elaborada:
  • – EXT0 usando um pino do RTC para levantar: esp_sleep_enable_ext0_wakeup(RTC_PIN, MODE).
  • – EXT1 que permiti definir múltiplos pinos do RTC: esp_sleep_enable_ext1_wakeup(MASK,MODE).
  • Qualquer pino de GPIO: esp_sleep_enable_gpio_wakeup().
  • UART wakeup, usando: esp_sleep_enable_uart_wakeup().
  • Através de programação do ULP: esp_sleep_enable_ulp_wakeup().

Outra informação importante é a relação dos recursos que podem tirar o ESP32 do sleep mode, conforme o modo escolhido. No caso, temos essa tabela da diyprojects.io:

tabela de sleep modes e recursos

UART wakeup

Não consegui implementar a UART wakeup de forma alguma. Para definir a UART como “despertador”, utiliza-se a função uart_set_wakeup_threshold(uart_port_t, uart_num, int wakeup_threshold). Não estava encontrando a definição dessa função, então cacei pelo header que continha sua declaração. Na documentação do ESP32 encontrei o header, que é simplesmente a uart.h. Porém, usando o VS Code com PlatfdormIO não basta simplesmente incluir, porque o caminho é diferente. Tive que procurar onde estava esse header:

UART wakeup - header

Por fim, o include acaba sendo “driver/uart.h”. Surpreendentemente já havia usado esse header no artigo relacionado a UART no ESP32, mas o propósito era outro.

Precisamos ter em mente que, infelizmente, esse modo só funcionará em light sleep – e em algum lugar tem que funcionar, ainda que seja apenas o ESP-IDF. Eu li em alguma parte da documentação que era possível levantar com deep sleep, mas enfim, lendo todo o material escrito a respeito, sabendo o papel de cada periférico, e implementando agora, não vejo (pelo menos ainda) como implementar UART wakeup de um deep sleep.

Outro ponto importante a considerar é que o gatilho usado para levantar a UART não será lido para o buffer, portanto esse byte deverá ser realmente usado para levantar a UART, sem nenhum outro propósito. Dependendo da velocidade da serial, mais bytes serão perdidos, por isso é ideal usar esse modo com uma velocidade baixa, como 9600bauds.

Daí após alguns dias tentando resolver a questão nas horas livres, acabei jogando a toalha e pensando: Preciso mesmo economizar tanto? O modem sleep já deixa o consumo abaixo de 10mA, não faz sentido tanto esforço.

E assim foi, acabei optando mesmo pelo modem sleep, que com uma bateria de 6800mAh dá pelo menos 170 horas, desconsiderando os momentos de wakeup para envio de dados, que também deve ser coisa breve. Mas pelo menos deixo descrito o processo para que você possa experimentar, já sabendo das dificuldades, e de repente deixar até uma dica no comentário do artigo em nossa página no Facebook.

Revisão: Ricardo Amaral de Andrade