// Lesen einer Datei von 64MB MMC-Speicher unter FAT16
// Seriel (9600,n,8,1) bei  20MHz
//
// Michael Dworkin
// 04.12.2003
// Compiler CC5x

#include <D:\cc5\16F877.H>
#pragma config |= 0b.11.111101.11.00.10
#pragma bit CS @ PORTC.2 //Ausgang für Chip Select

uns16 AL, BytN,ByteLes,Claster,FAT,Verz,Dat;        // algemeine Variablen
char AH ;

#pragma origin 100

//******************************************************************************
void InitUSART()
{
    BRGH=1;
    SPBRG=129;  // (9600 baud @ 20MHz input clock)
    SPEN = 1;       // Set_Serial_Pins;
    SYNC = 0;       // Set_Async_Mode;
    TX9 = 0;        // Set_8bit_Tx;
    RX9 = 0;        // Set_8bit_Rx;
    CREN = 1;       // Enable_Rx;
    TXEN = 1;       // Enable_Tx;
    RCIE=0;         // Rx Interrupt aus
}

//**************************************************************************
void SerString(const char *str) //Ein String seriell senden
{
    char ps;
    ps = *str;      // Pointer auf start des Strings ins ps
    while(ps>0)     // Pruefen ob String zu ende ist
    {
        str++;              // Pointer auf nexte Zeihen erhoehen
        if (ps== 0) break;  // Pruefen ob String zu ende ist
        while(!TXIF);       // Pruefen ob register TXREG leher ist
        TXREG =ps ;         // Datenbyte senden
        ps = *str;          // Inhalt des ponters ins ps
    }
}

//*****************************************************************************
char SPI(char d)        // Ueber SPI-Schnittstelle
{                       // senden
    SSPBUF=d;
    while (!BF);            //  Warten bis gesendet ist
    return SSPBUF;          // gleichzeitig empfangen
}

//******************************************************************************
char Command(char befF,uns16 AdrH,uns16 AdrL,char befH )
{                       // Ein Befehl zum MMC senden
    char a;
    for (a=0;a<9;a++)
    {
        Carry=0;
        AdrL = rl(AdrL);
        AdrH = rl(AdrH);
    }
    SPI(0xFF);
    SPI(befF);
    SPI(AdrH.high8);
    SPI(AdrH.low8);
    SPI(AdrL.high8);
    SPI(AdrL.low8);
    SPI(befH);
    SPI(0xFF);
    return SPI(0xFF);       // Response als Rueckgabewert
}

//****************************************************************************
bit MMC_Init()
{
    SMP=0;      // Input ist gueltig in der Mitte des Clock
    CKE=0;      // CKE=1;   // Fordere Flanke (steigende)
    CKP=1;      // CKP=0;   // Low ist Passiwe Zustand
    SSPM0=1;
    SSPEN=1;    // SPI Ein
    CS=1;       // MMC-Disabled
    char i;     // Variablen
    for(i=0; i < 10; i++)SPI(0xFF);
    CS=0;
    if (Command(0x40,0,0,0x95) !=1)goto Fehler ;
    st:
    if (Command(0x41,0,0,0xFF) !=0) goto st ;
    return 1;
    Fehler:
    return 0;
}

//***********************************************************************************
void Byte_lesen (void)
{
    bit zw;
    char a;
    int16 i;
    zw=0;
    Command(0x51,AH,AL,0xFF);
    while(SPI(0xFF) != 0xFE);       // Warten auf 0xFE,anfang jeder Datenuebertragung
    for(i=0; i < 512; i++)
    {
        a=SPI(0xFF);
        if (zw)
        {
            ByteLes.high8=a;
            zw=0;
        }
        if (i==BytN)
        {
            ByteLes.low8=a;
            zw=1;
        }

    }
    SPI(0xFF);                      // Am ende 2 Byte's ohne Bedeutung
    SPI(0xFF);
}

//******************************************************************************
void Suche(const char *wort)
{
    uns16 i,L,N;
    bit gef;
    char a,m,b;
    gef=0;
    m=0;
    N=Verz+32;          // Ende des Verzeichnisbereiches.
    for (L=Verz;L<N;L++)
    {
        Command(0x51,0,L,0xFF);
        while(SPI(0xFF) != 0xFE);
        for(i=0; i < 512; i++)
        {
            a=SPI(0xFF) ;
            b=wort[m];
            if(a==b)
            {
                m++;
                if(!wort[m])
                {
                    SerString("Gefunden ");
                    m=0;
                    BytN=i;
                    AL=L;
                    AH=0;
                    gef=1;
                }
                goto fu;
            }

            m=0;
            fu:
        }
        SPI(0xFF);                      // Am ende 2 Byte's ohne Bedeutung
        SPI(0xFF);
        if(gef) goto raus;
    }
    raus:
    SerString("Beendet ");
    BytN+=16;
    Byte_lesen();
}

//*******************************************************************************
void Lesen(char H,uns16 L)
{
    uns16 i;

    // Lesen  512 Byte-mode
    if (Command(0x51,H,L,0xFF) !=0) SerString("Lese_resp_Fehler");
    while(SPI(0xFF) != 0xFE);       // Warten auf 0xFE,anfang jeder Datenuebertragung
    for(i=0; i < 512; i++)
    {
        while(!TXIF);               // Pruefen ob register TXREG leher ist
        TXREG =SPI(0xFF);           // Datenbyte senden
    }
    SPI(0xFF);                      // Am ende 2 Byte's ohne Bedeutung
    SPI(0xFF);
}

//*********************************************************************************

void main(void)
{
    uns16 temp;
    INTCON=0;               // Interrupts aus
    ADCON1=0x6;             // PortA Digital
    TRISC=0b.1101.0011;     // sck rc3-0, sdo rc5-0, CS rc2-0.
    TRISB=0b.0000.0010;     // RB2>TX, RB1<RX
    InitUSART();            // 1 Serielle Datenuebertragung Initialisieren
    //SerString("Ich bin ON ");                 // Startmeldung
    MMC_Init();             // 2

    // Ermitteln von Anfang jedes Bereiches
    AL=0;                   // 3
    AH=0;
    BytN=0x1C6;
    Byte_lesen();
    AL=ByteLes;             // 4
    BytN=0xE;               // 5
    Byte_lesen();
    FAT=ByteLes+AL;         // 6
    BytN=0x16;              // 7
    Byte_lesen();
    ByteLes=ByteLes*2;
    Verz=FAT+ByteLes;       // 8
    Dat=Verz+32;            // 9, 10


    Suche("TEST    TXT");   // 11

    while(ByteLes != 0xFFFF)// 12, 25
    {
        Claster=ByteLes;        // 13
        Claster=Claster-2;      // 14
        AL=Claster;             // 15
        Carry=0;                // 16  Hier werden Grenzen der wariable berücksichtigt
        AL = rl(AL);            // Multiplizieren mit 2 mit Eubertrag
        AH = rl(AH);


        #asm                    // 17
        MOVF  Dat+1,W
        ADDWF AL+1,1
        MOVF  Dat,W
        ADDWF AL,1
        BTFSS 0x03,Carry
        GOTO  keinCarry
        BCF   0x03,Carry
        INCF  AL+1,1
        BTFSC 0x03,Carry
        INCF  AH,1
        keinCarry:
        #endasm

        Lesen(AH,AL);           // 18 Erste Block des Clasters
        Carry=0;                // 19
        AL++;
        if(Carry)AH++;          // Hier werden Grenzen der wariable berücksichtigt
        Lesen(AH,AL);           // 20 Zweite Block des Clasters

        AL=FAT;                 // 21 nexte Claster
        temp=ByteLes/0x100;
        AL=AL+temp;             // 22
        temp=temp*0x100;        // 23
        BytN=ByteLes-temp;
        BytN=BytN*2;
        Byte_lesen();           // 24
    }

    while(1);
}