Festplatte

Aus der Mikrocontroller.net Artikelsammlung, mit Beiträgen verschiedener Autoren (siehe Versionsgeschichte)
Wechseln zu: Navigation, Suche

Festplatte

Im uC-Forum tauchen gelegentlich immer mal wieder Fragen auf, wie man eine Festplatte ansteuert. Da ich mich selber auch relativ lange damit befasst habe, habe ich viel Zeit investiert um alle Infos zusammen zu tragen. In diesem Artikel sollen die wichtigsten Grundlagen vermittelt werden. Also wie eine Festplatte aufgebaut ist, welche Register es gibt und wie man mittels Command Codes irgendwelche Aktionen ausführt.

Grundlegender Aufbau einer Festplatte

Sicher haben einige von euch schon mal eine Festplatte auseinander genommen. Die können diesen Abschnitt getrost überspringen ;) Für die anderen hier mal ein Bild:

Festplatte 1.jpg

Der Plattenstapel dreht sich üblicherweise mit einer Geschwindigkeit von 4200 oder 5400 U/min (Notebook-Festplatten), 7200 U/min (Desktop-Festplatten) oder mit über 10'000 U/min (Server-Festplatten). Die Platten selber bestehen aus Aluminium oder Glas, welches mit einer ferromagnetischen Schicht versehen ist. Die Schreib-/Leseköpfe können mittels eines sogenannten 'Servos' über den Platten positioniert werden. Sie sind im Prinzip kleine Spulen, die über einen Flexiblen Leiter mit einem Verstärker verbunden sind. Dieser Verstärker stellt die Verbindung mit der Elektronik her. Wenn nun die Platten rotieren, entsteht dadurch ein Luftzug im Festplattengehäuse. Der Luftzug hebt dann die Schreib-/Leseköpfe von der Plattenoberfläche ab, diese schweben dann einige nm über der Plattenoberfläche. Aus diesem Grund brauchen Festplatten einen minimalen Luftdruck (Oft ist im Datenblatt vermerkt, bis zu welcher Meereshöhe man das Gerät betreiben darf).

Wie werden jetzt die Daten gespeichert?

Nun müssen natürlich irgendwie die Bits & Bytes auf dieser magnetischen Plattenschicht abgelegt werden können. Um das zu tun, wird eine spezielle Einteilung vorgenommen. Als erstes werden die Platten in konzentrische Ringe unterteilt. Diese Ringe werden als 'Track' bezeichnet. Alle Tracks, die vom Plattenzentrum den selben Abstand haben, nennt man Zylinder. Die Tracks wiederum unterteilt man in Sektoren. Üblicherweise sind es 63 Sektoren pro Track. In jedem Sektor lassen sich 512 Bytes speichern. Möchte man nun Einen Sektor gezielt adressieren, benötigt man also dessen Zylinder, die Sektornummer, und die Nummer des Schreib-/Lesekopfs (da die Ober- und Unterseite der Platten für die Datenspeicherung verwendet werden). Diese Adressierung nennt man CHS (für Cylinder, Head, Sector). Sie wird von neueren Festplatten oft nicht mehr unterstützt. Für diese gibt es eine einfachere Adressierungsart, nämlich LBA (Linear Block Address). Hier wird eine einzige 28 Bit lange Zahl verwendet, die alle Sektoren nacheinander linear durchnummeriert. In beiden Adressierungsarten lassen sich aber max. 128 GByte adressieren (warum, dazu später mehr).

Der IDE-Stecker

IDE- (bzw. ATA-) Festplatten besitzen eine relativ einfache Schnittstelle zur Steuerung. Die Steckerbelegung sieht wie folgt aus:

Festplatte Connector.jpg

Beschreibung der Signale:

  1. DD0..15: Hier werden die Daten und Steuerkommandos übertragen.
  2. DA0..2: Über die 'Drive Address' lassen sich die einzelnen Register ansprechen.
  3. CS0, CS1: Chip Select. Wählt zusammen mit DAx ein Register aus (low-aktiv).
  4. RESET: Hard-Reset der Steuerelektronik (low-aktiv).
  5. DIOW: Write-Signal (low-aktiv).
  6. DIOR: Read-Signal (low-aktiv).
  7. INTRQ: Interrupt Request (high-aktiv!)
  8. DASP: Drive active (open-collector). Hiermit kann eine LED angesteuert werden. Vorwiderstand nicht vergessen! ;-)
  9. PDIAG: Dient zur Kommunikation der Festplatten untereinander.
  10. CSEL: Cable Select. Wird ebenfalls nur benötigt, wenn man 2 Festplatten hat.
  11. IORDY: Zeigt an, dass Daten übertragen werden können.

Die restlichen Signale braucht man nur, wenn man mit DMA arbeitet, worauf ich in diesem Artikel nicht näher eingehe. Zum steuern der Festplatte braucht man übrigens die Leitungen IORDY, CSEL un PDIAG nicht unbedingt. An DASP kann man eine LED incl. Vorwiderstand anschliessen. Die blinkt dann auf, wenn auf die Platte zugegriffen wird. Die Signalpegel für die Leitungen sind alle 5V TTL. Wenn man also einen mit 3.3V betriebenen Microcontroller mit 5V-Toleranten Eingängen hat, kann man die Festplatte problemlos ansteuern (habe ich selbst allerdings noch nicht getestet).

Der Registerblock

Die Festplatte besitzt 13 verschiedene Register. Auf diese kann man wie folgt zugreifen:

/CS0 /CS1 DA2 DA1 DA0 Register (Read) Register (Write)
1 0 1 1 0 Alternate Status Device Control
1 0 1 1 1 N/A N/A
0 1 0 0 0 Data Register Data Register
0 1 0 0 1 Error Register Features Register
0 1 0 1 0 Sector Count Sector Count
0 1 0 1 1 Sector Number / LBA Bits 0..7 Sector Number / LBA Bits 0..7
0 1 1 0 0 Cylinder Low / LBA Bits 8..15 Cylinder Low / LBA Bits 8..15
0 1 1 0 1 Cylinder High / LBA Bits 16..23 Cylinder High / LBA Bits 16..23
0 1 1 1 0 Device Register & LBA Bits 24..27 Device Register & LBA Bits 24..27
0 1 1 1 1 Status Register Command Register

Wenn man DMA verwendet, dann sind noch weitere Adressierungen möglich, auf diese gehe ich hier allerdings (noch) nicht ein. Wenn beide Chip Select-Eingänge auf 1 sind, dann ist der Datenbus in einem hochohmigen Zustand (tristate). Zu beachten ist noch, dass alle Register (ausser dem Datenregister) nur 8 Bit breit sein. Diese 8 Bit werden auf den Datenleitungen DD0..7 übertragen. Auch erkennt man aus der Tabelle, dass u.U. je nach Operation (lesen, schreiben) unterschiedliche Register ausgewählt werden (was auch richtig ist, denn es macht ja keinen Sinn, etwas ins Status-Register zu schreiben...).

Das Alternate Status / Status Register

Das Alternate Status Register hat grundsätzlich dieselbe Funktion wie das Status Register. Mit einem kleinen Unterschied: Wenn die Laufwerkselektronik einen Interrupt erzeugt (z. B. weil Daten gelesen werden sollen), dann wird der Interrupt gelöscht, wenn man das Status Register liest. Beim Lesen des Alternate Status Registers bleibt der Interrupt jedoch erhalten. In beiden Registern sind die folgenden Bits enthalten:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
BSY DRDY DF DSC DRQ COR IDX ERR
BSY
Busy-Flag. Wenn das Bit gesetzt ist, sind alle anderen Bits ungültig und das Laufwerk ist beschäftigt.
DRDY
Drive Ready. Es können Befehle zur Festplatte gesendet werden.
DF
Device Fault. Es ist beim Schreiben von Daten zu einem Fehler gekommen.
DSC
Drive Seek Complete. Zeigt an, dass das Laufwerk den angeforderten Track gefunden hat und die Schreib-/Leseköpfe dort positioniert hat.
DRQ
Zeigt an, dass Daten zum Laufwerk transportiert werden sollen (beim Schreiben), bzw. dass Daten vom Laufwerk abgeholt werden können (beim Lesen).
CORR
Corrected Data. Wenn Daten von der Elektronik korrigiert worden sind, wird dieses Bit gesetzt.
IDX
Index. Wird bei jeder Umdrehung des Plattenstapels auf 1 gesetzt.
ERR
Error. Das Error-Register muss ausgelesen werden, um nähere Informationen zu erhalten.

Das Command-Register

In das Command Register schreibt man einen speziellen Command-Code, der bestimmte Aktionen einletet. So bewirkt z. B. das schreiben des Codes 0x30 das schreiben eines Sektors auf die Platte. Der Befehl wird unmittelbar nach dem Schreiben ins Command Register ausgeführt und BSY auf 1 gesetzt.

Das Data Register

Das Data Register ist 16 Bit breit (als einziges der Register). Bei einem Lese- oder Schreibkommando können hier die gelesenen Daten abgeholt bzw. reingeschrieben werden.

Device Control Register

Das Device Control Register enthält folgende Bits:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 SRST nIEN 0

Setzt man SRST auf 1, so wird ein Software Reset durchgeführt. Mit nIEN kann man die Interrupts ein- oder ausschalten.

Device Register & LBA Bits 24..27

Im Device Register stehen folgende Bits:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
1 L 1 DRV H3 / LBA27 H2 / LBA26 H1 / LBA25 H0 / LBA24

L gibt an, dass das Laufwerk in den LBA-Modus geschaltet werden soll (L = 1) oder dass CHS-Adressierung verwendet werdem soll (L = 0). DRV dient zur Adressierung eines Laufwerks, also zur Unterscheidung Master / Slave und ist nur nötig, wenn man 2 Laufwerke an einem Kabel betreibt. DRV = 0 wählt das Master-Laufwerk aus, DRV = 1 adressiert das Slave-Laufwerk. Die Bits H0..H3 geben die Nummer des Kopfes an, wenn CHS-Adressierung verwendet wird. Wird LBA verwendet, dann kommen hier die Bits 24..27 hin.

Error Register

Das Error Register sieht so aus:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
CRC UNC 0 IDNF 0 ABRT TK0NF AMNF

CRC bedeutet, dass bei einem DMA-Transfer ein CRC-Fehler aufgetreten ist. UNC gibt an, dass bei einer Datenübertragung ein Fehler erkannt worden ist, dieser aber nicht korrigiert werden konnte. IDNF zeigt an, dass der angeforderte Sektor nicht gefunden worden ist. ABRT wird auf 1 gesetzt, wenn ein Befehl abgebrochen (aborted) wurde. TK0NF Zeigt an, dass Track 0 nicht gefunden worden ist. AMNF (Address Mark not found): Zeigt an, dass der gewünschte Sektor zwar gefunden wurde, seine Daten aber nicht.

Features Register

Das Features Register bekommt, je nach ausgeführtem Befehl, eine andere Bedeutung.

Cylinder High / LBA Bits 16..23

Hier kommt das High Byte der Zylindernummer rein, wenn man CHS-Adressierung verwendet. Setzt man LBA ein, dann müssen hier die entsprechenden LBA Bits geschrieben werden.

Cylinder Low / LBA Bits 8..15

Das Low-Byte der Zylindernummer bei CHS-Adressierung; Bits 8..15 bei LBA-Adressierung.

Sector Number / LBA Bits 0..7

Wenn man mit CHS arbeitet, muss hier die Sektornummer stehen. Achtung: Sektoren werden von 1 her beginnend Adressiert! Bei LBA werden hier die Bits 0..7 platziert.

Sector Count Register

Hier kann man angeben, wie viele Sektoren man beim nächsten Befehl übertragen möchte. Die Festplatte kann bis 256 Sektoren auf einmal lesen.

Die Steuerung der Platte

Um jetzt endlich die Festplatte ansteuern zu können, wird wie folgt vorgegangen: Als erstes muss man allfällige Command-Parameter in den entsprechenden Registern platzieren. Siehe Beispiel. Anschliessend wird der Command Code ins Command Register geschrieben. Dann kann man auf 2 Arten verfahren:

  1. Wenn man Interrupts verwendet, kann man jetzt getrost irgend was anderes machen. Die Festplatte generiert selbständig einen Interrupt, wenn sie zum Übertragen der Daten bereit ist.
  2. Wenn keine Interrupts zur Verfügung stehen, kann man so lange das Status Register pollen, bis BSY = 0 ist.

Wenn man den Command Code abgesetzt hat und die Platte nicht mehr BSY ist, kann man schon das Datenregister schreiben (bzw. lesen). Das Vorgehen für den Read Sector-Command ist z. B. wie folgt:

  1. Sector Count schreiben
  2. Sector Number schreiben
  3. Cylinder Low schreiben
  4. Cylinder High schreiben
  5. Device Register schreiben (angeben, ob LBA verwendet werden soll, welches Device man adressieren will etc).
  6. Den Command Code ins Command Register schreiben
  7. Das Status-Register abfragen
  8. Wenn BSY = 1, gehe zu 7
  9. Das Daten-Register lesen (16 Bit!)
  10. Das Status-Register lesen
  11. Wenn DRQ = 1 ist, dann gehe zu 9
  12. fertig!

Im Detail:

  1. Sector Count Register Adressieren
  2. Anzahl Sektoren an DD0..7 anlegen
  3. DIOW = 0
  4. DIOW = 1
  5. Sector Number Rgsister adressieren
  6. Sektornummer an DD0..7 anlegen
  7. DIOW = 0
  8. DIOW = 1
  9. ...
  10. Command Register adressieren
  11. Command Code an DD0..7 anlegen
  12. DIOW = 0
  13. DIOW = 1
  14. Status-Register Adressieren
  15. DIOR = 0
  16. Wert von DD0..7 zwischenspeichern
  17. DIOR = 1
  18. BSY-Bit abfragen, und wenn gesetzt gehe zu 15
  19. Daten-Register adressieren
  20. DIOR = 0
  21. Wert von DD0..15 lesen
  22. DIOR = 1
  23. Status-Register adressieren
  24. DIOR = 0
  25. Wert von DD0..7 zwischenspeichern
  26. DIOR = 1
  27. DRQ-Bit abfragen, und wenn gesetzt gehe zu 20
  28. Fertig!

Command Codes

Um natürlich bestimmte Aktionen ausführen zu können, muss man die Command Codes der Festplatte kennen. Die wichtigsten Command Codes lauten:

Command Code Kommentar
Identify Device 0xEC Gibt Infos wie Modell, Hersteller, Kapazität... aus
Read Sector(s) 0x21 / 0x20 Liest die gewünschte Anzahl Sektoren von der Platte
Seek 0x70 Positioniert die Schreib-/Leseköpfe über dem angegebenen Sektor
Standby 0xE2 Schaltet die Platte aus. Sie wird autom. wieder aktiv, wenn man ihr einen neuen Befehl sendet.
Write Sector(s) 0x30 / 0x31 Schreibt die gewünschte Anzahl Sektoren auf die Platte.

Es gibt natürlich noch wesentlich mehr Kommandos, aber mit diesen paar hier kann man i.d.R. schon alles, was man braucht, um ein Dateisystem zu implementieren. Eine genauere Beschreibung findet sich unter diesem Link: http://t13.org/Documents/MinutesDefault.aspx?DocumentType=4&DocumentStage=2 Dann dort den gewünschten ATA-Standard auswählen (Aktuell ist glaube ich ATA-7).

Links