ESP8266 building OTA firmware for 2MB boards

During the past weeks i’ve worked on getting the FOTA upgrades work on the 2MB boards by Olimex.

The wonderful esp-link project by Thorsten von Eicken was a great example of  two things:

  1. How to concatenate the espfs filesystem image with the firmware images.
  2. How to properly write a new image to the flash.

It was a nice example to start with.

So after a lot of fiddling with  Makefiles, cgi routines and esptool  – i’ve finally got the OTA working.

Gotchas:

  • esptool.py modifies the images when writting – you have to pass the correct options for the flash split you want to use. Why on earth it modifies a already correctly build images with app_genbin.py, when not requested too is subject to be discussed in another post.
  • When using 512 KB or 1024 KB flash the two firmware images are both mapped at 0x40200000 so when using user2.bin you need correct offset + 0x8000 for the 512KB case.
  • When using 1024KB images you do not need offset – second MB of the flash is mapped at 0x40200000 too. So no need to have offset and essentially that makes the user1.bin same as user2.bin /not tested yet/. But this means doing less builds and if you plan to distribute upgrades less content.
ifeq ("$(ESP_FLASH_SIZE)","512")
build/eagle.esphttpd.v6.ld: $(SDK_LDDIR)/eagle.app.v6.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
            $(SDK_LDDIR)/eagle.app.v6.ld >$@
build/eagle.esphttpd1.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.512.app1.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  irom0_0_seg/ s/2B000/38000/' \
            $(SDK_LDDIR)/eagle.app.v6.new.512.app1.ld >$@
build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  irom0_0_seg/ s/2B000/38000/' \
            $(SDK_LDDIR)/eagle.app.v6.new.512.app2.ld >$@

endif
ifeq ("$(ESP_FLASH_SIZE)","1024")
build/eagle.esphttpd.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld >$@
build/eagle.esphttpd1.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  irom0_0_seg/ s/6B000/7B000/' \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld >$@
build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  irom0_0_seg/ s/6B000/7B000/' \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld >$@

endif
ifeq ("$(ESP_FLASH_SIZE)","2048")
build/eagle.esphttpd.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld >$@
build/eagle.esphttpd1.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  iram1_0_seg/ s/8000/10000/' \
                        -e '/^  irom0_0_seg/ s/6B000/E0000/' \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app1.ld >$@
build/eagle.esphttpd2.v6.ld: $(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld
        $(Q) sed -e '/\.irom\.text/{' -e 'a . = ALIGN (4);' -e 'a *(.espfs)' -e '}'  \
                        -e '/^  iram1_0_seg/ s/8000/10000/' \
                        -e '/^  irom0_0_seg/ s/6B000/E0000/' \
                        -e '/^  irom0_0_seg/ s/40281010/40201010/' \
            $(SDK_LDDIR)/eagle.app.v6.new.1024.app2.ld >$@

endif

ifeq ("$(ESP_FLASH_SIZE)","512")
flash: all
$(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash \
0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \
0x7E000 $(SDK_BASE)/bin/blank.bin
endif

ifeq ("$(ESP_FLASH_SIZE)","1024")
flash: all
$(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash \
0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin \
0xfc000 $(SDK_BASE)/bin/blank.bin
endif

ifeq ("$(ESP_FLASH_SIZE)","2048")
flash: all
$(Q) $(ESPTOOL) --port $(ESPPORT) --baud $(ESPBAUD) write_flash \
0x00000 "$(SDK_BASE)/bin/boot_v1.4(b1).bin" 0x01000 $(FW_BASE)/user1.bin
# 0x1fe000 blank.bin
# 0x1FC000 esp_init_data_default.bin

endif

I’ve added  ESP_FLASH_SIZE variable to build correct linker scripts and flash commands. I’m working on a template project which will be available on github. But you’ve got the idea of how to do it. One nice addition i’m working on is the ability to have different output directories.

The other minor modification you will need is to properly initialize EspFs in your user_main and link the espfs_img.o in your final linking step.

Now there are two upgrade scenarios – user initiated for consumer devices and automatic for industrial deployment. And the two transports for them HTTP and MQTT. HTTP was easy, MQTT is next – stay tuned.

 

 

ESP8266 using different flash sizes – FOTA and Download tool

Which goes where – when using a bootloader for FOTA.

The files:

  • master_device_key.bin –  Obtained from Espressif Cloud
  • esp_init_data_default.bin – Stores default RF parameter values
  • boot.bin – bootloader
  • user1.bin and user2.bin – user firmware
  • blank.bin – blank settings , flash to get default parameters

1. 512KB

  • master_device_key.bin 0x3E000
  • esp_init_data_default.bin 0x7C000
  • blank.bin 0x7E000
  • boot.bin 0x00000
  • user1.bin 0x01000
  • user2.bin 0x41000

2. 1024KB Flash

  • master_device_key.bin 0x3E000
  • esp_init_data_default.bin 0xFC000
  • blank.bin 0xFE000
  • boot.bin 0x00000
  • user1.bin 0x01000
  • user2.bin 0x81000

3. 2048KB Flash

  • master_device_key.bin 0x3E000
  • esp_init_data_default.bin 0x1FC000
  • blank.bin 0x1FE000
  • boot.bin 0x00000
  • user1.bin 0x01000
  • user2.bin 0x81000

4. 4096KB Flash

  • master_device_key.bin 0x3E000
  • esp_init_data_default.bin 0x3FC000
  • blank.bin 0x3FE000
  • boot.bin 0x00000
  • user1.bin 0x01000
  • user2.bin 0x81000

 

How to use 1MB and above flash on espressif forum describes the use of download tool.

Here is what download tool does:

Options

  • Crystal Frequncy choices:  40Mhz, 26Mhz,  24Mhz – For a 40M crystal , the booting uart tx baud is 115200,(74880 for 26m accordinglyCrystal Freq will be set to the BYTE[48] of esp_init_data_default.bin
  • SPI Flash speed: 0 = 40MHz , 1 = 26.7MHz,  2 = 20MHz,  f = 80MHz  stored in BYTE[3]&0f of the images
  • SPI flash read mode: 0 = QIO, 1 = QOUT, 2=DIO, 3=DOUT  set to the 3rd BYTE at flash address 0x0 so it is BYTE[2].
  • Flash size: Flash size is SET to the higher 4bit of 4TH BYTE at flash address 0x0 which is BYTE[3]>>4)&0xf in the image:
    0:512KB(256KB+256KB)  – 4Mbit
    1:256KB – 2Mbit
    2:1MB(512KB+512KB) – 8Mbit
    3:2MB(512KB+512KB) – 16Mbit
    4:4MB(512KB+512KB) – 32Mbit
    5:2MB-C1(1024KB+1024KB) – 16Mbit
    6:4MB-C1(1024KB+1024KB) – 32Mbit

tout as vdd33 – esp_init_data_default.bin BYTE[107]  = 0xff

tout as adc – esp_init_data_default.bin BYTE[107]  = VDD*10 /vdd > 1.8 and vdd < 3.6/

Low power options are left out for now.

To be continued …