ESP32-S3 FLASH 操作

发布时间 2023-04-24 21:59:59作者: SpinJump

FLASH 读取操作

整个分区的读、写、擦除

# ESP-IDF Partition Table
# Name,    Type,  SubType, Offset,  Size, Flags
nvs,       data,  nvs,     0x9000,  0x4000,
otadata,   data,  ota,     ,        0x2000,
phy_init,  data,  phy,     ,        0x1000,
key_data,  0x40,  0,       ,        256k,
factory,   app,   factory, ,        3M,
const esp_partition_t *partition = esp_partition_find_first(0x40,  ESP_PARTITION_SUBTYPE_ANY,"key_data");

    // const esp_partition_t *partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY, "storage");
    assert(partition != NULL);

    static char store_data[] = "Test the read, write, and erase operations of the entire partition.";
    static char read_data[sizeof(store_data)];
    memset(read_data, 0xFF, sizeof(read_data));

    if(sizeof(store_data) >  partition->size)
    {
        ESP_LOGE(TAG,"The data exceeds the partition size.");
        return ;
    }

    // // 先擦除 分区
    ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, partition->size));

    // // 开始写入数据
    ESP_ERROR_CHECK(esp_partition_write(partition, 0, store_data, sizeof(store_data)));
    ESP_LOGI(TAG, "Written data: %s", store_data);

    // 读取数据,同时检查对比和写入数据的完整性
    ESP_ERROR_CHECK(esp_partition_read(partition, 0, read_data, sizeof(read_data)));
    // assert(memcmp(store_data, read_data, sizeof(read_data)) == 0);
    ESP_LOGI(TAG, "Read data: %s", read_data);

扇区的读、写、擦除

  1. esp32-s3 flash 的最小写入单位是字节,最大写入单位是页,但是超过一个扇区时就需要注意容易被误擦除。
  2. esp32-s3 flash 的最小读取单位是字节。
  3. esp32-s3 flash 的最小擦除单位是扇区。打印 erase_size就可以知道最小擦除的对齐是多少了。
typedef struct {
    esp_flash_t* flash_chip;            /*!< SPI flash chip on which the partition resides */
    esp_partition_type_t type;          /*!< partition type (app/data) */
    esp_partition_subtype_t subtype;    /*!< partition subtype */
    uint32_t address;                   /*!< starting address of the partition in flash */
    uint32_t size;                      /*!< size of the partition, in bytes */
    uint32_t erase_size;                /*!< size the erase operation should be aligned to */
    char label[17];                     /*!< partition label, zero-terminated ASCII string */
    bool encrypted;                     /*!< flag is set to true if partition is encrypted */
} esp_partition_t;

4.这个是单独操作扇区的示例。

#define  FLASH_SECTOR_SIZE  0x1000  //4K

void app_main(void)
{

    static char store_data[] = "Test the read, write, and erase operations of the entire partition.\n\
                                Test the read, write, and erase operations of the entire partition.\n\
                                Test the read, write, and erase operations of the entire partition.\n\
                                Test the read, write, and erase operations of the entire partition.\n\
                                Test the read, write, and erase operations of the entire partition.\n\
                                Test the read, write, and erase operations of the entire partition.";
    static char read_data[sizeof(store_data)];
    memset(read_data, 0xFF, sizeof(read_data));

    const esp_partition_t *partition = esp_partition_find_first(0x40, 0, "key_data");

    printf("erase_size %x size %x\r\n",partition->erase_size,partition->size);
    // // 先擦除 分区
    ESP_ERROR_CHECK(esp_partition_erase_range(partition, 0, FLASH_SECTOR_SIZE));

    // // 开始写入数据
    ESP_ERROR_CHECK(esp_partition_write(partition, 0, store_data, sizeof(store_data)));
    ESP_LOGI(TAG, "Written data: %s", store_data);

    // 读取数据,同时检查对比和写入数据的完整性
    ESP_ERROR_CHECK(esp_partition_read(partition, 0, read_data, sizeof(read_data)));
    assert(memcmp(store_data, read_data, sizeof(read_data)) == 0);
    
    ESP_LOGI(TAG, "read data: %s", read_data);

    printf("Restarting now.\n");
    fflush(stdout);

    // esp_restart();
}

封装两个 FLASH 读写函数

  1. 这两个读写函数,每次操作限制在 4K 之内。
#define KEY_DATA_SECTOR_SIZE 0X1000 //Sector size 4096/4K

static esp_err_t key_data_flash_read(void * buffer, uint32_t offset, uint32_t length)
{
    esp_err_t err;
    if(buffer ==NULL || (length > KEY_DATA_SECTOR_SIZE))
    {
        ESP_LOGE(KEY_DATA_TAG, "ESP_ERR_INVALID_ARG");
        return ESP_ERR_INVALID_ARG;
    }

    const esp_partition_t *key_data_partition = esp_partition_find_first(0x40,0x00,"key_data");
    if(key_data_partition == NULL)
    {
        ESP_LOGE(KEY_DATA_TAG, "Flash partition not found.");
        return ESP_FAIL;
    }

    err = esp_partition_read(key_data_partition, offset, buffer,length);
    if(err != ESP_OK)
    {
        ESP_LOGE(KEY_DATA_TAG, "Flash read failed.");
        return err;
    }
    return err;
}

static esp_err_t key_data_flash_write(void * buffer, uint32_t offset, uint32_t length)
{
    esp_err_t err;
    if(buffer ==NULL || (length > KEY_DATA_SECTOR_SIZE))
    {
        ESP_LOGE(KEY_DATA_TAG, "ESP_ERR_INVALID_ARG");
        return ESP_ERR_INVALID_ARG;
    }

    const esp_partition_t *key_data_partition = esp_partition_find_first(0x40,0x00,"key_data");
    if(key_data_partition == NULL)
    {
        ESP_LOGE(KEY_DATA_TAG, "Flash partition not found.");
        return ESP_FAIL;
    }

    err = esp_partition_erase_range(key_data_partition, offset, KEY_DATA_SECTOR_SIZE);
    if(err != ESP_OK)
    {
        ESP_LOGE(KEY_DATA_TAG, "Flash erase failed.");
        return err;
    }
    
    err = esp_partition_write(key_data_partition, offset, buffer, length);
    if(err != ESP_OK)
    {
        ESP_LOGE(KEY_DATA_TAG, "Flash write failed.");
        return err;
    }

    return err;
}