Librería para TFT con RA8875 para manejo de imágenes [Solucionado]

Hola compañeros,

He estado buscando durante varios días hasta aburrirme, y no he encontrado una librería que maneje cualquier tipo de imagen (me da igual que sea JPG, BMP o PNG) y que la muestre en una pantalla TFT de 7" de Buydisplay. La pantalla funciona de lujo, y con Arduino DUE va realmente rápido.

He probado las librerías de RA8875 y la misma de Adafruit. Con la primera funciona todo, pero la imagen de 24 bits que pone como ejemplo de representación de una imagen en pantalla, funciona porque está en hexadecimal. Yo quiero que lea un fichero de imagen (me da igual qué tipo) de la SD Card, y la muestre en la pantalla. SIMPLEMENTE (o no).

Pensé que sería más fácil, pero no hay manera.

¿Me podéis orientar un poco?

Y si no se puede, ¿me podéis decir cómo pasar una imagen a HEX en Linux? He probado Image2LCD con wine, pero no sé si es que no lo codifica como debe, o que estoy haciendo algo mal (seguramente esto último).

Un saludo a todos, y gracias por leerme. Espero que puedan ayudarme

Hola de echo yo cree un método para mostrar imágenes en una TFT , te lo advierto no es para nada eficiente en términos de escritura pero quizás te pueda servir.
Solo utilice un programa llamado Octave (opensource) si te interesa puedo decirte como.

Hola Eduardosanchez,

Lo primero gracias por contestar.

Sí, claro que me interesa :slight_smile: . Aunque no sea eficiente, me puede interesar (seguro que sí).

Estaría interesado también en saber de qué manera podría hacerse el incluir 20 pequeñas imágenes de 60x60 pixels de 6 colores máximo en un sketch para Arduino DUE.

Si alguien sabe cómo, por favor, que me diga dónde puedo encontrar información al respecto.

Gracias.

18turbo:
Sí, claro que me interesa :slight_smile: . Aunque no sea eficiente, me puede interesar (seguro que sí).

Gracias.

ok yo maneje un TFT con comunicación SPI, no se que tipo de comunicación utilice la tuya de cualquier modo eso es lo de menos. Lo unico que si te servira es saber cual es la profundidad de color de tu pantalla (8,12,16 bits) esto definirá la codificacion de la imagen, yo como tal codifique una imagen PGN en un tipo formato RGB565 (la pantalla era de 16 bits) en un archivo de texto. lo único que hice en realidad es abrir el archivo txt e ir obteniendo la información para "colorear" los píxeles a partir de caracteres.
tarda como medio segundo en dibujar una imagen completa(240*204 pixeles).
En cuanto a la imagen de 60x60 es por eso que debes saber cual es la profundidad del color. y te puede servir como referencia esta página.(incluso esa la puedes dejar en la memoria EEPROM como indica la siguiente pagina)
https://www.prometec.net/shield-mega-tft-imagen/

Primero leo esto

Con la primera funciona todo, pero la imagen de 24 bits que pone como ejemplo de representación de una imagen en pantalla, funciona porque está en hexadecimal. Yo quiero que lea un fichero de imagen (me da igual qué tipo) de la SD Card, y la muestre en la pantalla. SIMPLEMENTE (o no).

Los archivos deben convertirse. No hay ningun arduino que lea un formato .jpg o .bmp o lo que sea y lo presente, asi que olvidate de resolver eso porque no le da la potencia de cálculo.

Existen programas que convierten los archivos del formato que sea en hexa. Y esa es tu solución.
Lo guardas como Hexa en la SD y luego lo presentas.

Acá tendras tu respuesta Algunos consejos para usar TFT´s

El tema esta en Documentacion => Indice de temas tutoriales =>TFT => Algunos consejos para usar TFT´s

@eduardoSanchez

La TFT la compré preparada para SPI (aunque puede ir por paralelo) porque me interesaba así. Es de 24 bits, y la resolución de 800x480pixels. La SD Card no la he hecho funcionar todavía (me refiero a la que va en la TFT, no sé bien qué pasa, pero eso quizás sea para otro post).

Gracias por la info, muy interesante, aunque de poco me sirve porque en el ejemplo de la librería RA8875 que me funciona, la imagen está de la forma:

static const uint32_t image_data_batman_ume[16384] = {
    0x976a40, 0xaa8a3f, 0xb49f42, 0xb3a044, 0xb19b45, 0xac983f,...}

Y en el código veo que transforma ésta a RGB565:

void drawArray(const uint32_t * image,uint16_t isize,uint16_t iwidth,uint16_t x,uint16_t y){
  uint16_t pixels[iwidth];//container
  uint32_t i,idx;
  for (idx=0;idx<isize/iwidth;idx++){
    for (i = (iwidth*idx); i < iwidth*(idx+1);i++){
      pixels[i - (iwidth*idx)] = tft.Color24To565(image[i]);
    }
    tft.drawPixels(pixels,iwidth,x,idx+y);
  }
}

Por lo que me interesaba saber cómo consigo esta codificación (la que pongo en el primer código), porque a RGB565 no hay problemas.

@surbyte

Muchas gracias por la información tan clara. Necesitaba algo así. Sabiendo que nada lee los formatos de imagen y los presente por pantalla "tal cual" (al menos para la pantalla que yo tengo o de forma fácil o "limpia"), ya me busco la vida en hexadecimal, pero debo resolver el problema del código anterior (primer código que puse), porque no llego a entender como pasar una imagen a esa codificación. Si me podéis echar una manilla más...

Luego, con las pautas que me has dado (guardar en hexadecimal los ficheros en la SD para leerlos y presentarlos), pues ya lo tengo.

Gracias por el enlace del uso de las TFTs (estuve "procesándolo" toda la tarde :wink: )

Gracias a los 2.

Moderador: Texto editado

Buscando en el baúl de los recuerdos, he encontrado una función que me funcionaba en otra pantalla, y que creo que funcionaría en ésta.

Pongo el código por si le sirve a alguien, AUNQUE YO NO LA HE PROBADO TODAVÍA:

// These read 16- and 32-bit types from the SD card file.
// BMP data is stored little-endian, Arduino is little-endian too.
// May need to reverse subscript order if porting elsewhere.

void writePixb(int16_t x,uint16_t color){
  tft.setX(x);
  tft.writeCommand(RA8875_MRWC);
  tft.writeData16(color); 
}


void bmpDraw(const char *filename, int16_t x, int16_t y) 
  {

  File     bmpFile;
  int16_t  bmpWidth = 0, bmpHeight = 0;   // W+H in pixels
  uint8_t  bmpDepth = 0;              // Bit depth (currently must be 24)
  uint32_t bmpImageoffset = 0;        // Start of image data in file
  uint32_t rowSize = 0;               // 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  flip    = true;        // BMP is stored bottom-to-top
  int16_t  w=0, h=0, row=0, col=0;
  uint32_t pos = 0;
  uint16_t lcdidx = 0;

  if((x >= tft.width()) || (y >= tft.height())) return;
  // Open requested file on SD card
  if ((bmpFile = SD.open(filename)) == 0) return;
  // Parse BMP header
  if (read16(bmpFile) == 0x4D42) { // check BMP signature
    read32(bmpFile);
    (void)read32(bmpFile); // Read & ignore creator bytes
    bmpImageoffset = read32(bmpFile); // Start of image data
    read32(bmpFile);
    bmpWidth  = read32(bmpFile);
    bmpHeight = read32(bmpFile);
    if (read16(bmpFile) == 1) { // # planes -- must be '1'
      bmpDepth = read16(bmpFile); // determine color depth
      if ((bmpDepth == 24) && (read32(bmpFile) == 0)) { // 0 = uncompressed
        // 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;

        for (row=0; row<h; row++) { // For each scanline...
          tft.setY(row+y);
          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) {
                writePixb(col+x,lcdbuffer[lcdidx]);
                lcdidx = 0;
              }
              bmpFile.read(sdbuffer, sizeof(sdbuffer));
              buffidx = 0; // Set index to beginning
            }
            lcdbuffer[lcdidx] = tft.Color565(sdbuffer[buffidx++],sdbuffer[buffidx++],sdbuffer[buffidx++]);
            writePixb(col+x,lcdbuffer[lcdidx]);
          } // end pixel

        } // end scanline
        // Write any remaining data to LCD
        if(lcdidx > 0) writePixb(col+x,lcdbuffer[lcdidx]);
      } // end goodBmp
    }//correct plane
  }//end BMP signature
  bmpFile.close();
}



uint16_t read16(File f) {
  uint16_t result = 0;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read(); // MSB
  return result;
}

uint32_t read32(File f) {
  uint32_t result = 0;
  ((uint8_t *)&result)[0] = f.read(); // LSB
  ((uint8_t *)&result)[1] = f.read();
  ((uint8_t *)&result)[2] = f.read();
  ((uint8_t *)&result)[3] = f.read(); // MSB
  return result;
}

El tema está ahora en conseguir hacer funcionar la SD Card de la TFT para que lea un BMP y pueda probar el código.

No sé si llegado este punto, debiera abrir otro hilo o seguir con el problema de la SD Card aquí.

bueno si consigues la forma de hacer que una librería SD pueda leer archivos decodificados en 16 o 24 bits me avisas que he estuve cerca de dos meses y no encontre nada.
para saber cómo pasa una imagen a una pantalla es bastante interesante para hacer que la mía funcionara lo hice como te dije pero tuve que hacer una libreria para el manejo de mi pantalla lo que necesitas saber es 1 el tipo de interfaz como te mencionaba en mi caso una spi de 4 hilos estos son

mosi
sclk
slave select
data/cmand

si tu pantalla funciona de forma similar estamos en el mismo canal. pues al final lo que hace un microcontrolador es mandar el comando(a través del dato/comando) un valor por SPI a la pantalla que le indica que registros de la memoria RAM de la pantalla se van a escribir "habilitar una ventana" después de eso (en mi código 9 transferencias de SPI 3 comandos los demás datos) y despues solo envía datos que contienen la información osea el valor para cada píxel, en mi caso al ser RGB565 con dos transferencias SPI de 8bits rellenaba un pixel, obvio primero se envian los mas significativos después los menos.

18turbo:
@eduardoSanchez

La TFT la compré preparada para SPI (aunque puede ir por paralelo) porque me interesaba así. Es de 24 bits, y la resolución de 800x480pixels. La SD Card no la he hecho funcionar todavía (me refiero a la que va en la TFT, no sé bien qué pasa, pero eso quizás sea para otro post).

Gracias por la info, muy interesante, aunque de poco me sirve porque en el ejemplo de la librería RA8875 que me funciona, la imagen está de la forma:

void drawArray(const uint32_t * image,uint16_t isize,uint16_t iwidth,uint16_t x,uint16_t y){

uint16_t pixels[iwidth];//container
  uint32_t i,idx;
  for (idx=0;idx<isize/iwidth;idx++){
    for (i = (iwidthidx); i < iwidth(idx+1);i++){
      pixels[i - (iwidth*idx)] = tft.Color24To565(image[i]);
    }
    tft.drawPixels(pixels,iwidth,x,idx+y);
  }
}




Por lo que me interesaba saber **cómo consigo esta codificación** (la que pongo en el primer código), porque a RGB565 no hay problemas.

bien lo que necesitas es codificación RGB888 eso queire decir al parecer(falta verificar con la datasheet del controlador de tu pantalla) que la configuración de color es 8 bit rojo, 8 bit verde, 8 bit azul.
con Octave puedes hacer esto descargar octave instalar modulo Image. y empezar es básicamente mathlab open source. lo único que haces es tratar una imagen como una matriz , si tu imagen BMP ya está codificada en 24 bit lo único que haces es guardar ese valor en un archivo de texto separado con comas y después abrirlo declarar un array de 60x60 y guardarlo en la EEPROM. Exacto solo funcionaria para la de 60x60 y digo quizas por que no se si quepa en la EEPROM de arduino. (hace poco me ayudaron a guardar matrices de 32 bits en la EEPROM de arduino si te interesa te lo paso).
ACLARO LO ANTERIOR SOLO PARA LA DE 60X60 UNA IMAGEN DE PANTALLA COMPLETA NO CABRIA
con el SPI de transferencias de 8 bits que segun yo solo se puede asi en arduino necesitas enviar una componente de color es decir 3 transferencias SPI por pixel.
Todo mi proceso de "destripado" de librerias similares esta en una memoria( la uso para la titulación) si gustas te puedo compartirla como referencia.
Saludos

@Eduardosanchez

Sí, mi TFT usa 4 hilos SPI (podía haberla comprado para 3 hilos), pero compré para 4, que son:
*MISO
*MOSI
*SCK
*CS

Ahora bien, no sé qué pasa que en la DUE no funciona la SD Card. Y pensándolo, ANTES DE NADA, ya que tengo la Arduino MEGA por aquí donde sí me funciona la SD Card, voy a ver si hago funcionar la TFT en la Mega (aunque vaya más lenta, que creo que la configuración es la misma para la DUE que para la MEGA para mi TFT), y vamos despejando problemas...

Por mí, todo lo que quieras compartir, adelante. Yo, si consigo hacer funcionar lo que quiero no tendré inconveniente en pasártelo.

Un saludo, y gracias por ayudarme.

Moderador: No repitas lo que se lee arriba

Mi MEGA funciona con la TFT y la SD Card a la vez.

Además lee la tarjeta con el archivo BMP. Ahora falta que funcione :frowning: Estoy en ello.

Por cierto, con GIMP puedes coger el fichero gráfico que quieras, exportarlo a BMP (y en configuraciones Avanzadas de la exportación, seleccionar RGB565 para exportarlo a este formato.

Seguiré probando un poco más, y sino, lo dejo para mañana.

Saludos

He probado lo básico y no me funciona. Mañana seguiré, pero yo creo que esa función debe funcionar. Es posible que mi BMP no esté correctamente exportado, o algo así.

Te mande MP Revisa.

Pues funciona el código (la función) para mostrar cualquier BMP en una TFT. El código es parte copiado de algo antiguo que tenía por ahí pero funciona. Tendré que mejorarlo un poquito.

No doy por solucionado este hilo, porque me falta probarlo en la DUE, pero en el Arduino MEGA con la TFT y la SD Card, funciona.

Gracias a todos los que me habéis ayudado.

Un saludo

GENIAL!

Y como haras para pasar de una Mega que trabaja a 5V a un DUE que lo hace a 3.3V con tu TFT ?

@surbyte

No hay problema porque lleva intermedia una shield que controla el voltaje (siempre coge de los 5V).

De todas formas, mi TFT lleva para seleccionar 3V3 en vez de 5V, sin la Shield. Sólo hay que puentear con estaño unas pistas que explican en el datasheet. Pero bueno no me hace falta.

De hecho, ya lo he probado todo y ¡¡¡FUNCIONA!!!

Tengo que decir que parte del código no es mío, es una extracción de una librería que saqué hace dos años. Por desgracia no puedo decir quien fue el autor porque no lo sé y no puedo acordarme de dónde la saqué.

Pero bueno, se puede reproducir un BMP en la TFT con RA8875 teniendo en cuenta ciertas cosas:

  • que el BMP esté codificado en 24 bits (R8G8B8)
  • sabiendo de antemano que no es una opción optimizada y que debemos tener en cuenta la velocidad

Otra cosa que me ha dado mucha "caña" ha sido el SPI en la DUE. Que para que quede constancia, por si a alguien más le puede servir, el SPI del MEGA que se usa en los pines 50 a 52 NO SIRVEN para la DUE.

En la DUE hay que "puentear" los pines centrales del SPI de manera que salgan dos pines para cada sitio (uno para la TFT y otro para la SD Card) para que luego el CS de cada uno los controle. Así que he hecho un paralelo de los cables del SPI, y me funcionó por fin con el CS de la TFT en 10, y el CS de la SD Card en 25. Evidentemente también hay que cambiar el ChipSelect en la configuración de los sketch.

Tengo que darle las gracias a @EduardoSanchez que me está ayudando.

Voy a retocar un poco el código para ver si lo puedo optimizar.

Lo ideal es que se use una TFT en paralelo y una DUE (por el tema de la velocidad). Tuve la opción de comprarla así, pero por mi proyecto tenía que hacerlo por SPI.

Saludos

De hecho, he probado ya imágenes de ¡¡¡1,2MB!!! de 800x480 pixels y funciona sin problemas.