Čeština / English
Login

Návody / Přístup k externímu IDE disku

Autor: Stanislav Sigmund

Abstrakt: Dokument popisuje jak připojit externí disk s rozhraním IDE případně paměťovou kartu Compact Flash k FITkitu a dále způsob komunikace přes rozhraní IDE.

Update: 10.6.2009

1. Rozhraní IDE

K připojení standardního disku IDE se používá konektor, který obsahuje 40 pinů. Stejné rozhraní je možné bezezměny využít i ke komunikaci s paměťovou kartou Compact Flash (CF). Význam a umístění jednotlivých pinů je uvedeno v následující tabulce. Symbol - u některých signálů značí jejich aktivitu v log. 0. Ke komunikaci se používá úroveň signálů TTL a pro FITKit tedy není zapotřebí nic měnit. Následující popis vychází ze specifikace ATA-3, která by měla být v dnešní době podporována téměř všemi pevnými disky.

Signál

I/O

číslo pinu

Signál

I/O

číslo pinu

RESET-

I

1

Zem

2

DD7

I/O

3

DD8

I/O

4

DD6

I/O

5

DD9

I/O

6

DD5

I/O

7

DD10

I/O

8

DD4

I/O

9

DD11

I/O

10

DD3

I/O

11

DD12

I/O

12

DD2

I/O

13

DD13

I/O

14

DD1

I/O

15

DD14

I/O

16

DD0

I/O

17

DD15

I/O

18

Zem

19

klíč

20

DMARQ

O

21

Zem

22

DIOW-

I

23

Zem

24

DIOR-

I

25

Zem

26

IORDY

O

27

CSEL

28

DMACK-

I

29

Zem

30

INTRQ

O

31

Rezervováno

32

DA1

I

33

PDIAG-

34

DA0

I

35

DA2

I

36

CS0-

I

37

CS1-

I

38

DASP-

39

Zem

40

Tabulka : Popis jednotlivých pinů konektoru (I=disk pouze čte, O=disk pouze zapisuje, I/O=obousměrný)

Jednotlivé piny mají následující význam:

  • RESET- : Hardwarový reset (inicializace). Po inicializaci disky provedou diagnostiku.

  • DD0-DD15 : Obousměrné datové vodiče. Přenos dat probíhá po 16-ti bitech, přístup k registrům po 8-mi bitech (signály DD0-DD7).

  • klíč : Tento pin bývá odstraněn a měl by zabránit špatnému otočení kabelu

  • DMARQ : Disk signalizuje, že může přenést jedno slovo dat v DMA režimu

  • DMACK- : Tímto signálem signalizuje řadič disku platnost dat v DMA režimu

  • DIOW- : Tento signál signalizuje zápis dat na disk (použit ve všech režimech)

  • DIOR- : Tento signál signalizuje čtení dat z disku (použit ve všech režimech)

  • IORDY : Signalizace disku, že je připraven na další přenos dat (jen PIO režim). Je nutný jen v PIO módech 2 a výš, v nižších je pouze volitelný

  • INTRQ : Signalizuje dokončení operace, je vypínatelný

  • DA0, DA1, DA2, CS0-, CS1- : tyto signály slouží k adresaci registru (viz Tabulka 2)

  • CSEL : Umožňuje konfiguraci disků podle umístění na kabelu

  • DASP-,PDIAG : Jsou použity disky k diagnostice a vzájemné identifikaci

1.1. Využití signálů

Disk může v dnešní době pracovat v několika režimech, lišících se víceméně přenosovou rychlostí. Nejjednodušším je přenos dat v PIO režimu, kdy jsou využity signály DD0-DD15, DA0-DA2, CS0-, CS1-, DIOW- a DIOR-. Komplikovanější avšak výkonnější DMA režim navíc vyžaduje obsluhu signálů DMARQ a DMACK-.

Je vhodné též využít signál RESET-, nebo jej trvale umístit do stavu log. 1. Signály INTRQ a IORDY mohou být použity volitelně. Ostatní signály by měly zůstat nezapojené.

1.2. Připojení IDE k FITKitu:

FITkit je připojen k IDE přes standartní 40-pinový kabel, pro FITkit verze 1.x musí být konekor upraven obroušením jeho okrajů, aby nezavazel pinům konektoru, FITKit 2.0 má jiné umístění konektoru (nevyžaduje jeho úpravu). FITKit 2.0 ale nemá připraven žádný typ architektury.

ide_kabel.png

Obrázek 1.1: Oříznutí kabelu

Použitý řadič umožňuje několik poloh kabelu, o zapojení vývodů se stará komponenta IDE_port. Tato komponenta se nachází v adresáři fpga\ctrls\ide.

ide_port.png

Obrázek 1.2: Komponenta IDE_port

Popis portů komponenty:

  • X: 46-bitový port, slouží pro přímé napojení na port X FPGA komponenty (konektor)

  • IDE: 26-bitový port, napojuje se na port IDE řadiče, obsahuje všechny nutné signály

Komponenta má několik architektur, které jsou přizpůsobeny poloze konektoru:

  • Architektura basic: Je určena pro standartní polohu kabelu, viz obrázek

ide_basic.png

Obrázek 1.3: Poloha kabelu pro architekturu basic

  • Architektura rotate: Je určena pro obrácenou polohu kabelu, vhodné pro umístění FITKitu na disk - zabraňuje přetočení kabelu

ide_rotate.png

Obrázek 1.4: Poloha kabelu pro architekturu rotate

  • Architektura small: Je určena pro minimální využití portu X, umožňuje použití standartních komponent, vhodné ve spojení s architekturou čipu IDE (port X je přítomen zároveň se standartními porty). Pro tuto variantu je však potřeba speciálně upravit kabel a konektor se umísťuje jinak, aby se využily piny se zemí.

ide_small.png

Obrázek 1.5: Poloha kabelu pro architekturu small

Úprava kabelu

Je potřeba přepojit několik vodičů - lze využít samotný konektor, neboť obsahuje samořezná upínací místa. Při návrhu se předpokládalo přehnutí vývodů 33-40 ke kabelu, což umožňuje snížení rozdílu v délce původních a přepojených vodičů. Nadstavovat je nutné pouze vývod č. 1. Tabulka 2 ukazuje seznam vývodů a jejich přepojení. Je vhodné (ale ne nutné) pospojovat vodiče, označené "Na společnou zem" a připojit je na vývody 1 a 2.

Vodič

Úprava

Připojit vodič

Vodič

Úprava

1

Přepojit na 19

Společná zem

29

Beze změny

2

Zem

30

Na společnou zem

3-18

Beze změny

31

Zrušit

19

Na společnou zem

1

32

Zrušit

20

Zrušit

38

33

Přepojit na 27

21

Beze změny

34

Zrušit

22

Na společnou zem

37

35

Přepojit na 26

23

Beze změny

36

Přepojit na 24

24

Na společnou zem

36

37

Přepojit na 22

25

Beze změny

38

Přepojit na 20

26

Na společnou zem

35

39

Zrušit

27

Zrušit

33

40

Na společnou zem

28

Zrušit

Tabulka : Tabulka 2: Přepojení pinů na konektoru

2. Komunikace s pevným diskem

Komunikace probíhá prostřednictvím zápisu/čtení do/z řídících/datových registrů. Jednotlivé registry a jejich adresy jsou uvedeny v následující tabulce (hodnoty signálů CS1- a CS0- jsou konečné, tedy po invertování).

Adresa Význam při čtecí a zápisové operaci

CS1-

CS0-

DA2

DA1

DA0

čtení

zápis

1

1

0

0

0

klidový stav + DMA přenos

1

0

1

1

0

alternativní status + řízení zařízení

0

1

0

0

0

přenos dat (PIO)

0

1

0

0

1

chybový registr

funkce

0

1

0

1

0

počet sektorů

0

1

0

1

1

LBA(7-0)

0

1

1

0

0

LBA(15-8)

0

1

1

0

1

LBA(23-16)

0

1

1

1

0

LBA(27-24) + výběr disku

0

1

1

1

1

status

příkaz

Tabulka : Tabulka 3: Adresy jednotlivých registrů

Popis registrů

  • klidový stav + DMA přenos: Tato kombinace adresních bitů definuje klidový stav a je používána v případě DMA přenosu, kdy je nutné nastavit tuto adresu, což umožňuje přerušit probíhající DMA přenos

  • alternativní status : vrací stejné výsledky, jako registr status, ale neruší stav chyby.

  • řízení zařízení : bit 1 = vypnutí přerušení (0=přerušení zapnuto), bit 2 = softwarový reset

  • chybový registr : pokuď je nastaven bit 0 v registrech status/alternativní status, vrací seznam chyb:

    bit 7

    bit 6

    bit 5

    bit 4

    bit 3

    bit 2

    bit 1

    bit 0

    r

    UNC

    MC

    IDNF

    MCR

    ABRT

    TK0NF

    AMNF

    Tabulka : přiřazení jednotlivých bitů chybového registru

    Význam bitů chybového registru:

    • AMNF: adresa nebyla nalezena i po nalezení správného ID sektoru

    • TK0NF: stopa číslo 0 nenalezena

    • ABRT: příkaz přerušen (neznámý příkaz, nebo nastala chyba)

    • MCR: žádost o změnu média (pouze u vyměnitelných médií)

    • IDNF: sektor nenalezen

    • MC: médium změněno (pouze u vyměnitelných médií)

    • UNC: neopravitelná data (při zápisu/čtení)

    • r: rezervován

  • status registr/alternativní status : vrací stav média, čtení tohoto registru ruší chybové stavy

    bit 7

    bit 6

    bit 5

    bit 4

    bit 3

    bit 2

    bit 1

    bit 0

    BSY

    DRDY

    DF

    DSC

    DRQ

    CORR

    IDX

    ERR

    Tabulka : přiřazení jednotlivých bitů stavového registru

    Význam bitů stavového registru:

    • ERR: nalezena chyba, popis chyby je v chybovém registru

    • IDX: záleží na výrobci

    • CORR: nalezena opravitelná data, přenos dat je nepřerušen

    • DRQ: žádost o data - disk je připraven přenášet data

    • DSC: stopa nalezena

    • DF: chyba zařízení - porucha disku

    • DRDY: zařízení připraveno

    • BSY: zařízení zaneprázdněno - nepřijímá další příkazy

  • funkce: slouží pro zapsání dodatečných parametrů pro některé příkazy

  • počet sektorů: určuje počet přenášených sektorů naráz, 0 = 256

  • LBA(23-0): adresa sektoru v režimu LBA28

  • LBA(27-24) + výběr disku: nejvyšší 4 bity adresy, bity 7 a 5 mají být nastaveny na 1, bit 6 je nastaven na 1 pro LBA režim, bit 4 určuje vybraný disk (0=MASTER)

  • příkaz: provedení příkazu disku, příkaz se spouští zápisem kódu na tento registr (všechny potřebné hodnoty už musejí být nastaveny)

Přenosové režimy

Režim PIO

V režimu PIO je celý přenos v režii řadiče komunikujícího s diskem. Veškeré doby jsou uvedeny pro rychlost PIO 0. Přenos znaku (v případě registru) nebo slova (jsou-li přenášena data) musí být vždy zahájen nastavením správné adresy (CS1-, CS0-, DA2-DA0) -viz Tabulka 3. Po ustalovací době adresních bitů (min. 70ns) může být aktivován signál DIOW- v případě jedná-li se o zápis nebo signál DIOR- v případě čtení. Vybraný signál musí být nastaven min. po dobu 290ns. Při zápisu dat musí být na datových vodičích data přítomna min. 60ns před daktivací signálu DIOW- a min. 30ns po jeho deaktivaci. Čtená data jsou platná min. 50ns před deaktivací signálu DIOR-. Minimální délka cyklu je 600ns.

PIO.png

Obrázek 2.1: PIO režim

Režim DMA

V režimu DMA je přenos řízen diskem. Během přenosu musí řadič nastavit neutrální adresu (signály CS0- a CS1- jsou na 1 po zinvetování). Veškeré doby jsou uvedeny pro rychlosti DMA0/DMA1. Přenos zahajuje disk nastavenim signálu DMARQ, pokuď řadič může data zpracovat či je dodat, tak nastaví signál DMAACK. Poté vždy řadič nastaví signál DIOR-/DIOW- podle směru dat (nastaveny musejí být min. po dobu 215ns/80ns), data musejí být nastavena diskem/řadičem (čtení/zápis na disk) min. 100ns/30ns před zrušením těchto signálů. Při zápisu musí řadič data na výstupu podržet min. 20ns/15ns po ukončení DIOW-. Disk může zrušit signál DMARQ nejpozději 120ns/40ns po nastavení signálů DIOR-/DIOW-. Minimální doba mezi náběžnými hranami signálů DIOW-/DIOR- je 480ns/150ns, což určuje max. přenosovou rychlost.

DMA.png

Obrázek 2.2: DMA režim

2.1. Přehled njedůležitějších příkazů

Příkazy se provedou zapsáním potřebných hodnot do registrů a pak zapsáním čísla příkazu do registru příkaz.

Seznam příkazů a jejich číselných kódů:

Příkazy čtení/zápisu:

  • PIO čtení 0x21

  • PIO čtení s návratem 0x20

  • PIO zápis 0x31

  • PIO zápis s návratem 0x30

  • DMA čtení 0xC9

  • DMA čtení s návratem 0xC8

  • DMA zápis 0xCB

  • DMA zápis s návratem 0xCA

vstupy:

  • adresa prvního sektoru a číslo disku v registrech LBA(23-0) (předpokládáme vždy režim LBA).

  • počet sektorů (1-256) ke čtení/zápisu v registru počet sektorů

popis:

  • zahájení čtení/zápisu v PIO/DMA režimu a příp. s návratem (opakování čtení špatně načtených registrů).

  • data jsou přítomna při nastavení stavu DRQ ve status registru

  • ve specifikaci ATA 3 musí být přítomny všechny typy těchto příkazů, ale používány by měly být spíše typy s návratem (na testovaném disku verze bez návratu nepracovala tak, jak měla)

Příkazy identifikace disku

  • Identifikace PIO 0xEC

  • Identifikace DMA 0xEE

popis:

  • přenos 1 sektoru (512B dat) z disku, obsahující informace aktuální o disku. Verze DMA je ve specifikaci ATA3 pouze dobrovolná (je tedy nutné počítat i s PIO verzí)

  • některé (nejpoužívanější) položky (pro úplný seznam viz specifikace ATA):

Offset

Velikost [B]

Popis

14H

20

Sériové číslo disku (opačné pořadí znaků a znaky vyplněny do konce mezerami)

36H

40

Model disku (jako u sériového čísla)

78H

4

počet adresovatelných sektorů (pouze LBA)

7EH

2

bity 15-8 - aktivní DMA režim, bity 7-0 - podporovaný DMA režim

A0H

2

bity 15-1 podporovaná specifikace ATA (bit 1=ATA1, ...)

Tabulka : Některé položky identifikace disku

Příkaz nastavení vlastností disku:

  • Nastav vlastnosti 0xEF

vstupy:

  • registr funkcí obsahuje číslo podpříkazu

  • další registry podle jednotlivých podpříkazů

popis:

  • nastaví některou z vlastností, může například nastavovat vyrovnávací paměť, spotřebu disku, či režim přenosu

  • režim přenosu: podpříkaz 03H, hodnota se nastavuje do registru počtu sektorů. Typ režimu je vybrán horními 5 bity, spodní 3 bity určují hodnotu.

Horních 5 bitů

Dolní 3 bity

Popis

00000

000

Základní PIO režim

00000

001

Základní PIO režim (bez řízení s IORDY)

00001

nnn

PIO režim nnn

00100

nnn

DMA režim nnn

Tabulka : Nastavení přenosového režimu

Další příkazy (viz specifikace ATA):

  • příkazy pro přenášení skupin sektorů (čtení/zápis, PIO/DMA)

  • příkazy pro verifikaci zápisu/čtení

  • příkazy pro řízení stavu disku (spotřeby)

  • příkazy SMART

  • příkazy zabezpečení dat

Specifikace ATA2: http://www.t13.org/Documents/UploadedDocuments/project/d0948r4c-ATA-2.pdf

Specifikace ATA3: http://www.t13.org/Documents/UploadedDocuments/project/d2008r7b-ATA-3.pdf

3. Souborový systém FAT32

3.1. Master Boot Record MBR

Tabulka MBR se nachází v sektoru 0 a popisuje jednotlivé oddíly, nacházející se na disku. Na začátku sektoru se nachází 446B spustitelného kódu. Za touto oblastí se nachází čtyři 16-bytové popisy jednotlivých oddílů. Sektor je uzavřen znakem AA55H, který označuje MBR sektor. Jednotlivé popisy mají strukturu, uvedenou v tabulce 5.

Offset

Velikost [B]

Popis

00H

1

Stav(0 = neaktivní, 80H = aktivní)

01H

1

Začátek – číslo hlavy

02H

2

Začátek – cylindr/sektor

04H

1

Typ oddílu (tabulka 6)

05H

1

Konec – číslo hlavy

06H

2

Konec – cylindr/sektor

08H

4

Logické číslo počátečního sektoru

0CH

4

Počet sektorů oddílu

Tabulka : Tabulka 5: Popis položky MBR

Typ

Popis

00H

Neznámý/žádný

01H

FAT12

04H

FAT16 (menší než 32MB)

05H

Rozšířený oddíl DOS

06H

FAT16 (větší než 32MB)

0BH

FAT32

0CH

FAT32 s LBA rozšířením (služby 13H BIOS)

0EH

FAT16 s LBA

0FH

Rozšířený oddíl DOS s LBA

Tabulka : Tabulka 6: Typy souborových systémů

Rozšířený oddíl DOS umožňuje větší počet oddílů na disku, než jsou základní čtyři. Ukazuje na strukturu, podobnou MBR, která obsahuje popis dalšího oddílu FAT a případně odkaz na další rozšířený oddíl. Adresa je ovšem vztažena k pozici aktuální tabulky, je tedy nutné je sečíst. Poslední rozšířený oddíl obsahuje již pouze poslední oddíl FAT.

3.2. FAT Boot Record

Podrobněji bude popisován systém FAT32, ostatní systémy pouze okrajově. První sektor oddílu FAT je Boot Record (viz tabulka 7). Obsahuje všechny potřebné údaje ke správnému nastavení oddílu.

Offset

Velikost [B]

Popis

Jméno

00H

3

Adresa spustitelné oblasti

JumpCode

03H

8

Jméno systému, který oddíl vytvářel

OEMName

0BH

2

Počet bytů na sektor (512,1024,2048,4096)

BytsPerSec

0DH

1

Sektorů na cluster

SecPerClus

0EH

2

Rezervovaných sektorů (běžně 32)

RsvdSecCnt

10H

1

Počet FAT tabulek (běžně 2)

NumFATs

11H

2

Počet položek v Root Directory (pro FAT32=0)

RootEntCnt

13H

2

Celkový počet sektorů.=0: údaj je ve 32b v.

TotSec16

15H

1

Typ disku, = F8H: pevný

Media

16H

2

Počet sektorů na FAT t.=0: údaj je ve 32b v.

FATSz16

18H

2

Sektorů na stopu

SecPerTrck

1AH

2

Počet hlaviček

NumHeads

1CH

4

Počet skrytých sektorů

HiddSec

20H

4

Celkový počet sektorů.=0: údaj je ve 16b v.

TotSec32

24H

4

Počet sektorů na FAT t.=0: údaj je ve 16b v.

FATSz32

28H

2

Aktivita FAT tabulek, bit 7 = 1: pouze jedna aktivní FAT tabulka (její číslo v bitech 0-3), = 0: mirroring|

ExtFlags

2AH

2

Verze FAT, měla by být = 0

FSVer

2CH

4

Číslo clusteru kořenového adresáře

RootClus

30H

2

Číslo informačního sektoru (obvykle 1)

FSInfo

32H

2

Číslo záložního boot sektoru

BkBootSec

34H

12

Rezervováno

40H

1

Písmeno disku, pevné disky začínají od 80H

DrvNum

41H

1

Rezervováno

42H

1

Následující 3 položky jsou přítomné:

BootSig

43H

4

Číslo svazku, pro identifikaci

VolID

47H

11

Jméno svazku

VolLab

52H

8

Typ systému, obvykle "FAT32 "

FilSysType

Tabulka : Tabulka 7: Boot Record

3.3. Informační struktura

Informační struktura, pokud se nachází na oddílu (FSInfo>0), obsahuje některé informativní údaje. Tyto údaje jsou pouze informativní a nemusejí být správné.

Offset

Velikost [B]

Popis

1E8H

4

Počet volných clusterů, = -1: neznámý

1ECH

4

Číslo clusteru, který byl naposledy alokován (zrychlení vyhledávání)

Tabulka : Tabulka 8: Informační struktura

3.4. Základní informace

Nejprve je třeba zjistit počet položek, alokovaných zvlášť pro kořenový adresář(pouze FAT12 a FAT16):

RootDir = [(RootEntCnt * 32) + BytsPerSec - 1]/BytsPerSec

Pro systém FAT32 bývá RootEntCnt = 0, Tedy i RootDir = 0. Poté je nutné zjistit číslo sektoru clusteru č. 2 (první cluster v systému). Před daty jsou tabulky FAT, rezervované sektory a sektory kořenového adresáře (pouze FAT12 a FAT16):

ClusStart = (NumFATs * FATSize) + RsvdSecCnt + RootDir

Nesmíme zapomenout, že čísla sektorů jsou vztažena k začátku oddílu. Následuje výpočet počtu clusterů v oddíle:

Clusters = (Sectors - ClussStart) / SecPerClus

Typ FAT tabulky by měl být určen právě z počtu clusterů, nikoliv tedy ze jména svazku (FilSysType) nebo jiných typických znaků. Pokud je počet clusterů menší než 4085, jedná se o FAT12, je-li větší nebo roven 4085 a menší, než 65525, jedná se o FAT16 a je-li větší nebo roven 65525, jedná se o FAT32. Číslo sektoru, na kterém se nachází cluster, lze spočítat: Sector = (Cluster-2)*SecPerClus + ClusStart

3.5. Adresářová struktura

Adresáře jsou podobné souborům, liší se pouze svojí délkou (adresáře mají vždy nulovou délku) a atributem DIRECTORY. Přístup k nim je však podobný. Adresář obsahuje jednotlivé položky, dlouhé 32B, které popisuje tabulka 9. Položky jsou řazeny za sebou a konec adresáře je označen zarážkou. Kořenový adresář se ve FAT32 nachází na clusteru č. RootClus.

Offset

Velikost [B]

Popis

Jméno

00H

8

Jméno položky, prázdná místa vyplněna znakem 32

Name

08H

3

Koncovka p., prázdná místa vyplněna znakem 32

Ext

0BH

1

Atributy položky

Attr

0CH

1

Rezervováno

NTRes

0DH

1

Čas vytvoření – setiny sekundy (pro 2 sekundy)

CrtTimeTenth

0EH

2

Čas vytvoření – granularita jsou 2 sekundy

CrtTime

10H

2

Datum vytvoření

CrtDate

12H

2

Datum posledního čtení/zápisu

LstAccDate

14H

2

Číslo prvního clusteru (horní polovina)

FstClusH

16H

2

Čas poslední změny (včetně vytvoření souboru)

WrtTime

18H

2

Datum poslední změny (včetně vytvoření souboru)

WrtDate

1AH

2

Číslo prvního clusteru (dolní polovina)

FstClusL

1CH

4

Délka souboru

FileSize

Tabulka : Tabulka 9: Položka adresáře

Typ položky je určen prvním znakem jména:

  • E5H – volná položka

  • 05H – normální položka, první znak = E5H

  • 00H – prázdná položka, za ní se nenachází žádná jiná položka (zarážka)

  • jiná hodnota – normální položka

CrtDate, LstAccDate, WrtDate

CrtTime, WrtTime

Rok

Měsíc

Den

Hodiny

Minuty

Vteřiny

(Bity 15 – 9)

1980|Bity 8 – 5

Bity 4 – 0

Bity 15 – 11

Bity 10 – 5

(Bity 4 – 0) * 2

Tabulka : Formát datumu a času

Atributy položky (kromě dlouhého jména jsou všechny komutativní):

  • 01H: Pouze pro čtení

  • 02H: Skrytý soubor/adresář

  • 04H: Systémový soubor/adresář

  • 08H: Jméno svazku (smí být pouze v kořenovém adresáři)

  • 10H: Adresář

  • 20H: Archivní soubor/adresář (byl změněn)

  • 0FH: Dlouhé jméno

3.6. Dlouhá jména

Pokud má nějaká položka dlouhé jméno, je toto uloženo v položkách jí předcházejících a s atributem "Dlouhé jméno". Každá taková položka obsahuje 13 znaků v kódování UTF16 a popisuje ji tabulka 10.

Offset

Velikost [B]

Popis

Jméno

00H

1

Pořadové číslo záznamu

SequenceNumber

01H

10

5 znaků jména

Name1

0BH

1

Atribut = 0FH

Attr

0CH

1

Rezervováno

Type

0DH

1

Kontrolní součet

CheckSum

0EH

12

6 znaků jména

Name2

1AH

2

Musí být 0

FirstClusterLO

1CH

6

3 znaky jména

Name3

Tabulka : Tabulka 9: Položka adresáře

Položky jsou řazeny v opačném pořadí (od konce jména po jeho začátek), pořadové číslo je od N po 1, položka s číslem N má k tomuto číslu přičteno ještě 40H.

3.7. Tabulka FAT

FAT tabulky se nacházejí za oblastí rezervovaných sektorů. První sektor tabulky (FATNum) se dá vypočítat pomocí vztahu: FATSector = RsvdSecCnt + FATNum * FATSz Pro FAT32 je tabulka tvořena polem položek o velikosti 4B, z nichž je použito 28bitů, nejvyšší 4bity jsou rezervovány a neměly by se měnit. Pro velikost sektoru 512B (nejpoužívanější) se tedy v jednom sektoru nachází 128 položek. Každá položka obsahuje číslo následujícího clusteru souboru/adresáře. Hodnota větší nebo rovna 0FFFFFF8H znamená konec řetězce, řetězec dále již nepokračuje a aktuální cluster je poslední. Číslo prvního clusteru řetězu je uloženo v položce adresáře ve FstClusL a FstClusH. Soubor o nulové délce, který dosud nemá alokována data, má číslo 0. Hodnota 0FFFFFF7H znamená vadný cluster. Hodnota 0 označuje volný cluster. Clustery číslo 0 a 1 nesmějí být použity.

FAT.png

Obrázek 3.1: Ukázka tabulky FAT

Na obrázku je ukázka tabulky FAT (v tomto případě FAT32) s velikostí 2KB na cluster. Kořenový adresář má přidělených 5 clusterů (2,3,4,7,5) a obsahuje 3 položky (zbytek místa by měl být vynulován, nulová položka je poslední položkou v adresáři).

  • První položka obsahuje soubor PRVNI.NIC (název by měl být psán velkými písmeny, FAT je necitlivá na velikost písmen). Ten však nemá ještě přiděleno místo, neboť jej dosud nepotřeboval, a tak má jako počáteční cluster hodnotu 0.

  • Druhá položka byla smazána, avšak předtím měla přidělena cluster číslo 5 (a pravděpodobně i 6, což vysvětluje skok v řetězci adresáře).

  • Třetí položka má přiděleny 4 clustery (8,9,10,11), aby mohla obsahovat všech 7654B dat.

4. Řadič IDE v FPGA

Použitý řadič se skládá z několika bloků a využívá komunikace přes rozhraní SPI. Zdrojové kódy se nacházejí v adresáři fpga\ctrls\ide, přičemž jsou k dispozici tři verze podle toho, zda má být přítomen kanál pro přímý přenos dat do jiných zařízení na FPGA.

ide_ctrl.png

Obrázek 4.1: Řadič IDE

ide_ctrl_blok.png

Obrázek 4.2: Blokové schéma řadiče

Popis signálů

  • IDE: 26b port, určený pro připojení na komponentu ide_port

  • RST: reset řadiče

  • CLK: hodiny

  • DI, DI_REQ, DO, DO_VLD, CS: signály rozhraní SPI

  • INTRQ: plánován pro přerušení, není využit a u varianty s výstupním kanálem ani není přítomen

  • READ_EN: řadič má připravena data pro zařízení

  • WRITE_EN: řadič vyžaduje data ze zařízení

  • DATA_IN: vstupní data do řadiče (8b)

  • DATA_OUT: výstupní data ze řadiče (8b)

  • ACCEPT: potvrzení platnosti dat (v obou směrech) zařízením

Základním blokem je obvod zápisu/čtení v PIO režimu, neboť ten je nutný pro přístup k registrům a taktéž umožňuje 16-bitový přenos dat - především využito identifikací disku, u které je DMA verze pouze volitelná. tento režim využívá port na adresách 0300H – 033EH, bity 5-1 adresy určují adresu registru. Přístup je vždy 16-bitový. Na adrese 04H se nachází řídící registr (8-bitový) signálu RESET-, ten je řízen bitem 0.

Další blok je určen pouze k hromadnému zápisu registrů s rostoucí adresou, což umožňuje především rychlejší zadání počtu sektorů, adresy sektoru a provedení příkazu (v tomto pořadí adresy rostou). Tento blok využívá adresy 0000H-001FH, kde bity 4-0 určují adresu prvního registru.

Přenos dat má nastarosti řadič DMA, který obsahuje jednu paměť BRAM, která se svojí velikostí 2kB umožňuje uchovávat až 4 sektory v paměti. Umístění dat v této paměti umožňuje především náhodný přístup k datům a odlehčení paměti procesoru v případě zápisu dat. Také konvertuje 16b data na 8b. Přístup k datům se provádí registrem na adesách 0800H-0FFFH, kde spodních 11 bitů určuje adresu 1. přenášeného znaku (horní 2 bity určují sektor). Přenos dat je 8b a umožňuje blokový přenos dat s inkrementální adresou. Přenos je řízen registrem na adrese 05H (8b registr), kde jednotlivé bity mají význam:

  • Zápis: bit 7 - spouští DMA přenos, bit 6 – provádí RESET obvodu, bit 5 – rychlost DMA (0=DMA0, 1=DMA1), bit 4 směr dat (0=čtení z disku, 1=zápis), bity 0-1 – výběr oblasti BRAM

  • Čtení: bit 7 – řadič stále pracuje

Reset obvodu je vhodné provést zvlášť před spuštěním a také před provedením příkazu na disku. Bity 1 a 0 určují jeden ze 4 cílových bloků paměti, přenáší se vždy všech 512 znaků.

Poslední blok je volitelný (výběrem typu řadiče) a je určen pro přenášení dat mezi pamětí řadiče a jiným zařízením na FPGA. Přenos je řízen řadičem a je 8bitový. Během přenosu je blokován přístup k datům, na stav přenosu se lze dotázat, ale pokud komunikující obvod příliž nezdržuje, mohu být data přenesena dříve, než je dotaz proveden. Zároveň může být přeneseno všech 2048 znaků. Řídící registr (24b) je na adresách 10H-11H:

  • Zápis: bit 23 – spouští obvod, bit 22 určuje směr dat (0=z obvodu), bity 21-11 jsou cílová adresa, bity 10-0 pak počáteční adresa

  • Čtení: bit 23 – obvod běží, bity 21-11 jsou cílová adresa, bity 10-0 pak aktuální adresa

  • Počet přenesených znaků = cílová adresa-počáteční adresa+1. Popis komunikace:

    Pokud chce řadič data číst z/zapisovat do vnitřní paměti BRAM, vystaví signál READ_EN / WRITE_EN a zapíše data na DATA_OUT /čte data z DATA_IN. Komunikující zařízení potvrzuje data signálem ACCEPT.

Celkový přehled portů je v tabulce 4.

adresa

režim

použití

délka adresy (B)

délka dat(B)

00H

Z

hromadný přístup k registrům disku

2

1+

03H

Z/Č

zápis/čtení PIO režim

2

2

04H

Z

řízení hardwarového resetu

1

1

05H

Z/Č

řízení/stav DMA kanálu

1

1

08H-0FH

Z/Č

čtení/zápis dat z sektorové paměti

2

1+

10H-11H

Z/Č

řízení/stav výstupního kanálu

1

3

Tabulka : Tabulka 4: přehled portů řadiče

5. Obsluha disku

K usnadnění práce s diskem byly vytvořeny dvě jednotky a sice ide.h a fat.h.

5.1. Jednotka ide.h

Tato jednotka je určena pro zastřešení práce s řadičem pevných disků. Jejím úkolem je identifikace disku/disků, načítání/ukládání dat, správa paměti na řadiči a případně ovládání výstupního kanálu. V hlavičkovém souboru se nachází mnoho konstant pro adresy portů, jejich hodnoty, ale i seznam všech příkazů disku. Vzhledem k nejasnostem při identifikaci disků je jednotka schopná identifikovat pouze disku typu MASTER, i když je stavěná pro práci na 2 discích.

Popis funkcí - základní funkce

void IDE_HDD_Setup_Init();

Je třeba provést před hledáním disku

int IDE_HDD_Setup();

vyhledává disk/disky, dokud je třeba hledat, tak vrací IDE_SETUP_WAIT

void Set_Wait_Count(int count);

nastaví dobu čekaní na operace, základní hodnota je 16000

int IDE_Identify(unsigned char *buff);

do 512B bufferu v paměti zapíše data z identify (používá PIO režim), vrací IDE_RET_OK v případě úspěchu

void IDE_Hard_Reset();

provede hardwarový reset

void IDE_Cache_Init();

inicializuje vnitřní paměť řadiče, nastaví ji na základní hodnoty. Vhodné ji provést po nalezení disků a před přístupem na disk

void IDE_Cache_Set(unsigned char cache,unsigned long Ssector,unsigned long Esector,unsigned char disk);

nastaví operační oblast jedné ze 4 oblastí v paměti. Oblast cache teď bude použita pro sektory Ssector až Esector disku disk. Určena pro optimalizaci přístupu.

int IDE_Cache_Flush(unsigned char cache);

Vyprázdní vybranou cache – pokud obsahuje nezapsaná data, jsou zapsána na disk

int IDE_Set_Sector(unsigned long sector,unsigned char disk);

nastaví aktuální disk a sektor, vrací stav, (IDE_C_OK v případě úspěchu)

int IDE_Write(unsigned short offset,unsigned short count,unsigned char *data);

zapíše count dat na aktuální sektor od pozice offset, count+offset<=512. Pokud data==NULL, zapisuje data z výstupního kanálu. Vrací počet zapsaných bytů

int IDE_Read(unsigned short offset,unsigned short count,unsigned char *data);

přečte count dat z aktuálního sektoru od pozice offset, count+offset<=512. Pokud data==NULL, zapisuje data na výstupní kanál. Vrací počet přečtených bytů

void IDE_Convert_String(unsigned char *str,signed char len);

upravuje řetězec z identify na ANSI formu, cílová oblast musí být alepsoň len+1 velká. Znaky jsou totiž přeházeny a zbytek řetězce je vyplněn znaky mezer

Popis funkcí - systémové funkce (málo využití mimo jednotku)

unsigned long FPGA_SPI_RW_A8_D3(unsigned char mode,unsigned char addr,unsigned long data);

upravená funkce, určená pro data délky 3 - FPGA_SPI_RW_A8_DN zadává byty v opačném pořadí. V případě čtení vrací přečtená data.

void IDE_CH_WriteData(unsigned short addr,unsigned short count); void IDE_CH_ReadData(unsigned short addr,unsigned short count);

zapisuje/čte count dat z/do cahce do/z výstupního kanálu

int IDE_CMD(unsigned char cmd);

provede příkaz, testuje chybové stavy před a po, vrací IDE_RET_OK

void IDE_ReadData(unsigned short addr,unsigned short count,unsigned char *buff); void IDE_WriteData(unsigned short addr,unsigned short count,unsigned char *buff);

přečte/zapíše data z/do cache

unsigned short IDE_Read_Word(); void IDE_Write_Word(unsigned short data);

přečte/zapíše data z/do datového PIO registru

void IDE_Change_Disc(int disc);

změní aktuální disk

void IDE_Sector(unsigned long addr);

změní aktuální sektor

void IDE_Spd_Sector(unsigned long addr,unsigned char cmd);

změní aktuální sektor a provede příkaz

unsigned char IDE_Read_Reg(unsigned char addr); void IDE_Write_Reg(unsigned char addr,unsigned char value);

přečte/zapíše registr

int IDE_Wait_Status(unsigned char astatus,unsigned char nstatus,unsigned char errdetect,unsigned short count);

čeká, až se nastaví status astatus a zruší status nstatus, nebo vyprší čas (count testů). Pokud errdetect!=0, pak při příznaku chyby skončí. Vhodný před některými příkazi, případně po nich

5.2. Jednotka fat.h

Tato jednotka slouží k přístupu na disky se souborovým systémem FAT32. Je možno ji upravit i na systémy FAT16 a FAT12, ale jejich použití se nepředpokládá.

Popis funkcí

int FAT_init_Part(unsigned char part,tFAT *fat,char *volume,unsigned char disc);

prochází přítomné souborové systémy na disku disc. Pokud je fat==NULL, tak vrací počet přípustných souborových systémů, pokud ne, inicializuje part přípustný souborový systém (počítáno od 0). Pokud volume!=NULL, zapíše do něj jmenovku svazku (oblast velká alespoň 13 bytů, řetězec ve formátu ANSI)

int FAT_Close(tFAT *f);

uzavře použitou FAT – uloží údaj o volném místě a naposledy použitém clusteru, vhodné před ukončením práce po zápise na disk

int FAT_Root_Dir(tFAT *f,tFile *dir);

do dir načte kořenový adresář FAT systému

void FAT_Set_Find(tFile *dir,char *name);

započne hledání v adresáři dir položky jména name (lze použít hvězdičkovou/otazníkovou notaci)

int FAT_Find_Next(tFile *dir,char *Fname,unsigned char *ext,unsigned char *attr,tFile *file);

hledá v adresáři dir položku se zadaným jménem, do Fname uloží jméno položky (min. 9B) a do ext pozici koncovky ve jméně (min. 4B). Do attr uloží atributy položky – je vhodné porovnávat na adresář/jmenovku svazku. Pokud file!=NULL, pak je do něj položka inicializována (lze číst, zapisovat, případně použít jako adresář pro hledání). Vrací FAT_OK, pokud nalezne další položku a FAT_EOF, pokud došel na konec adresáře

void FAT_Set_Find_Continue(tFile *dir,char *name);

umožní pokračovat v hledání, položka name je stejná, jako u FAT_Set_Find. Může být použito pouze jedno hledání zároveň a některé funkce (FAT_Delete_File) také hledání přerušují. Potom je hledání nutné obnovit, neboť je hledané jméno globální proměnná

int FAT_Create_File(tFile *dir,char *name,unsigned char attr,tFile *f);

vytvoří soubor se jménem name a atributy attr v adresáři dir, pokud neexistuje, (nebo nemá nulovou délku). Délku lze vynulovat pomocí fce FAT_Clear. Datum a čas vytvoření je určen globálními proměnnými NEW_FILE_DATE a NEW_FILE_TIME. Funkce testuje platnost použitých znaků

int FAT_Clear(tFile *f);

vynuluje délku souboru a uvolní použité místo

int FAT_Delete_File(tFile *f);

vymaže soubor, přerušuje případné hledání souborů

FAT_Close_File(tFile *f);

uzavře soubor – aktualizuje délku souboru, zapíše nezapsaná data

int FAT_Read(tFile *f,unsigned short length,unsigned char *buff); int FAT_Write(tFile *f,unsigned short length,unsigned char *buff);

přečte/zapíše length bytů z/do souboru. Pokud je buff==NULL, přenášejí se data přes výstupní kanál řadiče.

int FAT_Seek(tFile *f,unsigned long pos);

nastaví polohu v souboru na pozici pos. Pos je v intervalu<0;f->FileSize>. Od této pozice lze nadále zapisovat i číst

Datové typy (přehled užitečných vlastností:

tFAT: popis souborového systému

  • unsigned char FATType: typ FAT (například FAT_32)

  • unsigned long Clusters: celokvý pořet clusterů

  • unsigned long SecPerClus: počet sektorů/cluster

  • unsigned long FreeClus: počet volných clusterů, 0xffffffff = neznámo

tFile: popis souboru/adresáře

  • unsigned char attr: atributy

  • unsigned long Pos: aktuální pozice v souboru

  • unsigned long FileSize: velikost souboru (max. 2GB)

  • tFAT *fat: odkaz na FAT souboru

Konstanty atributů:

  • ATTR_READ_ONLY: pouze pro čtení

  • ATTR_HIDDEN: skrytý soubor

  • ATTR_SYSTEM: systémový soubor

  • ATTR_VOLUME_ID: identifikátor svazku, pouze v kořenovém adresáři

  • ATTR_DIRECTORY: adresář

  • ATTR_ARCHIVE: archivní soubor

  • ATTR_LONG_NAME: dlouhé jméno

5.3. Použití jednotek

Inicializace disku a 1. partition:

tFAT F;
tFile ADir;
char name[13];
void Init() {
term_send_str("Inicializace IDE");
IDE_HDD_Setup_Init();
while (IDE_HDD_Setup() == IDE_SETUP_WAIT) {
  WDG_reset();
  term_send_str(".");
}
term_send_crlf();
term_send_str("Disk: ");
switch (IDE_HDD[0].status) {
  case IDE_HDD_UNKNOWN:term_send_str("  Neidentifikovan!");break;
  case IDE_HDD_NONE:term_send_str("  Neni");break;
  case IDE_HDD_BAD:term_send_str("  Vadny!");break;
  case IDE_HDD_ATA:term_send_str("  ATA");break;
  case IDE_HDD_ATAPI:term_send_str("  ATAPI");break;
  case IDE_HDD_ATA+IDE_HDD_SMART:term_send_str("  ATA + SMART");break;
}
term_send_crlf();
if (IDE_HDD[0].status >= IDE_HDD_ATA) {
  term_send_str("  Velikost: ");
  term_send_num(IDE_HDD[0].sectors >> 11);
  term_send_str_crlf(" MB");
}
F.FATType = 0;
int cnt = 0;
if ((IDE_HDD[0].status & IDE_HDD_ATA) == IDE_HDD_ATA) {
  term_send_str_crlf("Disk: 0");
  if ((cnt = FAT_init_Part(0,NULL,NULL,0)) == FAT_ERR) {
    term_send_str_crlf("Chyba pri nacitani MBR");
    return;
  }
  term_send_str("Pocet aktivnich partition s FAT32: ");
  term_send_num(cnt);
  term_send_crlf();
}
if (cnt > 0) {
  if (FAT_init_Part(0,&F,name,0) == FAT_ERR) return;
  switch (F.FATType) {
    case FAT_32: term_send_str_crlf("FAT32");break;
    case FAT_16: term_send_str_crlf("FAT16");break;
    case FAT_12: term_send_str_crlf("FAT12");break;
  }
  term_send_str_crlf("Celkova velikost [kByte]: ");
  term_send_num(F.Clusters * F.SecPerClus / 2);
  term_send_crlf();
  if (F.FreeClus != 0xFFFFFFFF) {
    term_send_str(" Volne misto (posledni udaj): ");
    term_send_num(F.FreeClus * F.SecPerClus / 2);
    term_send_crlf();
  }
  if (name[0] != 0) {
    term_send_str_crlf("Jmeno oddilu: ");
    term_send_str_crlf(name);
  }
  return FAT_OK;
} else {
  term_send_str_crlf("Nenalezen zadny oddil FAT32 na discich!");
  return;
}
if (FAT_Root_Dir(&F,&ADir) != FAT_OK) return;
}

Výpis obsahu adresáře:

FAT_Set_Find(&ADir,NULL); // NULL = '*'
int status;
tFile file;
int packed=0; // =1 pro zkrácený výpis položek
while ((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) {
  if ((file.attr & ATTR_VOLUME_ID) == 0) { // jmeno svazku nevypisujeme
    term_send_str(name);term_send_char(' ');
    if (!packed) {
      int i;
      for (i = 12 - strlen(name);i > 0;i--) term_send_char(' ');
      if ((file.attr & ATTR_READ_ONLY) > 0) term_send_char('r');
      else term_send_char(' ');
      if ((file.attr & ATTR_HIDDEN) > 0) term_send_char('h');
      else term_send_char(' ');
      if ((file.attr & ATTR_ARCHIVE) > 0) term_send_char('a');
      else term_send_char(' ');
      if ((file.attr & ATTR_SYSTEM) > 0) term_send_char('s');
      else term_send_char(' ');
      if ((file.attr & ATTR_DIRECTORY) > 0) term_send_str("DIR");
      else term_send_num(file.FileSize);
      term_send_crlf();
    }
  }
}
initdir.png

Obrázek 5.1: Výstup výpisu inicializace a příkazu dir

Změna adresáře:

if ((name[0]== '/') || (name[0] == '\\')) { // skok do kořenového asdresáře
  if (FAT_Root_Dir(ADir.fat,&ADir) != FAT_OK)
    term_send_str_crlf("Nelze inicializovat RootDir!");
}
FAT_Set_Find(&ADir,name);
int status;
while (((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) &&
       (((file.attr & ATTR_DIRECTORY) == 0) ||
       ((file.attr & ATTR_VOLUME_ID) > 0))) WDG_reset();

if (status == FAT_ERR) term_send_str_crlf("Chyba pri hledani adresare!");

if (status == FAT_EOF)
{
   term_send_str_crlf("Adresar nenalezen!");
}
else
{
  memcpy(&ADir,&file,sizeof(tFile));
  if (ADir.StartClus == 0) FAT_Root_Dir(ADir.fat,&ADir);
}

Vypsání obsahu souboru:

FAT_Set_Find(&ADir,Fname);

int status;
char data[64];

while (((status = FAT_Find_Next(&ADir,name,NULL,NULL,&file)) == FAT_OK) &&
       ((file.attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) > 0)) WDG_reset();

if (status == FAT_ERR) term_send_str_crlf("Chyba pri hledani souboru!");

if (status == FAT_EOF) term_send_str_crlf("Soubor nenalezen!");

if (status == FAT_OK)
{
  while ((status = FAT_Read(&file,63,data)) > 0)
  {
    data[status] = 0;
    term_send_str(data);
  }
}
Zobrazeno: 1711x Naposledy: 23.9.2017 12:48:23