projet pipboy, problème lecture image bmp

Bonjour !

Je suis entrain de upgrader un kit pip boy avec un écran "fonctionnel", grâce au code de MattiusMatt. J'ai donc acheté un module lcd pas cher sur Aliexpress (oui je sais, c'est pas terrible), j'ai un peu changé le programme et contre toutes attentes, ça marche, à peu près...
En effet, le programme s'arrête au moment où il faut afficher une image bmp, j'en ai donc déduis que le problème se trouvait là. Je vous ai mis le début du code + une vidéo.
Arduino uno + module ci : https://fr.aliexpress.com/item/32905829057.html?spm=a2g0s.9042311.0.0.78586c37y42gDl

(J'ai mis qu'une première partie, ça bug au "// Vault Boy Loading", donc au moment où il veut afficher une image)

#include <Adafruit_TFTLCD.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <SD.h>

// Comment here when I know what this is for??
#if defined(__SAM3X8E__)
    #undef __FlashStringHelper::F(string_literal)
    #define F(string_literal) string_literal
#endif

// ASCII Consts
#define ASCII_CR 13
#define ASCII_LF 10
#define ASCII_PIPE 124
#define ASCII_TILDE 126
#define ASCII_B 66
#define ASCII_M 77

// TFT Pins
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

// SD Pin
#define SD_CS 10

// GPS
#define GPS_SCREEN 3

// Radio
#define RADIO_SCREEN 4

// Pip Screens
const char PIP_0[] = "0.pip";
const char PIP_1[] = "1.pip";
const char PIP_2[] = "2.pip";
const char PIP_3[] = "3.pip";
const char PIP_4[] = "4.pip";

#define TS_MINX 204
#define TS_MINY 195
#define TS_MAXX 948
#define TS_MAXY 910

// PIP Colours
#define GREEN   0x07E0
#define BLACK   0x0000

// TFT
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Initialisation

void setup() {
  // Debug using serial
  Serial.begin(9600);

  if (!enableSD()) { return; }

  if (!enableTFT()) { return; }
  
  runLoadSequence();
}

bool enableSD() {
  //Serial.print(F("Initialising SD card..."));
  
  if (!SD.begin(SD_CS)) {
    Serial.println(F("SD failed!"));
    return false;
  }
  
  //Serial.println(F("SD Initialised!"));

  return true;
}

bool enableTFT() {
  //Serial.println(F("Initialising TFT"));
  
  // TFT
  tft.begin(0x7575);
  tft.setRotation(1);
  tft.setTextColor(0x07E0);
  tft.setTextSize(1);

  return true;
}

void runLoadSequence() {
  //Serial.println(F("Running load sequence"));
  
  // Splash 0
  tft.fillScreen(0x0000);
  loadText("0.txt", 0, 0, 0);
  delay(1000);

  // Loading
  tft.fillScreen(0x0000);
  loadText("1.txt", 0, 0, 20);
  //Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  delay(1000);

  // Vault Boy Loading
  tft.fillScreen(0x0000);
  bmpDraw("l.bmp", 95, 35);
  delay(1000);
}

Le lien pour voir la vidéo : https://drive.google.com/file/d/1KBXa9LavJBRG2lDj1ptzSSdYdd-wWhr3/view?usp=sharing

Merci pour votre aide !! Au passage, si vous voulez suivre le projet, ma page facebook : Raphi corp.

Vous avez vérifié que la carte SD est bien connectée et vous avez bien les bons fichiers dessus ?

Sinon ce code là

 // ASCII Consts
#define ASCII_CR 13
#define ASCII_LF 10
#define ASCII_PIPE 124
#define ASCII_TILDE 126
#define ASCII_B 66
#define ASCII_M 77

serait plus simple et plus lisible en écrivant

 // ASCII Consts
#define ASCII_CR ‘\r’
#define ASCII_LF ‘\n’
#define ASCII_PIPE ‘|’
#define ASCII_TILDE ‘~’
#define ASCII_B ‘B’
#define ASCII_M ‘M’

Oui j'ai bien les bons fichiers, tout charge nickel, le programme fonctionne... Jusqu'à ce qu'arrive la première image à afficher. Ma SD est simple, de 2go, formatée en fat32.
L'auteur du code a bien mis les images bmp au bon format, etc.

Je me demande si ce n'est pas un probl d'alimentation parce que le module est en 3v alors qu'il est branché sur les deux pin d'alimentation.

D'après ceci, bmpDraw est une méthode de la bibliothèque Adafruit_ImageReader

Il faut donc en définir une instance

Adafruit_ImageReader reader; // Class w/image-reading functions

Puis appeler la méthode en s'y référant

ImageReturnCode stat;
stat = reader.drawBMP("/1.bmp", tft, 0, 0);

Attention aux limitations imposées aux fichiers images

To make new bitmaps, make sure they are less than 240 by 320 pixels and save them in 24-bit BMP format! They must be in 24-bit format, even if they are not 24-bit color as that is the easiest format for the Arduino to decode.

Sinon une autre possibilité, peut-être celle que tu utilises, est de définir une fonction bmpDraw comme c'est fait ici

//Drawing function, reads the file from the SD card and do the 
//conversion and drawing, also it shows messages on the Serial monitor in case of a problem
//No touchy to this function :D

void bmpDraw(char *filename, int x, int y) {

  File     bmpFile;
  int      bmpWidth, bmpHeight;   // W+H in pixels
  uint8_t  bmpDepth;              // Bit depth (currently must be 24)
  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[BUFFPIXEL];  // pixel out buffer (16-bit per pixel)
  uint8_t  buffidx = sizeof(sdbuffer); // Current position in sdbuffer
  boolean  goodBmp = false;       // Set to true on valid header parse
  boolean  flip    = true;        // BMP is stored bottom-to-top
  int      w, h, row, col;
  uint8_t  r, g, b;
  uint32_t pos = 0, startTime = millis();
  uint8_t  lcdidx = 0;
  boolean  first = true;

  if((x >= tft.width()) || (y >= tft.height())) return;

  Serial.println();
  progmemPrint(PSTR("Loading image '"));
  Serial.print(filename);
  Serial.println('\'');
  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == NULL) {
    progmemPrintln(PSTR("File not found"));
    return;
  }

  // Parse BMP header
  if(read16(bmpFile) == 0x4D42) { // BMP signature
    progmemPrint(PSTR("File size: ")); Serial.println(read32(bmpFile));
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    progmemPrint(PSTR("Image Offset: ")); Serial.println(bmpImageoffset, DEC);
    // Read DIB header
    progmemPrint(PSTR("Header size: ")); Serial.println(read32(bmpFile));
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if(read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // bits per pixel
      progmemPrint(PSTR("Bit Depth: ")); Serial.println(bmpDepth);
      if((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed

        goodBmp = true; // Supported BMP format -- proceed!
        progmemPrint(PSTR("Image size: "));
        Serial.print(bmpWidth);
        Serial.print('x');
        Serial.println(bmpHeight);

        // BMP rows are padded (if needed) to 4-byte boundary
        rowSize = (bmpWidth * 3 + 3) & ~3;

        // If bmpHeight is negative, image is in top-down order.
        // This is not canon but has been observed in the wild.
        if(bmpHeight < 0) {
          bmpHeight = -bmpHeight;
          flip      = false;
        }

        // Crop area to be loaded
        w = bmpWidth;
        h = bmpHeight;
        if((x+w-1) >= tft.width())  w = tft.width()  - x;
        if((y+h-1) >= tft.height()) h = tft.height() - y;

        // 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...
          // Seek to start of scan line.  It might seem labor-
          // intensive to be doing this on every line, but this
          // method covers a lot of gritty details like cropping
          // and scanline padding.  Also, the seek only takes
          // place if the file position actually needs to change
          // (avoids a lot of cluster math in SD library).
          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; col++) { // For each column...
            // Time to read more pixel data?
            if (buffidx >= sizeof(sdbuffer)) { // Indeed
              // Push LCD buffer to the display first
              if(lcdidx > 0) {
                tft.pushColors(lcdbuffer, lcdidx, first);
                lcdidx = 0;
                first  = false;
              }
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }

            // Convert pixel from BMP to TFT format
            b = sdbuffer[buffidx++];
            g = sdbuffer[buffidx++];
            r = sdbuffer[buffidx++];
            lcdbuffer[lcdidx++] = tft.color565(r,g,b);
          } // end pixel
        } // end scanline
        // Write any remaining data to LCD
        if(lcdidx > 0) {
          tft.pushColors(lcdbuffer, lcdidx, first);
        } 
        progmemPrint(PSTR("Loaded in "));
        Serial.print(millis() - startTime);
        Serial.println(" ms");
      } // end goodBmp
    }
  }

  bmpFile.close();
  if(!goodBmp) progmemPrintln(PSTR("BMP format not recognized."));
}

J'ai téléchargé la librairie d'Adafruit Image reader mais ça marche pas. Peut être parce que dans le code, effectivement, il n'y a rien qui dit ce qu'il faut faire avec la fonction drawbmp.
J'essayerai de bidouiller ça.

Est ce que ça peut aussi être l'alimentation ? Les pin du Shield branchés sur le 5v ET le 3v alors que la carte est marquée en 3v ?

Avec un arduino UNO!!!
Il y a assez de RAM pour faire tourner tout ça?
MattiusMatt a utilisé une mega.
Au passage, il aurait été bien de mettre un lien vers le code original pour que l'on sache de quoi il est question

Je n'ai pas mis de lien vers le code de MatthiusMat pour ne pas surcharger mon post mais je l'ai cité et j'assume totalement le fait de me baser sur son code pour mon projet (et il sera largement cité). Donc ce n'est pas par malhonnêteté.

Quand au fait d'utiliser une Arduino uno... Hé bien il est probable que ce soit effectivement un problème si d'autres me confirment cela. Je n'avais que ma petite Uno sous la main. Je ne pensais pas que le problème venait de là, j'ai vu sur les vidéo que Matt avait aussi utilisé des Arduino Nano pour rendre son montage plus transportable. Du coup je me suis dit "C'est bon ça passe" XD

Bonjour
Lien ou pas lien ?
Ne pas perdre de vue que des contributeurs importants de ce forum le consultent avec leur smartphone.
Il en découle que la présence de liens cliquables et de code inclus correctement (balises) dans le corps du message augmente la probabilité de réponses.
Chaque forum a ses règles et ses usages

Faire de l'évocation d'un code un lien cliquable ne surcharge pas le forum, c'est juste un petit effort de rédaction dans l'intérêt du demandeur

Code original
Lien ici

Ca c'est le début de mon code modifié pour mon matériel (notamment mon module qui fonctionne en 0x7575)

#include <Adafruit_TFTLCD.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <SD.h>

// Comment here when I know what this is for??
#if defined(__SAM3X8E__)
    #undef __FlashStringHelper::F(string_literal)
    #define F(string_literal) string_literal
#endif

// ASCII Consts
#define ASCII_CR 13
#define ASCII_LF 10
#define ASCII_PIPE 124
#define ASCII_TILDE 126
#define ASCII_B 66
#define ASCII_M 77

// TFT Pins
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

// SD Pin
#define SD_CS 10

// GPS
#define GPS_SCREEN 3

// Radio
#define RADIO_SCREEN 4

// Pip Screens
const char PIP_0[] = "0.pip";
const char PIP_1[] = "1.pip";
const char PIP_2[] = "2.pip";
const char PIP_3[] = "3.pip";
const char PIP_4[] = "4.pip";

#define TS_MINX 204
#define TS_MINY 195
#define TS_MAXX 948
#define TS_MAXY 910

// PIP Colours
#define GREEN   0x07E0
#define BLACK   0x0000

// TFT
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Initialisation

void setup() {
  // Debug using serial
  Serial.begin(9600);

  if (!enableSD()) { return; }

  if (!enableTFT()) { return; }
  
  runLoadSequence();
}

bool enableSD() {
  //Serial.print(F("Initialising SD card..."));
  
  if (!SD.begin(SD_CS)) {
    Serial.println(F("SD failed!"));
    return false;
  }
  
  //Serial.println(F("SD Initialised!"));

  return true;
}

bool enableTFT() {
  //Serial.println(F("Initialising TFT"));
  
  // TFT
  tft.begin(0x7575);
  tft.setRotation(1);
  tft.setTextColor(0x07E0);
  tft.setTextSize(1);

  return true;
}

void runLoadSequence() {
  //Serial.println(F("Running load sequence"));
  
  // Splash 0
  tft.fillScreen(0x0000);
  loadText("0.txt", 0, 0, 0);
  delay(1000);

  // Loading
  tft.fillScreen(0x0000);
  loadText("1.txt", 0, 0, 20);
  //Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  delay(1000);

  // Vault Boy Loading
  tft.fillScreen(0x0000);
  bmpDraw("l.bmp", 95, 35);
  delay(1000);
}

Est ce que ça peut aussi être l'alimentation ? Les pin du Shield branchés sur le 5v ET le 3v alors que la carte est marquée en 3v ?

En suivant le lien vets le module afficheur donnée dans le message initial on peut lire :

Régulateur LDO 3.3 V 300mA embarqué
Compatible 5 V, utilisation avec une logique 3.3 V ou 5 V

Cela semble confirmé par la présence d'un régulateur3,3V et de deux circuits intérgés adaptateurs de niveaux logiques.... si le produit livré est conforme à l'annonce.
adapt.png

adapt.png

Raphi33:
Je n'ai pas mis de lien vers le code de MatthiusMat ...... Donc ce n'est pas par malhonnêteté.

C'est pas le problème. C'est juste pour que l'on puisse consulter le projet original pour se faire une idée.

Je serais curieux de connaître la taille RAM libre à la fin du setup()

On voit aussi dans les projets du même style que les gens utilisent plutôt des raspberry PI ou des Teensy qui sont quand même un peu plus musclés qu'une arduino.
Les Teensy permettent de développer dans l'IDE arduino

Je voulais limiter les coûts mais si vous me dites que ce n'est pas bon, j'investirai. Au moins dans une Arduino mega.
Mon module lcd doit pas être très bon, même si les test graphiques fonctionnent.
Le programme se lance, il y a le fameux texte qui défile avant l'image du pip-boy. Et malheureusement, au moment où il faut afficher l'image... Écran noir

vous pouvez trouver un clone du Mega pour 5 ou 6 euros en Asie... il faudra juste être patient pour le recevoir

Raphi33:
Je voulais limiter les coûts

Une Raspberry Pi Zero coute sensiblement le même prix qu'une mega

Raphi33:
mais si vous me dites que ce n'est pas bon

Disons que j'émets un doute. Les Arduino basées sur l'ATmega 328 disposent de peu de mémoire RAM. Les librairies graphiques et SD consomment pas mal de ressources donc il est probable mais pas certains que tu te trouves à court de mémoire. Pour le vérifier il faudrait faire afficher dans une console la mémoire disponible en différents points du programme pour en être certain.
Voir par exemple ici:Arduino Playground - AvailableMemory

Bon j'ai acheté une Arduino mega. Je la reçois en fin de semaine. Je vous tiendrai au courant de la suite. Merci pour ces premiers conseils !

ça y'est, j'ai reçut ma Arduino Mega 2560.
J'ai envoyé le code et j'ai eu ce message d'erreur :

Les options de compilation ont été modifiées, tout sera recompilé
In file included from C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\Adafruit_TFTLCD.cpp:19:0:

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\pin_magic.h:282:33: warning: backslash and newline separated by space

   #define read8inline(result) { \    

                                 ^

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\Adafruit_TFTLCD.cpp:803:0: warning: "read8" redefined

   #define read8(x) x=read8fn()

 ^

In file included from C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\Adafruit_TFTLCD.cpp:19:0:

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\pin_magic.h:183:0: note: this is the location of the previous definition

   #define read8             read8inline

 ^

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\Adafruit_TFTLCD.cpp: In member function 'void Adafruit_TFTLCD::begin(uint16_t)':

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\pin_magic.h:401:21: warning: large integer implicitly truncated to unsigned type [-Woverflow]

   hi = (d) >> 8; lo = (d); CD_DATA   ; write8(hi); write8(lo); }

                     ^

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\pin_magic.h:187:29: note: in expansion of macro 'writeRegister16inline'

   #define writeRegister16   writeRegister16inline

                             ^

C:\Users\helen\Documents\Arduino\libraries\TFTLCD-Library-master\Adafruit_TFTLCD.cpp:283:5: note: in expansion of macro 'writeRegister16'

     writeRegister16(ILI9341_VCOMCONTROL1, 0x2B2B);

     ^

Le croquis utilise 26556 octets (10%) de l'espace de stockage de programmes. Le maximum est de 253952 octets.
Les variables globales utilisent 1398 octets (17%) de mémoire dynamique, ce qui laisse 6794 octets pour les variables locales. Le maximum est de 8192 octets.

L'écran est blanc, rien s'affiche, le test graphique MCUfriend fonctionne

Pour rappel, ecran tftlcd 2,8' commandé sur Aliexpress (0x7575)
lien vers code original ici que j'ai modifié pour mon matériel ci après :

#include <Adafruit_TFTLCD.h>
#include <Adafruit_GFX.h>
#include <SPI.h>
#include <SD.h>

// Comment here when I know what this is for??
#if defined(__SAM3X8E__)
    #undef __FlashStringHelper::F(string_literal)
    #define F(string_literal) string_literal
#endif

// ASCII Consts
#define ASCII_CR 13
#define ASCII_LF 10
#define ASCII_PIPE 124
#define ASCII_TILDE 126
#define ASCII_B 66
#define ASCII_M 77

// TFT Pins
#define LCD_CS A3
#define LCD_CD A2
#define LCD_WR A1
#define LCD_RD A0
#define LCD_RESET A4

// SD Pin
#define SD_CS 10

// GPS
#define GPS_SCREEN 3

// Radio
#define RADIO_SCREEN 4

// Pip Screens
const char PIP_0[] = "0.pip";
const char PIP_1[] = "1.pip";
const char PIP_2[] = "2.pip";
const char PIP_3[] = "3.pip";
const char PIP_4[] = "4.pip";

#define TS_MINX 204
#define TS_MINY 195
#define TS_MAXX 948
#define TS_MAXY 910

// PIP Colours
#define GREEN   0x07E0
#define BLACK   0x0000

// TFT
Adafruit_TFTLCD tft(LCD_CS, LCD_CD, LCD_WR, LCD_RD, LCD_RESET);

// Initialisation

void setup() {
  // Debug using serial
  Serial.begin(9600);

  if (!enableSD()) { return; }

  if (!enableTFT()) { return; }
 
  runLoadSequence();
}

bool enableSD() {
  //Serial.print(F("Initialising SD card..."));
 
  if (!SD.begin(SD_CS)) {
    Serial.println(F("SD failed!"));
    return false;
  }
 
  //Serial.println(F("SD Initialised!"));

  return true;
}

bool enableTFT() {
  //Serial.println(F("Initialising TFT"));
 
  // TFT
  tft.begin(0x7575);
  tft.setRotation(1);
  tft.setTextColor(0x07E0);
  tft.setTextSize(1);

  return true;
}

void runLoadSequence() {
  //Serial.println(F("Running load sequence"));
 
  // Splash 0
  tft.fillScreen(0x0000);
  loadText("0.txt", 0, 0, 0);
  delay(1000);

  // Loading
  tft.fillScreen(0x0000);
  loadText("1.txt", 0, 0, 20);
  //Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);
  delay(1000);

  // Vault Boy Loading
  tft.fillScreen(0x0000);
  bmpDraw("l.bmp", 95, 35);
  delay(1000);
}

T_T

J'ai tenté des heures, je suppose que ça vient des librairies et un peu de ma Arduino mega puisque l'écran reste blanc alors qu'avec la Uno il y avait un début de programme. Quelqu'un ? Une piste ? PleeeAAse ! Help... Me !

Raphi33:
le test graphique MCUfriend fonctionne

Si le test graphique fonctionne, tu ne peux pas incriminer le matériel.

Maintenant, puisque le test graphique MCUfriend fonctionne tu as la certitude que ton matériel est bon.
Il faut passer à l'étape suivante.
Tu veux utiliser les librairies Adafruit.
Il faut donc faire la même démarche en commençant par les tests graphiques de la librairie Adafruit. pour voir s'ils passent correctement.