Hello,
I'm currently working on a project and have several components connected to an ESP32 (Wemos D1 Mini ESP32). Most parts are working fine, only I can't get my MicroSD card and the LCD/TFT working using the same SPI pins, sharing VSPI (using different select pins).
The LCD is working properly, but the SD card can not be used. Using this setup without changing the hardware connections, I can activate the SD card. Running the sketch the verbose output shows this:
21:38:44.104 -> Trying to connect to SD card with 20 MHz.
21:38:44.104 -> [ 1036][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.231 -> [ 1137][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.313 -> [ 1237][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.428 -> [ 1337][E][sd_diskio.cpp:199] sdCommand(): Card Failed! cmd: 0x00
21:38:44.428 -> [ 1337][W][sd_diskio.cpp:516] ff_sd_initialize(): GO_IDLE_STATE failed
21:38:44.428 -> [ 1338][E][sd_diskio.cpp:805] sdcard_mount(): f_mount failed: (3) The physical drive cannot work
21:38:44.428 -> [ 1347][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.529 -> [ 1452][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.598 -> [ 1552][W][sd_diskio.cpp:174] sdCommand(): no token received
21:38:44.712 -> [ 1652][E][sd_diskio.cpp:199] sdCommand(): Card Failed! cmd: 0x00
21:38:44.712 -> Error talking to SD card!
I reduced the sketch:
/*
* Using Arduino IDE v2.2.1
* Settings:
* Board: ESP32 / Wemos D1 Mini ESP32
* CPU frequency: 240 MHz (WiFi/BT)
* Core Debung Level: "Verbose"
* Erase all Flash before sketch upload: disabled
* Flash Frequency: 80MHz
* Partition Scheme: No OTA (Large APP)
* Upload Speed: 921600
*
* Hardware:
* - Wemos D1 Mini ESP32
* - 1.54 Inch Full Color IPS LCD Display Module 240x240 SPI Interface ST7789 8Pin
* - Micro SD card module
*
* Connections:
* ESP32 ST7789 (Display, also used by TTGO T-Display)
* IO4 BLK
* IO5 CS VSPI:CS
* IO16 DC
* IO23 RES (Reset) VSPI:MOSI
* IO19 SDA VSPI:MISO
* IO18 SCL VSPI:SCLK
*
* SD Card:
* IO19 SDA VSPI:MISO
* IO18 SCL VSPI:SCLK
* IO23 RES VSPI:MOSI
* IO17 CS
*/
#define USESDCARD
// SD Card chip select
#define SD_CS 17
#define LOGFILENAME "/test.log"
// WiFi
#include "WiFi.h"
#define WIFI_SCAN_PERIOD 5000
long lastWiFiScanMillis;
bool bWifiEnabled;
bool bWifiScanComplete = true;
// LCD/TFT display
// TFT_eSPI version 2.3.70
// use "#include <User_Setups/Setup25_TTGO_T_Display.h>"
#include <TFT_eSPI.h>
#include <SPI.h>
#include <Wire.h>
int tft_width = 240;
int tft_height = 240;
uint8_t tft_rotation = 3;
static const uint16_t tft_sizeScaler = 2;
TFT_eSPI tft = TFT_eSPI( tft_width, tft_height );
// If SD card should be supported
#ifdef USESDCARD
#include "SD.h"
uint32_t sdCardSize = 0l; // Card size in byte
bool sdAvailable = false;
File logfile;
#endif
// Brownout detector
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
void setup()
{
// Disable brownout detector
WRITE_PERI_REG( RTC_CNTL_BROWN_OUT_REG, 0 );
Serial.begin( 115200 );
vTaskDelay( 300 );
pinMode( TFT_CS, OUTPUT );
digitalWrite( TFT_CS, HIGH ); // TFT Chip select high (inactive)
pinMode( SD_CS, OUTPUT );
digitalWrite( SD_CS, HIGH ); // SDCard Chip select high (inactive)
enableWiFi();
// Initialize the screen
tft.init();
tft.setTextSize( tft_sizeScaler );
tft.setRotation( tft_rotation );
tft.fillRect( 0, 0, tft_width - 1, tft_height - 1, TFT_WHITE );
#ifdef USESDCARD
digitalWrite( TFT_CS, HIGH ); // TFT Chip select high (inactive)
sdAvailable = SDCardInit();
#endif
Serial.println( F( "Initialized" ) );
tft.drawString( "Hello", 10, 10, 1 );
}
void loop()
{
unsigned long currentMillis = millis();
if( bWifiEnabled )
{
if( ( currentMillis - lastWiFiScanMillis > WIFI_SCAN_PERIOD ) && ( bWifiScanComplete == true ) )
{
bWifiScanComplete = false;
WiFi.scanNetworks( true );
Serial.print( "\nScan start ... " );
lastWiFiScanMillis = currentMillis;
}
checkWiFis();
}
vTaskDelay( 100 );
}
#ifdef USESDCARD
bool SDCardInit()
{
bool init = false;
Serial.println( "Trying to connect to SD card with " + String( SPI_FREQUENCY / 1000000 ) + " MHz." );
if( SD.begin( SD_CS, tft.getSPIinstance() ) )
{
Serial.println( "SD card initialized successfull" );
Serial.print( "SD card type=" );
switch( SD.cardType() )
{
case CARD_NONE:
Serial.println( "None" );
break;
case CARD_MMC:
Serial.println( "MMC" );
break;
case CARD_SD:
Serial.println( "SD" );
break;
case CARD_SDHC:
Serial.println( "SDHC" );
break;
case CARD_UNKNOWN:
Serial.println( "Unknown" );
break;
default:
Serial.println( "Unknown" );
break;
}
// Get card size in MB
sdCardSize = SD.cardSize() / 1000000;
Serial.print( "Card size: " ); Serial.print( SD.cardSize() / 1000000 ); Serial.println( "MB" );
Serial.print( "Total bytes: " ); Serial.print( SD.totalBytes() / 1000000 ); Serial.println( "MB" );
Serial.print( "Used bytes: " ); Serial.print( SD.usedBytes() / 1000000 ); Serial.println( "MB" );
}
else
{
Serial.println( "Error talking to SD card!" );
}
return init;
}
// Unmount SD card
void SDCardUnmount()
{
if( sdAvailable )
{
Serial.print( "Unmounting SD card..." );
SD.end();
Serial.println( "done." );
sdAvailable = false;
}
}
void appendFile( const char *path, const char *message )
{
if( sdAvailable )
{
Serial.printf( "Appending to file: %s\n", path );
File file = SD.open( path, FILE_APPEND );
if( !file )
{
Serial.println( F( "Failed to open file for appending" ) );
return;
}
if( file.print( message ) )
{
Serial.println( F( "Message appended" ) );
}
else
{
Serial.println( F( "Append failed" ) );
}
file.close();
}
}
#endif
void enableWiFi()
{
bWifiScanComplete = true;
esp_err_t result;
bool bresult;
if( WiFi.isConnected() )
{
result = WiFi.disconnect() ;
Serial.print( F( "WiFi.disconnect()=" ) );
Serial.println( result );
}
bresult = WiFi.mode( WIFI_STA );
Serial.print( F( "WiFi.mode( WIFI_STA )=" ) );
if( bresult )
Serial.println( "OK" );
else
Serial.println( "not OK" );
bWifiEnabled = true;
lastWiFiScanMillis = millis();
if( lastWiFiScanMillis > WIFI_SCAN_PERIOD )
lastWiFiScanMillis -= WIFI_SCAN_PERIOD;
}
void disableWiFi()
{
esp_err_t result;
bool bresult;
if( WiFi.isConnected() )
{
result = WiFi.disconnect() ;
Serial.print( F( "WiFi.disconnect()=" ) );
Serial.println( result );
}
bresult = WiFi.mode( WIFI_OFF );
Serial.print( F( "WiFi.mode( WIFI_OFF )=" ) );
if( bresult )
Serial.println( "OK" );
else
Serial.println( "not OK" );
bWifiEnabled = false;
}
void checkWiFis()
{
int n = WiFi.scanComplete();
String tmp;
if( ( n != WIFI_SCAN_RUNNING ) && ( n != WIFI_SCAN_FAILED ) )
{
bWifiScanComplete = true;
Serial.println( String( n ) + " network(s) found:" );
for( int i = 0; i < n; i++ )
{
tmp = WiFi.SSID( i ) + ", Channel " + String ( WiFi.channel( i ) );
Serial.println( tmp );
#ifdef USESDCARD
appendFile( LOGFILENAME, tmp.c_str() );
#endif
}
WiFi.scanDelete();
}
}
My question is: is it possible to share the SPI (using VSPI as per default) between SD and TFT?
The HSPI is used by an other component so I can't / won't share this.
For the complete project the speed of the TFT is not really important, I reduced the SPI frequency down to 20MHz by modifying "Setup25_TTGO_T_Display.h":
#define SPI_FREQUENCY 20000000 // Maximum for ILI9341
Or did I miss something?
Best regards
Nils