ESP: rBoot

From Frotmail Projects
Jump to navigation Jump to search

Inleiding

Bijna de handigste feature van de ESP8266 is het kunnen programmeren via WiFi.

Er zijn door de tijd heen verschillende manieren geweest om de ESP remote te flashen. Maar 1 van de meest betrouwbare manieren is wel via rBoot.

rBoot is een bootloader die het mogelijk maakt om verschillende ROM's te booten.

Voor je met rBoot aan de slag kan dien je wel wat basis te begrijpen...

2 Images

Het is niet mogelijk om de flash te beschrijven terwijl de huidige rom van deze locatie draait (applicatie stopt en ESP zal niet booten zonder dat deze opnieuw geflashed wordt). Daarom is het noodzakelijk de flash te partitioneren.

Door 2 of meer locaties te defineren kan de applicatie vanuit de ene locatie draaien terwijl je een andere locatie overschrijft. Door vervolgens de config van de bootloader aan te passen kan je rebooten naar deze andere locaties.

Flash layout

De ESP8266 komt grofweg in 2 smaken. Een 1MB en 4MB uitvoering:

  • ESP-01: 1MB, 2x GPIO en TX/RX
  • ESP-07: 1MB, 9x GPIO, TX/RX en ADC
  • ESP-12: 4MB, 15x GPIO, TX/RX e ADC

Een 1MB versie heeft dus flash geheugen van 0x000000 t/m 0x0FFFFF. Een 4MB versie gaat van 0x000000 t/m 0x3FFFFF.

De ESP is in staat om maximaal 1 MB geheugen tegelijk aan te spreken. Het is wel mogelijk om de rom en spiffs in separate 1MB "pagina's" te zetten maar een rom of spiffs mag nooit over de scheiding van 2 pagina's vallen.

Voor rBoot op een 4MB chip is dit veruit de eenvoudigste inrichting:

0x000000    rboot.bin          len: ~2300 bytes     (0x920)
0x001000    config.bin         len: 32 bytes        (0x20)
0x002000    rom0.bin           len: max 1M - 0x2010 (0xFDFF0)
0x100000    spiffs_rom1.bin    len: max 1M - 0x10   (0xFFFEF)
0x202000    rom0.bin           len: max 1M - 0x2010 (0xFDFF0)
0x300000    spiffs_rom2.bin    len: max 1M - 0x10   (0xFFFEF)

Tijdens het compilen en linken worden in de rom bestanden verwijzingen opgenomen naar absolute geheugenlocaties. Dat is ook de reden waarom in bovenstaand voorbeeld beide rom0's starten op 0x?02000. Per blok van 1MB vallen de absolute verwijzingen naar geheugen dan op dezelfde posities.

Verder zie je in dit voorbeeld dat ik 2x een spiffs rom upload. Per image is het zo mogelijk om een aparte pagina van 1MB toe te wijzen als storage. Dit is geen eis, je kan ook vanuit beide images dezelfde SPIFFS image benaderen.

Makefile-user.mk

MODULES = app
SERIAL_BAUD_RATE = 115200
ESP_HOME = /opt/esp-open-sdk
SMING_HOME = /opt/Sming/Sming
SPI_SIZE = 512K
SPIFF_FILES = files
SPIFF_SIZE = 524288
RBOOT_ENABLED ?= 1
RBOOT_BIG_FLASH ?= 1
RBOOT_TWO_ROMS  ?=0
SPI_SIZE        ?= 4M

Bij het flashen kan je het beste de bootconfig (0x1000 t/m 0x1020) leeg flashen (overschrijven met nullen) zodat deze automatisch wordt gegenereerd.

Verder dien je de rboot.bin, rom0.bin en eventueel de spiffs_rom.bin te flashen op resp. 0x00000, 0x02000 en 0x100000. Daarna kan je rom0.bin opnieuw flashen op 0x202000 maar dit kan je ook via OTA flashen.

Een automatisch gegenereerde bootconfig is vaak prima voor een 4MB flash chip met 2 images, maar voor bijzondere situaties zal deze niet volstaan. Zou je de bootconfig zelf willen schrijven dan kan dit door de volgende struct naar een file te schrijven:

typedef struct {
    uint8 magic;           // our magic
    uint8 version;         // config struct version
    uint8 mode;            // boot loader mode
    uint8 current_rom;     // currently selected rom
    uint8 gpio_rom;        // rom to use for gpio boot
    uint8 count;           // number of roms in use
    uint8 unused[2];       // padding
    uint32 roms[MAX_ROMS]; // flash addresses of the roms
#ifdef BOOT_CONFIG_CHKSUM
    uint8 chksum;          // boot config chksum
#endif
} rboot_config;

Dit kan je doen door bijvoorbeeld een nieuwe file te maken in een hex editor, of je laat eerst een config genereren (0x1000-0x1020 overschrijven met nullen en rboot starten) welke je met esptool.py download en edit.

In dit voorbeeld willen we op een 1MB flash chip 2 images en 1 spiffs wegschrijven:

0x1000.bin

0x00  E1 01 08 00  00 02 00 00  
0x08  00 20 00 00  00 20 06 00
0x10  00 00 00 00  00 00 00 00

Op adres 0x0b t/m 0x08 staat het adres van rom0.bin (achtersevoren) dus: 0x00002000

Op adres 0x0f t/m 0x0c staat het adres van rom1.bin dus: 0x00062000

rom0 mag dus 0x62000 - 0x02000 = 0x60000 groot zijn (=384K) Als we dan rom1 net zo groot nemen zou spiffs op (0x62000 + 0x60000 =) 0xC2000 mogen starten. Voor spiffs is dan 247K over (0xFFFFF - 0xC2000)

In dit scenario kan niet dezelfde rom0.bin worden weggeschreven naar beide applicatie blokken. De absolute adressering is namelijk niet identiek binnen de 1MB pagina. Daarom moeten in de Makefile-user.mk andere opties worden meegegeven:

Makefile-user.mk

MODULES = app
SERIAL_BAUD_RATE = 115200
ESP_HOME = /opt/esp-open-sdk
SMING_HOME = /opt/Sming/Sming
SPI_SIZE = 247K
SPIFF_FILES = files
SPIFF_SIZE = 252928
RBOOT_ENABLED ?= 1
RBOOT_BIG_FLASH ?= 0
RBOOT_TWO_ROMS  ?= 1
SPI_SIZE        ?= 1M
RBOOT_ROM_0     ?= rom0
RBOOT_LD_0      ?= rom0.33.ld
RBOOT_ROM_1     ?= rom1
RBOOT_LD_1      ?= rom1.33.ld

RBOOT_ROM_X is de naam van het bestand waarin de rom wordt weggeschreven. In dit geval rom0.bin en rom1.bin.

RBOOT_LD_X is de naam van het link bestand. Hierin dien je aan te geven per rom waar deze in de 1MB pagina wordt geplaatst.

rom0.33.ld

/* Linker Script for rboot */

MEMORY
{
  dport0_0_seg :                        org = 0x3FF00000, len = 0x10
  dram0_0_seg :                         org = 0x3FFE8000, len = 0x14000
  iram1_0_seg :                         org = 0x40100000, len = 0x8000
  irom0_0_seg :                         org = 0x40202010, len = 0x4FF00
}

INCLUDE "../ld/common.ld"

Met irom0_0_seg geven we aan dat de rom start op 0x02010 met een maximale lengte van 0x4FF00 (waarom niet op 0x2000??? TODO uitzoeken). Vervolgens maken we ook een rom1.33.ld en daarin zetten we:

/* Linker Script for rboot */

MEMORY
{
  dport0_0_seg :                        org = 0x3FF00000, len = 0x10
  dram0_0_seg :                         org = 0x3FFE8000, len = 0x14000
  iram1_0_seg :                         org = 0x40100000, len = 0x8000
  irom0_0_seg :                         org = 0x40262010, len = 0x4FF00
}

INCLUDE "../ld/common.ld"

ESP: linker files

Tenslotte flashen we het geheel met:

./esptool.py --port /dev/ttyUSB0 write_flash -fs 8m \
        0x0000 firmware/rboot.bin \
        0x1000 0x1000.bin \
        0x02000 firmware/rom0.bin \
        0x62000 firmware/rom1.bin \
        0xc5000 firmware/spiff_rom.bin