ESP32的系统存储

一、ESP32中的分区表

ESP32的程序编译完后会分成几个部分:①bootloader②app③partition分区的bin文件

(1)ESP-IDF提供的默认分区文件:

①Type:app用于表示运行的程序 data表示存储的数据 

②Flags:encrypted:表示分区将被加密 readonly表示只允许对分区进行读操作,指定了类型后会被强制加密,所以不用选encrypted

①nvs表示非易失性存储区,表示掉电之后数据依然能够保存,esp32专门有了这一片区域,存储以下几个内容:1、存储每台wifi物理层的校准数据,2、存wifi数据,比如wifi的ssid和密码,3、存我们应用自己的数据

②phy表示用于分区存储WIFI的物理层初始化数据,一般这里是不启用的

③bootloader在分区表中起始地址是0x1000,分区表在flash中存储的地址为0x8000,大小是0x1000,除开bootloader和分区表本身,真正可用的地址是在0x9000开始的

④偏移Offset留空则esp-idf就会自动帮我们计算

⑤factory为默认的app分区,上电之后程序会在这里启动,如果存在类型为ota的分区,bootloader会先检查ota的分区的内容,再决定启用哪个app分区的内容进行程序启用,这么做是为了处理ota升级

⑥app分区的内存地址必须与0x10000对齐(64KB)

(2)具有ota的分区文件:

①子类型是ota的分区用于存储当前所选的ota应用程序的信息,这个分区的大小需要设置为0x2000

②ota_0和ota_1由otadata中的信息决定要启用哪个ota应用程序分区中的程序,至少要有两个ota应用程序分区

③进行分区表设置的内存大小设置的时候,要注意大小不要超过esp模组的flash大小

(3)menuconfig中的分区设置

(4)如何读写分区表中的分区

①包含头文件“esp_partition.h”

②定义一个分区指针

static const esp_partition_t* partition_ptr = NULL;

③查找分区传递给分区指针

partition_ptr = esp_partition_find_first(USER_PARTITION_TYPE,USER_PARTITION_SUBTYPE,NULL,);

这个函数与find的区别是其会将分区表的第一项返回,但是find函数会返回迭代器,将所有返回

④对分区flash进行先擦除再读取的操作

void app_main(void)
{
    partition_ptr = esp_partition_find_first(USER_PARTITION_TYPE,USER_PARTITION_SUBTYPE,NULL,);
    if(partition_ptr == NULL)
    {
        ESP_LOGE(TAG,"Can't find partition");
        return;
    } 
    esp_partition_erase_range(partition_ptr,0,0x1000);
    const char *test_string = "this is for test partition";
    esp_partition_write(partition_ptr,0,test_string,strlen(test_string));
    char read_buf[64];
    memset(read_buf,0,sizeof(read_buf));    //进行数据清0,防止脏数据
    esp_partition_read(partition_ptr,0,read_buf,strlen(test_string));
    ESP_LOGI(TAG,"read partition data:%s",read_buf);
    return;
}

二、ESP32中的NVS

①NVS一般用于存储一些配置数据、状态数据等,一般不会用来存放大量数据量,在嵌入式系统中,NVS主要是在Flash上进行键值对的存储

②NVS还需要指定一个命名空间,因为键名是有可能取到一样的

③命名空间和键都是字符串类型,字符串默认的是15个字节

④写入数据代码编写:

1、先添加nvs_flash.h头文件

2、定义命名空间

3、进行nvs初始化,检测是否成功(可以使用ESP_ERROR_CHECK,这个函数发现错误时会阻塞在这里,而且会打印相应的错误类型,要记得包含esp_err.h头文件),不成功则擦除后再进行初始化

4、使用nvs_open打开命名空间,并指定怎么进行操作,传入操作句柄其会返回操作句柄

5、使用nvs_set_blob写入数据,随后使用nvs_commit进行立即写入

6、关闭命名空间

⑤读取数据代码编写:

1、先定义一个长度存储值

2、通过只读打开命名空间

3、通过nvs_get_blob函数第三个参数传入NULL,其会返回第四个参数length的值

4、分配内存空间并读取相应的键的值

void my_nvs_blob_read(const char *namespace, const char *key, void *buffer, int maxlen)
{
    nvs_handle_t nvs_handle;
    size_t length = 0;
    nvs_open(namespace, NVS_READONLY, &nvs_handle);
    nvs_get_blob(nvs_handle, key, NULL, &length);
    if (length && length <= maxlen)
    {
        nvs_get_blob(nvs_handle, key, buffer, &length);
    }
    nvs_close(nvs_handle);
}

三、SPIFFS文件系统

(1)SPIFFS是一个用于SPI nor flash设备的嵌入式文件系统

(2)我们要使用SPIFFS文件系统的时候要新建一个分区表,指定type=data,子类型subtype=spiffs,表示此分区用于spiffs文件系统存储,记得在menuconfig中进行设置

(3)在espidf中虚拟文件系统vfs为驱动程序提供一个统一接口,可以操作类文件对象,我们可以如果我们想要用标准C语言函数来统一管理和操作文件系统,就需要把操作SPIFFS文件系统和FAT32文件系统的接口注册到VFS中,由VFS来统一管理,这样就可以使用标准C语言进行文件操作

(4)spiffs文件系统做不到全部使用分区里面的大小,只能稳定使用75%左右

进行代码编写

(1)包含头文件“esp_spiffs.h”

(2)定义一个spiffs文件系统的描述结构体,填充路径(挂载点);分区的名称(分区的名称可以留空,一旦留空的话分区就会找到第一个spiffs分区作为操作对象);最大可打开的文件数;挂载失败是否执行格式化

esp_vfs_spiffs_conf_t conf = 
    {
        .base_path = "/spiffs",
        .partition_label = NULL,
        .max_files = 5,
        .format_if_mount_failed = true,
    };

(3)进行结构体注册

esp_vfs_spiffs_register(&conf);

(4)在初始化时可以检查SPIFFS文件系统的完整性,使用如下的函数

esp_spiffs_check(conf.partition_label);

(5)获取分区的总区域和可用区域

esp_spiffs_info(conf.partition_label,&total,&used);

(6)随后即可以通过C语言文件操作

FILE *f = fopen("/spiffs/hello.txt", "w");
    if(f == NULL)
    {
        ESP_LOGE("spiffs","Failed to open file");
        return;
    }
    fprintf(f,"Helloword\n");
    fclose(f);

    vTaskDelay(pdMS_TO_TICKS(1000));
    
    f =  fopen("/spiffs/hello.txt", "r");
    if(f == NULL)
    {
        ESP_LOGE("spiffs","Failed to open file for read");
        return;
    }
    char line[64];
    fgets(line,sizeof(line),f);
    fclose(f);

(7)主文件中的代码如下:

#include <stdio.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_spiffs.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <string.h>

void app_main(void)
{
    esp_vfs_spiffs_conf_t conf =
        {
            .base_path = "/spiffs",
            .partition_label = NULL,
            .max_files = 5,
            .format_if_mount_failed = true,
        };
    esp_err_t ret = esp_vfs_spiffs_register(&conf);
    if (ret != ESP_OK)
    {
        ESP_LOGE("spiffs", "spiffs mount fail!"); // 提示挂载失败
        return;
    }
    ret = esp_spiffs_check(conf.partition_label);
    if (ret != ESP_OK)
    {
        ESP_LOGE("spiffs", "spiffs check fail!");
        return;
    }
    /*获取spiffs分区的大小*/
    size_t total = 0, used = 0;
    ret = esp_spiffs_info(conf.partition_label, &total, &used);
    if (ret != ESP_OK)
    {
        ESP_LOGE("spiffs", "get spiffs info fail!");
        return;
    }

    ESP_LOGI("spiffs", "spiffs total size:%d,used:%d", total, used);

    if (used > total)
    {
        ret = esp_spiffs_check(conf.partition_label);
        if (ret != ESP_OK)
        {
            ESP_LOGE("spiffs", "used > total & spiffs check fail!"); // 提示挂载失败
            return;
        }
    }

    FILE *f = fopen("/spiffs/hello.txt", "w");
    if(f == NULL)
    {
        ESP_LOGE("spiffs","Failed to open file");
        return;
    }
    fprintf(f,"Helloword\n");
    fclose(f);

    vTaskDelay(pdMS_TO_TICKS(1000));
    
    f =  fopen("/spiffs/hello.txt", "r");
    if(f == NULL)
    {
        ESP_LOGE("spiffs","Failed to open file for read");
        return;
    }
    char line[64];
    fgets(line,sizeof(line),f);
    fclose(f);

    char *pos = strchr(line,'\n');  //找到回车字符并返回它的下标
    if(pos)
    {
        *pos = 0;
    }
    ESP_LOGI("spiffs","read str:%s",line);
    esp_vfs_spiffs_unregister(conf.partition_label);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值