Hallo,
ich habe mir im Zuge meines MP3-Player-Projektes die Ansteuerung einer
Festplatte als ehrgeizige Zwischenetappe gesetzt. Leider gibts dabei
(noch) Probleme. Aber nun von Anfang an: Ich habe im Internet
vollständige Routinen inkl. Doku für die Ansteuerung einer Festplatte
gefunden. Der Code stammt von den beiden Brasilianern Angelo Bannack und
Giordano Bruno Wolaniuk. Meine Testschaltung ist der der beiden sehr
ähnlich. Ich habe sowohl den kompletten Code inkl. Doku sowie meine
Schaltung angehängt. Hier mal die ersten paar Zeilen der main():
1 | int main(void)
|
2 | {
|
3 | TFILE *farq;
|
4 | struct direntry *de;
|
5 | char path[12];
|
6 |
|
7 |
|
8 | mcuInit(); // start ATMega128
|
9 | fdevopen(uart_putc, NULL); // configure printf to send data to serial port
|
10 |
|
11 | printf("FAT16/32 file system driver v1.00\r\n");
|
12 | printf("Written by Angelo Bannack and Giordano Bruno Wolaniuk\r\n\r\n");
|
13 |
|
14 | ataInit(); // Start ATA
|
15 | fatInit(); // Start FAT
|
16 |
|
17 | print_hd_info();
|
18 |
|
19 | ...
|
Also die beiden printf-Ausgaben werden übertragen, aber in der ataInit()
bleibt das Script hängen. Hier die Funktion:
1 | void ataInit(void)
|
2 | {
|
3 | unsigned char i;
|
4 | unsigned char* buffer = (unsigned char*) SECTOR_BUFFER_ADDR;
|
5 |
|
6 |
|
7 | DDR_DATAL= 0x00; // Use DATAL as the input from the hardrive
|
8 | DDR_DATAH= 0x00; // Use DATAH as the input from the hardrive
|
9 | PORT_DATAL= 0xFF; // Enable pullup on DATAL
|
10 | PORT_DATAH= 0xFF; // Enable pullup on DATAH
|
11 |
|
12 | DDR_ADDR = 0xDF; // Use ADDR PORT as the output for the hardrive
|
13 | // But use PORT_ADDR.5 as host interrupt (INPUT)
|
14 | PORT_ADDR= 0xc0; // Initialize PORT_ADDR to c0.
|
15 |
|
16 |
|
17 | ataWriteByte(ATA_REG_ACTSTATUS, 0x06); // Assert Software reboot.
|
18 | delay(100);
|
19 | ataWriteByte(ATA_REG_ACTSTATUS, 0x00);
|
20 | delay(100);
|
21 |
|
22 | //TESTTEIL: (hinzugefügt von mir)
|
23 | printf("ataReadByte(ATA_REG_ACTSTATUS): ");
|
24 | printf(ataReadByte(ATA_REG_ACTSTATUS));
|
25 |
|
26 | // Wait until drive clear BUSY Bit in Alternate Status Register
|
27 | while(IDE_Wait_State(ATA_SR_BSY) == 1);
|
28 |
|
29 | // issue identify command
|
30 | ataWriteByte(ATA_REG_HDDEVSEL, 0);
|
31 | ataWriteByte(ATA_REG_ACTSTATUS, 0x02);
|
32 |
|
33 | while(IDE_Wait_State(ATA_SR_DRDY) == 0);
|
34 |
|
35 | ataWriteByte(ATA_REG_CMDSTATUS1, 0xEC);
|
36 | // wait for drive to request data transfer
|
37 |
|
38 | while(IDE_Wait_State(ATA_SR_DRQ) == 0);
|
39 |
|
40 | delay(200); // wait 200 us
|
41 | // read in the data
|
42 | ataReadDataBuffer(buffer, 512);
|
43 |
|
44 | // set local drive info parameters
|
45 | ataDriveInfo.cylinders = *( ((unsigned int*) buffer) + ATA_IDENT_CYLINDERS );
|
46 | ataDriveInfo.heads = *( ((unsigned int*) buffer) + ATA_IDENT_HEADS );
|
47 | ataDriveInfo.sectors = *( ((unsigned int*) buffer) + ATA_IDENT_SECTORS );
|
48 | ataDriveInfo.LBAsupport = *( ((unsigned int*) buffer) + ATA_IDENT_FIELDVALID );
|
49 | ataDriveInfo.sizeinsectors = *( (unsigned long*) (buffer + ATA_IDENT_LBASECTORS*2) );
|
50 | // copy model string
|
51 | for(i=0; i<40; i+=2)
|
52 | {
|
53 | // correct for byte order
|
54 | ataDriveInfo.model[i ] = buffer[(ATA_IDENT_MODEL*2) + i + 1];
|
55 | ataDriveInfo.model[i+1] = buffer[(ATA_IDENT_MODEL*2) + i ];
|
56 | }
|
57 | // terminate string
|
58 | ataDriveInfo.model[40] = 0;
|
59 |
|
60 | // process and print info
|
61 | if(!ataDriveInfo.LBAsupport) {
|
62 | // CHS, no LBA support
|
63 | // calculate drive size
|
64 | ataDriveInfo.sizeinsectors = (unsigned long) ataDriveInfo.cylinders*ataDriveInfo.heads*ataDriveInfo.sectors;
|
65 | }
|
66 | }
|
Der Code kommt über die folgende Zeile einfach nicht hinaus. Außerdem
die Funktion IDE_Wait_State():
1 | while(IDE_Wait_State(ATA_SR_BSY) == 1);
|
2 |
|
3 | unsigned char IDE_Wait_State(unsigned char test_bit)
|
4 | {
|
5 | if ((ataReadByte(ATA_REG_ACTSTATUS) & test_bit) == test_bit)
|
6 | return 1;
|
7 | return 0;
|
8 | }
|
Meine Testzeile darüber funktioniert auch nicht. Ich kann einfach kein
Byte aus dem Alternate Status Register lesen. Hier die entsprechende
Funktion:
1 | unsigned char ataReadByte(unsigned char reg)
|
2 | {
|
3 | register unsigned char ret;
|
4 |
|
5 | PORT_DATAL = 0xFF; // habilita pull-ups
|
6 | DDR_DATAL = 0x00; // Use the DATAH as an input
|
7 | PORT_ADDR = PORT_ADDR & 0xe0; // Clear the lower 5 bits of the address line
|
8 | PORT_ADDR = PORT_ADDR | (reg & 0x1f); // Assert the address Line
|
9 |
|
10 | //cbi(PORT_IDE_RD, PIN_IDE_RD); // Assert DIOR
|
11 | PORT_IDE_RD &= ~(1 << PIN_IDE_RD);
|
12 | __asm volatile ("NOP");
|
13 | __asm volatile ("NOP");
|
14 | __asm volatile ("NOP");
|
15 |
|
16 | ret = PIN_DATAL;
|
17 | //sbi(PORT_IDE_RD, PIN_IDE_RD); // Negate DIOR
|
18 | PORT_IDE_RD |= (1 << PIN_IDE_RD);
|
19 |
|
20 | return (ret);
|
21 | }
|
Die cbi() und sbi() habe ich wegkommentiert und ersetzt. Kann mir
vielleicht jemand sagen, warum ich nicht auf die Register zugreifen
kann? Ich weiß, es handelt sich um sehr viel Code, aber ich komme
einfach nicht weiter. Ich verwende übrigens eine Seagate ST31720A,
dessen Datenblatt ich auch angehängt habe.
Ich hoffe auf eure Hilfe!