vendredi 13 avril 2018

Chapitre 25 : utilisation du timer du BCM2835


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