quarta-feira, maio 15, 2019

ESP32/Arduino: Partições da Flash e emulação de EEProm

Nos Arduinos baseados nos microcontroladores ATmega, a Flash é interna ao microcontrolador e tem uma organização bastantes simples: o bootloader e a aplicação, com tamanhos e posições definidos pelos fuses.

No ESP32 a Flash é externa (mas está dentro do módulo) e possui um esquema mais flexível que permite criar várias partições.

A Flash é o CI na parte de baixo - fonte: https://randomnerdtutorials.com/esp32-pinout-reference-gpios/


A Tabela de Partição

O nome, tipo, posição e tamanho de cada partição da Flash é definido em uma tabela (normalmente no endereço 0x8000 e com tamanho 0xC00 bytes). Cada definição de partição ocupa 32 bytes (), portanto podem existir até 96 partições. A documentação da tabela está aqui.

O programa abaixo lista a tabela de partição, usando a Partition Table API.
  1. // Fonte: https://github.com/espressif/arduino-esp32/issues/703#issuecomment-348255862  
  2.   
  3. #include <esp_partition.h>  
  4.   
  5. // Iniciação  
  6. void setup() {  
  7.   Serial.begin (115200);  
  8.   dump();  
  9. }  
  10.   
  11. // Nada a fazer  
  12. void loop() {  
  13.   delay(500);  
  14. }  
  15.   
  16. // Lista a tabela de partições  
  17. void dump() {  
  18.   size_t ul;  
  19.   esp_partition_iterator_t _mypartiterator;  
  20.   const esp_partition_t *_mypart;  
  21.     
  22.   ul = spi_flash_get_chip_size();   
  23.   Serial.print("Flash chip size: ");   
  24.   Serial.println(ul);  
  25.     
  26.   Serial.println("Partiton table:");  
  27.   _mypartiterator = esp_partition_find(ESP_PARTITION_TYPE_APP, ESP_PARTITION_SUBTYPE_ANY, NULL);  
  28.   if (_mypartiterator) {  
  29.     do {  
  30.       _mypart = esp_partition_get(_mypartiterator);  
  31.       printf("%x - %x - %x - %x - %s - %i\r\n", _mypart->type, _mypart->subtype, _mypart->address, _mypart->size, _mypart->label, _mypart->encrypted);  
  32.     } while (_mypartiterator = esp_partition_next(_mypartiterator));  
  33.   }  
  34.   esp_partition_iterator_release(_mypartiterator);  
  35.   _mypartiterator = esp_partition_find(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, NULL);  
  36.   if (_mypartiterator) {  
  37.     do {  
  38.       _mypart = esp_partition_get(_mypartiterator);  
  39.       printf("%x - %x - %x - %x - %s - %i\r\n", _mypart->type, _mypart->subtype, _mypart->address, _mypart->size, _mypart->label, _mypart->encrypted);  
  40.     } while (_mypartiterator = esp_partition_next(_mypartiterator));  
  41.     esp_partition_iterator_release(_mypartiterator);  
  42.   }  
  43. }  
A saída abaixo corresponde a uma ESP32 DevKit com configuração padrão do Arduino.
Flash chip size: 4194304
Partiton table:
0 - 10 - 10000 - 140000 - app0 - 0
0 - 11 - 150000 - 140000 - app1 - 0
1 - 2 - 9000 - 5000 - nvs - 0
1 - 0 - e000 - 2000 - otadata - 0
1 - 99 - 290000 - 1000 - eeprom - 0
1 - 82 - 291000 - 16f000 - spiffs - 0
De Onde Vem a Tabela de Partição

O kit de desenvolvimento da ExpressIf (ESP-IDF) contém uma ferramenta (um script python) que gera uma imagem binária da tabela a partir de um arquivo csv. Esta ferramente é rodada sempre que você manda gravar um sketch através da IDE do Arduino e a imagem gerada é gravada na flash.

O arquivo csv usado pela IDE é o xxx\packages\esp32\hardware\esp32\1.0.2\tools\partitions\default.csv, onde xxx é a pasta onde estão os pacotes do Arduino e 1.0.2 é a versão do suporte ao ESP32. Para descobrir a pasta, entre em Preferência e veja onde estão armazenadas as preferências da IDE.
# Name,   Type, SubType, Offset,  Size, Flags
nvs,      data, nvs,     0x9000,  0x5000,
otadata,  data, ota,     0xe000,  0x2000,
app0,     app,  ota_0,   0x10000, 0x140000,
app1,     app,  ota_1,   0x150000,0x140000,
eeprom,   data, 0x99,    0x290000,0x1000,
spiffs,   data, spiffs,  0x291000,0x16F000,
Emulação de EEProm (v1.0.2)

Importante: a próxima versão do suporte ao ESP32 vai mudar o que está escrito abaixo e provavelmente quebrar as aplicações que usam EEProm...

Nos microcontroladores ATmega temos a EEProm, que é uma memória não volátil que permite a alteração de bytes isolados. Isto é muito útil para armazenar configurações. O ESP32 não tem este tipo de memória. A solução (até a versão 1.02) é emular a EEProm usando uma partição da Flash.

O código da biblioteca EEProm para o release da versão 1.0.2 está aqui. Funciona parecido com a biblioteca do ATmega, exceto que:

  • É preciso chamar EEProm.begin() no início
  • Para tornar as gravações permanentes é necessário chamar EEprom.commit()
Na versão 1.0.3 (que está em beta) o módulo foi re-escrito para usar a NVS (non-volatile store) e marcado como deprecated com a recomendação de usar a biblioteca Preferences (que vai ser objeto do próximo post).







Nenhum comentário: