LovyanGFX icon indicating copy to clipboard operation
LovyanGFX copied to clipboard

How can LovyanGFX support the sdmmc ?

Open zhjygit opened this issue 5 months ago • 18 comments

Here, i have a esp32s3-groom1-N16R8-lcd4.3,my tf cart is sdmmc type. If I want to read the png maps from sd card and draw the picture on the tft display via the gps location datas. Most of the code on github is about the spiSD card, how can LovyanGFX support the sdmmc? Waiting for you reply. Here is my project:https://github.com/jgauchia/IceNav-v3, this project uses the LovyanGFX and spiSD card. Maybe you can solve the problem.

zhjygit avatar Jan 22 '24 13:01 zhjygit

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Feb 21 '24 14:02 github-actions[bot]

just include FS.h or SD.h before including LovyanGFX (e.g. insert #include <FS.h> at first line of hardware/tft.h) and it will expose LGFX filesystem related functions.

however it's more practical to just stick with Stream related functions e.g. :

auto jpgFile = SD.open("/path/to/my-image.jpg");
tft.drawJpg( &jpgFile );

tobozo avatar Feb 21 '24 14:02 tobozo

This works for Arduino ESP32 , have not tried yet with ESP32 IDF >5.00 and written the function changes:- Also not tested with ESP S3 or ESP C3 yet....

// updated include order as per Tobozo comment below
#define LGFX_USE_V1
#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include <LovyanGFX.hpp>



There is no SDcard SPI CS in LovyanGFX LCD SPI setup So native file handling has to be set up with includes FS/SD as normal for SD card (See SDTest in exmples for ESP32) SD card is SPI and if your LCD is an SPI type you will be sharing MISIO,MOSI and CLK so cfg.bus_shared = true; !!!

I used CS as 5 for LCD and CS as 4 for SD card Here is my SD card pin out (Arduino default VSPI) 3V3 to 3V3 pin CS 4 (GPIO4) -- NOT Default for Arduino SD card MOSI 23 (GPIO23) --Default for Arduino SD card CLK 18 (GPIO18)- -Default for Arduino SD card MISO 19 (GPIO19)--Default for Arduino SD card GND to GND pin

***** Place your LGFX setup class next ******* Use Examples Howtouse/usersetting as a guide translate Japanese with google translate

I have ILI9488 (SPI) LCD , with Touch IC FT6336 (I2C) and LED Backlight that can use PWM

// NOT SHOWN IN FULL 
class LGFX : public lgfx::LGFX_Device
{
    lgfx::Panel_ILI9488     _panel_instance;
    lgfx::Bus_SPI           _bus_instance;   // SPI bus instance
    lgfx::Light_PWM         _light_instance;
    lgfx::Touch_FT5x06       _touch_instance; // FT5206, FT5306, FT5406, FT6206, FT6236, FT6336, FT6436
//..................

// Configure bus control settings........... 
    cfg.spi_host = VSPI_HOST; // Select the SPI to use VSPI_HOST 
// ................
    cfg.pin_sclk =  18; // Set SPI SCLK pin number
    cfg.pin_mosi = 23; // Set the SPI MOSI pin number
    cfg.pin_miso = 19; // Set SPI MISO pin number (-1 = disable)
    cfg.pin_dc =     22; // Set SPI D/C pin number (-1 = disable)
//.............
// Set display panel control......................
    cfg.pin_cs = 5; // Pin number to which CS is connected (-1 = disable)
    cfg.pin_rst = 3 ; // Pin number to which RST is connected (-1 = disable)  (I use EN pin)
//.............
// IPS LCD's may need cfg.invert = true;
// remember !! cfg.bus_shared = true;
//.............

// Set backlight control ......................
    cfg.pin_bl = 21;  // Pin number to which the backlight is connected
//Configure touch screen control settings. ...................
//...................
    cfg.pin_int    = 25;  //Pin number to which Touch  INT is connected
// ..................
// For I2C connection
    cfg.i2c_port = 1; // Select I2C to use (0 or 1)
    cfg.i2c_addr = 0x38; // I2C device address number
    cfg.pin_sda = 33; // Pin number to which SDA is connected
    cfg.pin_scl = 32; // Pin number to which SCL is connected
    cfg.freq = 400000; // Set I2C clock
 _touch_instance.config(cfg);
     _panel_instance.setTouch(&_touch_instance);  // タッチスクリーンをパネルにセットします。
   }
    setPanel(&_panel_instance); // Set the panel to use.
  }
};

LGFX lcd;
/*
Example to show how to place a PNG picture on screen at any  X,,Y  or scale etc.
Note this streams the file from the SD card and fixes the SD card CS issues I had.
See call in loop... Note:  'Auto' is C++ in Aurdino main 
Take care if  calling from C  maybe within a ESP IDF C based code source
*/
void drawPng(
 fs::FS &fs,
 const char *filename,
 int32_t x=0,
 int32_t y=0,
 int32_t maxW =-1,
 int32_t maxH = -1,
 int32_t offX =0,
 int32_t offY = 0,
 float scale_x =1.0F ,
 float scale_y =1.0f,
 textdatum_t datum = TL_DATUM
 ){
 auto pngFile = fs.open(filename);
 if(!pngFile){
    Serial.println("Failed to open the image file.");
 } else {
   lcd.drawPng( &pngFile,x,y,maxW,maxH,offX,offY,datum);
   pngFile.close();
 }
}


// Example function to show fies on sdcard to LCD display 
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();
   lcd.setCursor(0, 0);
   lcd.setTextColor(TFT_WHITE);	
   lcd.setFont( &fonts::Font0   );
   while(file){
       

       if(file.isDirectory()){
           Serial.print("  DIR : ");
           Serial.println(file.name());
           lcd.print(("  DIR : "));
           lcd.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());

           lcd.print("  FILE: ");
           lcd.print(file.name());
           lcd.print("  SIZE: ");
           lcd.println(file.size());
        
       }
       file = root.openNextFile();
   }
}

//Example Setup for SDcard, LCD and touch
void setup(void)
{
 Serial.begin(115200);
   if(!SD.begin(4)){  // Note call it with 4 if thats your SD card CS
       Serial.println("Card Mount Failed");
       return;
   }
   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);
   lcd.init();
   lcd.begin();        
   lcd.setRotation(3);  // My LCD is 420x320 ribbon to the left 
   lcd.setBrightness(255); // Change to lower LED backlight 
   lcd.clear(TFT_BLACK);
   lcd.setCursor(0, 0);
   lcd.setTextColor(TFT_WHITE);
   lcd.setTextSize((std::max(lcd.width(), lcd.height()) + 255) >> 8);

//  Calibrate when touch is available. (Optional)
 if (lcd.touch())
 {
   if (lcd.width() < lcd.height()) lcd.setRotation(lcd.getRotation() ^ 1);

   // Draw the guide text on the screen.
   lcd.setTextDatum(textdatum_t::middle_center);
   lcd.drawString("touch the arrow marker.", lcd.width()>>1, lcd.height() >> 1);
   lcd.setTextDatum(textdatum_t::top_left);

   // Calibrate when using touch. Touch the tips of the arrows displayed at the four corners of the screen in order.
   std::uint16_t fg = TFT_WHITE;
   std::uint16_t bg = TFT_BLACK;
   if (lcd.isEPD()) std::swap(fg, bg);
   lcd.calibrateTouch(nullptr, fg, bg, std::max(lcd.width(), lcd.height()) >> 3);
 }
// After clear screen show some text and enter loop
 lcd.clear(TFT_BLACK);
 lcd.drawString("Demo here", 0, 0);
 lcd.drawString("Draw on screen", (lcd.width()/2)-80, lcd.height()-20);
}
//Main Arduino loop
void loop(void)
{

 //Example touch loop
 int32_t x, y;
 if (lcd.getTouch(&x, &y)) {
   // make top left hand corner a touch zone
     if(x<20 && y<20){
       lcd.fillScreen(TFT_BLACK);
       drawPng(SD,"/logo.png",0,100);  // Note make sure your SDcard as a png image keep small
       listDir(SD, "/", 0);            // Show the dir with files in root (dont have lots about 6 files)
     }
   
   lcd.fillRect(x-2, y-2, 2, 2, TFT_WHITE);    // places dot for each touch position
 }
 delay(1); // Note on Arduino loop is FreeRTOS task loop 
 // with no vTaskDelay(pdMS_TO_TICKS(100)); so can fire watchdog time out
 // if loop run without giving some CPU time for tasks
 // I think Arduino delay is made from vTaskDelay so may fix this issue?
}

daverathbone avatar Mar 07 '24 21:03 daverathbone

ths is wrong:

#define LGFX_USE_V1
#include <LovyanGFX.hpp>
#include "FS.h"
#include "SD.h"
#include "SPI.h

by doing so you just create two different instances of LovyanGFX, one with filesystem support (sketch scope) and one without it (global scope).

This works for Arduino ESP32

and it probably fails with platformio and esp-idf

filesystem related libraries should be included before LovyanGFX to prevent this:

#define LGFX_USE_V1
#include <FS.h>
#include <SD.h>
#include <SPI.h>
#include <LovyanGFX.hpp>

tobozo avatar Mar 07 '24 22:03 tobozo

@daverathbone if this works for you, please share a link I am particularly interested in working examples using SdFat / exFat working with SPI shared between SD and display

thanks!

mhaberler avatar Mar 08 '24 04:03 mhaberler

@daverathbone if this works for you, please share a link I am particularly interested in working examples using SdFat / exFat working with SPI shared between SD and display

thanks!

The format for your SDcard is handled external to the display code suggest you get an example running with your SD card format first , e.g. read file, open file etc. then the streaming or file handling should use the standard C/C++ file handling within LovyanGFX calls.

daverathbone avatar Mar 08 '24 10:03 daverathbone

@daverathbone I considered that, but the application requires a 64bit filesystem and DataWrapper is all 32bit

I want to nail down the specific requirements in setup and calling sequence to have both the SD and display on the same bus. Very easy to create to have a display operation kill SD I/O and vice versa.

This repo https://github.com/GOB52/M5Stack_FlipBookSD has a working example of SdFat I/O and M5Unified/M5GFX - I want the same for LovyanGFX.

The whole thing is a bit of black art; for example it took me the above repo to get this to work - it is unclear to me why

        M5.Display.startWrite();
        M5.Display.clear(TFT_RED);
        M5.Display.endWrite();

is ok, but

        display.startWrite();
        display.clear(TFT_RED);
        display.endWrite();

brings down the house.

mhaberler avatar Mar 08 '24 11:03 mhaberler

@mhaberler

M5Unified can manage more than one display, so aliasing display to M5.Display before the init occured may be the reason why you get a crash when using the alias.

M5Unified.hpp

    M5GFX Display;  // setPrimaryされたディスプレイのインスタンス
    M5GFX &Lcd = Display;

Personnally I find the macro to be more reliable than the global declaration:

#define myDisplay M5.Display

tobozo avatar Mar 08 '24 12:03 tobozo

oh ok, observed behaviour starts making sense now - will adopt your macro practice

how did you find your way to this result ;-?

edit: tried, house still standing ;)

mhaberler avatar Mar 08 '24 13:03 mhaberler

how did you find your way to this result ;-?

by pulling my hair with M5Stack-SD-Updater context guessing

tobozo avatar Mar 08 '24 13:03 tobozo

great, so the M5Unified version works fine with simultaneous display and SD/SdFat use

trying to use non-M5 boards, I massaged that code to use LovyanGFX and I'm back at square 1 - using display disables SD card

is this possible in principle after all, or does the status https://github.com/lovyan03/LovyanGFX/issues/491 apply (i.e. unresolved)?

works fine for target coreS3-pmtiles-m5unified, breaks for coreS3-pmtiles-lovyangfx https://github.com/mhaberler/embedded-protomaps/commits/lovyangfx/

mhaberler avatar Mar 08 '24 19:03 mhaberler

If display and SD card are on the same SPI Bus, then you need to do this

https://github.com/sukesh-ak/ESP32-TUX/blob/47639648a37ffc9ef9c2a748eeb9761894b9238a/main/devices/conf_WT32SCO1.h#L120

cfg.bus_shared = true;    // Set to true when sharing the bus with sd card (bus control is performed with drawJpgFile, etc.)

And then don't initialize the bus again. Both options are demonstrated in my ESP32-TUX project.

sukesh-ak avatar Mar 27 '24 16:03 sukesh-ak

found this old gist with a very slow buf safe approach to sharing the bus, not sure if it's still working though

tobozo avatar Mar 28 '24 11:03 tobozo

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

github-actions[bot] avatar Apr 27 '24 12:04 github-actions[bot]

not stale

mhaberler avatar Apr 27 '24 13:04 mhaberler