Outils pour utilisateurs

Outils du site


tppic

AVANT TOUTE CHOSE, POUR ACCEDER A L'INTEGRALITE DU SUJET DE TP, SE LOGGER EN (en cliquant en haut à droite sur s'identifier): utilisateur; au, mot de passe; au si vous êtes en salle ER2AU utilisateur; en, mot de passe; en si vous êtes en salle ER2EN

TP Bus de communication : Initiation au micro-contrôleur PIC32 et utilisation d'un réseau local pour l'échange de données via sockets UDP

Objectifs

L'objectif de cette série de TP est d'illustrer la communication entre des dispositifs « industriels » de type micro-contrôleurs et des ordinateurs via un réseau Ethernet. Dans un premier temps, vous utiliserez un micro-contrôleur PIC 32 bits de la marque Microchip, programmé à l'aide de l'environnement de développement MPLABX. Ce micro-contrôleur dispose d'un grand nombre d'interfaces de communication dont l'interface ethernet intégrée que nous allons exploiter pour échanger des informations avec un serveur et d'autres cartes PIC. Pour réaliser cela, nous utiliserons des fonctions de la pile (Librairie) TCP/IP Microchip.

Lors des quatre premières heures de TP, vous devrez développer une application sur ce PIC pour qu'il dialogue avec une application déjà écrite sur un PC distant appelé « superviseur ».

Ensuite, vous développerez une application sur PC pour dialoguer avec la carte PIC, sujet présenté dans: tpqt

Présentation des réseaux

Détermination des adresses

La commande affiche les différentes interfaces présentes sur la machine. Dans les salles de TP, il y a 2 interfaces filaires par machine, et il vous incombe de déterminer laquelle est connectée à chaque réseau ou VLAN (en fonction de l'IP associée).

L'adresse MAC de chaque interface est affichée sur la ligne “Adresse physique”

Pour connaître l'adresse MAC d'une machine distante, nous pouvons utiliser le mécanisme d'ARP (Adress Resolution Protocol). Pour cela, nous envoyons une requête de ping à la machine distante en tapant dans une console:

ping adresse_IP

Pour terminer l'exécution de la commande ping, taper CTRL+C.

Si la machine depuis laquelle on lance cette commande ne connaît pas encore l'adresse MAC correspondant à cette IP, elle va envoyer une requête ARP sur le réseau pour demander quel dispositif a cette IP. Le dispositif en question, s'il est présent et qu'il est capable de répondre à la requête, va alors répondre à la requête ARP. (puis plus tard au ping…). La machine qui a lancé la requête ARP va ensuite stocker dans une table la correspondance entre les adresses IP et MAC et cette table sera visible en saisissant dans une console la commande suivante (qui remplace avantageusement: arp -a):

Présentation du format d'échange des données

Chaque application BroadcastReceiver réalise la tâche suivante: Tout d'abord, elle ouvre des sockets UDP (canal de communication, se reporter au cours de réseau) pour communiquer:

Ensuite l'application BroadcastReceiver affiche les datagrammes UDP reçus sous forme d'une chaîne de caractères, et si la chaîne est conforme au format attendu, elle visualise l'état des trois boutons dont la valeur a été passée via des variables que nous nommerons b1state, b2state et b3state (actif à 1). Une variable compteur est également transmise pour comptabiliser le nombre de trames émises par le PIC. Le format à respecter a été choisi arbitrairement comme une chaîne ASCII générée par :

sprintf(chaine,"compteur= %6d b1:%d  b2:%d  b3:%d\n",compteuretudiant,b1state,b2state,b3state);

La fonction sprintf fonctionne de la même façon que le printf sauf que la chaine, au lieu d'être affichée sur une console, est écrite dans une variable de type tableau de caractères dont l'adresse de début est passée en premier paramètres de la fonction sprintf. Dans cet exemple, la variable char chaine[100] est donc remplie avec les caractères qui auraient normalement été affichés si l'on avait exécuté la fonction printf.

L'application permet également de commander les LED de la carte PIC. Elle dispose pour cela de 4 Boutons. Les boutons « Led0 », « Led1 » et « Led2 » doivent faire commuter l'état des leds correspondantes sur la carte PIC lors d'un appui, alors que le bouton « start clignote LED0 » permet de commuter automatiquement la led0 toutes les 2 secondes. Chaque commutation d'une Led numérotée i est pilotée en envoyant une chaine ASCII générée par:

sprintf(chaine,"%d",i) ;

Pour rappel, l'objectif de ce premier TP est de développer l'application tournant sur le PIC qui va émettre l'état des boutons et commander les LED.

Présentation de la carte de développement

La carte utilisée est une PIC32 Ethernet Starter Kit.

La documentation de cette carte est disponible dans le fichier: http://homepages.laas.fr/bvandepo/files/iut/tp_pic/doc/PIC32_Starter_Kits_Users_Guide_DS61159A.pdf

La documentation du micro-contrôleur PIC32MX est dans le fichier: http://homepages.laas.fr/bvandepo/files/iut/tp_pic/doc/PIC32MX-61156D.pdf

Pour les plus curieux, le schéma de la carte est visible sur: http://homepages.laas.fr/bvandepo/files/iut/tp_pic/doc/PIC32ESKSchematics.pdf

La structure interne du PIC32 est visible sur l'image suivante:

La carte possède des E/S simples à utiliser, 3 LED et 3 boutons:

  1. bouton SW1: Actif à l'état bas et connecté au bit 6 du port D (RD6)
  2. bouton SW2: Actif à l'état bas et connecté au bit 7 du port D (RD7)
  3. bouton SW3: Actif à l'état bas et connecté au bit 13 du port D (RD13)
  4. LED 0: actif à l'état haut et connectée au bit 0 du port D (RD0)
  5. LED 1: actif à l'état haut et connectée au bit 1 du port D (RD1)
  6. LED 2: actif à l'état haut et connectée au bit 2 du port D (RD2)

Cette carte est dotée d'une connectivité variée:

  1. Interface USB Host: La carte peut être raccordée à des périphériques (clef usb, souris,clavier…)
  2. Interface USB OnTheGo: La carte peut être raccordée comme un périphérique (Device) à un hôte (PC ou autre carte micro-contrôleur) ou comme un hôte au choix.
  3. Interface USB Debug: Cette interface USB est connectée à un second micro-contrôleur PIC de la carte de développement servant au chargement et au test des programmes. Cette interface est également utilisée pour alimenter la carte en 5V via le bus USB.
  4. Interface Ethernet 10/100: Cette interface permet de raccorder la carte à un réseau ethernet.
  5. Connecteur d'extension: ce connecteur de 120 broches permet d'utiliser diverses broches et interfaces du micro-contrôleur.

Structure interne du micro-contrôleur

Le micro contrôleur est de type 32 bits, il est donc capable d'effectuer des opérations directement sur des registres de 32 bits. Comme nous allons le programmer en langage C, cela se traduira principalement par une plus grande vitesse d'exécution des calculs sur les grands nombres.

Le micro-contrôleur intègre la partie MAC (Média Access Control), la couche PHY (PHYsique) étant quand à elle réalisée par le composant DP83848C de chez Texas Instrument, voir le fichier: http://homepages.laas.fr/bvandepo/files/iut/tp_pic/doc/1668041.pdf

Développement sur PIC

Le développement de l'application se fait en langage C. Nous utiliserons une version un peu allégée du projet de démo “TCP/IP Demo App” dans lequel nous ajouterons une tâche de communication utilisant 2 sockets UDP.

Structure de l'application à construire

Le code que vous devez développer doit être écrit uniquement dans deux fichiers etudiantSocketApp.c et etudiantSocketApp.h. Ces fichier définissent 2 fonctions appelées par le programme principal:

  1. une fonction void etudiantSocketAppInit(); appelée une fois en début de programme.
  2. une fonction void etudiantSocketAppTask(); appelée en boucle dans le programme à une cadence dépendant des autres tâches à exécuter. Par exemple, le micro contrôleur exécute une tâche de réponse au PING comme nous le verrons plus loin. Il ne faut donc pas que la fonction App soit bloquante, au risque de bloquer l'exécution d'autres services.

Durant le développement de votre application, vous pourrez utiliser la fonction DBPRINTF(char texte[]); pour afficher dans la console debug des messages courts indiquant l'état du programme. Veillez à utiliser cette fonctionnalité avec parcimonie car elle est très lente. Veillez également à ce que la chaine passée en paramètre soit bien terminée par \n pour déclencher l'envoi effectif de la chaine sur l'interface debug. Dans le cas contraire, vous pourrez faire un appel à:

DBPRINTF("\n");

L'affichage des infos de debug dans le champ Output→DBPRINTF (droite de Starter Kits dans la partie inférieure de MPLABX).

Note sur les types

Afin de différencier les entiers sur 8,16 et 32 bits, 3 types sont définis:

  1. DWORD pour des entiers sur 32 bits.
  2. WORD pour des entiers sur 16 bits.
  3. BYTE pour des entiers sur 8 bits.

D'autres types sont également définis: UDP_SOCKET, UDP_PORT, NODE_INFO…

Sockets MICROCHIP

L'application à développer utilise une interface propre à MICROCHIP pour l'utilisation des sockets. Son usage reste très proche de celui des Sockets BSD vus en TP de réseau. La documentation complète de la pile TCP/IP est disponible dans le fichier: http://homepages.laas.fr/bvandepo/files/iut/tp_pic/doc/TCPIPStackHelp.chm

Cliquer sur Index puis sur UDP pour accéder à la partie qui nous sera utile. Le schéma suivant montre les différentes fonctions correspondant à l'utilisation d'un socket UDP:

Nous nous restreindrons à utiliser les sockets dans un seul sens de communication à la fois et nous utiliserons donc deux sockets définis comme variables globales pour établir et maintenir la communication bidirectionnelle:

UDP_SOCKET udpsock;  //utilisé pour l'émission depuis le PIC
UDP_SOCKET udpsock2; //utilisé pour la réception depuis le PIC

Chaque socket doit ensuite être ouvert dans la fonction Init par un appel à la fonction:

UDP_SOCKET UDPOpen( UDP_PORT localPort,  NODE_INFO * ptr_remoteNode,  UDP_PORT remotePort);

localPort et remotePort sont ici égaux et valent le numéro du port associé au socket. ptr_remoteNode est un pointeur sur une structure qui permet d'indiquer l'adresse IP de la machine connectée avec le socket. Cette structure est constituée de deux tableaux d'octets IPAddr.v[] et MACAddr.v[] codant respectivement l'adresse IP et l'adresse MAC du destinataire. Pour une socket écoutant sur n'importe quelle adresse IP, il faut passer la valeur NULL comme paramètre effectif ptr_remoteNode.

Socket en émission

Le socket en émission peut alors émettre ses données à condition qu'il y ait de la place dans les buffers d'émission de l'interface Ethernet. Pour déterminer la place disponible, nous utiliserons la fonction suivante qui retourne le nombre de caractères que l'on peut émettre sur un socket:

WORD UDPIsPutReady( UDP_SOCKET s);

Si il y a suffisamment de place pour émettre les données, une chaîne de caractères cData contenant wDataLen caractères peut être émise par un appel à la fonction:

WORD UDPPutArray( BYTE * cData, WORD wDataLen); //retourne le nombre de caractères effectivement émis.

Finalement, pour demander l'émission effective des données sur l'interface, on fait appel à la fonction :

void UDPFlush();

Socket en réception

Le socket en réception utilise d'autres fonctions. La fonction UDPIsGetReady retourne le nombre de caractères pouvant être lus sur un socket,:

WORD UDPIsGetReady( UDP_SOCKET s); 

Les caractères (au nombre de wDataLen) sont ensuite lus vers une chaîne cData par la fonction:

WORD UDPGetArray( BYTE * cData,  WORD wDataLen);

La fonction UDPClose() ne sera pas utilisée dans notre application, car les 2 sockets sont ouverts à l'initialisation et utilisés tout au long de l'exécution du programme.

Gestion du temps

La fonction etudiantSocketAppTask() n'est pas appelée à intervalle de temps constant. Pour définir le nombre de fois que la tâche doit être exécutée par seconde, on utilise un timer que l'on vient scruter (mécanisme de scrutation plutôt que d'interruption) à chaque appel de la fonction etudiantSocketAppTask() pour savoir s'il est temps d'exécuter la tâche.

Après avoir défini la variable globale DWORD tim = 0; et la constante

#define ETUDIANTSOCKETAPP_OCCURENCE_PAR_SEC 5ul //pour 5 fois par secondes,

la fonction Task possède cette structure:

void etudiantSocketAppTask()
{
if(TickGet() -tim >= TICK_SECOND/ ETUDIANTSOCKETAPP_OCCURENCE_PAR_SEC)
  {
  tim = TickGet();
  compteur++; //Tâche à exécuter, incrémentation d'un compteur par exemple....
  } 
}

Génération et décodage de chaînes de caractères ASCII

Nous allons utiliser des tableaux de caractères pour l'émission et la réception des données via les sockets car ce sont les paramètres d'entrées/sorties utilisés par les fonctions disponibles pour l'envoi et la réception de datagrammes. Pour rappel, les fonctions permettant d'écrire et de lire dans une chaîne de caractères chainecarac la chaîne de caractères formatée format(par exemple Bonjour %d) sont:

int sprintf(char* chainecarac, const char * format, ... );
int sscanf(char* chainecarac, const char * format, ... ); 

La fonction strlen retourne le nombre de caractères d'une chaîne chainecarac:

 int strlen(char* chainecarac);

Lecture de l'état des boutons

L'état des 3 boutons est lu dans des variables par

b1state=(int)!PORTReadBits(IOPORT_D, BIT_6);
b2state=(int)!PORTReadBits(IOPORT_D, BIT_7);
b3state=(int)!PORTReadBits(IOPORT_D, BIT_13);

Commande des LED

Les Leds sont changées d'état en exécutant:

LED0_IO ^= 1;  //opérateur Ou exclusif avec opérande 1 = complémentation
LED1_IO ^= 1; 
LED2_IO ^= 1;

Il est bien sûr possible de commander les leds par valeur par exemple avec:

LED1_IO = 0; ou LED1_IO = 1;  

Remarques importantes:

  1. Ne brancher le câble réseau sur l'interface du PIC que lorsque vous voulez tester votre programme sur la carte et que vous l'avez déjà testé en pas à pas.
  2. Les cartes PIC ainsi que les câbles réseaux sont numérotés, il est IMPERATIF de n'utiliser que votre câble et votre carte et de régler correctement l'adresse IP de votre carte via le fichier “TCPIPConfig PIC32 Internal Ethernet.h”.
  3. Votre application est contenue uniquement dans les fichiers etudiantSocketApp.c et etudiantSocketApp.h. Vous n'avez pas à modifier d'autres fichiers hormis “TCPIPConfig PIC32 Internal Ethernet.h”.
  4. Ne jamais brancher une carte PIC sur le réseau sans avoir préalablement chargé votre programme… Elle contient peut être un mauvais programme qui va polluer tout le réseau et empêcher vos collègues de travailler!
  5. La carte de développement PIC32 est alimentée par le USB, ne pas chercher à l'alimenter par une alimentation externe.
  6. Ne pas changer la position des cavaliers sur les cartes.

Travail demandé

Les exercices dont le nom se termine par une « * » sont à faire valider.

Identification des binômes
  1. Remplir la feuille de présence pour déterminer qui utilise quelle carte et quelle adresse IP.

Identification des éléments utiles sur le schéma et analyse des couches réseau *

  1. Repérer sur le schéma à remplir les éléments utilisés pour faire dialoguer la carte PIC avec le PC superviseur..
  2. Etablir un schéma faisant apparaître les différentes couches réseau impliquées.

Récupération du projet: (POUR LA PREMIERE SEANCE UNIQUEMENT!!!!!)

Configuration de l'adresse IP de chaque carte

L'adresse IP associée à chaque carte est dite 'statique', c'est à dire qu'elle est attribuée à chaque carte par le programme de chacune d'elle, au lieu d'être attribuée par un serveur (on parle alors d'adresse 'dynamique' fournie par un serveur DHCP)

  1. Ouvrir « TCPIPConfig PIC32 Internal Ethernet.h » dans le projet
  2. Localiser le réglage de l'adresse IP et du masque dans ce fichier et remplacer les valeurs par celles qui conviennent. Par exemple, pour régler le quatrième octet de l'IP à la valeur 100:

#define MY_DEFAULT_IP_ADDR_BYTE4 {100ul}

Le masque est réglé à l'aide des macros MY_DEFAULT_MASK_BYTE1 à 4, de la même manière.

Le suffixe ul apres la valeur 100 signifie que la valeur est une constante à interpréter en tant que Unsigned Long.

Chargement de votre programme et utilisation du mode debug
  1. Cliquer sur Debug→Debug project. NB: la première compilation est lente (qq minutes) mais les suivantes seront plus rapides car seuls les fichiers modifiés seront recompilés (sauf si vous modifiez « TCPIPConfig PIC32 Internal Ethernet.h ») .
  2. Placer des points d'arrêt dans votre programme, en cliquant sur le numéro de la ligne (petit carré rouge apparaît), pour le désactiver, cliquer à nouveau sur le carré.
  3. Presser Debug→debug project pour charger le programme dans le micro contrôleur et lancer le mode debug (Debug→Finish debugger session)
Test de communication avec la carte *

Il y a plusieurs applications fonctionnant sur le PIC, notamment un service de réponse au PING.

  1. Votre carte étant en fonctionnement (RUN) et raccordée au réseau, lancer une demande de ping depuis le PC superviseur avec l'adresse de votre carte. Votre PC envoie alors des demandes de PING à l'adresse de la carte PIC. Si celle-ci est connectée au réseau et en fonction, elle doit répondre et l'outil ping doit afficher le temps mis par la carte pour répondre (généralement moins d'une milliseconde sur ce réseau local). Cette opération peut être réalisée soit depuis le PC superviseur soit depuis votre machine de développement en saisissant par exemple dans une console:
Prise en main des E/S *
  1. Débrancher le cable réseau pour cet exercice.
  2. Dans la fonction Task, recopier l'état des boutons sur les leds correspondantes à une cadence d'une fois par seconde.
  3. Utiliser l'outil de debug en pas à pas pour suivre l'exécution de votre programme.
  4. Afficher sur l'interface debug la chaine qui devrait être envoyé au superviseur pour donner l'état des boutons à l'aide de la fonction DBPRINTF présentée plus haut. La chaine affichée devra être générée dans le tableau chaine à l'aide de:
sprintf(chaine,"compteur= %6d b1:%d  b2:%d  b3:%d\n",compteur,b1state,b2state,b3state);
Réception de commandes des LED *
  1. Remplir les fonctions Init et Task pour gérer la réception périodique des chaînes de caractères commandant les LED depuis le PC superviseur. Pour cela, vous devrez ouvrir une socket écoutant sur le bon numéro de port et depuis n'importe quelle IP. Veillez à définir un tableau de caractères en mémoire et à ne pas tenter de lire plus de caractères qu'il n'y a de place dans ce tableau.
  2. Tester votre programme en demandant sur le PC superviseur, via l'application BroadcastReceiver qui communique avec votre carte PIC, de commuter chacune des LED.
Émission de l'état des boutons *
  1. Remplir les fonctions Init et Task pour gérer l'envoi périodique à une fréquence d'un Hertz d'une chaîne de caractères codant l'état des boutons poussoirs vers le PC superviseur.

Pour cette tâche, il faut configurer l'ouverture de la socket pour qu'elle s'établisse avec une seule machine sur le réseau. Dans un premier temps, nous n'utiliserons pas le mécanisme ARP et nous devrons donc régler l'adresse IP et l'adresse MAC de la machine destination (le PC superviseur) avant d'ouvrir la socket en définissant une variable globale NODE_INFO myRemoteNode; puis en l'initialisant dans la fonction Init avec les valeurs que vous aurez déterminée grâce aux commandes ping et arp:

myRemoteNode.IPAddr.v[0] = XXX;  //Adresse IP du PC superviseur, premier octet  (de poids fort)
myRemoteNode.IPAddr.v[1] = XXX;
myRemoteNode.IPAddr.v[2] = XXX;
myRemoteNode.IPAddr.v[3] = XXX;
myRemoteNode.MACAddr.v[0]= XXX; //Adresse MAC du PC superviseur, premier octet
myRemoteNode.MACAddr.v[1]= XXX;
myRemoteNode.MACAddr.v[2]= XXX;
myRemoteNode.MACAddr.v[3]= XXX;
myRemoteNode.MACAddr.v[4]= XXX;
myRemoteNode.MACAddr.v[5]= XXX; 

Ensuite, passer myRemoteNode en paramètre à la fonction UDPOpen lors de l'ouverture de la socket en émission.

Attention: pour pouvoir observer le trafic avec Wireshark coté superviseur, il faut absolument lancer l'application BroadcastReceiver qui va “ouvrir” les ports!

Gestion de l'ARP pour la communication avec le PC superviseur*

On souhaite maintenant mettre en place le mécanisme d'ARP dans l'application sur le PIC. Vous allez dans un premier temps “casser” l'initialisation de myRemoteNode.MACAddr.v[i] en mettant des 0 dans toutes les cases et nous allons utiliser les fonctions suivantes pour remplir automatiquement le tableau:

ARPResolve(type pointeur sur adresse IP  );

et

bool ARPIsResolved(type pointeur sur adresse IP, type pointeur sur adresse MAC)

Dans la fonction Task, ajouter une machine à état simple permettant de faire des requêtes ARP avec la fonction ARPResolve. Ceci permet d'envoyer une requette ARP avec l'adresse IP passée en argument. Dans les appels suivants de la fonction task, il vous faudra tester si ARPIsResolved a renvoyé true, ce qui signifie que la réponse ARP est arrivée et donc que le champ adresse MAC est mis à jour. Dans ce cas il faudra ouvrir la socket (une seule fois) puis effectuer l'envoi des données comme dans l'exercice précedent. Dans le cas contraire, il faudra appeler à nouveau ARPResolve pour envoyer une nouvelle requête.

Il est important que la fonction etudiantSocketAppTask() soit NON BLOQUANTE!

Tester l'émission avec le mécanisme d'ARP avec le PC superviseur.

Communication avec votre PC*

Récupérer le dossier « commum/2AU/PIC/socketqtbroastreceiver »

Configurer l'application BroadcastReceiver en éditant le script « lancer.bat » (click droit, modifier) pour configurer les ports UDP en émission et en réception. La syntaxe est la suivante

broadcastReceiver IP_destination port_UDP_émission port_UDP_réception paramètres_optionnels_de_réglages_de_la_fenêtre

par exemple:

start broadcastreceiver 192.168.1.100 27016 27017 10 40 500 130   

Déterminer les adresses IP (et MAC) de l'adaptateur réseau Realteck du PC étudiant en lançant ipconfig /all dans une console.

Modifier le code du PIC en conséquence (adresses IP (et MAC si ARP non fonctionnel) destinataire et numéros de ports).

Vérifier la communication entre le PC et le PIC


tppic.txt · Dernière modification: 2017/04/01 19:08 par bvandepo