Sketch for displaying SD card file structure on OLED screen.

I think I got in a bit over my head but I am sure this is not uncharted territory.
I have a Teensy++ dev board, an SD card shield, and a Monochrome 128x32 OLED display from adafruit, and a 5 way tach switch.
I have all of the parts wired correctly and the SD card and Display work separately with their respective example scripts.
What I am trying to do display the files and directories from the SD card in an onscreen menu. Ideally, having the ability of highlighting a specific file for execution.

After extensive googling I have found an example of what I am trying to do but it uses a color screen and a rotary encoder…
https://github.com/watterott/S65-Shield/blob/master/src/examples/S65Shield/examples/MenuDemo/MenuDemo.pde

My C is still pretty weak so I am having a hard time getting started translating the sketch from the S65 library to the SSD1306 screen that I have.
Anyone out there already blaze this trail? Point me in an easier direction?

librariesAndJunk.zip (279 KB)

Hi Jonathan, I am in a similar situation. I have looked up your reference and copied the code into a local sketch to experiment with, thanks for that. My TFT LCD is a ST7735R and it has an SD card on the back of it. I can read the files back from the SD card and write text to the LCD screen, but I can't seem to write info I have read from the SD card to directly to the screen. I want to use the screen to select particular midi files. So this is essential for my Arduino project. However my C++ programming skills are fairly basic at the moment and I am struggling to get it to work. Here are my connections which may save others a day's work.

// LCD & SD Interface ST7735R // VCC to VCC (it has its own 3V regulator) // BKL to GND (Enables the LED Back Light) // Reset to Reset (Gives a Screen CLS) // RS to Pin9 (dc?) // MISO to Pin 12 // MOSI to pin 11 // SCLK to Pin 13 // LCD_CS to Pin 10 (cs?) // SD_CS TO Pin 4 // GND to GND

Then correct the libraries so they are consistent with the above.

I will have an experiment tomorrow with your suggested reference and report back on any progress.

Rob

Cool man. Let me know if you make an headway. I have been busy lately but will take another stab at it this weekend.

I have had a look at the code and I find it very hard to follow. They appear to be using a slightly different SD library, a different display and using a rotary encoder to do the menu selections. I guess the modern equivalent of the rotary encoder would be the touchy circle on the front of the i-pods or the rotary wheel on the MS style mice. I like that idea, but it is hard to understand, I think I need a deep course in the basics of C++ before I can untangle some/most(?) of the code.

I suspect my problem lies either in the way that particular SD card library is written, where it assumes any output will be going to the serial interface and nothing else, or that the data returned from a directory interrogation concerning any file files found in it, comes back in some array format I have no idea about. I don’t particularly want to write some convoluted bit of code to untangle bad programming that someone else has created, or because I don’t understand it, I would rather fix it properly as a lot of other ideas are going to depend on this section I would like it clean and mean code, no spaghetti code.

I would like to write a screen formatter that followed some standard, and for my size screen I reckon the old standard of Teletext would do (without the double height characters to begin with) but something like that. They still use that format with the Totaliser betting in Australia. Go into any pub with on line betting and you will screens and screens of teletext. It puts a smile on an old hands face I can tell you.

Teletext would give standardised high lighting and low-res graphics. Who knows I (er we!) could come up with the First Arduino Totaliser screen :slight_smile:

Ahem, I will go back to that program again and see what I can glean, I am getting way off track here.

Rob

Hi Jonathan,

I will list my code where I have combined the SD code with the LCD code. I will point out in it where the stumbling block is.

//High Speed Graphics Interface for LCD and SD 
//    for a Uno

// Pins SCLK and MOSI are fixed in hardware, and pin 10
// must be an output

// This works 16/03/2012
// LCD & SD Interface  ST7735R
// VCC to VCC (it has its own 3V regulator)
// BKL to GND (Enables the LED Back Light)
// Reset to Reset  (Gives a Screen CLS)
// RS to Pin9  (dc?)
// MISO to Pin 12
// MOSI to pin 11
// SCLK to Pin 13
// LCD_CS to Pin 10  (cs?)
// SD_CS TO Pin 4
// GND to GND

//Declare three strings
String stringOne, stringTwo, stringThree;  //to experiment with

#define sclk 13    // for MEGAs use pin 52
#define mosi 11    // for MEGAs use pin 51
#define cs 10   // for MEGAs you probably want this to be pin 53
#define dc 9
#define rst 8  // you can also connect this to the Arduino reset

// Color definitions
#define	BLACK           0x0000
#define	BLUE            0x001F
#define	RED             0xF800
#define	GREEN           0x07E0
#define      CYAN            0x07FF
#define      MAGENTA         0xF81F
#define      YELLOW          0xFFE0  
#define      WHITE           0xFFFF

#include <ST7735.h>
#include <SPI.h>
#include <SD.h>

//set up for fast SPI interface to LCD and SD
ST7735 tft = ST7735(cs, dc, rst);    


// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;

const int chipSelect = 4; //SD_CS   
//A pixel by pixel CLS?
void fillpixelbypixel(uint16_t color) {
  for (uint8_t x=0; x < tft.width; x++) {
    for (uint8_t y=0; y < tft.height; y++) {
      tft.drawPixel(x, y, color);
    }
  }
  delay(100);
}

void setup(void) {
  
    stringOne = String("Wardies Midi Slave");

  Serial.begin(9600);
  Serial.println("Reading from SD to LCD");
  tft.initR();               // initialize a ST7735R chip
  pinMode(10, OUTPUT);     // change this to 53 on a mega

  Serial.println("Initialising the LCD and CD Card");
  tft.writecommand(ST7735_DISPON);
 
 // we'll use the initialization code from the utility libraries
 // since we're just testing if the card is working!
  if (!card.init(SPI_HALF_SPEED, chipSelect)) {
    Serial.println("initialization failed. Things to check:");
    Serial.println("* is a card is inserted?");
    Serial.println("* Is your wiring correct?");
    Serial.println("* did you change the chipSelect pin to match your shield or module?");
    return;
  } else {
   Serial.println("Wiring is correct and a card is present."); 
  }

  // print the type of card
  Serial.print("\nCard type: ");
  switch(card.type()) {
    case SD_CARD_TYPE_SD1:
      Serial.println("SD1");
      break;
    case SD_CARD_TYPE_SD2:
      Serial.println("SD2");
      break;
    case SD_CARD_TYPE_SDHC:
      Serial.println("SDHC");
      break;
    default:
      Serial.println("Unknown");
  }

  // Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
  if (!volume.init(card)) {
    Serial.println("Could not find FAT16/FAT32 partition.\nMake sure you've formatted the card");
    return;
  }


  // print the type and size of the first FAT-type volume
  uint32_t volumesize;
  Serial.print("\nVolume type is FAT");
  Serial.println(volume.fatType(), DEC);
  Serial.println();
  
  volumesize = volume.blocksPerCluster();    // clusters are collections of blocks
  volumesize *= volume.clusterCount();       // we'll have a lot of clusters
  volumesize *= 512;                            // SD card blocks are always 512 bytes
  Serial.print("Volume size (bytes): ");
  Serial.println(volumesize);
  Serial.print("Volume size (Kbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);
  Serial.print("Volume size (Mbytes): ");
  volumesize /= 1024;
  Serial.println(volumesize);

  
  Serial.println("\nFiles found on the card (name, date and size in bytes): ");
  root.openRoot(volume);
  
  // list all files in the card with date and size
  root.ls(LS_R | LS_DATE | LS_SIZE);  //prints out a nice list of the folder contents but back to serial.etc)

//OK THIS WHERE I am stumbling.......

//Somehow put the contents of root.???? into a character array (I am guessing, desperate!)

char str4[200];
stringOne.toCharArray(str4, 199);
 

//now set up the LCD and try to list the contents of the SD card onto the LCD (not back to serial. etc)
  tft.fillScreen(BLACK);
  testdrawtext2(str4, RED,0);
  testdrawtext2("SD Contents", WHITE,9);
//list dumping code probably in here?


  
//down to here...........  :-(
  
  Serial.println("done");
  delay(1000);
}

void loop() {
  tft.writecommand(ST7735_INVON);  // inverse ON
  delay(500);
  tft.writecommand(ST7735_INVOFF);  //  inverse OFF
  delay(500);
}

void testlines(uint16_t color) {
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, 0, tft.width-1, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, 0, x, tft.height-1, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, 0, 0, y, color);
   }
   
   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(0, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(0, tft.height-1, tft.width-1, y, color);
   }

   tft.fillScreen(BLACK);
   for (uint16_t x=0; x < tft.width; x+=6) {
     tft.drawLine(tft.width-1, tft.height-1, x, 0, color);
   }
   for (uint16_t y=0; y < tft.height; y+=6) {
     tft.drawLine(tft.width-1, tft.height-1, 0, y, color);
   }
   
}

void testdrawtext1(char *text, uint16_t color) {
  tft.drawString(0, 0, text, color);
}

void testdrawtext2(char *text, uint16_t color, int myLine) {
  tft.drawString(0, myLine, text, color);
}

void testfastlines(uint16_t color1, uint16_t color2) {
   tft.fillScreen(BLACK);
   for (uint16_t y=0; y < tft.height; y+=5) {
     tft.drawHorizontalLine(0, y, tft.width, color1);
   }
   for (uint16_t x=0; x < tft.width; x+=5) {
     tft.drawVerticalLine(x, 0, tft.height, color2);
   }
}

void testdrawrects(uint16_t color) {
 tft.fillScreen(BLACK);
 for (uint16_t x=0; x < tft.width; x+=6) {
   tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color);
 }
}

void testfillrects(uint16_t color1, uint16_t color2) {
 tft.fillScreen(BLACK);
 for (uint16_t x=tft.width-1; x > 6; x-=6) {
   tft.fillRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color1);
   tft.drawRect(tft.width/2 -x/2, tft.height/2 -x/2 , x, x, color2);
 }
}

void testfillcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=radius; x < tft.width; x+=radius*2) {
    for (uint8_t y=radius; y < tft.height; y+=radius*2) {
      tft.fillCircle(x, y, radius, color);
    }
  }  
}

void testdrawcircles(uint8_t radius, uint16_t color) {
  for (uint8_t x=0; x < tft.width+radius; x+=radius*2) {
    for (uint8_t y=0; y < tft.height+radius; y+=radius*2) {
      tft.drawCircle(x, y, radius, color);
    }
  }  
}

Thanks and appreciation to the people who have obviously manufactured most of this code before me, but I think my main problem is not understanding what is going on the SD libraries???

This may help you get a lever on the problem.

Rob

I haven't had the time to work on this particular function of my project but it will become a priority soon. I will post when I have news.

No Worries my main concern at the moment is the Midi Parsing section. However to debug parts of the midi parser (and along way to go yet) I added a simple line printer.

void testdrawtext2(char* text, uint16_t color, int myLine) {
  //21 characters horizontal, and 153/9= 17, 0-17=18 lines vertical
  eraseLine(myLine);  //draw a black rectangle on the line in requested
  if (myLine < 18) { //only 0-17 lines defined
  int x_pos = myLine * 9;  //each character is 9pixels high
  text[18]=0; //make sure line does not exceed 18 Characters so no wrapping
  tft.drawString(0, x_pos, text, color);
  }
}

void eraseLine(int myLine) {
  for (uint16_t x=tft.width-1; x > 6; x-=6) {
   int yPos=myLine * 9;
   int endLine = yPos - 8;
   tft.fillRect(0,yPos,tft.width-1,9, BLACK);
 }

void CharToByte(char* chars, byte* bytes, unsigned int count){
    for(unsigned int i = 0; i < count; i++)
        bytes[i] = (byte)chars[i];
    }

void ByteToChar(byte* bytes, char* chars, unsigned int count){
   unsigned int i;  
   for(i = 0; i < count; i++){
         chars[i] = (char)bytes[i];
        }
   chars[i] =0; 
   }
}

It “plots” an indexed line of text onto the screen by first drawing a rectangle of black across that line and then writing the text over the top. Pretty simple but it works :cold_sweat:
As you can see I have also tried some byte to char conversions with no progress in cracking the display contents.
I suspect the SDFAT routines need a better data structure for returning the folder information (like an array of file names - and mybe it does that already and I can’t see it?), more generalised so the program calling it gets better info to work with.

Cheers, Rob