I am attempting to modify the standard CardInfo tutorial to display the serial output on a 128x128 FTOLED display. I have 100% success with all the tutorial Examples for the SD and FTOLED libraries on their own, However I am getting unexpected results trying to merge the two.
For the most part it works; the serial output is displayed on the FTOLED.. untill the program gets to the stage where it should be listing the files on the SD card. At this point the program outputs to the serial port only and not the display.
As I am just learning the basics of using the SD card and the FTOLED display, I've probably missed a fundamental explanation somewhere on how this all works. I have trawled Google and the resource section for answers but have so far come up empty handed.
Hardware doesn't seem to be the issue here, Just my limited understanding of whats going on in the code.
/*
SD card test
This example shows how use the utility libraries on which the'
SD library is based in order to get info about your SD card.
Very useful for testing a card when you're not sure whether its working or not.
The circuit:
* SD card attached to SPI bus as follows:
** MOSI - pin 11 on Arduino Uno/Duemilanove/Diecimila
** MISO - pin 12 on Arduino Uno/Duemilanove/Diecimila
** CLK - pin 13 on Arduino Uno/Duemilanove/Diecimila
** CS - depends on your SD card shield or module.
Pin 4 used here for consistency with other Arduino examples
created 28 Mar 2011
by Limor Fried
modified 9 Apr 2012
by Tom Igoe
*/
// include the SD library:
#include <SD.h>
#include <SPI.h>
#include <FTOLED.h>
#include <fonts/SystemFont5x7.h>
// set up variables using the SD utility library functions:
Sd2Card card;
SdVolume volume;
SdFile root;
// change this to match your SD shield or module;
// Arduino Ethernet shield: pin 4
// Adafruit SD shields and modules: pin 10
// Sparkfun SD shield: pin 8
const int chipSelect = 4;
const byte pin_cs = 7;
const byte pin_dc = 2;
const byte pin_reset = 3;
OLED oled(pin_cs, pin_dc, pin_reset);
OLED_TextBox box(oled);
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
// while (!Serial) {
// ; // wait for serial port to connect. Needed for Leonardo only
// }
oled.begin();
oled.selectFont(SystemFont5x7);
box.setForegroundColour(GREEN);
Serial.println("\nInitializing SD card...");
box.println("\nInitializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(53, OUTPUT); // change this to 53 on a mega
// 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)) {
box.setForegroundColour(RED);
Serial.println("initialization failed. Things to check:");
box.println("initialization failed. Things to check:");
Serial.println("* is a card is inserted?");
box.println("* is a card is inserted?");
Serial.println("* Is your wiring correct?");
box.println("* Is your wiring correct?");
Serial.println("* did you change the chipSelect pin to match your shield or module?");
box.println("* did you change the chipSelect pin to match your shield or module?");
return;
} else {
Serial.println("SD Card Found!");
box.println("SD Card Found!");
}
// print the type of card
box.print("\nCard type: ");
switch(card.type()) {
case SD_CARD_TYPE_SD1:
box.println("SD1");
break;
case SD_CARD_TYPE_SD2:
box.println("SD2");
break;
case SD_CARD_TYPE_SDHC:
box.println("SDHC");
break;
default:
box.println("Unknown");
}
// Now we will try to open the 'volume'/'partition' - it should be FAT16 or FAT32
if (!volume.init(card)) {
box.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;
box.print("\nVolume type is FAT");
box.println(volume.fatType(), DEC);
box.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
box.print("Volume size (bytes): ");
box.println(volumesize);
box.print("Volume size (Kbytes): ");
volumesize /= 1024;
box.println(volumesize);
box.print("Volume size (Mbytes): ");
volumesize /= 1024;
box.println(volumesize);
box.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);
}
void loop(void) {
}
any help would be greatly appreciated.
Thanks.
Edit:
After a bit of digging, in the library, under a sub-directory marked "Beware of the Tiger", In a file called SdFile.cpp, I found the following snippit of code;
//------------------------------------------------------------------------------
/** List directory contents to Serial.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \param[in] indent Amount of space before file name. Used for recursive
* list to indicate subdirectory level.
*/
void SdFile::ls(uint8_t flags, uint8_t indent) {
dir_t* p;
rewind();
while ((p = readDirCache())) {
// done if past last used entry
if (p->name[0] == DIR_NAME_FREE) break;
// skip deleted entry and entries for . and ..
if (p->name[0] == DIR_NAME_DELETED || p->name[0] == '.') continue;
// only list subdirectories and files
if (!DIR_IS_FILE_OR_SUBDIR(p)) continue;
// print any indent spaces
for (int8_t i = 0; i < indent; i++) Serial.print(' ');
// print file name with possible blank fill
printDirName(*p, flags & (LS_DATE | LS_SIZE) ? 14 : 0);
// print modify date/time if requested
if (flags & LS_DATE) {
printFatDate(p->lastWriteDate);
Serial.print(' ');
printFatTime(p->lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(p) && (flags & LS_SIZE)) {
Serial.print(' ');
Serial.print(p->fileSize);
}
Serial.println();
// list subdirectory content if requested
if ((flags & LS_R) && DIR_IS_SUBDIR(p)) {
uint16_t index = curPosition()/32 - 1;
SdFile s;
if (s.open(this, index, O_READ)) s.ls(flags, indent + 2);
seekSet(32 * (index + 1));
}
}
}
This explains why my project goes south for the winter when It comes to displaying the directory contents on the OLED.
Perhaps it would be wise to develop a set of examples and basic tutorials with more in depth descriptions on the nature and use of the various library functions.
Now.. how to fix this?...
Edit: I've done some experimentation with trying to get this to work, and I'll have to admit the complexity of the problem is a little bit above my amateur programming skills. So far as I can tell, most Arduino libraries appear to be geared towards sending info through the serial port expressly with regard to debugging, etc.
The way I see it I have three opions;
Option A; re-write the library to include the functionality (I tried but failed miserably at this),
Option B; Track the multiple calls for various functions throughout the library in the code and transpose them in to my sketch in order to allow me to alter them to print to the OLED instead of the serial (I have begun to do this but it's going to take allot of homework as I like to know what the code I am attempting to write does).
Option C; Scrap the original idea and build a serial monitor with one of the spare "Eleven" boards I have lying around (something I am going to try anyway as it sounds like a handy tool to have).
I believe, especially with the introduction of the new Arduino's that have built-in OLED displays, that the practice of using serial output as the only supported means of debug will soon have to change.
May I make a suggestion that the SDfat libraries be upgraded to allow "easier" selection of the output method, as this will allow far more versatility, especially when the new OLED-Integrated chips arrive on the scene.