📄 mmc_spi_fat32.c
字号:
////////////////////////////////////////////////////////////////////////
/////////////////// 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -