Arduino ESP8266 使用LittleFS存储配置文件实践

4 篇文章 0 订阅

Arduino ESP8266 使用LittleFS存储配置文件实践

首先引用前辈的文章,了解一下esp8266 的flash 布局layout:

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 保存的地址在何处?
Aduino环境下翻看相关源码,管中窥一下豹:

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

 

引用arduino-esp8266 的filesystem 的doc文章,实践如何上传文件


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

基于Arduino使用ESP8266LittleFS文件系统可用于存储和管理文件。LittleFS是专为嵌入式系统设计的文件系统,可以轻松地在ESP8266使用。 首先,你需要在Arduino IDE中安装ESP8266核心。然后,在你的Arduino项目中,包含`FS.h`头文件,并在setup函数中初始化文件系统。 ```cpp #include <FS.h> void setup() { // 初始化LittleFS文件系统 if (!LittleFS.begin()) { Serial.println("An error occurred while mounting LittleFS"); return; } } ``` 现在,你可以使用LittleFS文件系统操作文件,比如读取、写入、追加和删除文件等。下面是一些常见的操作示例: 1. 创建一个文件: ```cpp File file = LittleFS.open("/myfile.txt", "w"); if (file) { file.println("Hello, world!"); file.close(); } else { Serial.println("Failed to create file"); } ``` 2. 读取文件内容: ```cpp File file = LittleFS.open("/myfile.txt", "r"); if (file) { while (file.available()) { Serial.write(file.read()); } file.close(); } else { Serial.println("Failed to open file"); } ``` 3. 追加内容到文件末尾: ```cpp File file = LittleFS.open("/myfile.txt", "a"); if (file) { file.println("This will be appended at the end"); file.close(); } else { Serial.println("Failed to open file"); } ``` 4. 删除文件: ```cpp if (LittleFS.remove("/myfile.txt")) { Serial.println("File deleted successfully"); } else { Serial.println("Failed to delete file"); } ``` 这些是基本的文件操作示例,你可以根据需要进一步扩展,并使用LittleFS文件系统进行更复杂的操作。记得在使用完文件后关闭它,以便释放资源。 使用LittleFS文件系统,你可以方便地在ESP8266上读写文件,并且具有更高的灵活性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值