Entrées analogiques du Beagle Bone Black

Publié par cpb
Mai 25 2013

BeagleBone Black Entrées AnalogiquesLe nouveau BeagleBone Black est compatible avec son prédécesseur blanc en ce qui concerne les ports d’entrées-sorties, ce qui lui permet d’hériter de ses fameuses “capes” (les cartes d’extension que l’on peut empiler afin d’ajouter de nouvelles fonctionnalités). Pour commencer à explorer le BeagleBone Black, je me suis intéressé à ses entrées analogiques, comme @HuguesSert me l’avait suggéré sur Twitter.

Le BeagleBone Black propose 7 entrées analogiques dans l’intervalle de tension [0, +1.8V] initialement conçues pour supporter un écran tactile d’où le “TSC” (Touchscreen) que l’on trouvera dans le nom du driver, mais on peut parfaitement les utiliser pour d’autres applications. Ces canaux se trouvent sur le connecteur P9 (celui situé du côté de l’alimentation +5V). Les entrées A0 à A6 se situent respectivement sur les broches 39, 40, 37, 38, 33, 36 et 35 de P9, la masse analogique étant sur la broche 34 et sur la broche 32 on peut trouver une tension de référence à +1.8V.

Attention à ne surtout pas dépasser la tension de référence, sur une entrée analogique. Je ne me suis pas risqué à vérifier s’il y a des protections efficaces, mais le System Reference Manual du BeagleBone Black précise cette limite explicitement (p.27).

Entrées analogiques BeagleBoard Black

Broches d’alimentation en 1.8V

La méthode la plus simple pour fournir une valeur ne dépassant jamais 1,8V est encore de fournir en entrée un signal obtenu par division de cette tension de référence. Nous pouvons vérifier qu’elle est bien présente entre les broches 34 (GND_ADC) et 32 (V_ADC).

Tension Analogique du BeagleBone

Entrées analogiques

Sur le précédent BeagleBone (je n’en ai plus d’exemplaire sous la main, je n’ai pas vérifié ceci), il suffisait pour lire l’état d’une des entrées analogiques de consulter : /sys/devices/platform/tsc/ain<numero> ou /sys/devices/platform/omap/tsc/ain<numero> sur les noyaux récents. Ceci ne fonctionne plus sur le nouveau BeagleBone Black.

Avec ce dernier, nous sommes encouragés à utiliser un nouveau sous-système du kernel : IIO (Industrial I/O Subsystem) qui est dédié aux convertisseurs analogiques->numériques (ADC, en entrée) et dans une moindre mesure aux convertisseurs numériques->analogiques (DAC, en sortie).

Nous allons devoir activer la gestion des IIO en utilisant le module Cape Manager du kernel.

Démarrons un BeagleBone Black sur la distribution Angström incluse dans la carte eMMC, puis interrogeons le module Cape Manager pour voir quelles capes il a détectées.

root@beaglebone:~# ls /sys/devices/
44e10800.pinmux  ARMv7 Cortex-A8  bone_capemgr.8  breakpoint  fixedregulator.9	ocp.2  platform  soc.0	software  system  tracepoint  virtual
root@beaglebone:~#

 

root@beaglebone:~# cat /sys/devices/bone_capemgr.8/slots
 0: 54:PF--- 
 1: 55:PF--- 
 2: 56:PF--- 
 3: 57:PF--- 
 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
 5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
root@beaglebone:~#

Pour le moment, seules deux pseudo-capes sont présentes, pour implémenter le support du connecteur HDMI et de la mémoire flash eMMC. Les supports de capes (nommés Device Tree Fragments) se trouvent dans le répertoire firmware/cape du kernel après application des patches pour BeagleBone (je reviendrai sur ce sujet dans un prochain article). En voici la liste pour le noyau 3.8.13.

[kernel]$ ls firmware/capes/
am33xx_pwm-00A0.dts        bone_pwm_P9_16-00A0.dts
BB-BONE-AUDI-01-00A0.dts   bone_pwm_P9_21-00A0.dts
BB-BONE-CAM3-01-00A2.dts   bone_pwm_P9_22-00A0.dts
BB-BONE-eMMC1-01-00A0.dts  bone_pwm_P9_28-00A0.dts
BB-BONE-GPEVT-00A0.dts     bone_pwm_P9_29-00A0.dts
BB-BONE-LCD4-01-00A0.dts   bone_pwm_P9_31-00A0.dts
BB-BONE-LCD4-01-00A1.dts   bone_pwm_P9_42-00A0.dts
BB-BONE-LCD7-01-00A2.dts   cape-bone-2g-emmc1.dts
BB-BONE-LCD7-01-00A3.dts   cape-bone-adafruit-lcd-00A0.dts
BB-BONE-LCD7-01-00A4.dts   cape-bone-adafruit-rtc-00A0.dts
BB-BONELT-BT-00A0.dts      cape-boneblack-hdmi-00A0.dts
BB-BONE-PRU-01-00A0.dts    cape-bone-dvi-00A0.dts
BB-BONE-PRU-02-00A0.dts    cape-bone-dvi-00A1.dts
BB-BONE-PWMT-00A0.dts      cape-bone-dvi-00A2.dts
BB-BONE-RS232-00A0.dts     cape-bone-exptest-00A0.dts
BB-BONE-RST-00A0.dts       cape-bone-geiger-00A0.dts
BB-BONE-RST2-00A0.dts      cape-bone-hexy-00A0.dts
BB-BONE-SERL-01-00A1.dts   cape-bone-iio-00A0.dts
bone_pwm_P8_13-00A0.dts    cape-bone-lcd3-00A0.dts
bone_pwm_P8_19-00A0.dts    cape-bone-lcd3-00A2.dts
bone_pwm_P8_34-00A0.dts    cape-bone-mrf24j40-00A0.dts
bone_pwm_P8_36-00A0.dts    cape-bone-nixie-00A0.dts
bone_pwm_P8_45-00A0.dts    cape-bone-pinmux-test-00A0.dts
bone_pwm_P8_46-00A0.dts    cape-bone-tester-00A0.dts
bone_pwm_P9_14-00A0.dts    cape-bone-weather-00A0.dts
[kernel]$

Celle qui va nous intéresser pour le moment est cape-bone-iio. Demandons au Cape Manager d’en assurer le support.

root@beaglebone:~# echo cape-bone-iio > /sys/devices/bone_capemgr.8/slots
root@beaglebone:~#

Vérifions à nouveau les capes gérées.

root@beaglebone:~# cat /sys/devices/bone_capemgr.8/slots 
 0: 54:PF--- 
 1: 55:PF--- 
 2: 56:PF--- 
 3: 57:PF--- 
 4: ff:P-O-L Bone-LT-eMMC-2G,00A0,Texas Instrument,BB-BONE-EMMC-2G
 5: ff:P-O-L Bone-Black-HDMI,00A0,Texas Instrument,BB-BONELT-HDMI
 6: ff:P-O-L Override Board Name,00A0,Override Manuf,cape-bone-iio
root@beaglebone:~#

Un nouveau répertoire helper.11 (le driver s’appelle TSC AM335x IIO Helper) est alors apparu dans /sys/devices/ocp.2/. Voyons son contenu.

root@beaglebone:~# ls -l /sys/devices/ocp.2/helper.11/
total 0
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN0
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN1
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN2
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN3
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN4
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN5
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN6
-r--r--r-- 1 root root 4096 Jan  1 01:35 AIN7
lrwxrwxrwx 1 root root    0 Jan  1 01:35 driver -> ../../../bus/platform/drivers/bone-iio-helper
-r--r--r-- 1 root root 4096 Jan  1 01:35 modalias
drwxr-xr-x 2 root root    0 Jan  1 01:35 power
lrwxrwxrwx 1 root root    0 Jan  1 00:40 subsystem -> ../../../bus/platform
-rw-r--r-- 1 root root 4096 Jan  1 00:40 uevent
root@beaglebone:~#

Les fichiers AIN0 à AIN6 représentent les entrées analogiques que nous allons tester. L’entrée AIN7 est utilisée me semble-t-il pour la régulation de la tension d’alimentation.

Relions la broche 36 (entrée analogique 5) à la broche 34 (GND_ADC) et demandons le contenu du fichier AIN5.

root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5
340
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
0
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
0
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
0
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
0
root@beaglebone:~#

La première valeur (340) était un peu surprenante. Maintenant, relions la broche 36 à la broche 32 (VDD ADC).

root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
0
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1799
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1799
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1799
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1798
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1799
root@beaglebone:~#

Plusieurs remarques s’imposent :

  • La valeur fournie par le fichier AIN est donc la tension mesurée en millivolts. Le convertisseur ADC du processeur AM3559 offre une résolution de 12 bits, mais le driver Linux se contente donc de 11 bits (intervalle [0-2047]) à cause de la limitation à +1.8V.
  • Visiblement, à chaque lecture du fichier AIN, le driver nous renvoie la dernière valeur qu’il avait déjà mesurée puis relance une nouvelle acquisition. La première valeur lue de chaque série n’est donc pas valide. C’est important d’en tenir compte dans les applications qui échantillonnent un signal.

Je branche maintenant sur la broche AIN5 (36) le point-milieu d’un potentiomètre dont les deux extrémités sont reliées aux broches 32 (VDD_ADC) et 34 (GND_ADC). Je place le potentiomètre à peu près à mi-course.

BeagleBone et Potentiometre

root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
1799
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
791
root@beaglebone:~# cat /sys/devices/ocp.2/helper.11/AIN5 
791
root@beaglebone:~#

Nous avons confirmation que la première valeur est fausse (c’est l’acquisition faite juste après la dernière lecture de l’expérience précédente).
On peut voir varier dynamiquement la valeur d’entrée analogique alors que je tourne le potentiomètre alternativement d’une butée à l’autre.

root@beaglebone:~# while true; do cat /sys/devices/ocp.2/helper.11/AIN5 ; done
[...]
0
0
0
10
87
280
561
987
1460
1728
1796
1799
1798
[...]
1799
1798
1778
1728
1578
1331
967
621
359
221
116
61
13
0
0
[...]
(Contrôle-C)
root@beaglebone:~#

La boucle du shell n’étant pas très rapide, nous voyons peu de valeurs durant la phase intermédiaire entre les deux butées. La documentation du processeur AM3359 du BeagleBone Black précise qu’il peut réaliser 200.000 échantillonnages par seconde. Vérifions ceci avec un petit programme C qui va lire en boucle l’entrée AIN indiquée.

read-ain.c:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 128
#define HELPER_NAME "cape-bone-iio\n"

int main(int argc, char * argv[])
{
	int num;
	int fd;
	char buffer[BUFFER_SIZE];
	int i;
	int nb_samples;
	int * values;
	int n;

	if ((argc < 3)
	 || (sscanf(argv[1], "%d", & num) != 1)
	 || (sscanf(argv[2], "%d", & nb_samples) != 1)) {
		fprintf(stderr, "usage: %s analog-input-number nb-samples\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	if ((num < 0) || (num > 6)) {
		fprintf(stderr, "wrong analog input number: %d\n", num);
		exit(EXIT_FAILURE);
	}
	values = calloc(nb_samples, sizeof(int));
	if (values == NULL) {
		perror(argv[0]);
		exit(EXIT_FAILURE);
	}

	strcpy(buffer, "/sys/devices/bone_capemgr.8/slots");
	fd = open(buffer, O_WRONLY);
	if (fd < 0) {
		perror(buffer);
		exit(EXIT_FAILURE);
	}
	write(fd, HELPER_NAME, strlen(HELPER_NAME));
	close(fd);

	snprintf(buffer, BUFFER_SIZE, "/sys/devices/ocp.2/helper.11/AIN%d", num);
	fd = open(buffer, O_RDONLY);
	if (fd < 0) {
		perror(buffer);
		exit(EXIT_FAILURE);
	}
	for (i = 0; i < nb_samples; i ++) {
		lseek(fd, 0, SEEK_SET);
		n = read(fd, buffer, BUFFER_SIZE);
		if (n < 0) {
			perror("read");
			exit(EXIT_FAILURE);
		}
		buffer[n] = '\0';
		if (sscanf(buffer, "%d", & (values[i])) != 1) {
			fprintf(stderr, "unreadable value: %s\n", buffer);
			exit(EXIT_FAILURE);
		}
//		usleep(1000);
	}
	for (i = 0; i < nb_samples; i ++) {
		fprintf(stdout, "%d\n", values[i]);
	}

	close (fd);
	return EXIT_SUCCESS;
}

Ce programme lit en boucle l’entrée analogique indiquée en premier argument et stocke les valeurs dans un tableau dont la dimension est fournie en second argument. Puis il affiche le résultat. Compilons-le, et exécutons-le avec peu d’itérations pour commencer.

root@beaglebone:~# gcc read-ain.c -o read-ain -Wall
root@beaglebone:~# time  ./read-ain 5 32
root@beaglebone:~# ./read-ain 5  32
669
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
1555
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
-1270740598
root@beaglebone:~#

Nous nous apercevons alors que le driver nous renvoie des valeurs erronées si nous lisons l’entrée analogique trop vite. En effet, il ne vérifie pas (ce qui est probablement une erreur) si la lecture précédente est terminée avant d’en relancer une nouvelle. Un patch est apparemment en cours d’intégration pour le driver de l’ADC AM335x, mais en attendant, le plus simple est d’ajouter une petite attente après chaque lecture bien que ce ne soit qu’un palliatif inélégant. Empiriquement, j’ai vu qu’un sommeil de 900 à 1000 microsecondes semble suffire (c’est la ligne en commentaire dans l’exemple ci-dessus).

Conclusion

Les entrées analogiques accessibles par l’intermédiaire du port P9 sont initialement prévues pour la gestion d’un écran tactile. En l’état actuel, le driver ne permet pas d’obtenir directement depuis l’espace utilisateur des valeurs d’acquisition à une fréquence supérieure à 1kHz environ, ce qui est plutôt faible en traitement du signal.

Ces entrées sont donc bien adaptées pour participer à l’IHM d’un système embarqué (en lisant la valeur d’un potentiomètre par exemple), mais pas pour des véritables acquisitions de données analogiques. Nous pouvons espérer que l’évolution du driver pour le convertisseur A/N améliorera cette situation.

 

Sources :
Sitara AM335x Datasheet

6 Réponses

  1. Tee Eff dit :

    Merci Christophe

    Je viens de recevoir mon BBB et tes articles me semblent très intéressants.

    Je vais expérimenter tout ça ce week-end.

  2. yann dit :

    Assez tentante en effet cette carte… Le seul manque que je lui trouve en fait, c’est côté alim: Via USB c’est bien, mais l’ethernet POE lui aurait ouvert des horizons plus larges encore.

  3. Tee Eff dit :

    Christophe, j’ai fais les manipulation que tu décris, (enfin la première partie) et j’ai 2 remarques:

    A un moment tu indique :”Maintenant, relions la broche 36 à la broche 34 (VDD ADC).”
    Il s’agit bien sur de la broche 32 et non 34.

    Chez moi j’ai bone_capemgr.9 et non bone_capemgr.8, helper.14 au lieu de helper.11
    (uname -a indique:
    Linux beaglebone 3.8.13 #1 SMP Fri May 31 12:58:04 CEST 2013 armv7l GNU/Linux)

    Si les répertoires changent de nom comme ça, ça ne va pas être pratique pour porter les softs !

    • cpb dit :

      Oui, merci de m’avoir signalé l’erreur sur le numéro de broche, je corrige le texte de l’article en conséquence.

      En ce qui concerne le nombre qui suit le nom du répertoire bone_capemgr (8 ou 9) et celui du répertoire helper (11 ou 14), j’ai vu qu’il y a en effet des variantes, mais je n’ai pas l’explication.

      Au niveau des scripts shell on peut utiliser

      # cd /sys/devices/bone_capemgr.*
      # echo cape-bone-iio > slots

      Puis

      # cd /sys/devices/ocp.2/helper.*
      # cat AIN0

      Mais je conviens que ce n’est pas très élégant. Je vais essayer de trouver la signification de ces numéros.

  4. Pierre dit :

    Merci Christophe

    Il semble qu’on puisse lire la valeur 12bit dans le repertoire:
    /sys/bus/iio/devices/iio\:device0/
    Exemple:
    cat /sys/bus/iio/devices/iio\:device0/in_voltage5_raw

URL de trackback pour cette page