Tutorat système SE4 : USB

Xavier Redon

2022 - 2023

1  Objectif

Vous allez programmer un périphérique USB basé sur un microcontrôleur ATMega16u2 et un utilitaire d’interaction avec ce périphérique USB via la bibliothèque libusb-1.0.

Le périphérique USB embarque quelques LED et des mémoires de capacité modeste. Vous pourrez le programmer directement par DFU (Device Firmware Update) USB, c’est à dire en basculant le périphérique dans une configuration USB particulière permettant de lui envoyer le programme à exécuter par le bus USB.

Votre but est de faire en sorte que le périphérique apparaisse comme un périphérique de stockage avec une fonctionnalité supplémentaire permettant d’obtenir quelques informations sur l’utilisation du périphérique.

2  Matériel

Le périphérique USB a été conçu avec le logiciel KiCAD (projet keyloggerDevice.zip), voir son schéma électronique :

Le périphérique comporte principalement :

3  Programmation

Comme vous l’avez compris, vous allez devoir écrire deux programmes.

4  Programmation du périphérique

Il s’agit du point le plus délicat du tutorat : la réalisation d’une interface USB de classe "Mass Storage" étendue.

4.1  Prise en main

Commencez par un test basique de la clef : faire clignoter une ou plusieurs LED. Avec un peu de soudure, vous pouvez aussi tester les boutons. Pour le programme de test, vous pouvez partir de ce projet : TestLED.tgz.  
 
La seconde étape est de tenter de communiquer avec les mémoires SPI. Lisez la documentation de la mémoire (DS-45DB641E-027-1385809.pdf). Pour vous faciliter la vie une micro-bibliothèque de gestion des mémoires AT45DB641E est donnée : AT45DB641E.tgz. Récupérez les octets d’identification des mémoires. Utilisez les LED de la carte pour communiquer les octets reçus.

4.2  Fonction mémoire de masse

Vous pouvez enfin passer à l’utilisation de la bibliothèque LUFA pour implanter un périphérique USB de classe Mass Storage. Téléchargez la dernière version de la bibliothèque LUFA http://www.fourwalledcubicle.com/LUFA.php. Créez un répertoire PolytechLille au même niveau que les répertoires Demos et Projects. Le principe serait de recopier la démonstration de périphérique USB bas niveau MassStorage dans le répertoire PolytechLille et de l’adapter pour le périphérique du tutorat. Mais, pour vous aider, une version modifiée de cette démonstration MassStorage est donnée : MassStorageSimple.tgz. Dans cette version, vous n’avez à modifier que les fichiers Lib/DataflashManager.h et Lib/DataflashManager.c.  
 
Une tendance naturelle est de créer un tableau pour stocker une page mémoire mais avec un ATMega16u2, il vaut mieux éviter : ce microcontrôleur ne possède que 512 octets de mémoire vive. Même allouer un tableau pour une page de 256 octets n’est pas une bonne idée sachant que la bibliothèque LUFA consomme déjà de la mémoire. Vous écrirez donc les octets un à un dans le tampon d’écriture des mémoires et vous lirez les octets d’une page mémoire un à un.

4.3  Fonction supplémentaire

La fonctionnalité supplémentaire est décrite dans la section 5.4.  
 
Vous allez modifier le projet pour ajouter une interface "spécifique vendeur" et des points d’accès de type interruption. Il faut un point d’accès "OUT" (sens hôte vers périphérique) et un point d’accès "IN" (sens périphérique vers hôte). La déclaration des interfaces et des points d’accès se font dans les fichiers Descriptors.c et Descriptors.h. La gestion des points d’interruption se fait dans l’autre source .c.  
 
La démonstration Keyboard comporte déjà le code pour déclarer et exploiter des points d’accès de type interruption. Inspirez-vous en (cherchez les fonctions Endpoint_ConfigureEndpoint, Endpoint_SelectEndpoint, etc). N’hésitez pas à consulter la documentation de la bibliothèque LUFA sur Internet.

4.4  Téléversement du programme

Pour téléverser votre programme sur l’ATMega16u2, le paquetage Debian dfu-programmer est nécessaire. Installez-le au besoin. La procédure à suivre pour charger votre programme sur l’ATMega16u2 est la suivante :

4.5  Test de la mémoire de masse

Pour tester le bon fonctionnement de votre carte, procédez comme suit :

5  Récupération des informations

L’objectif est d’utiliser la bibliothèque USB libusb-1.0 pour écrire un programme C permettant de récupérer des informations de votre périphérique USB.

Vous avez le manuel complet de la bibliothèque à l’URL http://libusb.sourceforge.net/api-1.0/modules.html. Vous trouverez un résumé de la bibliothèque à l’URL http://rex.plil.fr/Enseignement/Systeme/Systeme.IMA4/. Pour cette utilisation assez basique nous utiliserons les fonctions de communication bloquantes.

5.1  Recherche du périphérique USB

Pour simplifier la programmation vous utiliserez la fonction libusb_open_device_with_vid_pid pour trouver votre périphérique USB.  
 
Faites afficher le numéro du bus sur lequel se trouve le périphérique ainsi que son adresse sur ce bus.

5.2  Réclamer l’interface spécifique

Commencez par récupérer la configuration courante du périphérique. La fonction libusb_get_active_config_descriptor qui permet cela nécessite un pointeur sur périphérique de type libusb_device *. Vous pouvez obtenir ce pointeur en fonction de la "poignée" dont vous disposez par la fonction libusb_get_device. Faites afficher la valeur de cette configuration.  
 
Il vous reste ensuite à réclamer l’interface de type "spécifique vendeur" pour votre usage. Attention, la fonction libusb_claim_interface nécessite le numéro de l’interface et pas son indice. Vous allez donc parcourir la structure arborescente de description de configuration du périphérique de la façon suivante :

Affichez l’indice et le numéro de l’interface détectée et réclamée. Affichez aussi les numéros et directions des points d’accès trouvés.

5.3  Fermeture du périphérique USB

Ecrivez une fonction qui libère le périphérique détecté. Pour cela, relachez l’interface réclamée puis fermez la "poignée". Pour faire cela facilement, vous aurez besoin du couple "poignée" et numéro d’interface. Prévoyez donc une structure pour pouvoir passer facilement ce couple de fonction en fonction. Affichez l’indice et le numéro de l’interface libérée.

5.4  Fonctionnalité de l’utilitaire

Votre programme doit pouvoir s’utiliser dans deux modes différents, initialisation des informations et récupération des informations. Le mode est déterminé par la valeur du premier paramètre passé au programme.  
 
Dans le mode initialisation, votre programme va juste envoyer un octet au périphérique sur le point d’accès "OUT" de l’interface spécifique. A minima, le programme doit permettre de remettre à zéro les compteurs de lecture et d’écriture des pages.  
 
Dans le mode récupération, votre programme doit simplement lancer une requête sur le point d’accès "IN". Les quelques octets retournés doivent contenir les informations sur votre "mémoire de masse", a minima le nombre de pages écrites et lues. Votre programme doit afficher ces informations de façon claire pour un humain.  
 
La fonction de la bibliothèque à utiliser pour les communications est libusb_interrupt_transfer.


Ce document a été traduit de LATEX par HEVEA