Wie funktioniert die speicherabgebildete E / A-Adressierung?
Ich versuche, ein mitgeliefertes Beispiel für I2S zu verstehen : Hat es jemand zum Laufen gebracht? .
Uhren konfigurieren:
#define BCM2708_PERI_BASE 0x20000000
#define CLOCK_BASE (BCM2708_PERI_BASE + 0x101000) /* Clocks */
Zuerst wird der Code wie folgt abgebildet ...
clk_map = (unsigned char *)mmap(
(caddr_t)clk_mem,
MAP_BLOCK_SIZE,
PROT_READ|PROT_WRITE,
MAP_SHARED|MAP_FIXED,
mem_fd,
CLOCK_BASE
);
Dann macht es etwas ...
// Always use volatile pointer!
clk = (volatile unsigned *)clk_map;
Und wenn darauf verwiesen wird, gibt es diese seltsamen Zusätze von 0x26 & 0x27, worum geht es dann?
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;
Auf dem Datenblatt kann ich sehen, wo sie einige dieser Werte haben, wie die Basisadresse, aber ich habe Mühe, die anderen zu verstehen. Wo ist das CLOCK_BASE
bestimmt und was ist los?
Antworten:
Auf einem Computer schreiben Sie an eine angegebene 'Speicheradresse'. Diese Adresse wird vom System als Hardware-Adresse erkannt und die entsprechende Hardware empfängt oder sendet den entsprechenden Wert.
Die meisten Hardwaresysteme haben viele verschiedene Register, die gesetzt oder gelesen werden können. Manche haben vielleicht ein paar, manche viele. Diese Register werden in einem kontinuierlichen Bereich zusammengefasst. Ein Basiszeiger zeigt auf den ersten im Bereich, und Sie schreiben beispielsweise mit base_pointer + 1 auf den zweiten Port. Sie müssen nicht, Sie könnten direkt auf einen Zeiger schreiben, aber die Verwendung eines Offsets erleichtert die Arbeit.
Der Raspberry Pi erkennt eine Vielzahl von Hardwareregistern unter der Adresse 0x20000000. Auf eine Reihe von Registern, die Uhrensysteme steuern, wird von BCM2708_PERI_BASE + 0x101000 aus zugegriffen. Die Register, die die I2S-Uhr steuern, sind die 38. und 39. Register in diesem Block, die mit BCM2708_PERI_BASE + 0x101000 + 0x26 und 0x27 geschrieben wurden
Sie können jedoch nicht nur die Uhrwerte ändern, sondern müssen die Uhr deaktivieren, die Werte ändern und neu starten.
Wenn diese Antwort zu einfach ist, entschuldige ich mich. In diesem Fall ist Ihre Frage wirklich hart, viel Glück. Möglicherweise finden Sie diesen Link hilfreich
Update: Warum mmap verwenden und nicht direkt in den Speicher schreiben?
Wenn ein Programm die Speicheradressen ausführt, von denen es annimmt, dass sie keine realen Adressen sind, werden sie vom Speichermanager auf reale Adressen abgebildet. Dies verhindert, dass ein Programm ein anderes beeinflussen kann. Zwei Prozesse können problemlos an ihre eigene Adresse 1234 lesen und schreiben, und der Speichermanager hält die beiden Speicherorte vollständig getrennt.
Hardware-Ports befinden sich jedoch an absoluten physischen Adressen. Sie können jedoch nicht direkt darauf schreiben, da der Speichermanager Ihre Adresse verwendet und sie Ihrem persönlichen Speicherbereich zuordnet.
Unter Linux ist / dev / mem eine ' Zeichengerätedatei, die ein Abbild des Hauptspeichers des Computers ist '.
Wenn Sie dies wie eine Datei öffnen, können Sie es wie eine Datei lesen und beschreiben. Im mitgelieferten Beispiel ist mem_fd ein Datei-Handle, das sich aus dem Öffnen von / dev / mem ergibt
Ein weiteres System, das das Leben erheblich erleichtern kann, ist die Möglichkeit, eine Datei dem Speicher zuzuordnen und wie Speicher darauf zu schreiben. Wenn Sie also eine Datei haben, in der Sie verschiedene bestimmte Bits lesen oder schreiben möchten, können Sie den Dateizeiger nicht vor- und zurückbewegen, sondern ihn einem Speicherort zuordnen und direkt darauf schreiben, als wäre er Speicher.
In diesem Beispiel erstellt der Code also ein Handle für den physischen Speicher, als wäre er eine Datei auf der Festplatte, und fordert das System auf, ihn so zu behandeln, als wäre er Speicher. Ein bisschen kompliziert, aber notwendig, um den virtuellen Speichermanager zu umgehen und an eine tatsächliche physikalische Adresse zu schreiben. Der Wert 0x20000000 scheint ein bisschen wie ein roter Hering zu sein. Der Code schlägt diese Adresse als Hinweis vor, das System muss / dev / mem hier nicht zuordnen, obwohl dies wahrscheinlich der Fall ist. Normalerweise wird der Wert null übergeben und das System ordnet das Dateihandle der Adresse zu, die es für am besten hält.
Jetzt wird der physische Speicher dem virtuellen Arbeitsspeicher des Prozesses zugeordnet und die Lese- und Schreibvorgänge werden dort ausgeführt, wo Sie es erwarten.
Verweise:
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
quelle
@AlexChamberlain Das liegt an der OS-Struktur. Sie können darauf verzichten,
mmap
aber das Paging ist deklariert, daher kein direkter Zugriff. Im Kernel-Modus können Siemmap
beispielsweise auf das Einfügen Ihres Treibers als Kernel-Modul verzichtenmmap
. Im einfachsten Fall des Betriebssystems, in dem kein Seitentabellenspeicher verwendet wird, können Sie auch ohne zugreifenmmap
, indem Sie z. direkter physischer Adresszugriff.quelle