ESP8266 SDK开发: 外设篇-内存分布说明及Flash读写
<p><iframe name="ifd" src="https://mnifdv.cn/resource/cnblogs/Learn8266ForSDK" frameborder="0" scrolling="auto" width="100%" height="1500"></iframe></p>
说明
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个
然后,为啥做这个芯片的要规定 块,扇区和页这些东西呢????
因为哈,擦除的时候规定要么擦除某个扇区要么擦除某个块
这是最小擦除的单位....
然后写数据的时候呢是页写....也就是只能写某一页,所以最多写256字节
假设咱需要把数据写到第一个块里面的第一个扇区里面的第一页里面
那么咱呢可以直接写命令擦除第一个块里面的第一个扇区
然后把数据写到里面.
或者也可以擦除第一个块,然后把数据写到里面
然后看看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函数
1.擦除某个扇区
总共1024个扇区,扇区号从0开始,所以是 0 - 1023
列如擦除上面的倒数第5个扇区 就是 spi_flash_erase_sector (1019)
2.往扇区里面写数据
3.从flash里面读取数据
4.SDK还封装了一套交替存储API
就是使用3个扇区保存数据,第一个扇区和第三个扇区来回的保存数据
第二个扇区只保存一个标志位,标志当前数据是存储在第一个扇区还是第二个扇区(程序内部实现)
API函数的第二个参数假设是 1017
那么就是使用第1017和1018扇区来回的保存数据,1018扇区保存标志位
注意:关于4字节对齐
如果你存储数据,存储的数据个数是4的倍数就可以.
一般咱都会把数据放到一个数组里面,所以咱把数组长度定义为4的倍数就可以
我上面说的是char型的数组
如果是u16型的数组,数组长度定义为2的倍数就可以
如果是u32的就随意啦....
开始实践(普通)
好像啥都说明白了....用户自己实践就可以了
//设置扇区地址 #define flash_save_sector 1019 //设置写入flash的起始地址 #define flash_save_addr flash_save_sector*4*1024 //(该扇区的起始地址) //存储的数据 char flash_data[16] = "test flash data"; /** * @brief system_done * @param None * @param None * @retval None * @warning None * @example **/ void system_done(void) { char temp[16]; //擦除扇区 spi_flash_erase_sector (flash_save_sector); //写入数据 spi_flash_write(flash_save_addr,(uint32 *)flash_data,sizeof(flash_data)); //读取数据 spi_flash_read(flash_save_addr,(uint32 *)temp,sizeof(temp)); os_printf("\r\n save data =%s \r\n",temp); } void ICACHE_FLASH_ATTR user_init(void){ uart_init_2(BIT_RATE_115200,BIT_RATE_115200); //注册系统初始化完成回调函数 system_init_done_cb(system_done); }
开始实践(写保护)
1.官方给了例子
注意 priv_param_start_sec 参数是这个参数
咱使用的时候也这样就可以