Arduino ESP8266 使用LittleFS存储配置文件实践
http://idarc.cn/index.php/archives/1156/
ESP8266 flash布局(layout)
支持flash为512KB, 1M, 2M, 4M.
4KB为1个扇区,也就是16进制的0x1000. 4096
非OTA布局
a) 前64个扇区256KB烧写主程序+用户数据+用户参数, 主程序文件名eagle.flash.bin, 最大64KB, 用户参数占用最后4个扇区, 共16KB
b) 后面的部分, 烧写主程序+用户数据+系统参数, 主程序文件名 eagle.irom0text.bin, 最大768KB, 默认200KB. 系统参数占用最后4个扇区, 共16KB.sdk提供. 依次为:
b1) 初始化射频参数,1个扇区, esp_init_data_default.bin
b2) 初始化系统参数,2个扇区, blnk.bin
b3) bootloader, 1个扇区.
64KB主程序+(用户数据)+16KB用户参数
OTA布局
a) 可选前段是256KB, 512KB, 1MB, 后段至少要大于等于前段的大小.
b) 前段包括启动程序+主程序+用户数据+用户参数(后两个扇区为云端KEY). 启动程序boot.bin为4KB, 主程序user1.bin, 用户参数4个扇区16KB的后两个扇区存储乐鑫云端KEY master_device_key.bin
c) 后段包括预留区+主程序+用户数据+系统参数. 预留区4KB, 与启动程序的4KB对应, 主程序user2.bin,实际上是云端下载的缓存区, 事实上也不需要烧录. 系统参数与非OTA布局的相同.
布局文件的位置
在ESP8266_NONOS_SDK/ld/eagle.app.v6.ld中的MEMORY字段.
eagle.flash.bin和eagle.irom0text.bin的构成
eagle.flash.bin是用于存储直接读取到程序内存运行的程序段和数据内存的数据段的.
eagle.irom0text.bin是用于存储放在flash上, 不直接读取到内存中的程序段的.
程序内存:iram, internal ram, 通过ibus访问, 共32KB, 存放编译后的elf的TEXT字段
数据内存:dram, data ram, 通过 dbus访问, 可能是80kb或者96kb. 存放编译后的elf的data, rodata字段, 这部分字段可用约50kB. 其他的空间用于存放BBS, stack, heap.
FLASH存储: irom, 最大768KB, 存放编译后的elf的irom0.text字段, C源码函数前面有ICACHE_FLASH_ATTR前缀的就是说这个函数是放在irom中的. 另, 最大768KB的原因是, irom起始于256KB处, esp8266最大访问1MB程序段, 故1MB - 256KB = 768KB.
具体需要看(sdk中的eagle.app.v6.ld文件)[https://github.com/espressif/ESP8266_RTOS_SDK/blob/master/ld/eagle.app.v6.ld]对这几个存储的地址和大小的分配, 例如:
MEMORY
{
dport0_0_seg : org = 0x3FF00000, len = 0x10
dram0_0_seg : org = 0x3FFE8000, len = 0x18000
iram1_0_seg : org = 0x40100000, len = 0x8000
irom0_0_seg : org = 0x40220000, len = 0x5C000
}
编译术语
BBS block started By Symbol. 存放未初始化的全局变量, 静态分配
data 已经初始化的全局变量, 静态分配
text 程序执行代码
rodata 字符串与#define常量
heap 堆,动态分配的内存段(malloc, free)
stack 栈, 临时局部变量, 函数调用栈
常量段, 编译器产生的数据
LittleFS.cpp
FS LittleFS = FS(FSImplPtr(new littlefs_impl::LittleFSImpl(FS_PHYS_ADDR, FS_PHYS_SIZE, FS_PHYS_PAGE, FS_PHYS_BLOCK, FS_MAX_OPEN_FILES)));
参数
FS_PHYS_ADDR,
FS_PHYS_SIZE,
FS_PHYS_PAGE,
FS_PHYS_BLOCK,
FS_MAX_OPEN_FILES
#include <Arduino.h>
#include <stdlib.h>
#include <algorithm>
#include "LittleFS.h"
#include "debug.h"
#include "flash_hal.h"
extern "C" {
#include "c_types.h"
#include "spi_flash.h"
}
D:\Mixly_WIN\arduino\portable\packages\esp8266\hardware\esp8266\2.7.4\cores\esp8266
文件flash_hal.h
#ifdef ARDUINO
extern "C" uint32_t _FS_start;
extern "C" uint32_t _FS_end;
extern "C" uint32_t _FS_page;
extern "C" uint32_t _FS_block;
#define FS_PHYS_ADDR ((uint32_t) (&_FS_start) - 0x40200000)
#define FS_PHYS_SIZE ((uint32_t) (&_FS_end) - (uint32_t) (&_FS_start))
#define FS_PHYS_PAGE ((uint32_t) &_FS_page)
#define FS_PHYS_BLOCK ((uint32_t) &_FS_block)
#endif
arduino IDE 开发板配置
flash size: "4MB (FS:1MB OTA:~1019KB)"
4M1M.build.flash_ld=eagle.flash.4m1m.ld
D:\Mixly_WIN\arduino\portable\packages\esp8266\hardware\esp8266\2.7.4
boards.txt
d1.menu.eesz.4M1M=4MB (FS:1MB OTA:~1019KB)
d1.menu.eesz.4M1M.build.flash_size=4M
d1.menu.eesz.4M1M.build.flash_size_bytes=0x400000
d1.menu.eesz.4M1M.build.flash_ld=eagle.flash.4m1m.ld
d1.menu.eesz.4M1M.build.spiffs_pagesize=256
d1.menu.eesz.4M1M.upload.maximum_size=1044464
d1.menu.eesz.4M1M.build.rfcal_addr=0x3FC000
d1.menu.eesz.4M1M.build.spiffs_start=0x300000
d1.menu.eesz.4M1M.build.spiffs_end=0x3FA000
d1.menu.eesz.4M1M.build.spiffs_blocksize=8192
d1.menu.eesz.4M2M=4MB (FS:2MB OTA:~1019KB)
d1.menu.eesz.4M2M.build.flash_size=4M
d1.menu.eesz.4M2M.build.flash_size_bytes=0x400000
d1.menu.eesz.4M2M.build.flash_ld=eagle.flash.4m2m.ld
d1.menu.eesz.4M2M.build.spiffs_pagesize=256
d1.menu.eesz.4M2M.upload.maximum_size=1044464
d1.menu.eesz.4M2M.build.rfcal_addr=0x3FC000
d1.menu.eesz.4M2M.build.spiffs_start=0x200000
d1.menu.eesz.4M2M.build.spiffs_end=0x3FA000
d1.menu.eesz.4M2M.build.spiffs_blocksize=8192
d1.menu.eesz.4M3M=4MB (FS:3MB OTA:~512KB)
d1.menu.eesz.4M3M.build.flash_size=4M
d1.menu.eesz.4M3M.build.flash_size_bytes=0x400000
d1.menu.eesz.4M3M.build.flash_ld=eagle.flash.4m3m.ld
d1.menu.eesz.4M3M.build.spiffs_pagesize=256
d1.menu.eesz.4M3M.upload.maximum_size=1044464
d1.menu.eesz.4M3M.build.rfcal_addr=0x3FC000
d1.menu.eesz.4M3M.build.spiffs_start=0x100000
d1.menu.eesz.4M3M.build.spiffs_end=0x3FA000
d1.menu.eesz.4M3M.build.spiffs_blocksize=8192
d1.menu.eesz.4M=4MB (FS:none OTA:~1019KB)
d1.menu.eesz.4M.build.flash_size=4M
d1.menu.eesz.4M.build.flash_size_bytes=0x400000
d1.menu.eesz.4M.build.flash_ld=eagle.flash.4m.ld
d1.menu.eesz.4M.build.spiffs_pagesize=256
d1.menu.eesz.4M.upload.maximum_size=1044464
d1.menu.eesz.4M.build.rfcal_addr=0x3FC000
d1.menu.ip.lm2f=v2 Lower Memory
d1.menu.ip.lm2f.build.lwip_include=lwip2/include
d1.menu.ip.lm2f.build.lwip_lib=-llwip2-536-feat
d1.menu.ip.lm2f.build.lwip_flags=-DLWIP_OPEN_SRC -DTCP_MSS=536 -DLWIP_FEATURES=1 -DLWIP_IPV6=0
4M1M其中的配置:
d1.menu.eesz.4M1M.build.flash_size=4M
d1.menu.eesz.4M1M.build.flash_size_bytes=0x400000-----------------4,194,304 (4MB)
d1.menu.eesz.4M1M.build.flash_ld=eagle.flash.4m1m.ld-------------------------
d1.menu.eesz.4M1M.build.spiffs_pagesize=256
d1.menu.eesz.4M1M.upload.maximum_size=1044464-----------------FEFF0==(1MB-4KB)(1,048,576)
d1.menu.eesz.4M1M.build.rfcal_addr=0x3FC000
d1.menu.eesz.4M1M.build.spiffs_start=0x300000
d1.menu.eesz.4M1M.build.spiffs_end=0x3FA000
d1.menu.eesz.4M1M.build.spiffs_blocksize=8192
D:\Mixly_WIN\arduino\portable\packages\esp8266\hardware\esp8266\2.7.4\tools\sdk\ld
eagle.flash.4m1m.ld
/* Flash Split for 4M chips */
/* sketch @0x40200000 (~1019KB) (1044464B) */
/* empty @0x402FEFF0 (~2052KB) (2101264B) */
/* spiffs @0x40500000 (~1000KB) (1024000B) */
/* eeprom @0x405FB000 (4KB) */
/* rfcal @0x405FC000 (4KB) */
/* wifi @0x405FD000 (12KB) */
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 = 0x40201010, len = 0xfeff0
}
PROVIDE ( _FS_start = 0x40500000 );
PROVIDE ( _FS_end = 0x405FA000 );//-------------------FA000=1000 KB
PROVIDE ( _FS_page = 0x100 );//-------------------256
PROVIDE ( _FS_block = 0x2000 );//-----------------------8192
PROVIDE ( _EEPROM_start = 0x405fb000 );
/* The following symbols are DEPRECATED and will be REMOVED in a future release */
PROVIDE ( _SPIFFS_start = 0x40500000 );
PROVIDE ( _SPIFFS_end = 0x405FA000 );
PROVIDE ( _SPIFFS_page = 0x100 );
PROVIDE ( _SPIFFS_block = 0x2000 );
INCLUDE "local.eagle.app.v6.common.ld"
上文
/* sketch @0x40200000 (~1019KB) (1044464B) */
#define FS_PHYS_ADDR ((uint32_t) (&_FS_start) - 0x40200000)---------------300000
这里计算地址为0x300000
https://arduino-esp8266.readthedocs.io/en/latest/filesystem.html#filesystem
Filesystem
Flash layout
Even though file system is stored on the same flash chip as the program, programming new sketch will not modify file system contents. This allows to use file system to store sketch data, configuration files, or content for Web server.
The following diagram illustrates flash layout used in Arduino environment:
|--------------|-------|---------------|--|--|--|--|--|
^ ^ ^ ^ ^
Sketch OTA update File system EEPROM WiFi config (SDK)
.。。。。。。。
They share a compatible API but have incompatible on-flash implementations, so it is important to choose one or the per project as attempting to mount a SPIFFS volume under LittleFS may result in a format operation and definitely will not preserve any files, and vice-versa.
它们共享一个兼容的API,但在flash实现上不兼容,因此每个项目选择一个或多个API是很重要的,因为尝试在LittleFS下装载SPIFFS卷可能会导致格式化操作,并且肯定不会保留任何文件,反之亦然。
Uploading files to file system
-----------------------------------------------------
ESP8266FS is a tool which integrates into the Arduino IDE. It adds a menu item to Tools menu for uploading the contents of sketch data directory into ESP8266 flash file system.
ESP8266FS是一个集成到Arduino IDE中的工具。在工具菜单中增加了一个菜单项,用于将草图数据目录的内容上传到ESP8266 flash文件系统中。
工具能把文件打包成SPIFFS映像,上传到flash的文件系统区
Download the tool: https://github.com/esp8266/arduino-esp8266fs-plugin/releases/download/0.5.0/ESP8266FS-0.5.0.zip
In your Arduino sketchbook directory, create tools directory if it doesn’t exist yet.
Unpack the tool into tools directory (the path will look like <home_dir>/Arduino/tools/ESP8266FS/tool/esp8266fs.jar) If upgrading, overwrite the existing JAR file with the newer version.
Restart Arduino IDE.
Open a sketch (or create a new one and save it).
Go to sketch directory (choose Sketch > Show Sketch Folder).
Create a directory named data and any files you want in the file system there.
Make sure you have selected a board, port, and closed Serial Monitor.
If your board requires you to press a button (or other action) to enter bootload mode for flashing a sketch, do that now.
Select Tools > ESP8266 Sketch Data Upload. This should start uploading the files into ESP8266 flash file system. When done, IDE status bar will display SPIFFS Image Uploaded message.
------------------------------------------------------
ESP8266LittleFS is the equivalent tool for LittleFS.
ESP8266LittleFS为LittleFS的同样工具。工具能把文件打包成LittleFS映像,上传到flash的文件系统区
Download the 2.6.0 or later version of the tool: https://github.com/earlephilhower/arduino-esp8266littlefs-plugin/releases
Install as above
To upload a LittleFS filesystem use Tools > ESP8266 LittleFS Data Upload实践,按说明配置好,上传的提示
[LittleFS] data : E:\project\8266ap\WiFiAccessPoint\data
[LittleFS] size : 1000
[LittleFS] page : 256
[LittleFS] block : 8192
/a.txt
/b.txt
/hello.txt
[LittleFS] upload : E:\temp\arduino_build_677886/WiFiAccessPoint.mklittlefs.bin
[LittleFS] address : 0x300000
[LittleFS] reset : --before default_reset --after hard_reset
[LittleFS] port : COM3
[LittleFS] speed : 921600
[LittleFS] python : D:\Mixly_WIN\arduino\portable\packages\esp8266\tools\python3\3.7.2-post1\python3.exe
[LittleFS] uploader : D:\Mixly_WIN\arduino\portable\packages\esp8266\hardware\esp8266\2.7.4\tools\upload.py
esptool.py v2.8
Serial port COM3
Connecting....
Chip is ESP8266EX
Features: WiFi
Crystal is 26MHz
MAC: a4:cf:12:ef:89:a4
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 460800
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 1024000 bytes to 1345...
Wrote 1024000 bytes (1345 compressed) at 0x00300000 in 0.0 seconds (effective 200378.7 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
ok,上传完成。如此这般,开发设备时很多需要初始化的数据、配置参数等等。都可以烧录到flash里,8266内部进行读写就so easy啦。
https://docs.platformio.org/en/latest/platforms/espressif8266.html#uploading-files-to-filesystem