Comment fonctionne l'adressage des E / S mappées en mémoire?
J'essaie de comprendre un exemple fourni I2S: Quelqu'un l'a fait fonctionner? .
Configuration des horloges:
#define BCM2708_PERI_BASE 0x20000000
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
Il mappe d'abord le code comme ça ...
clk_map = (unsigned char *)mmap(
(caddr_t)clk_mem,
MAP_BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
CLOCK_BASE
);
Ensuite, il fait quelque chose ...
// Always use volatile pointer!
clk = (volatile unsigned *)clk_map;
Et quand il est référencé, il y a ces ajouts étranges de 0x26 et 0x27, de quoi s'agit-il?
printf("Disabling I2S clock\n");
*(clk+0x26) = 0x5A000000;
*(clk+0x27) = 0x5A000000;
usleep(10);
printf("Confiure I2S clock\n");
*(clk+0x26) = 0x5A000001;
*(clk+0x27) = 0x5A000000 | 3<<12 | 1<<9; // divider: 3.125==0b11.001
usleep(10);
printf("Enabling I2S clock\n");
*(clk+0x26) = 0x5A000011;
En regardant la fiche technique, je peux voir où ils ont certaines de ces valeurs, comme l'adresse de base, mais j'ai du mal à comprendre les autres. Où est-ce CLOCK_BASE
déterminé et que se passe-t-il?
Réponses:
Sur un ordinateur, vous écrivez à une «adresse mémoire» spécifiée. Cette adresse est reconnue par le système comme une adresse matérielle et le matériel approprié reçoit ou envoie la valeur appropriée.
La plupart des systèmes matériels ont de nombreux registres différents qui peuvent être définis ou lus. Certains pourraient en avoir quelques-uns, certains pourraient en avoir beaucoup. Ces registres seront regroupés dans une plage continue. Un pointeur de base pointe vers le premier de la plage et vous écrivez, par exemple, sur le deuxième port avec base_pointer + 1. Ce n'est pas nécessaire, vous pouvez écrire directement sur un pointeur, mais l'utilisation d'un décalage facilite la tâche.
Le Raspberry Pi reconnaît une vaste gamme de registres matériels à l'adresse 0x20000000. Une gamme de registres qui contrôlent les systèmes d'horloge est accessible à partir de BCM2708_PERI_BASE + 0x101000. Les registres qui contrôlent l'horloge I2S sont les 38e et 39e registres de ce bloc, écrits en utilisant BCM2708_PERI_BASE + 0x101000 + 0x26 et 0x27
Cependant, vous ne pouvez pas simplement modifier les valeurs d'horloge, vous devez désactiver l'horloge, modifier les valeurs et la redémarrer.
Si cette réponse est trop basique, mes excuses. Dans ce cas, votre question est vraiment hardcore, bonne chance. Vous pourriez trouver ce lien utile
Mise à jour: pourquoi utiliser mmap et ne pas écrire directement dans la mémoire?
Lorsqu'un programme exécute les adresses mémoire qu'il pense ne pas avoir de vraies adresses, elles sont mappées à des adresses réelles par le gestionnaire de mémoire. Cela empêche un programme de pouvoir en affecter un autre. Deux processus peuvent parfaitement lire et écrire sur leur propre adresse 1234, et le gestionnaire de mémoire gardera les deux emplacements complètement séparés.
Les ports matériels, cependant, sont à des adresses physiques absolues. Mais vous ne pouvez pas leur écrire directement parce que le gestionnaire de mémoire prendra votre adresse et la mappera à votre zone de mémoire personnelle.
Sous Linux / dev / mem est un « fichier de périphérique de caractères qui est une image de la mémoire principale de l'ordinateur »
Si vous l'ouvrez comme un fichier, vous pouvez y lire et y écrire comme un fichier. Dans l'exemple fourni mem_fd est un descripteur de fichier résultant de l'ouverture de / dev / mem
Un autre système qui peut vous faciliter la vie est la possibilité de mapper un fichier en mémoire et d'y écrire comme de la mémoire. Donc, si vous avez un fichier dans lequel vous souhaitez lire ou écrire différents bits spécifiques, au lieu de déplacer le pointeur de fichier en arrière et en avant, vous pouvez le mapper vers un emplacement en mémoire, puis y écrire directement comme s'il s'agissait de mémoire.
Ainsi, dans cet exemple, le code crée un handle vers la mémoire physique, comme s'il s'agissait d'un fichier sur le disque, puis demande au système de le traiter comme s'il s'agissait de mémoire. Un peu compliqué, mais nécessaire pour contourner le gestionnaire de mémoire virtuelle et écrire sur une adresse physique réelle. La valeur 0x20000000, semble-t-il, est un peu un hareng rouge. Le code propose cette adresse à titre indicatif, le système n'a pas à mapper / dev / mem ici, bien qu'il le fasse probablement. Normalement, la valeur null serait transmise et le système mapperait le descripteur de fichier à l'adresse qu'il jugeait la meilleure.
Maintenant, la mémoire physique est mappée à la mémoire virtuelle des processus, et les lectures et écritures vont là où vous vous attendez.
Les références:
http://www.kernel.org/doc/man-pages/online/pages/man2/mmap.2.html
http://www.raspberrypi.org/phpBB3/viewtopic.php?f=44&t=8496&p=104359
https://superuser.com/questions/71389/what-is-dev-mem
la source
@AlexChamberlain cela est dû à la structure du système d'exploitation. Vous pouvez vous en passer
mmap
mais la pagination est déclarée, donc pas d'accès direct. En mode noyau, vous pouvez vous passermmap
, par exemple, d'insérer votre pilote en tant que module noyau sans avoir besoin demmap
. En outre, dans le cas le plus simple du système d'exploitation, où aucune mémoire de table de pages n'est utilisée, vous pouvez accéder sansmmap
non plus, par ex. accès direct à l'adresse physique.la source