Introduction 'a la plateforme Raspberry Pi
←
→
Transcription du contenu de la page
Si votre navigateur ne rend pas la page correctement, lisez s'il vous plaît le contenu de la page ci-dessous
Introduction à la plateforme Raspberry Pi — Partie 2 — B. Q UOITIN, D. H AUWEELE et G. H UYSMANS Faculté des Sciences, Université de Mons 10 décembre 2014 1 Objectifs de la séance L’objectif de cette séance est de permettre l’interaction entre la platine Raspberry Pi et le monde réel au travers des ports d’entrées/sorties (GPIO). Plusieurs petits circuits électroniques simples seront réalisés sur une platine d’expérimentation (breadboard). De courts programmes en shell, Python et/ou C seront écrits afin de contrôler les entrées/sorties. Comme pour la première séance, la plateforme sera utilisée sans écran. Les composants électroniques utilisés seront issus du SparkFun Inventor’s Kit 1 . 2 Entrées/sorties GPIO Le processeur ou plus exactement System-on-Chip (SoC) qui équipe la platine Raspberry Pi possède un grand nombre de portes d’entrées/sorties. Celles-ci permettent au SoC d’interagir avec d’autres périphériques ou circuits électroniques. Ces ports d’entrées/sorties sont souvent appelés GPIO pour General Purpose In- put/Output. Le comportement de ces ports d’entrées/sorties est contrôlable par programme. Le SoC BCM2835 dispose de 54 lignes GPIO. Certaines sont accessibles au travers de l’un des connec- teurs de la platine. Les broches GPIO accessibles dépendent de la version de la platine Raspberry Pi. Sur les modèles A et B (rev.1 et 2), 17 GPIO sont accessibles au travers du connecteur P1 (26 broches). Sur les modèles A+ et B+, 26 GPIOs sont accessibles au travers du connecteur J8 (40 broches). Les Tables 12, 11 et 10 renseignent sur l’identification des différentes broches des connecteurs GPIO. Certaines des broches permettent d’accéder à l’alimentation électrique de la platine Raspberry Pi (3,3V ou 5V). Certaines broches sont marquées GND, il s’agit du point de potentiel de référence (0V). Les autres broches sont étiquettées avec le numéro de broche GPIO et lorsque c’est possible par une fonction alterna- tive. Sur la Table 11 par exemple, on peut y observer que les broches 8 et 10 du connecteur correspondent aux GPIO 14 et 15 respectivement mais que ces broches peuvent également être utilisées pour une liaison série (UART TxD et RxD). Lors de la première séance, ce sont ces broches que nous avons utilisées pour y connecter un adaptateur USB/série afin d’obtenir une console. Une bonne référence pour obtenir de l’information sur les autres connecteurs ou sur un autre modèle de platine est le site http://elinux.org/RPi_Low-level_peripherals. 2.1 Précautions et limites d’utilisation + Attention, l’utilisation des broches d’entrées/sorties nécessite de respecter certaines limita- tions. Dans le cas contraire, la broche d’entrée/sortie voir le SoC peuvent être définitivement endommagés ! En particulier, ni la platine ni le SoC ne fournissent de mécanisme de protec- tion contre les surtensions ou les courants trop forts. 1. https://www.sparkfun.com/products/retired/12060 1
Les contraintes suivantes sont valables pour le modèle B mais devraient être similaires pour les autres modèles. Une broche d’entrée/sortie fonctionne comme une source de tension en 3,3V. Les broches ne tolèrent pas une tension de 5V ! Le courant qui peut être tiré d’une broche est limité par plusieurs facteurs. Le courant tiré d’une broche provient de l’alimentation USB (5V) puis est abaissé à 3V3 par un régulateur, puis il passe par le SoC. — Limite par broche : 16mA (contrainte du SoC). — Limite totale 3V3 : 50mA (contrainte du régulateur 3V3). Cela donne un courant moyen maximum d’environ 2-3mA par broche. — Limite totale 5V : ? ? ?mA (contrainte de l’alimentation USB). En résumé, tirer le moins de courant possible d’une broche d’entrées/sorties. 3 Application : contrôle d’une LED et d’un bouton poussoir Cette section décrit comment configurer une broche comme entrée ou sortie digitale et comment en contrôler ou lire l’état. Afin de mettre en pratique ce contrôle, la platine Raspberry Pi sera utilisée d’une part pour contrôler l’allumage d’une LED et d’autre part pour lire l’état d’un bouton poussoir. Les Figures 1a et 1b présentent le schéma des circuits correspondants. Le circuit de commande de la LED est articulé autour de 2 résistances (R1 et R2), d’un transistor bipolaire NPN (Q1) et d’une LED (LD1). La résistance R1 de 330 ohms limite le courant qui traverse la LED 2 à environ 4mA. Le transistor permet de commander le circuit de la LED en tirant un courant faible d’environ 0,3mA de la broche de sortie 3 . Le bouton poussoir est placé en série avec une résistance (R2) de façon à limiter le courant tiré du port au cas où il serait incorrectement configuré en sortie et placé dans un état haut. Dans ce cas, le courant sera limité à 10mA, ce qui reste dans les limites permises. La résistance R1 est une résistance de pull-up optionnelle 4 . Lorsque le bouton poussoir est pressé, la tension présente sur la broche sera proche de 0V, ce qui sera interpreté comme un niveau 0. Lorsque l’interrupteur est relâché, la résistance de pull-up du port rendra la tension proche de 3,3V et donc d’un niveau haut. (a) Commande d’une LED avec une sortie digitale. (b) Capture d’un bouton poussoir avec une entrée digitale. La Figure 2a montre comment le circuit de contrôle de la LED peut être implémenté sur une plaquette d’expérimentation (breadboard). Attention, il est important de pouvoir identifier les différentes broches de la LED et du transistor. La LED a 2 broches : une anode et une cathode. La cathode est la broche la plus courte. Sur le schéma elle située à la pointe de la flêche. Le transistor bipolaire a trois broches : une base, un collecteur et un émetteur. Sur le schéma, les lettres ”b”, ”c” et ”e” ont été ajoutées pour faciliter l’iden- tification des broches du transistor. Pour identifier les broches du transistor, il est nécessaire de consulter sa fiche technique (datasheet). La Figure 2b montre un extrait de la fiche technique du transistor 2N2222 qui permet d’en repérer les différentes broches. 2. Les caractéristiques de la LED fournie avec l’Arduino SIK ne sont pas connues avec exactitude. Cependant, il est typique pour une LED de ce type de ne pas supporter un courant supérieur à 20mA. La tension nécessaire aux bornes de la LED pour qu’elle commence à conduire (forward voltage drop, Vf orward ) est égale à environ 2V pour une LED émettant dans le rouge. Le courant qui traverse la LED peut être calculé simplement comme I = (3, 3V − Vf orward )/330Ω ≈ 4mA 3. Le courant traversant la jonction base-émetteur du transistor est égal à I = (3, 3V − 0, 7V )/10kΩ ≈ 0, 26mA. 4. Certains ports comportent déjà une résistance de pull-up externe. De plus, il est possible d’activer une résistance de pull-up interne pour chaque port individuellement. 2
(b) Broches du transis- (a) Commande d’une LED avec une sortie digitale. tor 2N2222. 4 Contrôle logiciel Une fois le circuit implémenté sur la plaquette d’expérimentation et relié à la platine Raspberry Pi, il est nécessaire de s’intéresser à la partie logicielle du contrôle. Cette section discute de plusieurs moyens de contrôler une entrée ou une sortie digitale et des performances de ceux-ci. Le premier moyen utilisé sera au travers de fichiers virtuels au travers de l’API SysFS. Le second moyen sera via un programme écrit en Python, grâce à l’API RPi.GPIO. Finalement, le troisième moyen sera via un programme écrit en C qui accède directement aux registres du SoC contrôlant les entrées/sorties. Cette dernière approche est plus complexe et rébarbative, mais elle permet d’une part d’obtenir les meilleures performances et d’autre part de comprendre ce qu’il y a sous le capot. En effet, tous les autres moyens plus simples de contrôler les entrées/sorties se reposent in fine sur l’utilisation des registres du SoC. A titre de comparaison, la Table 1 donne un aperçu des performances qu’il est possible d’obtenir pour le contrôle d’une sortie digitale avec différentes API. Ce tableau a été obtenu par J. Pihlajamaa 5 . On peut constater que l’accès direct aux registres permet de faire changer l’état d’une sortie digitale plusieurs dizaines de fois par seconde alors qu’avec l’API SysFS, il n’est pas possible d’effectuer plus de quelques milliers de changements par seconde. Language Library Version / tested Square wave Shell SysFS N.A. / July 3, 2012 3.4 kHz Python RPi.GPIO 0.3.0 / August 1, 2012 44 kHz Python wiringPi github / August 14, 2012 20 kHz C /dev/mem + mmap N.A. / July 3 and August 14, 2012 14-22 MHz C BCM 2835 1.3 ? / July 3, 2012 4.7 - 5.1 MHz C wiringPi not available / August 14, 2012 6.9 - 7.1 MHz Perl BCM 2835 1.0 / July 3, 2012 35 kHz TABLE 1 – Comparaison des différentes API pour le contrôle d’une sortie digitale. 5. http://codeandlife.com/2012/07/03/benchmarking-raspberry-pi-gpio-speed 3
4.1 Contrôle via sysFS Selon la philosophie UNIX, tout peut être contrôlé au travers de fichiers. Cette approche a été appliquée aux entrées/sorties grâce à SysFS 6 . Il s’agit d’un système générique permettant à un programme utilisateur d’accéder au travers du système de fichiers à de l’état maintenu par le noyau. En clair, des fichiers virtuels apparaissent dans le système de fichiers, typiquement sous le chemin /sys. Comme illustré à la Figure 3, lire ou écrire ces fichiers, au travers d’appels système standards tels que read et write, a pour effet de lire ou écrire de l’état maintenu par le noyau. F IGURE 3 – Illustration de l’interface SysFS. Le contrôle des entrées/sorties digitales avec SysFS peut être réalisé au travers de deux groupes de fichiers. Les premiers, situés sous /sys/class/gpio permettent de placer une broche d’I/O particulière sous le contrôle de SysFS. Par défaut, aucune broche n’est sous le contrôle de SysFS. La Table 2 documente les fichiers de ce groupe. En écrivant le numéro d’une broche d’entrée/sortie dans le fichier export, cette broche passe sous le contrôle de SysFS. Il suffit d’écrire ce numéro dans le fichier unexport pour obtenir l’effet inverse. File Access Description export W Pin number to export unexport W Pin number to remove TABLE 2 – Fichiers SysFS sous /sys/class/gpio Lorsqu’une broche d’entrée/sortie passe sous le contrôle de SysFS, de nouveaux fichiers virtuels appa- raissent dans le répertoire /sys/devices/virtual/gpio/gpion où le n final désigne le numéro de la broche. Le fichier direction permet de configurer une broche comme entrée (in) ou comme sor- tie (out). Le fichier value est utilisé pour lire ou écrire l’état de la broche. Le fichier edge permet de capturer de manière asynchrone des événements de changement d’état d’une broche en entrée. File Access Description direction R/W Direction of pin : in or out edge R/W Event trigger : rising, falling, both or none value R/W State of pin : 0 or 1 TABLE 3 – Fichiers SysFS sous /sys/devices/virtual/gpio/gpion L’exemple qui suit illustre l’utilisation de SysFS pour le contrôle de la broche 3 en sortie. La première étape consiste à mettre GPIO 3 sous le contrôle de SysFS en écrivant la valeur 3 dans le fichier export. 6. voir Ottawa Linux Symposium, 2005 - https://www.kernel.org/pub/linux/kernel/people/mochel/doc/ papers/ols-2005/mochel.pdf et https://www.kernel.org/doc/Documentation/gpio/sysfs.txt 4
La commande echo est utilisée pour afficher une chaı̂ne de caractères. Ici, la sortie de echo est re- dirigée avec le symbole > vers un fichier. Cela a pour effet d’écrire la chaı̂ne de caractères 3 dans le fichier export. Après cette écriture, de nouveaux fichiers (virtuels) sont créés dans le répertoire /sys/ devices/virtual/gpio afin de contrôler la broche 3. La commande ls est utilisée pour montrer le contenu du répertoire /sys/devices/virtual/gpio/gpio3 ainsi créé. Ensuite, la valeur out est écrite dans le fichier direction afin de configurer la broche 3 en sortie. Finalement, en écrivant 1 ou 0 dans le fichier value, l’état de la broche 3 est changé. pi@rpi:˜$ echo "3" > /sys/class/gpio/export pi@rpi:˜$ ls /sys/devices/virtual/gpio/gpio3 active_low direction edge power subsystem uevent value pi@rpi:˜$ echo "out" > /sys/devices/virtual/gpio/gpio3/direction pi@rpi:˜$ echo "1" > /sys/devices/virtual/gpio/gpio3/value → LED ON pi@rpi:˜$ echo "0" > /sys/devices/virtual/gpio/gpio3/value → LED OFF pi@rpi:˜$ echo "3" > /sys/class/gpio/unexport Le exemple qui suit illustre la configuration de la broche 2 en entrée digitale. La différence avec l’exemple précedent est que la valeur in est écrite dans le fichier direction. De plus, le fichier value est lu afin d’obtenir l’état de la broche. pi@rpi:˜$ echo "2" > /sys/class/gpio/export pi@rpi:˜$ ls /sys/devices/virtual/gpio gpio2 gpiochip0 pi@rpi:˜$ echo "in" > /sys/devices/virtual/gpio/gpio2/direction pi@rpi:˜$ cat /sys/devices/virtual/gpio/gpio2/value ... returns 1 (button released) or 0 (button pressed) ... pi@rpi:˜$ echo "2" > /sys/class/gpio/unexport 4.2 Contrôle via API Python Un autre moyen simple de contrôler les entrées/sorties est d’utiliser le langage de programmation Py- thon. Des API spécifiques à la plateforme Raspberry Pi sont disponibles. Celle utilisée ici est nommée RPi.GPIO. L’API est très simple et est résumée à la Table 4. La documentation complète peut être obtenue à l’adresse http://sourceforge.net/p/raspberry-gpio-python/wiki. Utiliser l’API RPi.GPIO requiert une première phase de configuration avec la fonction setmode. Cette fonction indique comment les broche d’entrées/sorties sont identifiées. La première possibilité est d’utiliser les numéros de broches du SoC BCM2835 (argument = BCM). La seconde possibilité consiste à utiliser le numéro de broche du connecteur (argument = BOARD). La première approche nous semble préferable et est donc utilisée dans les exemples qui suivent. La fonction setup permet de configurer une broche en entrée ou en sortie. La fonction cleanup permet de libérer l’utilisation d’une broche et de restaurer sa configuration initiale. La fonction input permet de lire l’état d’une broche (configurée en entrée). La fonction output permet de changer l’état d’une broche (configurée en sortie). NDLR : L’objectif de cette séance n’est pas d’apprendre le langage Python. Si vous ne connaissez pas Python, vous pouvez consulter un tutoriel tel que par exemple https://docs.python.org/2/ tutorial/ L’exemple de programme qui suit contrôle une sortie digitale et en change régulièrement l’état. Les lignes 1 et 2 servent à importer les modules RPi.GPIO et time. Le module RPi.GPIO sera désigné par le nom GPIO grâce à la directive as de la clause import. La ligne 4 requiert l’usage de la numérotation des broches selon le SoC. La ligne 5 configure la broche 3 en sortie. La ligne 7 initialise une variable booléenne à la valeur False. Cette variable contiendra le prochain état de la broche. Les lignes 9 à 12 sont une boucle de 10 itérations. La directive for indique que le bloc qui suit sera répété. Le nombre de répétition est contrôlé par la variable i qui prendra les valeurs entières successives comprises dans l’intervalle 0 à 19. Les valeurs de cet intervalle sont générées par la fonction range. L’intérieur de la boucle est composé des lignes 10 à 12. En python, il n’y a pas de délimitation de bloc. Le contenu du bloc 5
Fonction Description setmode(mode) Selectionne le mode d’identification des broches : BCM = selon le SoC BCM2835 BOARD = selon le connecteur de la platine setup(broche,fonction) Configure broche comme entrée (IN) ou comme sortie (OUT) cleanup Libère les ressources utilisées par le module et res- taure la configuration des broches. input(broche) Lit l’état d’une broche. output(pin,state) Définit l’état d’une broche. TABLE 4 – Résumé de l’API python RPi.GPIO. est indenté : chaque ligne est précédée d’une tabulation. La ligne 10 change l’état de la broche : le nouvel état est celui trouvé dans la variable state. La ligne 11 inverse l’état de la variable booléenne state. La ligne 12 attend durant 1 seconde. La ligne 14 libère les ressources utilisées par le module RPi.GPIO et restaure l’état initial de la broche 3. 1 import RPi.GPIO as GPIO 2 import time 3 4 GPIO.setmode(GPIO.BCM) 5 GPIO.setup(3, GPIO.OUT) 6 7 state= False 8 9 for i in range(20): 10 GPIO.output(3, state) 11 state= not(state) 12 time.sleep(1) 13 14 GPIO.cleanup() Afin d’exécuter le programme ci-dessus, il faut le placer dans un fichier texte. Ici, nous supposons qu’il s’agit du fichier gpio-out.py. Le programme peut ensuite être exécuté comme suit pi@rpi:˜$ python gpio-out.py Traceback (most recent call last): File "gpio-out.py", line 5, in GPIO.setup(3, GPIO.OUT) RuntimeError: No access to /dev/mem. Try running as root! pi@rpi:˜$ sudo python gpio-out.py (...broche 3 devrait changer...) pi@rpi:˜$ L’exemple de programme qui suit contrôle une broche d’entrée. La ligne 5 configure la broche 2 en entrée. Le programme est constitué d’une boucle sans fin qui s’étale sur les lignes 9 à 18. Il s’agit d’une boucle while qui s’exécute tant que la condition est vraie. Ici, la condition est True et par conséquent toujours vraie. La ligne 10 lit l’état de la broche 2 et le stocke dans la variable state. La ligne 11 attend 100ms 7 . Lignes 12 et 13, si l’état lu (variable state) est identique à l’ancien état (variable oldState), alors l’itération courante est terminée : grâce au mot clé continue, le programme retourne immédiatement au début de la boucle. L’ancien état devient le nouvel état à la ligne 14. Aux lignes 15 à 7. Sans cette attente, le programme va en permanence exécuter la boucle et consommer 100% du CPU. 6
18, une chaı̂ne de caractère est affichée avec print selon l’état de la broche. Ce programme ne se termine pas, en raison de la boucle sans fin. Pour l’arrêter, presser les touches Ctrl-C. 1 import RPi.GPIO as GPIO 2 import time 3 4 GPIO.setmode(GPIO.BCM) 5 GPIO.setup(2, GPIO.IN) 6 7 oldState= None 8 9 while True: 10 state= GPIO.input(2) 11 time.sleep(0.1) 12 if state == oldState: 13 continue 14 oldState= state 15 if state: 16 print "button released" 17 else: 18 print "button pressed" 19 20 GPIO.cleanup() Dans le programme ci-dessus, l’appel à la fonction cleanup de la ligne 20 n’est jamais réalisé. La raison est que le programme est terminé abruptement par la pression des touches Ctrl-C. Ceci résulte en l’envoi au programme d’un signal d’interruption. Il est possible de capturer ce signal afin d’interrompre le programme tout en libérant correctement les ressources. L’exemple ci-dessous illustre comment cela peut être fait. Tout le code du programme initial n’est pas repris. La clé de la solution est l’usage de la structure try...except qui permet de capturer l’exception KeyboardInterrupt produite lorsqu’un signal d’interruption est reçu durant l’exécution de la boucle. 1 try: 2 while True: 3 state= GPIO.input(2) 4 time.sleep(0.1) 5 # ... 6 except KeyboardInterrupt: 7 pass 8 9 GPIO.cleanup() Il est possible d’activer les résistances pull-up ou pull-down via le module RPi.GPIO, avec la fonc- tion setup. Par exemple, si le programme est utilisé avec le circuit bouton poussoir de la Figure 1b, la résistance R1 de 10kΩ doit être utilisée 8 . Cependant, elle peut être omise si la résistance de pull-up interne de la broche est activée. L’extrait suivant illustre comment configurer la broche 22 comme entrée avec pull-up interne activée. 1 GPIO.setup(22, GPIO.IN, pull up down=GPIO.PUD UP) 4.3 Contrôle via les registres Les API telles que SysFS et RPi.GPIO permettent le contrôle des entrées/sorties au travers de registres spéciaux du SoC BCM2835. Les performances de SysFS et RPi.GPIO sont limitées (voir Table 1). Pour 8. Sauf dans le cas de GPIO 2 et 3 (modèles rev.2 ou plus), des résistances de pull-up externe de 1,8KΩ sont présentes sur la platine 7
cette raison, cette section s’intéresse au contrôle des entrées/sorties par la programmation directe des re- gistres spéciaux du SoC. Les registres spéciaux sont accédés au travers d’opération de lecture / écriture en mémoire. On parle de memory-mapped registers. Les registres font 32 bits de large. La Table 5 présente une liste partielle des registres destinés au contrôle des broches d’entrées/sorties. Pour chaque registre, les informations suivantes sont fournies : le nom du registre, une brève description, le type d’accès (lecture/écriture) et l’adresse à laquelle le registre est accessible en mémoire. Register name Description Access Addresses GPFSEL0 select function R/W 0x7E200000 GPFSEL1 select function R/W 0x7E200004 ... ... GPFSEL5 select function R/W 0x7E200014 GPSET0 set output state W 0x7E20001C GPSET1 set output state W 0x7E200020 GPCLR0 clear output state W 0x7E200028 GPCLR1 clear output state W 0x7E20002C GPLEV0 read input state R 0x7E200034 GPLEV1 read input state R 0x7E200038 several registers configure pin events read datasheet GPPUD, GPPUDCLOK..1 configure pull-up/down read datasheet TABLE 5 – Aperçu des registres spéciaux destinés au contrôle des entrées/sorties du SoC BCM2835. Afin de contrôler une broche de sortie digitale, il est nécessaire de contrôler 3 registres. Le premier registre, nommé GPFSELn, permet de sélectionner la fonction associée à la broche : dans notre cas, sortie digitale. Ensuite, les registres nommés GPSETp et GPCLRp permettent respectivement de mettre l’état de la broche à un état haut ou bas. La Table 6 indique la signification des bits du registre GPFSEL0. Les autres registres GPFSELn sont structurés de la même manière. Le registre GPFSEL0 permet de contrôler la fonction des broches GPIO 0 à 9. Trois bits sont réservés dans ce registre par broche. Par exemple, la fonction de la broche 0 est sélectionnée avec les bits 0 à 2 de GPFSEL0 alors que la fonction de la broche 6 sera sélectionnée avec les bits 18 à 20. A ce stade, les seules fonctions qui nous intéressent sont 000 (0) pour une entrée et 001 (1) pour une sortie. Bits Field Description 31-30 — Reserved 29-27 FSEL9 Select function of GPIO 9 26-24 FSEL8 Select function of GPIO 8 ... ... 5-3 FSEL1 Select function of GPIO 1 2-0 FSEL0 Select function of GPIO 0 TABLE 6 – Structure du registre GPFSEL0. La Table 7 décrit le contenu du registre GPSET0. Ce registre contrôle l’état des broches 0 à 31. Le registre GPSET1 a une structure similaire et contrôle les broches 32 à 54. Mettre à 1 le bit k dans le registre GPSET0 revient à mettre la broche k à un niveau haut (pour 0 ≤ k ≤ 31). La Table 8 décrit le contenu du registre GPCLR0. Le comportement est similaire à celui du registre GPSET0 à l’exception que mettre à 1 le bit k dans le registre GPCLR0 revient à mettre la broche k à un niveau bas (pour 0 ≤ k ≤ 31). Le registre GPCLR1 a une structure similaire et contrôle les broches 32 à 53. 8
Bits Field Description 31 SET31 0 = no change ; 1 = set GPIO pin 31 ... ... 1 SET1 0 = no change ; 1 = set GPIO pin 1 0 SET0 0 = no change ; 1 = set GPIO pin 0 TABLE 7 – Structure du registre GPSET0. Bits Field Description 31 CLR31 0 = no change ; 1 = clear GPIO pin 31 ... ... 1 CLR1 0 = no change ; 1 = clear GPIO pin 1 0 CLR0 0 = no change ; 1 = clear GPIO pin 0 TABLE 8 – Structure du registre GPCLR0. La Table 9 décrit le contenu du registre GPLEV0. Ce registre permet de connaı̂tre l’état des broches 0 à 31. Le registre GPLEV1 a une structure similaire et permet de lire l’état des broches 32 à 54. Bits Field Description 31 LEV31 0 = low ; 1 = high ... ... 1 LEV1 0 = low ; 1 = high 0 LEV0 0 = low ; 1 = high TABLE 9 – Structure du registre GPLEV0. L’extrait de programme en C suivant illustre comment la broche 22 peut être configurée en sortie. Pour cela, il est nécessaire de remplacer les bits 6 à 8 dans le registre GPFSEL2 par la valeur 001. Assurez-vous que vous comprenez pourquoi il s’agit de ce registre et de ces bits. Le programme suivant fait l’hypothèse que l’adresse du registre GPFSEL2 se trouve préalablement dans la variable GPFSEL2. La valeur du registre est lue et les bits 6 à 8 sont masqués en effectuant un ET bit à bit (opérateur &) avec la valeur exprimée en hexadécimal 0xFFFFFE3F. Cette valeur correspond à un nombre de 32 bits dans lequel tous les bits sont à 1 sauf les bits 6 à 8 qui valent 0. Le résultat est combiné (opérateur |, OU bit à bit) avec la valeur sélectionnant une sortie (1) décalée de 6 positions vers la gauche (opérateur
Les commandes suivantes illustrent comment il est possible au travers de SysFS de configurer les interruptions matérielles GPIO et la génération d’événements fichiers. pi@rpi:˜$ echo "3" > /sys/class/gpio/export pi@rpi:˜$ echo "in" > /sys/devices/virtual/gpio/gpio3/direction pi@rpi:˜$ echo "both" > /sys/devices/virtual/gpio/gpio3/edge pi@rpi:˜$ 5.1 Evenements GPIO en Python L’exemple suivant illustre comment les événements GPIO peuvent être capturés au travers de l’API RPi.GPIO. L’API s’occupe également de configurer 1 import RPi.GPIO as GPIO 2 3 GPIO.setmode(GPIO.BCM) 4 GPIO.setup(2, GPIO.IN) 5 6 while True: 7 GPIO.wait_for_edge(2, GPIO.BOTH) 8 if GPIO.input(2): 9 print "button released" 10 else: 11 print "button pressed" 6 Projet d’application Que faire en pratique avec les entrées/sorties digitales de la platine Raspberry Pi ? Les applications sont nombreuses et sont seulement limitées par votre imagination. Un exemple pourrait être de contrôler un éclairage (p.ex. une LED), un moteur, un relais, etc. ou contrôler l’état d’un capteur à distance au travers d’une page web. 10
A Annexe A.1 Structure d’une broche GPIO Il peut être utile de comprendre la structure des broches d’I/O afin de les utiliser correctement et de ne pas endommager le SoC. Toutes les broches GPIO ont une structure similaire. Chaque broche peut être utilisée comme une entrée ou une sortie digitale. Certaines broches ont des fonctionnalités plus complexes telles que des interfaces de communication (UART, I2 C, SPI) ou PWM. La Figure 4 illustre la structure d’une broche GPIO unique. La partie extérieure à droite du rectangle, illustre la broche, tandis que l’intérieur du rectangle illustre le contenu du SoC permettant de contrôler cette broche. Un buffer de sortie permet de changer la tension de la broche en fonction d’un bit dans un registre du SoC. Ce buffer de sortie n’est actif que si la broche est configurée comme sortie via un bit d’un registre du SoC (voir l’étiquette direction). Un buffer d’entrée permet de lire l’état de la broche. F IGURE 4 – Structure d’une broche d’I/O. Finalement, pour chaque broche, des résistances de pull-up ou pull-down peuvent être optionnellement activées individuellement. Les résistances de pull-up ou pull-down sont utilisées avec les broches confi- gurées comme entrées digitales, en l’absence de connection avec un circuit externe ou lorsque celui-ci est en état de haute impédance. Une résistance de pull-up tire le niveau de l’entrée vers le haut, tandis qu’une résistance de pull-down tire le niveau vers le bas. A.2 Exemple complet en C Cette section contient un exemple complet de programme en C permettant d’accéder directement aux registres du SoC. Le programme nécessite d’accéder aux registres spéciaux du SoC. Cependant, ces registres se situent dans une zone mémoire qui n’est pas directement accessible à un programme utilisateur. Il est cependant possible d’accéder à l’entiereté de la mémoire au travers du pseudo fichier /dev/mem. L’accès à ce pseudo fichier est restreint : il faut les privilèges d’administrateur. Accéder au fichier /dev/mem avec des appels systèmes tels que read et write n’est pas très efficace. Pour cette raison, le programme demande au kernel de créer une page mémoire alignée sur la partie du fichier (lire de la mémoire) qui correspond aux registres spéciaux contrôlant les GPIO. Ainsi, lire/écrire dans cette page mémoire aura pour effet de lire/écrire dans /dev/mem à la position des registres qui nous intéressent. Pour obtenir une telle page, l’appel système mmap est employé. Il est notamment nécessaire d’indiquer à mmap l’adresse mémoire de base à laquelle se situent les registres. Cette adresse vaut 0x20200000. Les étudiants attentifs auront peut être remarqué que cette adresse est fort différente des adresses ren- seignées à la Table 5. La raison est simplement que /dev/mem expose la mémoire au travers des adresses physiques alors que la Table 5 renseigne les adresses des registres GPIO sur un bus interne au SoC. La Figure 5 illustre la correspondance entre les divers types d’adresses. Toute cette technique est regroupée dans la fonction get mmapped gpio dans le programme ci- dessous. Le restant du programme consiste à accéder aux registres au travers de la page mémoire ainsi créée. Le programme configure la broche 27 en sortie puis change sa valeur toutes les secondes. 11
F IGURE 5 – Correspondance entre adresses de bus, physiques et virtuelles. 1 #include 2 #include 3 #include 4 #include 5 #include 6 #include 7 #include 8 #include 9 10 #define PHYS_GPIO_BASE 0x20200000 11 12 #define GPFSEL0_OFFSET 0x00000 13 #define GPSET0_OFFSET 0x0001C 14 #define GPCLR0_OFFSET 0x00028 15 16 #define GPF_INPUT 0 17 #define GPF_OUTPUT 1 18 19 void * get_mmapped_gpio() 20 { 21 int page_size= getpagesize(); 22 int fd= open("/dev/mem", O_RDWR | O_SYNC); 23 if (fd < 0) { 24 perror("open"); 25 return NULL; 26 } 27 28 void * addr= mmap(NULL, page_size, PROT_READ | PROT_WRITE, 29 MAP_SHARED, fd, PHYS_GPIO_BASE); 30 if (addr == MAP_FAILED) { 31 perror("mmap"); 32 return NULL; 33 } 34 35 close(fd); 36 return addr; 37 } 38 12
39 int main() 40 { 41 void * addr= get_mmapped_gpio(); 42 if (addr == NULL) 43 exit(EXIT_FAILURE); 44 45 volatile uint32_t * GPFSEL0= (volatile uint32_t *) (addr + GPFSEL0_OFFSET); 46 volatile uint32_t * GPSET0= (volatile uint32_t *) (addr + GPSET0_OFFSET); 47 volatile uint32_t * GPCLR0= (volatile uint32_t *) (addr + GPCLR0_OFFSET); 48 49 unsigned char pin= 27; 50 volatile uint32_t * GPFSEL= GPFSEL0 + (pin/10); 51 int bit_pos= 3 * (pin%10); 52 *GPFSEL= (*GPFSEL & ˜(7
3,3V 1 2 5V I2C SDA GPIO 2 3 4 5V I2C SCL GPIO 3 5 6 GND GPCLK0 GPIO 4 7 8 GPIO 14 UART TxD GND 9 10 GPIO 15 UART RxD GPIO 17 11 12 GPIO 18 PCM CLK GPIO 27 13 14 GND GPIO 22 15 16 GPIO 23 3,3V 17 18 GPIO 24 SPI MOSI GPIO 10 19 20 GND SPI MISO GPIO 9 21 22 GPIO 25 SPI SCLK GPIO 11 23 24 GPIO 8 SPI CE0 GND 25 26 GPIO 7 SPI CE1 EEPROM ID SD 27 28 EEPROM ID SC GPIO 5 29 30 GND GPIO 6 31 32 GPIO 12 GPIO 13 33 34 GND GPIO 19 35 36 GPIO 16 GPIO 26 37 38 GPIO 20 GND 39 40 GPIO 21 TABLE 10 – Connecteur J8, modèles A+ et B+ 3,3V 1 2 5V I2C1 SDA GPIO 2 3 4 5V I2C1 SCL GPIO 3 5 6 GND GPCLK0 GPIO 4 7 8 GPIO 14 UART TxD GND 9 10 GPIO 15 UART RxD GPIO 17 11 12 GPIO 18 PCM CLK GPIO 27 13 14 GND GPIO 22 15 16 GPIO 23 3,3V 17 18 GPIO 24 SPI0 MOSI GPIO 10 19 20 GND SPI0 MISO GPIO 9 21 22 GPIO 25 SPI0 SCLK GPIO 11 23 24 GPIO 8 SPI0 CE0 GND 25 26 GPIO 7 SPI0 CE1 TABLE 11 – Connecteur P1, modèles A et B rev.2 14
3,3V 1 2 5V I2C0 SDA GPIO 0 3 4 5V I2C0 SCL GPIO 1 5 6 GND GPCLK0 GPIO 4 7 8 GPIO 14 UART TxD GND 9 10 GPIO 15 UART RxD GPIO 17 11 12 GPIO 18 PCM CLK GPIO 21 13 14 GND GPIO 22 15 16 GPIO 23 3,3V 17 18 GPIO 24 SPI0 MOSI GPIO 10 19 20 GND SPI0 MISO GPIO 9 21 22 GPIO 25 SPI0 SCLK GPIO 11 23 24 GPIO 8 SPI0 CE0 GND 25 26 GPIO 7 SPI0 CE1 TABLE 12 – Connecteur P1, modèles A et B rev.1 15
Vous pouvez aussi lire