ESP8266学习笔记(2)——内存分布及Flash读写接口

一、存储芯片W25Q系列

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内存分布

  • 程序区:代码编译生成的 bin 文件,烧录到 Flash 占用的区域,请勿改写
  • 系统参数区: esp_iot_sdk 中底层用于存放系统参数的区域,请勿改写
  • 用户参数区:上层应用程序存储用户参数的区域。开发者请根据实际使用的 Flash size 设置,可 以参考文档“2A-ESP8266__IOT_SDK_User_Manual” 中的 “Flash Map” 一章。

2.1 Non-FOTA

2.2 FOTA

更多图查看:

链接:https://blog.csdn.net/k7arm/article/details/51812021

三、Flash读写接口

SPI Flash 接口位于 /ESP8266_NONOS_SDK/include/spi_flash.h

system_param_xxx 接口位于 /ESP8266_NONOS_SDK/include/user_interface.h

3.1 spi_flash_erase_sector

3.2 spi_flash_write

注意:

  • Flash 请先擦再写。
  • Flash 读写必须 4 字节对齐。

示例代码:   

#define N 0x7C

uint32 data[M];

spi_flash_erase_sector (N);

spi_flash_write (N*4*1024, data, M*4);

3.3 spi_flash_read

3.4 system_param_save_with_protect

3.5 system_param_load

示例代码:

/***************Flash 读写结构体声明***************/

struct esp_platform_saved_param {

// 服务器参数
uint8 devkey[40];
uint8 token[40];
uint8 activeflag;
char server_domain[64];
ip_addr_t server_ip;
int server_port;

// AP参数
uint8 ssid[32];
uint8 password[64];
int authmode;
uint8 ssid_hidden;

// 填充
uint8 pad[2];
};

/***************Flash 读写结构体定义***************/
struct esp_platform_saved_param esp_param;

/***************Flash 写入数据***************/
system_param_save_with_protect(0x7D, &esp_param, sizeof(esp_param));

/***************Flash 读出数据***************/
system_param_load(0x7D, 0, &esp_param, sizeof(esp_param)); 

四、Flash读写保护

4.1 Espressif Flash读写保护示例

4.1.1 实现原理

Espressif Flash 读写保护示例,使用 三个 sector(扇区)实现(每 sector 4KB),提供 4KB 的可靠存储空间。 将 sector 1 和 sector 2 作为数据 sector,轮流读写,始终分别存放“本次”数据和“前一次”数据, 确保了至少有一份数据存储安全;sector 3 作为 flag sector,标志最新的数据存储 sector。

保护机制如下:

  1. 初始上电时,数据存储在 sector 2 中,从 sector 2 中将数据读到 RAM。
  2. 第一次写数据时,将数据写入 sector 1。此时若突然掉电,sector 1写入失败,sector 2 & 3数据未改变;重新上电时,仍是从 sector 2 中 读取数据,不影响使用。
  3. 改写 sector 3,将标志置为 0,表示数据存于 sector 1。此时若突然掉电,sector 3 写入失败,sector 1 & 2 均存有一份完整数据;重新上电时,因 sector 3 无有效 flag,默认从 sector 2 中读取数据,则仍能正常使用,只是未能包含掉电前对 sector 1 写入的数据。
  4. 再一次写数据时,先从 sector 3 读取 flag,若 flag 为0,则上次数据存于 sector 1,此次应将数据写入 sector 2;若 flag 为非 0,则认为上次数据存于 sector 2,此次应将数据写入 sector 1。此时若写数据出错,请参考步骤 2、 3的说明,同理。
  5. 写入 sector 1(或 sector 2)完成后,才会写 sector 3,重置 flag。注意:只有数据扇区(sector 1或 sector 2)写完之后,才会写 flag sector(sector 3),这样即使 flag sector 写入出错,两个数据扇区都已存有完整数据内容,目前默认会读取 sector 2。

4.1.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 读写即可。

4.2 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 的数据,校验,并执行。

4.3 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]

             《Esp8266 进阶之路24》

             《ESP8266 Flash》

好的,我知道了。针对你的问题,我能够为你提供如下的解答: 在使用 MicroPython 和 ESP8266 控制 LED 的过程中,可以通过 PWM 技术实现呼吸灯效果。PWM(Pulse Width Modulation)脉宽调制技术是一种通过改变信号的占空比来控制电路输出功率的技术。 具体实现步骤如下: 1. 首先需要在 ESP8266 上安装 MicroPython,然后连接 ESP8266 和 LED。 2. 在 MicroPython 中,可以使用 machine 模块中的 Pin 和 PWM 类来控制 LED。 3. 先使用 Pin 类将 LED 连接到 ESP8266 上的一个 GPIO 引脚。 4. 再使用 PWM 类来初始化一个 PWM 对象,并设置 PWM 对象的频率和占空比。 5. 最后使用 PWM 对象的 duty() 方法来改变占空比,从而控制 LED 显示的亮度。 下面是一个简单的 MicroPython 代码示例,用于控制 LED 呼吸灯效果: ```python from machine import Pin, PWM import time led_pin = Pin(2, Pin.OUT) # 连接到GPIO2 pwm = PWM(led_pin, freq=5000) # 初始化PWM对象,设置频率为5000Hz while True: for duty_cycle in range(0, 1024, 8): # 从0到1024,每次增加8 pwm.duty(duty_cycle) # 设置占空比 time.sleep_ms(5) # 暂停5ms for duty_cycle in range(1023, -1, -8): # 从1023到0,每次减少8 pwm.duty(duty_cycle) # 设置占空比 time.sleep_ms(5) # 暂停5ms ``` 上面的代码中,使用了一个无限循环来让 LED 一直显示呼吸灯效果。在每个循环中,通过循环改变占空比,从而让 LED 呈现出呼吸灯效果。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Leung_ManWah

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值