ST7796S with ArduinoMega does not show pictures correctly

Hi everyone,

I need your help. I'm trying to make a puzzle game which shows a 44 picture with 1 empty field. If you click on a neighboring tile, it will slide it to the empty space. Right now, I'm just using the tutorial field, trying to display a 320320 picture. It works, but a little part of the picture is shifted. Anyone knows why that could be?

Also, instead of painting the whole picture in one piece, I would like to make it in 16 parts(4*4), can anyone tell me a good way how to cut up the picture without putting up 16 pictures?

Thanks in advance!

// IMPORTANT: LCDWIKI_KBV LIBRARY MUST BE SPECIFICALLY
// CONFIGURED FOR EITHER THE TFT SHIELD OR THE BREAKOUT BOARD.

//This program is a demo of how to show a bmp picture from SD card.

//Set the pins to the correct ones for your development shield or breakout board.
//the 16bit mode only use in Mega.you must modify the mode in the file of lcd_mode.h
//when using the BREAKOUT BOARD only and using these 16 data lines to the LCD,
//pin usage as follow:
//             CS  CD  WR  RD  RST  D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  D10  D11  D12  D13  D14  D15 
//Arduino Mega 40  38  39  43  41   37  36  35  34  33  32  31  30  22  23  24   25   26   27   28   29
//             TP_IRQ  MOSI  MISO  TP_CS  EX_CLK
//Arduino Mega   44    51     50    53      52

//when using the BREAKOUT BOARD only and using these 8 data lines to the LCD,
//pin usage as follow:
//             CS  CD  WR  RD  RST  D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  D10  D11  D12  D13  D14  D15 
//Arduino Mega 40  38  39  43  41   37  36  35  34  33  32  31  30  /   /    /    /    /    /    /    /
//             TP_IRQ  MOSI  MISO  TP_CS  EX_CLK
//Arduino Mega   44    51     50    53      52

//Remember to set the pins to suit your display module!

/**********************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, QD electronic SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE 
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
**********************************************************************************/

#include <SD.h>
#include <SPI.h>
#include <LCDWIKI_GUI.h> //Core graphics library
#include <LCDWIKI_KBV.h> //Hardware-specific library

//the definiens of 8bit mode as follow:
//if the IC model is known or the modules is unreadable,you can use this constructed function
LCDWIKI_KBV my_lcd(ILI9488,40,38,39,43,41); //model,cs,cd,wr,rd,reset

//if the IC model is not known and the modules is readable,you can use this constructed function
//LCDWIKI_KBV my_lcd(320,480,40,38,39,43,41);//width,height,cs,cd,wr,rd,reset

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

#define PIXEL_NUMBER  320//(my_lcd.Get_Display_Width())
#define FILE_NUMBER 4
#define FILE_NAME_SIZE_MAX 20

uint32_t bmp_offset = 0;
uint16_t s_width = 320;//my_lcd.Get_Display_Width();  
uint16_t s_heigh = 320;//my_lcd.Get_Display_Height();
//int16_t PIXEL_NUMBER;

char file_name[FILE_NUMBER][FILE_NAME_SIZE_MAX];

uint16_t read_16(File fp)
{
    uint8_t low;
    uint16_t high;
    low = fp.read();
    high = fp.read();
    return (high<<8)|low;
}

uint32_t read_32(File fp)
{
    uint16_t low;
    uint32_t high;
    low = read_16(fp);
    high = read_16(fp);
    return (high<<8)|low;   
 }
 
bool analysis_bpm_header(File fp)
{
    if(read_16(fp) != 0x4D42)
    {
      return false;  
    }
    //get bpm size
    read_32(fp);
    //get creator information
    read_32(fp);
    //get offset information
    bmp_offset = read_32(fp);
    //get DIB infomation
    read_32(fp);
    //get width and heigh information
    uint32_t bpm_width = read_32(fp);
    uint32_t bpm_heigh = read_32(fp);
    if((bpm_width != s_width) || (bpm_heigh != s_heigh))
    {
      return false; 
    }
    if(read_16(fp) != 1)
    {
        return false;
    }
    read_16(fp);
    if(read_32(fp) != 0)
    {
      return false; 
     }
     return true;
}

void draw_bmp_picture(File fp)
{
  uint16_t i,j,k,l,m=0;
  uint8_t bpm_data[PIXEL_NUMBER*3] = {0};
  uint16_t bpm_color[PIXEL_NUMBER];
  fp.seek(bmp_offset);
  for(i = 0;i < s_heigh;i++)
  {
    for(j = 0;j<s_width/PIXEL_NUMBER;j++)
    {
      m = 0;
      fp.read(bpm_data,PIXEL_NUMBER*3);
      for(k = 0;k<PIXEL_NUMBER;k++)
      {
        bpm_color[k]= my_lcd.Color_To_565(bpm_data[m+2], bpm_data[m+1], bpm_data[m+0]);
        m +=3;
      }
      for(l = 0;l<PIXEL_NUMBER;l++)
      {
        my_lcd.Set_Draw_color(bpm_color[l]);
        my_lcd.Draw_Pixel(j*PIXEL_NUMBER+l,i);
      }    
     }
   }    
}

void setup() 
{
    Serial.begin(9600);
   my_lcd.Init_LCD();
   my_lcd.Fill_Screen(BLUE);
   //s_width = my_lcd.Get_Display_Width();  
   //s_heigh = my_lcd.Get_Display_Height();
   //PIXEL_NUMBER = my_lcd.Get_Display_Width()/4;
   if(PIXEL_NUMBER == 60)
   {
       strcpy(file_name[0],"flower.bmp");
       strcpy(file_name[1],"tiger.bmp");
       strcpy(file_name[2],"tree.bmp");
       strcpy(file_name[3],"RedRose.bmp");
   }
   else
   {
       strcpy(file_name[0],"01.bmp");
       strcpy(file_name[1],"02.bmp");
       strcpy(file_name[2],"03.bmp");
       strcpy(file_name[3],"04.bmp");
   }
  //Init SD_Card
   pinMode(48, OUTPUT);
   
    if (!SD.begin(48)) 
    {
      my_lcd.Set_Text_Back_colour(BLUE);
      my_lcd.Set_Text_colour(WHITE);    
      my_lcd.Set_Text_Size(1);
      my_lcd.Print_String("SD Card Init fail!",0,0);
    }
}

void loop() 
{
    int i = 0;
    File bmp_file;
    for(i = 0;i<FILE_NUMBER;i++)
    {
       bmp_file = SD.open(file_name[i]);
       if(!bmp_file)
       {
            my_lcd.Set_Text_Back_colour(BLUE);
            my_lcd.Set_Text_colour(WHITE);    
            my_lcd.Set_Text_Size(1);
            my_lcd.Print_String("didnt find BMPimage!",0,10);
            while(1);
        }
//        if(!analysis_bpm_header(bmp_file))
//        {  
//            my_lcd.Set_Text_Back_colour(BLUE);
//            my_lcd.Set_Text_colour(WHITE);    
//            my_lcd.Set_Text_Size(1);
//            my_lcd.Print_String("bad bmp picture!",0,0);
//            return;
//        }
          draw_bmp_picture(bmp_file);
         bmp_file.close(); 
         delay(2000);
     }
}

First off. Your life will be painful with the BADLY_SPELLED library.

I suggest that you use an Adafruit_GFX style library like the rest of the civilised world.

Yes, you can display the .BMP format bitmap in 4 tiles if you really want. (or any sub-section of the picture)
You will just have to seek to the correct place in the file. Then read pixel data for one (short) row.

David.

p.s. your picture shows a very strange looking lady. Or is that what game ladies are supposed to look like ?

david_prentice:
First off. Your life will be painful with the BADLY_SPELLED library.

I don't understand. Does this library have a bad reputation or what?

david_prentice:
I suggest that you use an Adafruit_GFX style library like the rest of the civilised world.

Yes, you can display the .BMP format bitmap in 4 tiles if you really want. (or any sub-section of the picture)
You will just have to seek to the correct place in the file. Then read pixel data for one (short) row.

David.

Ok, I'll search after this a bit. Can you suggest some functions, which I should use?
I've tried drawing from an array, and it wasn't successful. Can you suggest a conversion program, if it's needed?
Thanks in advance!

david_prentice:
p.s. your picture shows a very strange looking lady. Or is that what game ladies are supposed to look like ?

It's a cyberpunk themed picture, not sure if it's from the actual game, or just an art.

Look at this way.

If someone asked you to drive a car with pedals in the wrong place, a steering wheel that you turn to the left when you go right, ...
Would you be comfortable ?

Yes, this special car will "work". Just not like normal cars.

Have you seen the videos of riding a bicycle with "wrong" handlebars?

Of course this might be important for cyberpunk.
But most people would be happier with conventional car, bike, library, ...

Regarding accessing a small "subwindow" in a large bitmap. You just calculate the position and seek to the specific place in the bitmap where your row starts.

It is exactly the same arrangement as the compiler does when accessing a multi-dimensional array.

David.

Ok, i tried to follow the instructions, this is the code i came up with:

#include <Adafruit_ST7796S_kbv.h>
#include <Adafruit_GFX.h>         // Core graphics library
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
#include <Adafruit_ImageReader.h> // Image-reading functions

  SdFat                SD;         // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys



#define SD_CS   4 // SD card select pin
#define TFT_CS 10 // TFT select pin
#define TFT_DC  9 // TFT display/command pin
#define TFT_RST 8 // RST can be set to -1 if you tie it to Arduino's reset

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, TFT_RST);

  
void setup() {
//Init SD_Card
   pinMode(48, OUTPUT);

}

void loop() {
  // put your main code here, to run repeatedly:
ImageReturnCode stat;
Adafruit_Image img;
stat = reader.loadBMP("/01.bmp", img);
img.draw(tft, 0, 0);
//stat = reader.drawBMP("/01.bmp", tft, 0, 0);

}

Does not work, no picture is shown, I guess I missed something. Any idea what it could be? If there is any good docu for adafruit screens please send me a link, I didn't find much.

MCUFRIEND_kbv can be installed via the IDE Library Manager
MCUFRIEND_kbv is designed for Parallel Uno Shields.
MCUFRIEND_kbv only supports Parallel Mega Shields as a SPECIAL

Adafruit_ST7796S_kbv is for Red SPI Displays (and is not available from the Library Manager)
It is not an Adafruit library. It just inherits a lot of Adafruit classes.

Please post a link to the actual Display that you have bought. e.g. Ebay Sale Page.
Then we can show you which libraries and which examples to use.

David.

This is the one:
https://it.aliexpress.com/item/4000126450233.html?spm=a2g0s.9042311.0.0.e7a84c4dkQcVS3&fbclid=IwAR3k4SSpKyfjOo-kX3JJP1GBOtLhPVCJv3x4A7n18A7ILAwNY1eTXzIGk24

I'm using it with a Mega2560.

From mcufriend_how_to.txt

17. If you do not have a standard Uno Shield, you can add a SPECIAL to the mcufriend_special.h

Edit mcufriend_shield.h:  #define USE_SPECIAL
   Edit mcufriend_special.h: e.g. #define USE_MEGA_16BIT_SHIELD
   If your "special" is write-only,  the library can not read the ID.  It always returns 0xD3D3

Your Shield has R4 jumper: 8-bit: USE_MEGA_8BIT_PORTC_SHIELD
Your Shield is write-only. Force the ID: [b]tft.begin(0x7796)[/b]

If you configure R5 jumper: 16-bit: USE_MEGA_16BIT_SHIELD

Older Surenoo Shields have no R4/R5 jumpers: always 8-bit: USE_MEGA_8BIT_SHIELD

David.

I've tried all the shields, still no picture.

//#include <FreeDefaultFonts.h>
//#include <FreeSevenSegNumFontPlusPlus.h>
//#include <TFT_PRINTGLUE.h>
//#include <UTFTGLUE.h>
#include <MCUFRIEND_kbv.h>


#include <Adafruit_ST7796S_kbv.h>
#include <Adafruit_GFX.h>         // Core graphics library
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
#include <Adafruit_ImageReader.h> // Image-reading functions

  SdFat                SD;         // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys

#define USE_MEGA_8BIT_PORTC_SHIELD;

#define SD_CS   4 // SD card select pin
#define TFT_CS 10 // TFT select pin
#define TFT_DC  9 // TFT display/command pin
#define TFT_RST 8 // RST can be set to -1 if you tie it to Arduino's reset

// Use hardware SPI (on Uno, #13, #12, #11) and the above for CS/DC
Adafruit_ST7796S_kbv tft = Adafruit_ST7796S_kbv(TFT_CS, TFT_DC, TFT_RST);

  
void setup() {
//Init SD_Card
  pinMode(48, OUTPUT);
  tft.begin(0x7796);
}

void loop() {
  // put your main code here, to run repeatedly:
ImageReturnCode stat;
Adafruit_Image img;
stat = reader.loadBMP("/01.bmp", img);
img.draw(tft, 0, 0);
//stat = reader.drawBMP("/01.bmp", tft, 0, 0);

}

From your link in #6.

Your link shows an 8-bit Parallel Mega Shield. Install MCUFRIEND_kbv via IDE Library Manager.

which means that you should:

Edit mcufriend_shield.h:

#define USE_SPECIAL

Edit mcufriend_special.h: e.g.

#define USE_MEGA_8BIT_PORTC_SHIELD

If your "special" is write-only, the library can not read the ID. It always returns 0xD3D3
Edit sketch setup() e.g.

tft.begin(0x7796);

Run all the library examples. Edit sketch setup() to suit your write-only 0x7796

David.

IT'S ALIVE!!! :smiley:

I had to remove #include <Adafruit_ST7796S_kbv.h> that
init was wrong, but that and what you said solved the issue.

Thanks a lot!

I finally managed to load the bmp's and draw them out (although only top-bottom ones), but i can't seem to init the touchscreen part. I'm using the touchshield_new tutorial of MCUFRIEND_kbv but with tft.begin(0x7796); added. Screen is on, but the ouchscreen is not responding. My guess is, that this line is the culprit, but i don't know what to write it over with: const int XP=6,XM=A2,YP=A1,YM=7; //ID=0x9341
Do you have any ideas where to find these parameters?

// the regular Adafruit "TouchScreen.h" library only works on AVRs

// different mcufriend shields have Touchscreen on different pins
// and rotation.
// Run the TouchScreen_Calibr_native sketch for calibration of your shield

#include <MCUFRIEND_kbv.h>
MCUFRIEND_kbv tft;       // hard-wired for UNO shields anyway.
#include <TouchScreen.h>

char *name = "Please Calibrate.";  //edit name of shield
const int XP=6,XM=A2,YP=A1,YM=7; //ID=0x9341
const int TS_LEFT=907,TS_RT=136,TS_TOP=942,TS_BOT=139;

TouchScreen ts = TouchScreen(XP, YP, XM, YM, 300);
TSPoint tp;

#define MINPRESSURE 200
#define MAXPRESSURE 1000

int16_t BOXSIZE;
int16_t PENRADIUS = 1;
uint16_t ID, oldcolor, currentcolor;
uint8_t Orientation = 0;    //PORTRAIT

// Assign human-readable names to some common 16-bit color values:
#define BLACK   0x0000
#define BLUE    0x001F
#define RED     0xF800
#define GREEN   0x07E0
#define CYAN    0x07FF
#define MAGENTA 0xF81F
#define YELLOW  0xFFE0
#define WHITE   0xFFFF

void show_Serial(void)
{
    Serial.println(F("Most Touch Screens use pins 6, 7, A1, A2"));
    Serial.println(F("But they can be in ANY order"));
    Serial.println(F("e.g. right to left or bottom to top"));
    Serial.println(F("or wrong direction"));
    Serial.println(F("Edit name and calibration statements\n"));
    Serial.println(name);
    Serial.print(F("ID=0x"));
    Serial.println(ID, HEX);
    Serial.println("Screen is " + String(tft.width()) + "x" + String(tft.height()));
    Serial.println("Calibration is: ");
    Serial.println("LEFT = " + String(TS_LEFT) + " RT  = " + String(TS_RT));
    Serial.println("TOP  = " + String(TS_TOP)  + " BOT = " + String(TS_BOT));
    Serial.println("Wiring is always PORTRAIT");
    Serial.println("YP=" + String(YP)  + " XM=" + String(XM));
    Serial.println("YM=" + String(YM)  + " XP=" + String(XP));
}

void show_tft(void)
{
    tft.setCursor(0, 0);
    tft.setTextSize(1);
    tft.print(F("ID=0x"));
    tft.println(ID, HEX);
    tft.println("Screen is " + String(tft.width()) + "x" + String(tft.height()));
    tft.println("");
    tft.setTextSize(2);
    tft.println(name);
    tft.setTextSize(1);
    tft.println("PORTRAIT Values:");
    tft.println("LEFT = " + String(TS_LEFT) + " RT  = " + String(TS_RT));
    tft.println("TOP  = " + String(TS_TOP)  + " BOT = " + String(TS_BOT));
    tft.println("\nWiring is: ");
    tft.println("YP=" + String(YP)  + " XM=" + String(XM));
    tft.println("YM=" + String(YM)  + " XP=" + String(XP));
    tft.setTextSize(2);
    tft.setTextColor(RED);
    tft.setCursor((tft.width() - 48) / 2, (tft.height() * 2) / 4);
    tft.print("EXIT");
    tft.setTextColor(YELLOW, BLACK);
    tft.setCursor(0, (tft.height() * 6) / 8);
    tft.print("Touch screen for loc");
    while (1) {
        tp = ts.getPoint();
        pinMode(XM, OUTPUT);
        pinMode(YP, OUTPUT);
        if (tp.z < MINPRESSURE || tp.z > MAXPRESSURE) continue;
        if (tp.x > 450 && tp.x < 570  && tp.y > 450 && tp.y < 570) break;
        tft.setCursor(0, (tft.height() * 3) / 4);
        tft.print("tp.x=" + String(tp.x) + " tp.y=" + String(tp.y) + "   ");
    }
}


void setup(void)
{
    uint16_t tmp;

    tft.reset();
    ID = tft.readID();
    pinMode(48, OUTPUT);
    tft.begin(0x7796);
    Serial.begin(9600);
    show_Serial();
    tft.setRotation(Orientation);
    tft.fillScreen(BLACK);
    show_tft();

    BOXSIZE = tft.width() / 6;
    tft.fillScreen(BLACK);

    tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
    tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
    tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN);
    tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN);
    tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE);
    tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA);

    tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
    currentcolor = RED;
    delay(1000);
}

void loop()
{
    uint16_t xpos, ypos;  //screen coordinates
    tp = ts.getPoint();   //tp.x, tp.y are ADC values

    // if sharing pins, you'll need to fix the directions of the touchscreen pins
    pinMode(XM, OUTPUT);
    pinMode(YP, OUTPUT);
    // we have some minimum pressure we consider 'valid'
    // pressure of 0 means no pressing!

    if (tp.z > MINPRESSURE && tp.z < MAXPRESSURE) {
        // most mcufriend have touch (with icons) that extends below the TFT
        // screens without icons need to reserve a space for "erase"
        // scale the ADC values from ts.getPoint() to screen values e.g. 0-239
        //
        // Calibration is true for PORTRAIT. tp.y is always long dimension 
        // map to your current pixel orientation
        switch (Orientation) {
            case 0:
                xpos = map(tp.x, TS_LEFT, TS_RT, 0, tft.width());
                ypos = map(tp.y, TS_TOP, TS_BOT, 0, tft.height());
                break;
            case 1:
                xpos = map(tp.y, TS_TOP, TS_BOT, 0, tft.width());
                ypos = map(tp.x, TS_RT, TS_LEFT, 0, tft.height());
                break;
            case 2:
                xpos = map(tp.x, TS_RT, TS_LEFT, 0, tft.width());
                ypos = map(tp.y, TS_BOT, TS_TOP, 0, tft.height());
                break;
            case 3:
                xpos = map(tp.y, TS_BOT, TS_TOP, 0, tft.width());
                ypos = map(tp.x, TS_LEFT, TS_RT, 0, tft.height());
                break;
        }

        // are we in top color box area ?
        if (ypos < BOXSIZE) {               //draw white border on selected color box
            oldcolor = currentcolor;

            if (xpos < BOXSIZE) {
                currentcolor = RED;
                tft.drawRect(0, 0, BOXSIZE, BOXSIZE, WHITE);
            } else if (xpos < BOXSIZE * 2) {
                currentcolor = YELLOW;
                tft.drawRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, WHITE);
            } else if (xpos < BOXSIZE * 3) {
                currentcolor = GREEN;
                tft.drawRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, WHITE);
            } else if (xpos < BOXSIZE * 4) {
                currentcolor = CYAN;
                tft.drawRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, WHITE);
            } else if (xpos < BOXSIZE * 5) {
                currentcolor = BLUE;
                tft.drawRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, WHITE);
            } else if (xpos < BOXSIZE * 6) {
                currentcolor = MAGENTA;
                tft.drawRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, WHITE);
            }

            if (oldcolor != currentcolor) { //rub out the previous white border
                if (oldcolor == RED) tft.fillRect(0, 0, BOXSIZE, BOXSIZE, RED);
                if (oldcolor == YELLOW) tft.fillRect(BOXSIZE, 0, BOXSIZE, BOXSIZE, YELLOW);
                if (oldcolor == GREEN) tft.fillRect(BOXSIZE * 2, 0, BOXSIZE, BOXSIZE, GREEN);
                if (oldcolor == CYAN) tft.fillRect(BOXSIZE * 3, 0, BOXSIZE, BOXSIZE, CYAN);
                if (oldcolor == BLUE) tft.fillRect(BOXSIZE * 4, 0, BOXSIZE, BOXSIZE, BLUE);
                if (oldcolor == MAGENTA) tft.fillRect(BOXSIZE * 5, 0, BOXSIZE, BOXSIZE, MAGENTA);
            }
        }
        // are we in drawing area ?
        if (((ypos - PENRADIUS) > BOXSIZE) && ((ypos + PENRADIUS) < tft.height())) {
            tft.fillCircle(xpos, ypos, PENRADIUS, currentcolor);
        }
        // are we in erase area ?
        // Plain Touch panels use bottom 10 pixels e.g. > h - 10
        // Touch panels with icon area e.g. > h - 0
        if (ypos > tft.height() - 10) {
            // press the bottom of the screen to erase
            tft.fillRect(0, BOXSIZE, tft.width(), tft.height() - BOXSIZE, BLACK);
        }
    }
}

Regular Mcufriend Uno Shields have a bare Resistive Panel that shares pins with the TFT.
MCUFRIEND_kbv examples show how to use TouchScreen.h library with this bare Resistive Panel

Your display has an XPT2046 Touch Controller chip.

Install XPT2046_TouchScreen via the IDE Library Manager.

David.

Doesn't work. If I remove the picture, the screen will become a colored noise, if not, then the picture will miss it's first square, but won't write out anything.

#include <MCUFRIEND_kbv.h>
#include <Adafruit_GFX.h>         // Core graphics library
#include <SPI.h>             // f.k. for Arduino-1.5.2
#include <SdFat.h>                // SD card & FAT filesystem library
#include <Adafruit_SPIFlash.h>    // SPI / QSPI flash library
#include <Adafruit_ImageReader.h> // Image-reading functions
#include <XPT2046_Touchscreen.h>

#define SD_CS   4 // SD card select pin
#define NAMEMATCH ""         // "" matches any name
#define PALETTEDEPTH   8     // support 256-colour Palette

#define CS_PIN  8
#define TIRQ_PIN  2
XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN);  // Param 2 - Touch IRQ Pin - interrupt enabled polling

  SdFat                SD;         // SD card filesystem
  Adafruit_ImageReader reader(SD); // Image-reader object, pass in SD filesys

MCUFRIEND_kbv tft;
char namebuf[32] = "/";   //BMP files in root directory
int pathlen;

void setup() {
  tft.begin(0x7796);
    bool good = SD.begin(SD_CS);
    if (!good) {
        Serial.print(F("cannot start SD"));
        while (1);
    }
  Serial.begin(38400);
  ts.begin();
  ts.setRotation(1);
  while (!Serial && (millis() <= 1000));
}

void loop() {
    char *nm = namebuf + pathlen;
    File f = SD.open("Cyberpunk1.bmp");
    int i,j;
    uint8_t ret;
    uint32_t start;
  if (ts.tirqTouched()) {
    if (ts.touched()) {
      TS_Point p = ts.getPoint();
      Serial.print("Pressure = ");
      Serial.print(p.z);
      Serial.print(", x = ");
      Serial.print(p.x);
      Serial.print(", y = ");
      Serial.print(p.y);
      delay(30);
      Serial.println();
    }
  }
        f.getName(nm, 32 - pathlen);
        f.close();
        strlwr(nm);
        if (strstr(nm, ".bmp") != NULL && strstr(nm, NAMEMATCH) != NULL) {
            Serial.print(namebuf);
            Serial.print(F(" - "));
            tft.fillScreen(0);
            start = millis();
            for (i = 0; i < 4; i++){
              for (j = 0; j < 4; j++){
                ret = showBMP(namebuf, 80*i, 80*j, 80*i, 80*j, 80, 80);
              }
            }
            delay(5000);
        }
}

#define BMPIMAGEOFFSET 54

#define BUFFPIXEL      20

uint16_t read16(File& f) {
    uint16_t result;         // read little-endian
    f.read(&result, sizeof(result));
    return result;
}

uint32_t read32(File& f) {
    uint32_t result;
    f.read(&result, sizeof(result));
    return result;
}

uint8_t showBMP(char *nm, int x, int y, int startX, int startY, int sizeX, int sizeY)
{
    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;
    int 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;
        }

        // Set TFT address window to clipped image bounds
        tft.setAddrWindow(x, y, x + sizeX - 1, y + sizeY - 1);
        for (row = startY; row < startY+sizeY; row++) { // For each scanline...
            uint8_t r, g, b, *sdptr;
            int lcdidx, lcdleft;
            pos = bmpImageoffset + row * rowSize +2 * startX;
            bmpFile.seek(pos);//Adjust X position  TOP DOWN PICTURES ONLY!!!
            buffidx = sizeof(sdbuffer); // Force buffer reload

            for (col = 0; col < sizeX; ) {  //pixels in row
                lcdleft = sizeX - 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;
                    }
                    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);
}

Go on. It looks as if you have just invented some pins when the Shield plugs straight into a MEGA2560 and the TFT, SD, and Touch will all work 100%.

I don't have your USE_MEGA_8BIT_PORTC_SHIELD version.
But I do have the older USE_MEGA_8BIT_SHIELD display.

So I can confirm that the Shield works.

And I would be very certain that nothing will work when you use the wrong SD_CS and wrong Touch_CS.

David.

I don't understand... I've tried several combos, SD works, screen works, touch doesn't.
What values shall I use?
http://www.lcdwiki.com/3.95inch_Arduino_Display-Mega2560#Program_Download

If I use while to read my touch in, I get colored noise. If I do the read in in loop, then the first part of the picture will be missing.

Following your link there is http://www.lcdwiki.com/res/Program/Arduino/3.95inch/Mega2560_8BIT_ILI9488_MAR3953_V1.1/3.95inch_Arduino_Mega2560_8BIT_Module_ILI9488_MAR3953_V1.1.zip

Which is an enormous ZIP with paths that are too long for Windows.

It appears to be designed for ILI9488. Whereas this thread title is about ST7796S.

I "looked" at Example_07_show_bmp_picture\show_bmp_picture\show_bmp_picture.ino

This "looks" as if it should display a regular 24-bit .BMP file

I don't have your Shield. I don't want to install a BADLY-SPELLED library unless I have clear information about which example(s) you are trying. And a clear description of any problem.

The first step is to read the label on the anti-static bag that the display came in.
i.e. is it ILI9488 or ST7796S ?
i.e. is it 3.95 inch or 4.0 inch ?

I don't understand... I've tried several combos, SD works, screen works, touch doesn't.
What values shall I use?

From show_bmp_picture.ino

//when using the BREAKOUT BOARD only and using these 8 data lines to the LCD,
//pin usage as follow:
//             CS  CD  WR  RD  RST  D0  D1  D2  D3  D4  D5  D6  D7  D8  D9  D10  D11  D12  D13  D14  D15 
//Arduino Mega 40  38  39  43  41   37  36  35  34  33  32  31  30  /   /    /    /    /    /    /    /
//             TP_IRQ  MOSI  MISO  TP_CS  EX_CLK
//Arduino Mega   44    51     50    53      52

i.e. TP_CS=53 and SD_CS=48

David.

The label says ST7796S and the screen is 3,95".
With the badly spelled library it "worked", so i guess it's ILI9488 then.
But this interface definition show whole other pins:
http://www.lcdwiki.com/3.95inch_Arduino_Display-Mega2560#Interface_Definition

The pinout in your link shows the 18x2 male header with the pins numbered in the conventional way.

The Arduino MEGA2560 has a 18x2 female socket designed to receive the male header.

The Arduino pins that I posted in #16 correspond exactly. e.g. DB0 is clearly printed on the pcb, is number #18 in 18x2 nomenclature and is Digital#37 in Arduino nomenclature

ST7796S is Sitronix part number for the ST7796S controller.
ILI9488 is Ilitek part number for the ILI9488 controller.

If this is too difficult for you I suggest that you find another hobby.

David.

david_prentice:
If this is too difficult for you I suggest that you find another hobby.

I installed the 9488 lib opened the example, set in the CS, DC and RST values(40, 38, 41), and it doesn't work(the screen, i won't even get to the touch part).
I pretty much encounter the same problem whichever lib I try.

I'll be honest, if I can get this right, I'll stick to this combo forever :stuck_out_tongue: