| 
	
	|  |  |  
	
		| View previous topic :: View next topic |  
		| Author | Message |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				| Another MMC Over SPI FAT32 code! |  
				|  Posted: Fri Jul 27, 2007 4:16 am |   |  
				| 
 |  
				| Hi all! I have been working with Tomi's FAT32 code for MMC. I have made a few changes, made the code a bit nicer (I think) added suport for file and directory listing of both short and long filenames. ... And I want to share it with you! ;)
 
 There are just two files MMC_SPI_FAT32.h and MMC_SPI_FAT32.c, if you have used Tomi's code you know that you needed "my6720.h" but you do not need it with my code. Read through the MMC_SPI_FAT32.h and the top of the MMC_SPI_FAT32.c to se if you need to change anything and to get som examples of how to use it, and many more..
 
 Here comes MMC_SPI_FAT32.h:
 
  	  | Code: |  	  | #define MAXFILES 1 // This define specifies the maximum number
 // of simultaneously open files, more files
 // requires more ram. The maximun number of
 // this define is 8, this is because of my
 // error handlig.. but that should be more
 // then enough..
 
 // This enable functions and variables needed for filelisting
 // If you aren't going to use it, comment this line out to
 // save some RAM
 #define ENABLE_FILELISTNG
 
 typedef struct _diskinforec
 {
 char   hJumpCode[3];
 char  OEMName[8];
 int16   hBytesPerSector;
 char   bSectorsPerCluster;
 int16 Reserved1;
 char   FATCopies;
 int16 hMaxRootEntries;
 int16 hSectors;
 char   Descriptor;
 int16 holdSectorsPerFat;
 int16 hSectorsPerTrack;
 int16 hNumberofHeads;
 int32   hNumberofHidden;
 int32   hNumberofSectors;
 
 int32 hSectorsPerFat;
 int16 hFlags;
 int16 hFAT32Version;
 int32 hRootStartCluster;
 } diskinforec;
 
 typedef struct _direntry
 {
 char   sName[8];
 char   spam[3];
 char   bAttr;
 char   bReserved[8];
 int16 hClusterH;
 int16   hTime;
 int16   hDate;
 int16   hCluster;
 int32   wSize;
 } DIR;
 
 typedef struct
 {
 char    IOpuffer[512];
 DIR    DirEntry;
 int32 CurrentCluster;
 int16 posinsector;
 int32   position;
 int32 dirSector;
 int8   dirIdx;
 char   mode;
 BOOLEAN   Free;
 } FILE;
 
 typedef struct
 {
 int32 MMCAddress;
 int32 FATstartidx;
 int32 gStartSector;
 int32 gFirstDataSector;
 int8 gDirEntryIdx;
 int32 gDirEntrySector;
 int8 gFirstEmptyDirEntry;
 int32 gFirstDirEntryCluster;
 } FAT32Vars;
 
 typedef struct
 {
 unsigned long   Year;
 char         Month;
 char            Day;
 char            Hour;
 char            Minute;
 char            Second;
 } TimeRecord;
 
 typedef struct
 {
 int32 dirSector;
 int32 CurrentCluster;
 int dirIdx;
 } ListPos;
 
 typedef struct
 {
 char *name;
 char *shortName;
 BOOLEAN isDir;
 BOOLEAN isLong;
 } LongFileName;
 
 typedef char MMCResponse;
 
 MMCResponse MMCInit();
 MMCResponse ReadSector(int32 sector, char *hova);
 MMCResponse WriteSector(int32 sector, char *honnan);
 
 void      InitFAT();
 char      FindDirEntry(char *fname, char f);
 
 #ifdef ENABLE_FILELISTNG
 MMCResponse InitList(char *path);
 int8      ListFiles(char f);
 MMCResponse NextPage(char f);
 MMCResponse SetPage(char f, int32 page);
 MMCResponse CloseList(char f);
 void      FreeList();
 #endif
 
 MMCResponse fopen(char *fname, char mode);
 MMCResponse fclose(char f);
 MMCResponse fflush(char f);
 char      cwd(char *fname, char f);
 MMCResponse fputch(char be, char f);
 MMCResponse fgetch(char *ki, char f);
 MMCResponse fputstring(char *be, char f); // fputs is reserved in CCS C
 int16      fread(char *buffer, int16 leng, char f);
 MMCResponse fwrite(char *buffer, int16 leng, char f);
 MMCResponse remove(char *fname);
 MMCResponse getfsize(char *fname, int32 *fsiz);
 
 | 
 
 And here comes MMC_SPI_FAT32.c:
 
  	  | Code: |  	  | ////////////////////////////////////////////////////////////////////////
 /////////////////// FAT32 DRIVER FOR MMC OVER SPI //////////////////////
 ////////////////////////////////////////////////////////////////////////
 //// Original code by Tamas Bodorics (Tomi),                        ////
 //// http://www.ccsinfo.com/forum/viewtopic.php?t=23969             ////
 //// Modified by Mattias "miniman" Eriksson, Sweden                 ////
 //// Disclaimer:                                                    ////
 //// This code is provided for you "AS IS", this means I can NOT be ////
 //// held responsible for any damage or harm it may couse.          ////
 ////////////////////////////////////////////////////////////////////////
 //// Hardware:                                                      ////
 ////   This is the hardware I use. My pic is running at 5v, the MMC ////
 ////   at 3.3V, so I need voltage level conversion. That is what    ////
 ////   the resistors and zener diodes are for. First a 820 ohm      ////
 ////   resistor from is connected to the pic, then a 3.3V           ////
 ////   zenerdiode is connected with its anode to ground and its     ////
 ////   cathode to the resistor. This resistor-zenerdiode connection ////
 ////   leaves about 3V on the DATA/CS/CLOCK lines which is enough.  ////
 ////   A 100K pull-up resistor from Data out(Do) of the MMC is      ////
 ////   required. Note: this "picture" do not have the right pin     ////
 ////   assignments. Hope you can see what I'm trying to paint..     ////
 ////                                                                ////
 ////    __ __  3x820 ohm                       ______________       ////
 ////   |  U  |--\/\/\----------- o---DATA->---|=2            |      ////
 ////   | PIC |--\/\/\-------o----+---CS--->---|=1            |      ////
 ////   |     |--\/\/\--o----+----+---CLOCK>---|=5    MMC     |      ////
 ////   |     |        _|_, _|_, _|_,       o--|=7            |      ////
 ////   |     |       '/_\ '/_\ '/_\        |   \_____________|      ////
 ////   |     |     GND_|____|____|_GND     | 100k ohm               ////
 ////   |_____|-----------<-DATA-<----------o--\/\/\---<3.3V         ////
 ////                                                                ////
 //// Notes:                                                         ////
 //// - The card that is going to be used by this code has to be     ////
 ////   pre-formated with FAT32, 512byte/sector. To do this, run cmd ////
 ////   and type the following command:                              ////
 ////   format X: /A:512 /V:LABEL /FS:FAT32                          ////
 ////   where X is the diverletter of your card and LABEL is the     ////
 ////   volyme name. This can also be done in the diskmanager        ////
 //// - Use '/' as directory separator, example: "MYDIR/ELEMENT.WND" ////
 ////   "MYDIR/SUBDIR/OTHER.TXT" etc.                                ////
 ////                                                                ////
 //// Functions:                                                     ////
 ////   MMCInit()                                                    ////
 ////      Initializes the MMC, this function must be called before  ////
 ////      any other MMC functions, and at the top of the program.   ////
 ////      Returns a MMCResponse.                                    ////
 ////   InitFAT()                                                    ////
 ////      Initializes the FAT filesystem, this function must be     ////
 ////      called before any other MMC functions and after MMCInit,  ////
 ////      only if the later one returned MMC_OK.                    ////
 ////      Returns a MMCResponse.                                    ////
 ////   InitList(char *path)                                         ////
 ////      Initializes file and directory listing in the any         ////
 ////      directory that is specified by path. To list files and    ////
 ////      directorys in root directory path should be a empty       ////
 ////      string(""). Ottherwise path should end with a "/" e.g:    ////
 ////      "DIR/SUBDIR/". Returns a filehandle.                      ////
 ////   Listfiles(char f)                                            ////
 ////      List files and directorys in any directory that have been ////
 ////      openes by InitList(). Access the list through FileList    ////
 ////      array. See examples. There can only be one file handle    ////
 ////      open for file listing at the same time. Returns the       ////
 ////      number of files and directorys that where listed.         ////
 ////   NextPage(char f)                                             ////
 ////      To be able to handle many files in a dir, file listing    ////
 ////      is parted up in pages. To list next page, call NextPage   ////
 ////      and then ListFiles again. ListFiles must be called        ////
 ////      before a NextPage function, otherwise the function will   ////
 ////      not have any effect. Returns a MMCResponse.               ////
 ////   SetPage(char f)                                              ////
 ////      Set the page that you want to list, see above function    ////
 ////      to get better understanding. Note: no need to call        ////
 ////      ListFiles before this function. Returns a MMCResponse.    ////
 ////   CloseList(char f)                                            ////
 ////      Closes filelisting, in other words, the there are an      ////
 ////      extra free file handle to use. Returns a MMCResponse      ////
 ////   FreeList()                                                   ////
 ////      Frees all the strings in FileList array. This function    ////
 ////      is called before any new files are listed in ListFiles    ////
 ////      but not in CloseList. THis means you can access the last  ////
 ////      listed files even though you already have closed the      ////
 ////      list. But to free the mem that are used by FileList call  ////
 ////      this function.                                            ////
 ////   fopen(char *fname, char mode)                                ////
 ////      Opens a file specified by fname in the desired mode.      ////
 ////      Valid modes are: 'r' = read, 'w' = write and 'a' = append ////
 ////      No long filenames can be used. To open a file with long   ////
 ////      filename, listed by ListFiles(), use the shortName field  ////
 ////      in the FileList, FileList[i].shortName. Note: ListFiles   ////
 ////      do only filename, not the path..                          ////
 ////      Returns a filehandle if succeed, else a errorcode         ////
 ////   fclose(char f)                                               ////
 ////      Closes a file that previously have been opened by fopen.  ////
 ////      Returns a MMCResponse                                     ////
 ////   fputch(char be, char f)                                      ////
 ////      Puts a char, be, in file f that previously have been      ////
 ////      opened by fopen. Returns a MMCResponse                    ////
 ////   fgetch(char *ki, char f)                                     ////
 ////      get a char from file f that previously have been opened   ////
 ////      by fopen, and puts it at the position specified by ki     ////
 ////      Returns a MMCSresponse                                    ////
 ////   fputstring(char *be, char f)                                 ////
 ////      puts a entire string to file f that previously have been  ////
 ////      opened by fopen. Returns MMCResponse                      ////
 ////   fread(char *buffer, int16 leng, char f)                      ////
 ////      Reads a block of data with length leng from file f that   ////
 ////      previously have been opened by fopen.                     ////
 ////      Returns the number of bytes that were read.               ////
 ////   fwrite(char *buffer, int16 leng, char f)                     ////
 ////      Writes a block of data with length leng to a file f that  ////
 ////      previously have been opened by fopen.                     ////
 ////      Returns a MMCResponse                                     ////
 ////   getfsize(char *fname, int32 *fsiz)                           ////
 ////      Reads the size of a file with a filename specified by     ////
 ////      fname. Returns a MMCResponse.                             ////
 ////                                                                ////
 //// Examples:                                                      ////
 ////   // This example open a file for append, and writes "System   ////
 ////   // started". It also shows small error handling              ////
 ////   char f,gfilename[12];                                        ////
 ////   strcpy(gfilename,"EVENTS.LOG");                              ////
 ////   f = fopen(gfilename,'a'); // open EVENTS.LOG for append      ////
 ////   if (f & MMC_ERROR)                                           ////
 ////   {                                                            ////
 ////      printf("Couldn't open file!\r\n");                        ////
 ////      if(f == MMC_NO_CARD_INSERTED)                             ////
 ////         printf("Please, insert MMC!");                         ////
 ////      else if(f == MMC_MAX_FILES_REACHED)                       ////
 ////         printf("ops.. =)");                                    ////
 ////   }                                                            ////
 ////   else                                                         ////
 ////   {                                                            ////
 ////      strcpy(msg,"System started\r\n");                         ////
 ////      fputstring(msg,f);                                        ////
 ////      fclose(f);                                                ////
 ////   }                                                            ////
 ////                                                                ////
 ////   // Here is a exampel that covers almost everything...        ////
 ////   // It first lists all files and dirs in DIR/ and then open   ////
 ////   // The first and prints the file with printf, take a look:   ////
 ////   #include <MMC_SPI_FAT32.h> // As usual you also need to      ////
 ////   #include <MMC_SPI_FAT32.c> // include your device .h file... ////
 ////   void main(void)                                              ////
 ////   {                                                            ////
 ////      char f,filename[20],res,i,c;                              ////
 ////      while(TRUE)                                               ////
 ////      {                                                         ////
 ////         if(MMCInit() == MMC_OK)                                ////
 ////         {                                                      ////
 ////            printf("MMC initialized\r\n");                      ////
 ////            InitFAT();                                          ////
 ////            strcpy(filename,"DIR/");                            ////
 ////            f = InitList(filename);                             ////
 ////            if(f & MMC_ERROR)                                   ////
 ////               printf("Error");                                 ////
 ////            else                                                ////
 ////            {                                                   ////
 ////               do                                               ////
 ////               {                                                ////
 ////                  res = ListFiles(f);                           ////
 ////                  for(i=0;i<res;i++)                            ////
 ////                  {                                             ////
 ////                     printf(FileList[i].name);                  ////
 ////                     if(FileList[i].isDir)                      ////
 ////                        printf("\\\r\n");//a "\" with row break ////
 ////                     else                                       ////
 ////                        printf("\r\n");                         ////
 ////                  }                                             ////
 ////               } while(NextPage(f) == MMC_OK);                  ////
 ////               CloseList(f); // frees the file, but the list is ////
 ////            }                // still there...                  ////
 ////            strcpy(filename,FileList[0].shortName);             ////
 ////            f = open(filename,'r'); // open file for reading    ////
 ////            if((f & MMC_ERROR) == 0) // No error, same as       ////
 ////            {                        // if(f < MAXFILES)        ////
 ////               while(fgetch(&c,f) == MMC_OK)                    ////
 ////                  printf(c);                                    ////
 ////               fclose(f);                                       ////
 ////            }                                                   ////
 ////            else if(f == MMC_NOT_FOUND)                         ////
 ////               printf("1st file in list was probebly a dir");   ////
 ////            else                                                ////
 ////               printf("Other error\r\n");                       ////
 ////            while(TRUE)                                         ////
 ////               ; // Loop forever, program is finished           ////
 ////         }                                                      ////
 ////         else                                                   ////
 ////            printf("MMC init failed!\r\n");                     ////
 ////         delay_ms(1000);                                        ////
 ////         printf("Trying once more..\r\n");                      ////
 ////      }                                                         ////
 ////   }                                                            ////
 ////                                                                ////
 ////////////////////////////////////////////////////////////////////////
 //// Changelog:                                                     ////
 //// YYYY-MM-DD VER LOG                                             ////
 //// 2007-08-15 0.9 Fixed a hardware SPI error in writesector.      ////
 ////                Thanks to wielen who found the bug.             ////
 //// 2007-07-25 0.8 This, and almost all other text is written      ////
 ////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////
 
 // If you want to use software SPI keep this line uncommented
 // If you want to use hardware SPI comment this line..
 // Software SPI are slower, but you can use any clock and data
 // pins that you want..
 #define MMC_SPI_SOFTWARE
 
 
 // Change the port to whatever port you are going to use
 #use FAST_IO(B)
 // Change this to set the right tris for your pins
 #define SET_MMC_TRIS() set_tris_b(0x10) // 0b0001000 1=input,0=output
 // Change these pins to whatever pins you are using
 #define ChipSel      pin_B7 // Chip-Select pin
 #define ChipClk      pin_B5 // SPI-Clock pin
 #define ChipDout   pin_B6 // SPI-Data out pin
 #define ChipDin      pin_B4 // SPI-Data in pin
 
 #ifdef MMC_SPI_SOFTWARE
 // You can also specify a baud-rate in the line below, if not the fastest possible speed will be used.
 // For me that was 800kHz on a 18F4550 with 48MHz external clock
 #USE SPI(MASTER, SAMPLE_RISE, MSB_FIRST, IDLE=1, DI=ChipDin, DO=ChipDout, CLK=ChipClk, BITS=8, STREAM=MMC_SPI)
 #define MMC_Xfer(a) SPI_Xfer(MMC_SPI,a)
 #else
 // If MMC_SPI_SOFTWARE isn't defined (se above) these variables are used, you should check if they
 // matches your target device, but for most pic's they should do
 #byte SSPBUF   = 0xFC9
 #byte SSPSTAT   = 0xFC7
 #byte SSPCON1   = 0xFC6
 #bit  BF      = SSPSTAT.0
 #endif
 
 #ifdef ENABLE_FILELISTNG
 #include <STDLIBM.H> // used for malloc and free functions
 #endif
 
 int32 FATTable[128];
 int32 gFirstEmptyCluster;
 
 FAT32Vars gFAT32Vars;
 diskinforec DiskInfo;
 FILE gFiles[MAXFILES];
 
 // Time stores the date and time, this is used when writing and/or creating files
 TimeRecord Time;
 
 #ifdef ENABLE_FILELISTNG
 // Set the maximum number of files/dirs to be listed by Listfile()
 #define MAX_FILE_LIST 10
 // Variables used by InitList(), ListFiles(), NextPage() and SetPage()
 ListPos StartList;
 ListPos CurrentList;
 BOOLEAN changeList; // Do not use this; it is only used by SetPage() and ListFiles() and Initialized by InitFAT()
 // The result of ListFiles() function..
 LongFileName FileList[MAX_FILE_LIST];
 #endif
 
 #byte MMCAddressL = gFAT32Vars
 #byte MMCAddressH = gFAT32Vars+1
 #byte MMCAddressHL = gFAT32Vars+2
 #byte MMCAddressHH = gFAT32Vars+3
 #byte gStartSectorL = gFAT32Vars+8
 #byte gStartSectorH = gFAT32Vars+9
 #byte gStartSectorHL = gFAT32Vars+10
 
 // You should check that these values matches your pic device
 // but for most devices they should be correct
 #define FSR0L      *0xFE9
 #define POSTINC0   *0xFEE
 
 // A bunch of error codes
 #define MMC_OK                0
 #define MMC_ERROR             0x80
 #define MMC_INVALID_FILE       0x88
 #define MMC_MAX_FILES_REACHED    0x90
 #define MMC_NO_CARD_INSERTED    0x98
 #define MMC_TIME_OUT         0xA0
 #define MMC_INVALID_RESPONSE   0xA8
 #define MMC_NOT_FOUND         0xB0
 #define MMC_INVALID_CLUSTER      0xB8
 #define MMC_END_OF_DIR         0xC0
 #define MMC_INVALID_POSITION   0xC8
 
 // I don't like having constants in the code... yeah, I do have some anyway ;)
 #define END_OF_DIR                  17
 #define DIRENTRYS_PER_SECTOR         16
 #define CHARACTERS_IN_LONG_FILENAMES   13
 
 // If you want to have a cardinserted sens-pin, define CardInserted to a input, like:
 // #define CardInserted !input(PIN_XX)
 // MMC Card have two GND pins, pull one up with a resistor (10K or somwthing like that) to Vcc
 // and connect to desired pin
 #define CardInserted() 1
 
 // Looks a bit nicer in the code
 #define MMC_Select()    output_low(ChipSel)
 #define MMC_Deselect()   output_high(ChipSel)
 
 
 // Below this, there should be no need to change anything
 
 
 char IsSelfDir(char *be)
 {
 if (be[0] == '.' && be[1] == '.')
 return 0xFF;
 else
 return 0;
 }
 
 void MMCOut(char indata)
 {
 #ifdef MMC_SPI_SOFTWARE
 MMC_Xfer(indata);
 #else
 char i;
 SSPBUF=indata;
 while (!BF);
 i = SSPBUF;
 #endif
 }
 
 void MMC8Clock()
 {
 #ifdef MMC_SPI_SOFTWARE
 MMC_Xfer(0xFF);
 #else
 char i;
 SSPBUF=0xFF;
 while (!BF);
 i = SSPBUF;
 #endif
 }
 
 char MMCIn()
 {
 #ifdef MMC_SPI_SOFTWARE
 return MMC_Xfer(0xFF);
 #else
 char i;
 SSPBUF=0xFF;
 while (!BF);
 i = SSPBUF;
 return i;
 #endif
 }
 
 MMCResponse MMCInit()
 {
 char response,iii,errcnt;
 
 
 if (!CardInserted())
 return MMC_NO_CARD_INSERTED;
 
 SET_MMC_TRIS();  // Set input/output
 restart_wdt();
 MMC_Deselect();
 
 #ifndef MMC_SPI_SOFTWARE
 bit_clear(SSPCON1,5); // Disables serial port and configures these pins as I/O port pins
 SSPCON1 = 0x30; // modify this number to change SPI clock rate
 // Enables serial port and configures SCK, SDO, SDI and SS as serial port pins
 // Idle state for clock is a high level
 // 0000 = SPI Master mode, clock = FOSC/4
 
 SSPSTAT = 0;   // Only bit 6,7 are writable
 // 0 = Input data sampled at middle of data output time
 // 0 = Transmit occurs on transition from Idle to active clock state
 #endif
 
 iii = 10;
 errcnt = 100;
 do
 {
 MMCOut(0xFF);
 } while (--iii);
 delay_us(1000);
 
 MMC_Select(); // if the /CS line of the MMC is low during CMD0,(below), the card enters SPI-mode
 MMCOut(0x40); // CMD0
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x95); // CRC
 MMC8Clock();
 response = MMCIn();
 MMC_Deselect();
 do
 {
 delay_us(1000);
 //output_low(ChipClk);
 MMC_Select();
 MMCOut(0x41); // CMD1
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x00);
 MMCOut(0x01);
 MMC8Clock();
 response = MMCIn();
 MMC_Deselect();
 MMC8Clock();
 errcnt--;
 } while (response && errcnt);
 if(response == 0)
 return MMC_OK;
 else
 return MMC_TIME_OUT;
 }
 
 
 // "Packed" Date:
 // +-------+------------+-------+-----+
 // | BITS  |    15:9    |  8:5  | 4:0 |
 // | VALUE |Year – 1980 | Month | Day |
 // +-------+------------+-------+-----+
 int16 GetCurrentDOSDate()
 {
 int16 retval;
 
 retval = Time.Year - 1980;
 retval <<= 9;
 retval |= ((int16)Time.Month << 5);
 retval |= (int16)Time.Day;
 return retval;
 }
 
 // "Packed" Time:
 // +-------+-------+--------+----------+
 // | BITS  | 15:11 |  10:5  |   4:0    |
 // | VALUE | Hour  | Minute | Second/2 |
 // +-------+-------+--------+----------+
 int16 GetCurrentDOSTime()
 {
 int16 retval;
 
 retval = Time.Hour;
 retval <<= 11;
 retval |= ((int16)Time.Minute << 5);
 retval |= (int16)Time.Second >> 1;
 return retval;
 }
 
 // Function: Reads a sector from MMC
 MMCResponse ReadSector(int32 sector, char *hova)
 {
 char errs,response;
 char cnt2,cnt3;
 
 #byte sectorL = sector
 #byte sectorH = sector+1
 #byte sectorHL = sector+2
 
 if (!CardInserted())
 return MMC_NO_CARD_INSERTED;
 Disable_interrupts(GLOBAL);
 Restart_wdt();
 MMCAddressL = 0;
 MMCAddressH = sectorL;
 MMCAddressHL = sectorH;
 MMCAddressHH = sectorHL;
 gFAT32Vars.MMCAddress <<= 1;
 
 MMC_Select();
 MMCOut(0x51);
 MMCOut(MMCAddressHH);
 MMCOut(MMCAddressHL);
 MMCOut(MMCAddressH & 0xFE);
 MMCOut(0);
 MMCOut(0x01);
 errs = 8;
 do
 {
 response = MMCIn();
 } while (--errs && response==0xFF);
 errs = 50;
 do
 {
 response = MMCIn();
 if (response == 0xFE)
 break;
 delay_ms(1);
 } while (--errs);
 FSR0L = (int16)hova; // *0xFE9
 cnt3 = 2;
 cnt2 = 0;
 do
 {
 do
 {
 #ifdef MMC_SPI_SOFTWARE
 POSTINC0 = MMC_Xfer(0xFF); // *0xFEE
 #else
 SSPBUF=0xFF; // Writes 0xFF on SPI
 while(!BF); // Wait until Transmitted/Received
 POSTINC0 = SSPBUF; // Read the received byte and place it in adress oxFEE
 #endif
 } while (--cnt2);
 } while (--cnt3);
 response = MMCIn();
 response = MMCIn();
 MMC_Deselect();
 Enable_interrupts(GLOBAL);
 return MMC_OK;
 }
 
 // Writes a sector to MMC
 MMCResponse WriteSector(int32 sector, char *honnan)
 {
 char errs,response;
 char cnt2,cnt3;
 #byte sectorL = sector
 #byte sectorH = sector+1
 #byte sectorHL = sector+2
 
 if (!CardInserted())
 return MMC_NO_CARD_INSERTED;
 Disable_interrupts(GLOBAL);
 Restart_wdt();
 MMCAddressL = 0;
 MMCAddressH = sectorL;
 MMCAddressHL = sectorH;
 MMCAddressHH = sectorHL;
 gFAT32Vars.MMCAddress <<= 1;
 response = 0;
 //output_low(ChipClk);
 MMC_Select();
 MMCOut(0x58);
 MMCOut(MMCAddressHH);
 MMCOut(MMCAddressHL);
 MMCOut(MMCAddressH & 0xFE);
 MMCOut(0);
 MMCOut(0x01);
 MMC8Clock();
 errs = 8;
 do
 {
 response = MMCIn();
 } while (--errs && response==0xFF);
 if (response)
 {
 MMC_Deselect();
 //output_high(ChipClk);
 MMC8Clock();
 Enable_interrupts(GLOBAL);
 return MMC_INVALID_RESPONSE;
 }
 MMC8Clock();
 MMCOut(0xFE);
 FSR0L = (int16)honnan; // *0xFE9
 cnt3 = 2;
 cnt2 = 0;
 do
 {
 do
 { /*
 
 */
 #ifdef MMC_SPI_SOFTWARE
 MMC_Xfer(POSTINC0); // *0xFEE
 #else
 SSPBUF=POSTINC0; // Write the byte on address oxFEE to SPI
 while (!BF);
 response = SSPBUF; // thanks to wielen
 #endif
 } while (--cnt2);
 } while (--cnt3);
 MMCOut(0x00);
 MMCOut(0x01);
 response = MMCIn();
 response ^= 0xE5; // Bitwise exclusive or assignment operator, x^=y, is the same as x=x^y
 if (response)
 {
 goto endwr3;
 }
 do
 {
 response = MMCIn();
 } while (response == 0);
 response = 0;
 endwr3:
 MMC_Deselect();
 //output_high(ChipClk);
 MMC8Clock();
 Enable_interrupts(GLOBAL);
 return MMC_OK;
 }
 
 // Function: Initializes the FAT system
 void InitFAT()
 {
 int32 actsector;
 char i;
 
 gFirstEmptyCluster = 0;
 gFAT32Vars.gStartSector = 0;
 ReadSector(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
 if (gFiles[MAXFILES-1].IOpuffer[0] != 0xEB)
 {
 gStartSectorL = gFiles[MAXFILES-1].IOpuffer[0x1C6];
 gStartSectorH = gFiles[MAXFILES-1].IOpuffer[0x1C7];
 gStartSectorHL = gFiles[MAXFILES-1].IOpuffer[0x1C8];
 ReadSector(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
 }
 memcpy(&DiskInfo,gFiles[MAXFILES-1].IOpuffer,sizeof(DiskInfo));
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1;
 ReadSector(actsector,FATTable);
 gFAT32Vars.FATstartidx = 0;
 gFAT32Vars.gFirstDataSector = gFAT32Vars.gStartSector + DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1 - 2;
 
 for (i=0;i<MAXFILES;i++)
 {
 gFiles[i].Free = TRUE;
 }
 #ifdef ENABLE_FILELISTNG
 // Code for initializing file-listing
 for(i=0;i<MAX_FILE_LIST;i++)
 FileList[i].name = NULL;
 changeList = TRUE;
 #endif
 //   MMC_Debug("-FATInit ");
 }
 
 int32 GetNextCluster(int32 curcluster)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 if (clpage != gFAT32Vars.FATstartidx) // read in the requested page
 {
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 ReadSector(actsector,FATTable);
 gFAT32Vars.FATstartidx = clpage;
 }
 return (FATTable[clpos]);
 }
 
 void SetClusterEntry(int32 curcluster,int32 value)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 if (clpage != gFAT32Vars.FATstartidx)
 {
 ReadSector(actsector,FATTable);
 gFAT32Vars.FATstartidx = clpage;
 }
 FATTable[clpos] = value;
 WriteSector(actsector,FATTable);
 actsector += DiskInfo.hSectorsPerFat;
 WriteSector(actsector,FATTable);
 }
 
 void ClearClusterEntry(int32 curcluster)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 if (clpage != gFAT32Vars.FATstartidx)
 {
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
 WriteSector(actsector,FATTable);
 actsector += DiskInfo.hSectorsPerFat;
 WriteSector(actsector,FATTable);
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 ReadSector(actsector,FATTable);
 gFAT32Vars.FATstartidx = clpage;
 }
 FATTable[clpos] = 0;
 }
 
 int32 FindFirstFreeCluster()
 {
 int32 i,st,actsector,retval;
 char j;
 
 st = gFirstEmptyCluster;
 for (i=st;i<DiskInfo.hSectorsPerFat;i++)
 {
 if (i != gFAT32Vars.FATstartidx)
 {
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + i;
 ReadSector(actsector,FATTable);
 gFAT32Vars.FATstartidx = gFirstEmptyCluster = i;
 }
 for (j=0;j<128;j++)
 {
 if (FATTable[j] == 0)
 {
 retval = i;
 retval <<= 7;
 retval |= j;
 return retval;
 }
 }
 }
 return 0x0FFFFFFF;
 }
 
 // Function: Converts a dir-entry to a 8.3 filename
 void ConvertFilename(DIR *beDir,char *name)
 {
 char i,j,c;
 
 j = 0;
 name[0] = 0;
 for (i=0;i<8;i++)
 {
 c = beDir->sName[i];
 if (c == ' ')
 break;
 name[j++] = c;
 }
 for (i=0;i<3;i++)
 {
 c = beDir->spam[i];
 if (c == ' ' || c == 0)
 break;
 if (!i)
 name[j++] = '.';
 name[j++] = c;
 }
 name[j++] = 0;
 }
 
 // Function: Converts a dir-entry to a (part of a) long filename.
 //           One dir-entry can hold 13 unicode characters
 void ConvertLongFilename(DIR *beDir,char *name)
 {
 char i,j,c;
 
 j = 0;
 name[0] = 0;
 for (i=1;i<11;i+=2)
 {
 c = (char)(*(((char*)beDir)+i));
 if (c == 0x00 || c == 0xFF)
 break;
 name[j++] = c;
 }
 if(c!=0x00 && c!= 0xFF)
 {
 for (i=14;i<26;i+=2)
 {
 c = (char)(*(((char*)beDir)+i));;
 if (c == 0 || c == 0xFF)
 break;
 name[j++] = c;
 }
 if(c!=0x00 && c != 0xFF)
 {
 for (i=28;i<31;i+=2)
 {
 c = (char)(*(((char*)beDir)+i));
 if (c == 0 || c == 0xFF)
 break;
 name[j++] = c;
 }
 }
 }
 name[j++] = 0;
 }
 
 void GetDOSName(DIR *pDir, char *fname)
 {
 char i,j,leng,c,toext;
 
 toext = FALSE;
 j = 0;
 leng = strlen(fname);
 for (i=0;i<8;i++)
 pDir->sName[i] = ' ';
 for (i=0;i<3;i++)
 pDir->spam[i] = ' ';
 for (i=0;i<leng;i++)
 {
 c = fname[i];
 c = toupper(c);
 if (c == '.')
 {
 toext = TRUE;
 continue;
 }
 if (toext)
 pDir->spam[j++] = c;
 else
 pDir->sName[i] = c;
 }
 }
 
 // Function: Sets the file f to root dir
 MMCResponse ReadRootDirectory(char fil)
 {
 int32 actsector;
 
 if (fil > (MAXFILES-1))
 return MMC_INVALID_FILE;
 actsector = gFAT32Vars.gStartSector + DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1;
 ReadSector(actsector,gFiles[fil].IOpuffer);
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[fil].dirSector = actsector;
 gFiles[fil].dirIdx = 0;
 memcpy(&(gFiles[fil].DirEntry),gFiles[fil].IOpuffer,32);
 gFiles[fil].CurrentCluster = DiskInfo.hRootStartCluster;
 return MMC_OK;
 }
 
 // Funciton: Finds a file
 char FindDirEntry(char *fname,char f)
 {
 DIR *pDir;
 int16 i;
 char filename[16];
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1))
 {
 return FALSE;
 }
 gFAT32Vars.gFirstEmptyDirEntry = 0xFF;
 gFAT32Vars.gFirstDirEntryCluster = 0x0FFFFFFF;
 do
 {
 pDir = (DIR*)(gFiles[f].IOpuffer);
 for (i=0;i<DIRENTRYS_PER_SECTOR;i++)
 {
 if ((pDir->sName[0] == 0xE5 || pDir->sName[0] == 0) && gFAT32Vars.gFirstEmptyDirEntry == 0xFF) // store first free
 {
 gFAT32Vars.gFirstEmptyDirEntry = i;
 gFAT32Vars.gFirstDirEntryCluster = gFiles[f].CurrentCluster;
 }
 if (pDir->sName[0] == 0)
 {
 return FALSE;
 }
 ConvertFilename(pDir,filename);
 if (!strcmp(filename,fname))
 {
 memcpy(&(gFiles[f].DirEntry),pDir,32);
 gFiles[f].dirIdx = i;
 gFAT32Vars.gDirEntryIdx = i;
 return TRUE;
 }
 pDir++;
 }
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[f].dirSector = actsector;
 gFiles[f].CurrentCluster = nextcluster;
 }
 } while (nextcluster != 0x0FFFFFFF && nextcluster != 0);
 return FALSE;
 }
 
 // Function: Assign a filenumber(f) and open the directory
 //           where the file are and return the filename.
 char* TryFile(char *fname, char *f)
 {
 char i,leng;
 char *filename;
 
 *f = 0xFF;
 for (i=0;i<MAXFILES;i++)
 {
 if (gFiles[i].Free)
 {
 *f = i;
 break;
 }
 }
 if (*f == 0xFF)
 {
 return 0;
 }
 ReadRootDirectory(*f);
 filename = fname;
 leng = strlen(fname);
 for (i=0;i<leng;i++)
 {
 if (fname[i] == '/')
 {
 fname[i] = 0;
 if (!cwd(filename,*f))
 {
 gFiles[*f].Free = TRUE;
 return 0;
 }
 filename = fname+i+1;
 }
 }
 return filename;
 }
 
 void strfill(char *dest,char *source,int position)
 {
 char *d;
 for(d=dest+position; *source!=0; d++, source++)
 {
 *d = *source;
 }
 }
 
 // Parameters: path, the path to the directory you
 //             want to view
 // Function    : Initializes file/dir listing
 // Examples:
 // strcpy(path,""); // the "path" to the root directory
 // f = InitList(path);
 // ...
 // strcpy(path,"DIR3/DIR32/");
 // f = InitList(path);
 // if(InitList == MMC_OK)
 // {
 //   res = Listfiles(f);
 //   CloseList(f);
 // }
 #ifdef ENABLE_FILELISTNG
 MMCResponse InitList(char *path)
 {
 char f;
 if(TryFile(path,&f) == 0)
 {
 return MMC_NOT_FOUND;
 }
 gFiles[f].Free = FALSE;
 StartList.dirSector = gFiles[f].dirSector;
 StartList.CurrentCluster = gFiles[f].CurrentCluster;
 StartList.dirIdx = 0;
 CurrentList.dirSector = gFiles[f].dirSector;
 CurrentList.CurrentCluster = gFiles[f].CurrentCluster;
 CurrentList.dirIdx = 0;
 return f;
 }
 
 // Function: Lists a part (aka page) of the files in the directory
 //           specified by InitList()
 // Returns : The number of files/dirs that were listed
 int8 ListFiles(char f)
 {
 DIR *pDir;
 char filename[(CHARACTERS_IN_LONG_FILENAMES+1)]; // should be enough with 13+1
 char i,u,fni,len;
 BOOLEAN isLongFileName = FALSE;
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1))
 return 0;
 
 if(changeList)
 {
 FreeList();
 }
 
 if((gFiles[f].CurrentCluster != CurrentList.CurrentCluster) || (gFiles[f].dirSector != CurrentList.dirSector))
 {
 gFiles[f].dirSector = CurrentList.dirSector;
 gFiles[f].CurrentCluster = CurrentList.CurrentCluster;
 ReadSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
 }
 gFiles[f].dirIdx = CurrentList.dirIdx;
 
 
 u=0;
 do
 {
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*(int16)gFiles[f].dirIdx]));
 for (i=gFiles[f].dirIdx;i<DIRENTRYS_PER_SECTOR;i++) // loop throu all direntrys in the sector
 {
 if ((pDir->sName[0] != 0xE5 && pDir->sName[0] != 0)) // if file/dir isn't deleted and isn't the end of the directory
 {
 if(pDir->bAttr != 0x0F) // Normal filename (8.3)
 {
 if(isLongFilename) // If this is the short version of the long filename, just save the number
 {
 if(changeList)
 {
 FileList[u].shortName = malloc(13); // 8.3 = 8chars + '.' + 3chars + 0x00
 FileList[u].isLong = TRUE;
 ConvertFilename(pDir,filename);
 strcpy(FileList[u].shortName,filename); // copy the 8.3 name of the file
 }
 u++;
 isLongFilename = FALSE;
 if(u == MAX_FILE_LIST)
 {
 gFiles[f].dirIdx = i+1;
 return u;
 }
 }
 else // normal 8.3 filename
 {
 if(changeList)
 {
 ConvertFilename(pDir,filename);
 FileList[u].name = malloc(strlen(filename)+1); // +1 for char 0x00
 strcpy(FileList[u].name,filename);
 FileList[u].shortName = FileList[u].name; // point to same string
 FileList[u].isLong = FALSE;
 if(pDir->bAttr & 0x10) // is directory
 FileList[u].isDir = TRUE;
 else
 FileList[u].isDir = FALSE;
 }
 
 u++;
 if(u == MAX_FILE_LIST)
 {
 gFiles[f].dirIdx = i+1;
 return u;
 }
 }
 }
 else if((pDir->bAttr & 0x0F) == 0x0F) // If it is a long filename entry
 {
 fni = (pDir->sName[0] & 0x3F); // Filename Index
 if((pDir->sName[0] & 0x40)) // First LongFilename entry, the last characters of a long filename
 {
 if(changeList)
 {
 ConvertLongFilename(pDir,filename);
 len = strlen(filename)+CHARACTERS_IN_LONG_FILENAMES*(fni-1); // Length of the long filename
 FileList[u].name = malloc(len+1);// number of chars in this strinng + 13 in each other long filname entry
 FileList[u].name[len] = 0x00; // set last char to 0
 strfill(FileList[u].name,filename,(fni-1)*CHARACTERS_IN_LONG_FILENAMES); //Fills the name from position (fni-1)*13
 if(pDir->bAttr & 0x10) // is directory
 FileList[u].isDir = TRUE;
 else
 FileList[u].isDir = FALSE;
 }
 isLongFilename = TRUE;
 }
 else if((pDir->sName[0] & 0x80) == 0) // If it is a long filname, but not deleted
 {
 if(isLongfilename && changeList)
 {
 ConvertLongFilename(pDir,filename);
 strfill(FileList[u].name,filename,(fni-1)*CHARACTERS_IN_LONG_FILENAMES); //Fills the name from position (fni-1)*13
 }
 else
 printf(glcd_putc,"NoLongFileName!");
 }
 }
 }
 if (pDir->sName[0] == 0)
 {
 gFiles[f].dirIdx = END_OF_DIR;
 return u;
 }
 pDir++;
 }
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFiles[f].dirSector = actsector;
 gFiles[f].CurrentCluster = nextcluster;
 gFiles[f].dirIdx = 0;
 }
 } while (nextcluster != 0x0FFFFFFF && nextcluster != 0);
 gFiles[f].dirIdx = END_OF_DIR;
 return u;
 }
 
 // Function: Go to next page in the file/dir list
 // Returns : MMCResponse
 MMCResponse NextPage(char f)
 {
 int32 nextcluster,actsector;
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 
 CurrentList.dirSector = gFiles[f].dirSector;
 CurrentList.CurrentCluster = gFiles[f].CurrentCluster;
 
 if(gFiles[f].dirIdx == DIRENTRYS_PER_SECTOR)
 {
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 
 CurrentList.dirSector = actsector;
 CurrentList.CurrentCluster = nextcluster;
 CurrentList.dirIdx = 0;
 return MMC_OK;
 }
 return MMC_INVALID_CLUSTER;
 }
 else if(gFiles[f].dirIdx == END_OF_DIR)
 {
 return MMC_END_OF_DIR; // Last file/dir have already been listed by ListFiles
 }
 else
 {
 CurrentList.dirIdx = gFiles[f].dirIdx;
 }
 return MMC_OK;
 }
 
 // Note: 0 = first page
 MMCResponse SetPage(char f, int32 page)
 {
 int32 i;
 MMCResponse res;
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 
 CurrentList.dirSector = StartList.dirSector;
 CurrentList.CurrentCluster = StartList.CurrentCluster;
 CurrentList.dirIdx = StartList.dirIdx; // should always be 0
 
 changeList = FALSE; // this tells the ListFiles function to not change the list, just loop through files
 for(i=0;i<page;i++)
 {
 ListFiles(f);
 res = NextPage(f);
 if(res != MMC_OK)
 {
 changeList = TRUE;
 return res;
 }
 }
 changeList = TRUE;
 return MMC_OK;
 }
 
 MMCResponse CloseList(char f)
 {
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 gFiles[f].Free = TRUE;
 return MMC_OK;
 }
 
 void FreeList()
 {
 int i;
 for(i=0;i<MAX_FILE_LIST;i++)
 {
 if(FileList[i].isLong)           // If it is a long filename, name and short name are different string
 free(FileList[i].shortName); // then free both
 else
 FileList[i].shortName = NULL;
 free(FileList[i].name);          // else free ONLY name(they point to same string..)
 }
 }
 #endif// ENABLE_FILELISTNG
 
 // Function: Creates a file
 MMCResponse fcreate(char f,char *fname)
 {
 DIR *pDir;
 int32 actsector,actcl;
 int16 i;
 
 if (f > (MAXFILES-1))
 {
 return MMC_INVALID_FILE;
 }
 if (gFAT32Vars.gFirstDirEntryCluster == 0x0FFFFFFF)
 {
 // extend the directory file !!!
 gFAT32Vars.gFirstDirEntryCluster = FindFirstFreeCluster();
 gFAT32Vars.gFirstEmptyDirEntry = 0;
 SetClusterEntry(gFiles[f].CurrentCluster,gFAT32Vars.gFirstDirEntryCluster);
 SetClusterEntry(gFAT32Vars.gFirstDirEntryCluster,0x0FFFFFFF);
 actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
 for (i=0;i<512;i++)
 gFiles[f].IOpuffer[i] = 0;
 WriteSector(actsector,gFiles[f].IOpuffer);
 }
 actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*(int16)gFAT32Vars.gFirstEmptyDirEntry]));
 gFiles[f].dirSector = actsector;
 gFiles[f].dirIdx = gFAT32Vars.gFirstEmptyDirEntry;
 GetDOSName(pDir,fname);
 pDir->bAttr = 0;
 actcl = FindFirstFreeCluster();
 pDir->hCluster = actcl & 0xFFFF;
 pDir->hClusterH = actcl >> 16;
 SetClusterEntry(actcl,0x0FFFFFFF);
 pDir->wSize = 0;
 gFiles[f].position = 0;
 pDir->hDate = GetCurrentDOSDate();
 pDir->hTime = GetCurrentDOSTime();
 WriteSector(actsector,gFiles[f].IOpuffer);
 memcpy(&(gFiles[f].DirEntry),pDir,32);
 return MMC_OK;
 }
 
 int32 ComposeCluster(char f)
 {
 int32 retval;
 
 retval = gFiles[f].DirEntry.hClusterH;
 retval <<= 16;
 retval |= gFiles[f].DirEntry.hCluster;
 return retval;
 }
 
 // Function: Opens a file with the specified mode
 // Returns : A file handle or error code
 MMCResponse fopen(char *fname, char mode)
 {
 char found;
 char f;
 int32 actsector,actcluster,nextcluster;
 char *filename;
 
 if (!CardInserted())
 return MMC_NO_CARD_INSERTED;
 
 filename = TryFile(fname,&f);
 if (filename == 0)
 {
 return MMC_NOT_FOUND; // probebly invalid directory
 }
 found = FALSE;
 found = FindDirEntry(filename,f);
 
 if (!found)
 {
 if (mode == 'r')
 {
 gFiles[f].Free = TRUE;
 return MMC_NOT_FOUND;
 }
 else
 {
 if (fcreate(f,filename) != MMC_OK)
 return MMC_NOT_FOUND;
 found = TRUE;
 }
 }
 if (found)
 {
 gFiles[f].Free = FALSE;
 gFiles[f].mode = mode;
 if  (mode == 'a')
 {
 gFiles[f].position = gFiles[f].DirEntry.wSize;
 actcluster = ComposeCluster(f);
 while (actcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 nextcluster = GetNextCluster(actcluster);
 if (nextcluster == 0x0FFFFFFF || nextcluster == 0)
 break;
 actcluster = nextcluster;
 }
 actsector = actcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFiles[f].CurrentCluster = actcluster;
 gFiles[f].posinsector = gFiles[f].position & 0x01FF;
 if (gFiles[f].posinsector == 0 && gFiles[f].position != 0)
 gFiles[f].posinsector = 512;
 }
 else
 {
 gFiles[f].position = 0;
 actsector = ComposeCluster(f);
 actsector += gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFiles[f].CurrentCluster = ComposeCluster(f);
 gFiles[f].posinsector = 0;
 }
 }
 return f;
 }
 
 // Function: closes a open file and makes it avavible for a new file
 MMCResponse fclose(char f)
 {
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 if ((gFiles[f].mode == 'a') || (gFiles[f].mode == 'w'))
 fflush(f);
 gFiles[f].Free = TRUE;
 return MMC_OK;
 }
 
 // Function: writes the chach to the MMC
 MMCResponse fflush(char f)
 {
 int32 actsector;
 DIR *pDir;
 
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
 WriteSector(actsector,gFiles[f].IOpuffer);
 ReadSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFiles[f].dirIdx]));
 if (gFiles[f].DirEntry.bAttr & 0x10)  // if it is a directory
 pDir->wSize = 0;
 else
 pDir->wSize = gFiles[f].position;
 pDir->hDate = GetCurrentDOSDate();
 pDir->hTime = GetCurrentDOSTime();
 WriteSector(gFiles[f].dirSector,gFiles[f].IOpuffer);
 ReadSector(actsector,gFiles[f].IOpuffer);
 return MMC_OK;
 }
 
 // Function: Enter a specified directory
 char cwd(char *fname, char f)
 {
 int32 actsector;
 if (f > (MAXFILES-1))
 {
 return FALSE; // just in case of overaddressing
 }
 if (IsSelfDir(fname))
 {
 return TRUE; // already in Root dir
 }
 if (!FindDirEntry(fname,f))
 {
 return FALSE; // not found
 }
 
 actsector = ComposeCluster(f);
 actsector += gFAT32Vars.gFirstDataSector; // read current dir
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[f].dirSector = actsector;
 gFiles[f].CurrentCluster = ComposeCluster(f);
 
 return TRUE;
 }
 
 // Function: Put a char to the open file
 MMCResponse fputch(char be, char f)
 {
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 if (gFiles[f].posinsector == 512)
 {
 actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
 WriteSector(actsector,gFiles[f].IOpuffer);
 nextcluster = FindFirstFreeCluster();
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 SetClusterEntry(gFiles[f].CurrentCluster,nextcluster);
 SetClusterEntry(nextcluster,0x0FFFFFFF);
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFiles[f].CurrentCluster = nextcluster;
 gFiles[f].posinsector = 0;
 }
 }
 gFiles[f].IOpuffer[gFiles[f].posinsector] = be;
 gFiles[f].posinsector++;
 gFiles[f].position++;
 return MMC_OK;
 }
 
 // Function: Puts a string to the open file
 MMCResponse fputstring(char *be, char f)
 {
 int16 leng,i;
 
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 leng = strlen(be);
 for (i=0;i<leng;i++)
 fputch(be[i],f);
 return MMC_OK;
 }
 
 // Function: Read a buffer from the open file
 int16 fread(char *buffer, int16 leng, char f)
 {
 int16 i,retv;
 char c,v;
 
 if (f > (MAXFILES-1))
 return 0;
 retv = 0;
 for (i=0;i<leng;i++)
 {
 v = fgetch(&c,f);
 if (v == MMC_OK)
 {
 buffer[i] = c;
 retv++;
 }
 else
 break;
 }
 return retv;
 }
 
 // Function: Write a buffer to the open file
 MMCResponse fwrite(char *buffer, int16 leng, char f)
 {
 int16 i;
 
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 for (i=0;i<leng;i++)
 fputch(buffer[i],f);
 return MMC_OK;
 }
 
 // Function: Read a char from the open file
 MMCResponse fgetch(char *ki,char f)
 {
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1))
 return MMC_INVALID_FILE;
 if (gFiles[f].position >= gFiles[f].DirEntry.wSize)
 return MMC_INVALID_POSITION;
 *ki = gFiles[f].IOpuffer[gFiles[f].posinsector];
 gFiles[f].posinsector++;
 gFiles[f].position++;
 if (gFiles[f].posinsector == 512)
 {
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 ReadSector(actsector,gFiles[f].IOpuffer);
 gFiles[f].CurrentCluster = nextcluster;
 gFiles[f].posinsector = 0;
 }
 }
 return MMC_OK;
 }
 
 // Function: Removes a file
 MMCResponse remove(char *fname)
 {
 char i,found;
 char f;
 DIR *pDir;
 int32 nextcluster,currentcluster;
 char *filename;
 
 filename = TryFile(fname,&f);
 if (filename == 0)
 return MMC_NOT_FOUND;
 found = FindDirEntry(filename,f);
 if (!found)
 {
 gFiles[f].Free = TRUE;
 return MMC_NOT_FOUND;
 }
 
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*(int16)gFAT32Vars.gDirEntryIdx]));
 pDir->sName[0] = 0xE5;
 for (i=1;i<8;i++)
 pDir->sName[i] = ' ';
 for (i=0;i<3;i++)
 pDir->spam[i] = ' ';
 WriteSector(gFAT32Vars.gDirEntrySector,gFiles[f].IOpuffer);
 currentcluster = ComposeCluster(f);
 while (currentcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 nextcluster = GetNextCluster(currentcluster);
 ClearClusterEntry(currentcluster);
 currentcluster = nextcluster;
 }
 ClearClusterEntry(currentcluster);
 SetClusterEntry(currentcluster,0);
 currentcluster = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
 WriteSector(currentcluster,FATTable);
 currentcluster += DiskInfo.hSectorsPerFat;
 WriteSector(currentcluster,FATTable);
 gFiles[f].Free = TRUE;
 
 return MMC_OK;
 }
 
 
 // Function: Gets the size of a file
 MMCResponse getfsize(char *fname, int32 *fsiz)
 {
 char found;
 char f;
 DIR *pDir;
 char *filename;
 
 filename = TryFile(fname,&f);
 if (filename == 0)
 return MMC_NOT_FOUND;
 found = FindDirEntry(filename,f);
 if (!found)
 {
 gFiles[f].Free = TRUE;
 return MMC_NOT_FOUND;
 }
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*(Int16)gFAT32Vars.gDirEntryIdx]));
 gFiles[f].Free = TRUE;
 *fsiz = pDir->wSize;
 return MMC_OK;
 }
 
 | 
 
 Note: You can list long filenames, but you can not directly open them with fopen, not yet, instead use their short version of the name.. read text in MMC_SPI_FAT32.c for more info.
 I have not tested hardware SPI with this code yet, but it should work. I will test it in the future...
 
 Code is tested with a 128MB Multi Media Card from vivanco.
 
 This code is for Multi media cards, I do not know anything about SD cards, but maby it will work for them too, with some minor changes..
 
 Hope you will get use of this code and please post a comment of what you think about it, or if you got any suggestions. Maby I will update it sometime.
 
 Enjoy!
 /miniman
 
 Last edited by Miniman on Wed Aug 15, 2007 3:55 am; edited 1 time in total
 |  |  
		|  |  
		| M.Akmal 
 
 
 Joined: 02 Aug 2007
 Posts: 4
 
 
 
			    
 
 | 
			
				| problem in fat32 |  
				|  Posted: Fri Aug 03, 2007 12:06 pm |   |  
				| 
 |  
				| Hi I work on ur code but when i run  it there were errors
 and also there was an run time exception like "SSPBUF is used whilest master mode is on, data is ignored" wt is reason of it?
 then again i change it myself it runs but not working correctly. i m giving you ur code with my changings please help me why it is not working correctly........... I think you send AddressL,AddressH,AddressLH to mmcout() but i m not doing so because my method of initializing is different.......And also i change readsector() and writesector() to read_BLOCK() and write_BLOCK() functions.............please correct my difficiency................... please do this urgently...................................
 thanx in advance...please reply with detailed explanation...............here is code with changings...........
 
  	  | Code: |  	  | 
 #include <18F4620.h>
 #include "MyMMCFat32.h"
 #include<string.h>
 #include "my6720.h"
 
 #use delay(clock=8M, oscillator)
 #use rs232(baud=19200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
 #use i2c(Master,sda=PIN_C4,scl=PIN_C3)
 #use spi(DI=PIN_C4, DO=PIN_C5, CLK=PIN_C3, BITS=8,MSB_FIRST)
 
 //******************************** using pic 18F452*************************************
 /*  #DEFINE SSPSTAT 0x0FC7        // DECIMAL = 4039 =111111000111
 //#DEFINE SSPCON1 0x0FC6         // DECIMAL = 4038 = 111111000110
 #BIT SMP=SSPSTAT.7           // BIT =1
 #BIT CKE=SSPSTAT.6          // BIT =1
 #BIT CKP=SSPCON1.4          // BIT = 0
 #byte SSPBUF = 0xFC9
 #bit  BF  = SSPSTAT.0
 #byte SSPCON1= 0xFC6*/
 
 typedef struct     {
 unsigned long    tm_year;
 char            tm_mon;
 char            tm_day;
 char            tm_mday;
 char            tm_hour;
 char            tm_min;
 char            tm_sec;
 }    TimeRecord;
 TimeRecord myrec; // this variable is updated in regular intervals //in DoIdle()
 //////////////////////////////////// function declaration ///////////////////////////////////////////
 int MMCInit(int);
 int read_BLOCK( int32 , char *);
 int set_BLOCKLEN( int32 );
 int write_BLOCK (int32 , char *, int16);
 
 
 void InitFAT();
 char FindDirEntry(char *fname, char f);
 
 char fopen(char *fname, char mode);
 void fclose(char f);
 void fflush(char f);
 char cwd(char *fname, char f);
 void fputch(char be, char f);
 char fgetch(char *ki, char f);
 void fputstring(char *be, char f); // fputs is reserved in CCS C
 int16 fread(char *buffer, int16 leng, char f);
 void fwrite(char *buffer, int16 leng, char f);
 char remove(char *fname);
 char getfsize(char *fname, int32 *fsiz);
 
 
 
 int32 FATTable[128];
 int32 gFirstEmptyCluster;
 
 FAT32Vars gFAT32Vars;
 diskinforec DiskInfo;
 FILE gFiles[MAXFILES];
 
 
 ////////////////////////////////////////// declaration variables  ////////////////////////////////
 #byte MMCAddressL = gFAT32Vars
 #byte MMCAddressH = gFAT32Vars+1
 #byte MMCAddressHL = gFAT32Vars+2
 #byte MMCAddressHH = gFAT32Vars+3
 #byte gStartSectorL = gFAT32Vars+8
 #byte gStartSectorH = gFAT32Vars+9
 #byte gStartSectorHL = gFAT32Vars+10
 
 //#locate FATTable = 0x0800
 //#locate gFiles = 0x0A00
 //#locate gFAT32Vars = 0x0E70
 //#locate DiskInfo = 0x0E90
 
 int32 block_size;               // current MMC block size
 
 #use FAST_IO(C)
 #define  _CS PIN_C2    // chip select for MMC
 
 #define ChipSel pin_c2
 #define ChipClk pin_c3
 #define ChipDin pin_c5
 #define chipDout PIN_C4
 
 #define CardInserted PIN_A4 // these pins are already defined in my main C file
 //#define REDLED PIN_E7
 //#define YELLOWLED PIN_E6 // remove comments or comment out lines containing YELLOWLED refs in this    //file
 //#define GREENLED PIN_E5
 
 /////////////////////////////////////// isselfdir function defination  /////////////////////////////////////
 
 char IsSelfDir(char *be)
 {
 if (be[0] == '.' && be[1] == '.') return 0xFF;
 else return 0;
 }
 
 //////////////////////////////////// end of  IsSelfDir() ////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 void MMC8Clock()
 {
 char i;
 SSPBUF=0xFF;
 
 while (!BF);
 i = SSPBUF;
 }
 
 //////////////////////////////////// end of MMC8Clock() ////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 //////////////////////////////start of send command to mmc function////////////////////////
 //*****************************************************************************************
 
 int16 mmc_cmd(int8 cmd,int32 address,int8 tries,int8 valid,int8 invalid)
 {
 // arguments sent to this function from init_mmc()
 //for cmd0*********************** 0x40,0x00000000,128,0x01,0x99
 //For cmd1*********************** 0x41,0x00000000,128,0x00,0x99
 // for setting block length ************************0x50,size,16,0x00,0x40
 
 int i,r1;
 for( i=0;i<16;i++) SPI_READ(0xFF);// digest prior operation
 
 // commands
 // 7 6 5 4 3 2 1 0
 // 0 1 b b b b b b    bbbbbb=cmd
 // 16=0x50 set blocklength
 // 17=0x51 read block
 // 24=0x58 write block
 
 printf("\n\n cmd=%2X \n\r",cmd);
 output_high(PIN_C6);
 
 
 SPI_READ(cmd);
 // address of command is of 32 bits i-e 4 bytes ,below will separate every byte.
 SPI_READ(MAKE8(address,3));
 SPI_READ(MAKE8(address,2));
 SPI_READ(MAKE8(address,1));
 SPI_READ(MAKE8(address,0));
 SPI_READ(0x95);
 
 
 
 // card comes up in MMC mode and requires a valid MMC cmd to switch to SPI mode
 // valid crc for MMC 0x40 cmd only
 // spi mode doesn't require the CRC to be correct just there
 
 
 
 for(i=0;i< tries;i++)
 {
 r1=SPI_READ(0xFF);
 printf("\n \n r1=%2X",r1);
 output_high(PIN_C6);
 
 if (r1==valid)
 {
 printf(" \n \n i m valid \t %2X",r1);
 output_high(PIN_C6);
 
 break;
 }
 if (r1==invalid)
 {
 printf("\n \n i m invalid \t %2X",r1);
 output_high(PIN_C6);
 
 break;
 }
 }
 
 return(r1);
 }
 //////////////////////////////////////////////end of mmc_cmd()//////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 int MMCInit(int max_tries)
 {
 int i,tries,c,v;
 int32 start_lsec=0;
 char buff[512];
 
 printf("\n\n\n initializing MMC...\r");
 output_high(PIN_C6);
 
 
 ////////////////////////////// cmdo command sending //////////////////////////////
 
 cmd0:
 // place null treminators in globals fname and buff  ---> i m not understanding
 
 printf("i m in cmd0...\r");
 output_high(PIN_C6);
 
 output_high(PIN_C2);   /// reset chip hardware !!! required
 delay_ms(20);
 
 for(i=0;i<20;i++)
 {
 v =  SPI_READ(0xFF); // min 80 clocks to get MMC ready 0xFF=255=11111111
 printf("v ====%2X",v);
 output_high(PIN_C6);
 }
 
 // host starts the bus transaction by CS signal low.
 output_low(PIN_C2);   ///                      !!! required
 delay_ms(20);
 
 c=mmc_cmd(0x40,0x00000000,128,0x01,0x99);
 printf(" c---------------------=%2X",c);
 output_high(PIN_C6);
 
 if (c==0x01)
 {
 printf("\n CMD0 successful");
 output_high(PIN_C6);
 
 goto exit_cmd1;
 }
 // note: it must cycle at least 8 times (16 is safe )
 
 if (tries++<max_tries) goto cmd0;  /// restart
 
 else
 {
 printf("\n I m returning ");
 output_high(PIN_C6);
 
 return (10);
 }
 
 exit_cmd1:
 
 // CPDMOD - This SOMETIMES seems to be necessary
 // output_high(_CS);
 // SPI_READ(0xFF); // min 8 clocks to get MMC ready
 // output_low(_CS);
 //CPDMOD End
 
 
 printf("   I m exiting \n \r");
 output_high(PIN_C6);
 
 tries=0;
 
 ///////////////////////////// cmd1 command sending ////////////////////////////////////
 
 cmd1:
 
 printf(" \n  cmd1 starts here  \n \r");
 output_high(PIN_C6);
 
 /// now try  to switch to idle mode
 /// Note: cmd1(idle) is the only command allowed after a cmd0(reset)
 
 c=mmc_cmd(0x41,0x00000000,128,0x00,0x99);
 if (c==0x00)
 {
 printf("\n \n CMD1 successful   \r");
 output_high(PIN_C6);
 
 goto ready;
 }
 
 
 if( tries++<max_tries) { printf("cmd1"); goto cmd1;}
 else return(11);
 
 ready:
 
 for( i=0;i<32;i++) SPI_READ(0xFF);// digest operation
 
 /// MMC is inialized and in idle state ready for commands
 
 //// we need to first access the master boot sector physical address=0
 
 printf(" \n \n I m ready    \r");
 output_high(PIN_C6);
 }
 
 
 //////////////////////////////////// end of MMCInit() ////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 int16 GetCurrentDOSDate()
 {
 int16 retval;
 
 retval = myrec.tm_year - 1980;
 retval <<= 9;
 retval |= ((int16)myrec.tm_mon << 5);
 retval |= (int16)myrec.tm_mday;
 return retval;
 }
 
 //////////////////////////////////// end of getcurrentdosdate() ////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 int16 GetCurrentDOSTime()
 {
 int16 retval;
 
 retval = myrec.tm_hour;
 retval <<= 11;
 retval |= ((int16)myrec.tm_min << 5);
 retval |= (int16)myrec.tm_sec >> 1;
 return retval;
 }
 
 //////////////////////////////////// end of getcurrentdostime() ////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////
 
 //**************************setting block length****************************************
 
 
 int set_BLOCKLEN( int32 size)
 {
 int r1;
 printf(" \n \nin argument passing value  %lu ",size);
 
 r1=mmc_cmd(0x50,size,16,0x00,0x40); /// cmd,data,tries,valid code,invalid code
 
 if (r1==0x00)
 {
 printf("\n\n block length is set \r");
 output_high(PIN_C6);
 
 goto done ;
 }
 
 if (r1==0x40) goto invalid;
 
 return(false);
 
 invalid:
 
 
 printf("\n\r para err\n\r");
 output_high(PIN_C6);
 
 return (false);
 
 done:
 
 block_size=size; //// assign global block size
 return(true);
 
 }
 //////////////////////////////////////////////////////////end set_BLOCKLEN()////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 //*******************************reading blocks  ***************************************
 
 int read_BLOCK( int32 sector, char *buff)
 {
 //// low level read ..requires block len to be called first to set global blocksize
 
 int r1;
 long i,iw; /// allows large gt 255 buff size addressing
 
 
 
 #byte sectorL = sector
 #byte sectorH = sector+1
 #byte sectorHL = sector+2
 
 //if (input(CardInserted)) return;
 
 Disable_interrupts(GLOBAL);
 Restart_wdt();
 
 MMCAddressL = 0;
 MMCAddressH = sectorL;
 MMCAddressHL = sectorH;
 MMCAddressHH = sectorHL;
 gFAT32Vars.MMCAddress <<= 1;
 
 output_low(ChipClk);
 output_low(ChipSel);
 
 
 if(set_BLOCKLEN((int32)512)==false)
 {printf("error in setting block length");}
 
 r1=mmc_cmd(0x51,sector,16,0x00,0x40);
 
 if (r1==0x00) goto get_token ; // we can read data payload
 if (r1==0x40) goto invalid;
 
 
 printf("\n\r read block err 1 address=%lu \n\r",sector);
 output_high(PIN_C6);
 
 return(false);
 
 invalid:
 
 
 printf("\n\n read block err 2 adress=%lu \n\r",sector);
 output_high(PIN_C6);
 
 return(false);
 
 get_token:
 
 for(iw=0;iw<1024;iw++)
 {
 r1=SPI_READ(0xFF);
 
 if (r1==0xFE)
 {
 printf("\n\n i m going to read data \r");
 output_high(PIN_C6);
 
 goto read_data; // read token $FE
 }
 }
 
 
 printf("\n\r read block err 3 address=%lu \n\r",sector);
 output_high(PIN_C6);
 return(false);
 
 read_data:
 
 printf("\n\r read block tries for FE =%lu \n\r",iw);
 output_high(PIN_C6);
 
 for (i=0;i<block_size;i++)
 {
 buff[i]=SPI_READ(0xFF);
 printf("\n\n %2X \n\n",buff[i]);
 output_high(PIN_C6);
 }
 
 SPI_READ(0xFF); // read crc
 SPI_READ(0xFF);
 
 Enable_interrupts(GLOBAL);
 
 return(true);
 }
 //////////////////////////////////////end of read_BLOCK()//////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////
 
 int write_BLOCK( int32 address,char *buff,int16 size)  //DATA_AREA_ADDRESS ,i m muslim , 256
 {
 /// low level write ....MMC restriction is that exactly 512 bytes must be written
 /// so a 512 byte section is read in starting at address the first (size) bytes
 /// are over written with the new data and the updated 512 bytes written back
 /// the starting address of the block that contains the requeseted address
 
 /// the data may span a block if so it is split and two writes are done
 /// so as to maitain MMC 512 write boundary restrictions
 
 int r1,a,b,c,d;
 int16 i,blk_offset,bytes_posted;
 char tmp_buff[512];
 int32 block_address;
 
 #byte sectorL = address
 #byte sectorH = address+1
 #byte sectorHL = address+2
 
 
 Disable_interrupts(GLOBAL);
 
 Restart_wdt();
 
 MMCAddressL = 0;
 MMCAddressH = sectorL;
 MMCAddressHL = sectorH;
 MMCAddressHH = sectorHL;
 gFAT32Vars.MMCAddress <<= 1;
 
 a=make8(address,3);
 b=make8(address,2);
 c=make8(address,1);
 c=c & 0b11111110;
 d=0;          // confusion is it for offset
 
 block_address=make32(a,b,c,d);  //// address int divided by 512
 printf("block_address in decimal \t %lu",block_address);
 
 
 printf("wb>> size=%lu payload=",size);
 for(i=0;i<size;i++)printf("%c",buff[i]);
 
 
 /// first set up the block size to 512
 if(set_BLOCKLEN((int32)512)==false) return(false);  // sets global block_size
 
 if(block_size!=512)
 {
 printf("block length not set");
 return(false);
 }
 
 bytes_posted=0; /// no data updated yet
 
 
 next_block:     /// loop back here for second block
 
 printf("\n\r BLOCK ADDRESS ON WHICH TO WRITE=%lu \n\r",block_address);
 
 printf("read blk");
 
 
 /// first read in the existing block IN TO WHICH WE WANT TO WRITE
 if(read_BLOCK(block_address,tmp_buff)==false) return(false) ;
 
 
 
 /// now update the block with new data
 blk_offset=(address - block_address); /// offset within the block
 
 printf(" \n blk_offset WITH IN THE BLOCK=%lu size=%lu",blk_offset,size);
 
 
 if( blk_offset + size > 512 )  // 0 + 256 > 512
 {
 printf("i m in if block");
 printf("data range is in the block size");
 // data spans the block so write to end of block first
 
 //// original data
 printf("\n\r spans wb=");
 for(i=blk_offset;i<512;i++)printf("%c",tmp_buff[i]);
 
 for (i=blk_offset;i < 512;i++)tmp_buff[i]=buff[i-blk_offset];
 
 /// updated data
 printf("\n\r spans wb*=");
 for(i=blk_offset;i<512;i++)printf("%c",tmp_buff[i]);
 
 bytes_posted=512-blk_offset; /// wrote from offset to end of block
 printf("\n\r posted=%lu",bytes_posted);
 
 }
 else
 {
 printf("i m in else block");
 //original or remaining spanned block data fits in next block or original block
 
 printf(" blk offset=%lu",blk_offset);
 
 /// original data
 //checking tmp_buffer
 
 printf("\n\r wb=");
 for(i=blk_offset;i<blk_offset+size;i++)printf("%c",tmp_buff[i]); // for(0 ;_<11;0++)
 
 for (i=blk_offset;i<blk_offset+ size;i++)tmp_buff[i]=buff[bytes_posted+i-blk_offset];
 
 /// updated data
 printf("\n\r wb*=");
 for(i=blk_offset;i<blk_offset+size;i++)printf("%c",tmp_buff[i]);
 
 bytes_posted=size;
 printf("\n\r posted=%lu",bytes_posted);
 
 }
 
 //////////////////////////////////////////////////////////////////////
 /////////// write out the block
 /////////////////////////////////////////////////////////////////////
 
 
 printf("wb>> writing block %lu",block_address);
 
 r1=mmc_cmd(0x58,block_address,16,0x00,0x40);
 
 if (r1==0x00)
 {
 printf("i m goimg for sending token");
 goto send_token ; // we can send data payload
 }
 if (r1==0x40) goto invalid;
 
 return(false);
 
 invalid:
 
 printf("\n\r write block err %2X\n\r",r1);
 return(false);
 
 send_token:
 
 SPI_READ(0xFE);
 
 for (i=0;i < 512;i++)
 {
 SPI_READ(tmp_buff[i]);  /// send payload
 }
 
 
 SPI_READ(0xFF); // send dummy chcksum
 SPI_READ(0xFF);
 r1=SPI_READ(0xFF);
 
 for( i=0;i<0x0fff;i++)
 {
 printf("digest prior operation");
 r1=SPI_READ(0xFF);// digest prior operation
 if (r1!=0x00) break;
 }
 
 if(size > bytes_posted)
 {
 /// data spanned block so we need to upadte next block as well
 size=size-bytes_posted;
 block_address=block_address+512;/// advance a block
 
 address=address+bytes_posted; /// move address ptr forward
 
 goto next_block;
 }
 
 Enable_interrupts(GLOBAL);
 return(true);
 }
 
 ///////////////////////////end of write_BLOCK()/////////////////////////////
 ///////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////
 
 
 void InitFAT()
 {
 int32 actsector;
 char i;
 
 gFirstEmptyCluster = 0;
 gFAT32Vars.gStartSector = 0;
 
 read_BLOCK(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
 
 if (gFiles[MAXFILES-1].IOpuffer[0] != 0xEB)
 {
 gStartSectorL = gFiles[MAXFILES-1].IOpuffer[0x1C6];
 gStartSectorH = gFiles[MAXFILES-1].IOpuffer[0x1C7];
 gStartSectorHL = gFiles[MAXFILES-1].IOpuffer[0x1C8];
 
 read_BLOCK(gFAT32Vars.gStartSector,gFiles[MAXFILES-1].IOpuffer);
 }
 
 memcpy(&DiskInfo,gFiles[MAXFILES-1].IOpuffer,sizeof(DiskInfo));
 
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1;
 
 read_BLOCK(actsector,FATTable);
 
 gFAT32Vars.FATstartidx = 0;
 gFAT32Vars.gFirstDataSector = gFAT32Vars.gStartSector +DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1 - 2;
 
 for (i=0;i<MAXFILES;i++)
 gFiles[i].Free = TRUE;
 }
 
 //////////////////////////////////////////////end of   InitFAT()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 int32 GetNextCluster(int32 curcluster)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 
 if (clpage != gFAT32Vars.FATstartidx)
 {    // read in the requested page
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 
 read_BLOCK(actsector,FATTable);
 
 gFAT32Vars.FATstartidx = clpage;
 }
 
 return (FATTable[clpos]);
 }
 
 
 //////////////////////////////////////////////end of   GetNextCluster()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 void SetClusterEntry(int32 curcluster,int32 value)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 
 if (clpage != gFAT32Vars.FATstartidx)
 {
 read_BLOCK(actsector,FATTable);
 gFAT32Vars.FATstartidx = clpage;
 }
 
 FATTable[clpos] = value;
 write_BLOCK(actsector,FATTable,512);
 actsector += DiskInfo.hSectorsPerFat;
 
 write_BLOCK(actsector,FATTable,512);
 }
 
 
 
 //////////////////////////////////////////////end of   SetClusterEntry()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 void ClearClusterEntry(int32 curcluster)
 {
 int32 actsector;
 int32 clpage;
 char clpos;
 
 clpage = curcluster >> 7;
 clpos = curcluster & 0x7F;
 
 if (clpage != gFAT32Vars.FATstartidx)
 {
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
 
 write_BLOCK(actsector,FATTable,512);
 
 actsector += DiskInfo.hSectorsPerFat;
 
 write_BLOCK(actsector,FATTable,512);
 
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + clpage;
 
 read_BLOCK(actsector,FATTable);
 
 gFAT32Vars.FATstartidx = clpage;
 }
 
 FATTable[clpos] = 0;
 }
 
 
 //////////////////////////////////////////////end of  ClearClusterEntry()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 int32 FindFirstFreeCluster()
 {
 int32 i,st,actsector,retval;
 char j;
 
 st = gFirstEmptyCluster;
 
 for (i=st;i<DiskInfo.hSectorsPerFat;i++)
 {
 if (i != gFAT32Vars.FATstartidx)
 {
 actsector = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + i;
 
 read_BLOCK(actsector,FATTable);
 
 gFAT32Vars.FATstartidx = gFirstEmptyCluster = i;
 }
 
 for (j=0;j<128;j++)
 if (FATTable[j] == 0)
 {
 retval = i;
 retval <<= 7;
 retval |= j;
 return retval;
 }
 }
 return 0x0FFFFFFF;
 }
 
 
 //////////////////////////////////////////////end of  FindFirstFreeCluster()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 void ConvertFilename(DIR *beDir,char *name)
 {
 char i,j,c;
 
 j = 0;
 name[0] = 0;
 
 for (i=0;i<8;i++)
 {
 c = beDir->sName[i];
 
 if (c == ' ') break;
 
 name[j++] = c;
 }
 
 for (i=0;i<3;i++)
 {
 c = beDir->spam[i];
 
 if (c == ' ' || c == 0) break;
 
 if (!i) name[j++] = '.';
 name[j++] = c;
 }
 name[j++] = 0;
 }
 
 
 
 //////////////////////////////////////////////end of ConvertFilename()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 void GetDOSName(DIR *pDir, char *fname)
 {
 char i,j,leng,c,toext;
 
 toext = FALSE;
 j = 0;
 leng = strlen(fname);
 
 for (i=0;i<8;i++)
 pDir->sName[i] = ' ';
 
 for (i=0;i<3;i++)
 pDir->spam[i] = ' ';
 
 for (i=0;i<leng;i++)
 {
 c = fname[i];
 c = toupper(c);
 
 if (c == '.')
 {
 toext = TRUE;
 continue;
 }
 
 if (toext) pDir->spam[j++] = c;
 else pDir->sName[i] = c;
 }
 }
 
 
 
 ///////////////////////////////end of GetDOSName//////////////////////////////////////
 /////////////////////////////////////////////////////////////////////////////////////
 
 void ReadRootDirectory(char fil)
 {
 int32 actsector;
 
 if (fil > (MAXFILES-1)) return;
 
 actsector = gFAT32Vars.gStartSector + DiskInfo.FATCopies*DiskInfo.hSectorsPerFat+DiskInfo.Reserved1;
 
 read_BLOCK(actsector,gFiles[fil].IOpuffer);
 
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[fil].dirSector = actsector;
 gFiles[fil].dirIdx = 0;
 
 memcpy(&(gFiles[fil].DirEntry),gFiles[fil].IOpuffer,32);
 
 gFiles[fil].CurrentCluster = DiskInfo.hRootStartCluster;
 }
 
 
 //////////////////////////////////////////////end of GetDOSName()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 char FindDirEntry(char *fname,char f)
 {
 DIR *pDir;
 int16 i;
 char filename[16];
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1)) return FALSE;
 
 gFAT32Vars.gFirstEmptyDirEntry = 0xFFFF;
 gFAT32Vars.gFirstDirEntryCluster = 0x0FFFFFFF;
 
 do    ////start of do while
 {
 pDir = (DIR*)(gFiles[f].IOpuffer);
 
 for (i=0;i<16;i++)
 {
 if ((pDir->sName[0] == 0xE5 || pDir->sName[0] == 0) && gFAT32Vars.gFirstEmptyDirEntry == 0xFFFF)
 {
 // store first free
 gFAT32Vars.gFirstEmptyDirEntry = i;
 gFAT32Vars.gFirstDirEntryCluster = gFiles[f].CurrentCluster;
 }
 
 if (pDir->sName[0] == 0)  return FALSE;
 
 ConvertFilename(pDir,filename);
 
 if (!strcmp(filename,fname))
 {
 memcpy(&(gFiles[f].DirEntry),pDir,32);
 
 gFiles[f].dirIdx = i;
 gFAT32Vars.gDirEntryIdx = i;
 return TRUE;
 }
 
 pDir++;
 }
 
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[f].dirSector = actsector;
 gFiles[f].CurrentCluster = nextcluster;
 }
 
 }   ////end of do while
 while (nextcluster != 0x0FFFFFFF && nextcluster != 0);
 
 return FALSE;
 }
 
 
 //////////////////////////////////////////////end of FindDirEntry()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 // file I/O routines
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 char* TryFile(char *fname, char *f)
 {
 char i,leng;
 char *filename;
 
 *f = 0xFF;
 
 for (i=0;i<MAXFILES;i++)
 {
 if (gFiles[i].Free)
 {
 *f = i;
 break;
 }
 }
 
 if (*f == 0xFF) return 0;
 
 ReadRootDirectory(*f);
 
 filename = fname;
 leng = strlen(fname);
 
 for (i=0;i<leng;i++)
 {
 if (fname[i] == '/')
 {
 fname[i] = 0;
 
 if (!cwd(filename,*f))
 {
 gFiles[*f].Free = TRUE;
 return 0;
 }
 
 filename = fname+i+1;
 }
 }
 return filename;
 }
 
 //////////////////////////////////////////////end of tryfile()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 char fcreate(char f,char *fname)
 {
 DIR *pDir;
 int32 actsector,actcl;
 int16 i;
 
 if (f > (MAXFILES-1)) return FALSE;
 
 if (gFAT32Vars.gFirstDirEntryCluster == 0x0FFFFFFF)
 {
 // extend the directory file !!!
 gFAT32Vars.gFirstDirEntryCluster = FindFirstFreeCluster();
 gFAT32Vars.gFirstEmptyDirEntry = 0;
 SetClusterEntry(gFiles[f].CurrentCluster,gFAT32Vars.gFirstDirEntryCluster);
 SetClusterEntry(gFAT32Vars.gFirstDirEntryCluster,0x0FFFFFFF);
 actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector;
 
 for (i=0;i<512;i++)
 gFiles[f].IOpuffer[i] = 0;
 
 write_BLOCK(actsector,gFiles[f].IOpuffer,512);
 }
 
 actsector = gFAT32Vars.gFirstDirEntryCluster + gFAT32Vars.gFirstDataSector ;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gFirstEmptyDirEntry]));
 
 gFiles[f].dirSector = actsector;
 gFiles[f].dirIdx = gFAT32Vars.gFirstEmptyDirEntry;
 
 GetDOSName(pDir,fname);
 
 pDir->bAttr = 0;
 actcl = FindFirstFreeCluster();
 pDir->hCluster = actcl & 0xFFFF;
 pDir->hClusterH = actcl >> 16;
 
 SetClusterEntry(actcl,0x0FFFFFFF);
 
 pDir->wSize = 0;
 gFiles[f].position = 0;
 pDir->hDate = GetCurrentDOSDate();
 pDir->hTime = GetCurrentDOSTime();
 
 write_BLOCK(actsector,gFiles[f].IOpuffer,512);
 
 memcpy(&(gFiles[f].DirEntry),pDir,32);
 
 return TRUE;
 }
 
 //////////////////////////////////////////////end of fCreate()/////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////////////////
 
 int32 ComposeCluster(char f)
 {
 int32 retval;
 
 retval = gFiles[f].DirEntry.hClusterH;
 retval <<= 16;
 retval |= gFiles[f].DirEntry.hCluster;
 return retval;
 }
 
 ///////////////////////////////end of ComposeCluster()///////////////////////////////////////////////////
 ///////////////////////////////////////////////////////////////////////////////////////////
 
 char fopen(char *fname, char mode)
 {
 char found;
 char f;
 int32 actsector,actcluster,nextcluster;
 char *filename;
 
 if (input(CardInserted)) return 0xFF;
 
 //output_high(YELLOWLED);
 
 filename = TryFile(fname,&f);
 
 if (filename == 0) return 0xFF;
 
 found = FALSE;
 
 found = FindDirEntry(filename,f);
 
 if (!found)
 {
 if (mode == 'r')
 {
 gFiles[f].Free = TRUE;
 return 0xFF;
 }
 else
 {
 if (!fcreate(f,filename)){printf("file has been created"); output_high(PIN_C6); return 0xFF;}
 
 found = TRUE;
 }
 }
 
 if (found)
 {
 gFiles[f].Free = FALSE;
 gFiles[f].mode = mode;
 
 if  (mode == 'a')
 {
 gFiles[f].position = gFiles[f].DirEntry.wSize;
 
 actcluster = ComposeCluster(f);
 
 while (actcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 nextcluster = GetNextCluster(actcluster);
 if (nextcluster == 0x0FFFFFFF || nextcluster == 0) break;
 
 actcluster = nextcluster;
 }
 
 actsector = actcluster + gFAT32Vars.gFirstDataSector ;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFiles[f].CurrentCluster = actcluster;
 gFiles[f].posinsector = gFiles[f].position & 0x01FF;
 
 if (gFiles[f].posinsector == 0 && gFiles[f].position != 0)
 gFiles[f].posinsector = 512;
 }
 
 else
 {
 gFiles[f].position = 0;
 
 actsector = ComposeCluster(f);
 
 actsector += gFAT32Vars.gFirstDataSector;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFiles[f].CurrentCluster = ComposeCluster(f);
 
 gFiles[f].posinsector = 0;
 }
 }
 
 return f;
 }
 
 ///////////////////////////////////////////end of fOpen()///////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////////
 
 void fclose(char f)
 {
 //output_low(YELLOWLED);
 if (f > (MAXFILES-1)) return;
 
 if ((gFiles[f].mode == 'a') || (gFiles[f].mode == 'w'))
 fflush(f);
 
 gFiles[f].Free = TRUE;
 }
 
 /////////////////////////////////////////////end of fclose()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 void fflush(char f)
 {
 int32 actsector;
 DIR *pDir;
 
 if (f > (MAXFILES-1)) return;
 
 actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
 
 write_BLOCK(actsector,gFiles[f].IOpuffer,512);
 
 read_BLOCK(gFiles[f].dirSector,gFiles[f].IOpuffer);
 
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFiles[f].dirIdx]));
 
 if (gFiles[f].DirEntry.bAttr & 0x10)
 pDir->wSize = 0; // if it is a directory
 else
 pDir->wSize = gFiles[f].position;
 
 pDir->hDate = GetCurrentDOSDate();
 pDir->hTime = GetCurrentDOSTime();
 
 write_BLOCK(gFiles[f].dirSector,gFiles[f].IOpuffer,512);
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 }
 
 /////////////////////////////////////////////end of fflush()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 char cwd(char *fname, char f)
 {
 int32 actsector;
 
 if (f > (MAXFILES-1)) return FALSE; // just in case of overaddressing
 
 if (IsSelfDir(fname)) return TRUE; // already in Root dir
 
 if (!FindDirEntry(fname,f)) return FALSE; // not found
 
 actsector = ComposeCluster(f);
 
 actsector += gFAT32Vars.gFirstDataSector; // read current dir
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFAT32Vars.gDirEntrySector = actsector;
 gFiles[f].dirSector = actsector;
 
 gFiles[f].CurrentCluster = ComposeCluster(f);
 
 return TRUE;
 }
 
 /////////////////////////////////////////////end of cwd()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 void fputch(char be, char f)
 {
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1)) return;
 
 if (gFiles[f].posinsector == 512)
 {
 actsector = gFiles[f].CurrentCluster + gFAT32Vars.gFirstDataSector;
 
 write_BLOCK(actsector,gFiles[f].IOpuffer,512);
 
 nextcluster = FindFirstFreeCluster();
 
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 
 SetClusterEntry(gFiles[f].CurrentCluster,nextcluster);
 
 SetClusterEntry(nextcluster,0x0FFFFFFF);
 
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFiles[f].CurrentCluster = nextcluster;
 gFiles[f].posinsector = 0;
 }
 }
 
 gFiles[f].IOpuffer[gFiles[f].posinsector] = be;
 gFiles[f].posinsector++;
 gFiles[f].position++;
 
 }
 
 /////////////////////////////////////////////end of fputch()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 void fputstring(char *be, char f)
 {
 int16 leng,i;
 
 if (f > (MAXFILES-1)) return;
 
 leng = strlen(be);
 
 for (i=0;i<leng;i++)
 fputch(be[i],f);
 }
 
 /////////////////////////////////////////////end of fputstring()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 int16 fread(char *buffer, int16 leng, char f)
 {
 int16 i,retv;
 char c,v;
 
 if (f > (MAXFILES-1)) return 0;
 
 retv = 0;
 
 for (i=0;i<leng;i++)
 {
 v = fgetch(&c,f);
 
 if (v)
 {
 buffer[i] = c;
 retv++;
 }
 else break;
 }
 
 return retv;
 }
 
 /////////////////////////////////////////////end of fread()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 void fwrite(char *buffer, int16 leng, char f)
 {
 int16 i;
 
 if (f > (MAXFILES-1)) return;
 
 for (i=0;i<leng;i++)
 fputch(buffer[i],f);
 
 }
 
 /////////////////////////////////////////////end of fwrite()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 char fgetch(char *ki,char f)
 {
 int32 nextcluster,actsector;
 
 if (f > (MAXFILES-1)) return FALSE;
 
 if (gFiles[f].position >= gFiles[f].DirEntry.wSize) return FALSE;
 
 *ki = gFiles[f].IOpuffer[gFiles[f].posinsector];
 gFiles[f].posinsector++;
 gFiles[f].position++;
 
 if (gFiles[f].posinsector == 512)
 {
 nextcluster = GetNextCluster(gFiles[f].CurrentCluster);
 
 if (nextcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 actsector = nextcluster + gFAT32Vars.gFirstDataSector;
 
 read_BLOCK(actsector,gFiles[f].IOpuffer);
 
 gFiles[f].CurrentCluster = nextcluster;
 gFiles[f].posinsector = 0;
 }
 }
 return TRUE;
 }
 
 /////////////////////////////////////////////end of fgetch()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 char remove(char *fname)
 {
 char i,found;
 char f;
 DIR *pDir;
 int32 nextcluster,currentcluster;
 char *filename;
 
 filename = TryFile(fname,&f);
 
 if (filename == 0) return FALSE;
 
 found = FindDirEntry(filename,f);
 
 if (!found)
 {
 gFiles[f].Free = TRUE;
 return FALSE;
 }
 
 //output_high(YELLOWLED);
 
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gDirEntryIdx]));
 pDir->sName[0] = 0xE5;
 
 for (i=1;i<8;i++)
 pDir->sName[i] = ' ';
 for (i=0;i<3;i++)
 pDir->spam[i] = ' ';
 
 write_BLOCK(gFAT32Vars.gDirEntrySector,gFiles[f].IOpuffer,512);
 
 currentcluster = ComposeCluster(f);
 
 while (currentcluster != 0x0FFFFFFF && nextcluster != 0)
 {
 nextcluster = GetNextCluster(currentcluster);
 
 ClearClusterEntry(currentcluster);
 
 currentcluster = nextcluster;
 }
 
 ClearClusterEntry(currentcluster);
 
 SetClusterEntry(currentcluster,0);
 
 currentcluster = gFAT32Vars.gStartSector+DiskInfo.Reserved1 + gFAT32Vars.FATstartidx;
 
 write_BLOCK(currentcluster,FATTable,512);
 
 currentcluster += DiskInfo.hSectorsPerFat;
 
 write_BLOCK(currentcluster,FATTable,512);
 
 gFiles[f].Free = TRUE;
 
 //output_low(YELLOWLED);
 return TRUE;
 }
 
 
 /////////////////////////////////////////////end of fremove()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 char getfsize(char *fname, int32 *fsiz)
 {
 char found;
 char f;
 DIR *pDir;
 char *filename;
 
 filename = TryFile(fname,&f);
 
 if (filename == 0) return FALSE;
 
 found = FindDirEntry(filename,f);
 
 if (!found)
 {
 gFiles[f].Free = TRUE;
 return FALSE;
 }
 
 pDir = (DIR*)(&(gFiles[f].IOpuffer[32*gFAT32Vars.gDirEntryIdx]));
 gFiles[f].Free = TRUE;
 *fsiz = pDir->wSize;
 return TRUE;
 }
 /////////////////////////////////////////////end of getfsize()/////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////////////////////////
 
 
 
 
 
 ////////////////////main starts here //////////////////////////
 
 void main()
 {
 char f,msg[64],gfilename[32];
 char gPrevCard,gActCard; // previous and actual card states (inserted, removed)
 int v;
 
 //.................... // other declarations
 //....................
 
 //.................... // INIT code parts
 //....................
 
 //InitClockInt(); // init the clock chip
 //ReadClock();    // read the current time
 
 setup_adc_ports(NO_ANALOGS); //cannot be used for analog inputs
 
 //init_dram();              // function not found anywhere
 
 /// MMC Setup
 //below function is used to set I/O direction register .Must be used with Fast_io .
 // and when access as memory by using #bytes directive.
 // 1 indicate for recieving input and 0 indicate for giving outputs
 
 // here  I = input, O = output
 
 set_tris_c(0b10010011);
 //c7=rx I, c6=tx O, c5 SDO O,c4 SDI I
 //c3 CLK O,c2 CS O,
 output_high(_CS);
 
 /// init SPI interface
 printf("\n\r Start SPI MMC\n\r");
 
 
 
 
 SETUP_SPI(SPI_MASTER | SPI_CLK_DIV_16 | SPI_L_TO_H );  // initiazing SPI By grouping constants
 CKE=0;
 CKP=1;
 SMP=0;
 
 
 SETUP_SPI(SPI_MASTER | SPI_CLK_DIV_16 | SPI_H_TO_L |SPI_XMIT_L_TO_H );
 
 
 v = MMCInit(10); // init the card
 
 InitFAT(); // init the file system
 
 strcpy(gfilename,"myLuck.txt");
 f = fopen(gfilename,'a'); // open EVENTS.LOG for append
 if (f < MAXFILES) {
 sprintf(msg,"%04lu.%02u.%02u. %02u:%02u:%02u ",myrec.tm_year,myrec.tm_mon,myrec.tm_mday,myrec.tm_hour,myrec.tm_min,myrec.tm_sec);
 fputstring(msg,f);
 strcpy(msg,"System started\r\n");
 fputstring(msg,f);
 fclose(f);
 }
 
 }
 | 
 |  |  
		|  |  
		| Benjamin 
 
 
 Joined: 11 Jan 2006
 Posts: 21
 Location: Quebec (Canada)
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Tue Aug 07, 2007 7:50 am |   |  
				| 
 |  
				| Hi Miniman, 
 Thanks for the code.
 
 Instead of formating your disk, you should add at least FAT16 compatibility to your software (it's pretty easy to do).  A volume with less than 65525 clusters (and more than 4084) should be formated as FAT16.
 
 P.S. For those who would like to add SD compatibility, it's actually pretty simple.  MAXIM wrote a very goog application note with everything you need:
 
 www.maxim-ic.com/AN3969
 
 If you use the exemple code from MAXIM though, you should understand and verify it.  There's one or two minor errors.
 
 Ben.
 |  |  
		|  |  
		| Benjamin 
 
 
 Joined: 11 Jan 2006
 Posts: 21
 Location: Quebec (Canada)
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Tue Aug 07, 2007 11:52 am |   |  
				| 
 |  
				| Miniman, 
 There's something that I don't get in your code.  You don't seem to bother about the number of sectors per cluster? (see Boot Sector variable SecPerClus)  Your code is writen as if there was only one Sector per cluster.  For instance, when reading a file and reaching the end of the first sector you jump to the next cluster, instead of the next sector.
   
 What is it I'm not getting?
 |  |  
		|  |  
		| pic4me 
 
 
 Joined: 07 Aug 2007
 Posts: 2
 
 
 
			    
 
 | 
			
				| Problem with fat32 |  
				|  Posted: Tue Aug 07, 2007 12:37 pm |   |  
				| 
 |  
				| Hi miniman 
 I run ur code with pic18f4620............................
 the mmc initializes only with software spi not with hardware spi
 but after initializing it does nothing....................... when i debug it, it doesn't read root directory.......why it is doing so...........moreover i see ur ReadSector() and WriteSector() ......... when you pass any address....i mean   to char* hova or char* honnan...................  to it you do nothing with with that address.. you dont save any thing in that address therfor it returns nothing in that address...................... remember i  m saying abt gFiles[fil].iopuffer........ when u send this address u do nothing with that...........................................
 
 
 is my question correct?
 
 your work is definitely appreciateable..................... if i m right then plz correct it and reply........................................
 
 
 pic4me
 ////////////////////
 |  |  
		|  |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Aug 07, 2007 1:41 pm |   |  
				| 
 |  
				|  	  | Benjamin wrote: |  	  | Miniman, 
 There's something that I don't get in your code.  You don't seem to bother about the number of sectors per cluster? (see Boot Sector variable SecPerClus)  Your code is writen as if there was only one Sector per cluster.  For instance, when reading a file and reaching the end of the first sector you jump to the next cluster, instead of the next sector.
   
 What is it I'm not getting?
 | 
 
 Sorry, I do not know much about FAT, I just made some changed to Tomis code. I have also thought about that.. I must say I have not tested to read a file larger then a sector (512 bytes) but I have listed files in the rootdirectory where the file entrys  reached over 2sectors, so I do not think there are any thing wrong with the code. But I should test to read a file that are larger then a sector before I can say for sure..
 Sorry for my vague answer, but I do not have much info about it.
 
 
  	  | pic4me wrote: |  	  | I run ur code with pic18f4620............................ the mmc initializes only with software spi not with hardware spi
 but after initializing it does nothing....
 | 
 Sorry I do not understand what you are trying to say. Why do you use that many dots in your message? Explain a little bit better please!
 
 Best regards
 Miniman
 |  |  
		|  |  
		| Benjamin 
 
 
 Joined: 11 Jan 2006
 Posts: 21
 Location: Quebec (Canada)
 
 
			      
 
 | 
			
				|  |  
				|  Posted: Tue Aug 07, 2007 1:57 pm |   |  
				| 
 |  
				| Thanks for the answer, 
 I did write the same question to Tomi and I'm waiting for his response.  I believe the code should work with any disk smaller than 260 MB, since Microsoft formats these disks with 1 sector per cluster (in FAT32).
 
 Ben.
 |  |  
		|  |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Tue Aug 07, 2007 3:01 pm |   |  
				| 
 |  
				| I googled around a bit, and it seems like there are some formating programs that support the choice of sectors per cluster. So if you use a third party formating program you should be able to use larger cards if you specify 1 sector per cluster. Or am I wrong? I found this in the format help: "FAT file systems restrict the number of clusters to no more than 65526. FAT32 file systems restrict the number of clusters to between 65527 and 4177917"
 So you should not be able to use FAT32 on disk smaller then 32MB.
 
 Best regards
 Miniman
 |  |  
		|  |  
		| pic4me 
 
 
 Joined: 07 Aug 2007
 Posts: 2
 
 
 
			    
 
 | 
			
				| problem with fat32 |  
				|  Posted: Wed Aug 08, 2007 12:11 pm |   |  
				| 
 |  
				| hi miniman thnkx 4 ur reply infact i want to say that there is problem  when i use  ur code with pic18f4620. but now just tell me one thing for what micro u write ur code and on what micro u test it. and how u list ur files in root directory.i mean which command u use to list ur files in root directory
 do u understand what i m saying.............
 
 regards
 
 pic4me
 //////////
 //////////
 |  |  
		|  |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Aug 08, 2007 1:14 pm |   |  
				| 
 |  
				| I have tested my code with a 18F4550. I have only tested software spi mode yet, but the hardware mode is the same as Tomis orginal code. If you want an example on how to list files then check the comments in the top of the MMC_SPI_FAT32.c file. There are an example.
 
 Best regards
 Miniman
 |  |  
		|  |  
		| wielen 
 
 
 Joined: 15 Aug 2007
 Posts: 3
 
 
 
			    
 
 | 
			
				| hardware spi |  
				|  Posted: Wed Aug 15, 2007 12:57 am |   |  
				| 
 |  
				| hoi mini man 
 thanks for the code it works great for me, I'm still testing.
 
 i found a error in WriteSector and with hardware spi
 
 part of code
 */
 #ifdef MMC_SPI_SOFTWARE
 MMC_Xfer(POSTINC0); // *0xFEE
 #else
 SSPBUF=POSTINC0; // Write the byte on address oxFEE to SPI
 while (!BF);
 #endif
 
 
 
 I think you have to change it to somting like this, it works for me
 
 
 #ifdef MMC_SPI_SOFTWARE
 MMC_Xfer(POSTINC0); // *0xFEE
 #else
 SSPBUF=POSTINC0; // Write the byte on address oxFEE to SPI
 while (!BF);
 dummy= SSPBUFF ; dummy read to clear status bits
 #endif
 |  |  
		|  |  
		| Pret 
 
 
 Joined: 18 Jul 2006
 Posts: 92
 Location: Iasi, Romania
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Aug 15, 2007 2:43 am |   |  
				| 
 |  
				| In Tomi's code and also in most of FAT implementations on small controllers, there is a constraint regarding sectors per cluster. Only one sector is allowed per cluster. 
 You can format a disk with this contraint in command line. You do not need third party software. Just type in cmd "format i: /A:512". I could not format disks smaller than 64M as FAT32.
 |  |  
		|  |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Wed Aug 15, 2007 3:57 am |   |  
				| 
 |  
				| Thank you wielen! Your right, we must clear the status bit. I have changed and updated the code now.
 Thanks for your information Pret.
 
 Best regards
 Miniman
 |  |  
		|  |  
		| wielen 
 
 
 Joined: 15 Aug 2007
 Posts: 3
 
 
 
			    
 
 | 
			
				| Problems   with append |  
				|  Posted: Thu Aug 23, 2007 4:01 am |   |  
				| 
 |  
				| I try to write to a new file that is ok it works fine. but when i use this for the second time
 "f = fopen(filename,'a');"
 
 write some data
 
 fclose(f);
 
 The next time i open the file it works with out error, but there is no data
 in the file it seems this only happens when its more then 512 bytes, in
 the first block it works well.
 
 may be somebody have an solution for this problem?
 |  |  
		|  |  
		| Miniman 
 
 
 Joined: 30 Apr 2007
 Posts: 44
 
 
 
			    
 
 | 
			
				|  |  
				|  Posted: Thu Aug 23, 2007 9:40 am |   |  
				| 
 |  
				| if you open a file in with 'a' then it won't read any data.. maby you can post the code and I will take a deeper look what could be the problem. I must admit that I have not tested to read/write files larger then 512 bytes....
 |  |  
		|  |  
		|  |  
  
	| 
 
 | You cannot post new topics in this forum You cannot reply to topics in this forum
 You cannot edit your posts in this forum
 You cannot delete your posts in this forum
 You cannot vote in polls in this forum
 
 |  
 Powered by phpBB © 2001, 2005 phpBB Group
 
 |