IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Arduino Discussion :

Ecran TFT - Librairie GFX - Afficher bitmap en RAM


Sujet :

Arduino

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 002
    Par défaut Ecran TFT - Librairie GFX - Afficher bitmap en RAM
    Bonjour,

    Dans mon projet je commande un écran TFT SPI avec la bibliothèque GFX Adafruit, depuis un Arduino "client" ; la dalle tactile est gérée par la bibliothèque URTouch.h

    En fait j'utilise PDQ_GFX qui est une version optimisée, que je recommande d'ailleurs : https://hackaday.io/project/6038-pdq...r-lcd-graphics

    Cette bibliothèque ne permet apparemment que d'afficher des bitmaps en ROM (écrits avec PROGMEM)

    Dans mon projet l'Arduino "client" contient un petit buffer en RAM de 256 octets que je peux remplir à distance via un autre Arduino "serveur"

    Un bitmap monochrome ne prend pas beaucoup de place (un octet = 8 pixel), un sprite de 16 x 16 Pixels n'occupe que 32 octets.
    Ca tiens largement en RAM, même avec toutes les variables et mon fameux buffer de 256 octets il me reste encore 1084 octets de RAM libre
    Je n'utilise pas la maudite classe string donc pas de soucis de fragmentation... je pense d'ailleurs passer mon buffer RAM à 512 octets.

    Le but final c'est de réaliser un module Interface Homme Machine avec un écran tactile et des entrées/sorties entièrement pilotables via Ethernet.

    J'ai déjà bien avancé.

    Le module Interface Homme Machine est composé d'un Arduino UNO, d'un écran tactile SPI TFT et d'un shield Ethernet.
    L'arduino UNO fonctionne en client HTTP.
    Il envoie une requête à un serveur à chaque fois que j'appuie sur l'écran tactile.
    Le serveur répond en envoyant des "instructions" que l'Arduino exécute...
    J'ai déjà programmé presque toutes ces fameuses "instructions" qui permettent d'afficher du texte et de dessiner des formes géométriques en couleur.
    Ces instructions couvrent l'ensemble des fonctions de l'afficheur TFT.
    Certaines instructions permettent aussi d'écrire ou de lire les broches d'entrée/sortie de l'Arduino (la demande de lecture impose logiquement à l'Arduino de faire un deuxième requête au serveur en passant en paramètre les valeurs lues)
    Ca fonctionne bien et c'est rapide, ça tiens dans la ROM (il me reste encore 22% de ROM de libre) et j'utilise très peu de RAM ce qui est une bonne surprise (quand j'ai expliqué ce que je voulais faire au début de mon projet, beaucoup de personnes se sont montrées septiques sur la capacité de l'Arduino UNO à gérer à la fois un écran TFT tactile et un shield Ethernet, moi-même je m'attendais à devoir utiliser un Arduino MEGA)

    Tout l'intérêt de cette Interface Homme Machine est son côté "universel" :
    - je commande tout depuis le serveur ;
    - le projet final comporte un serveur et plusieurs interfaces homme machine clientes
    le code contenu dans les Arduino des interfaces homme machine est en fait indépendant de l'application finale, ce qui a de nombreux avantages :
    => pour faire évoluer le projet je n'aurais besoin de ne mettre à jour que le code du serveur
    => ces interfaces homme machine pourront être utilisées ensuite dans n'importe quel projet, un câble Ethernet suffit et peut transporter données et alimentation sur une grande longueur de façon fiable
    => ces interfaces homme machine peuvent être adaptées en version WIFI en utilisant un autre type d'Arduino

    Donc voilà pourquoi je cherche à pouvoir afficher sur l'écran TFT un bitmap (un petit sprite) stocké en RAM.

    Pour conserver le côté "universel" de l'interface homme machine les bitmaps ne doivent pas êtres gravés en ROM mais stockés en RAM, en étant envoyés par le serveur.

    Si je veux changer le ou les bitmaps à afficher j'aurais juste besoin de mettre à jour le code sur le serveur.

    Merci

    A bientôt

  2. #2
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 002
    Par défaut
    Alors bonne nouvelle

    J'ai regardé le code de la bibliothèque PDQ_GFX, et les fonctions existent !

    Les auteurs de ce fork d'Adafruit GFX ont du avoir la même idée que moi.

    Il y a même la possibilité de dessiner des bitmaps avec une couleur de fond

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    // drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps.
    template<class HW>
    void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color)
    {
    	coord_t i, j, byteWidth = (w + 7) / 8;
    	uint8_t byte;
     
    	for (j = 0; j < h; j++)
    	{
    		for (i = 0; i < w; i++)
    		{
    			if (i % 8 == 0)
    				byte = bitmap[j * byteWidth + i / 8];
    			else
    				byte <<= 1;
     
    			if (byte & 0x80)
    				HW::drawPixel(x+i, y+j, color);
    		}
    	}
    }
     
    // drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps.
    template<class HW>
    void PDQ_GFX<HW>::drawBitmap(coord_t x, coord_t y, uint8_t *bitmap, coord_t w, coord_t h, color_t color, color_t bg)
    {
    	coord_t i, j, byteWidth = (w + 7) / 8;
    	uint8_t byte;
     
    	for (j = 0; j < h; j++)
    	{
    		for (i = 0; i < w; i++)
    		{
    			if (i % 8 == 0)
    				byte = bitmap[j * byteWidth + i / 8];
    			else
    				byte <<= 1;
     
    			if (byte & 0x80)
    				HW::drawPixel(x+i, y+j, color);
    			else
    				HW::drawPixel(x+i, y+j, bg);
    		}
    	}
    }

  3. #3
    Membre chevronné Avatar de electroremy
    Homme Profil pro
    Ingénieur sécurité
    Inscrit en
    Juin 2007
    Messages
    1 002
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Doubs (Franche Comté)

    Informations professionnelles :
    Activité : Ingénieur sécurité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2007
    Messages : 1 002
    Par défaut
    Bonjour,

    Il y a juste un truc bizarre...

    Mes données sont dans :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    #define Buffer_RAM_Len 512
    char Buffer_RAM[Buffer_RAM_Len];
    Buffer_RAM est rempli juste après le démarrage, lorsque mon Arduino client se connecte la première fois au serveur ; il contient toutes sortes de données que mon programme exploite ensuite.

    Ce code là, permettant d'afficher un texte terminé par un octet null stocké dans Buffer_RAM à partir de l'index pos, fonctionne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.print(Buffer_RAM + pos);
    En revanche pas celui là :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.drawBitmap(X1, Y1, Buffer_RAM + i + 2, Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], Couleur[j]);
    (les données bitmap "brutes" commencent à l'index i+2 de Buffer_RAM, l'octet à l'index i est la largeur, l'octet à l'index i+1 est la hauteur du bitmap)

    Pour ne pas avoir d'erreur de compilation, je dois faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    tft.drawBitmap(X1, Y1, (byte*)(Buffer_RAM + i + 2), Buffer_RAM[i], Buffer_RAM[i+1], Couleur[coul_index], Couleur[j]);
    Avec le C++ Arduino, parfois des cast sont requis, parfois pas, c'est difficile à deviner.
    Je suppose que le compilateur essaye de les ajouter lui-même lorsqu'ils sont manquants mais n'y arrive pas dans tous les cas de figure.
    Buffer_RAM[i] et Buffer_RAM[i+1] sont convertis en int sans problème, mais je dois forcer le cast (byte*) pour Buffer_RAM + i + 2

    A bientôt

  4. #4
    Expert confirmé

    Homme Profil pro
    mad scientist :)
    Inscrit en
    Septembre 2019
    Messages
    2 922
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Etats-Unis

    Informations professionnelles :
    Activité : mad scientist :)

    Informations forums :
    Inscription : Septembre 2019
    Messages : 2 922
    Par défaut
    Il ne s’agit pas de deviner - c’est déterministe: il faut simplement regarder quelle est la signature de la fonction.

    Ici elle attend un pointeur sur des entiers non signés (byte ou uint8_t) et donc comme votre buffer pointe sur des char (entiers signés) ça ne va pas, le compilateur ne trouve pas de fonction prenant en paramètre un pointeur vers des char. Il n’y a pas de promotion automatique.

    En lui disant “ignore le type que j’ai déclaré, je te promets que tu trouveras des bytes en suivant ce pointeur” le compilateur vous fera confiance et va chercher une fonction avec cette signature, là bingo il en trouve une dans la bibliothèque (et les données pointées comme non signées).

    ====

    De manière plus générale le type des variables que vous utilisez est super important. Ça aide le compilateur a allouer la mémoire qui va bien et aussi quand vous avez des pointeurs à aller chercher la bonne information: par exemple ici Buffer_RAM est un porteur sur char, donc Buffer_RAM+5 va chercher le 6ème caractère en mémoire, 5 octets plus loin puisque un char tient sur un octet. Mais si Buffer_RAM avait été déclaré comme un tableau d’entier alors Buffer_RAM+5 serait le 6ème entier et donc le compilo irait 10 octets plus loin car un entier tient sur 2 octets. => c’est pour cela que le typage est super important.

    Sinon quand vous accédez à un élément du tableau, La promotion d’un entier signé sur un octet vers un entier signé sur 2 octets est bien pris en charge par le compilo. Ces règles sont définies dans la spécification du langage C++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [DDraw] Débutant - Afficher BITMAP
    Par CodeCRC dans le forum DirectX
    Réponses: 9
    Dernier message: 22/06/2009, 10h24
  2. [Ecran TFT]Est-on limité à la résolution indiquée
    Par NicolasJolet dans le forum Périphériques
    Réponses: 6
    Dernier message: 06/09/2006, 20h25
  3. achat ecran tft par internet
    Par elekis dans le forum Périphériques
    Réponses: 7
    Dernier message: 27/07/2006, 21h17
  4. Nettoyage d'un ecran TFT
    Par Faith's Fall dans le forum Périphériques
    Réponses: 9
    Dernier message: 10/03/2005, 17h58
  5. Réponses: 3
    Dernier message: 31/01/2005, 15h22

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo