Closed wx85105157 closed 5 years ago
rst:0x1 (POWERON_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT) flash read err, 1000 ets_main.c 371 ets Jun 8 2016 00:22:57
rst:0x10 (RTCWDT_RTC_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:808 load:0x40078000,len:6084 load:0x40080000,len:6696 entry 0x400802e4 SD_MMC Card Type: SDSC SD_MMC Card Size: 1908MB 67108864 bytes written for 16832 ms 3.802281 Mbytes/S write 67108864 bytes read for 59760 ms 1.070950 Mbytes/S read Total space: 1907MB Used space: 64MB ets Jun 8 2016 00:22:57
rst:0x1 (POWERON_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT) flash read err, 1000 ets_main.c 371 ets Jun 8 2016 00:22:57
rst:0x10 (RTCWDT_RTC_RESET),boot:0x1b (SPI_FAST_FLASH_BOOT) configsip: 0, SPIWP:0xee clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00 mode:DIO, clock div:1 load:0x3fff0018,len:4 load:0x3fff001c,len:808 load:0x40078000,len:6084 load:0x40080000,len:6696 entry 0x400802e4 SD_MMC Card Type: SDHC SD_MMC Card Size: 3796MB 67108864 bytes written for 13809 ms 4.634659 Mbytes/S write 67108864 bytes read for 75129 ms 0.851868 Mbytes/S read Total space: 3795MB Used space: 64MB
The same problem, and could not solve. A file of 5 mb is written for 15 seconds.
Having the same issue.
I'm digging into this right now.
So I am using ESP32-IDF and having much better results using tests.
I have decreased the read time 1048576 bytes read for 1640 ms 1048576 bytes written for 6506 ms - previous result was 7300 ms Total space: 14786MB Used space: 3MB
FIrst changes I made were to this code as results from the ESP32 sd library were much better. I believe the bottleneck is still in the fat library configured for the SD lib.
SD_MMC.c
bool SDMMCFS::begin(const char * mountpoint, bool mode1bit)
{
if(_card) {
return true;
}
//mount
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// removed custom configuration
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
// overrided for my settings from the esp32 test - these do not apply to all boards... you have been warned.
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
slot_config.width = 1;
slot_config.flags = SDMMC_HOST_FLAG_1BIT;
sdmmc_host_set_bus_ddr_mode(SDMMC_HOST_SLOT_1, true);
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 5,
.allocation_unit_size = 64 * 1024
};
// static sdcard path made a difference in the path, I am unsure why but will know more later.
esp_err_t ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &_card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
log_e("Failed to mount filesystem. If you want the card to be formatted, set format_if_mount_failed = true.");
} else if (ret == ESP_ERR_INVALID_STATE) {
_impl->mountpoint(mountpoint);
log_w("SD Already mounted");
return true;
} else {
log_e("Failed to initialize the card (%d). Make sure SD card lines have pull-up resistors in place.", ret);
}
_card = NULL;
return false;
}
_impl->mountpoint(mountpoint);
return true;
}
I think the next issue lies in the SDMMC's IO functions.
In the ESP32-IDF library the test cases use a lot of very standard c code. Going to look into the implementation of file.write and file.read in the arduino-esp32 package as most of the latency seems to be in there.
The other thing, depending on the sd card, the ideal allocation size for reads vs writes in the esp32-idf examples seems to be 8192 bytes per block (for my sd card), so will also try and statically set that, then establish how to implement something which performs, but also runs on other sd cards optimally, perhaps might require adding a few functions, to set the 'block size' as they yeild different results and would be beneficial if you could configure them, depending on what you write to the flash.
void test_fatfs_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool is_write)
{
const size_t buf_count = file_size / buf_size;
FILE* f = fopen(filename, (is_write) ? "wb" : "rb");
TEST_ASSERT_NOT_NULL(f);
struct timeval tv_start;
gettimeofday(&tv_start, NULL);
for (size_t n = 0; n < buf_count; ++n) {
if (is_write) {
TEST_ASSERT_EQUAL(buf_size, 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));
TEST_FAIL();
}
}
}
struct timeval tv_end;
gettimeofday(&tv_end, NULL);
TEST_ASSERT_EQUAL(0, fclose(f));
float t_s = tv_end.tv_sec - tv_start.tv_sec + 1e-6f * (tv_end.tv_usec - tv_start.tv_usec);
printf("%s %d bytes (block size %d) in %.3fms (%.3f MB/s)\n",
(is_write)?"Wrote":"Read", file_size, buf_size, t_s * 1e3,
file_size / (1024.0f * 1024.0f * t_s));
}
Using bare c problem is much less of an issue.
Results are as follows. Let me know your results if you can.
block size 16k
1048576 bytes read for 1611 ms 1048576 bytes written for 6488 ms <--- original library code Wrote 1048576 bytes (block size 16384) in 2235.549ms (0.447 MB/s) Read 1048576 bytes (block size 16384) in 274.089ms (3.648 MB/s) <--- pure c write/read fat32
block size 8k, note im using 1 wire, non spi. (olimex-evb)
1048576 bytes read for 1612 ms 1048576 bytes written for 5588 ms Wrote 1048576 bytes (block size 8192) in 655.021ms (1.527 MB/s) Read 1048576 bytes (block size 8192) in 269.950ms (3.704 MB/s)
block size 4k
1048576 bytes read for 1623 ms 1048576 bytes written for 6915 ms Wrote 1048576 bytes (block size 4096) in 1263.701ms (0.791 MB/s) Read 1048576 bytes (block size 4096) in 332.474ms (3.008 MB/s)
block size 2k
1048576 bytes read for 1622 ms 1048576 bytes written for 7050 ms Wrote 1048576 bytes (block size 2048) in 1681.870ms (0.595 MB/s) Read 1048576 bytes (block size 2048) in 444.073ms (2.252 MB/s)
Arduino ESP32 Script.
/*
* Connect the SD card to the following pins:
*
* SD Card | ESP32
* D2 12
* D3 13
* CMD 15
* VSS GND
* VDD 3.3V
* CLK 14
* VSS GND
* D0 2 (add 1K pull up after flashing)
* D1 4
*/
#include "FS.h"
#include "SD_MMC.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include "esp_log.h"
#include "esp_system.h"
#include "esp_vfs.h"
#include "esp_vfs_fat.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/sdmmc_host.h"
#include "driver/sdmmc_defs.h"
#include "sdmmc_cmd.h"
#include "diskio.h"
#include "ff.h"
bool test_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool is_write)
{
const size_t buf_count = file_size / buf_size;
FILE* f = fopen(filename, (is_write) ? "wb" : "rb");
if(f == NULL) return false;
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));
return false;
}
}
}
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);
Serial.printf("%s %d bytes (block size %d) in %.3fms (%.3f MB/s)\n",
(is_write)?"Wrote":"Read", file_size, buf_size, t_s * 1e3,
file_size / (1024.0f * 1024.0f * t_s));
}
void listDir(fs::FS &fs, const char * dirname, uint8_t levels){
Serial.printf("Listing directory: %s\n", dirname);
File root = fs.open(dirname);
if(!root){
Serial.println("Failed to open directory");
return;
}
if(!root.isDirectory()){
Serial.println("Not a directory");
return;
}
File file = root.openNextFile();
while(file){
if(file.isDirectory()){
Serial.print(" DIR : ");
Serial.println(file.name());
if(levels){
listDir(fs, file.name(), levels -1);
}
} else {
Serial.print(" FILE: ");
Serial.print(file.name());
Serial.print(" SIZE: ");
Serial.println(file.size());
}
file = root.openNextFile();
}
}
void createDir(fs::FS &fs, const char * path){
Serial.printf("Creating Dir: %s\n", path);
if(fs.mkdir(path)){
Serial.println("Dir created");
} else {
Serial.println("mkdir failed");
}
}
void removeDir(fs::FS &fs, const char * path){
Serial.printf("Removing Dir: %s\n", path);
if(fs.rmdir(path)){
Serial.println("Dir removed");
} else {
Serial.println("rmdir failed");
}
}
void readFile(fs::FS &fs, const char * path){
Serial.printf("Reading file: %s\n", path);
File file = fs.open(path);
if(!file){
Serial.println("Failed to open file for reading");
return;
}
Serial.print("Read from file: ");
while(file.available()){
Serial.write(file.read());
}
}
void writeFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Writing file: %s\n", path);
File file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
if(file.print(message)){
Serial.println("File written");
} else {
Serial.println("Write failed");
}
}
void appendFile(fs::FS &fs, const char * path, const char * message){
Serial.printf("Appending to file: %s\n", path);
File file = fs.open(path, FILE_APPEND);
if(!file){
Serial.println("Failed to open file for appending");
return;
}
if(file.print(message)){
Serial.println("Message appended");
} else {
Serial.println("Append failed");
}
}
void renameFile(fs::FS &fs, const char * path1, const char * path2){
Serial.printf("Renaming file %s to %s\n", path1, path2);
if (fs.rename(path1, path2)) {
Serial.println("File renamed");
} else {
Serial.println("Rename failed");
}
}
void deleteFile(fs::FS &fs, const char * path){
Serial.printf("Deleting file: %s\n", path);
if(fs.remove(path)){
Serial.println("File deleted");
} else {
Serial.println("Delete failed");
}
}
void testFileIO(fs::FS &fs, const char * path){
File file = fs.open(path);
static uint8_t buf[512];
size_t len = 0;
uint32_t start = millis();
uint32_t end = start;
if(file){
len = file.size();
size_t flen = len;
start = millis();
while(len){
size_t toRead = len;
if(toRead > 512){
toRead = 512;
}
file.read(buf, toRead);
len -= toRead;
}
end = millis() - start;
Serial.printf("%u bytes read for %u ms\n", flen, end);
file.close();
} else {
Serial.println("Failed to open file for reading");
}
file = fs.open(path, FILE_WRITE);
if(!file){
Serial.println("Failed to open file for writing");
return;
}
size_t i;
start = millis();
for(i=0; i<2048; i++){
file.write(buf, 512);
}
end = millis() - start;
Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end);
file.close();
}
void setup(){
Serial.begin(115200);
if(!SD_MMC.begin()){
Serial.println("Card Mount Failed");
return;
}
uint8_t cardType = SD_MMC.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD_MMC card attached");
return;
}
Serial.print("SD_MMC Card Type: ");
if(cardType == CARD_MMC){
Serial.println("MMC");
} else if(cardType == CARD_SD){
Serial.println("SDSC");
} else if(cardType == CARD_SDHC){
Serial.println("SDHC");
} else {
Serial.println("UNKNOWN");
}
uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024);
Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize);
listDir(SD_MMC, "/", 0);
createDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 0);
removeDir(SD_MMC, "/mydir");
listDir(SD_MMC, "/", 2);
writeFile(SD_MMC, "/hello.txt", "Hello ");
appendFile(SD_MMC, "/hello.txt", "World!\n");
readFile(SD_MMC, "/hello.txt");
deleteFile(SD_MMC, "/foo.txt");
renameFile(SD_MMC, "/hello.txt", "/foo.txt");
readFile(SD_MMC, "/foo.txt");
testFileIO(SD_MMC, "/test.txt");
const size_t buf_size = 16 * 1024;
uint32_t* buf = (uint32_t*) calloc(1, buf_size);
esp_fill_random(buf, buf_size);
const size_t file_size = 1 * 1024 * 1024;
test_rw_speed("/sdcard/test.bin", buf, buf_size, file_size, true);
test_rw_speed("/sdcard/test.bin", buf, buf_size, file_size, false);
Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024));
}
void loop(){
}
Using bare c problem is much less of an issue.
Results are as follows. Let me know your results if you can.
block size 16k
1048576 bytes read for 1611 ms 1048576 bytes written for 6488 ms <--- original library code Wrote 1048576 bytes (block size 16384) in 2235.549ms (0.447 MB/s) Read 1048576 bytes (block size 16384) in 274.089ms (3.648 MB/s) <--- pure c write/read fat32
block size 8k, note im using 1 wire, non spi. (olimex-evb)
1048576 bytes read for 1612 ms 1048576 bytes written for 5588 ms Wrote 1048576 bytes (block size 8192) in 655.021ms (1.527 MB/s) Read 1048576 bytes (block size 8192) in 269.950ms (3.704 MB/s)
block size 4k
1048576 bytes read for 1623 ms 1048576 bytes written for 6915 ms Wrote 1048576 bytes (block size 4096) in 1263.701ms (0.791 MB/s) Read 1048576 bytes (block size 4096) in 332.474ms (3.008 MB/s)
block size 2k
1048576 bytes read for 1622 ms 1048576 bytes written for 7050 ms Wrote 1048576 bytes (block size 2048) in 1681.870ms (0.595 MB/s) Read 1048576 bytes (block size 2048) in 444.073ms (2.252 MB/s)
Arduino ESP32 Script.
/* * Connect the SD card to the following pins: * * SD Card | ESP32 * D2 12 * D3 13 * CMD 15 * VSS GND * VDD 3.3V * CLK 14 * VSS GND * D0 2 (add 1K pull up after flashing) * D1 4 */ #include "FS.h" #include "SD_MMC.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include "esp_log.h" #include "esp_system.h" #include "esp_vfs.h" #include "esp_vfs_fat.h" #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "driver/sdmmc_host.h" #include "driver/sdmmc_defs.h" #include "sdmmc_cmd.h" #include "diskio.h" #include "ff.h" bool test_rw_speed(const char* filename, void* buf, size_t buf_size, size_t file_size, bool is_write) { const size_t buf_count = file_size / buf_size; FILE* f = fopen(filename, (is_write) ? "wb" : "rb"); if(f == NULL) return false; 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)); return false; } } } 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); Serial.printf("%s %d bytes (block size %d) in %.3fms (%.3f MB/s)\n", (is_write)?"Wrote":"Read", file_size, buf_size, t_s * 1e3, file_size / (1024.0f * 1024.0f * t_s)); } void listDir(fs::FS &fs, const char * dirname, uint8_t levels){ Serial.printf("Listing directory: %s\n", dirname); File root = fs.open(dirname); if(!root){ Serial.println("Failed to open directory"); return; } if(!root.isDirectory()){ Serial.println("Not a directory"); return; } File file = root.openNextFile(); while(file){ if(file.isDirectory()){ Serial.print(" DIR : "); Serial.println(file.name()); if(levels){ listDir(fs, file.name(), levels -1); } } else { Serial.print(" FILE: "); Serial.print(file.name()); Serial.print(" SIZE: "); Serial.println(file.size()); } file = root.openNextFile(); } } void createDir(fs::FS &fs, const char * path){ Serial.printf("Creating Dir: %s\n", path); if(fs.mkdir(path)){ Serial.println("Dir created"); } else { Serial.println("mkdir failed"); } } void removeDir(fs::FS &fs, const char * path){ Serial.printf("Removing Dir: %s\n", path); if(fs.rmdir(path)){ Serial.println("Dir removed"); } else { Serial.println("rmdir failed"); } } void readFile(fs::FS &fs, const char * path){ Serial.printf("Reading file: %s\n", path); File file = fs.open(path); if(!file){ Serial.println("Failed to open file for reading"); return; } Serial.print("Read from file: "); while(file.available()){ Serial.write(file.read()); } } void writeFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Writing file: %s\n", path); File file = fs.open(path, FILE_WRITE); if(!file){ Serial.println("Failed to open file for writing"); return; } if(file.print(message)){ Serial.println("File written"); } else { Serial.println("Write failed"); } } void appendFile(fs::FS &fs, const char * path, const char * message){ Serial.printf("Appending to file: %s\n", path); File file = fs.open(path, FILE_APPEND); if(!file){ Serial.println("Failed to open file for appending"); return; } if(file.print(message)){ Serial.println("Message appended"); } else { Serial.println("Append failed"); } } void renameFile(fs::FS &fs, const char * path1, const char * path2){ Serial.printf("Renaming file %s to %s\n", path1, path2); if (fs.rename(path1, path2)) { Serial.println("File renamed"); } else { Serial.println("Rename failed"); } } void deleteFile(fs::FS &fs, const char * path){ Serial.printf("Deleting file: %s\n", path); if(fs.remove(path)){ Serial.println("File deleted"); } else { Serial.println("Delete failed"); } } void testFileIO(fs::FS &fs, const char * path){ File file = fs.open(path); static uint8_t buf[512]; size_t len = 0; uint32_t start = millis(); uint32_t end = start; if(file){ len = file.size(); size_t flen = len; start = millis(); while(len){ size_t toRead = len; if(toRead > 512){ toRead = 512; } file.read(buf, toRead); len -= toRead; } end = millis() - start; Serial.printf("%u bytes read for %u ms\n", flen, end); file.close(); } else { Serial.println("Failed to open file for reading"); } file = fs.open(path, FILE_WRITE); if(!file){ Serial.println("Failed to open file for writing"); return; } size_t i; start = millis(); for(i=0; i<2048; i++){ file.write(buf, 512); } end = millis() - start; Serial.printf("%u bytes written for %u ms\n", 2048 * 512, end); file.close(); } void setup(){ Serial.begin(115200); if(!SD_MMC.begin()){ Serial.println("Card Mount Failed"); return; } uint8_t cardType = SD_MMC.cardType(); if(cardType == CARD_NONE){ Serial.println("No SD_MMC card attached"); return; } Serial.print("SD_MMC Card Type: "); if(cardType == CARD_MMC){ Serial.println("MMC"); } else if(cardType == CARD_SD){ Serial.println("SDSC"); } else if(cardType == CARD_SDHC){ Serial.println("SDHC"); } else { Serial.println("UNKNOWN"); } uint64_t cardSize = SD_MMC.cardSize() / (1024 * 1024); Serial.printf("SD_MMC Card Size: %lluMB\n", cardSize); listDir(SD_MMC, "/", 0); createDir(SD_MMC, "/mydir"); listDir(SD_MMC, "/", 0); removeDir(SD_MMC, "/mydir"); listDir(SD_MMC, "/", 2); writeFile(SD_MMC, "/hello.txt", "Hello "); appendFile(SD_MMC, "/hello.txt", "World!\n"); readFile(SD_MMC, "/hello.txt"); deleteFile(SD_MMC, "/foo.txt"); renameFile(SD_MMC, "/hello.txt", "/foo.txt"); readFile(SD_MMC, "/foo.txt"); testFileIO(SD_MMC, "/test.txt"); const size_t buf_size = 16 * 1024; uint32_t* buf = (uint32_t*) calloc(1, buf_size); esp_fill_random(buf, buf_size); const size_t file_size = 1 * 1024 * 1024; test_rw_speed("/sdcard/test.bin", buf, buf_size, file_size, true); test_rw_speed("/sdcard/test.bin", buf, buf_size, file_size, false); Serial.printf("Total space: %lluMB\n", SD_MMC.totalBytes() / (1024 * 1024)); Serial.printf("Used space: %lluMB\n", SD_MMC.usedBytes() / (1024 * 1024)); } void loop(){ }
very good. I'm outside home,when i back a week later,i will test your code. can you test large file read?like 64MB or bigger?
Thanks, will try when I get some time free to do that will probably be tomorrow evening.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed in 14 days if no further activity occurs. Thank you for your contributions.
This stale issue has been automatically closed. Thank you for your contributions.
my tf(SDHC) card test on pc have 20MB/s read。 and I use the SDMMC_Text.ino to test,only 0.7MB/s。
I test three 4G tf card,one 2g,read slow as 0.5~0.7MB/S。the 2G card has 1MB write。
how to change the code to get fast read?