Linear Feedback Shift Register with VHDL.
Dans la première partie, nous avons vu la lecture et l'écriture en mode digital (0 ou 1). Maintenant nous allons lire la valeur analogique sur une patte en utilisant un petit montage avec une Photorésistance LDR.
Il faut savoir qu'il y a 7 entrées analogiques réparties sur le Port 9 de la platine: la patte 39 référencée AIN0, la patte 40 référencée AIN1, la patte 37 référencée AIN2, la patte 38 référencée AIN3, la patte 33 référencée AIN4, la patte 36 référencée AIN5, la patte 35 référencée AIN6 et la patte 39 référencée AIN0. A proximité les pattes 32 et 34, respectivement la patte de tension de référence 1.8V VDD_ADC et la patte de mise à la masse GNDA_ADC.
La lecture analogique utilise le convertisseur interne de la platine, ici un convertisseur Analogique > Numérique de résolution 12 Bits, nous lirons donc un nombre compris entre 0 et 4095 pour une tension entre 0 et 1.8V. Le taux d'échantillonnage est de 200K par seconde par défaut et TRES IMPORTANT, la tension en entrée NE DOIT JAMAIS dépasser 1.8V. Si vous avez besoin d'utiliser la tension de 3.3V proposée par la platine, il faudra IMPERATIVEMENT utiliser un diviseur de tension !
Il n'y a pas besoin de paramétrer ces 7 pattes car on ne peut les utiliser qu'en mode entrée analogique. Le fichier où trouver les valeurs de ces pattes est le suivant cd /sys/devices/platform/tsc. A noter que la patte AIN0 sera lue dans le fichier ain1, la patte AIN1 dans le fichier ain2, et ainsi de suite...
root@beaglebone:~# cd /sys/devices/platform/tsc root@beaglebone:/sys/devices/platform/tsc# ls ain1 ain2 ain3 ain4 ain5 ain6 ain7 ain8 driver modalias power subsystem uevent
Revenons à notre montage avec notre photorésistance. Nous utiliserons une résistance de 10 Kilo Ohms et donc notre photorésistance. Une patte de la résistance sera connectée à la patte 34 (GNDA_ADC) de la platine, l'autre patte sera connectée à la fois à une des pattes de la photorésistance et à la patte 39 (AIN0) de la platine. La patte restante de la photorésistance sera connectée sera connectée à la patte 32 (VDD_ADC) qui fournit la tension 1.8V. La résistance interne de la photo résistance évolue inversement avec l'intensité lumineuse, ce type de capteur n'est pas très précis mais il permets de mesurer des variations de lumières sans problème. Lorsqu'il fait sombre, la photorésistance se comporte comme une résistance de très grande valeur, plusieurs Méga Ohms, et lorsque le niveau lumineux augmente, la résistance diminue fortement. Le courant traversant le circuit augmente alors dans la résistance Pull Down de 10 Kilo Ohms, la chute de tension au borne de cette résistance Pull Down devient de plus en plus importante et donc la tension mesurée sur la patte d'entrée analogique de la platine augmente.
La commande pour lire la valeur entre 0 et 4095 sur la patte AINO est très simple.
root@beaglebone:/sys/devices/platform/tsc# cat ain1 2675
A présent voici le script de lecture que nous appelerons analogique.sh. Nous faisons un petit calcul pour transformer la valeur renvoyée sur 12 Bits en pourcentage. (Utiliser un capuchon de stylo bic pour tester la pénombre ;))
#!/bin/sh # Fichier analogique.sh # Affiche en % (0-100) l'intensité lumineuse recue par la photorésistance # On boucle une grosse vingtaine de seconde pour vous laisser le temps de tester count=1 while [ $count -le 200 ]; do let val=$(cat /sys/devices/platform/tsc/ain1)*100/4095 clear echo $val sleep 0.1 let count=count+1 done
Vous trouverez sur le web de nombreux exemples où on utilise des capteurs qui peuvent être interfacer sur la platine mais qui doivent souvent être alimenté entre 3 et 5V. FAITES très attention si vous connectez un capteur de témpérature sur la patte de tension 3,3V car le module de convertisseur Analogique > Numérique de la platine n'accepte pas de lire au dessus de 1.8V.
L'exemple suivant utilise un capteur de température basse tension TMP36 qui nécessite une tension minimale de 2.7V pour fonctionner. L'utilisateur le branche donc sur la patte qui fournit le 3.3V et lis ensuite via une des pattes d'entrée analogique la valeur de température sur 12 Bits. Il ne risque pas grand chose car vu la plage étendue dans les hautes températures, la valeur de 3.3V qui correspondrait à une température de plus de 100°C ne sera jamais atteinte dans son appartement, enfin je l'espère ;)
Il faut savoir que les entrées analogiques de la platine Beaglebone ne sont pas spécialement dédiées à la lecture de capteur mais plutot pour l'interfaçage d'écran tactile. Dès que le module avec l'écran tactile 3" sera sorti, il est prévu pour le 29 juin, j'y reviendrai.
Tout d'abord un petit rappel: Un signal PWM est un signal numérique (donc deux états, Bas et Haut, seulement) qui représente une valeur analogique sous la forme d’un rapport cyclique que l'utilisateur pourra faire varier. On pourra donc contrôler l'intensité lumineuse de Leds, d'Ampoules basse tension ou la vitesse de Servomoteurs pour le modélisme ou autres Moteurs CC. Un signal PWM permet d'obtenir l'équivalent d'une variation de tension continue mais pour que l'impression d'une valeur moyenne constante apparaisse, il faut que l'alternance état Haut / état Bas soit suffisamment rapide pour que cette alternance ne se remarque pas.
Nous allons donc dans cette partie faire varier l'intensité lumineuse de notre Led en faisant varier le rapport cyclique (ou duty cycle) du signal PWM. Pour se faire, étudions la configuration du module PWM sur la platine.
Les dernières versions de la distribution Angstrom, celles supérieures à 3.2.+ supportent le module PWM mais, comme sur la version de mon noyau 3.2.14, il est nécessaire de l'activer, enfin d'activer l'horloge du module PWM. Cela ne peut être fait à travers les fichiers classiques que nous manipulons dans les autres parties, il faut en effet écrire et modifier le registre dans la mémoire de la platine. En fouillant sur le web, j'ai trouvé ce lien qui présente une méthode rapide que je vais résumer rapidement. Voici la séquence de commandes nécessaire à l'activation de l'horloge PWM. L'auteur utilise un module du langage de script Python, mmap, qui va permettre de modifier la mémoire et le registre. Le script final, écrit donc en langage Python, est téléchargé à l'aide de la merveilleuse commande Shell wget puis lancé avec la commande python setPWMReg.py.
root@beaglebone:~# opkg install python-mmap root@beaglebone:~# wget http://www.gigamegablog.com/docs/setPWMReg.py root@beaglebone:~# python setPWMReg.py
La platine Beaglebone dispose de 4 sorties PWM, EHRPWM1A et EHRPWM1B sur les pattes 14 et 16 du port 9, et EHRPWM2A et EHRPWM2B sur les pattes 19 et 13 du port 8. Il semblerait que le script proposé au dessus ne me permette pas d'utiliser la sortie PWM sur les pattes 19 et 13. En date du 13 juin, je suis en train de travailler dessus (MAJ à venir donc) car il semblerait qu'une légère modification du script permette d'activer les autres sorties.
Notre montage est très simple, l'anode (+) de la Led sera connectée à la patte 14 du port 9, la cathode (-) à une résistance 220 Ohms qui sera elle connectée à la masse. La tension de sortie étant de 3.3V sur cette patte 14, on pourrait aussi connecter la Led sans résistance. Voyons donc les paramètres pour cette patte 14 (P9_14) dont le nom de fichier pour le Mux Mode est gpmc_a2.
root@beaglebone:/sys/kernel/debug/omap_mux# cat gpmc_a2 name: gpmc_a2.gpio1_18 (0x44e10848/0x848 = 0x0027), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7 signals: gpmc_a2 | mii2_txd3 | rgmii2_td3 | mmc2_dat1 | NA | NA | ehrpwm1A | gpio1_18
Sans surprise, le Mode 7 est le mode par défaut et nous voyons que le mode précédent le Mode 7 dans l'enumération, le Mode 6, est le mode dont nous avons besoin pour utiliser la sortie PWM sur cette patte.
root@beaglebone:/sys/kernel/debug/omap_mux# echo 6 > gpmc_a2 root@beaglebone:/sys/kernel/debug/omap_mux# cat gpmc_a2 name: gpmc_a2.ehrpwm1A (0x44e10848/0x848 = 0x0006), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE6 signals: gpmc_a2 | mii2_txd3 | rgmii2_td3 | mmc2_dat1 | NA | NA | ehrpwm1A | gpio1_18
Nous pouvons maintenant contrôler via Linux la sortie PWM sur la patte 14 et notamment fixer les paramètres tels que la fréquence et le rapport cyclique du signal.
root@beaglebone:~# cd /sys/class/pwm root@beaglebone:/sys/class/pwm# ls ecap.0 ecap.1 ehrpwm.0:0 ehrpwm.0:1 ehrpwm.1:0 ehrpwm.1:1 root@beaglebone:/sys/class/pwm# cd ehrpwm.1:0 root@beaglebone:/sys/class/pwm/ehrpwm.1:0# ls device duty_ns duty_percent period_freq period_ns polarity power request run subsystem ...
Le fichier request sert à activer ou libérer la sortie PWM, le fichier run sert à lancer ou stopper le module PMW. Sinon le fichier period_freq sert à fixer la fréquence en Hz du signal et le fichier duty_percent sert à fixer le fameux rapport cyclique. Il faut savoir que la fréquence est partagée entre la paire de sortie EHRPWM1A et EHRPWM2A.
Voici comment allumer notre Led à 50% de sa valeur maximale. La fréquence utilisée est 100Hz pour éviter le scintillement. Vous remarquerez que nous mettons le rapport cyclique à zéro avant tout nouveau changement de fréquence, ceci est clairement spécifié dans les notes d'application du processeur AM335x_PWM. L'instruction finale cat request nous montre bien que la sortie PWM est en cours d'utilisation par le système et que nous pouvons modifier les paramètres à travers le système Linux.
root@beaglebone:/sys/class/pwm/ehrpwm.1:0# cat request ehrpwm.1:0 is free root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 1 > request root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 0 > duty_percent root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 100 > period_freq root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 50 > duty_percent root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 1 > run root@beaglebone:/sys/class/pwm/ehrpwm.1:0# cat request ehrpwm.1:0 requested by sysfs
Vous pouvez vous maintenant faire varier le rapport cyclique et voir les différents niveaux lumineux de la Led.
root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 20 > duty_percent root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 80 > duty_percent root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 10 > duty_percent root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 100 > duty_percent
Si vous voulez arrêter la sortie PWM, n'oubliez pas de la libérer aussi.
root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 0 > run root@beaglebone:/sys/class/pwm/ehrpwm.1:0# cat request ehrpwm.1:0 requested by sysfs root@beaglebone:/sys/class/pwm/ehrpwm.1:0# echo 0 > request root@beaglebone:/sys/class/pwm/ehrpwm.1:0# cat request ehrpwm.1:0 is free
Passons maintenant à notre prochain montage qui va consister à lire sur la patte d'entrée analogique P9_39 le niveau d'intensité lumineuse à travers notre photorésistance de la première partie et à allumer de façon proportionnelle notre Led sur la patte P9_14, en clair moins de lumière sera detectée par notre photorésistance, moins la Led sera éclairée.
Voici donc le script appelé pwm_led.sh. Ce script se termine quand la quantité de lumière reçue est très faible (<5%)
#!/bin/sh # fichier pwm_led.sh # On paramètre le mode 6 pour pouvoir utiliser EHRPMW1A echo 6 > /sys/kernel/debug/omap_mux/gpmc_a2 # Activation du module PWM. echo 1 > /sys/class/pwm/ehrpwm.1:0/request # On démarre le module PWM echo 1 > /sys/class/pwm/ehrpwm.1:0/run # on fixe la fréquence à 100Hz. echo 0 > /sys/class/pwm/ehrpwm.1:0/duty_percent echo 100 > /sys/class/pwm/ehrpwm.1:0/period_freq # On lit la valeur sur l'entrée analogique de la patte P9_39. # Cette valeur est mis à l'échelle en pourcentage. let "duty=$(cat /sys/devices/platform/tsc/ain1)*100/4095" # Tant qu'il fait jour (la photorésistance capte suffisament de lumière > 5%), # La boucle écrit sur la sortie PWM de la Led et allume la Led selon le niveau de lumière. while [ $duty -gt 5 ]; do echo $duty > /sys/class/pwm/ehrpwm.1:0/duty_percent let "duty=$(cat /sys/devices/platform/tsc/ain1)*100/4095" clear echo $duty done # On stoppe la sortie PWM echo 0 > /sys/class/pwm/ehrpwm.1:0/run echo 0 > /sys/class/pwm/ehrpwm.1:0/request
Notre prochain script sera une variante du script analogique.sh présenté plus haut, nous n'afficherons plus le résultat de la lecture analogique sur la console Linux mais sur un afficheur LCD Série 2x16 caractères. Ce genre d'afficheur LCD Série, rétroéclairé ou non, est aussi vendu chez Lextronic en France. Il a besoin d'une tension de 5V que nous trouverons sur la patte 6 VDD_5V de la platine. Les masses seront reliées entre elles. L'entrée de l'afficheur sera connectée à la platine comme indiqué plus bas.
Qui dit afficheur série dit établissement d'une liaison série entre notre Beaglebone et l'afficheur. La platine dispose de 5 ports série paramétrables et utilisables pour établir cette liaison. Ce sont les paires de pattes UART1_TXD/RXD à UART5_TXD/RXD, par exemple sur le port 9, celui de gauche, nous avons les pattes 24 et 26 pour l'UART1. Nous avons ici un afficheur série à sens unique, nous envoyons des informations sur l'afficheur mais lui ne nous renvoie aucune information. Nous avons donc juste besoin de la patte 24 appelée UART1_TXD. Comme nous en avons l'habitude, nous allons utiliser le manuel de référence pour trouver le Mode qui correspondra au bon usage de la patte. Ici c'est le mode 0 qui nous intéresse pour le bon paramétrage. Cette patte 24 est référencée par le label uart1_txd.
root@beaglebone:/sys/kernel/debug/omap_mux# echo 0 > uart1_txd root@beaglebone:/sys/kernel/debug/omap_mux# cat uart1_txd name: uart1_txd.uart1_txd (0x44e10984/0x984 = 0x0000), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE0 signals: uart1_txd | mmc2_sdwp | d_can1_rx | i2c1_scl | NA | pr1_uart0_txd_mux1 | NA | gpio0_15
Attention si nous avions utilisé la patte 21 UART2_TXD référencée spi0_d0, nous aurions dû écrire cette commande car le manuel de référence nous dit que c'est le mode 1 qui correspond au bon paramétrage.
root@beaglebone:/sys/kernel/debug/omap_mux# cat spi0_d0 name: spi0_d0.gpio0_3 (0x44e10954/0x954 = 0x0037), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7 signals: spi0_d0 | uart2_txd | i2c2_scl | NA | NA | NA | NA | gpio0_3 root@beaglebone:/sys/kernel/debug/omap_mux# echo 1 > spi0_d0 root@beaglebone:/sys/kernel/debug/omap_mux# cat spi0_d0 name: spi0_d0.uart2_txd (0x44e10954/0x954 = 0x0001), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE1 signals: spi0_d0 | uart2_txd | i2c2_scl | NA | NA | NA | NA | gpio0_3
Nous avons donc notre patte 24 (TX) prête à envoyer des données à notre afficheur sur son entrée (RX) via la liaison série. Nous devons consulter la documentation de l'afficheur pour trouver quel type de liaison série mettre en oeuvre. Sans grande surprise, nous trouvons qu'il faut utiliser une liaison série 1N8, 8 bits par caractères, Aucune parité, 1 Stop Bit et avec des vitesses allant de 9600 à 19200 bauds. Tout d'abord jetons un oeil sur les ports série de notre Beaglebone.
root@beaglebone:~# dmesg | grep tty [ 0.000000] Kernel command line: console=ttyO0,115200n8 run_hardware_tests quiet root=/dev/mmcblk0p2 ro rootfstype=ext4 rootwait ip=none [ 0.121074] omap_uart.0: ttyO0 at MMIO 0x44e09000 (irq = 72) is a OMAP UART0 [ 0.128058] console [ttyO0] enabled [ 0.128410] omap_uart.1: ttyO1 at MMIO 0x48022000 (irq = 73) is a OMAP UART1 [ 0.128717] omap_uart.2: ttyO2 at MMIO 0x48024000 (irq = 74) is a OMAP UART2 [ 0.129003] omap_uart.3: ttyO3 at MMIO 0x481a6000 (irq = 44) is a OMAP UART3 [ 0.129277] omap_uart.4: ttyO4 at MMIO 0x481a8000 (irq = 45) is a OMAP UART4 [ 0.129560] omap_uart.5: ttyO5 at MMIO 0x481aa000 (irq = 46) is a OMAP UART5Nous utiliserons donc le fichier /dev/ttyO1 pour "écrire" sur notre afficheur via la patte 24 UART1_TXD. Ensuite nous utiliserons la commande shell stty pour paramétrer simplement le port série. Reportez à la documentation sur stty pour connaître les options utilisées et leurs significations.
root@beaglebone:~# stty -F /dev/ttyO1 9600 -parity -clocal crtscts -echo
Nous utiliserons la vitesse de transmission de 9600 bauds donc prenez garde à bien sélectionner la valeur 9600 au dos de l'afficheur avec les deux commutateurs SW1 et SW2 (Cf Manuel plus haut). La lecture du manuel sera nécessaire pour trouver les séquences correctes à envoyer pour allumer/éteindre le rétroéclairage, modifier le type de curseur et l'affichage...
Voici donc notre ancien script modifié pour afficher la valeur de l'intensité lumineuse lue avec la photorésistance sur l'afficheur LCD.
#!/bin/sh # fichier analogique_lcd.sh # Affiche en % (0-100) sur l'afficheur LCD l'intensité lumineuse recue par la photorésistance # Configure la patte 24 pour utiliser le Mode 0 et uart1_txd echo 0 > /sys/kernel/debug/omap_mux/uart1_txd # Paramétrage de la liaison série 1N8 9600 Bauds stty -F /dev/ttyO1 9600 -parity -clocal crtscts -echo # Allume l'afficheur, curseur invisible et pas de clignotement echo $'\x16' > /dev/ttyO1 # Retroclairage de l'afficheur echo $'\x11' > /dev/ttyO1 # On boucle une grosse dizaine de seconde pour vous laisser le temps de tester count=1 while [ $count -le 25 ]; do let val=$(cat /sys/devices/platform/tsc/ain1)*100/4095 echo $'\x0C' > /dev/ttyO1 echo $val > /dev/ttyO1 sleep 0.4 let count=count+1 done # Retroéclairage sur off echo $'\x12' > /dev/ttyO1 # Eteint l'afficheur echo $'\x15' > /dev/ttyO1
Vous trouverez page 7 et 8 du manuel de l'afficheur les constantes à utiliser pour allumer ou non le rétroéclairage, effacer l'écran de l'afficheur ou bien l'éteindre complètement. Cet exemple est encore une fois simpliste mais il vous permettra de démarrer et d'interfacer d'autres matériels utilisant des liaisons séries asynchrones du même type.
Pour aller plus loin, vous pouvez télécharger ce programme en langage C qui simule l'affichage d'un égaliseur (equalizer) audio.
root@beaglebone:~# wget http://emmanuel.pouly.free.fr/fichier/serial.c Connecting to emmanuel.pouly.free.fr (212.27.63.136:80) serial.c 100% |****************************************************| 1575 0:00:00 ETA root@beaglebone:~# gcc -o progser serial.c root@beaglebone:~# ./progser Serial connection established on /dev/ttyO1
Voici une photo de l'écran LCD utilisé, une fois le programme lancé, vous devriez voir la taille des barres varier aléatoirement.
Si vous désirez utiliser le port série avec d'autres matériels, attention cependant à ne pas connecter des modules à communication bidirectionnelle TX/RX (contrairement à l'afficheur LCD) qui ont besoin d'une tension supérieure à 3.3V, il y a un risque de destruction de votre platine ! Vous pouvez visiter ce site web où il est question d'interfaçage de modules X-Bee.
Nous allons utiliser le capteur de température Dallas DS18B20 (précision +/- 0.5°C) à sortie numérique et mettre en oeuvre le fameux bus 1-Wire pour établir une communication avec le capteur. Le bus 1-Wire utilise un unique bus maître qui contrôle un ou plusieurs capteurs dits capteurs esclaves. Nous pourrons donc connecter plusieurs capteurs esclaves DS18B20 sur le même bus mais aussi d'autres types de capteurs en tout genres car chacun aura un numéro d'identification unique sur le bus.
Si vous avez mis à jour la distribution Angstrom comme suggéré dans la partie 1 et que vous avez au moins le noyau 3.2.14, normalement le driver Linux (w1-gpio) pour l'émulation du bus 1-Wire est installé.
root@beaglebone:~# dmesg | grep 1-wire [ 0.605112] Driver for 1-wire Dallas network protocol. root@beaglebone:~# dmesg | grep w1 [ 0.238150] w1-gpio connected to P8_6
Nous utiliserons donc la patte 6 sur le port 8 pour connecter notre capteur DS18B20. Si vous étudiez la fiche technique du capteur, vous observerez qu'il est possible d'alimenter le capteur de deux façons différentes, appelées mode normal et mode parasite. En mode parasite le capteur est alimenté par la même patte que la patte qui sert au transfert de données alors qu'en mode normal, celui que nous utiliserons, le capteur est alimenté avec sa patte VDD et sera connecté au 3.3V sur la platine.
Il est spécifié qu'il faut rajouter une forte résistance de tirage Pull Up sur la ligne de transfert de données. Visualisons donc les paramètres par défaut de la patte P8_6 (label gpmc_ad3) où sera connecté la ligne de transfert de données.
root@beaglebone:~# cat /sys/kernel/debug/omap_mux/gpmc_ad3 name: gpmc_ad3.gpio1_3 (0x44e1080c/0x80c = 0x0037), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7 signals: gpmc_ad3 | mmc1_dat3 | NA | NA | NA | NA | NA | gpio1_3
On voit que la résistance de tirage interne Pull Up (environ 30 Kilo Ohms selon des renseignements trouvés sur le web) est activée. Si la patte P8_6 était dans le mode 27 (tirage Pull Down), le capteur aurait un fonctionnement erratique, voir ne serait pas reconnu.
Chaque capteur DS18B20 possède un numéro d'identification unique codé sur 64 bits.
root@beaglebone:~# cd /sys/bus/w1/devices root@beaglebone:/sys/bus/w1/devices# ls 28-000000cc57d8 w1_bus_master1
On voit ici qu'un nouveau répertoire (le nom sera différent chez vous) est créé: 28-000000cc57d8. Le répertoire sera toujours du type 28-xxxxxxxxxxxx car 28 représente le code de la famille des capteurs DS18B20. Le reste représente le numéro de série unique et l'octet CRC inscrits dans la ROM.
root@beaglebone:/sys/bus/w1/devices# cd 28-000000cc57d8 root@beaglebone:/sys/bus/w1/devices/28-000000cc57d8# ls driver id name power subsystem uevent w1_slave
Lisons maintenant les 9 octets du scratchpad. Le calcul du cycle de vérification du CRC indique YES (le résultat est l'octet le plus à droite, ici 0xe9) et nous pouvons donc lire la température avec une résolution de 0.0625°C. En effet, le 5eme octet en partant de la gauche, ici 0x7f soit 0b01111111, est l'octet qui nous indique que le capteur est configuré avec une résolution de 12 bits (page 7 et 8 de la fiche technique vue plus haut). Il faut attendre 750 ms entre chaque conversion lorsque l'on utilise la résolution de 12 bits.
La température se lit sur les 2 premiers octets, ici 0x53 et 0x01, le premier octet étant l'octet de poids faible. Mais heureusement pour nous, le driver w1-gpio se charge de nous indiquer la température en degré Celsius (enfin presque ;) ) en effectuant le travail de conversion et de complémentation comme il se chargeait de nous indiquer la valeur de la vérification du cycle CRC (pour ceux que cela intéresse voici un lien générique complet sur l'émulation du bus 1-Wire à travers le système GPIO).
root@beaglebone:/sys/bus/w1/devices/28-000000cc57d8# cat w1_slave 53 01 4b 46 7f ff 0d 10 e9 : crc=e9 YES 53 01 4b 46 7f ff 0d 10 e9 t=21187
J'ai trouvé sur le web cette ligne de commande qui utilise la puissante commande shell awk qui analyse la dernière ligne du fichier 28-000000cc57d8/w1_slave en utilisant comme séparateur de motif "=".
root@beaglebone:/sys/.../28-000000cc57d8# cat w1_slave | tail -1 | awk -F "=" '{print $2/1000 " C"}' 21.25 C
Je viens de me procurer ce jour 2 autres capteurs DS18B20. Il y a donc 3 capteurs de brancher sur le bus 1-Wire. Chaque capteur est alimenté par le 3.3V et les pattes centrales de lignes de données sont reliés entre elles tout simplement sur la ligne de bus. On retrouve bien un nom de répertoire unique à chaque fois et il est possible de lire la température sur chacun des capteurs.
root@beaglebone:/sys/bus/w1/devices# ls 28-000000cc57d8 28-0000035abea9 28-0000035ac659 w1_bus_master1
A noter que Lextronic vends des sondes étanches de 1.80 mètres à base de capteur DS18B20. Ce sont les mêmes modèles que ceux issus du fabriquant Sparkun.
Posons nous ce petit problème: Nous voulons que la platine fasse une nouvelle action lorsque vous appuyez sur le bouton poussoir mais vous ne voulez pas "scanner" en temps réel l'état de la patte où est connectée ce bouton poussoir. Il faut alors avoir recours à ce qu'on apelle une interruption. Une interruption est un "signal" qui stoppe le déroulement normal du programme en cours et qui va traiter la tâche liée à l'interruption avant que le processus normal reprenne.
Reprenons notre bouton poussoir connecté sur la patte P9_12. Nous voulons cette patte pour gérer une interruption qui sera pris en compte lors d'une pression. Nous voyons donc ci-dessus que cette patte P9_12 (label gpmc_ben1) est bien utilisable à travers le système de fichiers GPIO (gpio-60).
root@beaglebone:~# echo 60 > /sys/class/gpio/export root@beaglebone:~# cat /sys/kernel/debug/omap_mux/gpmc_ben1 name: gpmc_ben1.gpio1_28 (0x44e10878/0x878 = 0x0037), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE7 signals: gpmc_ben1 | mii2_col | NA | mmc2_dat3 | NA | NA | mcasp0_aclkr | gpio1_28 root@beaglebone:~# cat /sys/kernel/debug/gpio GPIOs 0-31, gpio: gpio-6 (mmc_cd ) in lo GPIOs 32-63, gpio: gpio-35 (w1 ) in hi gpio-53 (beaglebone::usr0 ) out lo gpio-54 (beaglebone::usr1 ) out lo gpio-55 (beaglebone::usr2 ) out lo gpio-56 (beaglebone::usr3 ) out lo gpio-60 (sysfs ) in hi GPIOs 64-95, gpio: GPIOs 96-127, gpio:
Cependant cette patte n'est pas encore utilisable comme patte "génératrice" d'interruption comme le montre ce fichier.
root@beaglebone:~# cat /proc/interrupts CPU0 4: 0 INTC omap2_elm 12: 1730 INTC edma 14: 0 INTC edma_error 16: 0 INTC tsc 17: 0 INTC cppi41_dma 18: 0 INTC musb-hdrc.0 19: 1 INTC musb-hdrc.1 30: 24 INTC omap_i2c 40: 0 INTC cpsw.0 43: 0 INTC cpsw.0 58: 0 INTC ehrpwmTZ 59: 0 INTC ehrpwmTZ 64: 5512 INTC mmc0 67: 8820 INTC gp timer 70: 113 INTC omap_i2c 72: 46 INTC OMAP UART0 75: 0 INTC rtc0 76: 0 INTC rtc0 86: 0 INTC ehrpwm_evt 87: 0 INTC ehrpwm_evt 93: 447 INTC cpsw.0 94: 331 INTC cpsw.0 100: 0 INTC gpmc 166: 0 GPIO mmc0 Err: 0
Il faut écrire dans le fichier /sys/class/gpio/gpio60/edge pour que l'interruption ait lieu, soit sur un front montant (rising), soit sur un front descendant (falling), soit sur les deux fronts (both).
root@beaglebone:~# cat /sys/class/gpio/gpio60/edge none root@beaglebone:~# echo both > /sys/class/gpio/gpio60/edge root@beaglebone:~# cat /sys/class/gpio/gpio60/edge bothLa patte P9_12 apparait alors avec le numéro d'interruption IRQ 220. Ici c'est la seule patte qui a été configuré comme interruption.
root@beaglebone:~# cat /proc/interrupts CPU0 4: 0 INTC omap2_elm 12: 1730 INTC edma 14: 0 INTC edma_error 16: 0 INTC tsc 17: 0 INTC cppi41_dma 18: 0 INTC musb-hdrc.0 19: 1 INTC musb-hdrc.1 30: 24 INTC omap_i2c 40: 0 INTC cpsw.0 43: 0 INTC cpsw.0 58: 0 INTC ehrpwmTZ 59: 0 INTC ehrpwmTZ 64: 5512 INTC mmc0 67: 9277 INTC gp timer 70: 113 INTC omap_i2c 72: 46 INTC OMAP UART0 75: 0 INTC rtc0 76: 0 INTC rtc0 86: 0 INTC ehrpwm_evt 87: 0 INTC ehrpwm_evt 93: 529 INTC cpsw.0 94: 380 INTC cpsw.0 100: 0 INTC gpmc 166: 0 GPIO mmc0 220: 0 GPIO gpiolib Err: 0
Maintenant, comme on peut le voir ci-dessous, après 2 pressions sur notre bouton poussoir, nous avons la valeur 4 qui apparaît en face du numéro d'IRQ 220. En effet, une pression correspond à la fois à un front montant et à un front descendant. Le déclenchement d'interruption se fait donc sur les deux fronts (cf. paramètre both écrit dans le fichier edge).
root@beaglebone:~# cat /proc/interrupts CPU0 4: 0 INTC omap2_elm 12: 1732 INTC edma 14: 0 INTC edma_error 16: 0 INTC tsc 17: 0 INTC cppi41_dma 18: 0 INTC musb-hdrc.0 19: 1 INTC musb-hdrc.1 30: 24 INTC omap_i2c 40: 0 INTC cpsw.0 43: 0 INTC cpsw.0 58: 0 INTC ehrpwmTZ 59: 0 INTC ehrpwmTZ 64: 5518 INTC mmc0 67: 9362 INTC gp timer 70: 113 INTC omap_i2c 72: 46 INTC OMAP UART0 75: 0 INTC rtc0 76: 0 INTC rtc0 86: 0 INTC ehrpwm_evt 87: 0 INTC ehrpwm_evt 93: 539 INTC cpsw.0 94: 388 INTC cpsw.0 100: 0 INTC gpmc 166: 0 GPIO mmc0 220: 4 GPIO gpiolib Err: 0
Un gros problème va cependant apparaître assez rapidement. Il n'est pas possible d'accéder à travers le système de fichier GPIO à la gestion des interruptions. D'ailleurs comme on peut le voir ci-dessous, l'IRQ 220 est classée comme spurious ce qui signifie qu'elle est détectée comme parasite et il n'est pas possible d'agir à travers les fichiers directement pour la classer comme gérée. Je suis en train en date du 21 juin d'étudier quelques scripts en C et en Python qui permettraient de les utiliser de façon correcte.
A suivre prochainement donc... N'hésitez pas à m'écrire si vous avez des infos ou idées.
root@beaglebone:~# cd /proc/irq root@beaglebone:/proc/irq# ls 0 101 105 109 112 116 12 123 127 16 19 22 25 29 32 36 ... 83 87 90 94 98 1 102 106 11 113 117 120 124 13 166 2 220 26 3 33 37 ... 84 88 91 95 99 10 103 107 110 114 118 121 125 14 17 20 23 27 30 34 38 ... 85 89 92 96 100 104 108 111 115 119 122 126 15 18 21 24 28 31 35 39 ... 86 9 93 97 root@beaglebone:/proc/irq# cd 220 root@beaglebone:/proc/irq/220# ls gpiolib spurious root@beaglebone:/proc/irq/220# cat spurious count 2 unhandled 0 last_unhandled 0 ms root@beaglebone:/proc/irq/220# cat spurious count 4 unhandled 0 last_unhandled 0 ms root@beaglebone:/proc/irq/220# cat spurious count 6 unhandled 0 last_unhandled 0 ms
Résultat de mes expérimentations avec l'interfaçage d'une eeprom 24LC32 en utilisant le protocole I2C (Mise à Jour en Cours).
J'ai voulu connecter une mémoire EEPROM 24LC32 à la platine Beaglebone en utilisant tout d'abord les pattes 17 et 18 du port 9 (I2C1_SCL et I2C1_SDA) de la platine. Les pattes 1 à 4 (A0 A1 A2 Vss) de l'Eeprom sont reliées à la masse sur la Beaglebone ce qui signifie que l'adresse de l'Eeprom sur le bus I2C sera 0x50. La patte 8 (Vcc) de l'Eeprom est reliée au 3.3v (VDD_3V3) de la platine, la patte 7 (WP) de l'Eeprom est elle reliée à la masse (les opérations de lecture/écriture de/vers l'Eeprom sont alors possibles). Ils ne nous restent donc que les deux pattes 6 et 5 (SCL et SDA) de l'Eeprom qui seront bien sûr à relier au patte 17 et 18 (I2C1_SCL et I2C1_SDA) de la platine Beaglebone. J'ai décidé ne pas utiliser de résistances de tirage Pull Up externes sur les lignes SCL/SDA et d'activer celles en interne de notre Beaglebone en utilisant le bon Mux Mode.
Regardons le mux mode actuel des pattes P9_17 et P9_18. On s'apercoit que 0x0062 (0b01100010) correspond au mode 2 avec les résistances de tirage Pull Up désactivées. Il faudra écrire 0b01110010 (0x72) pour avoir les résistances de tirage Pull Up activées. Pour information les pattes 19 et 20 (I2C2_SCL et I2C2_SDA) ont déjà les résistances de tirage Pull Up activées par défaut.
En fait les pattes 17 et 18 sont "réservées" pour l'utilisation de modules supplémentaires Beaglebone Cape, il est donc préférable d'utiliser les deux autres pattes, 19 et 20, qui sont elles correctement paramétrées.
root@beaglebone:/sys/kernel/debug/omap_mux# cat spi0_cs0 name: spi0_cs0.i2c1_scl (0x44e1095c/0x95c = 0x0062), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE2 signals: spi0_cs0 | mmc2_sdwp | i2c1_scl | NA | NA | NA | NA | gpio0_5 root@beaglebone:/sys/kernel/debug/omap_mux# cat spi0_d1 name: spi0_d1.i2c1_sda (0x44e10958/0x958 = 0x0062), b NA, t NA mode: OMAP_PIN_OUTPUT | OMAP_MUX_MODE2 signals: spi0_d1 | mmc1_sdwp | i2c1_sda | NA | NA | NA | NA | gpio0_4 root@beaglebone:/sys/kernel/debug/omap_mux# echo 72 > spi0_cs0 root@beaglebone:/sys/kernel/debug/omap_mux# echo 72 > spi0_d1
Comme on peut le voir nous avons deux bus I2C possible à analyser, le bus 1 et le bus 3.
root@beaglebone:~# dmesg | grep i2c [ 0.067266] omap_i2c.1: alias fck already exists [ 0.089101] omap_i2c omap_i2c.1: bus 1 rev2.4.0 at 100 kHz [ 0.211828] omap_i2c.3: alias fck already exists [ 0.230589] omap_i2c omap_i2c.3: bus 3 rev2.4.0 at 100 kHz [ 0.604328] i2c /dev entries driver root@beaglebone:~# i2cdetect -r -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- UU -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: UU UU -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- root@beaglebone:~# i2cdetect -r -y 3 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: 50 -- -- -- UU UU UU UU -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- --
Notre Eeprom est bien détectée à l'adresse prévue 0x50. Nous sommes donc prêt à lire et écrire dans notre Eeprom en utilisant les commandes i2cget et i2cset du package i2ctools. Ici nous voulons écrire l'octet 0xd8 à l'adresse 0 de notre Eeprom située à l'adresse 0x50 sur le bus 3 et ensuite lire cet emplacement pour vérifier que l'écriture à bien eu lieu.
root@beaglebone:~# i2cset -y 3 0x50 0x00 0xd8 b root@beaglebone:~# i2cget -y 3 0x50 0x00 b 0xff
Malheureusement l'écriture n'a pas été faite... Peu importe les tests, on lit toujours 0xff. Quelques recherches sur le Web m'ont appris que ces deux commandes ne pouvaient être utiliser avec des Eeproms, ces commandes sont uniquement réservées aux divers capteurs qui utilisent un autre système d'accès à leur mémoire. Heureusement il existe dans ce package des outils pour écrire et lire les Eeproms comme la commande eeprog. Vous trouverez sur cette page et sur celle là des informations concernant la commande.
On écrit respectivement la valeur 0xd5 à l'adresse 0 de l'Eeprom puis la valeur 0xe8 à l'adresse 0xba de cette même Eeprom. La vérification de la lecture nous confirment que cette fois-ci les valeurs ont bien été acceptées aux emplacements spécifiés (Dans le premier cas on lit 16 octets à partir du début et dans le second cas on lit 256 octets encore à partir du début).
root@beaglebone:~/testsh# printf "\xd5" | eeprog /dev/i2c-3 0x50 -16 -f -w 0x00 eeprog 0.7.5, a 24Cxx EEPROM reader/writer Copyright (c) 2003 by Stefano Barbato - All rights reserved. Bus: /dev/i2c-3, Address: 0x50, Mode: 16bit Writing stdin starting at address 0x0 . root@beaglebone:~/testsh# eeprog /dev/i2c-3 0x50 -16 -f -x -r 0:16 eeprog 0.7.5, a 24Cxx EEPROM reader/writer Copyright (c) 2003 by Stefano Barbato - All rights reserved. Bus: /dev/i2c-3, Address: 0x50, Mode: 16bit Reading 256 bytes from 0x0 0000| d5 b2 c3 d4 00 00 00 ff ff ff ff ff ff ff ff 5c
root@beaglebone:~/testsh# printf "\xe8" | eeprog /dev/i2c-3 0x50 -16 -f -w 0xba eeprog 0.7.5, a 24Cxx EEPROM reader/writer Copyright (c) 2003 by Stefano Barbato - All rights reserved. Bus: /dev/i2c-3, Address: 0x50, Mode: 16bit Writing stdin starting at address 0xba . root@beaglebone:~/testsh# eeprog /dev/i2c-3 0x50 -16 -f -x -r 0:256 eeprog 0.7.5, a 24Cxx EEPROM reader/writer Copyright (c) 2003 by Stefano Barbato - All rights reserved. Bus: /dev/i2c-3, Address: 0x50, Mode: 16bit Reading 256 bytes from 0x0 0000| d5 b2 c3 d4 00 00 00 ff ff ff ff ff ff ff ff 5c 0010| 6d ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0020| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0030| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0040| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0050| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0060| ff 61 62 63 63 30 30 64 64 ff ff ff ff ff ff ff 0070| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0080| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 0090| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00a0| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00b0| ff ff ff ff ff ff ff ff ff ff e8 ff ff ff ff ff 00c0| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00d0| ff ff ff ff ff ff ff ff 00 ff ff ff ff ff ff ff 00e0| ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 00f0| 6d ff ff ff ff ff ff ff ff ff ff ff ff ff ff 7e
Bien sûr il est possible de formater l'affichage de la lecture à votre convenance en utilisant awk et sed ou de rediriger la sortie vers un fichier texte ou autre.
root@beaglebone:~/testsh# eeprog /dev/i2c-3 0x50 -16 -f -x -r 0:16 | awk -F "|" '{print $2}' | \ > sed '/^$/d' | awk '{ gsub(/ /,"",$0); print}' > datt.txt eeprog 0.7.5, a 24Cxx EEPROM reader/writer Copyright (c) 2003 by Stefano Barbato - All rights reserved. Bus: /dev/i2c-3, Address: 0x50, Mode: 16bit Reading 16 bytes from 0x0 root@beaglebone:~/testsh# vi datt.txt
Voici normalement le résultat avec l'affichage de notre fichier texte sans formatage, ni espace.
77b2c3d4000000ffffffffffffffff5c ~ ~ (...) ~ ~ "datt.txt" 1L, 33C
Très prochainement je vais tester un capteur de pression atmosphérique I2C dès son achat courant juillet. Vous pouvez aussi aller jeter un oeil sur la partie du site qui traite de l'interfaçage I2C avec une manette filaire Nunchuk pour Wii.