SE3 PSE Binome2023-5

De projets-se.plil.fr
Aller à la navigation Aller à la recherche

Projet système embarqué de Rémi BOURSAULT et Antoine LECOMTE

L'objectif de ce module est de modéliser une manette, puis de la rendre fonctionnelle, pour jouer au jeu Space Invaders qui est codé dans le même module.

Les professeurs avaient préalablement fourni un dossier contenant un modèle de PCB incomplet et différents fichiers ".c" et ".h" pour nous aider à démarrer.

Création de Manette

La création de la manette commence par la création sur kicad d'un PCB. Nous avons pris celui fourni sur le wiki du projet qui possède tous les composants mais non routés.



Modélisation PCB

A partir du fichier KiCad fourni, nous avons modélisé un PCB déstiné à être utilisé comme manette. Nous avons donc ajouté des boutons, replacé ces derniers. Grâce au schéma nous avons sélectionné des PIN pour connecter les boutons, ainsi que des LEDs et des résistances que nous avons aussi ajouté.

Voyant que nous avions encore de l'espace de libre sur notre carte, étant un peu ambitieux et voyant que le procédé n'est pas bien compliqué, nous décidons alors de rajouter quelque boutons et quelques LEDs en plus pour que notre manette soit un peu plus crédibles.

Il nous a alors fallu rajouté les dit composants sur notre schéma pour que ceux-ci soient rajoutés automatiquement sur le PCB lors de l'utilisation de la fonction "Update PCB with changes made to schematic"



Ajout du plan de masse et des via


Une fois le routage effectué, nous avons ajouté un plan de masse et ajouté une grande quantité de via à différent endroits de la carte pour que la masse soit bien connectée et éviter les fuites thermiques de certains composants.

Ensuite le fichier a été envoyé pour impression en Chine, grâce au fichier Gerber généré par KiCad que vous pouvez retrouvez sur notre GIT:


Rendu 3D final de la carte

Programmateur AVR

En attendant de recevoir les cartes, nous nous sommes initiés à la programmation d'un périphérique USB, nous avons utilisé les bibliothèques LUFA et LibUSB pour utilisé un programmateur AVR. Il nous a fallu également modifier des fichiers Descripteurs, en ".c" et ".h" qui permettent, une fois téléversés dans le programmateur, d'être détecter par le PC et que celui-ci reconnaisse les fonctionnalités du périphérique (InPoint et EndPoint).


Soudure de la carte

Une fois la carte reçu, nous avons pris tous nos composants et avons commencé à les souder. N'ayant que très peu d'expérience dans ce domaine ce n'était pas quelque chose de facile au début. Il nous a fallu un peu d'aide et pas mal de flux pour comprendre comment faire des soudures propres. Une fois le coup de main pris, la fin du montage de la carte était assez rapide. Nous avons donc pu passer à la programmation pour la reconnaissance par l'ordinateur de notre carte.

Carte vierge
Carte avec tous les composants soudés


Une fois la carte soudée il a fallu pouvoir la configurer pour par la suite pouvoir la programmer. Pour se faire il faut lui injecter un bootloader via son programmateur ISP. Ce qui passe la manette en mode DFU et elle est alors reconnu par l'ordinateur.

Manette reconnu en mode DFU

LUFA de la manette

Après avoir reçu les cartes et terminé de souder les composants nous avons pu attaquer la programmation du microcontrôleur pour pouvoir utiliser la manette. Nous avons procédés étape par étape, en commençant par allumé les LEDs puis réceptionner les signaux des boutons pour finir par fusionner les deux pour avoir une manette fonctionnelle.

LEDs

Pour éviter un décalage sur le portF il faut désactiver le JTAG en copiant deux fois cette ligne au niveau de la déclaration des pins : MCUCR |= (1<<JTD);cela permet d'accéder aux LEDs sur les pins PF4 et PF5.

Une fois la configuration terminé, nous avons testé nos LEDs avec la fonction suivante :

void blink_leds(void){
  PORTF |= 0b00110011;
  _delay_ms(200);
  PORTF &= ~0b00110011;
  _delay_ms(200);
  PORTF |= 0b00110011;
  _delay_ms(200);
  PORTF &= ~0b00110011;
}

Ce qui nous donne ce résultat



Nous avons également fait la fonction EtatLED dans le fichier USBFinal.c (fichier servant à détecter et communiquer avec la manette par le port USB) qui se trouve dans le dossier libUSB, qui sert à allumer ou éteindre la LED de son choix.

Celle ci utilise le device, handle et configuration descriptor qui ont été définies dans des fonctions précédentes, disponible sur le git dans usbfinal.c ,grandement inspirées de ce qui est donné sur le site de Monsieur Redon, qui sélectionnent la manette et le config descriptor. On aurait dû également sélectionner l'interface dans cette fonction précédente plutôt que de le faire dans EtatLED mais nous nous en sommes rendus compte trop tard.

void EtatLED(int etat, int numLED, libusb_device *manette, libusb_device_handle *handle, struct libusb_config_descriptor *configdesc)
{
    int indint=0;/* e.g. première interface */
    int indalt=0; /* e.g. première alternative */
    int interface=1; //;configdesc->interface[indint].altsetting[indalt].bInterfaceNumber;
    int status=libusb_claim_interface(handle,interface);

    if(status!=0)
    {
            printf("bij\n");
        perror("libusb_claim_interface");
        exit(-1);
    }

    printf("Interface %d claimed\n",interface);

    unsigned char data = 0;
    if(etat){
       switch (numLED){
        case 1:
            data = 0x01;
            break;
        case 2:
            data = 0x02;
            break;
        case 3:
            data = 0x03;
            break;
        case 4:
            data = 0x04;
            break;
        default:
            printf("Selectionnez un chiffre entre 1 et 4");
        }
    }else{
        switch (numLED){
        case 1:
            data = 0x11;
            break;
        case 2:
            data = 0x12;
            break;
        case 3:
            data = 0x13;
            break;
        case 4:
            data = 0x14;
            break;
        default:
            printf("Selectionnez un chiffre entre 1 et 4");
        }
    }

Exemple d'appel dans le main EtatLED(0,1, manette, handle, configdesc);. La fonction va éteindre la LED 1.

Boutons

Les LEDs étant configuré il est temps de passer à l'utilisation des boutons. Le principe reste globalement le même, on modifie les fichiers descriptors et minimal selon nos besoins. Pour nous faciliter un peu la tâche nous avons pris les fichiers déjà existant pour des joysticks. Nous allons considérer que si un de nos boutons est appuyé cela reviendra au même que si un joystick est dirigée au maximum dans une direction donnée.


La modification majeure à faire pour que nos boutons soit détecté était sur la fonction

bool GetNextReport(USB_JoystickReport_Data_t* const ReportData)
{
  static uint8_t PrevJoyStatus    = 0;
  static uint8_t PrevButtonStatus = 0;
  bool           InputChanged     = false;

  /* Clear the report contents */
  memset(ReportData, 0, sizeof(USB_JoystickReport_Data_t));

  if(~(PIND>>PD4) & 1){
    ReportData->X = -100;
  }
  if(~(PIND>>PD7) & 1){
    ReportData->X =  100;
  }
  if(~(PIND>>PD6) & 1){
    ReportData->Y = -100;
  }
  if(~(PINB>>PB4) & 1){
    ReportData->Y =  100;
  }
  if(~(PINF>>PF7) & 1){
    ReportData->Button |= (1 << 0);
  }
  if(~(PINF>>PF6) & 1){
    ReportData->Button |= (1 << 1);
  }
  /* Return whether the new report is different to the previous report or not */
  return InputChanged;
}

Cela nous permet de dire que si un bouton que nous avons configuré est enfoncé, on met la direction X ou Y à plus ou moins 100. Nous les avons tester avec jstest-gtk qui permet de visualiser les directions et appuis d'un joystick, tous nos boutons sont reconnus et configurés comme nous le souhaitons.

Regroupement des deux

Pour avoir une manette fonctionnelle à 100% la dernière étape est de fusionner les différents fichiers pour les LEDs et pour les boutons pour que tout soit utilisable en même temps. Pour cela il a fallu modifié le fichier Descritors.c, dans la fonction

const USB_Descriptor_Configuration_t PROGMEM ConfigurationDescriptoril faut indiquer le nombre d'interface à deux, puis rajouter une interface. Dans notre cas étant parti du fichier des boutons nous avons rajouté celle des LEDs. Une fois ceci fais, il ne restait plus qu'à rajouter les fonctions de chaque partie dans un même fichier .c et nous avons fini la configuration et la programmation de notre manette.

Implémentation dans le Space Invaders

Ajout des boutons

On va dans cette partie utiliser tout ce qui a été implémenté pour rendre la manette utilisable avec le jeu Space Invaders codé en parallèle.

D'abord, on a, grâce au tutoriel fourni, ajouté l'utilisation des boutons avec la librairie SDL. Il nous a suffit de créer une fonction qui d'abord initialise notre manette en détectant le nombre de Joystick que celle ci possède.

Initialisation de la manette


Ensuite, on a créé une fonction handleControllerReformed qui pendant que le jeu tourne vient récupérer les valeurs des axes et des boutons de la manette en utilisant le pointeur initialisé par JoystickInitialisation.

Fonction récupérant la valeur des axes et des boutons

Maintenant que nous avons les valeurs des boutons et des axes à chaque instant, nous pouvons les utiliser comme input dans nos programmes pour, par exemple, les déplacements du vaisseau et le lancer de missiles. La valeur des axes est toujours maximale car notre joystick est en fait 4 boutons interprétés comme un Joystick, c'est pour cela qu'on vient comparer leurs valeurs aux valeurs maximales envoyés par un Joystick (32767 et -32768). Les boutons sont des booléens qui retournent 1 quand ils sont à l'état bas et 0 à l'état haut.

Fonction permettant de faire se déplacer le joueur au clavier ou à la manette
Fonction permettant d'ajouter un missile si l'on appuie sur e ou sur un bouton.











Vous pouvez voir le résultat de l'implémentation totale des boutons :



Ajout des Diodes Électro-Luminescentes (la classe)

Pour utiliser les LEDs, c'est légèrement plus compliqué. Le code que nous avions fait précédemment dans usbfinal.c, notamment EtatLED, va nous être utile. On va transformer ce fichier usbfinal.c en une librairie dynamique en .so. Grâce à ça, on va pouvoir réutiliser la fonction EtatLED dans notre programme pour le jeu et l'appeler directement dans des fonctions.

Pour faire cela, on va compiler en utilisant des options particulières pour gcc. La commande est gcc -fPIC -shared -o libusbfinal.so usbfinal.c -lusb-1.0. L'option -fPIC permet de génerer du code indépendant de l'emplacement mémoire auquel il est chargé. L'option -shared permet de génerer une bibliotèque partager plutôt qu'un executable, et -lusb-1.0 permet d'indiquer au compilateur qu'on utilise libusb 1.0 dans ce fichier C.

On se retrouve alors avec un fichier .so disponible dans le git (dans les fichiers LUFA, répértoire libUSB, le chemin précis est spécifié dans le readme).

Ce fichier est la bibliothèque dynamique qu'on peut appeler dans notre makefile.

Makefile pour le jeu, adapté à l'utilisation de la manette


On voit qu'il faut rajouter dans l'éxecution la commande export LD_LIBRARY_PATH=./src/include:$$LD_LIBRARY_PATH && ./$(TARGET) (nécessaire pour indiquer l'emplacement des bibliothèques dynamiques), et éxecuter la commande sudo make run pour lancer le jeu (libusb nécessite d'avoir les droits administrateurs).

On peut alors dans le fichier source C spaceinvaders ajouter le fichier d'en-tête associé à la librairie usbfinal.h également disponible dans le git, et utiliser toutes les fonctions crééés dans usbfinal.c. On a finalement créé une fonction displayLivesLEDs qui vient alumer le nombre de LEDs correspondant au nombre de vies restantes, qu'on appelle à chaque fois que le joueur est touché pour éviter des appels inutiles (tant que l'on ne fait rien, les LEDs gardent leur état).

Fonction de gestion des LEDs

Le résultat final avec implémentation des LEDs :


On peut également vous fournir le .zip du jeu spaceinvaders avec l'implémentation de la manette si besoin (trop volumineux pour le wiki) en nous contactant par mail (remi.boursault@polytech-lille.net).

CONCLUSION

On a fini.

Plus sérieusement, la manette possède les fonctionnalités attendues. Les fichiers LUFA permettent de faire comprendre à un PC qu'elle est constitué d'un Joystick, de deux boutons et de 4 LEDs. On a également réussi à utiliser tous ces éléments dans notre jeu comme il était demandé.

GIT

Vous pouvez consulter le dépôt Git des projet. Celui-ci contient le fichier gerber de la manette crée sur KiCad. Les fichiers utilisé pour le programmateur AVR sont dans le dossier projet-info-manette/ProgrammateurAVR. Et les fichiers utilisé pour la manette sont eux dans le dossier projet-info-manette/fichier_lufa_libusb.