ESP32 – Utilizando o Brown Out Detector (BOD) para quedas de alimentação
Em muitos projetos precisamos gerenciar, com cautela, a alimentação do nosso sistema, evitando mal funcionamento ou até perda de dados na RAM. Podemos, por exemplo, entrar em Deep Sleep ou salvar dados presentes na RAM numa memória não-volátil quando detectamos uma queda de alimentação, assim evitando a perda destes dados, é ai que entra o Brown Out Detector (BOD). O ESP32 conta com um BOD internamente com níveis de tensões e modos de operações configuráveis, nos permitindo tomar atitudes em casos de queda ou má alimentação.
[toc]
O que é Brown Out Detector (BOD) ?
Brown Out Detector (BOD), é um hardware interno ou externo que detecta problemas na alimentação de um sistema. Muito dos microcontroladores atuais tem este item disponível, inclusive o ESP32.
Há algumas formas que o BOD pode funcionar e você deve analisar especificamente para o seu microcontrolador, entretanto, tudo que será explicado abaixo é relacionado ao ESP32, que pode mudar levemente para algum outro microcontrolador.
O BOD presente no ESP32 gera uma interrupção na CPU, nos permitindo tratar este “problema de alimentação”, como salvar variáveis da RAM em memória não-volátil, ligar/desligar saídas, ativar sistemas de emergência com SCR, etc. Também permite a configuração de alguns parâmetros para melhor aproveitamento do mesmo, veja uma pequena lista de funcionalidades:
- Tensão de trigger configurável com precisão de +- 50mV: 2.43, 2.48, 2.58, 2.62, 2.67, 2.7, 2.77, 2.8V.
- Desativação do circuito RF (WiFi/Bluetooth) e/ou FLASH interna, afim de aumentar o precioso tempo restante com energia disponível.
O tempo de funcionamento que será citado abaixo, é imaginando um caso em que a alimentação do sistema é completamente removida. Mesmo assim, o BOD ainda tem velocidade suficiente para gerar a interrupção e a CPU processar alguns dados antes que a tensão fique abaixo do limite absoluto (2.3V) quando o ESP32 é desligado. O WROOM é recomendado para funcionar no mínimo com 2.7V, então é interessante configurar o nível de trigger neste valor ou acima.
Se nós queremos obter um maior tempo de funcionamento, utilizaremos o nível de trigger mais alto (2.8V), mas se a alimentação no ESP32 for instável, isso pode gerar falsos alarmes até mesmo com WiFi ativo, uma vez que os picos de consumo pode fazer a tensão cair a este nível. Para contornar este problema, basta melhorar seu circuito de alimentação ou deixar o nível de trigger mais baixo como 2.43V (o que reduziria o tempo de funcionamento). Vamos observar tudo isso melhor na prática!
Mãos à obra – BOD
O código foi feito na Arduino IDE, entretanto, funciona da mesma forma na IDF, bastando remove os itens do Arduino como DigitalWrite().
Componentes necessários
Programando
Você também pode obter o código (ou arquivo .ino) no repositório do GitHub: https://github.com/urbanze/vds_esp32_bod
extern "C" { #include <driver/rtc_cntl.h> } #define LED 2 void setup() { pinMode(LED, OUTPUT); init_bod(); } void loop() { } void IRAM_ATTR bod_isr(void*z) { //Liga o LED digitalWrite(LED, 1); //Mostra no Serial Monitor. Voce nao conseguira ler nada se remover o cabo USB ets_printf("\nBOD Trigged (2.8V)\n"); //Aborta a execucao, forcando o reinicio abort(); } void init_bod() { uint32_t value = 0; value |= (1<<30);//Ativa o BOD value |= (2<<16);//Ciclos de espera, precisa ser >1 & <1024 value |= (1<<15);//Desativa o RF value |= (7<<27);//Nivel de trigger (2.8V). Para 2.43V ficaria (0<<27) //Configura o registrador do BOD (*(volatile uint32_t *)(0x3FF480D4)) |= value; //Configura a ISR (bod_isr) pro BOD rtc_isr_register(bod_isr, NULL, (1<<7)); //Habilita a interrupcao do BOD (*(volatile uint32_t *)(0x3FF4803C)) |= (1<<7); }
Colocando para funcionar
Para conseguir gravar um GIF, foi adicionado um capacitor na alimentação do ESP32, fazendo com que seu tempo de funcionamento dure mais e possamos capturar no GIF.
Ao remover o cabo de alimentação do computador, a tensão começa a cair e logo que chega em 2.8V, o BOD entra em ação, ativando o LED para que possamos visualizar.
Entendendo a fundo
Podemos observar o funcionamento de um BOD neste curto vídeo da Microchip, que mantém o microcontrolador em reset enquanto a tensão não é estabilizada acima do definido.
O BOD do ESP32 não funciona desta maneira, infelizmente. Apenas reinicia e é logo iniciado novamente (o que pode gerar alguns raros problemas) no exemplo deste código. O ideal é sempre utilizar um BOD externo.
Apesar da rápida interrupção quando é detectado a tensão baixa, provavelmente você não conseguirá salvar dados na flash do ESP32 com a maioria das API’s (bibliotecas) nativas (Arduino ou ESP-IDF) por não serem tão rápidas assim. Talvez utilizando as API’s de Low-Level (spi_flash) ou até outras memórias externas seja possível.
Considerações finais
O BOD é muito importante em diversos projetos onde necessitamos monitorar a alimentação presente no sistema, afim de conseguir tomar atitudes com dados voláteis e até acionar outros sistemas como alarmes e etc. O BOD interno não substitui um externo (dedicado), sendo indicado em projetos mais “sérios”.
Referências
ESP32 – Technical Reference Manual
Otimo artigo, tirando as perguntas bestas desses abestados. Como tem gente fresca,chata e burra nessa área…
Nao consigo utilizar o READ_PERI_REG(RTC_CNTL_BROWN_OUT_REG); e WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG); com valores inteiros?
Nao me sinto confortavel em escrever bytes direto na cabeca do registrador atraves de enderecos….
Prefiro utilizar as funcoes da fabricante, pois tenho receio de brikar o esp.
Outra questao que eu gostaria de utilizar esta funcao com o processador ULP seria possivel utilizar os valores medidos no BOD para algum subprocessamento no ULP?
Imagino que desta maneira que citei acima seja mais intuitivo…
#include
Post muito legal sobre o Brown Out do ESP.
Como sugestão para enriquecer o texto e o código, diria para colocar um “vislumbre” do registrador de controle RTC_CNTL (0x3FF480D4) da ESP32 antes e depois de configurá-lo ou configurar duas vezes para ver ele mudando de valor. Lembrando que para a aplicação proposta no artigo isso não tem funcionalidade alguma.
// local onde estão localizadas diversas definições para o Low-Power Management (RTC_CNTL)
#include
void print_bd_status(void){
uint32_t bdStatus;
bdStatus = READ_PERI_REG(RTC_CNTL_BROWN_OUT_REG);
printf(“Brownout %.8x\r\n”, bdStatus);
}
Primeiramente parabéns por esses e outros artigos escritos aqui no blog, realmente são conteúdos muito ricos e bem escritos… Agora fiquei com uma pequena dúvida.
Quando você faz essa sequencia de operação
value |= (1<<30);//Ativa o BOD
value |= (2<1 & <1024
value |= (1<<15);//Desativa o RF
value |= (7<<27);//Nivel de trigger (2.8V). Para 2.43V ficaria (0<<27)
É feito essas operações OR e esses vários shifts no passo a passo apenas para fins didáticos?
Faria alguma diferença se pegássemos o resultado de todas essas operações e simplesmente atribuísse a variável "value"??
Ex: value = 0xFFFFFFFF (Um valor totalmente aleatório, imagina que esses F's fossem o resultado de todas essa operações)
E caso fosse só para fim didáticos, qual o motivo de usarmos os shifts e não o valor direto de por exemplo o shift pra esquerda de 16 no valor de 2?? ( value |= (2<<16) )
Muito obrigado e na espera de novos conteúdos :)
Ola
O comando value |= (1<<30); faz alteração no bit 30 do registrador, o que seria diferente de dizer value=0x4000; já que este ultimo comando faz alteração em todos os bits do registrador.
quanto a usar o deslocamento de bit, 1<<30 ou usar o valor hexadecimal 0x4000, não altera o código, é apenas preferência.