From 4a0740dd02d8698a9a6b980cdc079ad6ade26cb6 Mon Sep 17 00:00:00 2001 From: David Voswinkel Date: Sun, 9 Aug 2009 14:19:32 +0200 Subject: [PATCH] replace mmc layer with old software spi stuff --- avr/usbload/fat.c | 1216 ++++++++++++++++++++--------------------- avr/usbload/fat.h | 0 avr/usbload/file.c | 0 avr/usbload/file.h | 0 avr/usbload/mmc.c | 497 ++++++++--------- avr/usbload/mmc.h | 88 +-- avr/usbload/testing.c | 35 +- 7 files changed, 879 insertions(+), 957 deletions(-) mode change 100755 => 100644 avr/usbload/fat.c mode change 100755 => 100644 avr/usbload/fat.h mode change 100755 => 100644 avr/usbload/file.c mode change 100755 => 100644 avr/usbload/file.h mode change 100755 => 100644 avr/usbload/mmc.c mode change 100755 => 100644 avr/usbload/mmc.h diff --git a/avr/usbload/fat.c b/avr/usbload/fat.c old mode 100755 new mode 100644 index a1defdf..cc0fa2c --- a/avr/usbload/fat.c +++ b/avr/usbload/fat.c @@ -1,608 +1,608 @@ - -#include -#include - -#include "fat.h" -#include "file.h" -#include "hardware.h" - -struct Fat fat; // wichtige daten/variablen der fat -struct File file; // wichtige dateibezogene daten/variablen - - -#if (WRITE==1) - -//*************************************************************************************************************** -// schreibt sektor nummer:sec auf die karte (puffer:sector) !! -// setzt bufferFlag=0 da puffer nicht dirty sein kann nach schreiben ! -//*************************************************************************************************************** -unsigned char fat_writeSector(unsigned long int sec){ - - fat.bufferDirty=0; // buffer kann nicht dirty sein weil wird geschrieben - return(mmc_write_sector(sec,fat.sector)); // schreiben von sektor puffer -} - -#endif - - -// *************************************************************************************************************** -// umrechnung cluster auf 1.sektor des clusters (möglicherweise mehrere sektoren/cluster) ! -// *************************************************************************************************************** -unsigned long int fat_clustToSec(unsigned long int clust){ - - return (fat.dataDirSec+2+((clust-2) * fat.secPerClust)); // errechnet den 1. sektor der sektoren des clusters -} - -// *************************************************************************************************************** -// umrechnung sektor auf cluster (nicht die position im cluster selber!!) -// *************************************************************************************************************** -unsigned long int fat_secToClust(unsigned long int sec){ - - return ((sec-fat.dataDirSec-2+2*fat.secPerClust)/fat.secPerClust); // umkerhrfunktion von fat_clustToSec -} - - -//*************************************************************************************************************** -// läd sektor:sec auf puffer:sector zum bearbeiten im ram ! -// setzt currentSectorNr auf richtigen wert (also den sektor der gepuffert ist). es wird geprüft -// ob der gepufferte sektor geändert wurde, wenn ja muss erst geschrieben werden, um diese daten nicht zu verlieren ! -//*************************************************************************************************************** -unsigned char fat_loadSector(unsigned long int sec){ - - if(sec!=fat.currentSectorNr){ // nachladen nötig - #if (WRITE==1) - if(fat.bufferDirty==1) fat_writeSector(fat.currentSectorNr); // puffer diry, also vorher schreiben - #endif - mmc_read_sector(sec,fat.sector); // neuen sektor laden - fat.currentSectorNr=sec; // aktualisiert sektor nummer (nummer des gepufferten sektors) - return(0); - } - - else return(0); // alles ok, daten sind schon da (sec==fat.currentSectorNr) - - return(1); // fehler -} - - - - - - - -// datei lesen funktionen: - -// fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir -> fat_loadFileDataFromDir -> fat_cd "daten chain" - -//*************************************************************************************************************** -// läd die reihe:row des gepufferten sektors auf das struct:file. dort stehen dann -// alle wichgigen daten wie: 1.cluster,länge bei dateien, name des eintrags, reihen nummer (im sektor), attribut use... -//*************************************************************************************************************** -unsigned char fat_loadRowOfSector(unsigned int row){ - - unsigned char i; - row=row<<5; // multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 usw). - - void *vsector; // void, damit man schoen umbiegen kann :) - - for(i=0;i<11;i++) - file.name[i]=fat.sector[row+i]; // datei name, ersten 10 bytes vom 32 byte eintrag. - - file.attrib=fat.sector[row+11]; // datei attribut, byte 11. - - vsector=&fat.sector[row+26]; // low word von fist.cluster - file.firstCluster=*(unsigned short*)vsector; - - vsector=&fat.sector[row+20]; // high word von first.cluster - file.firstCluster|=(*(unsigned short*)vsector)<<16; - - vsector=&fat.sector[row+28]; // 4 byte von file.length - file.length=*(unsigned long int*)vsector; - - return(0); -} - - -//*************************************************************************************************************** -// geht reihen weise durch sektoren des clusters mit dem startsektor:sec, und sucht nach der datei mit dem -// namen:name. es werden die einzelnen sektoren nachgeladen auf puffer:sector vor dem bearbeiten. -// wird die datei in dem cluster gefunden ist return 0 , sonst return1. -//*************************************************************************************************************** -unsigned char fat_loadFileDataFromCluster(unsigned long int sec , char name[]){ - - unsigned char r; - unsigned char s=0; - - do{ // sektoren des clusters prüfen - r=0; // neuer sektor, dann reihen von 0 an. - mmc_read_sector(sec+s,fat.sector); // läd den sektor sec auf den puffer fat.sector - fat.currentSectorNr=sec+s; // setzen des aktuellen sektors - do{ // reihen des sektors prüfen - fat_loadRowOfSector(r); // zeile 0-15 auf struct file laden - if(file.name[0]==0){ // wenn man auf erste 0 stößt müsste der rest auch leer sein! - file.row=r; // zeile sichern. - return(1); - } - if(0==strncmp((char*)file.name,name,10)){ // zeile r ist gesuchte - file.row=r; // zeile sichern. - return(0); - } - r++; - }while(r<16); // zählt zeilennummer (16(zeilen) * 32(spalten) == 512 bytes des sektors) - s++; - }while(s neuer cluster nötig. - - dir=fat_secToClust(fat.startSectors); // dir ist jetzt neuer cluster zum verketten ! - fat_setCluster(start,dir); // cluster-chain mit neuem cluster verketten - fat_setCluster(dir,0x0fffffff); // cluster-chain ende markieren - - //es muessen neue gesucht werden, weil der bekannte aus file.c ja grade verkettet wurden. datei eintrag passte nicht mehr ins dir... - fat_getFreeClustersInRow(2); // neue freie cluster suchen, für datei. - file.firstCluster=fat_secToClust(fat.startSectors); // 1. cluster der datei - file.lastCluster=fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei - - fat.currentSectorNr=fat_clustToSec(dir); // setzen des richtigen sektors, also auf den 1. der neu verketteten - - unsigned int j=511; - do{ - fat.sector[j]=0x00; //schreibt puffer fat.sector voll mit 0x00==leer - }while(j--); - - unsigned char i=1; // ab 1 weil der 1.sektor des clusters eh noch beschrieben wird... - do{ - fat_writeSector(fat.currentSectorNr+i); // löschen des cluster (überschreibt mit 0x00), wichtig bei ffls, - i++; - }while(i>16;// low word von cluster - - vsector=&fat.sector[row+22]; - *(unsigned long int*)vsector=0x01010101; // unnoetige felder beschreiben - - vsector=&fat.sector[row+26]; - *(unsigned short*)vsector=(cluster&0x0000ffff); // high word von cluster - - vsector=&fat.sector[row+28]; - *(unsigned long int*)vsector=length; // laenge -} - - -//*************************************************************************************************************** -// macht den datei eintrag im jetzigen verzeichniss (fat.dir). -// file.row enthält die reihen nummer des leeren eintrags, der vorher gesucht wurde, auf puffer:sector ist der gewünschte -// sektor gepuffert. für fat16 im root dir muss andere funktion genutzt werden, als fat_getFreeRowOfDir (durchsucht nur dirs). -// fat.rootDir enthält bei fat32 den start cluster des directory, bei fat16 den 1. sektor des rootDir bereichs! -//*************************************************************************************************************** -void fat_makeFileEntry(char name[],unsigned char attrib,unsigned long int length){ - - unsigned int s; // zähler für root dir sektoren fat16 - - if(fat.dir==0&&fat.fatType==32)fat_getFreeRowOfDir(fat.rootDir); // IM ROOT DIR (fat32) - - else if(fat.dir==0 && fat.fatType==16){ // IM ROOT DIR (fat16) - for(s=0;s<(unsigned int)(fat.dataDirSec+2-fat.rootDir);s++){ // zählt durch RootDir sektoren (errechnet anzahl rootDir sektoren). - if(0==fat_getFreeRowOfCluster(fat.rootDir+s))break; // geht durch sektoren des root dir. - } - } - - else fat_getFreeRowOfDir(fat.dir); // NICHT ROOT DIR fat32/fat16 - - fat_makeRowDataEntry(file.row,name,attrib,file.firstCluster,length); // schreibt file eintrag auf puffer - fat_writeSector(fat.currentSectorNr); // schreibt puffer auf karte -} - -#endif - - - - - -// fat funktionen: - -//*************************************************************************************************************** -// sucht nötige folge Cluster aus der fat ! -// erster daten cluster = 2, ende einer cluster chain 0xFFFF (fat16) oder 0xFFFFFFF, 0xFFFFFF8 (fat32), -// stelle des clusters in der fat, hat als wert, den nächsten cluster. (1:1 gemapt)! -//*************************************************************************************************************** -unsigned long int fat_getNextCluster(unsigned long int oneCluster){ - - // FAT 16**************FAT 16 - if(fat.fatType==16){ - unsigned long int i=oneCluster>>8;; // (i=oneCluster/256)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) - unsigned long int j=(oneCluster<<1)-(i<<9); // (j=(oneCluster-256*i)*2 == 2*oneCluster-512*i)errechnet das low byte von oneCluster - - if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig, wird von fat_loadSector geprüft - void *bytesOfSec=&fat.sector[j]; // zeiger auf puffer - return *(unsigned short*)bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :) - } - } - - // FAT 32**************FAT 32 - else{ - unsigned long int i=oneCluster>>7; // (i=oneCluster/128)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) - unsigned long int j=(oneCluster<<2)-(i<<9); // (j=(oneCluster-128*i)*4 == oneCluster*4-512*i)errechnet das low byte von oneCluster - - if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig wird von fat_loadSector geprüft - void *bytesOfSec=&fat.sector[j]; // zeiger auf puffer - return *(unsigned long int*)bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :) - } - } - - return(0); -} - - -//*************************************************************************************************************** -// sucht verkettete cluster einer datei, die in einer reihe liegen. worst case: nur ein cluster. -// sieht in der fat ab dem cluster offsetCluster nach. sucht die anzahl von MAX_CLUSTERS_IN_ROW, -// am stück,falls möglich. prüft ob der cluster neben offsetCluster dazu gehört... -// setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren -//*************************************************************************************************************** -void fat_getFatChainClustersInRow(unsigned long int offsetCluster){ - - unsigned int i=0; - fat.startSectors=fat_clustToSec(offsetCluster); // setzen des 1. sektors der datei - fat.endSectors=fat.startSectors; - do{ - if( (offsetCluster+1+i)==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust; // zählen der zusammenhängenden sektoren - else { - file.lastCluster=offsetCluster+i; // cluster daneben gehört nicht dazu, somit ist offset+i der letzte bekannte - break; - } - }while(i++>8; // (i=cluster/256)errechnet den sektor der fat in dem cluster ist (rundet immer ab) - unsigned long int j=(cluster<<1)-(i<<9); // (j=(cluster-256*i)*2 == 2*cluster-512*i)errechnet das low byte von cluster - - if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) - void *bytesOfSec=&fat.sector[j]; // init des zeigers auf unterste adresse - *(unsigned short*)bytesOfSec=content;// weil ram auch little endian geht das so :) - fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde - } - } - - // FAT 32**************FAT 32 - else{ - unsigned long int i=cluster>>7; // (i=cluster/128)errechnet den sektor der fat in dem cluster ist (rundet immer ab) - unsigned long int j=(cluster<<2)-(i<<9); //(j=(cluster-128*i)*4 == cluster*4-512*i)errechnet das low byte von cluster - - if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) - void *bytesOfSec=&fat.sector[j]; // init des zeigers auf unterste adresse - *(unsigned long int*)bytesOfSec=content; // weil ram auch little endian geht das so :) - fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde - } - } -} - - -//*************************************************************************************************************** -// löscht cluster chain, beginnend ab dem startCluster. -// sucht cluster, setzt inhalt usw.. abschließend noch den cluster-chain ende markierten cluster löschen. -//*************************************************************************************************************** -void fat_delClusterChain(unsigned long int startCluster){ - - unsigned long int nextCluster=startCluster; // tmp variable, wegen verketteter cluster.. - - do{ - startCluster=nextCluster; - nextCluster=fat_getNextCluster(startCluster); - fat_setCluster(startCluster,0x00000000); - }while(!((nextCluster==0xfffffff&&fat.fatType==32)||(nextCluster==0xffff&&fat.fatType==16))); - fat_writeSector(fat.currentSectorNr); -} - -#endif - - -//*************************************************************************************************************** -// Initialisiert die Fat(16/32) daten, wie: root directory sektor, daten sektor, fat sektor... -// siehe auch Fatgen103.pdf. ist NICHT auf performance optimiert! -// byte/sector, byte/cluster, anzahl der fats, sector/fat ... (halt alle wichtigen daten zum lesen ders datei systems!) -//*****************************************************************<********************************************** -unsigned char fat_loadFatData(unsigned long int sec){ - - // offset,size - unsigned int rootEntCnt; // 17,2 größe die eine fat belegt - unsigned int fatSz16; // 22,2 sectors occupied by one fat16 - unsigned long int fatSz32; // 36,4 sectors occupied by one fat32 - - void *vsector; - - if(0==mmc_read_sector(sec,fat.sector)){ // lesen von fat sector und bestimmen der wichtigen berreiche - - fat.bufferDirty = 0; // init wert des flags - - fat.secPerClust=fat.sector[13]; // fat.secPerClust, 13 only (power of 2) - - vsector=&fat.sector[14]; - fat.fatSec=*(unsigned short*)vsector; - - vsector=&fat.sector[17]; - rootEntCnt=*(unsigned short*)vsector; - - vsector=&fat.sector[22]; - fatSz16=*(unsigned short*)vsector; - - fat.rootDir = (((rootEntCnt <<5) + 512) /512)-1; // ist 0 bei fat 32, sonst der root dir sektor - - if(fat.rootDir==0){ // FAT32 spezifisch (die prüfung so, ist nicht spezifikation konform !). - - vsector=&fat.sector[36]; - fatSz32=*(unsigned long int *)vsector; - - vsector=&fat.sector[44]; - fat.rootDir=*(unsigned long int *)vsector; - - fat.dataDirSec = fat.fatSec + (fatSz32 * fat.sector[16]); // data sector (beginnt mit cluster 2) - fat.fatType=32; // fat typ - } - - else{ // FAT16 spezifisch - fat.dataDirSec = fat.fatSec + (fatSz16 * fat.sector[16]) + fat.rootDir; // data sektor (beginnt mit cluster 2) - fat.rootDir=fat.dataDirSec-fat.rootDir; // root dir sektor, da nicht im datenbereich (cluster) - fat.rootDir+=sec; // addiert den startsektor auf " - fat.fatType=16; // fat typ - } - - fat.fatSec+=sec; // addiert den startsektor auf - fat.dataDirSec+=sec; // addiert den startsektor auf (umrechnung von absolut auf real) - fat.dataDirSec-=2; // zeigt auf 1. cluster - fat.dir=0; // dir auf '0'==root dir, sonst 1.Cluster des dir - return (0); - } - - - return (1); // sector nicht gelesen, fat nicht initialisiert!! -} - - -//************************************************************************************************<<*************** -// int fat sucht den 1. cluster des dateisystems (fat16/32) auch VBR genannt, -//************************************************************************************************<<*************** -unsigned char fat_initfat(void){ - - unsigned long int secOfFirstPartition=0; // ist 1. sektor der 1. partition aus dem MBR - - if(0==mmc_read_sector(0,fat.sector)){ - - void *vsector=&fat.sector[454]; //startsektor bestimmen - secOfFirstPartition=*(unsigned long int*)vsector; - - //prüfung ob man schon im VBR gelesen hat (0x6964654d = "Medi") - if(secOfFirstPartition==0x6964654d) return fat_loadFatData(0); //ist superfloppy - - else {return fat_loadFatData(secOfFirstPartition);} // ist partitioniert... - } - - return (1); -} - - -#if (SMALL_FILE_SYSTEM==0) - -// ***************************************************************************************************************** -// bereitet str so auf, dass man es auf die mmc/sd karte schreiben kann. -// wandelt z.b. "t.txt" -> "T TXT" oder "main.c" in "MAIN C " => also immer 8.3 und upper case letter -// VORSICHT es werden keine Prüfungen gemacht ! -// ***************************************************************************************************************** -char * fat_str(char *str){ - - unsigned char i; - unsigned char j=0; - unsigned char c; - char tmp[12]; // tmp string zum einfacheren umwandeln - - strcpy(tmp,str); - - for(i=0;i<11;i++)str[i]=' '; // als vorbereitung alles mit leerzeichen füllen - str[11]='\0'; - - i=0; - - do{ - c=toupper(tmp[j]); - if(c=='\0')return str; - if(c!='.')str[i]=c; - else i=7; - i++; - j++; - }while(i<12); - - return str; - -} - -#endif - + +#include +#include + +#include "fat.h" +#include "file.h" +#include "hardware.h" + +struct Fat fat; // wichtige daten/variablen der fat +struct File file; // wichtige dateibezogene daten/variablen + + +#if (WRITE==1) + +//*************************************************************************************************************** +// schreibt sektor nummer:sec auf die karte (puffer:sector) !! +// setzt bufferFlag=0 da puffer nicht dirty sein kann nach schreiben ! +//*************************************************************************************************************** +unsigned char fat_writeSector(unsigned long int sec){ + + fat.bufferDirty=0; // buffer kann nicht dirty sein weil wird geschrieben + return(mmc_write_sector(sec,fat.sector)); // schreiben von sektor puffer +} + +#endif + + +// *************************************************************************************************************** +// umrechnung cluster auf 1.sektor des clusters (möglicherweise mehrere sektoren/cluster) ! +// *************************************************************************************************************** +unsigned long int fat_clustToSec(unsigned long int clust){ + + return (fat.dataDirSec+2+((clust-2) * fat.secPerClust)); // errechnet den 1. sektor der sektoren des clusters +} + +// *************************************************************************************************************** +// umrechnung sektor auf cluster (nicht die position im cluster selber!!) +// *************************************************************************************************************** +unsigned long int fat_secToClust(unsigned long int sec){ + + return ((sec-fat.dataDirSec-2+2*fat.secPerClust)/fat.secPerClust); // umkerhrfunktion von fat_clustToSec +} + + +//*************************************************************************************************************** +// läd sektor:sec auf puffer:sector zum bearbeiten im ram ! +// setzt currentSectorNr auf richtigen wert (also den sektor der gepuffert ist). es wird geprüft +// ob der gepufferte sektor geändert wurde, wenn ja muss erst geschrieben werden, um diese daten nicht zu verlieren ! +//*************************************************************************************************************** +unsigned char fat_loadSector(unsigned long int sec){ + + if(sec!=fat.currentSectorNr){ // nachladen nötig + #if (WRITE==1) + if(fat.bufferDirty==1) fat_writeSector(fat.currentSectorNr); // puffer diry, also vorher schreiben + #endif + mmc_read_sector(sec,fat.sector); // neuen sektor laden + fat.currentSectorNr=sec; // aktualisiert sektor nummer (nummer des gepufferten sektors) + return(0); + } + + else return(0); // alles ok, daten sind schon da (sec==fat.currentSectorNr) + + return(1); // fehler +} + + + + + + + +// datei lesen funktionen: + +// fat_loadSector -> fat_loadRowOfSector -> fat_loadFileDataFromCluster -> fat_loadFileDataFromDir -> fat_loadFileDataFromDir -> fat_cd "daten chain" + +//*************************************************************************************************************** +// läd die reihe:row des gepufferten sektors auf das struct:file. dort stehen dann +// alle wichgigen daten wie: 1.cluster,länge bei dateien, name des eintrags, reihen nummer (im sektor), attribut use... +//*************************************************************************************************************** +unsigned char fat_loadRowOfSector(unsigned int row){ + + unsigned char i; + row=row<<5; // multipliziert mit 32 um immer auf zeilen anfang zu kommen (zeile 0=0,zeile 1=32,zeile 2=62 usw). + + void *vsector; // void, damit man schoen umbiegen kann :) + + for(i=0;i<11;i++) + file.name[i]=fat.sector[row+i]; // datei name, ersten 10 bytes vom 32 byte eintrag. + + file.attrib=fat.sector[row+11]; // datei attribut, byte 11. + + vsector=&fat.sector[row+26]; // low word von fist.cluster + file.firstCluster=*(unsigned short*)vsector; + + vsector=&fat.sector[row+20]; // high word von first.cluster + file.firstCluster|=(*(unsigned short*)vsector)<<16; + + vsector=&fat.sector[row+28]; // 4 byte von file.length + file.length=*(unsigned long int*)vsector; + + return(0); +} + + +//*************************************************************************************************************** +// geht reihen weise durch sektoren des clusters mit dem startsektor:sec, und sucht nach der datei mit dem +// namen:name. es werden die einzelnen sektoren nachgeladen auf puffer:sector vor dem bearbeiten. +// wird die datei in dem cluster gefunden ist return 0 , sonst return1. +//*************************************************************************************************************** +unsigned char fat_loadFileDataFromCluster(unsigned long int sec , char name[]){ + + unsigned char r; + unsigned char s=0; + + do{ // sektoren des clusters prüfen + r=0; // neuer sektor, dann reihen von 0 an. + mmc_read_sector(sec+s,fat.sector); // läd den sektor sec auf den puffer fat.sector + fat.currentSectorNr=sec+s; // setzen des aktuellen sektors + do{ // reihen des sektors prüfen + fat_loadRowOfSector(r); // zeile 0-15 auf struct file laden + if(file.name[0]==0){ // wenn man auf erste 0 stößt müsste der rest auch leer sein! + file.row=r; // zeile sichern. + return(1); + } + if(0==strncmp((char*)file.name,name,10)){ // zeile r ist gesuchte + file.row=r; // zeile sichern. + return(0); + } + r++; + }while(r<16); // zählt zeilennummer (16(zeilen) * 32(spalten) == 512 bytes des sektors) + s++; + }while(s neuer cluster nötig. + + dir=fat_secToClust(fat.startSectors); // dir ist jetzt neuer cluster zum verketten ! + fat_setCluster(start,dir); // cluster-chain mit neuem cluster verketten + fat_setCluster(dir,0x0fffffff); // cluster-chain ende markieren + + //es muessen neue gesucht werden, weil der bekannte aus file.c ja grade verkettet wurden. datei eintrag passte nicht mehr ins dir... + fat_getFreeClustersInRow(2); // neue freie cluster suchen, für datei. + file.firstCluster=fat_secToClust(fat.startSectors); // 1. cluster der datei + file.lastCluster=fat_secToClust(fat.endSectors); // letzter bekannter cluster der datei + + fat.currentSectorNr=fat_clustToSec(dir); // setzen des richtigen sektors, also auf den 1. der neu verketteten + + unsigned int j=511; + do{ + fat.sector[j]=0x00; //schreibt puffer fat.sector voll mit 0x00==leer + }while(j--); + + unsigned char i=1; // ab 1 weil der 1.sektor des clusters eh noch beschrieben wird... + do{ + fat_writeSector(fat.currentSectorNr+i); // löschen des cluster (überschreibt mit 0x00), wichtig bei ffls, + i++; + }while(i>16;// low word von cluster + + vsector=&fat.sector[row+22]; + *(unsigned long int*)vsector=0x01010101; // unnoetige felder beschreiben + + vsector=&fat.sector[row+26]; + *(unsigned short*)vsector=(cluster&0x0000ffff); // high word von cluster + + vsector=&fat.sector[row+28]; + *(unsigned long int*)vsector=length; // laenge +} + + +//*************************************************************************************************************** +// macht den datei eintrag im jetzigen verzeichniss (fat.dir). +// file.row enthält die reihen nummer des leeren eintrags, der vorher gesucht wurde, auf puffer:sector ist der gewünschte +// sektor gepuffert. für fat16 im root dir muss andere funktion genutzt werden, als fat_getFreeRowOfDir (durchsucht nur dirs). +// fat.rootDir enthält bei fat32 den start cluster des directory, bei fat16 den 1. sektor des rootDir bereichs! +//*************************************************************************************************************** +void fat_makeFileEntry(char name[],unsigned char attrib,unsigned long int length){ + + unsigned int s; // zähler für root dir sektoren fat16 + + if(fat.dir==0&&fat.fatType==32)fat_getFreeRowOfDir(fat.rootDir); // IM ROOT DIR (fat32) + + else if(fat.dir==0 && fat.fatType==16){ // IM ROOT DIR (fat16) + for(s=0;s<(unsigned int)(fat.dataDirSec+2-fat.rootDir);s++){ // zählt durch RootDir sektoren (errechnet anzahl rootDir sektoren). + if(0==fat_getFreeRowOfCluster(fat.rootDir+s))break; // geht durch sektoren des root dir. + } + } + + else fat_getFreeRowOfDir(fat.dir); // NICHT ROOT DIR fat32/fat16 + + fat_makeRowDataEntry(file.row,name,attrib,file.firstCluster,length); // schreibt file eintrag auf puffer + fat_writeSector(fat.currentSectorNr); // schreibt puffer auf karte +} + +#endif + + + + + +// fat funktionen: + +//*************************************************************************************************************** +// sucht nötige folge Cluster aus der fat ! +// erster daten cluster = 2, ende einer cluster chain 0xFFFF (fat16) oder 0xFFFFFFF, 0xFFFFFF8 (fat32), +// stelle des clusters in der fat, hat als wert, den nächsten cluster. (1:1 gemapt)! +//*************************************************************************************************************** +unsigned long int fat_getNextCluster(unsigned long int oneCluster){ + + // FAT 16**************FAT 16 + if(fat.fatType==16){ + unsigned long int i=oneCluster>>8;; // (i=oneCluster/256)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) + unsigned long int j=(oneCluster<<1)-(i<<9); // (j=(oneCluster-256*i)*2 == 2*oneCluster-512*i)errechnet das low byte von oneCluster + + if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig, wird von fat_loadSector geprüft + void *bytesOfSec=&fat.sector[j]; // zeiger auf puffer + return *(unsigned short*)bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :) + } + } + + // FAT 32**************FAT 32 + else{ + unsigned long int i=oneCluster>>7; // (i=oneCluster/128)errechnet den sektor der fat in dem oneCluster ist (rundet immer ab) + unsigned long int j=(oneCluster<<2)-(i<<9); // (j=(oneCluster-128*i)*4 == oneCluster*4-512*i)errechnet das low byte von oneCluster + + if(0==fat_loadSector(i+fat.fatSec)){ // ob neu laden nötig wird von fat_loadSector geprüft + void *bytesOfSec=&fat.sector[j]; // zeiger auf puffer + return *(unsigned long int*)bytesOfSec; // da der ram auch little endian ist, kann einfach gecastet werden und gut :) + } + } + + return(0); +} + + +//*************************************************************************************************************** +// sucht verkettete cluster einer datei, die in einer reihe liegen. worst case: nur ein cluster. +// sieht in der fat ab dem cluster offsetCluster nach. sucht die anzahl von MAX_CLUSTERS_IN_ROW, +// am stück,falls möglich. prüft ob der cluster neben offsetCluster dazu gehört... +// setzt dann fat.endSectors und fat.startSectors. das -1 weil z.b. [95,98] = {95,96,97,98} = 4 sektoren +//*************************************************************************************************************** +void fat_getFatChainClustersInRow(unsigned long int offsetCluster){ + + unsigned int i=0; + fat.startSectors=fat_clustToSec(offsetCluster); // setzen des 1. sektors der datei + fat.endSectors=fat.startSectors; + do{ + if( (offsetCluster+1+i)==fat_getNextCluster(offsetCluster+i) ) fat.endSectors+=fat.secPerClust; // zählen der zusammenhängenden sektoren + else { + file.lastCluster=offsetCluster+i; // cluster daneben gehört nicht dazu, somit ist offset+i der letzte bekannte + break; + } + }while(i++>8; // (i=cluster/256)errechnet den sektor der fat in dem cluster ist (rundet immer ab) + unsigned long int j=(cluster<<1)-(i<<9); // (j=(cluster-256*i)*2 == 2*cluster-512*i)errechnet das low byte von cluster + + if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) + void *bytesOfSec=&fat.sector[j]; // init des zeigers auf unterste adresse + *(unsigned short*)bytesOfSec=content;// weil ram auch little endian geht das so :) + fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde + } + } + + // FAT 32**************FAT 32 + else{ + unsigned long int i=cluster>>7; // (i=cluster/128)errechnet den sektor der fat in dem cluster ist (rundet immer ab) + unsigned long int j=(cluster<<2)-(i<<9); //(j=(cluster-128*i)*4 == cluster*4-512*i)errechnet das low byte von cluster + + if(0==fat_loadSector(i+fat.fatSec)){ // neu laden (fat_loadSector prüft ob schon gepuffert) + void *bytesOfSec=&fat.sector[j]; // init des zeigers auf unterste adresse + *(unsigned long int*)bytesOfSec=content; // weil ram auch little endian geht das so :) + fat.bufferDirty=1; // zeigt an, dass im aktuellen sector geschrieben wurde + } + } +} + + +//*************************************************************************************************************** +// löscht cluster chain, beginnend ab dem startCluster. +// sucht cluster, setzt inhalt usw.. abschließend noch den cluster-chain ende markierten cluster löschen. +//*************************************************************************************************************** +void fat_delClusterChain(unsigned long int startCluster){ + + unsigned long int nextCluster=startCluster; // tmp variable, wegen verketteter cluster.. + + do{ + startCluster=nextCluster; + nextCluster=fat_getNextCluster(startCluster); + fat_setCluster(startCluster,0x00000000); + }while(!((nextCluster==0xfffffff&&fat.fatType==32)||(nextCluster==0xffff&&fat.fatType==16))); + fat_writeSector(fat.currentSectorNr); +} + +#endif + + +//*************************************************************************************************************** +// Initialisiert die Fat(16/32) daten, wie: root directory sektor, daten sektor, fat sektor... +// siehe auch Fatgen103.pdf. ist NICHT auf performance optimiert! +// byte/sector, byte/cluster, anzahl der fats, sector/fat ... (halt alle wichtigen daten zum lesen ders datei systems!) +//*****************************************************************<********************************************** +unsigned char fat_loadFatData(unsigned long int sec){ + + // offset,size + unsigned int rootEntCnt; // 17,2 größe die eine fat belegt + unsigned int fatSz16; // 22,2 sectors occupied by one fat16 + unsigned long int fatSz32; // 36,4 sectors occupied by one fat32 + + void *vsector; + + if(0==mmc_read_sector(sec,fat.sector)){ // lesen von fat sector und bestimmen der wichtigen berreiche + + fat.bufferDirty = 0; // init wert des flags + + fat.secPerClust=fat.sector[13]; // fat.secPerClust, 13 only (power of 2) + + vsector=&fat.sector[14]; + fat.fatSec=*(unsigned short*)vsector; + + vsector=&fat.sector[17]; + rootEntCnt=*(unsigned short*)vsector; + + vsector=&fat.sector[22]; + fatSz16=*(unsigned short*)vsector; + + fat.rootDir = (((rootEntCnt <<5) + 512) /512)-1; // ist 0 bei fat 32, sonst der root dir sektor + + if(fat.rootDir==0){ // FAT32 spezifisch (die prüfung so, ist nicht spezifikation konform !). + + vsector=&fat.sector[36]; + fatSz32=*(unsigned long int *)vsector; + + vsector=&fat.sector[44]; + fat.rootDir=*(unsigned long int *)vsector; + + fat.dataDirSec = fat.fatSec + (fatSz32 * fat.sector[16]); // data sector (beginnt mit cluster 2) + fat.fatType=32; // fat typ + } + + else{ // FAT16 spezifisch + fat.dataDirSec = fat.fatSec + (fatSz16 * fat.sector[16]) + fat.rootDir; // data sektor (beginnt mit cluster 2) + fat.rootDir=fat.dataDirSec-fat.rootDir; // root dir sektor, da nicht im datenbereich (cluster) + fat.rootDir+=sec; // addiert den startsektor auf " + fat.fatType=16; // fat typ + } + + fat.fatSec+=sec; // addiert den startsektor auf + fat.dataDirSec+=sec; // addiert den startsektor auf (umrechnung von absolut auf real) + fat.dataDirSec-=2; // zeigt auf 1. cluster + fat.dir=0; // dir auf '0'==root dir, sonst 1.Cluster des dir + return (0); + } + + + return (1); // sector nicht gelesen, fat nicht initialisiert!! +} + + +//************************************************************************************************<<*************** +// int fat sucht den 1. cluster des dateisystems (fat16/32) auch VBR genannt, +//************************************************************************************************<<*************** +unsigned char fat_initfat(void){ + + unsigned long int secOfFirstPartition=0; // ist 1. sektor der 1. partition aus dem MBR + + if(0==mmc_read_sector(0,fat.sector)){ + + void *vsector=&fat.sector[454]; //startsektor bestimmen + secOfFirstPartition=*(unsigned long int*)vsector; + + //prüfung ob man schon im VBR gelesen hat (0x6964654d = "Medi") + if(secOfFirstPartition==0x6964654d) return fat_loadFatData(0); //ist superfloppy + + else {return fat_loadFatData(secOfFirstPartition);} // ist partitioniert... + } + + return (1); +} + + +#if (SMALL_FILE_SYSTEM==0) + +// ***************************************************************************************************************** +// bereitet str so auf, dass man es auf die mmc/sd karte schreiben kann. +// wandelt z.b. "t.txt" -> "T TXT" oder "main.c" in "MAIN C " => also immer 8.3 und upper case letter +// VORSICHT es werden keine Prüfungen gemacht ! +// ***************************************************************************************************************** +char * fat_str(char *str){ + + unsigned char i; + unsigned char j=0; + unsigned char c; + char tmp[12]; // tmp string zum einfacheren umwandeln + + strcpy(tmp,str); + + for(i=0;i<11;i++)str[i]=' '; // als vorbereitung alles mit leerzeichen füllen + str[11]='\0'; + + i=0; + + do{ + c=toupper(tmp[j]); + if(c=='\0')return str; + if(c!='.')str[i]=c; + else i=7; + i++; + j++; + }while(i<12); + + return str; + +} + +#endif + diff --git a/avr/usbload/fat.h b/avr/usbload/fat.h old mode 100755 new mode 100644 diff --git a/avr/usbload/file.c b/avr/usbload/file.c old mode 100755 new mode 100644 diff --git a/avr/usbload/file.h b/avr/usbload/file.h old mode 100755 new mode 100644 diff --git a/avr/usbload/mmc.c b/avr/usbload/mmc.c old mode 100755 new mode 100644 index c25f7d3..f10e614 --- a/avr/usbload/mmc.c +++ b/avr/usbload/mmc.c @@ -1,273 +1,224 @@ -/*####################################################################################### -Connect AVR to MMC/SD - -Copyright (C) 2004 Ulrich Radig - -Bei Fragen und Verbesserungen wendet euch per EMail an - -mail@ulrichradig.de - -oder im Forum meiner Web Page : www.ulrichradig.de - -Dieses Programm ist freie Software. Sie k�nnen es unter den Bedingungen der -GNU General Public License, wie von der Free Software Foundation ver�ffentlicht, -weitergeben und/oder modifizieren, entweder gem�� Version 2 der Lizenz oder -(nach Ihrer Option) jeder sp�teren Version. - -Die Ver�ffentlichung dieses Programms erfolgt in der Hoffnung, -da� es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, -sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT -F�R EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. - -Sie sollten eine Kopie der GNU General Public License zusammen mit diesem -Programm erhalten haben. -Falls nicht, schreiben Sie an die Free Software Foundation, -Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. -#######################################################################################*/ - -#include - -#include "mmc.h" - -#include - - -//############################################################################ -//Routine zur Initialisierung der MMC/SD-Karte (SPI-MODE) -unsigned char mmc_init (void){ - - unsigned char a; - unsigned int Timeout = 0; - - //Konfiguration des Ports an der die MMC/SD-Karte angeschlossen wurde - MMC_Direction_REG &=~(1< 200){ - MMC_Disable(); - return(1); //Abbruch bei Commando1 (Return Code1) - } - } - //Sendet Commando CMD1 an MMC/SD-Karte - Timeout = 0; - CMD[0] = 0x41;//Commando 1 - CMD[5] = 0xFF; - while( mmc_write_command (CMD) !=0){ - if (Timeout++ > 400){ - MMC_Disable(); - return(2); //Abbruch bei Commando2 (Return Code2) - } - } - - //SPI Bus auf max Geschwindigkeit - SPCR &= ~((1< 500){ - break; //Abbruch da die MMC/SD-Karte nicht Antwortet - } - } - return(tmp); -} - -//############################################################################ -//Routine zum Empfangen eines Bytes von der MMC-Karte -unsigned char mmc_read_byte (void){ - SPDR = 0xff; - while(!(SPSR & (1<>24 ); - cmd[2] = ((addr & 0x00FF0000) >>16 ); - cmd[3] = ((addr & 0x0000FF00) >>8 ); - - //Sendet Commando cmd24 an MMC/SD-Karte (Write 1 Block/512 Bytes) - tmp = mmc_write_command (cmd); - - if (tmp != 0) return(tmp); - - //Wartet einen Moment und sendet einen Clock an die MMC/SD-Karte - for (b=0;b<100;b++) - { - mmc_read_byte(); - } - - //Sendet Start Byte an MMC/SD-Karte - mmc_write_byte(0xFE); - - //Schreiben des Bolcks (512Bytes) auf MMC/SD-Karte - a=511; // do while konstrukt weils schneller geht - tmp=*Buffer++; // holt neues byte aus ram in register - do{ - SPDR = tmp; //Sendet ein Byte - tmp=*Buffer++; // holt schonmal neues aus ram in register - while( !(SPSR & (1<>24 ); - cmd[2] = ((addr & 0x00FF0000) >>16 ); - cmd[3] = ((addr & 0x0000FF00) >>8 ); - - mmc_read_block(cmd,Buffer,512); - - return(0); -} - - -/* -//############################################################################ -//Routine zum lesen des CID Registers von der MMC/SD-Karte (16Bytes) -unsigned char mmc_read_cid (unsigned char *Buffer){ - //Commando zum lesen des CID Registers - unsigned char cmd[] = {0x4A,0x00,0x00,0x00,0x00,0xFF}; - - mmc_read_block(cmd,Buffer,16); - - return(0); -} - -//############################################################################ -//Routine zum lesen des CSD Registers von der MMC/SD-Karte (16Bytes) -unsigned char mmc_read_csd (unsigned char *Buffer){ - //Commando zum lesen des CSD Registers - unsigned char cmd[] = {0x49,0x00,0x00,0x00,0x00,0xFF}; - - mmc_read_block(cmd,Buffer,16); - - return(0); -} -*/ +/*####################################################################################### +Connect AVR to MMC/SD + +Copyright (C) 2004 Ulrich Radig + +Bei Fragen und Verbesserungen wendet euch per EMail an + +mail@ulrichradig.de + +oder im Forum meiner Web Page : www.ulrichradig.de + +Dieses Programm ist freie Software. Sie können es unter den Bedingungen der +GNU General Public License, wie von der Free Software Foundation veröffentlicht, +weitergeben und/oder modifizieren, entweder gemäß Version 2 der Lizenz oder +(nach Ihrer Option) jeder späteren Version. + +Die Veröffentlichung dieses Programms erfolgt in der Hoffnung, +daß es Ihnen von Nutzen sein wird, aber OHNE IRGENDEINE GARANTIE, +sogar ohne die implizite Garantie der MARKTREIFE oder der VERWENDBARKEIT +FÜR EINEN BESTIMMTEN ZWECK. Details finden Sie in der GNU General Public License. + +Sie sollten eine Kopie der GNU General Public License zusammen mit diesem +Programm erhalten haben. +Falls nicht, schreiben Sie an die Free Software Foundation, +Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. +#######################################################################################*/ + +#include +#include + +#include "mmc.h" + + +uint8_t mmc_init() +{ + uint16_t Timeout = 0, i; + MMC_REG |= ((1 << MMC_DO) | (1 << MMC_CS) | (1 << MMC_CLK)); + MMC_REG &= ~(1 << MMC_DI); + MMC_WRITE |= ((1 << MMC_DO) | (1 << MMC_DI) | (1 << MMC_CS)); + _delay_ms(20); + for (i = 0; i < 250; i++) { + MMC_WRITE ^= (1 << MMC_CLK); + _delay_us(4); + } + MMC_WRITE &= ~(1 << MMC_CLK); + _delay_us(10); + MMC_WRITE &= ~(1 << MMC_CS); + _delay_us(3); + + uint8_t CMD[] = { 0x40, 0x00, 0x00, 0x00, 0x00, 0x95 }; + while (mmc_write_command(CMD) != 1) { + if (Timeout++ > 20) { + mmc_disable(); + return (1); + } + } + + Timeout = 0; + CMD[0] = 0x41; + CMD[5] = 0xFF; + while (mmc_write_command(CMD) != 0) { + if (Timeout++ > 800) { + mmc_disable(); + return (9); + } + } + return (0); +} +uint8_t mmc_write_command(uint8_t * cmd) +{ + uint8_t tmp = 0xff; + uint16_t Timeout = 0; + uint8_t a; + + for (a = 0; a < 0x06; a++) { + mmc_write_byte(*cmd++); + } + + while (tmp == 0xff) { + tmp = mmc_read_byte(); + if (Timeout++ > 50) { + break; + } + } + return (tmp); +} + + +uint8_t mmc_read_byte(void) +{ + uint8_t Byte = 0, j; + for (j = 0; j < 8; j++) { + Byte = (Byte << 1); + MMC_WRITE |= (1 << MMC_CLK); + _delay_us(4); + if (PINB & (1 << MMC_DI)) { + Byte |= 1; + } + + else { + Byte &= ~1; + } + MMC_WRITE &= ~(1 << MMC_CLK); + _delay_us(4); + } + return (Byte); +} + + +void mmc_write_byte(uint8_t Byte) +{ + uint8_t i; + for (i = 0; i < 8; i++) { + if (Byte & 0x80) { + MMC_WRITE |= (1 << MMC_DO); + } + + else { + MMC_WRITE &= ~(1 << MMC_DO); + } + Byte = (Byte << 1); + MMC_WRITE |= (1 << MMC_CLK); + _delay_us(4); + MMC_WRITE &= ~(1 << MMC_CLK); + _delay_us(4); + } + MMC_WRITE |= (1 << MMC_DO); +} + +uint8_t mmc_write_sector(uint32_t addr, uint8_t * Buffer) +{ + uint8_t tmp; + + + uint8_t cmd[] = { 0x58, 0x00, 0x00, 0x00, 0x00, 0xFF }; + uint8_t a; + uint16_t i; + + addr = addr << 9; + cmd[1] = ((addr & 0xFF000000) >> 24); + cmd[2] = ((addr & 0x00FF0000) >> 16); + cmd[3] = ((addr & 0x0000FF00) >> 8); + + + tmp = mmc_write_command(cmd); + if (tmp != 0) { + return (tmp); + } + + for (a = 0; a < 100; a++) { + mmc_read_byte(); + } + + mmc_write_byte(0xFE); + + for (a = 0; i < 512; i++) { + mmc_write_byte(*Buffer++); + } + + mmc_write_byte(0xFF); + mmc_write_byte(0xFF); + + if ((mmc_read_byte() & 0x1F) != 0x05) + return (1); + + while (mmc_read_byte() != 0xff) { + }; + return (0); +} + + +void mmc_read_block(uint8_t * cmd, uint8_t * Buffer, uint16_t Bytes) +{ + uint16_t a; + + if (mmc_write_command(cmd) != 0) { + return; + } + + while (mmc_read_byte() != 0xfe) { + }; + + + for (a = 0; a < Bytes; a++) { + *Buffer++ = mmc_read_byte(); + } + + mmc_read_byte(); + mmc_read_byte(); + return; +} + +uint8_t mmc_read_sector(uint32_t addr, uint8_t * Buffer) +{ + + + uint8_t cmd[] = { 0x51, 0x00, 0x00, 0x00, 0x00, 0xFF }; + + addr = addr << 9; + cmd[1] = ((addr & 0xFF000000) >> 24); + cmd[2] = ((addr & 0x00FF0000) >> 16); + cmd[3] = ((addr & 0x0000FF00) >> 8); + mmc_read_block(cmd, Buffer, 512); + return (0); +} + + +uint8_t mmc_read_cid(uint8_t * Buffer) +{ + + uint8_t cmd[] = { 0x4A, 0x00, 0x00, 0x00, 0x00, 0xFF }; + mmc_read_block(cmd, Buffer, 16); + return (0); +} + + +uint8_t mmc_read_csd(uint8_t * Buffer) +{ + + uint8_t cmd[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0xFF }; + mmc_read_block(cmd, Buffer, 16); + return (0); +} + diff --git a/avr/usbload/mmc.h b/avr/usbload/mmc.h old mode 100755 new mode 100644 index 1c397c1..c4ef8df --- a/avr/usbload/mmc.h +++ b/avr/usbload/mmc.h @@ -1,44 +1,44 @@ -/*####################################################################################### -Connect ARM to MMC/SD - -Copyright (C) 2004 Ulrich Radig -#######################################################################################*/ - - -#ifndef _MMC_H - #define _MMC_H - - #define MMC_Write PORTB //Port an der die MMC/SD-Karte angeschlossen ist also des SPI - #define MMC_Read PINB - #define MMC_Direction_REG DDRB - - - #if defined (__AVR_ATmega644__) - #define SPI_DI 6 //Port Pin an dem Data Output der MMC/SD-Karte angeschlossen ist - #define SPI_DO 5 //Port Pin an dem Data Input der MMC/SD-Karte angeschlossen ist - #define SPI_Clock 7 //Port Pin an dem die Clock der MMC/SD-Karte angeschlossen ist (clk) - #define MMC_Chip_Select 3 //Port Pin an dem Chip Select der MMC/SD-Karte angeschlossen ist - #define SPI_SS 4 //Nicht Benutz mu� aber definiert werden - #endif - - - //Prototypes - extern unsigned char mmc_read_byte(void); - extern void mmc_write_byte(unsigned char); - extern void mmc_read_block(unsigned char *,unsigned char *,unsigned in); - extern unsigned char mmc_init(void); - extern unsigned char mmc_read_sector (unsigned long,unsigned char *); - extern unsigned char mmc_write_sector (unsigned long,unsigned char *); - extern unsigned char mmc_write_command (unsigned char *); - //extern unsigned char mmc_read_csd (unsigned char *); - //extern unsigned char mmc_read_cid (unsigned char *); - - //set MMC_Chip_Select to high (MMC/SD-Karte Inaktiv) - #define MMC_Disable() MMC_Write|= (1<