feat(examples): Add storage IO speed benchmark example

New example which can benchmark IO speed of SPI flash partition
(raw, FATFS, SPIFFS) and SD card (raw, FATFS) connected via SPI and SDMMC.
This commit is contained in:
Adam Múdry 2023-06-20 12:00:26 +02:00
parent e297470e62
commit e7b88a52d1
14 changed files with 1241 additions and 0 deletions

View File

@ -0,0 +1,6 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(perf_benchmark)

View File

@ -0,0 +1,263 @@
| Supported Targets | ESP32 | ESP32-C2 | ESP32-C3 | ESP32-C6 | ESP32-H2 | ESP32-S2 | ESP32-S3 |
| ----------------- | ----- | -------- | -------- | -------- | -------- | -------- | -------- |
# Storage performance benchmark example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
**WARNING: This example will format both your SPI flash "storage" partition and SD card (if used)!**
This example demonstrates a benchmark of a storage media such as SPI flash memory and SD card.
Only ESP32 and ESP32-S3 targets can use SDMMC mode when connecting to a SD card.
### Pin assignments for SD card connection
The GPIO pin numbers used to connect an SD card can be customized using the following:
- Run `idf.py menuconfig` in the project directory and open "Performance Benchmark Example Configuration" menu.
However, pins cannot be customized when using ESP32 target in SDMMC mode (`SDMMC_HOST_SLOT_1`).
This example doesn't utilize card detect (CD) and write protect (WP) signals from SD card slot.
The table below shows the default pin assignments.
SD card pin | SPI pin | ESP32 pin | ESP32-S2 | ESP32-S3 | ESP32-H2 | ESP32-C3 and other chips | Notes
------------|---------|---------------|----------|----------|----------|--------------------------|-------------
D0 | MISO | GPIO2 | GPIO37 | GPIO37 | GPIO0 | GPIO6 | 10k pullup
D1 | - | GPIO4 | - | GPIO38 | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode
D2 | - | GPIO12 (MTDI) | - | GPIO33 | - | - | not used in 1-line SD mode; 10k pullup in 4-line mode
D3 | CS | GPIO13 (MTCK) | GPIO34 | GPIO34 | GPIO1 | GPIO1 | not used in 1-line SD mode, but card's D3 pin must have a 10k pullup
CLK | SCK | GPIO14 (MTMS) | GPIO36 | GPIO36 | GPIO4 | GPIO5 | 10k pullup
CMD | MOSI | GPIO15 (MTDO) | GPIO35 | GPIO35 | GPIO5 | GPIO4 | 10k pullup
### 4-line and 1-line SD modes
By default, this example uses 4 line SD mode, utilizing 6 pins: CLK, CMD, D0 - D3. It is possible to use 1-line mode (CLK, CMD, D0) by changing "SD/MMC bus width" in the example configuration menu (see `CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1`).
Note that even if card's D3 line is not connected to the ESP chip, it still has to be pulled up, otherwise the card will go into SPI protocol mode.
### Note about GPIO2 (ESP32 only)
GPIO2 pin is used as a bootstrapping pin, and should be low to enter UART download mode. One way to do this is to connect GPIO0 and GPIO2 using a jumper, and then the auto-reset circuit on most development boards will pull GPIO2 low along with GPIO0, when entering download mode.
- Some boards have pulldown and/or LED on GPIO2. LED is usually ok, but pulldown will interfere with D0 signals and must be removed. Check the schematic of your development board for anything connected to GPIO2.
### Note about GPIO12 (ESP32 only)
GPIO12 is used as a bootstrapping pin to select output voltage of an internal regulator which powers the flash chip (VDD_SDIO). This pin has an internal pulldown so if left unconnected it will read low at reset (selecting default 3.3V operation). When adding a pullup to this pin for SD card operation, consider the following:
- For boards which don't use the internal regulator (VDD_SDIO) to power the flash, GPIO12 can be pulled high.
- For boards which use 1.8V flash chip, GPIO12 needs to be pulled high at reset. This is fully compatible with SD card operation.
- On boards which use the internal regulator and a 3.3V flash chip, GPIO12 must be low at reset. This is incompatible with SD card operation.
* In most cases, external pullup can be omitted and an internal pullup can be enabled using a `gpio_pullup_en(GPIO_NUM_12);` call. Most SD cards work fine when an internal pullup on GPIO12 line is enabled. Note that if ESP32 experiences a power-on reset while the SD card is sending data, high level on GPIO12 can be latched into the bootstrapping register, and ESP32 will enter a boot loop until external reset with correct GPIO12 level is applied.
* Another option is to burn the flash voltage selection efuses. This will permanently select 3.3V output voltage for the internal regulator, and GPIO12 will not be used as a bootstrapping pin. Then it is safe to connect a pullup resistor to GPIO12. This option is suggested for production use.
The following command can be used to program flash voltage selection efuses **to 3.3V**:
```sh
components/esptool_py/esptool/espefuse.py set_flash_voltage 3.3V
```
This command will burn the `XPD_SDIO_TIEH`, `XPD_SDIO_FORCE`, and `XPD_SDIO_REG` efuses. With all three burned to value 1, the internal VDD_SDIO flash voltage regulator is permanently enabled at 3.3V. See the technical reference manual for more details.
`espefuse.py` has a `--do-not-confirm` option if running from an automated flashing script.
See [the document about pullup requirements](https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/sd_pullup_requirements.html) for more details about pullup support and compatibility of modules and development boards.
## How to use example
### Configure
1. Set the target chip: `idf.py set-target TARGET` (replace TARGET with ESP32 chip series name)
1. Configure the example (`idf.py menuconfig` -> "Performance Benchmark Example Configuration") wheter you want to:
- Test internal SPI flash
- Raw access
- FATFS
- SPIFFS
- Test SD card
- Select SD card interface
- SDSPI
- SDMMC
- SD card test configuration
- Raw access
- FATFS
- Set SD card frequency
- Set GPIO pins
Some configuration options may be available for ESP32 and ESP32-S3 only.
### Build and flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT build flash monitor
```
(Replace PORT with serial port name.)
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example output
```
I (345) example: Start of the example
I (355) example: Internal flash test
I (355) example: Mountig WL layer...
I (415) example: WL layer mounted
I (505) example: Test with 128kiB file
Wrote 131072 bytes in 320.295ms (0.390MiB/s) to address 0
I (895) example: WL layer unmounted
I (895) example: Mounting FATFS partition...
W (895) vfs_fat_spiflash: f_mount failed (13)
I (895) vfs_fat_spiflash: Formatting FATFS partition, allocation unit size=16384
I (1105) vfs_fat_spiflash: Mounting again
I (1105) example: FATFS mounted to /spiflash
I (1205) example: Test with 128kiB file
Wrote 131072 bytes (buffer size 4096B) in 1295.988ms (0.096MiB/s)
Wrote 131072 bytes (buffer size 8192B) in 1277.569ms (0.098MiB/s)
Wrote 131072 bytes (buffer size 16384B) in 1439.405ms (0.087MiB/s)
Read 131072 bytes (buffer size 4096B) in 17.721ms (7.054MiB/s)
Read 131072 bytes (buffer size 8192B) in 16.945ms (7.377MiB/s)
Read 131072 bytes (buffer size 16384B) in 16.596ms (7.532MiB/s)
I (5705) example: Test with 256kiB file
Wrote 262144 bytes (buffer size 4096B) in 2529.380ms (0.099MiB/s)
Wrote 262144 bytes (buffer size 8192B) in 2867.352ms (0.087MiB/s)
Wrote 262144 bytes (buffer size 16384B) in 2879.113ms (0.087MiB/s)
Read 262144 bytes (buffer size 4096B) in 34.809ms (7.182MiB/s)
Read 262144 bytes (buffer size 8192B) in 33.315ms (7.504MiB/s)
Read 262144 bytes (buffer size 16384B) in 32.601ms (7.668MiB/s)
I (14535) example: Test with 512kiB file
Wrote 524288 bytes (buffer size 4096B) in 5119.009ms (0.098MiB/s)
Wrote 524288 bytes (buffer size 8192B) in 5897.010ms (0.085MiB/s)
Wrote 524288 bytes (buffer size 16384B) in 5888.743ms (0.085MiB/s)
Read 524288 bytes (buffer size 4096B) in 68.975ms (7.249MiB/s)
Read 524288 bytes (buffer size 8192B) in 66.063ms (7.569MiB/s)
Read 524288 bytes (buffer size 16384B) in 64.624ms (7.737MiB/s)
I (32295) example: FATFS partition unmounted
I (32295) example: Mounting SPIFFS partition...
W (32295) SPIFFS: mount failed, -10025. formatting...
I (38195) example: SPIFFS mounted to /spiflash
I (41555) example: Partition size: total: 896321, used: 0
I (41645) example: Test with 128kiB file
Wrote 131072 bytes (buffer size 4096B) in 819.950ms (0.152MiB/s)
Wrote 131072 bytes (buffer size 8192B) in 777.949ms (0.161MiB/s)
Wrote 131072 bytes (buffer size 16384B) in 751.682ms (0.166MiB/s)
Read 131072 bytes (buffer size 4096B) in 101.810ms (1.228MiB/s)
Read 131072 bytes (buffer size 8192B) in 99.518ms (1.256MiB/s)
Read 131072 bytes (buffer size 16384B) in 98.472ms (1.269MiB/s)
I (45335) example: Test with 256kiB file
Wrote 262144 bytes (buffer size 4096B) in 1650.525ms (0.151MiB/s)
Wrote 262144 bytes (buffer size 8192B) in 3220.004ms (0.078MiB/s)
Wrote 262144 bytes (buffer size 16384B) in 7139.803ms (0.035MiB/s)
Read 262144 bytes (buffer size 4096B) in 204.933ms (1.220MiB/s)
Read 262144 bytes (buffer size 8192B) in 200.330ms (1.248MiB/s)
Read 262144 bytes (buffer size 16384B) in 198.129ms (1.262MiB/s)
I (60365) example: Test with 512kiB file
Wrote 524288 bytes (buffer size 4096B) in 13917.135ms (0.036MiB/s)
Wrote 524288 bytes (buffer size 8192B) in 14302.046ms (0.035MiB/s)
Wrote 524288 bytes (buffer size 16384B) in 14411.794ms (0.035MiB/s)
Read 524288 bytes (buffer size 4096B) in 317.944ms (1.573MiB/s)
Read 524288 bytes (buffer size 8192B) in 308.865ms (1.619MiB/s)
Read 524288 bytes (buffer size 16384B) in 304.305ms (1.643MiB/s)
I (108835) example: SPIFFS partition unmounted
I (108835) example: SD card test
I (108845) example: Initializing SD card
I (108845) example: Using SDMMC peripheral
I (108855) example: Mounting SD card - raw access
I (108855) gpio: GPIO[36]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108865) gpio: GPIO[35]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108875) gpio: GPIO[37]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108885) gpio: GPIO[38]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108895) gpio: GPIO[33]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108905) gpio: GPIO[34]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (108955) gpio: GPIO[34]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (108965) example: SD card mounted - raw access
Name: USD00
Type: SDHC/SDXC
Speed: 40.00 MHz (limit: 40.00 MHz)
Size: 15080MB
CSD: ver=2, sector_size=512, capacity=30883840 read_bl_len=9
SSR: bus_width=4
Wrote 65536 bytes in 25.321ms (2.468MiB/s) to sector 415075
Read 65536 bytes in 3.809ms (16.409MiB/s) from sector 415075
Wrote 131072 bytes in 7.415ms (16.858MiB/s) to sector 823598
Read 131072 bytes in 7.149ms (17.485MiB/s) from sector 823598
Wrote 196608 bytes in 10.829ms (17.315MiB/s) to sector 180761
Read 196608 bytes in 10.539ms (17.791MiB/s) from sector 180761
I (109045) example: SD card unmounted - raw access
I (109045) example: Mounting SD card - FATFS
I (109045) gpio: GPIO[36]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (109055) gpio: GPIO[35]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (109065) gpio: GPIO[37]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (109075) gpio: GPIO[38]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (109085) gpio: GPIO[33]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
I (109095) gpio: GPIO[34]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0
I (109145) gpio: GPIO[34]| InputEn: 0| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:0
W (109155) vfs_fat_sdmmc: failed to mount card (13)
W (109155) vfs_fat_sdmmc: partitioning card
W (109155) vfs_fat_sdmmc: formatting card, allocation unit size=16384
W (110525) vfs_fat_sdmmc: mounting again
Name: USD00
Type: SDHC/SDXC
Speed: 40.00 MHz (limit: 40.00 MHz)
Size: 15080MB
CSD: ver=2, sector_size=512, capacity=30883840 read_bl_len=9
SSR: bus_width=4
I (110535) example: SD card mounted - FATFS
I (110715) example: Test with 1MiB file
Wrote 1048576 bytes (buffer size 4096B) in 200.241ms (4.994MiB/s)
Wrote 1048576 bytes (buffer size 8192B) in 129.756ms (7.707MiB/s)
Wrote 1048576 bytes (buffer size 16384B) in 91.955ms (10.875MiB/s)
Wrote 1048576 bytes (buffer size 32768B) in 91.424ms (10.938MiB/s)
Read 1048576 bytes (buffer size 4096B) in 121.086ms (8.259MiB/s)
Read 1048576 bytes (buffer size 8192B) in 87.896ms (11.377MiB/s)
Read 1048576 bytes (buffer size 16384B) in 72.525ms (13.788MiB/s)
Read 1048576 bytes (buffer size 32768B) in 74.664ms (13.393MiB/s)
I (111655) example: Test with 4MiB file
Wrote 4194304 bytes (buffer size 4096B) in 797.167ms (5.018MiB/s)
Wrote 4194304 bytes (buffer size 8192B) in 533.538ms (7.497MiB/s)
Wrote 4194304 bytes (buffer size 16384B) in 530.830ms (7.535MiB/s)
Wrote 4194304 bytes (buffer size 32768B) in 497.953ms (8.033MiB/s)
Read 4194304 bytes (buffer size 4096B) in 473.495ms (8.448MiB/s)
Read 4194304 bytes (buffer size 8192B) in 351.240ms (11.388MiB/s)
Read 4194304 bytes (buffer size 16384B) in 289.767ms (13.804MiB/s)
Read 4194304 bytes (buffer size 32768B) in 287.260ms (13.925MiB/s)
I (115495) example: Test with 16MiB file
Wrote 16777216 bytes (buffer size 4096B) in 4754.141ms (3.365MiB/s)
Wrote 16777216 bytes (buffer size 8192B) in 2290.545ms (6.985MiB/s)
Wrote 16777216 bytes (buffer size 16384B) in 2088.811ms (7.660MiB/s)
Wrote 16777216 bytes (buffer size 32768B) in 2148.595ms (7.447MiB/s)
Read 16777216 bytes (buffer size 4096B) in 1899.620ms (8.423MiB/s)
Read 16777216 bytes (buffer size 8192B) in 1419.345ms (11.273MiB/s)
Read 16777216 bytes (buffer size 16384B) in 1158.909ms (13.806MiB/s)
Read 16777216 bytes (buffer size 32768B) in 1148.426ms (13.932MiB/s)
I (132515) example: SD card unmounted - FATFS
I (132515) example: End of the example
```
## Troubleshooting
### Failure to download the example
```
Connecting........_____....._____....._____....._____....._____....._____....._____
A fatal error occurred: Failed to connect to Espressif device: Invalid head of packet (0x34)
```
Disconnect the SD card D0/MISO line from GPIO2 and try uploading again. Read "Note about GPIO2" above.
### Card fails to initialize with `sdmmc_init_sd_scr: send_scr (1) returned 0x107` error
Check connections between the card and the ESP32. For example, if you have disconnected GPIO2 to work around the flashing issue, connect it back and reset the ESP32 (using a button on the development board, or by pressing Ctrl-T Ctrl-R in IDF Monitor).
### Card fails to initialize with `sdmmc_check_scr: send_scr returned 0xffffffff` error
Connections between the card and the ESP32 are too long for the frequency used. Try using shorter connections, or try reducing the clock speed of SD interface.

View File

@ -0,0 +1,2 @@
idf_component_register(SRCS "main.c" "tests.c"
INCLUDE_DIRS ".")

View File

@ -0,0 +1,194 @@
menu "Performance Benchmark Example Configuration"
config EXAMPLE_USE_MEGABYTES
bool "Use megabytes instead of megabits"
default y
help
If this config item is set, the IO speed will be displayed in megabytes per second
instead of megabits per second.
config EXAMPLE_TEST_SPIFLASH
bool "Test internal SPI flash"
default y
help
If this config item is set, the internal SPI flash will be tested.
menu "Internal flash test config"
depends on EXAMPLE_TEST_SPIFLASH
config EXAMPLE_TEST_SPIFLASH_RAW
bool "Test raw access"
default y
help
If this config item is set, raw access will be tested.
config EXAMPLE_TEST_SPIFLASH_FATFS
bool "Test FATFS"
default y
help
If this config item is set, FATFS will be tested.
config EXAMPLE_TEST_SPIFLASH_SPIFFS
bool "Test SPIFFS"
default y
help
If this config item is set, SPIFFS will be tested.
endmenu # "Internal flash test config"
config EXAMPLE_TEST_SD_CARD
bool "Test SD card"
default y
help
If this config item is set, the SD card will be tested after it is mounted.
choice EXAMPLE_SD_CARD_INTERFACE
prompt "SD card interface"
depends on EXAMPLE_TEST_SD_CARD
default EXAMPLE_USE_SDMMC if SOC_SDMMC_HOST_SUPPORTED
default EXAMPLE_USE_SDSPI if !SOC_SDMMC_HOST_SUPPORTED
help
Select the SD card interface.
if SOC_SDMMC_HOST_SUPPORTED
config EXAMPLE_USE_SDMMC
bool "SDMMC"
endif # SOC_SDMMC_HOST_SUPPORTED
config EXAMPLE_USE_SDSPI
bool "SDSPI"
endchoice # EXAMPLE_SD_CARD_INTERFACE
menu "SD card test config"
depends on EXAMPLE_TEST_SD_CARD
config EXAMPLE_TEST_SD_CARD_RAW
bool "Test raw access"
default y
help
If this config item is set, raw access will be tested.
config EXAMPLE_TEST_SD_CARD_FATFS
bool "Test FATFS"
default y
help
If this config item is set, FATFS will be tested.
choice EXAMPLE_SD_CARD_FREQ_PICKER
prompt "SD card frequency"
default EXAMPLE_SD_FREQ_HIGHSPEED if EXAMPLE_USE_SDMMC
default EXAMPLE_SD_FREQ_DEFAULT if EXAMPLE_USE_SDSPI
help
Select the frequency of SD card interface.
config EXAMPLE_SD_FREQ_PROBING
bool "Probing frequency (400kHz)"
config EXAMPLE_SD_FREQ_DEFAULT
bool "Default frequency (20MHz)"
config EXAMPLE_SD_FREQ_HIGHSPEED
bool "High speed frequency (40MHz)"
depends on EXAMPLE_USE_SDMMC
config EXAMPLE_SD_FREQ_CUSTOM
bool "Custom frequency"
endchoice # EXAMPLE_SD_CARD_FREQ_PICKER
config EXAMPLE_SD_FREQ_CUSTOM_VAL
int "Custom frequency (kHz)"
default 20000
depends on EXAMPLE_SD_FREQ_CUSTOM
help
Enter the custom frequency of SD card interface.
if EXAMPLE_USE_SDMMC
choice EXAMPLE_SDMMC_BUS_WIDTH
prompt "SD/MMC bus width"
help
Select the bus width of SD or MMC interface.
Note that even if 1 line mode is used,
D3 pin of the SD card must have a pull-up resistor connected.
Otherwise the card may enter SPI mode,
the only way to recover from which is to cycle power to the card.
config EXAMPLE_SDMMC_BUS_WIDTH_4
bool "4 lines (D0 - D3)"
config EXAMPLE_SDMMC_BUS_WIDTH_1
bool "1 line (D0)"
endchoice # EXAMPLE_SDMMC_BUS_WIDTH
if SOC_SDMMC_USE_GPIO_MATRIX
config EXAMPLE_PIN_CMD
int "CMD GPIO number"
default 35 if IDF_TARGET_ESP32S3
config EXAMPLE_PIN_CLK
int "CLK GPIO number"
default 36 if IDF_TARGET_ESP32S3
config EXAMPLE_PIN_D0
int "D0 GPIO number"
default 37 if IDF_TARGET_ESP32S3
if EXAMPLE_SDMMC_BUS_WIDTH_4
config EXAMPLE_PIN_D1
int "D1 GPIO number"
default 38 if IDF_TARGET_ESP32S3
config EXAMPLE_PIN_D2
int "D2 GPIO number"
default 33 if IDF_TARGET_ESP32S3
config EXAMPLE_PIN_D3
int "D3 GPIO number"
default 34 if IDF_TARGET_ESP32S3
endif # EXAMPLE_SDMMC_BUS_WIDTH_4
endif # SOC_SDMMC_USE_GPIO_MATRIX
endif # EXAMPLE_USE_SDMMC
if EXAMPLE_USE_SDSPI
config EXAMPLE_PIN_MOSI
int "MOSI GPIO number"
default 15 if IDF_TARGET_ESP32
default 35 if IDF_TARGET_ESP32S2
default 35 if IDF_TARGET_ESP32S3
default 5 if IDF_TARGET_ESP32H2
default 4 # C3 and others
config EXAMPLE_PIN_MISO
int "MISO GPIO number"
default 2 if IDF_TARGET_ESP32
default 37 if IDF_TARGET_ESP32S2
default 37 if IDF_TARGET_ESP32S3
default 0 if IDF_TARGET_ESP32H2
default 6 # C3 and others
config EXAMPLE_PIN_CLK
int "CLK GPIO number"
default 14 if IDF_TARGET_ESP32
default 36 if IDF_TARGET_ESP32S2
default 36 if IDF_TARGET_ESP32S3
default 4 if IDF_TARGET_ESP32H2
default 5 # C3 and others
config EXAMPLE_PIN_CS
int "CS GPIO number"
default 13 if IDF_TARGET_ESP32
default 34 if IDF_TARGET_ESP32S2
default 34 if IDF_TARGET_ESP32S3
default 1 # C3 and others
endif # EXAMPLE_USE_SDSPI
endmenu # "SD card test config"
endmenu # "Performance Monitor Example Configuration"

View File

@ -0,0 +1,337 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
// This example uses SDMMC or SDSPI peripheral to communicate with SD card.
#include <stdio.h>
#include <stdbool.h>
#include <sys/time.h>
#include "esp_log.h"
#include "esp_check.h"
#include "esp_partition.h"
#include "esp_vfs_fat.h"
#include "esp_spiffs.h"
#include "soc/soc_caps.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
#include "driver/sdspi_host.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "wear_levelling.h"
#include "sdkconfig.h"
#include "tests.h"
static const char *TAG = "example";
static const char *flash_partition_label = "storage";
wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
sdmmc_host_t host_g;
#ifdef CONFIG_EXAMPLE_USE_SDMMC
sdmmc_slot_config_t slot_config_g;
#else // CONFIG_EXAMPLE_USE_SDMMC
sdspi_device_config_t slot_config_g;
#endif // CONFIG_EXAMPLE_USE_SDSPI
#ifdef CONFIG_EXAMPLE_SD_FREQ_PROBING
#define EXAMPLE_SD_FREQ SDMMC_FREQ_PROBING
#elif CONFIG_EXAMPLE_SD_FREQ_DEFAULT
#define EXAMPLE_SD_FREQ SDMMC_FREQ_DEFAULT
#elif CONFIG_EXAMPLE_SD_FREQ_HIGHSPEED
#define EXAMPLE_SD_FREQ SDMMC_FREQ_HIGHSPEED
#elif CONFIG_EXAMPLE_SD_FREQ_CUSTOM
#define EXAMPLE_SD_FREQ CONFIG_EXAMPLE_SD_FREQ_CUSTOM_VAL
#else
#define EXAMPLE_SD_FREQ SDMMC_FREQ_DEFAULT
#endif
#ifdef CONFIG_EXAMPLE_USE_SDMMC
void init_sd_config(sdmmc_host_t *out_host, sdmmc_slot_config_t *out_slot_config, int freq_khz);
#else // CONFIG_EXAMPLE_USE_SDMMC
void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_config, int freq_khz);
#endif // CONFIG_EXAMPLE_USE_SDSPI
void test_spiflash_raw(void);
void test_spiflash_fatfs(void);
void test_spiflash_spiffs(void);
void test_sd_raw(void);
void test_sd_fatfs(void);
void app_main(void)
{
#ifdef CONFIG_EXAMPLE_TEST_SPIFLASH
ESP_LOGI(TAG, "Internal flash test");
/* SPI flash - raw access */
#ifdef CONFIG_EXAMPLE_TEST_SPIFLASH_RAW
test_spiflash_raw();
#endif // CONFIG_EXAMPLE_TEST_SPIFLASH_RAW
/* SPI flash - FATFS */
#ifdef CONFIG_EXAMPLE_TEST_SPIFLASH_FATFS
test_spiflash_fatfs();
#endif // CONFIG_EXAMPLE_TEST_SPIFLASH_FATFS
/* SPI flash - SPIFFS */
#ifdef CONFIG_EXAMPLE_TEST_SPIFLASH_SPIFFS
test_spiflash_spiffs();
#endif // CONFIG_EXAMPLE_TEST_SPIFLASH_SPIFFS
#endif // CONFIG_EXAMPLE_TEST_SPIFLASH
#ifdef CONFIG_EXAMPLE_TEST_SD_CARD
ESP_LOGI(TAG, "SD card test");
ESP_LOGI(TAG, "Initializing SD card");
init_sd_config(&host_g, &slot_config_g, EXAMPLE_SD_FREQ);
/* SD card - raw access */
#ifdef CONFIG_EXAMPLE_TEST_SD_CARD_RAW
test_sd_raw();
#endif // CONFIG_EXAMPLE_TEST_SD_CARD_RAW
/* SD card - FATFS */
#ifdef CONFIG_EXAMPLE_TEST_SD_CARD_FATFS
test_sd_fatfs();
#endif // CONFIG_EXAMPLE_TEST_SD_CARD_FATFS
#endif // CONFIG_EXAMPLE_TEST_SD_CARD
}
void test_spiflash_raw(void)
{
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG, "Mountig WL layer...");
const esp_partition_t *data_partition = esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_UNDEFINED, flash_partition_label);
if (data_partition == NULL) {
ESP_LOGE(TAG, "Could not find partition \"%s\"", flash_partition_label);
ESP_ERROR_CHECK(ESP_ERR_NOT_FOUND);
}
ret = wl_mount(data_partition, &s_wl_handle);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to mount wear levelling layer, ret = %i", ret);
ESP_ERROR_CHECK(ret);
}
ESP_LOGI(TAG, "WL layer mounted");
spiflash_speed_test_raw_run();
ret = wl_unmount(s_wl_handle);
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "WL layer unmounted");
}
void test_spiflash_fatfs(void)
{
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG, "Mounting FATFS partition...");
esp_vfs_fat_sdmmc_mount_config_t mount_config_spiflash = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 16 * 1024};
ret = esp_vfs_fat_spiflash_mount_rw_wl(FLASH_BASE_PATH, flash_partition_label, &mount_config_spiflash, &s_wl_handle);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "FATFS mounted to %s", FLASH_BASE_PATH);
} else {
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(ret));
ESP_ERROR_CHECK(ret);
}
spiflash_speed_test_fs_run();
// Unregister FATFS and unmount storage partition
ret = esp_vfs_fat_spiflash_unmount_rw_wl(FLASH_BASE_PATH, s_wl_handle);
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "FATFS partition unmounted");
}
void test_spiflash_spiffs(void)
{
esp_err_t ret = ESP_OK;
ESP_LOGI(TAG, "Mounting SPIFFS partition...");
esp_vfs_spiffs_conf_t conf = {
.base_path = FLASH_BASE_PATH,
.partition_label = flash_partition_label,
.max_files = 5,
.format_if_mount_failed = true};
// Use settings defined above to initialize and mount SPIFFS filesystem.
// Note: esp_vfs_spiffs_register is an all-in-one convenience function.
ret = esp_vfs_spiffs_register(&conf);
if (ret == ESP_OK) {
ESP_LOGI(TAG, "SPIFFS mounted to %s", FLASH_BASE_PATH);
} else {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount or format filesystem");
} else if (ret == ESP_ERR_NOT_FOUND) {
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
} else {
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
}
ESP_ERROR_CHECK(ret);
}
spiflash_speed_test_fs_run();
// Unregister SPIFFS and unmount storage partition
ret = esp_vfs_spiffs_unregister(conf.partition_label);
ESP_ERROR_CHECK(ret);
ESP_LOGI(TAG, "SPIFFS partition unmounted");
}
void test_sd_raw(void)
{
esp_err_t ret = ESP_OK;
sdmmc_card_t *card;
ESP_LOGI(TAG, "Mounting SD card - raw access");
card = (sdmmc_card_t *)malloc(sizeof(sdmmc_card_t));
if (card == NULL) {
ESP_LOGE(TAG, "Failed to allocate sdmmc_card_t structure");
ESP_ERROR_CHECK(ESP_ERR_NO_MEM);
}
// Initialize the interface
#ifdef CONFIG_EXAMPLE_USE_SDMMC
ret = sdmmc_host_init();
ESP_ERROR_CHECK(ret);
ret = sdmmc_host_init_slot(SDMMC_HOST_SLOT_1, &slot_config_g);
ESP_ERROR_CHECK(ret);
#elif CONFIG_EXAMPLE_USE_SDSPI // CONFIG_EXAMPLE_USE_SDMMC
int card_handle = -1;
ret = sdspi_host_init_device((const sdspi_device_config_t *)&slot_config_g, &card_handle);
ESP_ERROR_CHECK(ret);
#endif // CONFIG_EXAMPLE_USE_SDSPI
ret = sdmmc_card_init(&host_g, card);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize SD card (%s)", esp_err_to_name(ret));
ESP_LOGE(TAG, "If you were using SDMMC and switched to SPI reinsert the SD card or power cycle the board");
free(card);
ESP_ERROR_CHECK(ret);
}
ESP_LOGI(TAG, "SD card mounted - raw access");
sdmmc_card_print_info(stdout, card);
sdcard_speed_test_raw_run(card);
// Unmount SD card
#ifdef CONFIG_EXAMPLE_USE_SDMMC
sdmmc_host_deinit();
#else // CONFIG_EXAMPLE_USE_SDMMC
sdspi_host_deinit();
#endif // CONFIG_EXAMPLE_USE_SDSPI
free(card);
ESP_LOGI(TAG, "SD card unmounted - raw access");
}
void test_sd_fatfs(void)
{
esp_err_t ret = ESP_OK;
sdmmc_card_t *card;
ESP_LOGI(TAG, "Mounting SD card - FATFS");
esp_vfs_fat_sdmmc_mount_config_t mount_config_sdcard = {
.format_if_mount_failed = true,
.max_files = 5,
.allocation_unit_size = 16 * 1024};
#ifdef CONFIG_EXAMPLE_USE_SDMMC
ret = esp_vfs_fat_sdmmc_mount(SD_BASE_PATH, &host_g, &slot_config_g, &mount_config_sdcard, &card);
#else // CONFIG_EXAMPLE_USE_SDMMC
ret = esp_vfs_fat_sdspi_mount(SD_BASE_PATH, &host_g, &slot_config_g, &mount_config_sdcard, &card);
#endif // CONFIG_EXAMPLE_USE_SDSPI
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.",
esp_err_to_name(ret));
ESP_ERROR_CHECK(ret);
}
sdmmc_card_print_info(stdout, card);
ESP_LOGI(TAG, "SD card mounted - FATFS");
sdcard_speed_test_fatfs_run();
// Unmount SD card
esp_vfs_fat_sdcard_unmount(SD_BASE_PATH, card);
ESP_LOGI(TAG, "SD card unmounted - FATFS");
}
#ifdef CONFIG_EXAMPLE_TEST_SD_CARD
#ifdef CONFIG_EXAMPLE_USE_SDMMC
void init_sd_config(sdmmc_host_t *out_host, sdmmc_slot_config_t *out_slot_config, int freq_khz) {
#else // CONFIG_EXAMPLE_USE_SDMMC
void init_sd_config(sdmmc_host_t *out_host, sdspi_device_config_t *out_slot_config, int freq_khz) {
#endif // CONFIG_EXAMPLE_USE_SDSPI
// By default, SD card frequency is initialized to SDMMC_FREQ_DEFAULT (20MHz)
// For setting a specific frequency, use host.max_freq_khz
// (range 400kHz - 40MHz for SDMMC, 400kHz - 20MHz for SDSPI)
// Example: for fixed frequency of 10MHz, use host.max_freq_khz = 10000;
#ifdef CONFIG_EXAMPLE_USE_SDMMC
ESP_LOGI(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = freq_khz;
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// Set bus width to use:
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
slot_config.width = 4;
#else
slot_config.width = 1;
#endif
// On chips where the GPIOs used for SD card can be configured, set them in
// the slot_config structure:
#ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
slot_config.clk = CONFIG_EXAMPLE_PIN_CLK;
slot_config.cmd = CONFIG_EXAMPLE_PIN_CMD;
slot_config.d0 = CONFIG_EXAMPLE_PIN_D0;
#ifdef CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
slot_config.d1 = CONFIG_EXAMPLE_PIN_D1;
slot_config.d2 = CONFIG_EXAMPLE_PIN_D2;
slot_config.d3 = CONFIG_EXAMPLE_PIN_D3;
#endif // CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4
#endif // CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
// Enable internal pullups on enabled pins. The internal pullups
// are insufficient however, please make sure 10k external pullups are
// connected on the bus. This is for debug / example purpose only.
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
#else // CONFIG_EXAMPLE_USE_SDMMC
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
host.max_freq_khz = freq_khz;
spi_bus_config_t bus_cfg = {
.mosi_io_num = CONFIG_EXAMPLE_PIN_MOSI,
.miso_io_num = CONFIG_EXAMPLE_PIN_MISO,
.sclk_io_num = CONFIG_EXAMPLE_PIN_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
esp_err_t ret = spi_bus_initialize(host.slot, &bus_cfg, SDSPI_DEFAULT_DMA);
ESP_ERROR_CHECK(ret);
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdspi_device_config_t slot_config = SDSPI_DEVICE_CONFIG_DEFAULT();
slot_config.gpio_cs = CONFIG_EXAMPLE_PIN_CS;
slot_config.host_id = host.slot;
#endif // CONFIG_EXAMPLE_USE_SDSPI
*out_host = host;
*out_slot_config = slot_config;
}
#endif // CONFIG_EXAMPLE_TEST_SD_CARD

View File

@ -0,0 +1,254 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include <sys/time.h>
#include "esp_random.h"
#include "driver/sdmmc_types.h"
#include "sdmmc_cmd.h"
#include "wear_levelling.h"
#include "sdkconfig.h"
#include "tests.h"
static const char *TAG = "example_tests";
void spiflash_speed_test_raw_run(void);
void spiflash_speed_test_fs_run(void);
void sdcard_speed_test_raw_run(sdmmc_card_t *card);
void sdcard_speed_test_fatfs_run(void);
static void print_bench_output(struct timeval tv_start, struct timeval tv_end, size_t size, size_t start_offset, bool is_write)
{
bool use_megabytes;
#ifdef CONFIG_EXAMPLE_USE_MEGABYTES
use_megabytes = true;
#else
use_megabytes = false;
#endif // CONFIG_EXAMPLE_USE_MEGABYTES
float t_s = tv_end.tv_sec - tv_start.tv_sec + 1e-6f * (tv_end.tv_usec - tv_start.tv_usec);
double io_speed = size / (1024.0f * 1024.0f * t_s);
printf("%s %d bytes in %.3fms (%.3f%s) %s address %u\n",
(is_write)?"Wrote":"Read", size, t_s * 1e3, (use_megabytes)?io_speed:io_speed*8.0,
(use_megabytes)?"MiB/s":"Mib/s", (is_write)?"to":"from", start_offset);
}
static void test_rw_raw_spiflash_speed(wl_handle_t handle, size_t src_dest_addr, void *src_dest_buff, size_t size, bool is_write)
{
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
if (is_write) {
wl_write(handle, src_dest_addr, src_dest_buff, size);
} else {
wl_read(handle, src_dest_addr, src_dest_buff, size);
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
print_bench_output(tv_start, tv_end, size, src_dest_addr, is_write);
}
static void test_rw_raw_sd_speed(sdmmc_card_t *card, char* buf, uint32_t start_sector, size_t sector_count, size_t sector_size, bool is_write)
{
int file_size = sector_count * sector_size;
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
if (is_write) {
ESP_ERROR_CHECK(sdmmc_write_sectors(card, buf, start_sector, sector_count));
} else {
ESP_ERROR_CHECK(sdmmc_read_sectors(card, buf, start_sector, sector_count));
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
print_bench_output(tv_start, tv_end, file_size, start_sector, is_write);
}
static void test_rw_fs_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool is_write)
{
bool use_megabytes;
#ifdef CONFIG_EXAMPLE_USE_MEGABYTES
use_megabytes = true;
#else
use_megabytes = false;
#endif // CONFIG_EXAMPLE_USE_MEGABYTES
const size_t buf_count = file_size / buf_size;
FILE* f = fopen(filename, (is_write) ? "wb" : "rb");
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
for (size_t n = 0; n < buf_count; ++n) {
if (is_write) {
write(fileno(f), buf, buf_size);
} else {
if (read(fileno(f), buf, buf_size) != buf_size) {
printf("reading at n=%d, eof=%d", n, feof(f));
}
}
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
fclose(f);
float t_s = tv_end.tv_sec - tv_start.tv_sec + 1e-6f * (tv_end.tv_usec - tv_start.tv_usec);
double io_speed = file_size / (1024.0f * 1024.0f * t_s);
printf("%s %d bytes (buffer size %dB) in %.3fms (%.3f%s)\n",
(is_write)?"Wrote":"Read", file_size, buf_size, t_s * 1e3,
(use_megabytes)?io_speed:io_speed*8.0, (use_megabytes)?"MiB/s":"Mib/s");
}
void spiflash_speed_test_raw_run(void)
{
const size_t buf_size = 16 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(buf, buf_size);
size_t file_size;
ESP_LOGI(TAG, "Test with 128kiB file");
file_size = 128 * 1024;
test_rw_raw_spiflash_speed(s_wl_handle, 0, buf, file_size, true);
free(buf);
}
static void spiflash_speed_test(void *buf, size_t buf_size, size_t file_size, bool write)
{
test_rw_fs_speed(FLASH_BASE_PATH"/test.bin", buf, buf_size, file_size, write);
}
void spiflash_speed_test_fs_run(void)
{
const size_t buf_size = 16 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(buf, buf_size);
size_t file_size;
ESP_LOGI(TAG, "Test with 128kiB file");
file_size = 128 * 1024;
// Write
spiflash_speed_test(buf, 4 * 1024, file_size, true);
spiflash_speed_test(buf, 8 * 1024, file_size, true);
spiflash_speed_test(buf, 16 * 1024, file_size, true);
// Read
spiflash_speed_test(buf, 4 * 1024, file_size, false);
spiflash_speed_test(buf, 8 * 1024, file_size, false);
spiflash_speed_test(buf, 16 * 1024, file_size, false);
ESP_LOGI(TAG, "Test with 256kiB file");
file_size *= 2;
// Write
spiflash_speed_test(buf, 4 * 1024, file_size, true);
spiflash_speed_test(buf, 8 * 1024, file_size, true);
spiflash_speed_test(buf, 16 * 1024, file_size, true);
// Read
spiflash_speed_test(buf, 4 * 1024, file_size, false);
spiflash_speed_test(buf, 8 * 1024, file_size, false);
spiflash_speed_test(buf, 16 * 1024, file_size, false);
ESP_LOGI(TAG, "Test with 512kiB file");
file_size *= 2;
// Write
spiflash_speed_test(buf, 4 * 1024, file_size, true);
spiflash_speed_test(buf, 8 * 1024, file_size, true);
spiflash_speed_test(buf, 16 * 1024, file_size, true);
// Read
spiflash_speed_test(buf, 4 * 1024, file_size, false);
spiflash_speed_test(buf, 8 * 1024, file_size, false);
spiflash_speed_test(buf, 16 * 1024, file_size, false);
free(buf);
}
static void sd_speed_test(void *buf, size_t buf_size, size_t file_size, bool write)
{
test_rw_fs_speed(SD_BASE_PATH"/test.bin", buf, buf_size, file_size, write);
}
void sdcard_speed_test_fatfs_run(void)
{
const size_t buf_size = 32 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(buf, buf_size);
size_t file_size;
ESP_LOGI(TAG, "Test with 1MiB file");
file_size = 1 * 1024 * 1024;
// Write
sd_speed_test(buf, 4 * 1024, file_size, true);
sd_speed_test(buf, 8 * 1024, file_size, true);
sd_speed_test(buf, 16 * 1024, file_size, true);
sd_speed_test(buf, 32 * 1024, file_size, true);
// Read
sd_speed_test(buf, 4 * 1024, file_size, false);
sd_speed_test(buf, 8 * 1024, file_size, false);
sd_speed_test(buf, 16 * 1024, file_size, false);
sd_speed_test(buf, 32 * 1024, file_size, false);
ESP_LOGI(TAG, "Test with 4MiB file");
file_size = 4 * 1024 * 1024;
// Write
sd_speed_test(buf, 4 * 1024, file_size, true);
sd_speed_test(buf, 8 * 1024, file_size, true);
sd_speed_test(buf, 16 * 1024, file_size, true);
sd_speed_test(buf, 32 * 1024, file_size, true);
// Read
sd_speed_test(buf, 4 * 1024, file_size, false);
sd_speed_test(buf, 8 * 1024, file_size, false);
sd_speed_test(buf, 16 * 1024, file_size, false);
sd_speed_test(buf, 32 * 1024, file_size, false);
ESP_LOGI(TAG, "Test with 16MiB file");
file_size = 16 * 1024 * 1024;
// Write
sd_speed_test(buf, 4 * 1024, file_size, true);
sd_speed_test(buf, 8 * 1024, file_size, true);
sd_speed_test(buf, 16 * 1024, file_size, true);
sd_speed_test(buf, 32 * 1024, file_size, true);
// Read
sd_speed_test(buf, 4 * 1024, file_size, false);
sd_speed_test(buf, 8 * 1024, file_size, false);
sd_speed_test(buf, 16 * 1024, file_size, false);
sd_speed_test(buf, 32 * 1024, file_size, false);
free(buf);
}
static uint32_t sd_random_start_sector(uint32_t sector_size)
{
// Should be a little less than maximum number of sectors on a 512 MiB card
// (512 Mib - 64 MiB) / sector_size (most probably 512)
uint32_t upper_bound = (536870912 - 67108864) / sector_size;
return (esp_random() % (upper_bound + 1));
}
void sdcard_speed_test_raw_run(sdmmc_card_t *card)
{
size_t sector_count = 128;
uint32_t sector_size = card->csd.sector_size;
char *buf = (char *) calloc(1, sector_count * sector_size);
assert(buf != NULL);
uint32_t start_sector[3] = {sd_random_start_sector(sector_size), sd_random_start_sector(sector_size), sd_random_start_sector(sector_size)};
for(uint8_t i = 0; i < 3; i++) {
test_rw_raw_sd_speed(card, buf, start_sector[i], sector_count*(i+1), sector_size, true);
test_rw_raw_sd_speed(card, buf, start_sector[i], sector_count*(i+1), sector_size, false);
}
free(buf);
}

View File

@ -0,0 +1,25 @@
/*
* SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
/* This example code is in the Public Domain (or CC0 licensed, at your option.)
Unless required by applicable law or agreed to in writing, this
software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "driver/sdmmc_types.h"
#include "wear_levelling.h"
#define FLASH_BASE_PATH "/spiflash"
#define SD_BASE_PATH "/sdcard"
extern wl_handle_t s_wl_handle;
void spiflash_speed_test_raw_run(void);
void spiflash_speed_test_fs_run(void);
void sdcard_speed_test_raw_run(sdmmc_card_t *card);
void sdcard_speed_test_fatfs_run(void);

View File

@ -0,0 +1,6 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1M,
storage, data, undefined, , 0xF0000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1M,
6 storage, data, undefined, , 0xF0000,

View File

@ -0,0 +1,73 @@
# SPDX-FileCopyrightText: 2023 Espressif Systems (Shanghai) CO LTD
# SPDX-License-Identifier: Unlicense OR CC0-1.0
import pytest
from pytest_embedded import Dut
@pytest.mark.supported_targets
@pytest.mark.generic
@pytest.mark.parametrize(
'config',
[
'spiflash'
],
indirect=True
)
def test_examples_perf_benchmark_spiflash(dut: Dut) -> None:
# SPI flash
dut.expect('example: Mountig WL layer...', timeout=10)
dut.expect('example: WL layer mounted', timeout=90)
dut.expect('example: WL layer unmounted', timeout=240) # SPI flash has slow write speed
dut.expect('example: Mounting FATFS partition...', timeout=10)
dut.expect('example: FATFS mounted to', timeout=90) # Increased timeout due to formatting
dut.expect('example: FATFS partition unmounted', timeout=240) # SPI flash has slow write speed
dut.expect('example: Mounting SPIFFS partition...', timeout=10)
dut.expect('example: SPIFFS mounted to', timeout=90) # Increased timeout due to formatting
dut.expect('example: SPIFFS partition unmounted', timeout=240) # SPI flash has slow write speed
@pytest.mark.esp32
@pytest.mark.sdcard_sdmode
@pytest.mark.parametrize(
'config',
[
'sdmmc_1line',
'sdmmc_4line',
],
indirect=True,
)
def test_examples_perf_benchmark_sdcard_sdmmc(dut: Dut) -> None:
# SD card
dut.expect('example: Mounting SD card - raw access', timeout=10)
dut.expect('example: SD card mounted - raw access', timeout=10)
dut.expect('example: SD card unmounted - raw access', timeout=60)
dut.expect('example: Mounting SD card - FATFS', timeout=30)
dut.expect('example: SD card mounted - FATFS', timeout=120) # Increased timeout due to formatting
dut.expect('example: SD card unmounted - FATFS', timeout=180)
@pytest.mark.esp32
@pytest.mark.esp32s2
@pytest.mark.esp32c3
@pytest.mark.sdcard_spimode
@pytest.mark.parametrize(
'config',
[
'sdspi_1line',
],
indirect=True,
)
def test_examples_perf_benchmark_sdcard_spi(dut: Dut) -> None:
# SD card
dut.expect('example: Mounting SD card - raw access', timeout=10)
dut.expect('example: SD card mounted - raw access', timeout=10)
dut.expect('example: SD card unmounted - raw access', timeout=180)
dut.expect('example: Mounting SD card - FATFS', timeout=30)
dut.expect('example: SD card mounted - FATFS', timeout=120) # Increased timeout due to formatting
dut.expect('example: SD card unmounted - FATFS', timeout=180)

View File

@ -0,0 +1,17 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESP_TASK_WDT_EN=n
# FATFS
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096
# SPI flash
CONFIG_EXAMPLE_TEST_SPIFLASH=n
# SD card
CONFIG_EXAMPLE_TEST_SD_CARD=y
CONFIG_EXAMPLE_USE_SDSPI=n
CONFIG_EXAMPLE_USE_SDMMC=y
CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1=y
CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4=n

View File

@ -0,0 +1,17 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESP_TASK_WDT_EN=n
# FATFS
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096
# SPI flash
CONFIG_EXAMPLE_TEST_SPIFLASH=n
# SD card
CONFIG_EXAMPLE_TEST_SD_CARD=y
CONFIG_EXAMPLE_USE_SDSPI=n
CONFIG_EXAMPLE_USE_SDMMC=y
CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_1=n
CONFIG_EXAMPLE_SDMMC_BUS_WIDTH_4=y

View File

@ -0,0 +1,15 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESP_TASK_WDT_EN=n
# FATFS
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096
# SPI flash
CONFIG_EXAMPLE_TEST_SPIFLASH=n
# SD card
CONFIG_EXAMPLE_TEST_SD_CARD=y
CONFIG_EXAMPLE_USE_SDSPI=y
CONFIG_EXAMPLE_USE_SDMMC=n

View File

@ -0,0 +1,18 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESP_TASK_WDT_EN=n
# FATFS
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096
# SPI flash
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHMODE="qio"
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"
CONFIG_EXAMPLE_TEST_SPIFLASH=y
# SD card
CONFIG_EXAMPLE_TEST_SD_CARD=n

View File

@ -0,0 +1,14 @@
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions_example.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions_example.csv"
CONFIG_ESP_TASK_WDT_EN=n
# FATFS
CONFIG_FATFS_VFS_FSTAT_BLKSIZE=4096
# SPI flash
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHMODE="qio"
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
CONFIG_ESPTOOLPY_FLASHFREQ_80M_DEFAULT=y
CONFIG_ESPTOOLPY_FLASHFREQ="80m"