ESP8266内存分配
ESP8266-12E/F相关内存
两款模组在使用功能和内存功能都一样

模组中主要部分的芯片是乐鑫的esp8266,flash使用w25q32(4MB)


w25q 系列生产的加工的商家很多,但是里面的分布和命名规则都是一样的。比如华邦的w25q64,spi通讯接口,64就是指 64Mbit 也就是 8M 的容量。而我们平时的8266-12f的 32Mbit 就是 4M 容量。
以 w25q32 为例,里面的存储分布。w25q32把4M容量分为了 64 块,每一块又分为 16 个扇区,而每个扇区占 4K 大小。由此可计算到,w25q32有 32Mbit / 8 * 1024 / 16 / 4 = 64 块 ,有 64 * 16 = 1024 个扇区。
注:1B=8 Bit ,1KB=1024B ,1MB=1024KB

内存介绍
esp8266主要有内部芯片内存和外部Flash内存
- 程序区:代码编译生成的 bin 文件,烧录到 Flash 占用的区域,请勿改写;
- 系统参数区: esp_iot_sdk 中底层用于存放系统参数的区域,请勿改写;
- 用户参数区:上层应用程序存储用户参数的区域。开发者请根据实际使用的 Flash size 设置,可 以参考文档“2A-ESP8266__IOT_SDK_User_Manual” 中的 “Flash Map” 一章。
芯片内存
esp8266 sdk 默认将 iRAM 中 0x40108000 开始的 32KB 空间用作 cache,sdk 启动后会将对应的 spi flash 空间映射到 cache 空间。
esp8266 sdk 中,支持若干种 flash map 方式,有 256KB + 256KB、512KB + 512KB、1024KB + 1024KB。
在 256KB + 256KB 和 512KB + 512KB 两种 map 方式中,user1.bin 和 user2.bin 均在第一个 1MB 空间,因此映射到同一个 1MB 空间。

w25q32内存分布
注意擦除或写入都是以扇区为最小单位。



Non-FOTA

FOTA


更多图查看:
链接:https://blog.csdn.net/k7arm/article/details/51812021
ESP8266和w25q32内存分布说明
ESP826612F/E里面使用w25q32作为了flash存储.
提前说下哈,bit代表位 也就是 0 1 0 1 , Bit代表字节 ,一字节就是8位
w25q32的容量是32Mbit 也就是 32/8 = 4MB字节 = 4*1024 = 4096KB字节
然后 w25q32 这个芯片规定每 64KB字节作为一个块
所以呢w25q32总共分成了 4096/64 = 64个块,不要问我,块是神么…..就是一块一块的区域,所以就是块…
然后 w25q32 这个芯片还规定每 4KB字节作为一个扇区.每256字节作为一页.
所以所有的扇区个数是 64*16 = 1024个

ESP8266内存规定

芯片是4096KB字节 = 4096*1024 = 4194304字节 = 0x400000
eagle.flash.bin 从flash的最开始的地址开始存储
eagle.irom0text.bin (0x10000 = 65536) 偏移了65536字节即64KB
esp_init_data_default.bin (0x3FC000) 从倒数第4个扇区开始存储 (注:0x400000 - 4096-4096-4096-4096 = 0x3FC000)
blank.bin (0x3FE000)从倒数第2个扇区开始存储 (注:0x400000 - 4096-4096 = 0x3FE000)

注意,未使用区域是变化的…咱编译完程序会显示eagle.irom0text.bin 大小

随着程序量的增加eagle.irom0text.bin 大小也在增加
其实呢咱使用上面的未使用区域的时候一般可以从0x3FC000地址往前推,
(提醒:以一个扇区4KB作为最小使用哈,因为擦除的时候最小擦除是4KB)
假设咱感觉存储咱自己的数据只使用4KB就可以了,那么就是在 0x3EB000地址开始存储咱自己的数据.
0x3FC000 - 4KB = 0x3EB000 即从倒数第5个扇区开始存储数据

其实从0x3FC000 到 0x3FE000 总共有8KB,所有中间有两个扇区
因为esp_init_data_default.bin 的大小是固定的哈不会超过4KB,
所以0x3FE000 左面的那个4KB的扇区也是可以使用的
开始的地址是 0x3FD000 即从倒数第三个扇区存储数据

提供的API函数
- 擦除某个扇区
总共1024个扇区,扇区号从0开始,所以是 0 - 1023
列如擦除上面的倒数第5个扇区 就是 spi_flash_erase_sector (1019)

- 往扇区里面写数据

- 从flash里面读取数据

- SDK还封装了一套交替存储API
就是使用3个扇区保存数据,第一个扇区和第三个扇区来回的保存数据
第二个扇区只保存一个标志位,标志当前数据是存储在第一个扇区还是第二个扇区(程序内部实现)
API函数的第二个参数假设是 1017
那么就是使用第1017和1018扇区来回的保存数据,1018扇区保存标志位



注意:关于4字节对齐
如果你存储数据,存储的数据个数是4的倍数就可以.
一般咱都会把数据放到一个数组里面,所以咱把数组长度定义为4的倍数就可以
我上面说的是char型的数组
如果是u16型的数组,数组长度定义为2的倍数就可以
如果是u32的就随意啦….
开始实践(普通)

1 | //设置扇区地址 |

- Flash读写接口
SPI Flash 接口位于 /ESP8266_NONOS_SDK/include/spi_flash.h。
system_param_xxx 接口位于 /ESP8266_NONOS_SDK/include/user_interface.h。
spi_flash_erase_sector
spi_flash_write
注意:
Flash 请先擦再写。
Flash 读写必须 4 字节对齐。
示例代码:
1
2
3
4
5
6
7
uint32 data[M];
spi_flash_erase_sector (N);
spi_flash_write (N*4*1024, data, M*4);
spi_flash_read
system_param_save_with_protect
system_param_load
示例代码:
1 | /***************Flash 读写结构体声明***************/ |
开始实践(Flash读写保护)
实现原理
Espressif Flash 读写保护示例,使用 三个 sector(扇区)实现(每 sector 4KB),提供 4KB 的可靠存储空间。 将 sector 1 和 sector 2 作为数据 sector,轮流读写,始终分别存放“本次”数据和“前一次”数据, 确保了至少有一份数据存储安全;sector 3 作为 flag sector,标志最新的数据存储 sector。
保护机制如下:
- 初始上电时,数据存储在 sector 2 中,从 sector 2 中将数据读到 RAM。
- 第一次写数据时,将数据写入 sector 1。此时若突然掉电,sector 1写入失败,sector 2 & 3数据未改变;重新上电时,仍是从 sector 2 中 读取数据,不影响使用。
- 改写 sector 3,将标志置为 0,表示数据存于 sector 1。此时若突然掉电,sector 3 写入失败,sector 1 & 2 均存有一份完整数据;重新上电时,因 sector 3 无有效 flag,默认从 sector 2 中读取数据,则仍能正常使用,只是未能包含掉电前对 sector 1 写入的数据。
- 再一次写数据时,先从 sector 3 读取 flag,若 flag 为0,则上次数据存于 sector 1,此次应将数据写入 sector 2;若 flag 为非 0,则认为上次数据存于 sector 2,此次应将数据写入 sector 1。此时若写数据出错,请参考步骤 2、 3的说明,同理。
- 写入 sector 1(或 sector 2)完成后,才会写 sector 3,重置 flag。注意:只有数据扇区(sector 1或 sector 2)写完之后,才会写 flag sector(sector 3),这样即使 flag sector 写入出错,两个数据扇区都已存有完整数据内容,目前默认会读取 sector 2。
软件示例
在 IOT_Demo 中,使用 0x3C000 开始的 4 个 sector(每 sector 4KB),作为用户参数存储区。 其中 0x3D000、 0x3E000、 0x3F000 这 3 个 sector 实现了读写保护的功能,并存储了应用级参数 esp_platform_saved_param。

图中“有读写保护的存储区”, IOT_Demo 中建议调用 system_param_load 和 system_param_save_with_protect 进行读写。
system_param_load - 读 Flash 用户参数区数据
system_param_save_with_protect - 写 Flash 用户参数区数据
参数 struct esp_platform_saved_param 定义了目前乐鑫存储于 Flash 的用户应用级数据,用户只需将自己要存储的数据添加到结构体 struct esp_platform_saved_param 后面,调用上述两个函数进行 Flash 读写即可。

Flash读写保护参考一
方法: “轮流写入”+“首部记数”+“尾部校验”
占用空间: 2 个 sector,共计 8KB;提供 4KB 的带数据保护存储空间。

原理:
仍然 采用两个数据 sector 轮流写入来做备份数据保护,只是不再专门设立 flag sector。 记一个 counter,写入数据 sector 的首部,每次写入时计数加一,用记数比较来判别下一次应写入哪个 sector;在数据尾部加入校验码(CRC、checksum 等任一种校验方式),用以验证数据的完整性。
(1) 假设初次上电,数据存储在 sector A, sector A 的记数为初始值 0xFF,从 sector A 将数据读入 RAM。
(2) 第一次数据写入 sector B,则在 sector B 首部信息中记录 counter 为 1,尾部加入校验码。
(3) 再次写入数据时,先分别读取 sector A/B 的 counter 值进行比较,此次应当将数据写入 sector A, sector A 首部记录 counter 为 2,尾部加入校验码。
(4) 若发生突然掉电,当前正在写入的 sector 数据丢失,重新上电时,先比较 sector A/B 的 counter 值,读取 counter 值较大的完整 sector,根据 sector 尾部的校验码进行校验,当前 sector 数据是否可靠,若校验通过,则继续执行;若校验失败,则读取另一个 sector 的数据,校验,并执行。
Flash读写保护参考二
方法: “备份扇区”+“尾部校验”
占用空间: 2 个 sector,共计 8KB;提供 4KB 的带数据保护存储空间。

原理:
始终往 sector A 读写数据,每次写入时,同样写一遍 sector B 作为 sector A 的备份扇区,每个 sector 尾部均加入校验码(CRC、checksum等任一种校验方式)。
(1) 从 sector A 读取数据,并进行校验。
(2) 数据写入 sector A,尾部为校验码。
(3) sector A 写入完成后,同样的数据也写入 sector B 进行备份。
(4) 若发生突然掉电,当前正在写入的 sector 数据丢失,重新上电时,先从 sector A 读取数据,根据尾部的校验码进行校验,sector A 数据是否可靠,若校验通过,则继续执行;若校验失败,则读取 sector B 的数据,校验,并执行。
• 由 Leung 写于 2018 年 9 月 14 日
• 参考:《ESP8266 Flash 读写说明》[25l1]
《ESP8266 Non-OS SDK IoT_Demo 指南》[q878]
《ESP8266 Non-OS SDK API 参考》[7qq6]
其他方法
- 官方给了例子

注意 priv_param_start_sec 参数是这个参数

咱使用的时候也这样就可以


esp8266 flash地址规划
选取的是esp8266-12f 4096KB 4M flash内存
1.如何让确定为4M内存的?
原因:由于是从同事手上接项目,所以并无芯片规格书等物件。
查看工具编译选项,esp_init_data_default.bin: 0X3FC000 blank.bin :0X3FE000
备份系统程序地址是0x101000,绿色位置就是对应选择。

2.扇区应该如何划分?
esp8266 以4k为一个扇区,16k为一个块。4M内存的8266有1024个扇区。

OTA flash内存分布图

ESP8266-12F的扇区地址计算方法: blank.bin 位于扇区1022 地址0x3FE000 esp_init_data_default.bin位于扇区1020 地址0x3FC000
4M容量的十六进制3FC000地址转换为十进制为:4177920 所在扇区为:4177920/4/1024= 1020
4M容量的十六进制3FE000地址转换为十进制为:4186112 所在扇区为:4186112/4/1024= 1022
即system_param位置
Flash操作 ESP8266-12F的Flash操作: 下列扇区不能占用: blank.bin 位于扇区1022 地址0x3FE000 esp_init_data_default.bin位于扇区1020 地址0x3FC000
用户数据可存储的位置扇区号: (1024 - 16) /4 = 252 之后的四个扇区 在之前选位置也可以。只要不在用户程序处使用flash地址就可以。
相关链接(侵删)
- ESP8266-12E/F 内存分配
- ESP8266 SDK开发: 外设篇-内存分布说明及Flash读写
- esp8266 flash地址规划
- ESP8266学习笔记(2)——内存分布及Flash读写接口
- ESP8266 Flash
欢迎到公众号来唠嗑:
