[Bug?] read an image from SD card and draw it on TFT

Hello Forum,

I have developed a code to read an image stored on my SD Card and display it on a TFT. I can read the image from the SD Card successfully but I cannot draw it on the TFT. I dunno where is the bug.
Could you please guys help me figure it out?

Board: Arduino DUE

#include <Arduino.h>
#include <SPI.h>
#include <SD.h>
#include <string.h>

#include "ascii_data.h"

#define SERIAL_PORT 	9600

#define PIN_SCE 		10
#define PIN_RESET 		6
#define PIN_DC 			5
// #define PIN_SDIN
// #define PIN_SCLK
#define PIN_LED 		2

#define LCD_COMMAND 	LOW
#define LCD_DATA 		HIGH
#define CHAR_WIDTH 		6
#define CHAR_HEIGHT 	8
#define LCD_WIDTH 		84
#define LCD_HEIGHT 		48
#define CHARS_PER_ROW 	(LCD_WIDTH / CHAR_WIDTH)
#define CHARS_PER_COL 	(LCD_HEIGHT / CHAR_HEIGHT)

#define PIN_SCSD 		4

void draw();
void reset();
void cls();
void lcdMode(int mode);
void lcdInitialize();
void printString(int y, const char *value);
void printString(int x, int y, const char *value);
int printChar(int x, int y, char value);
void setPixel(int x, int y, int value);
void lcdWrite(int value);

byte data[84][6] = {0};

String input = "";
bool complete = false;

// ----------------------------------------------------------------------------

void setup()
{
  // Enable I/O stream
  Serial.begin(SERIAL_PORT);
  Serial.println("Serial Init..");

  // pin modes
  pinMode(PIN_SCE, OUTPUT);
  pinMode(PIN_RESET, OUTPUT);
  pinMode(PIN_DC, OUTPUT);
  pinMode(PIN_LED, OUTPUT);
  pinMode(PIN_SCSD, OUTPUT);

  // SD stuff
  SD.begin(PIN_SCSD);

  // display stuff
  reset();

  SPI.begin(PIN_SCE);
  SPI.setClockDivider(PIN_SCE, SPI_CLOCK_DIV16);

  lcdInitialize();

  input.reserve(200);

  printChar(0, 0, 'a');
}

void loop()
{
  while (Serial.available() > 0) {
    char ch = (char)Serial.read();
    //Serial.print(ch);
    if (isprint(ch) && ch != '\n') {
      input += ch;
      //Serial.println(input);
    }
    else {
      complete = true;
    }
  }

  if (complete) {
    Serial.print("Command: ");
    Serial.println(input);

    //Serial.println(input.startsWith("exists(") && input.endsWith(")"));

    if (input.startsWith("exists(") && input.endsWith(")")) {
      String file = input.substring(7, input.length() - 1);

      Serial.print("File: ");
      Serial.println(file);

      File f = SD.open(file);
      if (f) {
        Serial.println("File does exists");
        f.close();
      } else {
        Serial.println("File does not exist");
      }

    } else if (input.startsWith("print(") && input.endsWith(".img)")) {
      String file = input.substring(6, input.length() - 1);
      File f = SD.open(file);
      if (f) {
        cls();

        Serial.print("Printing image: ");
        // Dimensionen auslesen
        int width = 0;
        int height = 0;

        char ch = '\0';
        String dim = "";

        while (f.available()) {
          ch = (char)f.read();

          if (ch != ',' && ch != '\n')
            dim += ch;
          else {
            if (width == 0) {
              width = dim.toInt();
              dim = "";
            } else if (height == 0) {
              height = dim.toInt();
            }

            if (ch == '\n') {
              break;
            }
          }
        }

        Serial.print("Dimensions of image: ");
        Serial.print(width);
        Serial.print(" x ");
        Serial.println(height);

        for (int i = 0; i < height; ++i) {
          for (int x = 0; x < width; ++x){
            char ch = '\0';
            while (ch != '\n') {
              ch = f.read();
              if (ch == ','){
                continue;
              }else (ch == '0' || ch == '1') {
                int pix = ch - '0';
                setPixel(x, i, pix);
              }
            }
          }
        }
      }

    } else if (input.startsWith("print(") && input.endsWith(")")) {
      String file = input.substring(6, input.length() - 1);
      File f = SD.open(file);
      if (f) {
        cls();

        int x = 0;
        int y = 0;
        Serial.print("Printing: ");
        while (f.available()) {
          char ch = (char)f.read();
          Serial.print(ch);
          if (-1 == printChar(x, y, ch));

          draw();

          x = (x + 6) % 84;
          if (x == 0) {
            y = (y + 8) % 48;
          }
        }
        Serial.println();



      } else {
        Serial.println("Error: File does not exist");
      }


    } else {
      Serial.println("Unknown command");
    }

    complete = false;
    input = "";
  }

  draw();

  delay(10);

}

// ----------------------------------------------------------------------------

void draw()
{
  lcdMode(LCD_DATA);

  for (int b = 0; b < 6; ++b) {
    for (int x = 0; x < 84; ++x) {
      lcdWrite(data[x][b]);
    }
  }
}

void reset()
{
  digitalWrite(PIN_RESET, LOW);
  delay(500);
  digitalWrite(PIN_RESET, HIGH);
}

void cls()
{
  for (int x = 0; x < LCD_WIDTH; ++x) {
    for (int y = 0; y < LCD_HEIGHT; ++y) {
      setPixel(x, y, 0);
    }
  }
}

void lcdMode(int mode)
{
  digitalWrite(PIN_DC, mode);
}

void lcdInitialize()
{
  lcdMode(LCD_COMMAND);

  // FUNCTION SET (extended instruction set)
  lcdWrite(0x21);

  // SET BIAS
  lcdWrite(0x14);

  // SET TEMP COEFFICIENT
  lcdWrite(0x04);

  // SET CONTRAST
  lcdWrite(0xBF);

  // FUNCTION SET (normal instruction set)
  lcdWrite(0x20);

  // SET DISPLAY MODE (normal)
  lcdWrite(0x0C);

  // reset display
  lcdWrite(0x40);
  lcdWrite(0x80);
}

void printString(int y, const char *value)
{
  printString((84 - strlen(value) * 6) / 2, y, value);
}

void printString(int x, int y, const char *value)
{
  do
  {
    printChar(x, y, *value);
    x += 6;
  } while (*++value != '\0');
}

int printChar(int x, int y, char value)
{
  lcdMode(LCD_DATA);

  if (value < ' ') {
    return -1;
  }

  for (int dx = 0; dx < 6; ++dx) {
    for (int dy = 0; dy < 8; ++dy) {
      setPixel(x + dx, y + dy, !!(font[value - ' '][dx] & (1 << dy)));
    }
  }

  return 0;
}

void setPixel(int x, int y, int value)
{
  if (x >= 0 && x < 84 && y >= 0 && y < 48) {
    if (value) {
      data[x][y / 8] |= (1 << (y % 8));
    } else {
      data[x][y / 8] &= ~(1 << (y % 8));
    }
  }
}

void lcdWrite(int value)
{
  digitalWrite(PIN_SCE, LOW);
  SPI.transfer(PIN_SCE, value, SPI_CONTINUE);
  digitalWrite(PIN_SCE, HIGH);
}

Image_from_SD.zip (3.17 KB)

NSmit:
Hello Forum,

I have developed a code to read an image stored on my SD Card and display it on a TFT. I can read the image from the SD Card successfully but I cannot draw it on the TFT. I dunno where is the bug.
Could you please guys help me figure it out?

Board: Arduino DUE

#include <Arduino.h>

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

#include "ascii_data.h"

#define SERIAL_PORT 9600

#define PIN_SCE 10
#define PIN_RESET 6
#define PIN_DC 5
// #define PIN_SDIN
// #define PIN_SCLK
#define PIN_LED 2

#define LCD_COMMAND LOW
#define LCD_DATA HIGH
#define CHAR_WIDTH 6
#define CHAR_HEIGHT 8
#define LCD_WIDTH 84
#define LCD_HEIGHT 48
#define CHARS_PER_ROW (LCD_WIDTH / CHAR_WIDTH)
#define CHARS_PER_COL (LCD_HEIGHT / CHAR_HEIGHT)

#define PIN_SCSD 4

void draw();
void reset();
void cls();
void lcdMode(int mode);
void lcdInitialize();
void printString(int y, const char *value);
void printString(int x, int y, const char *value);
int printChar(int x, int y, char value);
void setPixel(int x, int y, int value);
void lcdWrite(int value);

byte data[84][6] = {0};

String input = "";
bool complete = false;

// ----------------------------------------------------------------------------

void setup()
{
 // Enable I/O stream
 Serial.begin(SERIAL_PORT);
 Serial.println("Serial Init..");

// pin modes
 pinMode(PIN_SCE, OUTPUT);
 pinMode(PIN_RESET, OUTPUT);
 pinMode(PIN_DC, OUTPUT);
 pinMode(PIN_LED, OUTPUT);
 pinMode(PIN_SCSD, OUTPUT);

// SD stuff
 SD.begin(PIN_SCSD);

// display stuff
 reset();

SPI.begin(PIN_SCE);
 SPI.setClockDivider(PIN_SCE, SPI_CLOCK_DIV16);

lcdInitialize();

input.reserve(200);

printChar(0, 0, 'a');
}

void loop()
{
 while (Serial.available() > 0) {
   char ch = (char)Serial.read();
   //Serial.print(ch);
   if (isprint(ch) && ch != '\n') {
     input += ch;
     //Serial.println(input);
   }
   else {
     complete = true;
   }
 }

if (complete) {
   Serial.print("Command: ");
   Serial.println(input);

//Serial.println(input.startsWith("exists(") && input.endsWith(")"));

if (input.startsWith("exists(") && input.endsWith(")")) {
     String file = input.substring(7, input.length() - 1);

Serial.print("File: ");
     Serial.println(file);

File f = SD.open(file);
     if (f) {
       Serial.println("File does exists");
       f.close();
     } else {
       Serial.println("File does not exist");
     }

} else if (input.startsWith("print(") && input.endsWith(".img)")) {
     String file = input.substring(6, input.length() - 1);
     File f = SD.open(file);
     if (f) {
       cls();

Serial.print("Printing image: ");
       // Dimensionen auslesen
       int width = 0;
       int height = 0;

char ch = '\0';
       String dim = "";

while (f.available()) {
         ch = (char)f.read();

if (ch != ',' && ch != '\n')
           dim += ch;
         else {
           if (width == 0) {
             width = dim.toInt();
             dim = "";
           } else if (height == 0) {
             height = dim.toInt();
           }

if (ch == '\n') {
             break;
           }
         }
       }

Serial.print("Dimensions of image: ");
       Serial.print(width);
       Serial.print(" x ");
       Serial.println(height);

for (int i = 0; i < height; ++i) {
         for (int x = 0; x < width; ++x){
           char ch = '\0';
           while (ch != '\n') {
             ch = f.read();
             if (ch == ','){
               continue;
             }else (ch == '0' || ch == '1') {
               int pix = ch - '0';
               setPixel(x, i, pix);
             }
           }
         }
       }
     }

} else if (input.startsWith("print(") && input.endsWith(")")) {
     String file = input.substring(6, input.length() - 1);
     File f = SD.open(file);
     if (f) {
       cls();

int x = 0;
       int y = 0;
       Serial.print("Printing: ");
       while (f.available()) {
         char ch = (char)f.read();
         Serial.print(ch);
         if (-1 == printChar(x, y, ch));

draw();

x = (x + 6) % 84;
         if (x == 0) {
           y = (y + 8) % 48;
         }
       }
       Serial.println();

} else {
       Serial.println("Error: File does not exist");
     }

} else {
     Serial.println("Unknown command");
   }

complete = false;
   input = "";
 }

draw();

delay(10);

}

// ----------------------------------------------------------------------------

void draw()
{
 lcdMode(LCD_DATA);

for (int b = 0; b < 6; ++b) {
   for (int x = 0; x < 84; ++x) {
     lcdWrite(data[x][b]);
   }
 }
}

void reset()
{
 digitalWrite(PIN_RESET, LOW);
 delay(500);
 digitalWrite(PIN_RESET, HIGH);
}

void cls()
{
 for (int x = 0; x < LCD_WIDTH; ++x) {
   for (int y = 0; y < LCD_HEIGHT; ++y) {
     setPixel(x, y, 0);
   }
 }
}

void lcdMode(int mode)
{
 digitalWrite(PIN_DC, mode);
}

void lcdInitialize()
{
 lcdMode(LCD_COMMAND);

// FUNCTION SET (extended instruction set)
 lcdWrite(0x21);

// SET BIAS
 lcdWrite(0x14);

// SET TEMP COEFFICIENT
 lcdWrite(0x04);

// SET CONTRAST
 lcdWrite(0xBF);

// FUNCTION SET (normal instruction set)
 lcdWrite(0x20);

// SET DISPLAY MODE (normal)
 lcdWrite(0x0C);

// reset display
 lcdWrite(0x40);
 lcdWrite(0x80);
}

void printString(int y, const char *value)
{
 printString((84 - strlen(value) * 6) / 2, y, value);
}

void printString(int x, int y, const char *value)
{
 do
 {
   printChar(x, y, value);
   x += 6;
 } while (
++value != '\0');
}

int printChar(int x, int y, char value)
{
 lcdMode(LCD_DATA);

if (value < ' ') {
   return -1;
 }

for (int dx = 0; dx < 6; ++dx) {
   for (int dy = 0; dy < 8; ++dy) {
     setPixel(x + dx, y + dy, !!(font[value - ' '][dx] & (1 << dy)));
   }
 }

return 0;
}

void setPixel(int x, int y, int value)
{
 if (x >= 0 && x < 84 && y >= 0 && y < 48) {
   if (value) {
     data[x][y / 8] |= (1 << (y % 8));
   } else {
     data[x][y / 8] &= ~(1 << (y % 8));
   }
 }
}

void lcdWrite(int value)
{
 digitalWrite(PIN_SCE, LOW);
 SPI.transfer(PIN_SCE, value, SPI_CONTINUE);
 digitalWrite(PIN_SCE, HIGH);
}

Read the reference manual for your LCD.

Normally, SPI connected devices are block devices. Meaning they expect a formatted block of data, not single bytes. I have no direct knowledge of your LCD, but I assume, your lcdWrite() function is totally confusing it.

Usually SPI devices are controlled in this manner:

void lcdTransaction(uint8_t command, char * inbuf, uint16_t inlen, char * outbuf){
SPI.beginTransaction(SPISettings(14000000, MSBFIRST, SPI_MODE0)); // use the correct values for your device. Claim SPI bus, configure it for this device.
digitalWrite(CSpin,LOW); // wake up SPI device, 
SPI.transfer(command); // first byte after wakeup is command
uint16_t index=0;
while(index<inlen){
  outbuf[index] = SPI.transfer(inbuf[index]); // transmit and Receive a byte, send data, accept response
  index++;
  }
digitalWrite(CSpin,HIGH); // end block transmission, allow SPI device to service requested command
SPI.endTransaction(); // release SPI bus for other device use (SdCard, etc..)
}

Normally every time you toggle the CSpin, the SPI device expects a new command sequence to start.

In my code example the SPI device expects a one byte command followed by an unknown number of data bytes.

If I tried to use your lcdWrite() function. Every byte would be interpreted as a command with Zero bytes of data?

Chuck.

This is what I get in the serial monitor:

Serial Init..
Command: print(photo.img)
Printing image: Dimensions of image: 35 x 35

but there is not any thing drawn on the TFT. I have only "a" letter. Which I used to test the screen.

NSmit:
This is what I get in the serial monitor:

Serial Init..

Command: print(photo.img)
Printing image: Dimensions of image: 35 x 35




but there is not any thing drawn on the TFT. I have only "a" letter. Which I used to test the screen.

Step back a few paces, build, test, debug routines that control your TFT. After you have the TFT functioning correctly, then integrate it with your SdCard images.

Based on your code, I do not believe you are in control of your TFT. You are just throwing bytes at the display.

I cannot offer any more help, I do not have any experience with TFT devices.

Chuck.