Hallo,
ich habe einen ATMega 1284P und eine ATA/IDE Schaltung inkl. Software
welche mir das lesen und schreiben auf einer Festplatte erlaubt.
erstmal meine Schaltung:
http://www.pofo.de/P8000/notes/plaene/eigene/P8000_WDC_Emulator/P8000_WDC_Emulator_v1.2_Plan.pdf
und der relevante Softwareteil:
https://github.com/OlliL/P8000_WDC_Emulator/blob/master/P8000_WDC_Emulator/wdc_drv_pata.c
Ich habe nun ein paar Festplatten getestet und alle laufen problemlos
bis auf eine.
WDC AC31600H (1.6GB)
WDC AC23200L (3.2GB)
WDC AC26400R (6.4GB)
Maxtor 2F040L0 (40GB)
MAXTOR 6L080J4 (80GB)
Probleme macht mir die WDC AC31600H. Diese liefert beim lesen eines
Sektors immer 1 im ErrorBit des Statusregisters und ich weiss einfach
nicht wiso. Ich habe die Festplatte mit MS-DOS 6.22 und FreeBSD
problemlos lesen und beschreiben können. Die Platte an sich scheint also
keine Probleme zu haben.
Die Ausgabe meiner IDENTIFY Routine:
1
INFO: Number of logical cylinders: 3148
2
INFO: Number of logical heads: 16
3
INFO: Number of logical sectors per logical track: 63
4
INFO: Serial number: WD-WT2891920914
5
INFO: Firmware revision: 23.16U73
6
INFO: Model number: WDC AC31600H
7
INFO: Capabilities: DMA, LBA, IORDY may be disabled, IORDY, Standard standby timer values,
8
INFO: User addressable sectors for 28-bit commands: 3173184
9
Single Word DMA modes: 0
10
Multiword Word DMA modes: 1031
11
PIO modes: 3
12
INFO: Minimum Multiword DMA cycle time per word: 120ns
13
INFO: Recommended Multiword DMA cycle time: 120ns
14
INFO: Minimum PIO transfer cycle time without flow control: 160ns
15
INFO: Minimum PIO cycle time with IORDY flow control: 120ns
Wie lese ich nun von der Platte. Ich versuche mal die entsprechende
Routine aus wdc_drv_pata.c zusammenzufassen:
- AVR-Port auf Output stellen
- Setzen PATA_RW_SECTOR_COUNT_REGISTER
Datentransfer: Anzahl zu lesende Blöcke
- Setzen PATA_RW_SECTOR_NUMBER_REGISTER
Datentransfer: niedrigen 8 bit der niedrigen 16 bit des zu lesenden
Blocks
- Setzen PATA_RW_CYLINDER_LOW_REGISTER
Datentransfer: hohen 8 bit der niedrigen 16 bit des zu lesenden Blocks
- Setzen PATA_RW_CYLINDER_HIGH_REGISTER
Datentransfer: niedrigen 8 bit der hohen 16 bit des zu lesenden Blocks
- Setzen PATA_RW_DEVICE_HEAD_REGISTER
Datentransfer: hohen 8 bit der hohen 16 bit des zu lesenden Blocks
und-verknüpft mit 0x0F und ergänzt um 0xE0 für drive 0 (master)
- Setzen PATA_W_COMMAND_REGISTER
Datentransfer: 0x20
Wie läuft der eigentliche Datentransfer ab:
- Daten an den Port anlegen,
- /DIOW aktiv setzen
- 2 * nop()
- /DIOW deaktivieren
Danach werden dann die eigentlichen Nutzdaten gelesen:
- AVR-Port auf Input stellen
- Schleifeneinstieg:
- warten bis BSY low wird und DRQ high wird
- Setzen PATA_RW_DATA_REGISTER
- /DIOR aktiv setzen
- 3 * nop()
- die niederen 8 Bit rufe ich nun direkt vom Port ab, die oberen 8 Bit
liegen automagisch in einem Latch zwischengeparkt
- /DIOR deaktivieren
- die oberen 8 Bit vom Latch abrufen
- alle Register (cs0,da0,....) deaktivieren
- und weiter bei "Schleifeneinstieg" bis alle Daten abgeholt wurden.
Danach rufe ich das STATUS-Register ab, und hier ist nun das Error-Bit
gesetzt.
Sieht einer Fehler?
Ich hasse es immer wenn ich meine Fragen selber beantworten muss....
1
/* Wait for BSY goes low and DRQ goes high */
2
while ( pata_bsy() & !pata_drq() ) {}
Was ist falsch? Genau... bitweises AND anstatt logisches AND... die
"moderneren" Platten waren zufällig alle schnell genug... oh man...
Problem erledigt....
Irgendwie passt das immer noch nicht. Wenn ich mir andere
Implementierungen anschaue, warten Diese bis bsy nicht mehr gesetzt ist,
dann wird das Kommando geschickt (0x20) und dann wird gewartet bis DRQ
high ist.
Wenn ich das bei mir so implementiere, dann kommt bei meinen
funktionierenden Platten schon beim IDENTIFY Müll raus.
Wenn ich vor dem Kommando nur auf bsy warte, bekomme ich bei meinen
funktionierenden Platten beim Lesen eines Blockes 2x d0 zu lesen und
dann direkt 58. Also BEVOR ich das Kommando 0x20 sende ist bereits DRQ
high. Wie soll man daraus schlau werden?
Bei meinem nicht funktionierenden LW geht er von 1x d0 auf 59 (error bit
gesetzt) noch BEVOR ich Kommando 0x20 sende.
Überhaupt... lesen der IDENTIFY Daten klappt ja bei allen Laufwerken.
Kann es evtl. sein, dass das Drive nicht richtig in den LBA-Mode gesetzt
wurde?
Läuft bei mir so ab:
Habe auch einfach mal versucht "hardcoded" CHS zu machen:
Sector count 1
Sector number 0
Cylinder low 0
Cylinder high 0
Device head 0xA0 (Drive 0, CHS, Head 0 sollte das sein).
Beim lesen der Daten wandert er auch dort von D0 auf 59.....
Hallo,
aua... sowas habe ich vor 15 Jahren mal mit einem 8515 gemacht, in ASM
als MP3-Player.
Den Source hätte ich wohl dmals etwas mehr kommentieren sollen.
Platte war irgendeine 2,5" 2GB.
Das HD war Memory-mapped am 8515, Schalplan müßte ich selber suchen.
Zugegriffen habe ich wohl im CHS-Mode, da muß ich aber erstmal genauer
schauen.
Zumindest schicke ich hier Drive/Head,Zylinder High/Low, Sektornr,
Sektoranzahl und dann die 0x20 für Read Sektor raus.
Dann warte ich, bis Busy nicht mehr aktiv ist und anschließend bis DRDY
aktiv ist.
Ich klebe das Fragment hier einfach mal rein, vielleicht hilft es
irgendwie.
Das erste pata_bsy() liefert 0x50 -> es geht los
und schon beim nächsten pata_bsy() kommt 0x59, pata_drq() liefert dann
natürlich auch 0x59.
Warum frage ich mich nur.... seufz
Ist doch jetzt auch nicht groß anders als ataReadSectorsCHS() in
https://arduino.googlecode.com/svn-history/r1/trunk/build/shared/lib/avrlib/ata.c
PS:
Habe jetzt sogar mal eine ST3290A (261MB) ausgegraben die z.B. nur CHS
kann... selbst die läuft problemlos.
Habe jetzt mal das Error-Register ausgelesen. 0x04 kommt zurück - bei
allen Lese- und Schreibversuchen.
ABRT
indicates the requested command has been aborted due to a
drive status error (such as not ready or write fault) or because
the command is invalid.
Keine IDE-Cracks hier? ;)
ich habe es nun mal umgebaut und setze Drive/Head zuerst.
Ich habe dann mal 10ms delays nach dem setzen der Daten der jeweiligen
register und nach dem aktivieren von /WR und weitere 10ms nach dem
deaktivieren von /WR
Dann habe ich noch ein Status-Reg-Check nach jedem Register-set
eingebaut und es bleibt kontinuierlich bei 0x50 bis ich dann das
Kommando setze. Danach geht es sofort auf 0x59.
:(
Oliver L. schrieb:> while ( ( !pata_rdy() ) & pata_bsy() ) {}
Das ist doch wieder ein bitweises AND - Du solltest Deinen Code
gründlich auf derartige Fallstricke überprüfen.
Habs rausgefunden.... Logik Analysator und MS-DOS sei dank der nach dem
Power-Cycle der Platte im laufenden Betrieb und anschliessendem Zugriff
auch den gleichen Fehler wie ich bekommt aber dann ein Drive-Initialize
absetzt und danach nochmal probiert - erfolgreich.
Also mache ich beim Bootup meines AVR einfadch auch ein
Drive-Inititalize-Command und nun läufts.....