Je me suis intéressé aux sorties PWM du BeagleBone Black. Quatre d’entre elles sont directement accessibles sur les connecteurs d’extension P8 et P9. L’accès en est encore relativement simple. En revanche pour les deux autres, il a fallu que j’explore le fonctionnement du Device Tree décrivant les entrées-sorties du BeagleBone Black, ce que j’aborderai dans un autre article.
Première sortie PWM
Une sortie PWM (Pulse Width Modulation) est une broche sur laquelle on programme un signal périodique avec un rapport cyclique configurable. Le rapport cyclique (généralement noté α) est le rapport entre la durée du niveau haut (TH sur le schéma ci-dessous) et la période T du signal.
Lorsque la durée du signal au niveau haut (+3,3V sur le BeagleBone Black) est égale à celle du niveau bas, le rapport cyclique vaut 1/2 et une mesure moyenne de la tension aux bornes de la sortie PWM donnera 3,3/2 = 1,65V.
Il y a quatre sorties PWM directement visibles sur les connecteurs P8 et P9 du BeagleBone Black :
- PWM 1A sur la broche 14 du port P9
- PWM 1B sur la broche 16 du port P9
- PWM 2A sur la broche 19 du port P8
- PWM 2B sur la broche 13 du port P8
Je choisis par exemple d’utiliser le PWM 1A. Nous pouvons prendre la masse GND sur la broche 1 ou 2 du connecteur P9. Nous devons commencer par activer le support des PWM dans le Cape Manager du BeagleBone.
# cd /sys/devices/bone_capemgr.* # pwd /sys/devices/bone_capemgr.8 # echo am33xx_pwm > slots # cat 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,am33xx_pwm #
Le suffixe numérique dans le nom de répertoire bone_capemgr
(ici : 8
) peut varier suivant les BeagleBones aussi j’utilise l’astérisque du shell pour le contourner. Nous voyons bien apparaître un composant am33xx_pwm
dans les slots.
Activons la sortie PWM 1A qui se trouve sur la broche P9-14.
# echo bone_pwm_P9_14 > slots # cat 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,am33xx_pwm 7: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_14 #
À nouveau une entrée est apparue pour représenter le PWM. À ce moment, une tension +3.3V est mesurable sur la broche P9-14.
# cd /sys/devices/ocp.2/pwm_test_P9_14.* # ls -l total 0 lrwxrwxrwx 1 root root 0 Jan 1 00:10 driver -> ../../../bus/platform/drivert -rw------- 1 root root 4096 Jan 1 00:12 duty -r--r--r-- 1 root root 4096 Jan 1 00:12 modalias -rw------- 1 root root 4096 Jan 1 00:12 period -rw------- 1 root root 4096 Jan 1 00:12 polarity drwxr-xr-x 2 root root 0 Jan 1 00:12 power -rw------- 1 root root 4096 Jan 1 00:12 run lrwxrwxrwx 1 root root 0 Jan 1 00:12 subsystem -> ../../../bus/platform -rw-r--r-- 1 root root 4096 Jan 1 00:10 uevent # cat period 500000 # cat duty 0 #
La période ainsi que la durée du niveau haut sont exprimées en nanosecondes. La période par défaut est donc de 500 microsecondes.
Modifions la durée de duty
.
# echo 500000 > duty #
Étonnamment, le signal qui se trouvait au niveau +3.3V alors que duty
valait zéro, redescend à 0V lorsqu’on fixe duty
à la même durée que la période. Nous voyons qu’il existe un champ polarity
, vérifions sa valeur et essayons de la modifier.
# cat polarity 1 # echo 0 > polarity #
Le signal remonte bien à +3.3V, ce qui semble plus logique.
# echo 0 > duty #
La sortie redescend à zéro.
Essayons à présent de modifier le niveau de duty
.
# echo 200000 > duty #
Nous voyons sur l’oscilloscope un net signal de période 500 microsecondes, dont le niveau haut dure 200 microsecondes.
Si on mesure la valeur de sortie avec un voltmètre simple, on voit une tension de +1,32V, ce qui correspond à 2/5 de +3,3V.
En modifiant dans duty
la durée accordée au niveau haut, on peut faire varier en sortie la tension moyenne, et faire ainsi fluctuer par exemple l’intensité lumineuse d’une led.
Précision de la période
Le signal affiché sur la sortie du PWM est généré entièrement par le matériel, sans intervention du noyau Linux, aussi est-il parfaitement stable quelque soit la charge du système. Je voudrais quand même vérifier la précision avec laquelle on peut réellement fixer la période. Pour cela, je vais tester des périodes de durées décroissantes, en observant le signal à l’oscilloscope. Comme la durée duty
ne doit jamais être supérieure à la période, je commence systématiquement par diminuer celle-ci.
Signal à 10kHz
# echo 50000 > duty # echo 100000 > period #
Nous observons un beau signal de 100 microsecondes de période.
Signal à 100 kHz
# echo 5000 > duty # echo 10000 > period #
Le signal de 10 microsecondes de période est toujours aussi net.
Signal à 1 MHz
# echo 500 > duty # echo 1000 > period #
Quelques effets capacitifs apparaissent sur les fronts des signaux, probablement dus aux sondes et aux prises grip-fils que j’ai utilisées. Le signal a une fréquence de 1 MHz et reste parfaitement stable.
Signal à 10 MHz
# echo 50 > duty # echo 100 > period #
A 10MHz, nous atteignons les limites de mon oscilloscope portable et le signal affiché est très déformé. Toutefois il conserve une bonne stabilité.
Précision de la période
En revenant à un signal de 1MHz, je vais faire une petite expérience : chercher le « pas » minimal avec lequel on peut fixer la durée du niveau duty
. Pour cela, je vais la faire varier entre 200 et 400 nanosecondes, en faisant une pause d’un dixième de seconde entre chaque valeur.
# echo 1000 > period # for i in $(seq 200 400) ; do echo $i > duty; usleep 100000; done
J’observe alors que le front descendant du signal, bien qu’assez bruité par les effets capacitifs, avance régulièrement, par de petits sauts toutes les secondes.
En zoomant plus serré, je peux alors vérifier et m’assurer que la période et la durée de duty
ont une précision en dizaines de nanosecondes. Ceci signifie que les valeurs 500 à 509 par exemple fixeront la même période mais que 510 la modifiera.
Deuxième sortie PWM
Nous avons remarqué qu’il y a deux paires de sorties PWM : 1A/1B et 2A/2B. Nous avons activé la sortie 1A. Pour activer la sortie 2A, on exécutera de manière similaire à la sortie précédente.
# cd /sys/devices/bone_capemgr.*
# echo bone_pwm_P8_19 > slots
# cd /sys/devices/ocp.2/pwm_test_P8_19.*
#
On pourra configurer period
, duty
et polarity
de façon totalement indépendante de la sortie 1A.
Essayons à présent de configurer la sortie 1B.
# cd /sys/devices/bone_capemgr.* # echo bone_pwm_P9_16 > slots [ 6067.120995] ehrpwm 48302200.ehrpwm: Period value conflicts with channel 0 [ 6067.128319] pwm_test pwm_test_P9_16.14: pwm_config() failed
Un message du noyau Linux nous indique une erreur de configuration. Un conflit apparaît entre les périodes des deux PWM. Vérifions quand même si P9-16 est chargé.
# cat 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,am33xx_pwm 8: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_14 9: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P8_19 10: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_16 #
Le slot numéro 10 lui est pourtant bien attribué. Essayons de l’utiliser.
# cd /sys/devices/ocp.2/pwm_test_P9_16* # ls -l total 0 -r--r--r-- 1 root root 4096 Jan 1 01:41 modalias drwxr-xr-x 2 root root 0 Jan 1 01:41 power lrwxrwxrwx 1 root root 0 Jan 1 01:41 subsystem -> ../../../bus/platform -rw-r--r-- 1 root root 4096 Jan 1 01:41 uevent #
Les fichiers nous permettant d’accéder à la configuration du PWM sont absents. Nous ne pouvons pas l’utiliser comme cela, il faut désactiver son slot.
# cd /sys/devices/bone_capemgr.* # echo -10 > slots # cat 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,am33xx_pwm 8: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_14 9: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P8_19 #
Je vais donc remettre la période et la durée de duty
initiales sur la sortie PWM 1A.
# echo 500000 > period # echo 0 > duty #
Puis j’active la sortie PWM 1B.
# cd /sys/devices/bone_capemgr.* # echo bone_pwm_P9_16 > slots # cat 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,am33xx_pwm 8: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_14 9: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P8_19 11: ff:P-O-L Override Board Name,00A0,Override Manuf,bone_pwm_P9_16 #
Et je modifie la période et le duty
.
# cd /sys/devices/ocp.2/pwm_test_P9_16.* # echo 100000 > period [ 901.071218] ehrpwm 48302200.ehrpwm: Period value conflicts with channel 0 [ 901.078557] pwm_test pwm_test_P9_16.15: pwm_config() failed -sh: echo: write error: Invalid argument # cat period 500000 #
Ah ! Le même problème se pose, puisque j’essaye de modifier la période de la sortie 1B et qu’elle ne serait donc plus en accord avec celle de la sortie 1A.
En fait les deux sorties 1A et 1B sont couplées (et synchronisées). Elles doivent avoir la même période, et la période de duty
commencera au même instant sur les deux sorties. En revanche elles peuvent avoir des durées de duty
et des polarités différentes. Voici une capture par exemple où la sortie 1A (en haut) a une polarité à 0
et une durée duty
de 100 microsecondes, alors que la sortie 1B a une polarité à 1
et une durée duty
de 300 microsecondes.
Conclusion
Les sorties PWM du BeagleBone Black sont performantes et précises. Si l’on n’utilise qu’une ou deux sorties, la programmation est très simple. Il n’en demeure pas moins que nous n’avons pas trouvé comment modifier la période d’un PWM dont les deux sorties sont utilisées simultanément. Pour cela il faut certainement intervenir dans le Device Tree qui a fait son apparition dans le noyau Linux 3.5 sur le BeagleBone. Je continue à explorer ce mécanisme, que je décrirai dans un prochain article.
Article très intérressant qui m’a permis de prendre pieds dans les pwm et la beaglebone black
En programmant la pwm1A et la pwm2A, donc indépendantes, avec une période d’une seconde et une duty de 0.5 seconde et que j’y branche des leds, elles finissent pas de désynchroniser.
Je reconnais que c’est tout à fait empirique.
Y a-t-il une explication à cela hormis un manque de précision ?
J’attends les autres articles avec impatience 😉
bonne continuation
Bruno
Véritablement dans les entrailles de la BB-black, très instructif.
Peut-on supposer un prochain article du même accabit pour avoir Xenomai sur cette carte ?
J’aimerais bien avoir le temps de creuser cela, oui… Mais la rentrée est bien chargée.
« Patience et longueur de temps. »
ma foi, je pense que cela va apparaitre sous peu; Et puis après tout avec le livre « Solutions temps réel sous Linux » je pourrais probablement le faire moi-même…
Cet article très clair m’a permit de débuter sur le PWM de cette carte.
Merci !
Bonjour,
Je vous remercie de votre article, c’est assez rare de trouver des gens qui partagent des informations claires sur la beaglebone.
Je voudrais savoir à quoi sert /sys/class/pwm/export, comme pour les gpio en envoyant une valeur à export il créé un dossier pwm*. Mais lorsque l’on utilise les fichiers de ce repertoire rien ne se passe. y a t’il comme pour les gpio quelque chose à faire dans le muxer ?
cordialement
Bonjour,
je viens de me procurer une beaglebone et j’aimerai utiliser les sorties pwm.
Quand je tape:
# echo am33xx_pwm > slots
voici le retour
bash:slots:permission denied
je ne comprends pas quelqu’un peu m’aider
Dans quel répertoire vous placez vous pour exécuter cette commande ?
Merci beaucoup pour votre article.
Je souhaite utiliser la pwm couplee a une entree ADC pour realiser le controle automatique de luminosite de mon ecran LCD 18bts.
Il n’y a plus qu’a :).
Bonjour du Nord ( je suis un ancien collegue de DFV 😉 )