Im using open-smart 3.2 inch tft lcd shield with driver ic: ILI9327 on Arduino mega and nomatter what code I upload from MCUFRIEND_kbv library it shows me white screen. I want to upload image from sd card and put it as background. I used same screen and same library on UNO on my project maybe a little over a year ago and it worked fine then, now I tried to upload any code on UNO or MEGA from the library examples and all I get is white screems (I tried another screen as well and same thing happens). I even downloaded the latest librabry version 2.9.8 and still same problem. Don't know why it isn't working now when it used to work in the past. Any ideas?
Post a link to the actual item that you have bought. e.g. Ebay sale page.
I cant find link since Ive ordered them probably more than 18 months ago but the picture of the screen is in the att.
From v2.9.8 MCUFRIEND_kbv/extras/mcufriend_how_to.txt
19. OPEN-SMART Shields have different wiring to regular Uno Shields:
Edit utility/mcufriend_shield.h: #define USE_SPECIAL
Edit utility/mcufriend_special.h: #define USE_OPENSMART_SHIELD_PINOUT
Edit MCUFRIEND_kbv.cpp: #define SUPPORT_8352B
Since ILI9327 is supported by default, you don't need the last line.
Please don't post photos of the front side of a shield. You only need to show the pcb side. i.e. where it is printed ILI9327
David.
Ok so now it works Ive uploaded button simple example to both mega and uno and it works fine. Now when I try to upload showBMP_not_Uno example to mega with sd card inserted on shield that has image I want to display it says:
SdFatSoftSpi does not name a type fore the line:
SdFatSoftSpi<12, 11, 13> SD;
P.S.
Ive tried to display image on UNO using showBMP_kbv_UNO example and I get a blue screen (no image shows).
Ive out an image on SD card 400x240 dimesions in bmp format and in serial monitor I get:
Show BMP files on TFT with ID:0x9327
ki.bmp - 1146ms
ki.bmp - 1146ms
ki.bmp - 1146ms
But still no image is displayed.
The Open-Smart pcb routes SPI to the 3x2 header.
So you can use the regular hardware SD.h e.g. showBMP_kbv_UNO example
showBMP_kbv_UNO expects SD_CS on digital#10 which matches regular Mcufriend pcb and Open-Smart.
I have no idea what your ki.bmp is.
I provide some example BMP images. Since you have aMega, you can afford to enable all the Palette-style BMP images. i.e. PALETTEDEPTH=8
If you have a problem, quote example sketch and example image.
David.
KI.bmp is image I want to display. I send it to you in the att. but in the jpg format since I cant upload .bmp format here.
david_prentice:
If you have a problem, quote example sketch and example image.
You should always run examples first.
You can attach a BMP file by enclosing it in a ZIP
Please try example images. Then attach your problem BMP (in a ZIP)
Note that the JPG is 7kB and the BMP will be 288kB.
The Mega can display JPG but a Uno does not have enough SRAM for JPGs.
David.
Ok now Ive managed with your code below to load 2 bmp images to screen and iteratres through them, one is your ex<mple tiger.bmp other is my picture that I want and both are displayed normally.
My question is can I load my picture to be loaded once and displayed all the time without it constantly refreshing and use it as background so I can write some data over it (like sensor values,etc.)?
#include <SPI.h>
#include <SD.h>
#include <Adafruit_GFX.h> // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#if defined(ESP32)
#define SD_CS 5
#else
#define SD_CS 5
#endif
#define NAMEMATCH ""
#define PALETTEDEPTH 0 // do not support Palette modes
char namebuf[32] = "/"; //BMP files in root directory
File root;
int pathlen;
void setup()
{
uint16_t ID;
Serial.begin(9600);
Serial.print("Show BMP files on TFT with ID:0x");
ID = tft.readID();
Serial.println(ID, HEX);
if (ID == 0x0D3D3) ID = 0x9481;
tft.begin(ID);
tft.fillScreen(0x001F);
tft.setRotation(1);
tft.setTextColor(0xFFFF, 0x0000);
bool good = SD.begin(SD_CS);
if (!good) {
Serial.print(F("cannot start SD"));
while (1);
}
root = SD.open(namebuf);
pathlen = strlen(namebuf);
}
void loop()
{
char *nm = namebuf + pathlen;
File f = root.openNextFile();
uint8_t ret;
uint32_t start;
if (f != NULL) {
#ifdef USE_SDFAT
f.getName(nm, 32 - pathlen);
#else
strcpy(nm, (char *)f.name());
#endif
f.close();
strlwr(nm);
if (strstr(nm, ".bmp") != NULL && strstr(nm, NAMEMATCH) != NULL) {
Serial.print(namebuf);
Serial.print(F(" - "));
tft.fillScreen(0);
start = millis();
ret = showBMP(namebuf, 5, 5);
switch (ret) {
case 0:
Serial.print(millis() - start);
Serial.println(F("ms"));
delay(5000);
break;
case 1:
Serial.println(F("bad position"));
break;
case 2:
Serial.println(F("bad BMP ID"));
break;
case 3:
Serial.println(F("wrong number of planes"));
break;
case 4:
Serial.println(F("unsupported BMP format"));
break;
case 5:
Serial.println(F("unsupported palette"));
break;
default:
Serial.println(F("unknown"));
break;
}
}
}
else root.rewindDirectory();
}
#define BMPIMAGEOFFSET 54
#define BUFFPIXEL 20
uint16_t read16(File& f) {
uint16_t result; // read little-endian
f.read((uint8_t*)&result, sizeof(result));
return result;
}
uint32_t read32(File& f) {
uint32_t result;
f.read((uint8_t*)&result, sizeof(result));
return result;
}
uint8_t showBMP(char *nm, int x, int y)
{
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24, 16, 8, 4, 1)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
uint8_t bitmask, bitshift;
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
uint32_t pos; // seek position
boolean is565 = false; //
uint16_t bmpID;
uint16_t n; // blocks read
uint8_t ret;
if ((x >= tft.width()) || (y >= tft.height()))
return 1; // off screen
bmpFile = SD.open(nm); // Parse BMP header
bmpID = read16(bmpFile); // BMP signature
(void) read32(bmpFile); // Read & ignore file size
(void) read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
(void) read32(bmpFile); // Read & ignore DIB header size
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
n = read16(bmpFile); // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
pos = read32(bmpFile); // format
if (bmpID != 0x4D42) ret = 2; // bad ID
else if (n != 1) ret = 3; // too many planes
else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette
else {
bool first = true;
is565 = (pos == 3);
rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
if (bmpHeight < 0) {
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w) >= tft.width())
w = tft.width() - x;
if ((y + h) >= tft.height())
h = tft.height() - y;
if (bmpDepth <= PALETTEDEPTH) {
bmpFile.seek(BMPIMAGEOFFSET);
bitmask = 0xFF;
if (bmpDepth < 8)
bitmask >>= bmpDepth;
bitshift = 8 - bmpDepth;
n = 1 << bmpDepth;
lcdbufsiz -= n;
palette = lcdbuffer + lcdbufsiz;
for (col = 0; col < n; col++) {
pos = read32(bmpFile); //map palette to 5-6-5
palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
}
}
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
for (row = 0; row < h; row++) { // For each scanline...
uint8_t r, g, b, *sdptr;
int lcdidx, lcdleft;
if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col = 0; col < w; ) { //pixels in row
lcdleft = w - col;
if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
uint16_t color;
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
r = 0;
}
switch (bmpDepth) { // Convert pixel from BMP to TFT format
case 24:
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
color = tft.color565(r, g, b);
break;
case 16:
b = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
if (is565)
color = (r << 8) | (b);
else
color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
break;
case 1:
case 4:
case 8:
if (r == 0)
b = sdbuffer[buffidx++], r = 8;
color = palette[(b >> bitshift) & bitmask];
r -= bmpDepth;
b <<= bmpDepth;
break;
}
lcdbuffer[lcdidx] = color;
}
tft.pushColors(lcdbuffer, lcdidx, first);
first = false;
col += lcdidx;
} // end cols
} // end rows
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
ret = 0; // good render
}
bmpFile.close();
return (ret);
}
Replace your setup() with:
void setup()
{
uint16_t ID;
ID = tft.readID();
Serial.print(F("ID = 0x"));
Serial.println(ID, HEX);
tft.begin(ID);
tft.fillScreen(0x001F);
tft.setRotation(1);
tft.setTextColor(0xFFFF, 0x0000);
bool good = SD.begin(SD_CS);
if (!good) {
Serial.println(F("cannot start SD"));
while (1);
}
uint8_t ret = showBMP("/k1.bmp", 0, 0);
Serial.print(F("/k1.bmp returns:"));
Serial.println(ret);
}
Put your own code in loop()
David.
So this is the code I put in with loop being empty I just wanted to test if image will appear. I get blue screen and in serial monitor it says:
-> ID = 0x9327
-> /kristalna.bmp returns:2
#include <SPI.h> // f.k. for Arduino-1.5.2
//#define USE_SDFAT
#include <SD.h> // Use the official SD library on hardware pins
#include <Adafruit_GFX.h> // Hardware-specific library
#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;
#if defined(ESP32)
#define SD_CS 5
#else
#define SD_CS 5
#endif
#define NAMEMATCH "" // "" matches any name
#define PALETTEDEPTH 0 // do not support Palette modes
char namebuf[32] = "/"; //BMP files in root directory
File root;
int pathlen;
void setup()
{ Serial.begin(9600);
uint16_t ID;
ID = tft.readID();
Serial.print(F("ID = 0x"));
Serial.println(ID, HEX);
tft.begin(ID);
tft.fillScreen(0x001F);
tft.setRotation(1);
tft.setTextColor(0xFFFF, 0x0000);
bool good = SD.begin(SD_CS);
if (!good) {
Serial.println(F("cannot start SD"));
while (1);
}
uint8_t ret = showBMP("/kristalna.bmp", 0, 0); //name of my file
Serial.print(F("/kristalna.bmp returns:"));
Serial.println(ret);
}
void loop() {
}
#define BMPIMAGEOFFSET 54
#define BUFFPIXEL 20
uint16_t read16(File& f) {
uint16_t result; // read little-endian
f.read((uint8_t*)&result, sizeof(result));
return result;
}
uint32_t read32(File& f) {
uint32_t result;
f.read((uint8_t*)&result, sizeof(result));
return result;
}
uint8_t showBMP(char *nm, int x, int y)
{
File bmpFile;
int bmpWidth, bmpHeight; // W+H in pixels
uint8_t bmpDepth; // Bit depth (currently must be 24, 16, 8, 4, 1)
uint32_t bmpImageoffset; // Start of image data in file
uint32_t rowSize; // Not always = bmpWidth; may have padding
uint8_t sdbuffer[3 * BUFFPIXEL]; // pixel in buffer (R+G+B per pixel)
uint16_t lcdbuffer[(1 << PALETTEDEPTH) + BUFFPIXEL], *palette = NULL;
uint8_t bitmask, bitshift;
boolean flip = true; // BMP is stored bottom-to-top
int w, h, row, col, lcdbufsiz = (1 << PALETTEDEPTH) + BUFFPIXEL, buffidx;
uint32_t pos; // seek position
boolean is565 = false; //
uint16_t bmpID;
uint16_t n; // blocks read
uint8_t ret;
if ((x >= tft.width()) || (y >= tft.height()))
return 1; // off screen
bmpFile = SD.open(nm); // Parse BMP header
bmpID = read16(bmpFile); // BMP signature
(void) read32(bmpFile); // Read & ignore file size
(void) read32(bmpFile); // Read & ignore creator bytes
bmpImageoffset = read32(bmpFile); // Start of image data
(void) read32(bmpFile); // Read & ignore DIB header size
bmpWidth = read32(bmpFile);
bmpHeight = read32(bmpFile);
n = read16(bmpFile); // # planes -- must be '1'
bmpDepth = read16(bmpFile); // bits per pixel
pos = read32(bmpFile); // format
if (bmpID != 0x4D42) ret = 2; // bad ID
else if (n != 1) ret = 3; // too many planes
else if (pos != 0 && pos != 3) ret = 4; // format: 0 = uncompressed, 3 = 565
else if (bmpDepth < 16 && bmpDepth > PALETTEDEPTH) ret = 5; // palette
else {
bool first = true;
is565 = (pos == 3); // ?already in 16-bit format
// BMP rows are padded (if needed) to 4-byte boundary
rowSize = (bmpWidth * bmpDepth / 8 + 3) & ~3;
if (bmpHeight < 0) { // If negative, image is in top-down order.
bmpHeight = -bmpHeight;
flip = false;
}
w = bmpWidth;
h = bmpHeight;
if ((x + w) >= tft.width()) // Crop area to be loaded
w = tft.width() - x;
if ((y + h) >= tft.height()) //
h = tft.height() - y;
if (bmpDepth <= PALETTEDEPTH) { // these modes have separate palette
bmpFile.seek(BMPIMAGEOFFSET); //palette is always @ 54
bitmask = 0xFF;
if (bmpDepth < 8)
bitmask >>= bmpDepth;
bitshift = 8 - bmpDepth;
n = 1 << bmpDepth;
lcdbufsiz -= n;
palette = lcdbuffer + lcdbufsiz;
for (col = 0; col < n; col++) {
pos = read32(bmpFile); //map palette to 5-6-5
palette[col] = ((pos & 0x0000F8) >> 3) | ((pos & 0x00FC00) >> 5) | ((pos & 0xF80000) >> 8);
}
}
// Set TFT address window to clipped image bounds
tft.setAddrWindow(x, y, x + w - 1, y + h - 1);
for (row = 0; row < h; row++) { // For each scanline...
uint8_t r, g, b, *sdptr;
int lcdidx, lcdleft;
if (flip) // Bitmap is stored bottom-to-top order (normal BMP)
pos = bmpImageoffset + (bmpHeight - 1 - row) * rowSize;
else // Bitmap is stored top-to-bottom
pos = bmpImageoffset + row * rowSize;
if (bmpFile.position() != pos) { // Need seek?
bmpFile.seek(pos);
buffidx = sizeof(sdbuffer); // Force buffer reload
}
for (col = 0; col < w; ) { //pixels in row
lcdleft = w - col;
if (lcdleft > lcdbufsiz) lcdleft = lcdbufsiz;
for (lcdidx = 0; lcdidx < lcdleft; lcdidx++) { // buffer at a time
uint16_t color;
// Time to read more pixel data?
if (buffidx >= sizeof(sdbuffer)) { // Indeed
bmpFile.read(sdbuffer, sizeof(sdbuffer));
buffidx = 0; // Set index to beginning
r = 0;
}
switch (bmpDepth) { // Convert pixel from BMP to TFT format
case 24:
b = sdbuffer[buffidx++];
g = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
color = tft.color565(r, g, b);
break;
case 16:
b = sdbuffer[buffidx++];
r = sdbuffer[buffidx++];
if (is565)
color = (r << 8) | (b);
else
color = (r << 9) | ((b & 0xE0) << 1) | (b & 0x1F);
break;
case 1:
case 4:
case 8:
if (r == 0)
b = sdbuffer[buffidx++], r = 8;
color = palette[(b >> bitshift) & bitmask];
r -= bmpDepth;
b <<= bmpDepth;
break;
}
lcdbuffer[lcdidx] = color;
}
tft.pushColors(lcdbuffer, lcdidx, first);
first = false;
col += lcdidx;
} // end cols
} // end rows
tft.setAddrWindow(0, 0, tft.width() - 1, tft.height() - 1); //restore full screen
ret = 0; // good render
}
bmpFile.close();
return (ret);
}
-> /kristalna.bmp returns:2 means "bad BMP ID"
What did the example sketch report ?
It reported:
Show BMP files on TFT with ID:0x9327
/krista~1.bmp - 4049ms
/krista~1.bmp - 4049ms
/krista~1.bmp - 4050ms
/krista~1.bmp - 4050ms
but image name is still kristalna.bmp on sd card.
So now I changed the code part to /krista~1.bmp and it works now.
Next Im gonan try and write sensor values to the screen over the image and see what happens.