Merge pull request #1527 from jimparis/rfcal_ne_0x05_initdata_fix_auto

Reintroduce automatic esp_init_data flashing, plus updated docs.
This commit is contained in:
Johny Mattsson 2016-10-06 12:02:48 +11:00 committed by GitHub
commit 9d8707429b
5 changed files with 73 additions and 46 deletions

View File

@ -207,14 +207,14 @@ sdk_patched: sdk_extracted $(TOP_DIR)/sdk/.patched-$(SDK_VER)
$(TOP_DIR)/sdk/.extracted-$(SDK_BASE_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip
mkdir -p "$(dir $@)"
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK/lib/* ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK/include/* )
(cd "$(dir $@)" && rm -fr esp_iot_sdk_v$(SDK_VER) ESP8266_NONOS_SDK && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_FILE_VER).zip ESP8266_NONOS_SDK/lib/* ESP8266_NONOS_SDK/ld/eagle.rom.addr.v6.ld ESP8266_NONOS_SDK/include/* ESP8266_NONOS_SDK/bin/esp_init_data_default.bin)
mv $(dir $@)/ESP8266_NONOS_SDK $(dir $@)/esp_iot_sdk_v$(SDK_VER)
rm -f $(SDK_DIR)/lib/liblwip.a
touch $@
$(TOP_DIR)/sdk/.patched-$(SDK_VER): $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER).zip
mkdir -p "$(dir $@)/patch"
(cd "$(dir $@)/patch" && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER)*.zip *.a && mv *.a $(SDK_DIR)/lib/)
(cd "$(dir $@)/patch" && unzip $(TOP_DIR)/cache/esp_iot_sdk_v$(SDK_PATCH_VER)*.zip *.a esp_init_data_default.bin && mv *.a $(SDK_DIR)/lib/ && mv esp_init_data_default.bin $(SDK_DIR)/bin/)
rmdir $(dir $@)/patch
rm -f $(SDK_DIR)/lib/liblwip.a
touch $@

View File

@ -149,5 +149,7 @@ void uart_div_modify(int no, unsigned int freq);
/* Returns 0 on success, 1 on failure */
uint8_t SPIRead(uint32_t src_addr, uint32_t *des_addr, uint32_t size);
uint8_t SPIWrite(uint32_t dst_addr, const uint32_t *src, uint32_t size);
uint8_t SPIEraseSector(uint32_t sector);
#endif

View File

@ -24,7 +24,7 @@ STD_CFLAGS=-std=gnu11 -Wimplicit
# makefile at its root level - these are then overridden
# for a subtree within the makefile rooted therein
#
#DEFINES +=
DEFINES += -DESP_INIT_DATA_DEFAULT="\"$(SDK_DIR)/bin/esp_init_data_default.bin\""
#############################################################
# Recursion Magic - Don't touch this!!

View File

@ -31,6 +31,18 @@
static task_handle_t input_sig;
/* Contents of esp_init_data_default.bin */
extern const uint32_t init_data[];
extern const uint32_t init_data_end[];
__asm__(
/* Place in .text for same reason as user_start_trampoline */
".section \".text\"\n"
".align 4\n"
"init_data:\n"
".incbin \"" ESP_INIT_DATA_DEFAULT "\"\n"
"init_data_end:\n"
".previous\n"
);
/* Note: the trampoline *must* be explicitly put into the .text segment, since
* by the time it is invoked the irom has not yet been mapped. This naturally
@ -47,6 +59,31 @@ void TEXT_SECTION_ATTR user_start_trampoline (void)
rtctime_early_startup ();
#endif
/* Re-implementation of default init data deployment. The SDK does not
* appear to be laying down its own version of init data anymore, so
* we have to do it again. To see whether we need to, we read out
* the flash size and do a test for esp_init_data based on that size.
* If it's missing, we need to initialize it *right now* before the SDK
* starts up and gets stuck at "rf_cal[0] !=0x05,is 0xFF".
* If the size byte is wrong, then we'll end up fixing up the init data
* again on the next boot, after we've corrected the size byte.
* Only remaining issue is lack of spare code bytes in iram, so this
* is deliberately quite terse and not as readable as one might like.
*/
SPIFlashInfo sfi;
SPIRead (0, (uint32_t *)(&sfi), sizeof (sfi)); // Cache read not enabled yet, safe to use
if (sfi.size < 2) // Compensate for out-of-order 4mbit vs 2mbit values
sfi.size ^= 1;
uint32_t flash_end_addr = (256 * 1024) << sfi.size;
uint32_t init_data_hdr = 0xffffffff;
uint32_t init_data_addr = flash_end_addr - 4 * SPI_FLASH_SEC_SIZE;
SPIRead (init_data_addr, &init_data_hdr, sizeof (init_data_hdr));
if (init_data_hdr == 0xffffffff)
{
SPIEraseSector (init_data_addr);
SPIWrite (init_data_addr, init_data, 4 * (init_data_end - init_data));
}
call_user_start ();
}
@ -87,9 +124,7 @@ void nodemcu_init(void)
// Fit hardware real flash size.
flash_rom_set_size_byte(flash_safe_get_size_byte());
// Reboot to get SDK to use (or write) init data at new location
system_restart ();
// Don't post the start_lua task, we're about to reboot...
return;
}

View File

@ -1,10 +1,17 @@
Adafruit provides a really nice [firmware flashing tutorial](https://learn.adafruit.com/building-and-running-micropython-on-the-esp8266/flash-firmware). Below you'll find just the basics for the two popular tools esptool and NodeMCU Flasher.
Adafruit provides a really nice [firmware flashing tutorial](https://learn.adafruit.com/building-and-running-micropython-on-the-esp8266/flash-firmware). Below you'll find just the basics for the two popular tools esptool and NodeMCU Flasher.
!!! attention
Keep in mind that the ESP8266 needs to be [put into flash mode](#putting-device-into-flash-mode) before you can flash a new firmware!
## esptool.py
!!! important
When switching between NodeMCU versions, see the notes about
[Upgrading Firmware](#upgrading-firmware).
## Tool overview
**esptool.py**
> A cute Python utility to communicate with the ROM bootloader in Espressif ESP8266. It is intended to be a simple, platform independent, open source replacement for XTCOM.
Source: [https://github.com/themadinventor/esptool](https://github.com/themadinventor/esptool)
@ -18,11 +25,16 @@ Run the following command to flash an *aggregated* binary as is produced for exa
`esptool.py --port <serial-port-of-ESP8266> write_flash -fm <mode> -fs <size> 0x00000 <nodemcu-firmware>.bin`
- `mode` is `qio` for 512&nbsp;kByte modules and `dio` for 4&nbsp;MByte modules (`qio` might work as well, YMMV).
- `size` is given in bits. Specify `4m` for 512&nbsp;kByte and `32m` for 4&nbsp;MByte.
- `size` is given in bits. Specify `4m` for 512&nbsp;kByte and `32m` for 4&nbsp;MByte. If unsure, try a smaller size;
NodeMCU will by default detect and correct the size at first boot.
In some uncommon cases, the [SDK init data](#sdk-init-data) may be invalid and NodeMCU may fail to boot. The easiest solution is to fully erase the chip before flashing:
`esptool.py --port <serial-port-of-ESP8266> erase_flash`
Check the [esptool flash modes documentation](https://github.com/themadinventor/esptool#flash-modes) for details and other options.
## NodeMCU Flasher
**NodeMCU Flasher**
> A firmware Flash tool for NodeMCU...We are working on next version and will use QT framework. It will be cross platform and open-source.
Source: [https://github.com/nodemcu/nodemcu-flasher](https://github.com/nodemcu/nodemcu-flasher)
@ -35,7 +47,7 @@ To enable ESP8266 firmware flashing GPIO0 pin must be pulled low before the devi
If you have a [NodeMCU dev kit](https://github.com/nodemcu/nodemcu-devkit-v1.0) then you don't need to do anything, as the USB connection can pull GPIO0 low by asserting DTR and reset your board by asserting RTS.
If you have an ESP-01 or other device without built-in USB, you will need to enable flashing yourself by pulling GPIO0 low or pressing a "flash" switch.
If you have an ESP-01 or other device without built-in USB, you will need to enable flashing yourself by pulling GPIO0 low or pressing a "flash" switch, while powering up or resetting the module.
## Which Files To Flash
@ -46,55 +58,33 @@ Otherwise, if you built your own firmware from source code:
- `bin/0x00000.bin` to 0x00000
- `bin/0x10000.bin` to 0x10000
Also, in some special circumstances, you may need to flash `blank.bin` or `esp_init_data_default.bin` to various addresses on the flash (depending on flash size and type), see [below](#upgrading-from-sdk-09x-firmware).
## Upgrading Firmware
!!! important
There are three potential issues that arise from upgrading (or downgrading!) firmware from one NodeMCU version to another:
It goes without saying that you shouldn't expect your NodeMCU 0.9.x Lua scripts to work error-free on a more recent firmware. Most notably Espressif changed the `socket:send` operation to be asynchronous i.e. non-blocking. See [API documentation](modules/net.md#netsocketsend) for details.
* Lua scripts written for one NodeMCU version (like 0.9.x) may not work error-free on a more recent firmware. Most notably, Espressif changed the `socket:send` operation to be asynchronous i.e. non-blocking. See [API documentation](modules/net.md#netsocketsend) for details.
Espressif changes the init data block (`esp_init_data_default.bin`) for their devices along the way with the SDK. So things break when a NodeMCU firmware with a certain SDK is flashed to a module which contains init data from a different SDK. Hence, this section applies to upgrading NodeMCU firmware just as well as *downgrading* firmware.
* The NodeMCU flash filesystem may need to be reformatted, particularly if its address has changed because the new firmware has a much different size than the old firmware. If it is not automatically formatted, then it should be valid and have the same contents as before the flash operation. You can still run [`file.format()`](modules/file.md#fileformat) to re-format your flash filesystem. You will know if you need to do this if your flash files exist but seem empty, or if data cannot be written to new files. However, this should be an exceptional case.
A typical case that often fails is when a module is upgraded from a 0.9.x firmware to a recent version. It might look like the new firmware is broken, but the reason for the missing Lua prompt is related to the big jump in SDK versions.
* The Espressif SDK Init Data may change between each NodeMCU firmware version, and may need to be erased or reflashed. See [SDK Init Data](#sdk-init-data) for details. Fully erasing the module before upgrading firmware will avoid this issue.
If there is no init data block found during SDK startup, the SDK will install one itself. If there is a previous (potentially too old) init block, the SDK *probably* doesn't do anything with it but there is no documentation from Espressif on this topic.
## SDK Init Data
Hence, there are two strategies to update the SDK init data:
!!! note
- Erase flash completely. This will also erase the (Lua) files you uploaded to the device! The SDK will install the init data block during startup.
- Don't erase the flash but replace just the init data with a new file during the flashing procedure. For this you would download [SDK patch 1.5.4.1](http://bbs.espressif.com/download/file.php?id=1572) and extract `esp_init_data_default.bin` from there.
Normally, NodeMCU will take care of writing the SDK init data when needed. Most users can ignore this section.
When flashing a new firmware (particularly with a much different size), the flash filesystem may be reformatted as the firmware starts. If it is not automatically reformatted, then it should be valid and have the same contents as before the flash operation. You can still run [`file.format()`](modules/file.md#fileformat) to re-format your flash filesystem. You will know if you need to do this if your flash files exist but seem empty, or if data cannot be written to new files. However, this should be an exceptional case.
NodeMCU versions are compiled against specific versions of the Espressif SDK. The SDK reserves space in flash that is used to store calibration and other data. This data changes between SDK versions, and if it is invalid or not present, the code may not boot correctly. Symptoms include messages like `rf_cal[0] !=0x05,is 0xFF`, or endless reboot loops.
**esptool.py**
!!! tip
For [esptool.py](https://github.com/themadinventor/esptool) you specify the init data file as an additional file for the `write_flash` command.
If you are seeing these symptoms, ensure that your chip is fully erased before flashing, for example:
```
esptool.py --port <serial-port-of-ESP8266> erase_flash
esptool.py --port <serial-port-of-ESP8266> write_flash <flash options> 0x00000 <nodemcu-firmware>.bin <init-data-address> esp_init_data_default.bin
```
`esptool.py --port <serial-port-of-ESP8266> erase_flash`
!!! note "Note:"
Also verify that you are using an up-to-date NodeMCU release, as some early releases of NodeMCU 1.5.4.1 did not write the SDK init data to a freshly erased chip.
The address for `esp_init_data_default.bin` depends on the size of your module's flash.
- `0x7c000` for 512 kB, modules like ESP-01, -03, -07 etc.
- `0xfc000` for 1 MB, modules like ESP8285, PSF-A85
- `0x1fc000` for 2 MB
- `0x3fc000` for 4 MB, modules like ESP-12E, NodeMCU devkit 1.0, WeMos D1 mini
Espressif refers to this area as "System Param" and it resides in the last four 4&nbsp;kB sectors of flash. Since SDK 1.5.4.1, a fifth sector is reserved for RF calibration (and its placement is controlled by NodeMCU), as described by this [patch notice](http://bbs.espressif.com/viewtopic.php?f=46&t=2407). At minimum, Espressif states that the 4th sector from the end needs to be flashed with "init data", and the 2nd sector from the end should be blank.
**NodeMCU Flasher**
The standard init data is provided as part of the SDK, in the file `esp_init_data_default.bin`. NodeMCU will automatically flash this file to the right place on first boot, if the sector appears to be empty. If you need to customize the contents of the init data, you can instead flash it manually and NodeMCU will not change it. See "4.1 Non-FOTA Flash Map" and "6.3 RF Initialization Configuration" of the [ESP8266 Getting Started Guide](https://espressif.com/en/support/explore/get-started/esp8266/getting-started-guide) for details on init data addresses and customization.
The [NodeMCU Flasher](https://github.com/nodemcu/nodemcu-flasher) will download init data using a special path:
```
INTERNAL://DEFAULT
```
Replace the provided (old) `esp_init_data_default.bin` with the one extracted above and use the flasher like you're used to.
**References**
* [2A-ESP8266__IOT_SDK_User_Manual__EN_v1.5.pdf, Chapter 6](http://bbs.espressif.com/viewtopic.php?f=51&t=1024)
* [SPI Flash ROM Layout (without OTA upgrades)](https://github.com/esp8266/esp8266-wiki/wiki/Memory-Map#spi-flash-rom-layout-without-ota-upgrades)