jeudi 15 février 2018

Chapitre 20 : lancement d'un thread



Dans ce programme, nous allons voir le lancement d’un thread qui tournera en parallèle du thread principal. Le thread principal attendra les signaux reçus par le thread fils et nous nous contenterons d’afficher les informations reçues.
Dans un premier temps j’ai essayé le call system CLONE mais cette fonction n’est pas implémentée sur mon Raspberry et j’ai donc utilisé le call system FORK code 02. Cette fonction dédouble entièrement le processus père et retourne dans le registre r0 soit 0 pour le thread fils soit le pid du père. Cela nous permet de distinguer maintenant les 2 threads et donc d’exécuter les instructions différentes. Si c’est le fils, nous appelons la routine exec_thread et si c’est le père nous exécutons les instructions parent.
Dans la routine du fils, nous appelons le Call system GETPPID code 40h pour récupérer le pid du père puis après un temps d’attente, nous appelons le call système PAUSE code 1Dh.  Cette dernière permet de mettre le thread fils en attente et à l’écoute des signaux qui peuvent le toucher. Pour cela nous récupérerons son pid et nous utiliserons la commande kill pour changer son état à partir de la console utilisateur.
Dans les instructions concernant le père, nous mettons dans une boucle le call système WAIT code 072h qui va attendre les signaux du fils. Les codes de chaque signal sont récupérés dans les 2 premiers octets de la zone mémoire qui a été passée en paramètre. Ici nous nous contentons d’afficher le contenu des zones jusqu’à recevoir le signal de fin du thread fils  pour sortir de la boucle et terminer le programme.
Nous lançons le programme par nomduprogramme ‘&  pour que celui ci tourne en arrière-plan (voir la documentation Linux ) et nous laisse l’accès à la console linux. En tapant la commande ps, nous voyons 2 fois le nom du programme avec 2 pid différents correspondant au 2 threads. Le pid le plus élevé correspond au thread du fils  (1976 dans l’exemple ci-dessous).

pi@raspberryVincent:~/vincent/asm/projet7 $ ps
  PID TTY          TIME CMD
 1894 pts/0    00:00:01 bash
 1975 pts/0    00:00:00 testfork
 1976 pts/0    00:00:00 testfork
 1979 pts/0    00:00:00 ps



Nous allons stopper le thread fils par la commande kill –STOP 1976, le relancer par kill –CONT 1976 et le tuer définitivement par kill –TERM 1976. Ce qui terminera aussi le thread du père pid 1975.
Vous pouvez regarder pour chaque cas, les informations transmises. Vous pouvez aussi dans la routine exec-thread mettre en commentaire l’appel système de PAUSE pour vérifier la fin normale du thread fils et le contenu du code retour (celui-ci pourra donc être différent suivant le travail effectué par le fils).
Ce programme est très simple et il reste à l’améliorer pour voir la gestion de plusieurs threads fils et le passage d’informations entre les threads père et fils.

mardi 6 février 2018

Chapitre 19 : GPIO Raspberry : utilisation bouton poussoir



Pour continuer l’utilisation de l’assembleur pour commander le GPIO, le programme suivant va simuler un feu tricolore. Son démarrage s’effectuera par appui sur un bouton poussoir. Pour le schéma électrique nous utiliserons le montage précédent avec une LED rouge reliée au pin 18 et nous ajoutons une LED orange reliée au pin 23 et une LED verte reliée au pin 25 (avec bien entendu une résistance de protection). Le bouton poussoir sera relié au pin 4 au travers d’une résistance de 10k. Les autres extrémités seront reliées au pin 3 (ground).
Dans le programme, les informations concernant ces N° de pins seront mises sous forme de constantes, ce qui permet de les modifier facilement. Ensuite le programme reprend l’ouverture du périphérique et son mappage en mémoire. Il reprend les routines de sélection d’allumage et d’extinction des pins. Nous avons rajouté une routine de lecture de l’état de chaque pin (etatPin) qui exploite l’information contenue dans les registres GPLEV0 du GPIO. Cette routine servira pour lire l’état du bouton poussoir. Nous avons aussi ajouté une routine pour gérer plusieurs temps d’attente en appelant la fonction système déjà vue sleepnano.
Les instructions du fonctionnement se retrouvent dans la routine traitement. Pour les 3 pins concernant les leds, nous leur attribuons la fonction de sortie (output) et pour le pin 4 lié au bouton poussoir la fonction entrée (input).
Puis dans une boucle, nous testons l’état du bouton poussoir que nous terminerons lorsque son état aura changé. Puis nous allumerons successivement les 3 led en laissant des temps d’allumage de 25, 5 et 30 secondes.
Ces allumages font partie d’une boucle sans fin. Il faudra donc arrêter le programme par un ctrl-C ce qui laissera une LED toujours allumée. Il serait donc utile d’ajouter un autre bouton poussoir pour arrêter proprement la boucle et terminer le programme.

vendredi 2 février 2018

Chapitre 18 : gérer le GPIO du Raspberry avec l'assembleur



Après tous ces chapitres consacrés à l’affichage, nous allons voir les routines pour  programmer le GPIO du Raspberry (qui je le rappelle est un modèle B). Classiquement nous allons faire clignoter une led connectée au pin 18 du GPIO. Vous trouverez sur Internet toutes les explications pratiques pour effectuer le montage électronique nécessaire (par ex : https://thepihut.com/blogs/raspberry-pi-tutorials/27968772-turning-on-an-led-with-your-raspberry-pis-gpio-pins).
 Curieusement, le programme va reprendre la fonction principale des programmes précédents car la programmation du GPIO va commencer par l’ouverture du périphérique et le mapping en mémoire des zones associées.
Mais le périphérique à ouvrir va s’appeler /dev/gpiomem  et les zones mémoires à utiliser sont très détaillées ( voir la documentation BCM2835-ARM-Peripherals).
Après le mapping des registres du GPIO en mémoire, il faut sélectionner la broche qui va être utilisée en sortie. Nous allons utiliser la broche physique 12 qui correspond au N° de pin 18 en appelant la sous routine selectPin. Oui c’est un truc bizarre il y a 2 numérotations différentes des broches et donc j’appellerais broche, la borne physique et pin le N° logique affecté à cette broche. Vous trouverez sur internet de nombreux schémas qui présentent la relation entre les 2 suivant les modèles du Raspberry. 
La sélection en sortie nécessite la modification de 3 bits avec le code fonction (Input ou Output) au bon emplacement dans un des 4 registres GPIO possibles ( attention ne pas confondre les registres du processeur (r0, r1 etc) avec les registres du GPIO). Pour cela il faut diviser le N° de pin (ici 18) par 10, le résultat donnera le N° du registre GPIO à mettre à jour et le reste donnera le rang du pin dans ce registre.  Mais attention, il faut mettre à jour les 3 bits sans modifier les autres sinon bonjour les dégâts. C’est le rôle de la suite des instructions de manipulation des bits qui prépare le registre r2 du processeur.

   mov r0,r3             @ rang du pin dans le registre
   add r3,r3,r0,lsl #1   @ calcul de la position dans le registre = rang * 3
   mov r1,#MASKPIN       @ masque des 3 bits à sélectionner
   lsl r1,r1,r3           @ déplacement du masque en fonction de la position
   bic r2,r2,r1           @ raz des 3 bits concernés dans le registre
   lsl r6,r6,r3           @ déplacement du code fonction à la bonne position
   orr r2,r2,r6           @ maj du code fonction à la bonne position
   str r2,[r5,r4,lsl#2]   @ stockage du registre à sa bonne place dans la mémoire

 Ensuite ce registre sera stocké au bon emplacement de la mémoire mappée. Ouf !!!
Ensuite, nous trouvons une petite boucle d’attente avant d’effectuer une extinction de la broche du GPIO (clear). Il est indiqué dans la documentation qu’il faut faire un clear avant d’effectuer un allumage de la broche. Contrairement au programme d’animation vu précédemment, nous n’utilisons pas le call système wait pour gérer le temps d’attente mais nous avons utilisé une simple boucle à titre d’exemple.
Dans la routine clearPin, nous commençons par sélectionner le registre du GPIO à mettre à jour. Là c’est plus simple car il n’y a que 2 registres concernés un pour les pins 0 à 31 l’autre pour les pins supérieurs à 32 (et plus exactement de 32 à 53). Et il n’est nécessaire que de positionner à 1 le bit équivalent à la position du pin.
Puis après un nouveau temps d’attente nous appelons la routine d’allumage du pin. C’est le même principe
 que la routine précédente sauf que les 2 registres ne sont pas les mêmes ( donnés par des offsets différents GPSET et GPCLR).
Vous remarquerez que l’allumage et l’extinction consistent à mettre le bit correspondant au N° de pin à 1 mais sur des registres différents. Ceci évite de commettre des erreurs !!
Lors des tests, la led ne s’allume pas !! Après avoir vérifié de nombreuses fois le programme et le câblage, je me suis aperçu que la led avait un sens de branchement : le fil long de la led doit être du coté de la broche 12 !!.
Normalement, ce programme fonctionne avec plusieurs versions du Raspberry qui utilise le BCM2835.
 Exercices : modifier le pin utilisé.
                     Faire clignoter 2 leds alternativement.
                       Lire la documentation BCM2835 et implémenter les autres fonctions.