#include <SD.h>
#include <Adafruit_TFTLCD.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#if not defined USE_ADAFRUIT_SHIELD_PINOUT
#error "For use with the shield, make sure to #define USE_ADAFRUIT_SHIELD_PINOUT in the TFTLCD.h library file"
#endif
// These are the pins as connected in the shield
#define LCD_CS A3 // Chip Select goes to Analog 3
#define LCD_CD A2 // Command/Data goes to Analog 2
#define LCD_WR A1 // LCD Write goes to Analog 1
#define LCD_RD A0 // LCD Read goes to Analog 0
// The chip select pin for the SD card on the shield
#define SD_CS 5
// In the SD card, place 24 bit color BMP files (be sure they are 24-bit!)
// There are examples in the sketch folder
#define NUMBER_OF_IMAGES 5
// our TFT wiring
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, 0);
String bmpFiles[5];
int bmpWidth, bmpHeight;
uint8_t bmpDepth, bmpImageoffset;
/************* HARDWARE SPI ENABLE/DISABLE */
// we want to reuse the pins for the SD card and the TFT - to save 2 pins. this means we have to
// enable the SPI hardware interface whenever accessing the SD card and then disable it when done
int8_t saved_spimode;
void disableSPI(void) {
saved_spimode = SPCR;
SPCR = 0;
}
void enableSPI(void) {
SPCR = saved_spimode;
}
void setup(){
Serial.begin(9600);
tft.reset();
// find the TFT display
uint16_t identifier = tft.readRegister(0x0);
if (identifier == 0x9325) {
Serial.println("Found ILI9325");
}
else if (identifier == 0x9328) {
Serial.println("Found ILI9328");
}
else {
Serial.print("Unknown driver chip ");
Serial.println(identifier, HEX);
while (1);
}
tft.begin();
// the image is a landscape, so get into landscape mode
tft.setRotation(1);
Serial.print("Initializing SD card...");
if(!SD.begin(SD_CS)) {
Serial.println("failed!");
return;
}
Serial.println("SD OK!");
for(int i=0; i < 5; i++){
int idx = i+1;
char buffer [12];
sprintf(buffer, "%d_EN-US.BMP", idx);
//buffer[11] = '\0';
Serial.println(buffer);
bmpFiles = buffer;
}
drawToScreen(bmpFiles[0]);
}
void drawToScreen(String fileName){
File bmpFile;
char fName[20];
fileName.toCharArray(fName, 12);
fName[12] = '\0';
Serial.print("Opening ");
Serial.print(fName);
bmpFile = SD.open(fName);
if(bmpFile){
Serial.println("Got it!");
}
Serial.println("Opened File");
if(!bmpFile){
Serial.print("didn't find image");
Serial.println(fileName);
while(1);
}
if(!bmpReadHeader(bmpFile)){
Serial.println("bad bmp");
return;
}
disableSPI(); // release SPI so we can use those pins to draw
bmpdraw(bmpFile, 0, 0);
// disable the SD card interface after we are done!
disableSPI();
bmpFile.close();
}
void serialEvent(){
int serialAvail = Serial.available() > 0;
Serial.print("Serial available: ");
Serial.println(serialAvail);
if(serialAvail){
Serial.println("line 1");
int input = (int)Serial.read();
Serial.println("line 2");
Serial.println(input);
disableSPI();
switch(input){
case 49:
Serial.print("Got 1: ");
Serial.println(bmpFiles[0]);
drawToScreen(bmpFiles[0]);
break;
case 50:
Serial.print("Got 2: ");
Serial.println(bmpFiles[1]);
drawToScreen(bmpFiles[1]);
break;
case 51:
Serial.print("Got 3: ");
Serial.println(bmpFiles[2]);
drawToScreen(bmpFiles[2]);
break;
case 52:
Serial.print("Got 4: ");
Serial.println(bmpFiles[3]);
drawToScreen(bmpFiles[3]);
break;
case 53:
Serial.print("Got 5: ");
Serial.println(bmpFiles[4]);
drawToScreen(bmpFiles[4]);
break;
}
delay(500);
}
}
/*********************************************/
// This procedure reads a bitmap and draws it to the screen
// its sped up by reading many pixels worth of data at a time
// instead of just one pixel at a time. increading the buffer takes
// more RAM but makes the drawing a little faster. 20 pixels' worth
// is probably a good place
#define BUFFPIXEL 20
void bmpdraw(File f, int x, int y) {
Serial.println("enable SPI");
enableSPI(); // enable the hardware SPI to talk to the SD card
f.seek(bmpImageoffset);
disableSPI(); // release it so we can use those pins
uint32_t time = millis();
uint16_t p;
uint8_t g, b;
int i, j;
uint8_t sdbuffer[3 * BUFFPIXEL]; // 3 * pixels to buffer
uint8_t buffidx = 3*BUFFPIXEL;
Serial.print("rotation = ");
Serial.println(tft.getRotation(), DEC);
for (i=0; i< bmpHeight; i++) {
// bitmaps are stored with the BOTTOM line first so we have to move 'up'
if (tft.getRotation() == 3) {
tft.writeRegister16(ILI932X_ENTRY_MOD, 0x1028);
tft.goTo(x+i, y);
}
else if (tft.getRotation() == 2) {
tft.writeRegister16(ILI932X_ENTRY_MOD, 0x1020);
tft.goTo(x+bmpWidth, y+i);
}
else if (tft.getRotation() == 1) {
tft.writeRegister16(ILI932X_ENTRY_MOD, 0x1018);
tft.goTo(x+bmpHeight-1-i, y);
}
else if (tft.getRotation() == 0) {
tft.writeRegister16(ILI932X_ENTRY_MOD, 0x1030);
tft.goTo(x, y+bmpHeight-i);
}
for (j=0; j<bmpWidth; j++) {
// read more pixels
if (buffidx >= 3*BUFFPIXEL) {
enableSPI(); // enable the hardware SPI to talk to the SD card
f.read(sdbuffer, 3*BUFFPIXEL);
disableSPI(); // release it so we can use those pins
buffidx = 0;
}
// convert pixel from 888 to 565
b = sdbuffer[buffidx++]; // blue
g = sdbuffer[buffidx++]; // green
p = sdbuffer[buffidx++]; // red
p >>= 3;
p <<= 6;
g >>= 2;
p |= g;
p <<= 5;
b >>= 3;
p |= b;
// write out the 16 bits of color
tft.writeData(p);
}
}
tft.writeRegister16(ILI932X_ENTRY_MOD, 0x1030);
Serial.print(millis() - time, DEC);
Serial.println(" ms");
}
boolean bmpReadHeader(File f) {
// read header
uint32_t tmp;
Serial.println("read16 in Read Header");
uint16_t r16 = read16(f);
if (r16 != 0x4D42) {
Serial.println(r16);
// magic bytes missing
return false;
}
Serial.println("read32 in Read Header");
// read file size
tmp = read32(f);
Serial.print("size 0x");
Serial.println(tmp, HEX);
// read and ignore creator bytes
read32(f);
bmpImageoffset = read32(f);
Serial.print("offset ");
Serial.println(bmpImageoffset, DEC);
// read DIB header
tmp = read32(f);
Serial.print("header size ");
Serial.println(tmp, DEC);
bmpWidth = read32(f);
bmpHeight = read32(f);
r16 = read16(f);
if (r16 != 1){
Serial.println(r16);
return false;
}
bmpDepth = read16(f);
Serial.print("bitdepth ");
Serial.println(bmpDepth, DEC);
if (read32(f) != 0) {
// compression not supported!
return false;
}
Serial.print("compression ");
Serial.println(tmp, DEC);
return true;
}
/*********************************************/
// These read data from the SD card file and convert them to big endian
// (the data is stored in little endian format!)
// LITTLE ENDIAN!
uint16_t read16(File f) {
uint16_t d;
uint8_t b;
b = f.read();
d = f.read();
d <<= 8;
d |= b;
return d;
}
// LITTLE ENDIAN!
uint32_t read32(File f) {
uint32_t d;
uint16_t b;
b = read16(f);
d = read16(f);
d <<= 16;
d |= b;
return d;
}
void loop(){
}
Switching images with 2.8" TFTLCD
Moderators: adafruit_support_bill, adafruit
Please be positive and constructive with your questions and comments.
-
- Posts: 2
- Joined: Fri May 04, 2012 2:24 pm
Switching images with 2.8" TFTLCD
So I'm using the 2.8" TFT LCD Shield. What I'm trying to do is change which BMP is displayed on the screen based on serial input. The first image is displayed on screen fine in the setup() method, but the next time I try to draw the BMP (ie: serialEvent), it seems to hang on the SD.open(fName). Code below. Any ideas?
-
- Posts: 2
- Joined: Fri May 04, 2012 2:24 pm
Re: Switching images with 2.8" TFTLCD
got it...needed to enableSPI after the drawToScreen method, not disableSPI.
Please be positive and constructive with your questions and comments.