BeagleBone Black et PWM

Publié par cpb
Juil 06 2013

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.

Rapport cyclique

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.

PWM BeagleBone Black

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.

PWM BeagleBone Black 2

Signal à 100 kHz

# echo  5000 > duty 
# echo 10000 > period
#

Le signal de 10 microsecondes de période est toujours aussi net.

PWM BeagleBone Black 3

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.

PWM BeagleBone Black 4

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é.

PWM BeagleBone Black 5

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.

PWM BeagleBone Black 6

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.

PWM BeagleBone Black 7

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.

9 Réponses

  1. Bruno dit :

    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

  2. Mouha dit :

    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 ?

  3. Mouha dit :

    “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…

  4. Tlams dit :

    Cet article très clair m’a permit de débuter sur le PWM de cette carte.

    Merci !

  5. Damien dit :

    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

  6. Cedric dit :

    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

  7. florian dit :

    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 😉 )

URL de trackback pour cette page