MODULE sdc; CONST Clock* = 20000; TYPE dbuf* = ARRAY 256 OF WORD; tdat* = RECORD n1, n2, n3, n4: WORD; (* Dateiname 8 bytes *) startc: WORD; (* Startcluster *) lh, ll: WORD; (* Laenge in Bytes *) END; VAR buf*: dbuf; Tick*: WORD; (* muss jede ms incrementiert werden *) fsl*, fsh*: WORD; (* Startadresse der FAT *) rsl*, rsh*: WORD; (* Startadresse des Root-Directory *) dsl*, dsh*: WORD; (* Startadresse des Datenbereichs *) spc*: WORD; (* Sektoren per Cluster *) PROCEDURE* Init; VAR i: WORD; BEGIN (* Ports konfigurieren: *) (* P6.7 fuer /CS als Output in OD *) ODP6 := ODP6 ORB 128; DP6 := DP6 ORB 128; P6 := P6 ORB 128; (* P3.9, P3.13 und P3.15 sind Output, ausser P3.15 OD, P3.8 ist Input *) ODP3 := ODP3 ORB $2200; DP3 := DP3 ORB $A200; P3 := P3 ORB $A200; (* SSC als Master mit Takt 400 kHz (fmax = 1 MHz mit dem Aufbau!) *) i := 7 + 16; (* je 8 Bits senden, MSB zuerst *) i := i + (64); (* schieben bei 1. Flanke, normhigh *) i := i + ($4000 + $8000); (* Master, enabled *) SSCCON := i; (* Baudrate 400 kBd bei 20-MHz-Takt (alle in kHz): *) SSCBR := Clock DIV (2 * 400) - 1; END Init; PROCEDURE* Wait; (* bis SSC-Transfer abgeschlossen ist *) VAR j: WORD; BEGIN REPEAT j := SSCRIC; j := j ANDB 128; (* SendeEnde *) UNTIL j # 0; SSCRIC := SSCRIC ANDB ($FFFF - 128); (* Flag löchen *) END Wait; PROCEDURE* EndCommand; VAR j: WORD; BEGIN P6 := P6 ORB 128; (* /CS := 1 *) (* 4 Dummireads nach AP16125 *) FOR j := 1 TO 4 DO SSCTB := $FF; Wait; END; END EndCommand; PROCEDURE* SendCommand(com, dath, datl, cs: WORD): WORD; VAR i, j: WORD; BEGIN (* /CS = P6.7 auf 0 *) FOR i := 1 TO 5 DO P6 := P6 ANDB ($FFFF - 128); END; SSCTB := com; Wait; i := dath; i := i DIV 256; SSCTB := i; Wait; i := dath; i := i MOD 256; SSCTB := i; Wait; i := datl; i := i DIV 256; SSCTB := i; Wait; i := datl; i := i MOD 256; SSCTB := i; Wait; SSCTB := cs; Wait; SSCTB := $FF; Wait; i := SSCRB; j := 8; WHILE (i = $FF) & (j > 0) DO SSCTB := $FF; Wait; i := SSCRB; DEC(j); END; RETURN i; (* /CS bleibt 0 fuer ev. Datenransfer *) END SendCommand; PROCEDURE* Open*: WORD; VAR i, ok, t: WORD; BEGIN ok := 0; (* 80 Einer senden, /CS = 1 *) FOR i := 0 TO 9 DO SSCTB := $FF; Wait; END; (* warte 10 ms nach AP16125 von Infineon*) t := Tick; t := t + 10; REPEAT UNTIL t = Tick; (* CMD0 *) t := Tick; t := t + 100; i := SendCommand($40, 0, 0, $95); EndCommand; WHILE (i # 1) & (Tick # t) DO i := SendCommand($40, 0, 0, $95); EndCommand; END; IF i = 1 THEN i := 0; ELSE i := i * 256; ok := 1 + i; END; (* CMD0 failed *) IF i = 0 THEN (* CMD1 *) t := Tick; t := t + 1000; i := 1; WHILE (i = 1) & (Tick # t) DO i := SendCommand($41, 0, 0, 1); EndCommand; END; IF i # 0 THEN i := i * 256; ok := i + 2; END; (* CMD1 failed *) END; (* Dies ist die zukunftsfeste Variante: IF i = 0 THEN (* ACMD41 *) t := Tick; t := t + 1000; i := 1; WHILE (i = 1) & (t # Tick) DO i := SendCommand($77, 0, 0, 0); (* CMD55 *) EndCommand; IF i = 1 THEN i := SendCommand($69, 0, 0, 0); (* CMD41 *) EndCommand; END; END; IF i # 0 THEN (* CMD1 *) t := Tick; t := t + 1000; i := 1; WHILE (i = 1) & (Tick # t) DO i := SendCommand($41, 0, 0, 1); EndCommand; END; IF i # 0 THEN i := i * 256; ok := i + 2; END; (* CMD1 failed *) END; END; *) (* Blockgroesse auf 512 Bytes setzen: *) IF i = 0 THEN (* CMD16 *) i := SendCommand($50, 0, $0200, 0); EndCommand; IF i # 0 THEN i := i * 256; ok := i + 3; END; (* CMD16 failed *) END; RETURN ok; END Open; PROCEDURE* Close*; VAR w: WORD; BEGIN FOR w := 1 TO 20 DO P6 := P6 ORB 128; END; (* /CS := 1, d.h. aus *) END Close; PROCEDURE* ReadBlock* (adrh, adrl: WORD): WORD; VAR i, j, w, ok: WORD; BEGIN ok := 0; i := SendCommand($51, adrh, adrl, 0); IF i = 0 THEN i := $FF; WHILE i = $FF DO (* Warte auf Data Token *) SSCTB := $FF; Wait; i := SSCRB; END; IF i = $FE THEN FOR j := 1 TO 256 DO (* Lese Block *) SSCTB := $FF; Wait; i := SSCRB; w := i; w := w * 256; SSCTB := $FF; Wait; i := SSCRB; w := w + i; buf[j] := w; END; FOR j := 1 TO 2 DO (* Checksum einlesen *) SSCTB := $FF; Wait; i := SSCRB; END; ELSE i := i * 256; ok := i + 2; (* kein Data Token #$FE *) END; ELSE i := i * 256; ok := i + 1; (* CMD17 failed *) END; EndCommand; RETURN ok; END ReadBlock; PROCEDURE* FindFat*: WORD; (* MBR ist bereits in buf *) VAR i, w, ok, ah, al, nfc, spf: WORD; BEGIN ok := 0; (* Typ der 1. Partition testen: *) w := buf[226]; w := w DIV 256; IF w = 6 THEN (* FAT16? *) (* Startsektor der 1. Partition auswerten: *) w := buf[228]; SWAP(w); al := w; w := buf[229]; SWAP(w); ah := w; FOR i := 1 TO 9 DO (* Startadresse des Bootsektors der 1. Partition berechnen: *) ah := ah * 2; w := al; IF (w ANDB $8000) # 0 THEN ah := ah + 1; END; al := al * 2; END; (* Bootsektor laden: *) i := ReadBlock(ah, al); IF i = 0 THEN (* Check Bytes per Sektor: *) w := buf[7]; w := w ANDB $FF00; i := buf[6]; i := i ANDB $00FF; w := w + i; IF w = 512 THEN w := buf[7]; w := w ANDB $00FF; spc := w; (* Sektoren/Cluster *) w := buf[8]; SWAP(w); (* Anzahl reservierter Sektoren *) w := w * 512; i := $FFFF - w; IF al > i THEN ah := ah +1; END; al := al + w; fsl := al; fsh := ah; (* Startadresse der FAT *) (* Anzahl an FATs *) nfc := buf[9]; nfc := nfc DIV 256; (* Sektoren / FAT *) spf := buf[12]; SWAP(spf); spf := spf * nfc; nfc := 0; (* Umrechnen in Bytes: *) FOR i := 1 TO 9 DO nfc := nfc * 2; w := spf; IF (w ANDB $8000) # 0 THEN nfc := nfc + 1; END; spf := spf * 2; END; (* HW in nfc, LW in spf *) i := $FFFF - spf; IF al > i THEN ah := ah + 1; END al := al + spf; ah := ah + nfc; rsl := al; rsh := ah; (* Startadresse des Root Dirs *) (* Rooteintraege zu 32 Byte: *) w := buf[10]; w := w ANDB $FF00; i := buf[9]; i := i ANDB $00FF; w := w + i; w := w * 32; i := $FFFF - w; IF al > i THEN ah := ah + 1; END; al := al + w; dsl := al; dsh := ah; (* Adresse 1. Cluster *) ELSE ok := 3; END; (* nicht 512 Bytes/Sektor *) ELSE ok := 2; END; (* Bootsektor konnte nocht gelesen werden *) ELSE ok := 1; (* kein FAT16 *) END; RETURN ok; END FindFat; PROCEDURE* FindDat*(VAR d: tdat): WORD; VAR rh, rl, i, n, m, b, e: WORD; BEGIN rh := rsh; rl := rsl; i := 1; e := 0; m := 0; b:= 1; REPEAT m := ReadBlock(rh, rl); IF b = 1 THEN i := i + 16; (* Dir-Eintrag ueberlesen *) ELSE i := 1; END; IF m = 0 THEN IF ODD(b) THEN i := i + 16; END; (* VFAT-Eintrag ueberlesen *) REPEAT n := buf[i]; IF n # 0 THEN IF (d.n1 = n) THEN n := buf[1 + i]; IF (d.n2 = n) THEN n := buf[2 + i]; IF (d.n3 = n) THEN n := buf[3 + i]; IF (d.n4 = n) THEN e := 1; (* found *) END; END; END; END; IF i < 224 THEN i := i + 32; ELSE e := 3; END; (* end of sector *) ELSE e := 2; m := 2; END; (* end of entries *) UNTIL e # 0; IF e = 1 THEN i := i - 32; n := buf[13 + i]; SWAP(n); d.startc := n; n := buf[14 + i]; SWAP(n); d.ll := n; n := buf[15 + i]; SWAP(n); d.lh := n; ELSE IF n # 0 THEN e := 0; IF rl > ($FFFF - 512) THEN rh := rh + 1; END; rl := rl + 512; b := b + 1; IF (rh > dsh) THEN n := 0; m := 1; e := 5;END; IF (rh = dsh) & (rl >= dsl) THEN n := 0; m := 1; (* Ende des Root-Dirs *) e := 5; END; ELSE e := 2; m := 2; (* end of entries *) END; END; ELSE e := 4; m := 4; END; (* ReadBlock failed *) UNTIL e # 0; RETURN m; END FindDat; BEGIN Tick := 0; Init; END sdc.