DMA

Wechseln zu: Navigation, Suche

von Benutzer:Andreas

DMA steht für "Direct Memory Access" (direkter Speicherzugriff). Der Begriff taucht fast nur im Zusammenhang mit PCs und größeren Mikrocontrollern auf, deswegen sind viele der Meinung, DMA wäre etwas furchtbar Komplexes das man bei Mikrocontrolleranwendungen nur in seltenen Fällen braucht. In Wirklichkeit handelt es sich dabei aber um ein sehr einfaches Konzept das sich in ein paar Sätzen erklären lässt.

Das Grundprinzip von DMA ist, dass Transfers zwischen Speicher und Peripherie (UART, SPI, AD-Wandler) automatisiert im Hintergrund ablaufen, ohne die CPU nennenswert zu belasten.

Angenommen man möchte einen großen Datenblock über das SPI eines Controllers übertragen, zum Beispiel an eine SD-Karte. Bei der klassischen Implementierung einer SPI-Übertragung muss die CPU für jedes Byte das gesendet werden soll warten bis der SPI-Controller bereit ist Daten entgegenzunehmen und dann das Byte in den Sendepuffer schreiben.

Mit DMA funktioniert der Transfer folgendermaßen: Man schreibt die Anzahl der zu übertragenden Datenworte und die Speicheradresse an der der zu übertragende Datenblock steht in ein Register und startet den DMA-Transfer durch Setzen eines Steuerbits. Der DMA-Controller überträgt nun das erste Datenwort, zählt die Adresse um einen Schritt nach oben, die Anzahl nach unten und wartet, bis das SPI-Interface wieder bereit ist. Das wiederholt sich so lange, bis das Zählregister bei 0 angekommen ist. Das ganze läuft praktisch unbemerkt im Hintergrund ab, das Programm der CPU wird währenddessen ganz normal weiter ausgeführt.

Beim AT91SAM7 sieht das unter Verwendung des sogenannten "Peripheral DMA Controller" (PDC) z. B. so aus:

unsigned char data[512];

// das Array wird mit irgend welchen Daten gefüllt
// ...

*AT91C_SPI_TPR = data;                      // Adresse des Arrays
*AT91C_SPI_TCR = sizeof(data);              // Anzahl der zu übertragenden Datenworte (hier Bytes)
*AT91C_SPI_PTCR = AT91C_PDC_TXTEN;          // Transfer starten

while(! (*AT91C_SPI_SR & AT91C_SPI_ENDTX)); // auf das Ende der Übertragung warten

*AT91C_SPI_PTCR = AT91C_PDC_TXTDIS;         // DMA deaktivieren

Für die optimale Nutzung von DMA wartet man natürlich nicht einfach so auf das Ende der DMA-Übertragung sondern nutzt die passenden Interrupts am Ende der DMA-Übertragung.