【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
对于一些大批量的数据,比如音视频,这种数据一般是用tf卡进行保存。但是对于一些参数、配置文件,或者是算法类的参数,这种还是倾向于用esp32内部flash进行保存。今天,就来看下,对于esp32来说,怎么用内部flash进行数据读写。
1、还是不用外部信号连接
和上一章wifi的测试一样,这一章只是内部数据读写,不涉及到外部信号读写。
2、弄清楚nvs和flash
esp的nvs是建立在flash基础之上的。也就是说,如果地址不对,操作flash的时候,有可能误操作nvs的内容。另外,flash本身是合封在esp32内部的,并不是挂在总线上面,这一点的话,速度略有差异,不过不影响我们使用。
3、适用范围
大多数情况下,nvs的操作已经够我们使用,比如开机次数、wifi密码、算法参数、用户自定义配置等等。只有数据稍大,但是又没有大到需要外置tf卡的时候,才需要flash读取。
4、ai编写代码
这一次ai编写代码的时候,提示我们首先需要修改CMakeLists.txt,内容是这样的,
idf_component_register(SRCS "main.c" INCLUDE_DIRS "." REQUIRES spi_flash nvs_flash)其次就是编写具体的函数内容,比如main.c,它的内容是这样的,
#include <stdio.h> #include <string.h> #include <stdint.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" #include "nvs_flash.h" #include "esp_flash.h" #include "esp_system.h" // Flash test parameters #define TEST_DATA_SIZE 256 #define TEST_SECTOR_OFFSET 0x180000 // Test sector offset (1.5MB position, after factory app) #define TEST_SECTOR_SIZE 4096 // Flash sector size (4KB) static const char *TAG = "FLASH_DEMO"; // NVS operation example static esp_err_t nvs_test(void) { esp_err_t err; nvs_handle_t my_handle; // Open NVS namespace err = nvs_open("storage", NVS_READWRITE, &my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error opening NVS: %s", esp_err_to_name(err)); return err; } // Write data int32_t boot_count = 0; err = nvs_get_i32(my_handle, "boot_count", &boot_count); if (err != ESP_OK && err != ESP_ERR_NVS_NOT_FOUND) { ESP_LOGE(TAG, "Error reading NVS: %s", esp_err_to_name(err)); nvs_close(my_handle); return err; } boot_count++; ESP_LOGI(TAG, "Boot count: %d", boot_count); err = nvs_set_i32(my_handle, "boot_count", boot_count); if (err != ESP_OK) { ESP_LOGE(TAG, "Error writing NVS: %s", esp_err_to_name(err)); nvs_close(my_handle); return err; } // Commit write err = nvs_commit(my_handle); if (err != ESP_OK) { ESP_LOGE(TAG, "Error committing NVS: %s", esp_err_to_name(err)); nvs_close(my_handle); return err; } // Write string char test_str[] = "Hello from NVS!"; err = nvs_set_str(my_handle, "message", test_str); if (err != ESP_OK) { ESP_LOGE(TAG, "Error writing string to NVS: %s", esp_err_to_name(err)); nvs_close(my_handle); return err; } err = nvs_commit(my_handle); // Read string char read_str[32] = {0}; size_t len = sizeof(read_str); err = nvs_get_str(my_handle, "message", read_str, &len); if (err == ESP_OK) { ESP_LOGI(TAG, "Read from NVS: %s", read_str); } nvs_close(my_handle); return ESP_OK; } // SPI Flash direct operation example static esp_err_t spi_flash_test(void) { esp_err_t err; uint8_t write_buffer[TEST_DATA_SIZE]; uint8_t read_buffer[TEST_DATA_SIZE]; esp_flash_t *flash_chip = (esp_flash_t *)esp_flash_default_chip; // Prepare test data for (int i = 0; i < TEST_DATA_SIZE; i++) { write_buffer[i] = i % 256; } // Erase region (sector) ESP_LOGI(TAG, "Erasing flash region at offset 0x%x", TEST_SECTOR_OFFSET); err = esp_flash_erase_region(flash_chip, TEST_SECTOR_OFFSET, TEST_SECTOR_SIZE); if (err != ESP_OK) { ESP_LOGE(TAG, "Error erasing flash: %s", esp_err_to_name(err)); return err; } // Write data ESP_LOGI(TAG, "Writing %d bytes to flash at offset 0x%x", TEST_DATA_SIZE, TEST_SECTOR_OFFSET); err = esp_flash_write(flash_chip, write_buffer, TEST_SECTOR_OFFSET, TEST_DATA_SIZE); if (err != ESP_OK) { ESP_LOGE(TAG, "Error writing flash: %s", esp_err_to_name(err)); return err; } // Read data ESP_LOGI(TAG, "Reading %d bytes from flash at offset 0x%x", TEST_DATA_SIZE, TEST_SECTOR_OFFSET); err = esp_flash_read(flash_chip, read_buffer, TEST_SECTOR_OFFSET, TEST_DATA_SIZE); if (err != ESP_OK) { ESP_LOGE(TAG, "Error reading flash: %s", esp_err_to_name(err)); return err; } // Verify data bool data_ok = true; for (int i = 0; i < TEST_DATA_SIZE; i++) { if (read_buffer[i] != write_buffer[i]) { ESP_LOGE(TAG, "Data mismatch at offset %d: expected 0x%02x, got 0x%02x", i, write_buffer[i], read_buffer[i]); data_ok = false; break; } } if (data_ok) { ESP_LOGI(TAG, "SPI Flash read/write test PASSED"); } return data_ok ? ESP_OK : ESP_FAIL; } void app_main(void) { // Initialize NVS esp_err_t err = nvs_flash_init(); if (err == ESP_ERR_NVS_NO_FREE_PAGES || err == ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); err = nvs_flash_init(); } ESP_ERROR_CHECK(err); // Test NVS operations ESP_LOGI(TAG, "=== Testing NVS ==="); nvs_test(); // Test SPI Flash direct operations ESP_LOGI(TAG, "=== Testing SPI Flash ==="); spi_flash_test(); ESP_LOGI(TAG, "Flash demo completed!"); }编写过程可能不顺利,比如说idf版本不对、缺少库、地址存在错误、测试不通过等等,这些都是正常的,直接发给ai,再来一次就可以了。
5、编译、测试和阅读代码
前面说过,本身代码是否可以顺利编译是非常重要的,如果有问题,需要直接通知ai修改。只有可以编译、可以执行的代码才值得我们去阅读和修改。编译好了,直接烧入,看看能不能跑起来,有没有错误。有错误的话,还是继续发送日志给ai。直到测试全ok为止。
最后就是开始阅读代码,保存起来,下次作为项目代码使用。