-
Notifications
You must be signed in to change notification settings - Fork 7.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SD card implementation does not set SPI mode before activating card #9218
Comments
This is a bit hard to believe, because SD access is guarded by SPI transactions that do set the mode to 0: https://github.com/espressif/arduino-esp32/blob/master/libraries/SD/src/sd_diskio.cpp#L468 If what you say indeed happens, then you must have hit some edge case/bug that makes transactions not working. |
Thanks for a heads up. I will try to make a minimum reproduction project where it's reproduced 100% of the time and post it shortly. |
I think I found the problem: it's due to speed. If SPI speed is changed to a high value between SD calls, subsequent SD calls will fail. Example code: #include <SD.h>
#define SD_SCK 0
#define SD_MISO 8
#define SD_MOSI 1
#define SD_SS 20
#define DBG_PIN 5
#define INTERNAL_TRANSACTION_SPEED 40000000 // 40 MHz
void debugMark() {
// Helps to visually identify stuff in logic analyzer
delay(50);
digitalWrite(DBG_PIN, HIGH);
delay(100);
digitalWrite(DBG_PIN, LOW);
delay(50);
}
void setup() {
Serial.begin(115200);
SPI.begin(SD_SCK, SD_MISO, SD_MOSI);
pinMode(DBG_PIN, OUTPUT);
digitalWrite(5, LOW);
delay(2000);
// Init SD card
Serial.print("Initializing SD card... ");
if (!SD.begin(SD_SS)) {
Serial.println("FAILED!");
return;
}
Serial.println("OK.");
// Read file
File f = SD.open("/foo.txt");
if (f) {
Serial.println("foo.txt: " + f.readString());
f.close();
}
debugMark();
// Start internal transaction
for (int i = 0; i < 256; i++) {
SPI.beginTransaction(SPISettings(INTERNAL_TRANSACTION_SPEED, MSBFIRST, SPI_MODE3));
SPI.write(i);
SPI.endTransaction();
}
debugMark();
// Read file again
f = SD.open("/foo.txt");
if (f) {
Serial.println("foo.txt: " + f.readString());
f.close();
}
}
void loop() {} If
Timing diagram looks as follows: Details:
All frequencies listed above are taken directly from the logic analyzer. I specified the exact values since the image is too small for them to be visible. :) FixesIf I set Alternatively, if I add this... SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE3)); // Reset speed back to 4 MHz
SPI.write(0);
SPI.endTransaction(); ...just before "// Read file again" comment, the issue is not being reproduced as well. |
I also noticed another curious (unrelated) thing: SPI clock polarity is not affected by SPI.beginTransaction(SPISettings(..., ..., SPI_MODE0));
SPI.write(0xFF);
SPI.endTransaction();
// SCK is now LOW (mode 0)
SPI.beginTransaction(SPISettings(..., ..., SPI_MODE3));
SPI.endTransaction();
// SCK is STILL LOW (despite being in mode 3) This has affected my TFT display, since clock polarity was not being changed before activating the display. EDIT: On a second thought, this comment might be off-copic, so I created another issue for this problem: #9221 |
Update: my bad, this was only reproducible with v2.0.6. Turns out my project was being built with v2.0.6 for some reason. Sorry for wasting your time. I cannot reproduce this anymore with v2.0.14. #9221 still persists though. |
Board
ESP32-C3
Device Description
ESP32-C3 SuperMini with ST7789 display and micro SD Card on the same SPI bus.
Hardware Configuration
Several pushbuttons on different pins (unrelated to the problem)
Version
v2.0.14v2.0.6IDE Name
nvim
Operating System
ArchLinux
Flash frequency
40MHz
PSRAM enabled
no
Upload speed
N/A
Description
SD library sets SPI mode to 0 as expected.
However, if SPI bus config changes between SD calls (e. g. a TFT display sets mode to 3), the SD library will attempt to use the incorrect mode, fail, and re-init the card.
Possible solution is to ensure that SPI mode is valid when enabling the card, and set it to 0 otherwise.
Signal diagram:
As you can see, SCK is initially 1 (CPOL=1, mode 3, set by TFT earlier). After 3 attempts, card is re-initialized (notice the burst on the right), and afterwards the mode is set to 0.
Sketch
Debug Message
Other Steps to Reproduce
No response
I have checked existing issues, online documentation and the Troubleshooting Guide
The text was updated successfully, but these errors were encountered: