-
Notifications
You must be signed in to change notification settings - Fork 7.7k
Description
Board
ESP32-C3 dev module
Device Description
ESP32-C3 dev module
Hardware Configuration
Micro SDHC card 4GB, wired to SCK:3, MOSI: 4, MISO:5, SD_CS:20
Version
v2.0.2
IDE Name
arduino IDE
Operating System
windows 10
Flash frequency
80M
PSRAM enabled
no
Upload speed
CDC
Description
The Micro SD car socket is wired to GPIOs : SCK:3, MOSI: 4, MISO:5, SD_CS:20,
I copied the IDF SPI SD card example into an arduino project, adjusted the GPIOs and it works perfectly, right away (after setting DMA to auto) at 20MHz and below.
But when i open the SD card SPI example provided in the Arduino IDE for ESP32-C3, set to the exact same pinout, on the exact same board / SD it fails miserably, with CRC errors and timeouts all over the place, regardless of the SPI bus speed (tested from 400K to 20M).
When i compare the traces with logic analyzer i cannot even compare, they are too dissimilar and the traces of the Arduino example are filled with 100ms timeouts. Basically all it can do is to read the card information, sector number, size, without error, but any write access leads to immediate failure.
Sketch
//**********IDE example********************
#include "FS.h"
#include "SD.h"
#include "SPI.h"
#define SCK 3
#define MOSI 4
#define MISO 5
#define SD_CS 20
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.path(), 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());
}
file.close();
}
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");
}
file.close();
}
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");
}
file.close();
}
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 sd_test(){
SPI.begin(SCK, MISO, MOSI, -1);
Serial.println("SD test");
if(!SD.begin(SD_CS,SPI,2000000)){
Serial.println("Card Mount Failed");
return;
}
Serial.println("Card Mount OK");
uint8_t cardType = SD.cardType();
if(cardType == CARD_NONE){
Serial.println("No SD card attached");
return;
}
Serial.print("SD 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.cardSize() / (1024 * 1024);
Serial.printf("SD Card Size: %lluMB\n", cardSize);
// listDir(SD, "/", 0);
// createDir(SD, "/mydir");
// listDir(SD, "/", 0);
// removeDir(SD, "/mydir");
// listDir(SD, "/", 2);
writeFile(SD, "/hello.txt", "Hello ");
// appendFile(SD, "/hello.txt", "World!\n");
// readFile(SD, "/hello.txt");
deleteFile(SD, "/foo.txt");
renameFile(SD, "/hello.txt", "/foo.txt");
readFile(SD, "/foo.txt");
// testFileIO(SD, "/test.txt");
Serial.printf("Total space: %lluMB\n", SD.totalBytes() / (1024 * 1024));
Serial.printf("Used space: %lluMB\n", SD.usedBytes() / (1024 * 1024));
}
void setup(){
Serial.begin(115200);
while(!Serial);
delay(1800);
Serial.println("System init");
sd_test();
}
void loop(){
}
//***************IDF Example*******************
#ifdef CORE_DEBUG_LEVEL
#undef CORE_DEBUG_LEVEL
#endif
#define CORE_DEBUG_LEVEL 3
#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#define SDMMC_FREQ_DEFAULT 2000
#include <stdio.h>
#include <string.h>
#include <sys/unistd.h>
#include <sys/stat.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_vfs_fat.h"
#include "driver/sdspi_host.h"
#include "driver/spi_common.h"
#include "sdmmc_cmd.h"
#include "sdkconfig.h"
static const char *TAG = "FGW";
#define MOUNT_POINT "/sdcard"
#define USE_SPI_MODE
#define SPI_DMA_CHAN SPI_DMA_CH_AUTO
#define PIN_NUM_MISO (gpio_num_t)5
#define PIN_NUM_MOSI (gpio_num_t)4
#define PIN_NUM_CLK (gpio_num_t)3
#define PIN_NUM_CS (gpio_num_t)20
#define ESP_LOGI ESP_LOGE
void app_main(void){
esp_err_t ret;
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = true,
//.format_if_mount_failed = false,
.max_files = 5,
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t* card;
const char mount_point[] = MOUNT_POINT;
ESP_LOGI(TAG, "Initializing SD card");
ESP_LOGI(TAG, "Using SPI peripheral");
sdmmc_host_t host = SDSPI_HOST_DEFAULT();
spi_bus_config_t bus_cfg = {
.mosi_io_num = PIN_NUM_MOSI,
.miso_io_num = PIN_NUM_MISO,
.sclk_io_num = PIN_NUM_CLK,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = 4000,
};
ret = spi_bus_initialize((spi_host_device_t)host.slot, &bus_cfg, SPI_DMA_CHAN);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Failed to initialize bus.");
return;
}
// 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 = PIN_NUM_CS;
slot_config.host_id = (spi_host_device_t)host.slot;
ret = esp_vfs_fat_sdspi_mount(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set the EXAMPLE_FORMAT_IF_MOUNT_FAILED menuconfig option.");
} else {
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));
}
return;
}
sdmmc_card_print_info(stdout, card);
ESP_LOGI(TAG, "Opening file");
FILE* f = fopen(MOUNT_POINT"/hello.txt", "w");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for writing");
return;
}
fprintf(f, "Hello %s!\n", card->cid.name);
fclose(f);
ESP_LOGI(TAG, "File written");
// Check if destination file exists before renaming
struct stat st;
if (stat(MOUNT_POINT"/foo.txt", &st) == 0) {
// Delete it if it exists
unlink(MOUNT_POINT"/foo.txt");
}
// Rename original file
ESP_LOGI(TAG, "Renaming file");
if (rename(MOUNT_POINT"/hello.txt", MOUNT_POINT"/foo.txt") != 0) {
ESP_LOGE(TAG, "Rename failed");
return;
}
// Open renamed file for reading
ESP_LOGI(TAG, "Reading file");
f = fopen(MOUNT_POINT"/foo.txt", "r");
if (f == NULL) {
ESP_LOGE(TAG, "Failed to open file for reading");
return;
}
char line[64];
fgets(line, sizeof(line), f);
fclose(f);
// strip newline
char* pos = strchr(line, '\n');
if (pos) {
*pos = '\0';
}
ESP_LOGI(TAG, "Read from file: '%s'", line);
esp_vfs_fat_sdcard_unmount(mount_point, card);
ESP_LOGI(TAG, "Card unmounted");
spi_bus_free((spi_host_device_t)host.slot);
}
void setup() {
Serial.begin(115200);
while(!Serial);
delay(1800);
Serial.println("System init ");
app_main();
}
void loop() {
}
Debug Message
//*****************IDE EXAMPLE DEBUG****************
ESP-ROM:esp32c3-api1-20210207
System init
SD test
Card Mount OK
SD Card Type: SDHC
SD Card Size: 3748MB
Writing file: /hello.txt
[ 4587][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 4691][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 4791][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 4891][W][sd_diskio.cpp:183] sdCommand(): crc error
File written
[ 4991][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 5102][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 5263][W][sd_diskio.cpp:177] sdCommand(): no token received
Deleting file: /foo.txt
[ 5364][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 5468][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 5568][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 5667][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 5768][W][sd_diskio.cpp:183] sdCommand(): crc error
File deleted
Renaming file /hello.txt to /foo.txt
[ 5901][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 6005][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 6105][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 6204][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 6305][W][sd_diskio.cpp:183] sdCommand(): crc error
File renamed
Reading file: /foo.txt
[ 6416][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 6517][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 6617][W][sd_diskio.cpp:183] sdCommand(): crc error
Read from file: [ 6717][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 6817][W][sd_diskio.cpp:183] sdCommand(): crc error
Hello [ 6921][W][sd_diskio.cpp:177] sdCommand(): no token received
[ 7020][W][sd_diskio.cpp:183] sdCommand(): crc error
[ 7121][W][sd_diskio.cpp:183] sdCommand(): crc error
Total space: 3747MB
[ 7221][W][sd_diskio.cpp:183] sdCommand(): crc error
Used space: 1MB
//*****************IDF EXAMPLE DEBUG****************
E (10090) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
E (10090) task_wdt: - IDLE (CPU 0)
E (10090) task_wdt: Tasks currently running:
E (10090) task_wdt: CPU 0: loopTask
System init
E (11898) FGW: Initializing SD card
E (11898) FGW: Using SPI peripheral
Name: 00000
Type: SDHC/SDXC
Speed: 20 MHz
Size: 3748MB
E (11971) FGW: Opening file
E (12020) FGW: File written
E (12049) FGW: Renaming file
E (12061) FGW: Reading file
E (12064) FGW: Read from file: 'Hello 00000!'
E (12064) FGW: Card unmounted
Other Steps to Reproduce
Well, to reproduce just wire a standard Micro SD to SCK:3, MOSI: 4, MISO:5, SD_CS:20 on a ESP32-C3 dev module or board and run each code, the IDE example fails, the IDF example works, which shows something is wrong in the implementation of the SD SPI on the C3.
It seems unlikely to be the SD driver itself since it has been proven. it works with the IDF example, which uses the same SD card driver, so maybe it has to do with the Arduino SPI driver / DMA? I compared quickly the SD.cpp from arduino with the SD driver of IDF and it seems identical for the SDCommand fonction.
I have checked existing issues, online documentation and the Troubleshooting Guide
- I confirm I have checked existing issues, online documentation and Troubleshooting guide.