diff --git a/Marlin/Configuration_adv.h b/Marlin/Configuration_adv.h
index 6398f4161b..741a85bdb2 100644
--- a/Marlin/Configuration_adv.h
+++ b/Marlin/Configuration_adv.h
@@ -290,6 +290,7 @@
 #define SD_FINISHED_STEPPERRELEASE true  //if sd support and the file is finished: disable steppers?
 #define SD_FINISHED_RELEASECOMMAND "M84 X Y Z E" // You might want to keep the z enabled so your bed stays in place.
 
+#define SDCARD_SORT_ALPHA // Sort in ASCII order by pre-reading the folder and making a lookup table!
 #define SDCARD_RATHERRECENTFIRST  //reverse file order of sd card menu display. Its sorted practically after the file system block order.
 // if a file is deleted, it frees a block. hence, the order is not purely chronological. To still have auto0.g accessible, there is again the option to do that.
 // using:
diff --git a/Marlin/SdFatConfig.h b/Marlin/SdFatConfig.h
index 710b1f7924..39ef381300 100644
--- a/Marlin/SdFatConfig.h
+++ b/Marlin/SdFatConfig.h
@@ -111,10 +111,12 @@ uint8_t const SOFT_SPI_SCK_PIN = 13;
 /**
  * Defines for long (vfat) filenames
  */
+/** Number of UTF-16 characters per entry */
+#define FILENAME_LENGTH 13
 /** Number of VFAT entries used. Every entry has 13 UTF-16 characters */
 #define MAX_VFAT_ENTRIES (2)
 /** Total size of the buffer used to store the long filenames */
-#define LONG_FILENAME_LENGTH (13*MAX_VFAT_ENTRIES+1)
+#define LONG_FILENAME_LENGTH (FILENAME_LENGTH*MAX_VFAT_ENTRIES+1)
 #endif  // SdFatConfig_h
 
 
diff --git a/Marlin/cardreader.cpp b/Marlin/cardreader.cpp
index d2fb418fba..862ed38475 100644
--- a/Marlin/cardreader.cpp
+++ b/Marlin/cardreader.cpp
@@ -11,6 +11,10 @@
 
 CardReader::CardReader()
 {
+  #if SORT_USES_MORE_RAM
+   sortnames = NULL;
+   sort_count = 0;
+  #endif
    filesize = 0;
    sdpos = 0;
    sdprinting = false;
@@ -53,15 +57,15 @@ char *createFilename(char *buffer,const dir_t &p) //buffer>12characters
 void  CardReader::lsDive(const char *prepend,SdFile parent)
 {
   dir_t p;
- uint8_t cnt=0;
+  uint8_t cnt=0;
  
-  while (parent.readDir(p, longFilename) > 0)
+  while (parent.readDir(p, diveFilename) > 0)
   {
     if( DIR_IS_SUBDIR(&p) && lsAction!=LS_Count && lsAction!=LS_GetFilename) // hence LS_SerialPrint
     {
 
-      char path[13*2];
-      char lfilename[13];
+      char path[FILENAME_LENGTH*2];
+      char lfilename[FILENAME_LENGTH];
       createFilename(lfilename,p);
       
       path[0]=0;
@@ -87,25 +91,22 @@ void  CardReader::lsDive(const char *prepend,SdFile parent)
       }
       lsDive(path,dir);
       //close done automatically by destructor of SdFile
-
-      
     }
     else
     {
       if (p.name[0] == DIR_NAME_FREE) break;
       if (p.name[0] == DIR_NAME_DELETED || p.name[0] == '.'|| p.name[0] == '_') continue;
-      if (longFilename[0] != '\0' &&
-          (longFilename[0] == '.' || longFilename[0] == '_')) continue;
+      if (diveFilename[0] != '\0' &&
+          (diveFilename[0] == '.' || diveFilename[0] == '_')) continue;
       if ( p.name[0] == '.')
       {
         if ( p.name[1] != '.')
         continue;
       }
-      
+
       if (!DIR_IS_FILE_OR_SUBDIR(&p)) continue;
       filenameIsDir=DIR_IS_SUBDIR(&p);
-      
-      
+
       if(!filenameIsDir)
       {
         if(p.name[8]!='G') continue;
@@ -124,10 +125,8 @@ void  CardReader::lsDive(const char *prepend,SdFile parent)
       } 
       else if(lsAction==LS_GetFilename)
       {
-        if(cnt==nrFiles)
-          return;
+        if (cnt == nrFiles) return;
         cnt++;
-        
       }
     }
   }
@@ -136,9 +135,6 @@ void  CardReader::lsDive(const char *prepend,SdFile parent)
 void CardReader::ls() 
 {
   lsAction=LS_SerialPrint;
-  if(lsAction==LS_Count)
-  nrFiles=0;
-
   root.rewind();
   lsDive("",root);
 }
@@ -177,6 +173,9 @@ void CardReader::initsd()
   }
   workDir=root;
   curDir=&root;
+  #ifdef SDCARD_SORT_ALPHA
+    presort();
+  #endif
   /*
   if(!workDir.openRoot(&volume))
   {
@@ -193,8 +192,10 @@ void CardReader::setroot()
     SERIAL_ECHOLNPGM(MSG_SD_WORKDIR_FAIL);
   }*/
   workDir=root;
-  
   curDir=&workDir;
+  #ifdef SDCARD_SORT_ALPHA
+    presort();
+  #endif
 }
 void CardReader::release()
 {
@@ -235,7 +236,7 @@ void CardReader::getAbsFilename(char *t)
     while(*t!=0 && cnt< MAXPATHNAMELENGTH) 
     {t++;cnt++;}  //crawl counter forward.
   }
-  if(cnt<MAXPATHNAMELENGTH-13)
+  if(cnt<MAXPATHNAMELENGTH-FILENAME_LENGTH)
     file.getFilename(t);
   else
     t[0]=0;
@@ -305,7 +306,7 @@ void CardReader::openFile(char* name,bool read, bool replace_current/*=true*/)
       //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
       if(dirname_end>0 && dirname_end>dirname_start)
       {
-        char subdirname[13];
+        char subdirname[FILENAME_LENGTH];
         strncpy(subdirname, dirname_start, dirname_end-dirname_start);
         subdirname[dirname_end-dirname_start]=0;
         SERIAL_ECHOLN(subdirname);
@@ -401,7 +402,7 @@ void CardReader::removeFile(char* name)
       //SERIAL_ECHO("end  :");SERIAL_ECHOLN((int)(dirname_end-name));
       if(dirname_end>0 && dirname_end>dirname_start)
       {
-        char subdirname[13];
+        char subdirname[FILENAME_LENGTH];
         strncpy(subdirname, dirname_start, dirname_end-dirname_start);
         subdirname[dirname_end-dirname_start]=0;
         SERIAL_ECHOLN(subdirname);
@@ -439,6 +440,9 @@ void CardReader::removeFile(char* name)
       SERIAL_PROTOCOLPGM("File deleted:");
       SERIAL_PROTOCOLLN(fname);
       sdpos = 0;
+      #ifdef SDCARD_SORT_ALPHA
+        presort();
+      #endif
     }
     else
     {
@@ -577,7 +581,7 @@ void CardReader::chdir(const char * relpath)
 {
   SdFile newfile;
   SdFile *parent=&root;
-  
+
   if(workDir.isOpen())
     parent=&workDir;
   
@@ -595,21 +599,156 @@ void CardReader::chdir(const char * relpath)
       workDirParents[0]=*parent;
     }
     workDir=newfile;
+    #ifdef SDCARD_SORT_ALPHA
+      presort();
+    #endif
   }
 }
 
 void CardReader::updir()
 {
-  if(workDirDepth > 0)
+  if (workDirDepth > 0)
   {
     --workDirDepth;
     workDir = workDirParents[0];
-    int d;
     for (int d = 0; d < workDirDepth; d++)
       workDirParents[d] = workDirParents[d+1];
+    #ifdef SDCARD_SORT_ALPHA
+      presort();
+    #endif
   }
 }
 
+#ifdef SDCARD_SORT_ALPHA
+
+/**
+ * Get the name of a file in the current directory by sort-index
+ */
+void CardReader::getfilename_sorted(const uint8_t nr) {
+  #if SORT_USES_MORE_RAM
+    getfilename(nr < sort_count ? sort_order[nr] : nr);
+  #else
+    getfilename(nr < SORT_LIMIT ? sort_order[nr] : nr);
+  #endif
+}
+
+/**
+ * Read all the files and produce a sort key
+ *
+ * We can do this in 3 ways...
+ *  - Minimal RAM: Read two filenames at a time sorting along...
+ *  - Some RAM: Buffer the directory and return filenames from RAM
+ *  - Some RAM: Buffer the directory just for this sort
+ */
+void CardReader::presort()
+{
+  #if SORT_USES_MORE_RAM
+    flush_presort();
+  #endif
+
+  uint16_t fileCnt = getnrfilenames();
+  if (fileCnt > 0) {
+
+    if (fileCnt > SORT_LIMIT) fileCnt = SORT_LIMIT;
+
+    #if SORT_USES_MORE_RAM
+      sortnames = malloc(fileCnt * sizeof(char*));
+      sort_count = fileCnt;
+    #elif SORT_USES_RAM
+      char *sortnames[fileCnt];
+      #if FOLDER_SORTING != 0
+        uint8_t isdir[fileCnt];
+      #endif
+    #else
+      char sortname[LONG_FILENAME_LENGTH+1];
+    #endif
+
+    if (fileCnt > 1) {
+
+      // Init sort order [and get filenames]
+      for (int i=0; i<fileCnt; i++) {
+        int byte=i/8, bit=1<<(i%8);
+        sort_order[i] = i;
+        #if SORT_USES_RAM
+          getfilename(i);
+          char *name = diveFilename[0] ? diveFilename : filename;
+          // SERIAL_ECHOPGM("--- ");
+          // SERIAL_ECHOLN(name);
+          sortnames[i] = (char*)malloc(strlen(name) + 1);
+          strcpy(sortnames[i], name);
+          #if FOLDER_SORTING != 0
+            isdir[i] = filenameIsDir;
+          #endif
+        #endif
+      }
+
+      // Bubble Sort
+      for (uint8_t i=fileCnt; --i;) {
+        bool cmp, didSwap = false;
+        for (uint8_t j=0; j<i; ++j) {
+          int s1 = j, s2 = j+1, o1 = sort_order[s1], o2 = sort_order[s2];
+          #if SORT_USES_RAM
+            #if FOLDER_SORTING != 0
+              cmp = (isdir[o1] == isdir[o2]) ? (strcasecmp(sortnames[o1], sortnames[o2]) > 0) : isdir[FOLDER_SORTING > 0 ? o1 : o2];
+            #else
+              cmp = strcasecmp(sortnames[o1], sortnames[o2]) > 0);
+            #endif
+          #else
+            getfilename(o1);
+            #if FOLDER_SORTING != 0
+              bool dir1 = filenameIsDir;
+            #endif
+            char *name = diveFilename[0] ? diveFilename : filename;
+            strcpy(sortname, name);
+            getfilename(o2);
+            name = diveFilename[0] ? diveFilename : filename;
+            #if FOLDER_SORTING != 0
+              cmp = (dir1 == filenameIsDir) ? (strcasecmp(sortname, name) > 0) : (FOLDER_SORTING > 0 ? dir1 : !dir1);
+            #else
+              cmp = strcasecmp(sortname, name) > 0);
+            #endif
+          #endif
+          if (cmp) {
+            // SERIAL_ECHOPGM("Swap ");
+            // SERIAL_ECHOLN(sortnames[o1]);
+            // SERIAL_ECHOPGM(" for ");
+            // SERIAL_ECHOLN(sortnames[o2]);
+            sort_order[s1] = o2;
+            sort_order[s2] = o1;
+            didSwap = true;
+          }
+        }
+        if (!didSwap) break;
+      }
+
+      #if SORT_USES_RAM && !SORT_USES_MORE_RAM
+        for (int i=0; i < fileCnt; ++i) free(sortnames[i]);
+      #endif
+    }
+    else {
+      sort_order[0] = 0;
+    }
+
+  }
+}
+
+void CardReader::flush_presort() {
+  #if SORT_USES_MORE_RAM
+    if (sort_count > 0) {
+      for (int i=0; i < sort_count; ++i) {
+        free(sortnames[i]);
+        sort_order[i] = i;
+      }
+      free(sortnames);
+      sortnames = NULL;
+      sort_count = 0;
+    }
+  #else
+    for (int i=SORT_LIMIT; --i;) sort_order[i] = i;
+  #endif
+}
+
+#endif
 
 void CardReader::printingHasFinished()
 {
diff --git a/Marlin/cardreader.h b/Marlin/cardreader.h
index 78f7148b1f..1d8d1b1fb6 100644
--- a/Marlin/cardreader.h
+++ b/Marlin/cardreader.h
@@ -3,7 +3,11 @@
 
 #ifdef SDSUPPORT
 
-#define MAX_DIR_DEPTH 10
+#define MAX_DIR_DEPTH 10          // Maximum folder depth
+#define SORT_USES_RAM false       // Buffer while sorting, else re-read from SD
+#define SORT_USES_MORE_RAM false  // Always keep the directory in RAM
+#define SORT_LIMIT 256            // Maximum number of sorted items
+#define FOLDER_SORTING -1         // -1=above  0=none  1=below
 
 #include "SdFile.h"
 enum LsAction {LS_SerialPrint,LS_Count,LS_GetFilename};
@@ -39,6 +43,12 @@ public:
   void updir();
   void setroot();
 
+#ifdef SDCARD_SORT_ALPHA
+  void presort();
+  void flush_presort();
+  void getfilename_sorted(const uint8_t nr);
+#endif
+
 
   FORCE_INLINE bool isFileOpen() { return file.isOpen(); }
   FORCE_INLINE bool eof() { return sdpos>=filesize ;};
@@ -51,19 +61,27 @@ public:
   bool saving;
   bool logging;
   bool sdprinting ;  
-  bool cardOK ;
-  char filename[13];
-  char longFilename[LONG_FILENAME_LENGTH];
+  bool cardOK;
+  char filename[FILENAME_LENGTH];
+  char diveFilename[LONG_FILENAME_LENGTH];
   bool filenameIsDir;
   int lastnr; //last number of the autostart;
 private:
   SdFile root,*curDir,workDir,workDirParents[MAX_DIR_DEPTH];
   uint16_t workDirDepth;
+#ifdef SDCARD_SORT_ALPHA
+  #if SORT_USES_MORE_RAM
+    uint16_t sort_count;
+    char **sortnames;
+  #else
+    uint8_t sort_order[SORT_LIMIT];
+  #endif
+#endif
   Sd2Card card;
   SdVolume volume;
   SdFile file;
   #define SD_PROCEDURE_DEPTH 1
-  #define MAXPATHNAMELENGTH (13*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1)
+  #define MAXPATHNAMELENGTH (FILENAME_LENGTH*MAX_DIR_DEPTH+MAX_DIR_DEPTH+1)
   uint8_t file_subcall_ctr;
   uint32_t filespos[SD_PROCEDURE_DEPTH];
   char filenames[SD_PROCEDURE_DEPTH][MAXPATHNAMELENGTH];
diff --git a/Marlin/ultralcd.cpp b/Marlin/ultralcd.cpp
index 734c859d02..89cec4c48f 100644
--- a/Marlin/ultralcd.cpp
+++ b/Marlin/ultralcd.cpp
@@ -972,9 +972,9 @@ void lcd_sdcard_menu()
     card.getWorkDirName();
     if(card.filename[0]=='/')
     {
-#if SDCARDDETECT == -1
+      #if SDCARDDETECT == -1
         MENU_ITEM(function, LCD_STR_REFRESH MSG_REFRESH, lcd_sd_refresh);
-#endif
+      #endif
     }else{
         MENU_ITEM(function, LCD_STR_FOLDER "..", lcd_sd_updir);
     }
@@ -983,16 +983,23 @@ void lcd_sdcard_menu()
     {
         if (_menuItemNr == _lineNr)
         {
-            #ifndef SDCARD_RATHERRECENTFIRST
-              card.getfilename(i);
+            #if defined(SDCARD_RATHERRECENTFIRST) && !defined(SDCARD_SORT_ALPHA)
+              int nr = fileCnt-1-i;
             #else
-              card.getfilename(fileCnt-1-i);
+              int nr = i;
             #endif
-            if (card.filenameIsDir)
-            {
-                MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.longFilename);
-            }else{
-                MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.longFilename);
+
+            #ifdef SDCARD_SORT_ALPHA
+              card.getfilename_sorted(nr);
+            #else
+              card.getfilename(nr);
+            #endif
+
+            if (card.filenameIsDir) {
+              MENU_ITEM(sddirectory, MSG_CARD_MENU, card.filename, card.diveFilename);
+            }
+            else {
+              MENU_ITEM(sdfile, MSG_CARD_MENU, card.filename, card.diveFilename);
             }
         }else{
             MENU_ITEM_DUMMY();
@@ -1198,7 +1205,7 @@ void lcd_init()
   #endif // SR_LCD_2W_NL
 #endif//!NEWPANEL
 
-#if defined (SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0)
+#if defined(SDSUPPORT) && defined(SDCARDDETECT) && (SDCARDDETECT > 0)
     pinMode(SDCARDDETECT,INPUT);
     WRITE(SDCARDDETECT, HIGH);
     lcd_oldcardstatus = IS_SD_INSERTED;