O fluxo de um programa para ESP32 será explorado neste artigo desde o primeiro estágio de boot, abordando alguns pontos importantes, até a chamada do app_main(). De maneira básica sem se aprofundar, assim, sendo uma análise importante para àqueles que querem entender esse processo, bem como, àqueles que necessitam customizar o boot de segundo estágio, o qual veremos a seguir. Desta forma, este artigo será dividido da seguinte maneira:
Além do conteúdo que será abordado aqui, a seguir, algumas recomendações de leituras relacionadas, veja:
Artigos relacionados
1. Bootloader de primeiro estágio
Após o processo de reset do módulo ESP32 ou SoC (System on Chip), como é também conhecido, o bootloader de primeiro estágio será executado. O firmware desenvolvido para execução desta parte, foi elaborado pela Espressif e está armazenado em uma memória não volátil, ou seja, numa memória ROM (Read Only Memory).
Conforme citado acima, o PRO CPU é imediatamente inicializado executando o vector table, localizado na mesma ROM (0x40000400). Além disso, ele realiza algumas configurações pertinente ao funcionamento do módulo, enquanto o outro core, o APP CPU é mantido em estado de reset.
Após esta etapa, a imagem do bootloader de segundo estágio que está armazenado na Flash (endereço 0x1000) será transferida para a RAM. Na sequência, a callback call_start_cpu0() localizada no arquivo bootloader_start.c e no diretório components/bootloader/subproject/main, será chamada e o processo do bootloader de segundo estágio terá início.
2. Bootloader de segundo estágio
O segundo estágio tem início na chamada da callback call_start_cpu0(), esta invoca a função bootloader_init() que faz algumas configurações necessárias de hardware e software para suportar o funcionamento, dentre as configurações estão:
- Inicialização do watchdog timer;
- Proteção da memória;
- Reset da região bss;
- Reset da MMU (Manager Memory Unity);
- Reconfiguração do clock;
- Inicialização do console (UART ou USB);
- Impressão da primeira mensagem no console: versão do ESP-IDF e indicação da inicialização do bootloader de segundo estágio (figura 1);
- Validação da versão do chip comparado o valor armazenado no header da imagem do bootloader;
- Configuração da Flash SPI se tudo estiver OK;
- Verifica se houve reset no watchdog timer;
- Habilita o hardware RNG (Random Number Generator) como fonte de entropia.
Em seguida, verifica-se qual tipo de partição sofrerá o boot (Single factory app, no OTA ou single factory app, two OTA definitions) mediante a consulta na tabela de partições localizada na memória Flash (0x8000), feito isto, carrega-se a imagem da aplicação.
Assim, finalizado o bootloader de segundo estágio, a callback call_start_cpu0() localizada em /esp-idf/components/esp_system/port/cpu_start.c é chamada, lembrando que até o presente momento o APP CPU está em reset.
As informações da figura 1 são oriundas do monitor de log do ESP-IDF executando uma aplicação hello_world. Este terminal pode ter acesso a partir da instalação do ESP-IDF no seu computador, a compilação do projeto hello_world e a execução do comando idf.py monitor, desta forma, obtem-se todas as informaçãoes pertinentes aos estágios de bootloader, bem como, da aplicação se esta estiver usando o printf(), por exemplo.
3. Início da aplicação do usuário
Já no ponto de entrada da aplicação, ou seja, na callback call_start_cpu0(), inicia o RTC, o carregamento do entry point do APP CPU (call_start_cpu1()), habilita o respectivo clock através da API start_other_core() e também faz a indicação de que o PRO CPU está ativo por meio do log no monitor (figura 2).
Deste modo, o PRO CPU aguarda o flag global de que o APP CPU foi inicializado e faz um jump para o endereço do start_cpu0() localizado em esp-idf/components/esp_system/startup.c. Já dentro desta função, começa-se a imprimir informações a respeito da aplicação, conforme a figura 3, somente então o PRO CPU faz alocação de heap, inicia o periférico de brownout, a área de uso da aplicação na memória Flash, o resumo de outros cores, desabilita o watchdog de boot e chama a função start_app() localizada em esp-idf/components/freertos/xtensa/port.c
Em start_app(), o PRO CPU inicializa o watchdog timer, bem como o configura para 5 segundos e habilita a interrupção para esse mesmo core. Além disso, descobre-se que este core é o responsável por rodar a main_task() da aplicação do usuário por meio da API do FreeRTOS xTaskCreatePinnedToCore(). Logo, é impresso no monitor que scheduler do RTOS foi inicializado no PRO CPU, conforme a figura 4. Além disso, verifica-se o funcionamento core APP CPU.
A main_task() é a função que invoca a app_main() que está em todas as aplicação que faz as configurações iniciais e cria as task do seu projeto. Deste modo, conseguimos entender, de maneira simplória, como um fluxo de programa para ESP32 é dado.