Emuler un écran TFT sous linux pour dev d'applications embarquées

Emuler un écran TFT sous linux pour dev d'applications embarquées - Codes et scripts - Linux et OS Alternatifs

Marsh Posté le 18-04-2012 à 18:18:27    

Bonjour à tous,
 
J'ai une carte microcontrôleur qui pilote en direct un écran tactile TFT couleur 480x272 pixels en 16 bits RGB 565. J'ai une RAM qui me sert de frame buffer, l'ecran fait 480x272 pixel, donc la zone framebuffer fait 261120 octets. Quand j'ai écris dans cette zone mémoire, ça affiche à l'écran.
 
Comme mon projet soft derrière est assez lourd, et que je code en C de façon portable en séparant les couches et en faisant une partie HAL (hardware abstraction layer), je peux développer mon code sur PC et le compiler pour la cible quand il est terminé.
Et du coup je voudrais émuler mon écran TFT sur ma machine linux. En gros j'ai juste besoin d'ouvrir une fenêtre de 480x272 pixel et qui représente un framebuffer virtuel 480x272 à partir d'une zone mémoire constituée d'un tableau de 130560 unsigned short. Quand j'écris dans cette zone mémoire (1 index de tableau = 1 pixel), ça doit s'afficher en conséquence dans la fenêtre.
 
Je pense que c'est pas sorcier à faire mais je suis un développeur embarqué, la prog gtk/qt ou autre j'y connais rien et ça me donne des boutons !!
 
Quelqu'un saurait-il quel environnement ou quelle technologie utiliser pour faire ça  :jap:


Message édité par nlc le 27-04-2012 à 23:58:45
Reply

Marsh Posté le 18-04-2012 à 18:18:27   

Reply

Marsh Posté le 18-04-2012 à 18:35:53    

J'ai trouvé ça, ça me parait pas mal comme point de départ : http://chl.be/glmf/kafka.fr.free.f [...] inter.html


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 19-04-2012 à 15:45:21    

Bon je me suis démerdé comme j'ai pu  :pt1cable:  
 
main.cpp :
 


#include <qapplication.h>
#include <qpainter.h>
#include <qlabel.h>
#include <qpixmap.h>
#include <qpaintdevice.h>
#include <qtimer.h>
#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
 
#include <pthread.h>
 
QApplication* app = new QApplication( 0, 0 );
QImage* image = new QImage(480,272, QImage::Format_RGB16);
QLabel myLabel;
 
 
 
 
static void timer50msInt ( int sig )
{
 signal( SIGALRM, timer50msInt );
 
 myLabel.setPixmap(QPixmap::fromImage(*image));
}
 
 
 
 
 
 
void _timerInit ( void )
{
 struct itimerval timer;
 
 timer.it_interval.tv_sec = 0;
 timer.it_interval.tv_usec = 50000;
 
 timer.it_value.tv_sec = timer.it_interval.tv_sec;
 timer.it_value.tv_usec = timer.it_interval.tv_usec;
 
 signal( SIGALRM, timer50msInt );
 
 setitimer( ITIMER_REAL, &timer, NULL );
}
 
 
 
 
 
 
 
void* monAppli ( void *ptr )
{
  unsigned char r = 0;
 
  while( 1 )
  { // Pour test, chaque seconde, modification de la composante rouge de tous les pixels
    // de l'image
    r+=128;
 
    for ( uint i = 0; i <480; i++ )
    { for ( uint j = 0; j <272; j++ )
      { QRgb pixel;
        pixel = qRgb(r,100,100);
        image->setPixel( i, j, pixel );
      }
    }
   
    sleep( 1 );
  }  
 
 return 0;
}
 
 
 
 
 
 
int main (int argc, char* argv[])
{
 
 pthread_t thread;
 
 // Création du thread de l'appli qui va utiliser l'ecran émulé
 
 pthread_create( &thread, NULL, monAppli, (void*) NULL);
 
 // Création de l'écran émulé, une image 480x272
 myLabel.setPixmap(QPixmap::fromImage(*image));
 myLabel.show();
 
 // Init du timer, toute les 50ms l'écran émulé est raffraichi avec l'image  
 _timerInit();
 
 return app->exec() ;
}


 
Je crée une image qui représente mon écran TFT, et par un timer je raffraichis le contenu de mon QLabel avec cette image toutes les 50ms (20Hz)
 
Et depuis l'autre thread, qui sera mon application utilisant l'écran (et qui sera ensuite embarquée dans ma carte électronique), je mets à jour l'écran (l'image) comme je veux pixel par pixel.
Ca me met ce warning de temps en temps en console mais pas grave ! QPixmap: It is not safe to use pixmaps outside the GUI thread
 
Ma couche d'abstraction se fera donc non pas sur une zone mémoire représentant mon framebuffer mais sur 2 fonctions setPixelColor(x, y, color) et getPixelColor(x, y).
 
Dans ma carte électronique ces 2 fonctions écriront/liront dans le frame buffer, et sur le PC ça écrira/lira dans l'image...
 
Allez je mets en résolu !


Message édité par nlc le 19-04-2012 à 18:56:15

---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 19-04-2012 à 16:15:45    

Oui ça marche, c'est tout crados mais pour ce que c'est supposé faire c'est parfait :-)


---------------
Un blog qu'il est bien
Reply

Marsh Posté le 19-04-2012 à 17:50:11    

ouais j'y connais rien en qt, si t'as mieux je prends !!


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 19-04-2012 à 18:39:10    

nlc a écrit :

ouais j'y connais rien en qt, si t'as mieux je prends !!


Pour éviter le warning, je pense qu'utiliser qthread permettrait d'éviter le warning. Mais comme tu le dis, tu t'en fout pas mal  :whistle:


Message édité par guepe le 19-04-2012 à 18:39:23

---------------
Un blog qu'il est bien
Reply

Marsh Posté le 19-04-2012 à 18:53:52    

Bah d'habitude j'aime bien les trucs propres, mais là c'est vrai que c'est juste pour quand je développe mon code embarqué sur le PC, donc bon, je crois en effet que je vais pas me casser la tête :D


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 19-04-2012 à 19:07:34    

Ah si j'ai oublié un truc :D
 
Maintenant va falloir que je récupère des évènements de clic souris avec l'emplacement X/Y pour faire une couche d'abstraction de simulation de l'écran tactile :/


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 19-04-2012 à 19:27:02    

nlc a écrit :

Ah si j'ai oublié un truc :D
 
Maintenant va falloir que je récupère des évènements de clic souris avec l'emplacement X/Y pour faire une couche d'abstraction de simulation de l'écran tactile :/


Qt fait ca très bien (note, j'ai pas beaucoup beaucoup bossé sur qt) : je sais plus trop, faut récupérer les évènements de la souris dans la zone de ton écran. Il te faut un widget qui puisse le récupérer (quel type est ton "écran" virtuel ?)
 
Ceci dit, si un modo passe, ce serait bien d'envoyer le topic dans prog.


---------------
Un blog qu'il est bien
Reply

Marsh Posté le 19-04-2012 à 20:57:13    

:hello:
 
je pense que tu peux creer ta propre classe derivant du widget "Qlabel" pour surcharger les events de type QMouseEvent
ca devrait etre assez leger a faire ... a priori;)

Reply

Marsh Posté le 19-04-2012 à 20:57:13   

Reply

Marsh Posté le 28-04-2012 à 00:05:49    

Bon j'ai réussi à me démerder pour simuler l'écran tactile mais c'est tout pourri ça marche mal, après le lancement de l'appli ça finit par planter au bout d'un moment avec :
 

Citation :

[nlc@localhost calculateurVElibMicrochip]$ ./Debug/calculateurVEframebuffer  
QApplication: Invalid Display* argument
QPixmap: It is not safe to use pixmaps outside the GUI thread
 
---> ici l'appli fonctionne un certain temps, mon programme C fait des affichages et l'interaction avec l'ecran tactile virtuel marche, puis au bout d'un moment :
 
unknown: Fatal IO error: client killed
Erreur de segmentation


Y aurait-il moyen de déplacer ce fil dans programmation/c++ ? En éditant le message je ne peux que changer la sous catégorie :(
Et en fait je suis pas vraiment au bon endroit vu que malgré que je tourne sous linux le programme c'est du C/C++/QT donc pas lié à la catégorie OS alternatif :)


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 28-04-2012 à 00:16:03    

j'ai oublié de poster mon code dégueu ! Pour rappel, je veux simuler un écran TFT tactile, avec une interface API très simple avec un programme écrit en C (qui sera ensuite embarqué dans un microcontrôleur). Au niveau de l'api il y a 3 choses à faire avec le code C++ :
- changer la couleur d'un pixel dont je fournis les coordonnées : void _PutPixel(short x, short y, short color )
- récupérer la couleur d'un pixel dont je fournis les coordonnées : short _GetPixel(short x, short y )
- récupérer les coordonnées X/Y de la souris et l'état des bouton de la souris (pour l'instant je suis en variables globales)
 
Voici le code pourri de mon main.cpp :

Code :
  1. #include <qapplication.h>
  2. #include <qpainter.h>
  3. #include <qlabel.h>
  4. #include <qpixmap.h>
  5. #include <qpaintdevice.h>
  6. #include <qtimer.h>
  7. #include <stdio.h>
  8. #include <signal.h>
  9. #include <sys/time.h>
  10. #include <pthread.h>
  11. QApplication* app = new QApplication( 0, 0 );
  12. QImage* image = new QImage(480,272, QImage::Format_ARGB32);
  13. QLabel myLabel;
  14. // Passerelle avec l'appli en C (mainDemo plus bas)
  15. extern "C" {
  16. int mainDemo (void);
  17. // Permet de changer la couleur d'un pixel de l'ecran TFT virtuel
  18. void _PutPixel(short x, short y, short color );
  19. // Permet de récupérer la couleur d'un pixel de l'ecran TFT virtuel
  20. unsigned short _GetPixel(short x, short y );
  21. // Permet de connaitre la position X/Y de la souris sur l'ecran TFT virtuel et l'état des boutons
  22. extern short mouseX, mouseY, mouseState;
  23. }
  24. // Fonctions utilisées par le programme C pour modifier un pixel de l'ecran
  25. // ou récupérer la valeur d'un pixel de l'ecran
  26. #define GFX_COLOR unsigned short
  27. #define RGBConvert(red, green, blue)    (GFX_COLOR) (((((GFX_COLOR)(red) & 0xF8) >> 3) << 11) | ((((GFX_COLOR)(green) & 0xFC) >> 2) << 5) | (((GFX_COLOR)(blue) & 0xF8) >> 3))                                             
  28. void _PutPixel(short x, short y, short color )
  29. {
  30. QRgb pixel;
  31. pixel = qRgb( ((color>>11)&0b11111)<<3, ((color>>5)&0b111111)<<2, (color&0b11111)<<3 );
  32. image->setPixel( x, y, pixel );
  33. }
  34. unsigned short _GetPixel(short x, short y )
  35. {
  36. QRgb color;
  37. color = image->pixel(x, y);
  38. return( RGBConvert( (color>>16)&0xFF,(color>>8)&0xFF,color&0xFF ) );
  39. }
  40. // Fonction appelée toutes les 50ms, permet de simuler un raffraichissement de
  41. // l'écran TFT à 20Hz
  42. static void timer50msInt ( int sig )
  43. {
  44. QPoint mousePos;
  45. QRect geom;
  46. int mouseButton, x, y;
  47. signal( SIGALRM, timer50msInt );
  48. // Mise à jour de l'image dans le widget myLabel
  49. myLabel.setPixmap(QPixmap::fromImage(*image));
  50. // On récupère les coordonnées brutes de la souris que l'on convertit en coordonnées
  51. // dans la fenetre en fonction de la position de la fenetre
  52. mousePos = QCursor::pos();
  53. x = mousePos.x();
  54. y = mousePos.y();
  55. geom = myLabel.geometry();
  56. x = x - geom.x();
  57. y = y - geom.y();
  58. // On récupère l'état des boutons de la souris
  59. mouseButton = app->mouseButtons();
  60. // On passe les données X/Y + états bouton souris au programme C
  61. mouseX = x;
  62. mouseY = y;
  63. mouseState = mouseButton;
  64. // printf( "%d %d %dn", x, y, mouseButton );
  65. }
  66. // Mise en route de la fonction périodique 50ms timer50msInt  
  67. void _timerInit ( void )
  68. {
  69. struct itimerval timer;
  70. timer.it_interval.tv_sec = 0;
  71. timer.it_interval.tv_usec = 50000;
  72. timer.it_value.tv_sec = timer.it_interval.tv_sec;
  73. timer.it_value.tv_usec = timer.it_interval.tv_usec;
  74. signal( SIGALRM, timer50msInt );
  75. setitimer( ITIMER_REAL, &timer, NULL );
  76. }
  77. // Thread permettant d'appeler l'appli en C qui utilise l'ecran TFT virtuel
  78. void* monAppli ( void *ptr )
  79. {
  80. usleep( 200000 );
  81. // Appel de timer50msInt() toutes les 50ms
  82. _timerInit();
  83. // Applicatif qui utilise l'ecran TFT virtuel (ne rend pas la main)
  84. mainDemo();
  85. return 0;
  86. }
  87. int main (int argc, char* argv[])
  88. {
  89. pthread_t thread;
  90. // Création du thread de l'appli qui va utiliser l'ecran émulé
  91. pthread_create( &thread, NULL, monAppli, (void*) NULL);
  92. // Création de l'écran émulé, une image 480x272
  93. myLabel.setPixmap(QPixmap::fromImage(*image));
  94. myLabel.show();
  95. return app->exec() ;
  96. }


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 28-04-2012 à 18:42:36    

Bon j'ai trouvé la solution !! C'est tout con, ne pas utiliser QT !! :D
J'utilise directement la Xlib qui permet d'utiliser Xwindow directement depuis du C.
 
C'est même plus simple mon écran virtuel c'est juste une zone mémoire (framebuffer), et toutes les 50ms je recopie l'intégralité de l'image à l'écran avec des XDrawPoint()
 
Et pour récupérer les évenements souris ça va être très simple aussi, tout ce la devrait marcher ce soir !


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Marsh Posté le 29-04-2012 à 01:32:43    

Bon c'est bon tout marche nickel, sans QT  :whistle:  
 
Et là c'est bien propre pas de message d'erreur, et tout est directement en C  :lol:  
 
Pour les curieux, mon tft.c :
 

Code :
  1. #include <X11/Xlib.h>
  2. #include <X11/Xutil.h>
  3. #include <signal.h>
  4. //
  5. // Abstraction layer for TFT screen, in PC mode the TFT screen is an X11 window
  6. //
  7. #define TFT_WIDTH  480
  8. #define TFT_HEIGHT 272
  9. // X11 Display, non static because used in touchscreen.c for mouse events
  10. Display* display;
  11. // X11 Window, non static beacause used in touchscreen.c for mouse events
  12. Window window;
  13. // Graphics Context
  14. static GC gc;
  15. // TFT Image content, based on framebuffer[][] data
  16. static XImage* tftImage; 
  17. // TFT framebuffer, used as data for tftImage
  18. static unsigned int framebuffer[TFT_WIDTH][TFT_HEIGHT];
  19. #define RGB565_TO_RBG24(c) ((((c>>11)&0b11111)<<19) | (((c>>5)&0b111111)<<10) | ((c&0b11111)<<3))
  20. void _tftPixelSet ( short x, short y, short color )
  21. {
  22. XPutPixel( tftImage, x, y, RGB565_TO_RBG24(color) );
  23. }
  24. #define RGB24_TO_RBG565(c) ((((c>>19)&0b11111)<<11) | (((c>>10)&0b111111)<<5) | ((c>>3)&0b11111))
  25. short _tftPixelGet ( short x, short y )
  26. {
  27. return( RGB24_TO_RBG565( framebuffer[x][y] ) );
  28. }
  29. int _tftInit ( void )
  30. {
  31. int x, y;
  32. // Window and graphic context construction
  33. display = XOpenDisplay(NULL);
  34. window = XCreateSimpleWindow(display, RootWindow(display, 0), 1, 1, 480, 272, 0, 0x000000, 0x000000);
  35. XStoreName( display, window, "Emulated TFT touchscreen" );
  36. XMapWindow(display, window);
  37. gc = XCreateGC(display, window, 0, 0);
  38. // Image definition, image datas based on framebuffer content
  39. tftImage = XCreateImage (display, DefaultVisual (display, 0), 24, ZPixmap, 0, (char*)framebuffer,
  40.                           TFT_WIDTH, TFT_HEIGHT, 8 * sizeof(unsigned int), 0);
  41. tftImage->byte_order = LSBFirst;
  42. // framebuffer initialisation, all pixels black
  43. for ( x=0 ; x<TFT_WIDTH ; x++ )
  44. { for ( y=0 ; y<TFT_HEIGHT ; y++ )
  45.     XPutPixel( tftImage, x, y, 0x000000 );
  46. }
  47. return 0;
  48. }
  49. void _tft10msInt ( void )
  50. {
  51. // Periodic interrupt function called every 10ms
  52. // Refresh image content in the X11 window
  53. if ( display )
  54.      { XPutImage (display, window, gc, tftImage, 0, 0, 0, 0, TFT_WIDTH, TFT_HEIGHT);
  55.        XFlush(display);
  56.      }
  57. }


Gros avantage, pas de thread, le main() de mon programme appelle normalement _tftInit() exactement comme il le fait quand le programme tourne dans ma carte électronique, et ça met en route l'écran TFT virtuel. Ensuite tout passe par _tfpPixelSet() et _tfpPixelGet() pour afficher sur l'écran. Il faut juste appeler _tft10msInt() toutes les 10ms pour le rafraîchissement "de l'écran"
 
J'ai pu faire tourner la démo des primitives de la librairie graphique Microchip ça fonctionne bien : http://www.youtube.com/watch?v=-dZJYgEEJrY
 :bounce:  
 
Pour la partie emulation de la dalle tactile j'ai mis ça dans touchpanel.c, et ça marche nickel aussi, le programme pense qu'il tourne dans la carte électronique et n'y voit que du feu  :whistle:  
 

Code :
  1. #include <stdio.h>
  2. #include <X11/Xlib.h>
  3. #include <X11/Xutil.h>
  4. #include <signal.h>
  5. //
  6. // Abstraction layer for touchpanel, in PC mode the touchpanel is based on X11 events
  7. //
  8. // External X11 window and display (in tft.c)
  9. extern Display* display;
  10. extern Window window;
  11. // X coordinate of touch location, or -1
  12. static short touchX;
  13. // X coordinate of touch location, or -1
  14. static short touchY;
  15. short _touchpanelGetX ( void )
  16. {
  17. return( touchX );
  18. }
  19. short _touchpanelGetY ( void )
  20. {
  21. return( touchY );
  22. }
  23. int _touchpanelInit ( void )
  24. {
  25. // Request X11 events we need  
  26. XSelectInput(display, window, PointerMotionMask | ButtonPressMask | ButtonReleaseMask );
  27. touchX = touchY = -1;
  28. return 0;
  29. }
  30. void _touchpanel10msInt ( void )
  31. {
  32. // Read all X11 pending events and update touchX and touchY values with touch
  33. // coordinate or -1 if touchpanel not touched
  34. XEvent event; // X11 Event
  35. while ( XPending( display ) != 0 )
  36. { XNextEvent( display, &event );
  37.    switch( event.type )
  38.    { case ButtonPress :
  39.           if ( event.xbutton.button == Button1 )
  40.               { touchX = event.xbutton.x;
  41.                 touchY = event.xbutton.y;
  42.               }
  43.           break;
  44.      case ButtonRelease :
  45.           if ( event.xbutton.button == Button1 )
  46.               { touchX = -1;
  47.                 touchY = -1;
  48.               }
  49.           break;
  50.      case MotionNotify :
  51.           if ( touchX!=-1 && touchX!=-1 )
  52.               { touchX = event.xmotion.x;
  53.                 touchY = event.xmotion.y;
  54.               }
  55.           break;
  56.    }
  57. }
  58. }


---------------
char table[] = {112,114,105,110,116,102,40,34,37,99,37,99,37,99,34,44,49,49,48,44,49,48,56,44,57,57,41,59,0}; char* tablePtr = table; while(*tablePtr) printf( "%c",*tablePtr++ );
Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed