在某些情况下,有些资源过于大,所以需要使用外部flash保存数据
这篇文章使用ESP32S3作为主控,驱动读写外部flash
1.硬件连接
flash通常为8pin,最主要的线为这六根:
- MOSI GPIO11
- MISO GPIO13
- CLK 12
- HD 9
- WP 14
- CS 10
需要注意的是,flash的HD和WP引脚在不同的读写模式下,具有不同的功能
- HD引脚的默认功能用于暂停SPI通信
- WP用于保护Flash存储器的某些部分不被写入或擦除
通信接口:目前市场是常见的flash支持五种通信方式:
- SPI:最常用的通信方式,使用两根数据线进行双向传输
- DOUT:数据读取使用两根数据线
- DIO:数据和地址传输都是用两根数据线
- IO0(通常标记为 MOSI 或 D0): 数据线0
- IO1(通常标记为 MISO 或 D1): 数据线1
- QOUT:数据读取使用四根数据线
- QIO:数据和地址传输都是用四根数据线
- IO0(通常标记为 MOSI 或 D0): 数据线0
- IO1(通常标记为 MISO 或 D1): 数据线1
- IO2(通常标记为 WP 或 D2): 数据线2
- IO3(通常标记为 HOLD 或 D3): 数据线3
2.软件驱动
驱动使用IDF中的驱动库:esp_flash,简单的配置相关接口,就可以进行读写操作了,ESP32中,模组内部的flash也使用的该组件
代码中,可以很方便的配置相关信息:连接引脚,时钟速率,读取模式,使用的SPI- #include <stdio.h>
- #include <string.h>
- #include <inttypes.h>
- #include <freertos/FreeRTOS.h>
- #include <freertos/task.h>
- #include <freertos/semphr.h>
- #include <unity.h>
- #include "esp_flash.h"
- #include "esp_private/spi_common_internal.h"
- #include "esp_flash_spi_init.h"
- #include "memspi_host_driver.h"
- #include "spi_flash_mmap.h"
- #include <esp_attr.h>
- #include "esp_log.h"
- #include "unity.h"
- #include "driver/gpio.h"
- #include "soc/io_mux_reg.h"
- #include "sdkconfig.h"
- #include "esp_partition.h"
- #include "esp_rom_gpio.h"
- #include "esp_rom_sys.h"
- #include "esp_timer.h"
- #include "spi_flash_mmap.h"
- #include "esp_private/spi_flash_os.h"
- #include "esp_timer.h"
- #define TAG "SPI_FLASH"
- typedef esp_flash_spi_device_config_t flashtest_config_t;
- #define FSPI_PIN_NUM_MOSI 11
- #define FSPI_PIN_NUM_MISO 13
- #define FSPI_PIN_NUM_CLK 12
- #define FSPI_PIN_NUM_HD 9
- #define FSPI_PIN_NUM_WP 14
- #define FSPI_PIN_NUM_CS 10
- // Just use the same pins for HSPI
- #define HSPI_PIN_NUM_MOSI FSPI_PIN_NUM_MOSI
- #define HSPI_PIN_NUM_MISO FSPI_PIN_NUM_MISO
- #define HSPI_PIN_NUM_CLK FSPI_PIN_NUM_CLK
- #define HSPI_PIN_NUM_HD FSPI_PIN_NUM_HD
- #define HSPI_PIN_NUM_WP FSPI_PIN_NUM_WP
- #define HSPI_PIN_NUM_CS FSPI_PIN_NUM_CS
- #define MAX_ADDR_24BIT 0x1000000
- #define TEST_SPI_SPEED 80
- #define TEST_SPI_READ_MODE SPI_FLASH_QIO
- flashtest_config_t ext_flash_config = {
- .io_mode = TEST_SPI_READ_MODE,
- .freq_mhz = TEST_SPI_SPEED,
- .host_id = SPI2_HOST,
- .cs_id = 0,
- .cs_io_num = FSPI_PIN_NUM_CS,
- .input_delay_ns = 0,
- };
- static void setup_bus(spi_host_device_t host_id)
- {
- if (host_id == SPI2_HOST)
- {
- ESP_LOGI(TAG, "setup flash on SPI%u (FSPI) CS0...\n", host_id + 1);
- spi_bus_config_t fspi_bus_cfg = {
- .mosi_io_num = FSPI_PIN_NUM_MOSI,
- .miso_io_num = FSPI_PIN_NUM_MISO,
- .sclk_io_num = FSPI_PIN_NUM_CLK,
- .quadhd_io_num = FSPI_PIN_NUM_HD,
- .quadwp_io_num = FSPI_PIN_NUM_WP,
- .max_transfer_sz = 16 * 1024,
- };
- esp_err_t ret = spi_bus_initialize(host_id, &fspi_bus_cfg, 0);
- TEST_ESP_OK(ret);
- }
- #if SOC_SPI_PERIPH_NUM > 2
- else if (host_id == SPI3_HOST)
- {
- ESP_LOGI(TAG, "setup flash on SPI%u (HSPI) CS0...\n", host_id + 1);
- spi_bus_config_t hspi_bus_cfg = {
- .mosi_io_num = HSPI_PIN_NUM_MOSI,
- .miso_io_num = HSPI_PIN_NUM_MISO,
- .sclk_io_num = HSPI_PIN_NUM_CLK,
- .quadhd_io_num = HSPI_PIN_NUM_HD,
- .quadwp_io_num = HSPI_PIN_NUM_WP,
- .max_transfer_sz = 16 * 1024,
- };
- esp_err_t ret = spi_bus_initialize(host_id, &hspi_bus_cfg, 0);
- TEST_ESP_OK(ret);
- // HSPI have no multiline mode, use GPIO to pull those pins up
- gpio_set_direction(HSPI_PIN_NUM_HD, GPIO_MODE_OUTPUT);
- gpio_set_level(HSPI_PIN_NUM_HD, 1);
- gpio_set_direction(HSPI_PIN_NUM_WP, GPIO_MODE_OUTPUT);
- gpio_set_level(HSPI_PIN_NUM_WP, 1);
- }
- #endif
- else
- {
- ESP_LOGE(TAG, "invalid bus");
- }
- }
- static void setup_new_chip(const flashtest_config_t *test_cfg, esp_flash_t **out_chip)
- {
- setup_bus(test_cfg->host_id);
- esp_flash_spi_device_config_t dev_cfg = {
- .host_id = test_cfg->host_id,
- .io_mode = test_cfg->io_mode,
- .freq_mhz = test_cfg->freq_mhz,
- .cs_id = test_cfg->cs_id,
- .cs_io_num = test_cfg->cs_io_num,
- .input_delay_ns = test_cfg->input_delay_ns,
- };
- esp_flash_t *init_chip;
- esp_err_t err = spi_bus_add_flash_device(&init_chip, &dev_cfg);
- if (err != ESP_OK)
- {
- printf("error in spi bus init:%d\n", err);
- return;
- }
- err = esp_flash_init(init_chip);
- if (err != ESP_OK)
- {
- printf("error in esp flash init:%d\n", err);
- return;
- }
- *out_chip = init_chip;
- }
- void write_erase_read_time_test(esp_flash_t *chip, uint32_t size)
- {
- printf("\ntest start...\n");
- printf("test size:%ld\n", size);
- long long start_time, end_time;
- uint8_t *write_buffer = malloc(size);
- uint8_t *read_buffer = malloc(size);
- // 写入部分测试值
- for (int i = 0; i < size; i++)
- {
- write_buffer[i] = i;
- }
- start_time = esp_timer_get_time();
- esp_flash_erase_region(chip, 0, size);
- end_time = esp_timer_get_time();
- printf("erase time:%lluus\n", end_time - start_time);
- start_time = esp_timer_get_time();
- esp_flash_write(chip, write_buffer, 0, size);
- end_time = esp_timer_get_time();
- printf("write time:%lluus\n", end_time - start_time);
- start_time = esp_timer_get_time();
- esp_flash_read(chip, read_buffer, 0, size);
- end_time = esp_timer_get_time();
- printf("read time:%lluus\n", end_time - start_time);
- printf("test end...\n\n");
- free(write_buffer);
- free(read_buffer);
- }
- #define TEST_DATA_SIZE 1024
- void app_main(void)
- {
- esp_flash_t *chip;
- setup_new_chip(&ext_flash_config, &chip);
- uint32_t size;
- esp_err_t err = esp_flash_get_size(chip, &size);
- if (err != ESP_OK)
- {
- printf("error in esp flash get size :%d\n", err);
- return;
- }
- printf("get size:%ld\n", size);
- write_erase_read_time_test(chip, 1 * TEST_DATA_SIZE);
- write_erase_read_time_test(chip, 2 * TEST_DATA_SIZE);
- write_erase_read_time_test(chip, 4 * TEST_DATA_SIZE);
- write_erase_read_time_test(chip, 8 * TEST_DATA_SIZE);
- write_erase_read_time_test(chip, 16 * TEST_DATA_SIZE);
- }
复制代码 3.性能实际测试
时钟速率为20、40、80Mhz,使用QIO模式,分别对1、2、4、8、16KB文件大小进行读写测试,结果如下
写/读测试(us)20Mhz40Mhz80Mhz1KB3711/2133453/1543069/1242KB3634/4083120/2892431/2284KB16787/80915806/56016778/4408KB196421/158417545/110516426/86416KB42919/315539205/219236918/1713出于好奇,我也测试了一下SPI与QSPI的速度差距,但是只测试了80Mhz时钟速率下的:
SPI 写/读测试(us)80Mhz1KB3056/2062KB2852/3924KB13440/7688KB16411/152116KB35974/3024可以看到,虽然QSPI的数据理论上是SPI的四倍,但是实际测试下来,速度提升还不到两倍,没有想象中那么高
实际的QSPI的速率也太低了,按照16KB的速度折合下来也才10MB每秒,只有理论速度的25%,某些地方应该还存在优化空间
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |