AVR - IDE Festplatte liefert immer Fehler beim lesen

OP #4377713
Lesenswert?

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?
OP #4377729
Lesenswert?

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....
OP #4377762
Lesenswert?

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:
1
uint8_t pata_init ()
2
{
3
    uart_putstring ( PSTR ( "INFO: PATA init start" ), true );
4
    while ( ( !pata_rdy() ) & pata_bsy() ) {}
5

6
    /*set drive 0 to LBA mode*/
7
    write_io_register ( PATA_RW_DEVICE_HEAD_REGISTER, ATA_LBA_DRIVE_0 );
8
    while ( ( !pata_rdy() ) & pata_bsy() ) {}
9

10
    /*recalibrate*/
11
    write_io_register ( PATA_W_COMMAND_REGISTER, CMD_RECALIBRATE );
12
    while ( pata_bsy() ) {}
13

14

15
    return ata_identify();
16

17
}
#4377876
Lesenswert?

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.
1
;*********************************************************************
2
;  IDE Read Sektor in ZYL_L, ZYL_H, SEKTOR, HEAD die Sektornummer
3
;           in HD_LOAD_L, HD_LOAD_H der Zeiger auf den Load-Buffer
4
;
5
;  Scratch-Reg: TEMP_A, TEMP_B, COPY, ZH, ZL, YH, YL, MCU_TMP
6
;*********************************************************************
7

8
ide_rd_sek:  
9
        ldi     ZL,RG_HEAD          ; Register Drive/Head
10
        mov     YL,LBA_0            ; Head
11
        rcall   ide_wr_byte
12

13
        ldi     ZL,RG_H_ZYL         ; Register Zylinder-Nummer High
14
        mov     YL,LBA_1            ; Zylinder High holen
15
        rcall   ide_wr_byte
16

17
        ldi     ZL,RG_L_ZYL         ; Register Zylinder-Nummer Low
18
        mov     YL,LBA_2            ; Zylinder Low holen
19
        rcall   ide_wr_byte
20

21
        ldi     ZL,RG_S_NUM         ; Register Sektor-Nummer
22
        mov     YL,LBA_3            ; Sektor holen
23
        rcall   ide_wr_byte
24

25
        ldi     ZL,RG_S_COUNT       ; Register Sektor-Anzahl
26
        ldi     YL,1                ; 1 Sektor
27
        rcall   ide_wr_byte
28

29
        ldi     ZL,RG_CMD           ; Register Command
30
        ldi     YL,$20              ; Command Read Sektor
31
        rcall   ide_wr_byte
32

33
sek_loop:
34
        ldi     ZL,RG_STAT          ; IDE-Adresse
35
        rcall   ide_rd_byte
36
        sbrc    YL,SR_BSY           ; Nicht mehr Busy
37
        rjmp    sek_loop            ; sonst weiter warten
38

39
        sbrs    YL,SR_DRDY          ; Ready ?
40
        rjmp    sek_loop
41

42
        sbrs    YL,SR_ERR           ; Fehler
43
        rjmp    read_sec
44

45
        push    YL                  ; Status-Byte merken
46
        ldi     ZL,RG_ERR           ; IDE-Adresse
47
        rcall   ide_rd_byte         ; Error-Byte nach YL
48
        pop     YH                  ; Status-Byte nach YH holen !!!
49

50
        ret                         ; Error, YH enthält Statusbyte, YL Error-Byte
51

52
read_sec:
53
        sbrs    YL,SR_DRQ           ; DRQ noch nicht da
54
        rjmp    sek_loop
55

56
        ldi     TEMP_B,2            ; 2* 256 Byte -> 1 Sektor
57

58
read_l:
59

60
; einlesen in MINI_BUF
61

62
        cli                         ; IRQ sperren
63

64
        ldi     ZL,RG_DATA          ; Datenregister
65
        ldi     ZH,EXT_RAM_DUMMY    ; $FF
66
        ld      TEMP_A,Z            ; Adresse im Latch
67

68
        ext_ram_off
69

70
        load_p  Z,MINI_BUF          ; weil ext. Ram aus !
71
        ldi     TEMP_A,128          ; für 256 Byte MINI_BUF und Word-Zugriff !
72

73
rd_loop:
74
        cbi     IDE_PORT,IDE_DIOR
75
        nop
76
        in      YL,IDE_L_IN
77
        in      YH,IDE_H_IN
78
        sbi     IDE_PORT,IDE_DIOR
79

80
        st      Z+,YL
81
        st      Z+,YH
82

83
        dec     TEMP_A
84
        brne    rd_loop
85

86
        ext_ram_on
87
        sei                         ; IRQ frei
88

89
; kopieren MINI_BUF -> (HD_LOAD)
90

91
        load_p  Z,MINI_BUF          ; weil ext. Ram aus !
92
        mov     YH,HD_LOAD_H
93
        mov     YL,HD_LOAD_L        ; Pufferadresse holen
94

95
        clr     TEMP_A              ; für 256 Byte MINI_BUF und Byte-Zugriff !
96

97
copy_loop:
98
        ld      COPY,Z+
99
        st      Y+,COPY
100

101
        dec     TEMP_A
102
        brne    copy_loop
103

104
        mov     HD_LOAD_H,YH
105
        mov     HD_LOAD_L,YL         ; aktuelle Puffer-Adresse merken
106

107
        dec     TEMP_B
108
        brne    read_l
109

110
        ret

Gruß aus Berlin
Michael
OP #4378123
Lesenswert?

Ich fahre nun erstmal alle meine Platten mit CHS an und lese den 1. 
Sektor auf jeder Platte.

1
    while ( pata_bsy() == 1);
2

3
    write_io_register (PATA_RW_SECTOR_COUNT_REGISTER,  1);
4
    write_io_register (PATA_RW_SECTOR_NUMBER_REGISTER, 1);
5
    write_io_register (PATA_RW_CYLINDER_LOW_REGISTER,  0);
6
    write_io_register (PATA_RW_CYLINDER_HIGH_REGISTER, 0);
7
    write_io_register (PATA_RW_DEVICE_HEAD_REGISTER,   0xA0);
8

9
    write_io_register (PATA_W_COMMAND_REGISTER, 0x21 );
10

11
    while ( pata_bsy() == 1);
12
    while ( pata_drq() == 0 );
13

14
    daten lesen
15

16
    error-bit auswerten

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.
OP #4379692
Lesenswert?

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.

:(
OP #4407309
Lesenswert?

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.....

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren