ESP8266 Flash的分布及其读写操作

  1. 读写操作API

    1. 基本操作

      (1) spi_flash_erase_sector

      功能 擦除 Flash 的某个扇区。
      函数定义 SpiFlashOpResult spi_flash_erase_sector (uint16 sec)
      参数 uint16 sec- 扇区号,从0 开始计数,每个扇区大小为4KB
      返回值 SpiFlashOpResult

      (2)spi_flash_write

      功能 将数据写入Flash 。
      请先调用spi_flash_erase_sector 擦除待写区域,再写入数据。
      函数定义 SpiFlashOpResult spi_flash_write (uint32 des_addr, uint32 *src_addr, uint32size)
      参数 uint32 des_addr – 写入Flash 的地址,起始位置。
      uint32 *src_addr – 写入Flash 的数据指针。
      uint32 size – 写入数据的长度,单位:byte。
      返回值 SpiFlashOpResult

      (3)spi_flash_read

      功能 从 Flash 读取数据。
      函数定义 SpiFlashOpResult spi_flash_read(uint32 src_addr, uint32 * des_addr, uint32 size)
      参数 uint32 src_addr – 读取Flash 的地址,起始位置。
      uint32 *des_addr – 读取Flash 的数据指针。
      uint32 size – 读取数据的长度,单位:byte。
      返回值 SpiFlashOpResult

      (4)返回值

      Typedef enum{
      SPI_FLASH_RESULT_OK,
      SPI_FLASH_RESULT_ERR,
      SPI_FLASH_RESULT_TIMEOUT
      }SpiFlashOpResult;

    2. 注意事项

      1. 每个扇区的大小为4kB,即4*1024 bytes

      2. Flash读写数据要以四字节对齐。

      3. Flash要先擦除再写入。

    3. 示例代码

      /*
      * 方式一
      */
      
      #define LEN 1            //以读写4字节的数据为例
      
      
      #define SEC 123           //读写的扇区(Sector)号
      
      
      #define SEC_OFFSET 0       //扇区内偏移量(必须是4的倍数)
      
      uint32 write_data[LEN];
      uint32 read_data[LEN];
      
      //TODO
      //Fill the write_data
      
      //读取数据
      spi_flash_read(SEC*4*1024+SEC_OFFSET, read_data, LEN*4); 
      
      //写入数据
      spi_flash_erase_sector(SEC);
      spi_flash_write(SEC*4*1024+SEC_OFFSET, write_data, LEN*4); 
      
      
      /*
      * 方式二
      */
      
      #define LEN 1             //以读写4字节的数据为例
      
      
      #define SEC 123           //读写的扇区(Sector)号
      
      
      #define SEC_OFFSET 0      //扇区内偏移量(必须是4的倍数)
      
      uint8 write_data[LEN*4];
      uint8 read_data[LEN*4];
      
      //TODO
      //Fill the write_data
      
      //读取数据
      spi_flash_read(SEC*4*1024+SEC_OFFSET, (uint32 *)&read_data, LEN*4); 
      
      //写入数据
      spi_flash_erase_sector(SEC);
      spi_flash_write(SEC*4*1024+SEC_OFFSET, (uint32 *)&write_data, LEN*4); 

      【总结】读写地址scr_addr=SEC*4*1024+SEC_OFFSET

  2. Flash地址映射

    ESP8266提供了读写Flash的接口,操作很简单,但不能随便找个地方就开始擦除然后写入自己的数据,这样很容易把数据写到不该写入的地方,造成一些潜在的问题,因此难点在于确定读写数据的安全位置。

    这里以8M bits1M bytes(1024 bytes)的Flash为例做以说明,其Flash布局如下。

bin 烧录地址 说明
boot.bin(boot_v1.6.bin) 0x00000 启动程序,SDK中提供。
user1.bin(user1.1024.new.2.bin) 0x01000 主程序,编译代码生成。
esp_init_data_default.bin 0x0fc000 初始化射频参数,SDK中提供。
blank.bin 0x0fe000 初始化系统参数,SDK中提供。

[注]上表参考ESP8266 Flash的维基百科的第三节(Layout With OTA)以及实际烧录配置。

程序区 boot.bin 起始地址0x00000
user1.bin起始地址0x01000
系统参数区 Flash最后4个扇区(即Flash最后16K Bytes)
esp_init_data_default.bin位于Flash倒数第4个 sector
blank.bin位于Flash倒数第2个sector

[注]软件支持云端升级(boot),上表参考自《ESP8266 Flash 读写说明》。

下面的更加直观地展示了1024KB Flash的分布情况:

Flash Layout
结合这张图,说明两个问题。

[注]对于1024KB的Flash,可以分为256(1024/4)个扇区,扇区号为0~255

  1. 确定各个文件的烧录地址

    (1)boot.bin,启动程序,烧录地址固定为Flash的开始位置,即0x00000

    (2)user1.bin,用户程序,紧跟在boot之后,boot占用第0个扇区(4KB),则user1.bin的起始地址应为第一个扇区的起始地址:

    1 × 4 × 1024 = 4096

    4096换算成十六进制就是0x01000;

    (3)esp_init_data_default.bin,初始化射频参数,位于Flash倒数第4个 sector(即252号扇区),则烧录地址应为:

    252 × 4 × 1024 = 1032192

    1032192换算成十六进制就是0x0fc000;

    (4)blank.bin,初始化系统参数,位于Flash倒数第2个sector(即254号扇区),则烧录地址为:

    254 × 4 × 1024 = 1040384

    1040384换算成十六进制就是0x0fe000;

  2. 用户存储数据的安全区域

    1. 如果用户程序user1.bin小于492KB,则剩余的空间可以用于存储用户数据;

      假设用户程序大小为480KB,则存储数据可用区域起始地址为:

      ( 4 + 480 ) × 1024 = 495616

      起始地址为:495616 —-> 0x79000,可用空间大小为此后的3个扇区(121号、122号、123号)。

    2. [推荐]存储在用户参数区(该区域专门用于上层应用程序存储用户参数),起始扇区号为:

      512 16 4 = 124

      则可用起始地址为:
      124 × 4 × 1024 = 507904

      起始地址为507904–> 0x7C000,可用此后的4个扇区(124号、125号、126号、127号)。

      [注]由上述计算可知,用户参数区是与程序区是相连的,因此用户程序大小不能超过492KB

【参考资料】
1. ESP8266 Flash 读写说明
2. ESP8266 Flash

猜你喜欢

转载自blog.csdn.net/u011852211/article/details/81390009