En écrivant les programmes précédents sur le GPIO,
j’avais trouvé que l’on pouvait aussi accéder aux périphériques en effectuant
un mapping de la mémoire à partir du fichier /dev/mem. Mais restriction
importante, le programme ne peut être lancé que par sudo alors que
l’utilisation de /dev/gpiomem permet le lancement par un utilisateur
quelconque.
Pour voir quand même les possibilités, j’ai écrit ceprogramme qui exploite le timer disponible sur le BCM2835. La mise au point de
ce programme m’a donné beaucoup de mal et j’ai passé de nombreuses heures sur
internet à chercher les causes des différents problèmes que j’ai rencontrés.
Enfin aujourd’hui ce programme fonctionne correctement et à part un petit truc
bizarre, j’ai progressé dans la compréhension des périphériques.
Comme pour l’utilisation du GPIO, le programme commence par
ouvrir le fichier /dev/mem et effectue le mapping dans la mémoire par l’instruction
mmap. Vous remarquerez que les flags n’autorisent que la lecture des données
mappées, limite imposée par la sécurisation de la mémoire par Linux. Et là j’ai
eu beaucoup de mal à exécuter correctement cette fonction. En fait, j’ai
utilisé le code call system 192 pour cette fonction mmap qui correspond dans la
documentation linux à mmap2. Et pour cette fonction, l’adresse à passer dans le registre r5 doit être indiquée en nombre de pages de 4096 caractères et ne doit
pas être l’adresse directe contrairement à tous les exemples que l’on trouve
sur Internet.
Donc ici la documentation du BCM2835 indique à la page 172 que
l’adresse du timer est 0x7E003000. Ce qui correspond pour le type de raspberry
que j’utilise à l’adresse virtuelle 0x20003000 soit à un nombre de pages de
0x2003 valeur que j’ai donnée à la constante ST_BASE. Pour d’autres modèles du
Raspberry, il faudra adapter cette valeur.
La deuxième erreur que j’avais faite pour l’appel de mmap, c’est
que je testais une valeur négative en cas d’erreur mais la fonction retourne
une adresse résultante du mapping qui peut être négative en notation signée et
donc à l’exécution, le mapping était correct mais mon programme se terminait avec
une erreur. J’ai donc modifié le test du retour pour ne détecter que les
erreurs comprises entre -125 et 0.
Ensuite le programme récupère la valeur du timer à l’offset
+4 pour effectuer un calcul du nombre de micro secondes données par le timer
pour chaque seconde (appel de la fonction sleep avec r0 egal à 1 et r1 à zéro).
Dans un premier temps, mon programme affichait la zone mémoire située à cette
adresse et je ne comprenais pas les données affichées car cela ne correspondait
pas à la documentation. Et d’ailleurs c’est toujours le cas, le programme fonctionne
correctement il affiche des valeurs proches de 1000145 par seconde bien que l’affichage
de la zone mémoire ne soit pas correcte. Je suspecte que la sécurisation de l’accès
à la mémoire par le Kernel Linux n’autorise pas (ou autorise mal) certains
instructions à la mémoire (en particulier les accès octet par octet).
En fin de boucle, le programme se termine par la fermeture
de la zone mappée et du fichier du périphérique.
L’utilisation de ce timer peut servir pour commander des
composants comme les LEDS du GPIO et c’est une solution intéressante pour les
programmes bare metal qui n’auront pas de fonction sleep du système d’exploitation
pour contrôler les durées. Et dans ce cas, pas besoin de mapping puisque le
programme pourra accéder directement à l’adresse du timer.
Je laisse le soin aux spécialistes des périphériques, d’étudier
les autres possibilités d’utiliser les données issues de /dev/mem.
Aucun commentaire:
Enregistrer un commentaire