Git Product home page Git Product logo

rboot's Introduction

rBoot - An open source boot loader for the ESP8266

by Richard A Burton, [email protected] http://richard.burtons.org/

rBoot is designed to be a flexible open source boot loader, a replacement for the binary blob supplied with the SDK. It has the following advantages over the Espressif loader:

  • Open source (written in C).
  • Supports up to 256 roms.
  • Roms can be variable size.
  • Able to test multiple roms to find a valid backup (without resetting).
  • Flash layout can be changed on the fly (with care and appropriately linked rom images).
  • GPIO support for rom selection.
  • Wastes no stack space (SDK boot loader uses 144 bytes).
  • Documented config structure to allow easy editing from user code.
  • Can validate .irom0.text section with checksum.
  • Temporary next-boot rom selection.

Limitations

The ESP8266 can only map 8Mbits (1MB) of flash to memory, but which 8Mbits to map is selectable. This allows individual roms to be up to 1MB in size, so long as they do not straddle an 8Mbit boundary on the flash. This means you could have four 1MB roms or 8 512KB roms on a 32Mbit flash (such as on the ESP-12), or a combination. Note, however, that you could not have, for example, a 512KB rom followed immediately by a 1MB rom because the 2nd rom would then straddle an 8MBit boundary. By default support for using more than the first 8Mbit of the flash is disabled, because it requires several steps to get it working. See below for instructions.

Building

A Makefile is included, which should work with the gcc xtensa cross compiler. There are two source files, the first is compiled and included as data in the second. When run this code is copied to memory and executed (there is a good reason for this, see my blog for an explanation). The make file will handle this for you, but you'll need my esptool2 (see github).

To use the Makefile set SDK_BASE to point to the root of the Espressif SDK and either set XTENSA_BINDIR to the gcc xtensa bin directory or include it in your PATH. These can be set as environment variables or by editing the Makefile.

Two small assembler stub functions allow the bootloader to launch the user code without reserving any space on the stack (while the SDK boot loader uses 144 bytes). This compiles fine with GCC, but if you use another compiler and it will not compile/work for you then uncomment the #define BOOT_NO_ASM in rboot.h to use a C version of these functions (this uses 32 bytes).

Tested with SDK v2.2 and GCC v4.8.5.

Installation

Simply write rboot.bin to the first sector of the flash. Remember to set your flash size correctly with your chosen flash tool (e.g. for esptool.py use the -fs option). When run rBoot will create it's own config at the start of sector two for a simple two rom system. You can can then write your two roms to flash addresses 0x2000 and (half chip size + 0x2000). E.g. for 8Mbit flash: esptool.py write_flash -fs 8m 0x0000 rboot.bin 0x2000 user1.bin 0x82000 user2.bin

Note: your device may need other options specified. E.g. The nodemcu devkit v1.0 (commonly, but incorrectly, sold as v2) also needs the -fm dio option.

For more interesting rom layouts you'll need to write an rBoot config sector manually, see next step.

The two testload bin files can be flashed in place of normal user roms for testing rBoot. You do not need these for normal use.

rBoot Config

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

Write a config structure as above to address 0x1000 on the flash. If you want more than 4 roms (default) just increase MAX_ROMS when you compile rBoot. Think about how you intend to layout your flash before you start! Rom addresses must be sector aligned i.e start on a multiple of 4096.

  • magic should have value 0xe1 (defined as BOOT_CONFIG_MAGIC).
  • version is used in case the config structure changes after deployment. It is defined as 0x01 (BOOT_CONFIG_VERSION). I don't intend to increase this, but you should if you choose to reflash the bootloader after deployment and the config structure has changed.
  • mode can be 0x00 (MODE_STANDARD) or 0x01 (MODE_GPIO_ROM). See below for an explanation of MODE_GPIO_ROM. There is also an optional extra mode flag 0x04 (MODE_GPIO_ERASES_SDKCONFIG), see below for details.
  • current_rom is the rom to boot, numbered 0 to count-1.
  • gpio_rom is the rom to boot when the GPIO is triggered at boot.
  • count is the number of roms available (may be less than MAX_ROMS, but not more).
  • unused[2] is padding so the uint32_t rom addresses are 4 bytes aligned.
  • roms is the array of flash address for the roms. The default generated config will contain two entries: 0x00002000 and 0x00082000.
  • chksum (if enabled, not by deafult) should be the xor of 0xef followed by each of the bytes of the config structure up to (but obviously not including) the chksum byte itself.

Default config

A default config sector will be created on boot if one does not exists, or if an existing config is corrupted, and the default rom will be set to rom 0. If you want to have a very customised config for which the default would not be suitable, you can override the implementation in the rboot.h header file. See the comments and example code in rboot.h for more information.

GPIO boot mode

If rBoot is compiled with BOOT_GPIO_ENABLED set in rboot.h (or RBOOT_GPIO_ENABLED set in the Makefile), then GPIO boot functionality will be included in the rBoot binary. The feature can then be enabled by setting the rboot_config mode field to MODE_GPIO_ROM. You must also set gpio_rom in the config to indicate which rom to boot when the GPIO is activated at boot.

If the GPIO input pin reads high at boot then rBoot will start the currently selected normal or temp rom (as appropriate). However if the GPIO is pulled low then the rom indicated in config option gpio_rom is started instead.

The default GPIO is 16, but this can be overriden in the Makefile (RBOOT_GPIO_NUMBER) or rboot.h (BOOT_GPIO_NUM). If GPIOs other than 16 are used, the internal pullup resistor is enabled before the pin is read and disabled immediately afterwards. For pins that default on reset to configuration other than GPIO input, the pin mode is changed to input when reading but changed back before rboot continues.

After a GPIO boot the current_rom field will be updated in the config, so the GPIO booted rom should change this again if required.

GPIO boot skip mode

If rBoot is compiled with BOOT_GPIO_SKIP_ENABLED set in rboot.h (or RBOOT_GPIO_SKIP_ENABLED set in the Makefile), then a GPIO can be used to skip to the next rom at boot. The feature must then be enabled by setting the rboot_config 'mode' field to MODE_GPIO_SKIP. This means you do not need to have a dedicated GPIO boot rom. If you have a rom that is technically good (valid checksum, etc.) but has operational problems, e.g. wifi doesn't work or it crashes on boot, rBoot will not be able to detect that and switch rom automatically. In this scenario rebooting the device while pulling the GPIO low will force rBoot to skip this rom and try the next one instead. In a simple two rom setup this simply toggles booting of the other rom.

RBOOT_GPIO_SKIP_ENABLED and RBOOT_GPIO_ENABLED cannot be used at the same time. BOOT_GPIO_NUM is used to select the GPIO pin, as with RBOOT_GPIO_ENABLED.

Erasing SDK configuration on GPIO boot (rom or skip mode)

If you set the MODE_GPIO_ERASES_SDKCONFIG flag in the configuration like this: conf.mode = MODE_GPIO_ROM|MODE_GPIO_ERASES_SDKCONFIG; then a GPIO boot will also the erase the Espressif SDK persistent settings store in the final 16KB of flash. This includes removing calibration constants, saved SSIDs, etc.

Note that MODE_GPIO_ERASES_SDKCONFIG is a flag, so it has to be set as well as MODE_GPIO_ROM to take effect.

Linking user code

Each rom will need to be linked with an appropriate linker file, specifying where it will reside on the flash. If you are only flashing one rom to multiple places on the flash it must be linked multiple times to produce the set of rom images. This is the same as with the SDK loader.

Because there are endless possibilities for layout with this loader I don't supply sample linker files. Instead I'll tell you how to make them.

For each rom slot on the flash take a copy of the eagle.app.v6.ld linker script from the sdk. You then need to modify just one line in it for each rom: irom0_0_seg : org = 0x40240000, len = 0x3C000

Change the org address to be 0x40200000 (base memory mapped location of the flash) + flash address + 0x10 (offset of data after the header). The logical place for your first rom is the third sector, address 0x2000. 0x40200000 + 0x2000 + 0x10 = 0x40202010 If you use the default generated config the loader will expect to find the second rom at flash address half-chip-size + 0x2000 (e.g. 0x82000 on an 8MBit flash) so the irom0_0_seg should be: 0x40200000 + 0x82000 + 0x10 = 0x40282010 Due to the limitation of mapped flash (max 8MBit) if you use a larger chip and do not have big flash support enabled the second rom in the default config will still be placed at 0x082000, not truly half-chip-size + 0x2000. Ideally you should also adjust the len to help detect over sized sections at link time, but more important is the overall size of the rom which you need to ensure fits in the space you have allocated for it in your flash layout plan.

Then simply compile and link as you would normally for OTA updates with the SDK boot loader, except using the linker scripts you've just prepared rather than the ones supplied with the SDK. Remember when building roms to create them as 'new' type roms (for use with SDK boot loader v1.2+). Or if using my esptool2 use the -boot2 option. Note: the test loads included with rBoot are built with -boot0 because they do not contain a .irom0.text section (and so the value of irom0_0_seg in the linker file is irrelevant to them) but 'normal' user apps always do.

irom checksum

The SDK boot loader checksum only covers sections loaded into ram (data and some code). Most of the SDK and user code remains on the flash and that is not included in the checksum. This means you could attempt to boot a corrupt rom and, because it looks ok to the boot loader, there will be no attempt to switch to a backup rom. rBoot improves on this by allowing the .irom0.text section to be included in the checksum. To enable this uncomment #define BOOT_IROM_CHKSUM in rboot.h and build your roms with esptool2 using the -iromchksum option.

Big flash support

This only needs to be enabled if you wish to be able to memory map more than the first 8MBit of the flash. Note you can still only map 8Mbit at a time. Use this if you want to have multiple 1MB roms, or more smaller roms than will fit in 8Mbits. If you have a large flash but only need, for example, two 512KB roms you do not need to enable this mode.

Support in rBoot is enabled by uncommenting the #define BOOT_BIG_FLASH in rboot.h.

Thinking about your linker files is either simpler or more complicated, depending on your usage of the flash. If you intend to use multiple 1MB roms you will only need one linker file and you only need to link once for OTA updates. Although when you perform an OTA update the rom will be written to a different position on the flash, each 8Mbit of flash is mapped (separately) to 0x40200000. So when any given rom is run the code will appear at the same place in memory regardless of where it is on the flash. Your base address for the linker would be 0x40202010. (Actually all but the first rom could base at 0x40200010 (because they don't need to leave space for rBoot and config) but then you're just making it more complicated again!)

If you wanted eight 512KB roms you would need two linker files - one for the first half of any given 8Mbits of flash and another for the second half. Just remember you are really laying out within a single 8MBit area, which can then be replicated multiple times on the flash.

Now the clever bit - rBoot needs to hijack the memory mapping code to select which 8Mbits gets mapped. There is no API for this, but we can override the SDK function. First we need to slightly modify the SDK library libmain.a, like so:

xtensa-lx106-elf-objcopy -W Cache_Read_Enable_New libmain.a libmain2.a

This produces a version of libmain with a 'weakened' Cache_Read_Enable_New function, which we can then override with our own. Modify your Makefile to link against the library main2 instead of main.

Next add rboot-bigflash.c (from the appcode directory) & rboot.h to your project - this adds the replacement Cache_Read_Enable_New to your code.

Getting gcc to apply the override correctly can be slightly tricky (I'm not sure why, it shouldn't be). One option is to add -u Cache_Read_Enable_New to your LD_FLAGS and change the order of objects on the LD command so your objects/.a file is before the libraries. Another way that seems easier was to #include rboot-bigflash.c into the main .c file, rather than compiling it to a separate object file. I can't make any sense of that, but I suggest you uncomment the message in the Cache_Read_Enable_New function when you first build with it, to make sure you are getting your version into the rom.

Now when rBoot starts your rom, the SDK code linked in it that normally performs the memory mapping will delegate part of that task to rBoot code (linked in your rom, not in rBoot itself) to choose which part of the flash to map.

Temporary boot option and rBoot<-->app communication

To enable communication between rBoot and your app you should enable the BOOT_RTC_ENABLED option in rboot.h. rBoot will then use the RTC data area to pass a structure with boot information which can be read by the app. This will allow the app to determine the boot mode (normal, temporary or GPIO) and the booted rom (even if it is a tempoary boot). Your app can also update this structure to communicate with rBoot when the device is next rebooted, e.g. to instruct it to temporarily boot a different rom to the one saved in the config. See the api documentation and/or the rBoot sample project for more details. Note: the message "don't use rtc mem data", commonly seen on startup, comes from the sdk and is not related to this rBoot feature.

Integration into other frameworks

If you wish to integrate rBoot into a development framework (e.g. Sming) you can set the define RBOOT_INTEGRATION and at compile time the file rboot-integration.h will be included into the source. This should allow you to set some platform specific options without having to modify the source of rBoot which makes it easier to integrate and maintain.

rboot's People

Contributors

alltheblinkythings avatar djphoenix avatar eriksl avatar jacmet avatar kanflo avatar mikee47 avatar ourairquality avatar patrickjahns avatar projectgus avatar raburton avatar riban-bw avatar samvrlewis avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rboot's Issues

Potential for flash corruption...

Here's a neat issue we've run into with our live devices using rboot. If the device loses power when rboot is writing to flash, it's possible for write to be incomplete. Basically if flash erase happens and power is lost before write then flash is left in the erased state.

It's a rare problem -- 1 : 1000 so far. But it has happened. Only way I can see this being worked around is to have two copies of the configuration and double-buffer them.

Can this codebase be used with ESP8266_NON_OS SDK for OTA ?

Hi,
Can this codebase be used for OTA with ESP8266_NON_OS SDK ?
I am using a 16Mbits flash version of ESP8266 , with two OTA partitions. OTA1 at address 0x1000 and OTA2 at address 0x81000. Both partitions have a size of 0x6A000 ( 434.176 KB ). I am not using rboot bootloader. I have already done a lot of work for my product and only stuck with OTA. I tried this code base , but it is failing at the writing to the flash part, probably fetching wrong address when i call the function rboot_get_config() . Can anyone help me out with this ?

big flash help

First of all please can you write maximum ota flash size?

I want to flash a 666k bin

1-I am using https://github.com/SuperHouse/esp-open-rtos/blob/master/examples/http_client_ota/http_get.c example (265k updater)

2-Rboot of https://github.com/SuperHouse/esp-open-rtos didnt work so i am using https://github.com/apiel/aboot/blob/master/aboot/aboot.h @apiel

SuperHouse/esp-open-rtos#668 (comment)

3-I was using 2 steps update with arduino. https://github.com/xoseperez/espurna/wiki/TwoStepUpdates

2 steps update :
1-Trigger update with normal 666k firmware.
2-Get an 265k updater firmware.
3-265k updater will get new 667k firmware

Will it work with rboot?

4-Last log SuperHouse/esp-open-rtos#727

SPIEraseSector at position 0x15e000 sector 350
SPIEraseSector at position 0x15f000 sector 351
Writing default boot config.
Header size: 632064
Booting at ram 640256.
sp 0x3ffff710
epc1=0x40001800, epc2=0x00000000, epc3=0x00000000, excvaddr=0xffffffef, depc=0x00000000
Fatal exception (28):
epc1=0x40001800, epc2=0x00000000, epc3=0x00000000, excvaddr=0x00007ff0, depc=0x00000000
Fatal exception (28):

I am open to use arduino ota update but i must switch back to esp-open-rtos also i dont how to make it

Thanks for any help.

Request: documentation of firmware format

Hi there. I trying to implement firmware generation without esptool2 binary. Now I stuck in firmware header format, so, if you can provide well-documented headers description (and so procedure of checksum generation), it will be great point.

So "hex2" header are already done with:

$(RBOOT_BUILD_BASE)/rboot-hex2a.h: $(RBOOT_BUILD_BASE)/rboot-stage2a.elf
  @ mkdir -p $(dir $@)
  @ rm -f $@
  @ $(OBJDUMP) -f $< | grep 'start address' | awk '{print "const uint32 entry_addr = " $$3 ";"}' >> $@
  @ $(OBJDUMP) -j .text -h $< | grep ' .text ' | awk '{print "const uint32 _text_addr = 0x" $$4 ";"}' >> $@
  @ $(OBJDUMP) -j .text -h $< | grep ' .text ' | awk '{print "const uint32 _text_len  = 0x" $$3 ";"}' >> $@
  @ echo 'const uint8  _text_data[] = {' >> $@
  @ $(OBJCOPY) --dump-section .text=/dev/stdout $< | xxd -i >> $@
  @ echo '};' >> $@

I will make PR for all no-esptool2-related stuff after done.

How update rboot.bin over the air

Hi.

I have some devices with rboot version v1.3.0.
I build a new firmware with rboot version v1.4.1 (SDK 1.5.4) and I updated the rom0 and rom1 over the air.
But the devices with old rboot.bin version does not change SSID/Password for Station Mode with command "wifi_station_set_config".

Someone can help me?

The device with rboot.bin version v1.4.1 works very well.

I changed the code with this suggestion (without success):
http://bbs.espressif.com/viewtopic.php?f=7&t=1085

ElF file bootrom.bin "no such file or directory: bootrom.bin" Ubuntu

Hi Richard,

Hope you can help.
I´m trying to generate ELF file from my code, to find out any breach on it, following the orientation below
OK: import esp_bin2elf
Ok: import flash_layout
Ok: flash_layout = flash_layout.layout_without_ota_updates
Ok: rom = esp_bin2elf.parse_rom('flashdump.bin', 'path/to/flashdump.bin', flash_layout)
Ok: section_names = esp_bin2elf.name_sections(rom)
Fail: elf = esp_bin2elf.convert_rom_to_elf(rom, section_names, 'flash_bin.elf')
error: "no such file or directory: bootrom.bin"

I have changed directory, permissions etc, but no one resolved.]
May i use bootrom.bin from the code or should i generate a new one ?
Than you!

RBOOT SDK 3.1

Having finally gotten RBOOT and my ESP-GO code running on ESP SDK 3.1 - I'm occasionally getting E.M.5832 - which results in a safe OTA failure... next time it usually works.... is there anything I can do to narrow down why I'm sometimes seeing this memory error?

Error in checksum calculation?

Hi,
I had worked a lot you your great code (but also I've made some mess in...), and I was looking to what seem be a miscalculation in the checksum. Actually I have a mismatch between the checksum calculated by rboot and the one calculated from esptool.py. Seems the latter doesn't consider the first segment in checksum calculation. Here the results from a modified esptool (for log):
./esptool.py --chip esp8266 image_info ../../firmware/firmware.bin
Entry point: 4010023c
4 segments

Segment 1: len 0xc1530 load 0x00000000 file_offs 0x00000008
Segment 2: len 0x077b4 load 0x40100000 file_offs 0x000c1548
Segment 3: len 0x00cf4 load 0x3ffe8000 file_offs 0x000c8d04
Segment 4: len 0x019bc load 0x3ffe8cf8 file_offs 0x000c9a00
Seg: 0 -> seg.include_in_checksum: 0. DataLen: 0xc1530
Checksum: 0xef
Seg: 1 -> seg.include_in_checksum: 1. DataLen: 0x77b4
Checksum: 0x56
Seg: 2 -> seg.include_in_checksum: 1. DataLen: 0xcf4
Checksum: 0x66
Seg: 3 -> seg.include_in_checksum: 1. DataLen: 0x19bc
Checksum: 0x76
Checksum: 76 (valid)

As you can see the first segment is excluded from calculation.
Doing the same with your code, i.e. adding:
if (sectcurrent!=0)
{
for (loop = 0; loop < readlen; loop++) {
chksum ^= buffer[loop];
}
}
seems set everything ok.

What do you think?

Rgds,

--gra

rboot for esp arduio lib

sorry to open ticket for my question, but I found your reference link on some of pages, I was wondering whether your lib can officially merge to the Arduino ESP8266 lib so could have your lib benefit in Arduio environmental

IRAM usage (question)

This is more like a question. I've been using rboot for over two years now, and works like a charm. But there is one thing I can't get my head around. My images are quite tight on IRAM usage (and yes, believe me, I do already use all kinds of tricks to free up the max of it, some code, e.g. timing dependend code, just need IRAM).

I now have between 1400 and sometimes 200 bytes IRAM free (but if it becomes this low, I always immediately free up some).

My question is, how much of the IRAM is used by rboot. I've tried various methods to find out, all with different results, so not very reliable I guess. Or better: how many bytes of the IRAM are required to remain free for rboot to run in? Can you maybe add a function to report this value to the image/user? Or if it could be calculated (start address + length), I could create a dummy entry in the loader script, or make the iram region smaller accordingly, then the loader would already notice any overrun (and report).

Having said this, maybe it's possible to load the code into the SPI caching area, which, AFAIK is not used/mapped at this stage, which means 32 kbytes free to use :-)

Thanks!

Support for SDK 2.0.0 (esp-open-sdk)

Hi.

We use rboot (27/Jul/2016) with SDK 1.5.4, works wery well.
After update to SDK 2.0.0 and rboot (last version), the rboot does not switch between roms (0 and 1).
Every boot start on rom 1.

What is wrong?

don't use rtc mem data

After rBoot runs and loads a ROM, the ESP8266 prints "don't use rtc mem data" to its serial port. A quick search of Google suggests this may be a warning that RTC memory has been corrupted but I haven't investigated far.

Slow boot

When using rBoot the booting time is roughly 7 times higher.

I used the Basic_Blink example in Sming.
Without rBoot, the boot time is ~ 300 ms
With rBoot and with/or without RTC_ENABLED the boot time is ~2300 ms

Any ideas why is that happening ?

Makefile correct SPI_SPEED?

ifeq ($(SPI_SPEED), 20)
E2_OPTS += -20
else ifeq ($(SPI_MODE), 26)
E2_OPTS += -26.7
else ifeq ($(SPI_MODE), 40)
E2_OPTS += -40
else ifeq ($(SPI_MODE), 80)
E2_OPTS += -80
endif

Issue with mapping of 1MB ROM

I have been used rBoot and two 512k+512k ROM OTA. However now 512kB ROM is not enough for our project, so I tried to use RBOOT_BIG_FLASH case. I changed the makefile in order to weak Cache_Read_Enable_New() and add the alternative one.
However, if I flash ROM0 and ROM1 (at 0x2000 and 0x102000 respectively) and command rBoot to start ROM1 it does start and work fine. However, if I remove ROM0 the firmware crashes after some time after starting. It seems that there is some problem with mapping because of the issue occurs in the case when ROM0 and ROM1 differs.
Could anybody explain this issue?

I'm using RTOS SDK1.5 and I didn't try this with RTOS SDK1.3-1.4.

RBOOT NONOS SDK 3.1

As original issue seems closed, you may recall you kindly re-wrote the flash-write section of RBOOT to get over the unreliability I was (am) suffering only with RBOOT or rather with OTA using SDK 3.1 - the changes produced a reboot on use. Did you get a chance to look at this?

I put in your new flash write routine (a couple of weeks ago, I've been travelling since so sorry if I missed anything) and on trying OTA, the Raspberry Pi 3 crashed and rebooted immediately. It does this every time.

For clarity, the original RBOOT code works perfectly every time with SDK 2.1

With SDK 3.1 all aspects of my code work perfectly except RBOOT/OTA which works sometimes and fails other times (not crashing, simply failing to OTA). With the new flash write code and SDK 3.1, OTA attempts produce an immediate reboot every time.

Pete

How to execute large application bin files

Hi,
I am using ESP-12F it has 4MBytes SPI FLASH, looking for firmware upgrade OTA.
I found your boot loader is capable of handling the images whose size is upto 512kBytes. I have a problem, I want to execute even large images on ESP.
My application bin size (user1.4096.new.6.bin is 512kBytes, eagle.irom0text.bin is 260KBytes) is larger than the OTA enabled bin (64KB /180KB) size. So my application is not running.

How can I change the application and library bin size limitations? Is it possible to update the boot loader so that I can change the mapping?

Please suggest me how to proceed further.

Read firmware with bigger chunks and without temp buffer

I see that in stage2 you're use temporary buffer of size 0x100. The reason of this is unknown for me, but with this patch it is keeps to work for me (much faster):

diff --git a/rboot-stage2a.c b/rboot-stage2a.c
index 9df98a8..2b2a5a4 100644
--- a/rboot-stage2a.c
+++ b/rboot-stage2a.c
@@ -42,13 +42,10 @@ usercode* NOINLINE load_rom(uint32 readpos) {
                
                while (remaining > 0) {
                        // work out how much to read, up to 16 bytes at a time
-                       uint32 readlen = (remaining < BUFFER_SIZE) ? remaining : BUFFER_SIZE;
+                       uint32 readlen = (remaining < 0x1000) ? remaining : 0x1000;
                        // read the block
-                       SPIRead(readpos, buffer, readlen);
+                       SPIRead(readpos, writepos, readlen);
                        readpos += readlen;
-                       // copy the block
-                       ets_memcpy(writepos, buffer, readlen);
-                       // increment next write position
                        writepos += readlen;
                        // decrement remaining count
                        remaining -= readlen;

Can you describe why you're use this buffer?

And, so, with union you can keep some space if one of header is less than 0x100 bytes:

diff --git a/rboot-stage2a.c b/rboot-stage2a.c
index 9df98a8..c9fd1cb 100644
--- a/rboot-stage2a.c
+++ b/rboot-stage2a.c
@@ -13,14 +13,18 @@
 
 usercode* NOINLINE load_rom(uint32 readpos) {
        
-	uint8 buffer[BUFFER_SIZE];
+	union {
+		rom_header rom;
+		section_header section;
+	} buffer;

        uint8 sectcount;
        uint8 *writepos;
        uint32 remaining;
        usercode* usercode;
        
-	rom_header *header = (rom_header*)buffer;
-	section_header *section = (section_header*)buffer;
+	rom_header *header = &buffer.rom;
+	section_header *section = &buffer.section;
        
        // read rom header
        SPIRead(readpos, header, sizeof(rom_header));

Bootloader restore

Hi,just want to ask a question,sorry first of all for posting hear,I want to restore the bootloader on my esp8266,it seems that its corrupt or something like that,i dont realy understand the esp at all,ime used to 328p and attiny85 etc,now i understand that the bootloader sits in the flash unit that resides next to the esp chip, am i right? also i cant find a bootloader bin thats allready compiled,also if the bootloader is broken how do i fix it,dont i need a bootloader on the esp to add a bootloader? i mean how do i get it into the bootloader mode if its broke,or does the flash need to be taken of and flashed using another method? also have you a compiled bootloader i can try? any will do i just want to try save my nodemcu.Thanks

failure selecting boot rom

I'm not sure this is an 'issue' the way it's meant, but I'm getting this a lot recently (using SMING):


 ets Jan  8 2013,rst cause:1, boot mode:(3,6)

load 0x40100000, len 1220, room 16
tail 4
chksum 0xda
load 0x3ffe8000, len 640, room 4
tail 12
chksum 0xa8
csum 0xa8

rBoot v1.4.2 - [email protected]
Flash Size:   32 Mbit
Flash Mode:   DIO
Flash Speed:  40 MHz

Resetting boot config.
Invalid rom selected, defaulting to 0.
Rom 0 at 0 is bad.
Rom -1 at 0 is bad.
Rom -1 at 0 is bad.
Rom -1 at 0 is bad.

What I have tried:

  • re-flashing the app - no change
  • make flashinit to clean the flash and then re-flashing the app - no change
  • try a brand new ESP8266 - no change in one case and success in another.

I have had odd issues of having to re-boot the esp numerous times but since I've mostly been using a serial speed of 460800baud, all I saw is unprintable characters filling the screen. I assume this is an intermittend issue, sometimes clearing itself with a few re-boots, or rather, I should say, in some cases, it happens in four out of five boots, in other cases, it happens in every boot in a resonable number of tries.

I have mostly suspected worn out flash cells, but this latest occurence is, as said, on a fresh out of the package ESP. I have many more and will try others, but if yo have any other explanation, I would be glad to hear that.

Oh, just for completenes: here's my hwconfig:

make hwconfig

esp_rgbww_firmware: Invoking 'hwconfig' for Esp8266 (debug) architecture

{
    "name": "Two ROM slots with single SPIFFS",
    "comment": "",
    "arch": "Esp8266",
    "options": [
        "4m",
        "spiffs"
    ],
    "bootloader_size": "8K",
    "partition_table_offset": "0x003fa000",
    "devices": {
        "spiFlash": {
            "type": "flash",
            "size": "4M",
            "mode": "dio",
            "speed": 40
        }
    },
    "partitions": {
        "rom0": {
            "device": "spiFlash",
            "address": "0x00002000",
            "size": "992K",
            "type": "app",
            "subtype": "ota_0",
            "readonly": false,
            "encrypted": false,
            "filename": "$(RBOOT_ROM_0_BIN)",
            "unused_before": 0,
            "unused_after": 0
        },
        "rom1": {
            "device": "spiFlash",
            "address": "0x00102000",
            "size": "992K",
            "type": "app",
            "subtype": "ota_1",
            "readonly": false,
            "encrypted": false,
            "filename": "$(RBOOT_ROM_0_BIN)",
            "unused_before": 0,
            "unused_after": 0
        },
        "spiffs0": {
            "device": "spiFlash",
            "address": "0x00200000",
            "size": "512K",
            "type": "data",
            "subtype": "spiffs",
            "readonly": false,
            "encrypted": false,
            "filename": "$(SPIFF_BIN_OUT)",
            "build": {
                "target": "spiffsgen",
                "files": "$(SPIFF_FILES)"
            },
            "unused_before": 0,
            "unused_after": 0
        },
        "rf_cal": {
            "device": "spiFlash",
            "address": "0x003fb000",
            "size": "4K",
            "type": "data",
            "subtype": "rfcal",
            "readonly": false,
            "encrypted": false,
            "filename": "",
            "unused_before": 0,
            "unused_after": 0
        },
        "phy_init": {
            "device": "spiFlash",
            "address": "0x003fc000",
            "size": "4K",
            "type": "data",
            "subtype": "phy",
            "readonly": false,
            "encrypted": false,
            "filename": "$(FLASH_INIT_DATA)",
            "unused_before": 0,
            "unused_after": 0
        },
        "sys_param": {
            "device": "spiFlash",
            "address": "0x003fd000",
            "size": "12K",
            "type": "data",
            "subtype": "sysparam",
            "readonly": false,
            "encrypted": false,
            "filename": "",
            "unused_before": 0,
            "unused_after": 0
        }
    }
}

4MB vs 1MB - simple blink app rom switch

I have 2 simple blink app which switches roms.

Nodemcu works fine but same blink apps dont work on esp01 or sonoff dualr2

flash for 32m (4MB) with qio - blink 2 is on 0x202000

esptool.py -p /dev/cu.SLAB_USBtoUART --baud 115200 write_flash -fs 4MB -fm qio -ff 40m \
		0x0 ../../bootloader/firmware/rboot.bin 0x2000 ./firmware/blink.bin  0x202000 ../../bootloader/firmware_prebuilt/blink.bin

flash for 8m (1MB) with dout - blink 2 is on 0x82000

esptool.py -p /dev/cu.usbserial-A7012RPU --baud 115200 write_flash -fs 1MB -fm dout -ff 40m \
		0x0 ../../bootloader/firmware/rboot.bin 0x2000 ./firmware/blink.bin  0x82000 ../../bootloader/firmware_prebuilt/blink.bin
ESP01 SERIAL

ESP-Open-SDK ver: 0.0.1 compiled @ Aug 22 2019 13:06:16
phy ver: 273, pp ver: 8.3

mode : softAP(62:01:94:9e:85:88)
add if1
bcn 100
BLINK BLINK say : 0
BLINK BLINK say : 1
BLINK BLINK say : 2
BLINK BLINK say : 3
BLINK BLINK say : 4
BLINK BLINK say : 5
BLINK BLINK say : 6
BLINK BLINK say : 7
blınk magic : 225
version : 1
mode : 0
current_rom : 0
gpio_rom : 0
count : 2
blınk rboot_get_current_rom : 0
blınk SAVED   rboot_set_config
blınk rboot_get_current_rom : 1
bcn 0
del if1
usl
sul 0 0

ets Jan  8 2013,rst cause:1, boot mode:(3,7)

load 0x3ffe8000, len 680, room 16
tail 8
chksum 0x40
load 0x40100000, len 1548, room 0

0x40100000: _stext at ??:?

tail 12
chksum 0x37
csum 0x37

rBoot v1.4.2 - [email protected]
Flash Size:   8 Mbit
Flash Mode:   DOUT
Flash Speed:  40 MHz
rBoot Option: RTC data

Booting rom 1 at 82000, load addr b86a0.
//STOPS HERE BUT NODEMCU CONTINUE TO ROM 0 

blink 1

#include <stdlib.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"

#include "rboot-integration.h"
#include <rboot-api.h>

const int gpio = 13;

void blinkenTask(void *pvParameters)
{
  int say = 0;

    gpio_enable(gpio, GPIO_OUTPUT);
    while(1) {

      printf("BLINK BLINK say : %d \n", say);


      gpio_write(gpio, 1);
      vTaskDelay(600 / portTICK_PERIOD_MS);
      gpio_write(gpio, 0);
      vTaskDelay(600 / portTICK_PERIOD_MS);


      say ++;
      if(say>7 )
      {
        rboot_config conf;
        conf = rboot_get_config();

        printf("blınk magic : %d \n", conf.magic);
        printf("version : %d \n", conf.version);
        printf("mode : %d \n", conf.mode);
        printf("current_rom : %d \n", conf.current_rom);
        printf("gpio_rom : %d \n", conf.gpio_rom);
        printf("count : %d \n", conf.count);
        printf("blınk rboot_get_current_rom : %d \n", rboot_get_current_rom());

        if(rboot_get_current_rom())
        {
          conf.current_rom = 0;
        }
        else
        {
          conf.current_rom = 1;
        }
        if(rboot_set_config(&conf))
        {
          printf("blınk SAVED   rboot_set_config   \n");
        }
        else {
          printf("blınk FAILED   rboot_set_config   \n");
        }

            printf("blınk rboot_get_current_rom : %d \n", rboot_get_current_rom());
            sdk_system_restart();
      }


  } //while END
}

void blinkenRegisterTask(void *pvParameters)
{
    GPIO.ENABLE_OUT_SET = BIT(gpio);
    IOMUX_GPIO2 = IOMUX_GPIO2_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */
    while(1) {
        GPIO.OUT_SET = BIT(gpio);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        GPIO.OUT_CLEAR = BIT(gpio);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void user_init(void)
{
    uart_set_baud(0, 115200);
    xTaskCreate(blinkenTask, "blinkenTask", 256, NULL, 2, NULL);
    //xTaskCreate(blinkenRegisterTask, "blinkenRegisterTask", 256, NULL, 2, NULL);
}

blink 2

#include <stdlib.h>
#include "espressif/esp_common.h"
#include "esp/uart.h"
#include "FreeRTOS.h"
#include "task.h"
#include "esp8266.h"

#include "rboot-integration.h"
#include <rboot-api.h>
 
const int gpio = 13;

void blinkenTask(void *pvParameters)
{
  int say = 0;

    gpio_enable(gpio, GPIO_OUTPUT);
    while(1) {
      printf("OK OK OK ");
      printf("BLINK2 say : %d \n", say);

      gpio_write(gpio, 1);
      vTaskDelay(2000 / portTICK_PERIOD_MS);
      gpio_write(gpio, 0);
      vTaskDelay(2000 / portTICK_PERIOD_MS);


      say ++;

      if(say>9 )
      {
              rboot_config conf;
              conf = rboot_get_config();

              printf("BLINK2 magic : %d \n", conf.magic);
              printf("version : %d \n", conf.version);
              printf("mode : %d \n", conf.mode);
              printf("current_rom : %d \n", conf.current_rom);
              printf("gpio_rom : %d \n", conf.gpio_rom);
              printf("count : %d \n", conf.count);
              printf("BLINK2 rboot_get_current_rom : %d \n", rboot_get_current_rom());

              if(rboot_get_current_rom())
              {
                conf.current_rom = 0;

              }
              else
              {
                conf.current_rom = 1;

              }

              if(rboot_set_config(&conf))
              {
                printf("BLINK2 SAVED   rboot_set_config   \n");
              }
              else {
                printf("BLINK2 FAILED   rboot_set_config   \n");
              }

                  printf("BLINK2 rboot_get_current_rom : %d \n", rboot_get_current_rom());
                  sdk_system_restart();

        }


    }
}


void blinkenRegisterTask(void *pvParameters)
{
    GPIO.ENABLE_OUT_SET = BIT(gpio);
    IOMUX_GPIO2 = IOMUX_GPIO2_FUNC_GPIO | IOMUX_PIN_OUTPUT_ENABLE; /* change this line if you change 'gpio' */
    while(1) {
        GPIO.OUT_SET = BIT(gpio);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
        GPIO.OUT_CLEAR = BIT(gpio);
        vTaskDelay(1000 / portTICK_PERIOD_MS);
    }
}

void user_init(void)
{
    uart_set_baud(0, 115200);
    xTaskCreate(blinkenTask, "blinkenTask", 256, NULL, 2, NULL);
    //xTaskCreate(blinkenRegisterTask, "blinkenRegisterTask", 256, NULL, 2, NULL);

}

Is there a special file (eagle.rom.addr.v6.ld -rboot-stage2a.ld -eagle.app.v6.ld) for 1MB ?

Random hang during power on

In my device environment, there are chances that ESP8266's bootloader (rboot) locked in a state that it is not loading any rom, and cannot be recovered by reset. To recover it from the error state, I need to remove the power souce and do a power cycle again.

The root cause is that during the boot process, rboot looked at the RTC memory area, since the application code is not there yet, the content in the RTC area is uninitialized. Rboot check the chksum value, idelly it should most likely failed due to random data content in memory, but the reality is that the chksum value sometimes return OK and rboot go ahead read the garbage in the rtc area, and read the wrong rom info. This is not recovable because app code is never loaded to update the RTC value, and without power cycle the RTC value is never changed, rboot is stuck in the cycle reading the same error content.

To fix it, I propose rboot should flush out the RTC memory area when detecting this situation, and jumpt to the normal standard boot mode.

> diff --git a/rboot.c b/rboot.c
> index 0e95db5..e4a3ce7 100644
> --- a/rboot.c
> +++ b/rboot.c
> @@ -386,11 +386,16 @@ uint32 NOINLINE find_image(void) {
> 	// if rtc data enabled, check for valid data
> 	if (system_rtc_mem(RBOOT_RTC_ADDR, &rtc, sizeof(rboot_rtc_data), RBOOT_RTC_READ) &&
> 		(rtc.chksum == calc_chksum((uint8*)&rtc, (uint8*)&rtc.chksum))) {
>                 if (rtc.next_mode & MODE_TEMP_ROM) {
>                         if (rtc.temp_rom >= romconf->count) {
>                                 ets_printf("Invalid temp rom selected.\r\n");
> -                               return 0;
> -                       }
> -                       ets_printf("Booting temp rom.\r\n");
> -                       temp_boot = TRUE;
> -                       romToBoot = rtc.temp_rom;
> +                               // make sure rtc temp boot mode doesn't persist
> +                               rtc.next_mode = MODE_STANDARD;
> +                               rtc.chksum = calc_chksum((uint8*)&rtc, (uint8*)&rtc.chksum);
> +                               system_rtc_mem(RBOOT_RTC_ADDR, &rtc, sizeof(rboot_rtc_data), RBOOT_RTC_WRITE);
> +                               ets_printf("Return to MODE_STANDARD\r\n");
> +                       } else {
> +                           ets_printf("Booting temp rom.\r\n");
> +                           temp_boot = TRUE;
> +                           romToBoot = rtc.temp_rom;
> +                        }
>                 }
>         }
> 
> 

Why rboot need up to addr 0x2000?

Hello Raburton,

Why have you specify that rboot is placed between addr 0x00000 and 0x2000?
Ok for addr 0x0000 but the bootloader and the structure fo rboot config don't really need of all that?

rboot + uart

Hi,

First of all; many thanks for releasing rboot!

I'm trying to get (ESP8266_NONOS_SDK-3.0) UART working on rboot, as I'd like to define how to boot depending on what's coming in on UART. However, I'm a bit puzzled on how to achieve that in combination with your Makefile and esptool2. I keep on hitting on undefined reference errors when compiling, so I guess it's something to do with linking the objects together somehow. As I'm not a Makefile/compiler master, I would appreciate your thoughts on this, i.e., how would you approach this?

GPIO boot fails

GPIO ROM selection fails to boot a ROM when the following conditions are met:

Boot mode = MODE_GPIO_ROM
MODE_GPIO_ROM = 0
romToBoot != 0
GPIO16 = 0

I have three ROMS:

ROM[0] @ 0x002000
ROM[1] @ 0x100000
ROM[2] @ 0x200000

With GPIO16 = 1, I can boot in to any of these ROMs. The code for each is based on the rBoot example code. I can switch between any ROM. If romToBoot = 0 then I can set GPIO16 = 0 and boot in to ROM[0] but with romToBoot set to 1 or 2, GPIO boot fails. Serial output is presented (at 74880 BAUD) thus:

Booting GPIO-selected.
Booting rom 0.

which shows the rBoot code is detecting the correct ROM to boot. No further serial output occurs.

I have tried using BOOT_NO_ASM with same result.

Add ESP32 Support

As the ESP32 is available for some time now, that would be great to see how to port rboot to that chip if possible. My first impression is that it's pretty close to ESP8266 in terms of architecture and the RTOS sdk seems very similar in features / boot image format.
But there are two cores and new features so it might be just an impression.
Did someone try rboot on ESP32 already?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.