kopia lustrzana https://github.com/espressif/esp-idf
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.pull/12097/head
rodzic
e297470e62
commit
e7b88a52d1
|
@ -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)
|
|
@ -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.
|
|
@ -0,0 +1,2 @@
|
|||
idf_component_register(SRCS "main.c" "tests.c"
|
||||
INCLUDE_DIRS ".")
|
|
@ -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"
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
|
@ -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,
|
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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"
|
Ładowanie…
Reference in New Issue