wiki:Peri19_T04

Ce TME a été créé par Julien Peeters et modifié par Franck Wajsbürt

TP3 : Pilotage d'un écran LCD en mode utilisateur et par un driver

Objectifs:

  • Fonctionnement d'un écran LCD et fonctions de base
  • Ecriture d'un driver d'affichage
  • Usage de IOCTL
  • Affichage du monitoring système

Pré-requis (Raspberry Pi):

  • Outils de compilation croisée
  • Configuration et utilisation des GPIO

Ressources:

Prenez le temps de parcourir les documents sur les afficheurs avant de commencer le TP.

Le code à modifier se trouve en pièces jointes de cette page lcd_user.c et Makefile. Vous pourrez les copier dans un répertoire TP4/lcd_user/

1. Configuration des GPIO pour le pilotage de l'écran

L'écran LCD de type HD44780 dispose de plusieurs signaux de contrôle et de données. Les signaux de contrôle sont au nombre de 3: RS, RW et E. Les signaux de données sont au nombre de 4 ou 8 suivant le mode.

Dans ce TP, nous utiliserons l'écran en mode 4-bit car la carte Raspberry Pi dispose d'un nombre limité de GPIO. De plus, le signal RW sera connecté directement à 0V (donc toujours en écriture) car nous n'allons gérer que les opérations d'écriture (Note: les GPIO de la carte Raspberry Pi fonctionnent en 3.3V, ils ne supportent pas les niveaux de tension 5V émis par l'afficheur, demandez-moi cela n'est pas clair).

Les signaux de contrôle RS et E sont utilisés de la manière suivante:

  • RS vaut 1 pour l'envoi d'une donnée (e.g. un caractère) et vaut 0 pour l'envoi d'une commande (instruction).
  • E est un signal de validation; la valeur sur le bus de données (4 bits) est pris en compte à chaque front descendant de ce signal.

Voici le mapping des GPIO pour les différents signaux:

Signal LCD GPIO
RS 7
E 27
D4, D5, D6, D7 22, 23, 24, 25

Dans la documentation de l'afficheur, on peut savoir :

  • Comment faut-il configurer les GPIOs pour les différents signaux de l'afficheur LCD ?
  • Comment écrire des valeurs vers le LCD ?
  • Quelles valeurs doivent être envoyées vers l'afficheur pour réaliser l'initialisation ?
  • Comment demander l'affichage d'un caractère ?
  • Comment envoyer des commandes telles que : l'effacement de l'écran, le déplacement du curseur, etc. ?

En particulier, page 11 de la documentation ( Datasheet du LCD de la plateforme) se trouve du pseudo-code pour l'usage de l'afficheur.

  • P1 est un registre dont l'état est recopié sur les broches D0 à D7 (bit7 de P1 sur D7, bit6 sur D6, etc. jusqu'à D4).
  • D_I est un registre dont l'état est recopié sur RS qui indique si on envoie un caractère (D) ou une instruction (I).
  • R_W est un registre dont l'état est recopié sur RW
  • Delay() est une attente en microsecondes.
4-bit Initialization: 
/**********************************************************/ 
void command(char i) 
{ 
  P1 = i;                       //put data on output Port 
  D_I =0;                       //D/I=LOW : send instruction 
  R_W =0;                       //R/W=LOW : Write       
  Nybble();                     //Send lower 4 bits 
  i = i<<4;                     //Shift over by 4 bits 
  P1 = i;                       //put data on output Port 
  Nybble();                     //Send upper 4 bits 
} 
/**********************************************************/ 
void write(char i) 
{ 
  P1 = i;                       //put data on output Port 
  D_I =1;                       //D/I=HIGH : send data 
  R_W =0;                       //R/W=LOW : Write    
  Nybble();                     //Clock lower 4 bits 
  i = i<<4;                     //Shift over by 4 bits 
  P1 = i;                       //put data on output Port 
  Nybble();                     //Clock upper 4 bits 
} 
/**********************************************************/ 
void Nybble() 
{ 
  E = 1; 
  Delay(1);                     //enable pulse width  >= 300ns 
  E = 0;                        //Clock enable: falling edge 
} 
/**********************************************************/ 
void init() 
{ 
  P1 = 0; 
  P3 = 0; 
  Delay(100);                   //Wait >40 msec after power is applied 
  P1 = 0x30;                    //put 0x30 on the output port 
  Delay(30);                    //must wait 5ms, busy flag not available 
  Nybble();                     //command 0x30 = Wake up  
  Delay(10);                    //must wait 160us, busy flag not available 
  Nybble();                     //command 0x30 = Wake up #2 
  Delay(10);                    //must wait 160us, busy flag not available 
  Nybble();                     //command 0x30 = Wake up #3 
  Delay(10);                    //can check busy flag now instead of delay 
  P1= 0x20;                     //put 0x20 on the output port 
  Nybble();                     //Function set: 4-bit interface 
  command(0x28);                //Function set: 4-bit/2-line 
  command(0x10);                //Set cursor 
  command(0x0F);                //Display ON; Blinking cursor 
  command(0x06);                //Entry Mode set 
} 
/**********************************************************/ 

2. Fonctionnement de l'écran et fonctions de base

La prise en compte de la donnée est réalisée lors d'un front descendant du signal E. Pour créer un front descendant:

  • on place la donnée,
  • puis le signal E est mis à 1 pendant 1µs.

command_lcd.png

Nous utilisons l'afficheur LCD en mode 4 bits. Or, les commandes et les données sont transmises sur 8 bits ou 1 octet. Ainsi, toutes les commandes et toutes les données sont transmises en deux étapes: les 4 bits de poids fort et ensuite les 4 bits de poids faible.

Nous avons toutes les fonctions dont nous avons besoin. Maintenant regardons d'un peu plus près la phase d'initialisation de l'afficheur LCD. Au démarrage, l'afficheur est dans un mode non défini (8 bits ou 4 bits). Il faut donc le forcer en mode 4 bits.

Vous êtes prêt à tester votre code et vérifier qu'il affiche correctement une chaine de caractère. erry Pi.

Il peut être utile de manipuler la position du curseur pour choisir où placer les caractères sur l'afficheur.

Pour cela, l'afficheur dispose de trois instructions: Cursor home, Display clear et Set DDRAM address. La dernière instruction est relative à la mémoire interne de l'afficheur (Display Data RAM).

La mémoire DDRAM est construite de la manière suivante:

0x00 ..... Ligne 1 ..... 0x13
0x40 ..... Ligne 2 ..... 0x53
0x14 ..... Ligne 3 ..... 0x27
0x54 ..... Ligne 4 ..... 0x67

On souhaites utiliser toutes les lignes

Questions:
1. Répondez aux questions qui se trouve dans le code lcd_user.c
2. Ecrire une fonction lcd_set_cursor qui positionne le curseur aux coordonnées (x,y) avec x la colonne, y la ligne.
3. Ecrire un programme qui affiche la chaine passée en paramètre sur chacune des lignes de l'afficheur.

4. Driver pour le LCD

  • Reprenez le pilote que vous aviez écrit pour les leds et modifiez la commande write de telle sorte que si vous appelez votre device /dev/lcd_xy (où xy sont les initiales de votre binôme), vous puissiez écrire.
    $ echo "Bonjour" > /dev/lcd_xy
    
    Vous allez devoir remplacer usleep() par udelay() et ajouter un #include <asm/delay.h> au début du code de votre module (merci Arthur). Vous devez (en principe) allouer de la mémoire noyau pour ce driver et utiliser la fonction copy_from_user(unsigned long dest, unsigned long src, unsigned long len); pour le message à écrire.
  • Ajoutez la gestion de l'appel système ioctl() pour
    • effacer l'écran : LCDIOCT_CLEAR
    • position le curseur : LCDIOCT_SETXY (vous pouvez coder les coordonnées dans l'argument).
Last modified 5 years ago Last modified on Mar 8, 2019, 1:26:40 PM

Attachments (2)

Download all attachments as: .zip