Wie funktioniert die speicherabgebildete E / A-Adressierung?

29

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_BASEbestimmt und was ist los?

Hundeohren
quelle
1
Dies ist wahrscheinlich am besten für StackOverflow geeignet. Obwohl es sich um das RPi handelt, werden Sie dort mit größerer Wahrscheinlichkeit Antworten auf Programmierfragen erhalten.
Jivings
4
Vielleicht, aber ich denke, es ist eher eine allgemeine Frage zur Pi-Programmierung, die die Interpretation des Datenblattes und der Pi-Hardware kombiniert. Mal sehen, ob es ein paar gute Infos gibt.
Hundeohren
Okay. Mal sehen, wie es geht :)
Jivings
1
Ich denke nicht, dass dies bei Stack Overflow zu gut funktionieren würde - es ist ziemlich spezialisiert und würde hier wahrscheinlich mehr fachmännische Aufmerksamkeit erhalten.
Flexo

Antworten:

18

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

David Sykes
quelle
Ich habe noch ein paar Fragen: Warum mmap sie? Warum nicht einfach direkt auf den Speicher zugreifen?
Alex Chamberlain
@AlexChamberlain Da der Code unter Linux ausgeführt wird, können Sie nicht direkt auf den Speicher zugreifen, da jeder Prozess seinen eigenen virtuellen Speicherplatz erhält. Man kann jedoch mmap / dev / mem öffnen, um direkten Zugriff auf den physischen Speicher zu erhalten
Nr.
1

@AlexChamberlain Das liegt an der OS-Struktur. Sie können darauf verzichten, mmapaber das Paging ist deklariert, daher kein direkter Zugriff. Im Kernel-Modus können Sie mmapbeispielsweise auf das Einfügen Ihres Treibers als Kernel-Modul verzichten mmap. Im einfachsten Fall des Betriebssystems, in dem kein Seitentabellenspeicher verwendet wird, können Sie auch ohne zugreifen mmap, indem Sie z. direkter physischer Adresszugriff.

Manoj Singh
quelle