added filesystem code based on FatFs

!!! UNTESTET !!!

* modified mmc code from microbuilders to work with our board
* added code for AT45DB041D DataFlash according to datasheet
This commit is contained in:
bsx 2011-06-15 10:51:22 +02:00
parent 1c8ddada00
commit 05791efb05
17 changed files with 5808 additions and 4 deletions

View File

@ -10,7 +10,7 @@ OBJS +=
OBJS += basic/basic.o basic/reinvoke_isp.o basic/delayms.o basic/voltage.o
OBJS += basic/keyin.o
OBJS += eeprom/eeprom.o
LIBS += core/libcore.a lcd/liblcd.a modules/libmodules.a
LIBS += core/libcore.a lcd/liblcd.a modules/libmodules.a filesystem/libfat.a
##########################################################################
# GNU GCC compiler flags
@ -30,6 +30,7 @@ LDLIBS = -lm
LDLIBS += -Lmodules -lmodules
LDLIBS += -Lcore -lcore
LDLIBS += -Llcd -llcd
LDLIBS += -Lfilesystem -lfat
OCFLAGS = --strip-unneeded
LD_PATH = lpc1xxx
@ -50,6 +51,9 @@ lcd/liblcd.a lcd/render.o lcd/display.o:
modules/libmodules.a:
cd modules && $(MAKE) ROOT_PATH=../$(ROOT_PATH)
filesystem/libfat.a:
cd filesystem && $(MAKE) ROOT_PATH=../$(ROOT_PATH)
tools/lpcfix:
cd tools && $(MAKE)
@ -77,7 +81,8 @@ clean:
@cd tools && $(MAKE) clean
@cd lcd && $(MAKE) clean
@cd modules && $(MAKE) clean
@cd filesystem && $(MAKE) clean
.PHONY: lcd/liblcd.a modules/libmodules.a
.PHONY: lcd/liblcd.a modules/libmodules.a filesystem/libfat.a

View File

@ -41,8 +41,6 @@
// LCD
#define RB_LCD_BL 1,9
//#define RB_LCD_A0 2,0
#define RB_LCD_CS 2,1
#define RB_LCD_RST 2,2
@ -61,6 +59,8 @@
#define RB_SPI_SCK 2,11
#define RB_SPI_CS_DF 2,0
#define RB_SPI_SS0 2,5
#define RB_SPI_SS1 2,4

View File

@ -56,3 +56,17 @@
#define CFG_LED_OFF (0)
/*=========================================================================*/
/*=========================================================================
SD CARD
-----------------------------------------------------------------------
CFG_HAVE_SDCARD Indicates whether the SD Card code should be
included in the filesystem access code.
If the SD Card is enabled, the number of volumes
in filesystem/ffconf.h must be increased accordingly.
-----------------------------------------------------------------------*/
#define CFG_HAVE_SDCARD (0)
/*=========================================================================*/

127
filesystem/00readme.txt Normal file
View File

@ -0,0 +1,127 @@
FatFs Module Source Files R0.08b (C)ChaN, 2011
FILES
ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module.
ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module.
integer.h Alternative type definitions for integer variables.
option Optional external functions.
Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and not depend on any specific
storage device. You have to provide a low level disk I/O module that written
to control your storage device.
AGREEMENTS
FatFs module is an open source software to implement FAT file system to
small embedded systems. This is a free software and is opened for education,
research and commercial developments under license policy of following trems.
Copyright (C) 2011, ChaN, all right reserved.
* The FatFs module is a free software and there is NO WARRANTY.
* No restriction on use. You can use, modify and redistribute it for
personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
* Redistributions of source code must retain the above copyright notice.
REVISION HISTORY
Feb 26, 2006 R0.00 Prototype
Apr 29, 2006 R0.01 First release.
Jun 01, 2006 R0.02 Added FAT12.
Removed unbuffered mode.
Fixed a problem on small (<32M) patition.
Jun 10, 2006 R0.02a Added a configuration option _FS_MINIMUM.
Sep 22, 2006 R0.03 Added f_rename.
Changed option _FS_MINIMUM to _FS_MINIMIZE.
Dec 11, 2006 R0.03a Improved cluster scan algolithm to write files fast.
Fixed f_mkdir creates incorrect directory on FAT32.
Feb 04, 2007 R0.04 Supported multiple drive system. (FatFs)
Changed some APIs for multiple drive system.
Added f_mkfs. (FatFs)
Added _USE_FAT32 option. (Tiny-FatFs)
Apr 01, 2007 R0.04a Supported multiple partitions on a plysical drive. (FatFs)
Fixed an endian sensitive code in f_mkfs. (FatFs)
Added a capability of extending the file size to f_lseek.
Added minimization level 3.
Fixed a problem that can collapse a sector when recreate an
existing file in any sub-directory at non FAT32 cfg. (Tiny-FatFs)
May 05, 2007 R0.04b Added _USE_NTFLAG option.
Added FSInfo support.
Fixed some problems corresponds to FAT32. (Tiny-FatFs)
Fixed DBCS name can result FR_INVALID_NAME.
Fixed short seek (0 < ofs <= csize) collapses the file object.
Aug 25, 2007 R0.05 Changed arguments of f_read, f_write.
Changed arguments of f_mkfs. (FatFs)
Fixed f_mkfs on FAT32 creates incorrect FSInfo. (FatFs)
Fixed f_mkdir on FAT32 creates incorrect directory. (FatFs)
Feb 03, 2008 R0.05a Added f_truncate().
Added f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated.
Fixed cached sector is not flushed when create and close without write.
Apr 01, 2008 R0.06 Added f_forward(). (Tiny-FatFs)
Added string functions: fputc(), fputs(), fprintf() and fgets().
Improved performance of f_lseek() on move to the same or following cluster.
Apr 01, 2009, R0.07 Merged Tiny-FatFs as a buffer configuration option.
Added long file name support.
Added multiple code page support.
Added re-entrancy for multitask operation.
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision.
Apr 14, 2009, R0.07a Separated out OS dependent code on reentrant cfg.
Added multiple sector size support.
Jun 21, 2009, R0.07c Fixed f_unlink() may return FR_OK on error.
Fixed wrong cache control in f_lseek().
Added relative path feature.
Added f_chdir().
Added f_chdrive().
Added proper case conversion for extended characters.
Nov 03, 2009 R0.07e Separated out configuration options from ff.h to ffconf.h.
Added a configuration option, _LFN_UNICODE.
Fixed f_unlink() fails to remove a sub-dir on _FS_RPATH.
Fixed name matching error on the 13 char boundary.
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
May 15, 2010, R0.08 Added a memory configuration option. (_USE_LFN)
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed fname member in the FILINFO structure on Unicode cfg.
String functions support UTF-8 encoding files on Unicode cfg.
Aug 16,'10 R0.08a Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss.
Fixed a wrong directory entry is created on non-LFN cfg when the given name contains ';'.
Fixed f_mkfs() creates wrong FAT32 volume.
Jan 15,'11 R0.08b Fast seek feature is also applied to f_read() and f_write().
f_lseek() reports required table size on creating CLMP.
Extended format syntax of f_printf function.
Ignores duplicated directory separators in given path names.

40
filesystem/Makefile Normal file
View File

@ -0,0 +1,40 @@
##########################################################################
# User configuration and firmware specific object files
##########################################################################
OBJS =
OBJS += ff.o
OBJS += diskio.o
OBJS += iobase.o
OBJS += mmc.o
OBJS += at45db041d.o
LIBNAME=fat
##########################################################################
# GNU GCC compiler flags
##########################################################################
ROOT_PATH?= ..
INCLUDE_PATHS = -I$(ROOT_PATH) -I../core -I.
include $(ROOT_PATH)/Makefile.inc
LIBFILE=lib$(LIBNAME).a
##########################################################################
# Compiler settings, parameters and flags
##########################################################################
all: $(LIBFILE)
$(LIBFILE): $(OBJS)
$(AR) rcs $@ $(OBJS)
%.o : %.c
$(CC) $(CFLAGS) -o $@ $<
clean:
rm -f $(OBJS) $(LIBFILE)
ff.o: ff.c ffconf.h diskio.h ff.h integer.h

215
filesystem/at45db041d.c Normal file
View File

@ -0,0 +1,215 @@
#include "projectconfig.h"
#include "diskio.h"
#include "iobase.h"
#include "core/ssp/ssp.h"
#include "basic/basic.h"
/* Opcodes */
#define OP_POWERDOWN (0xB9)
#define OP_RESUME (0xAB)
#define OP_PAGEREAD (0xD2)
#define OP_BUFFER1READ (0xD1) /* Low Frequency (<=33MHz) */
#define OP_BUFFER2READ (0xD3) /* Low Frequency (<=33MHz) */
#define OP_BUFFER1WRITE (0x84)
#define OP_BUFFER2WRITE (0x87)
#define OP_BUFFER1PROG (0x83) /* with builtin erase */
#define OP_BUFFER2PROG (0x86) /* with builtin erase */
#define OP_STATUSREAD (0xD7)
#define OP_DEVICEID (0x9F)
#define OP_PAGE2BUFFER1 (0x53)
#define OP_PAGE2BUFFER2 (0x55)
#define OP_BUFFER1PAGECMP (0x60)
#define OP_BUFFER2PAGECMP (0x61)
#define OP_AUTOREWRITE1 (0x58) /* Auto Page Rewrite throught Buffer 1 */
#define OP_AUTOREWRITE2 (0x59) /* Auto Page Rewrite throught Buffer 2 */
#define SB_READY (1 << 7)
#define SB_COMP (1 << 6)
#define SB_PROTECT (1 << 1)
#define SB_PAGESIZE (1 << 0)
#define CS_LOW() gpioSetValue(RB_SPI_CS_DF, 0)
#define CS_HIGH() gpioSetValue(RB_SPI_CS_DF, 1)
static volatile DSTATUS status = STA_NOINIT;
static void wait_for_ready() {
BYTE reg_status = 0xFF;
CS_LOW();
xmit_spi(OP_STATUSREAD);
do {
rcvr_spi_m((uint8_t *) &reg_status);
} while (!(reg_status & SB_READY));
CS_HIGH();
}
static void dataflash_powerdown() {
CS_LOW();
xmit_spi(OP_POWERDOWN);
CS_HIGH();
}
static void dataflash_resume() {
CS_LOW();
xmit_spi(OP_RESUME);
CS_HIGH();
}
DSTATUS dataflash_initialize() {
sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
gpioSetDir(RB_SPI_CS_DF, gpioDirection_Output);
dataflash_resume();
status &= ~STA_NOINIT;
return status;
}
DSTATUS dataflash_status() {
return status;
}
DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count) {
if (!count) return RES_PARERR;
if (status & STA_NOINIT) return RES_NOTRDY;
/* convert sector numbers to page numbers */
sector *= 2;
count *= 2;
do {
wait_for_ready();
DWORD pageaddr = sector << 9; // lower 9 bits are byte address within the page
BYTE remaining = 255;
CS_LOW();
xmit_spi(OP_PAGEREAD);
xmit_spi((BYTE)(pageaddr >> 16));
xmit_spi((BYTE)(pageaddr >> 8));
xmit_spi((BYTE)pageaddr);
xmit_spi(0x00); // follow up with 4 don't care bytes
xmit_spi(0x00);
xmit_spi(0x00);
xmit_spi(0x00);
do {
rcvr_spi_m(buff++);
} while (--remaining);
sector++;
CS_HIGH();
} while (--count);
return count ? RES_ERROR : RES_OK;
}
#if _READONLY == 0
DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count) {
if (!count) return RES_PARERR;
if (status & STA_NOINIT) return RES_NOTRDY;
/* convert sector numbers to page numbers */
sector *= 2;
count *= 2;
do {
wait_for_ready();
DWORD pageaddr = sector << 9; // lower 9 bits are byte address within the page
BYTE remaining = 255;
// write bytes into the dataflash buffer
CS_LOW();
xmit_spi(OP_BUFFER1WRITE);
xmit_spi(0x00);
xmit_spi(0x00);
xmit_spi(0x00);
do {
xmit_spi(*buff++);
} while (--remaining);
sector++;
CS_HIGH();
wait_for_ready();
// compare buffer with target memory page
CS_LOW();
xmit_spi(OP_BUFFER1PAGECMP);
xmit_spi((BYTE)(pageaddr >> 16));
xmit_spi((BYTE)(pageaddr >> 8));
xmit_spi((BYTE)pageaddr);
CS_HIGH();
wait_for_ready();
CS_LOW();
BYTE reg_status = 0xFF;
xmit_spi(OP_STATUSREAD);
rcvr_spi_m((uint8_t *) &reg_status);
CS_HIGH();
// trigger program only if data changed
if (reg_status & SB_COMP) {
CS_LOW();
xmit_spi(OP_BUFFER1PROG);
xmit_spi((BYTE)(pageaddr >> 16));
xmit_spi((BYTE)(pageaddr >> 8));
xmit_spi((BYTE)pageaddr);
CS_HIGH();
}
} while (--count);
return count ? RES_ERROR : RES_OK;
}
#endif /* _READONLY */
#if _USE_IOCTL != 0
DRESULT dataflash_ioctl(BYTE ctrl, void *buff) {
DRESULT res;
BYTE *ptr = buff;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
switch (*ptr) {
case 0: /* Sub control code == 0 (POWER_OFF) */
dataflash_powerdown();
res = RES_OK;
break;
case 1: /* Sub control code == 1 (POWER_ON) */
dataflash_resume();
res = RES_OK;
break;
case 2: /* Sub control code == 2 (POWER_GET) */
// TODO: figure out a way to retrieve the powerstate
*(ptr+1) = (BYTE)1;
res = RES_OK;
break;
default :
res = RES_PARERR;
}
} else {
if (status & STA_NOINIT) return RES_NOTRDY;
switch (ctrl) {
case CTRL_SYNC:
wait_for_ready();
res = RES_OK;
break;
case GET_SECTOR_COUNT:
// TODO: read from device ID register
*(WORD*)buff = 2048;
res = RES_OK;
break;
case GET_SECTOR_SIZE:
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE:
*(WORD*)buff = 1;
res = RES_OK;
break;
default:
res = RES_PARERR;
}
}
return res;
}
#endif /* _USE_IOCTL != 0 */

10
filesystem/at45db041d.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _AT45DB041D_H
#define _AT45DB041D_H 1
DSTATUS dataflash_initialize();
DSTATUS dataflash_status();
DRESULT dataflash_read(BYTE *buff, DWORD sector, BYTE count);
DRESULT dataflash_write(const BYTE *buff, DWORD sector, BYTE count);
DRESULT dataflash_ioctl(BYTE ctrl, void *buff);
#endif /* _AT45DB041D_H */

85
filesystem/diskio.c Normal file
View File

@ -0,0 +1,85 @@
#include "projectconfig.h"
#include "diskio.h"
#include "mmc.h"
#include "at45db041d.h"
/* diskio interface */
DSTATUS disk_initialize(BYTE drv) {
#if CFG_HAVE_SDCARD == 1
switch (drv) {
case 0:
#endif
return dataflash_initialize();
#if CFG_HAVE_SDCARD == 1
case 1:
return mmc_initialize();
default:
return STA_NOINIT;
}
#endif
}
DSTATUS disk_status(BYTE drv) {
#if CFG_HAVE_SDCARD == 1
switch (drv) {
case 0:
#endif
return dataflash_status();
#if CFG_HAVE_SDCARD == 1
case 1:
return mmc_status();
default:
return STA_NOINIT;
}
#endif
}
DRESULT disk_read(BYTE drv, BYTE *buff, DWORD sector, BYTE count) {
#if CFG_HAVE_SDCARD == 1
switch (drv) {
case 0:
#endif
return dataflash_read(buff, sector, count);
#if CFG_HAVE_SDCARD == 1
case 1:
return mmc_read(buff, sector, count);
default:
return RES_PARERR;
}
#endif
}
#if _READONLY == 0
DRESULT disk_write(BYTE drv, const BYTE *buff, DWORD sector, BYTE count) {
#if CFG_HAVE_SDCARD == 1
switch (drv) {
case 0:
#endif
return dataflash_write(buff, sector, count);
#if CFG_HAVE_SDCARD == 1
case 1:
return mmc_write(buff, sector, count);
default:
return RES_PARERR;
}
#endif
}
#endif /* _READONLY == 0 */
#if _USE_IOCTL != 0
DRESULT disk_ioctl(BYTE drv, BYTE ctrl, void *buff) {
#if CFG_HAVE_SDCARD == 1
switch (drv) {
case 0:
#endif
return dataflash_ioctl(ctrl, buff);
#if CFG_HAVE_SDCARD == 1
case 1:
return mmc_ioctl(ctrl, buff);
default:
return RES_PARERR;
}
#endif
}
#endif /* _USE_IOCTL != 0 */

84
filesystem/diskio.h Normal file
View File

@ -0,0 +1,84 @@
/*-----------------------------------------------------------------------
/ Low level disk interface modlue include file
/-----------------------------------------------------------------------*/
#ifndef _DISKIO
#define _READONLY 0 /* 1: Remove write functions */
#define _USE_IOCTL 1 /* 1: Use disk_ioctl fucntion */
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
int assign_drives (int, int);
DSTATUS disk_initialize (BYTE);
DSTATUS disk_status (BYTE);
DRESULT disk_read (BYTE, BYTE*, DWORD, BYTE);
#if _READONLY == 0
DRESULT disk_write (BYTE, const BYTE*, DWORD, BYTE);
#endif
DRESULT disk_ioctl (BYTE, BYTE, void*);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (defined for FatFs) */
#define CTRL_SYNC 0 /* Flush disk cache (for write functions) */
#define GET_SECTOR_COUNT 1 /* Get media size (for only f_mkfs()) */
#define GET_SECTOR_SIZE 2 /* Get sector size (for multiple sector size (_MAX_SS >= 1024)) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (for only f_mkfs()) */
#define CTRL_ERASE_SECTOR 4 /* Force erased a block of sectors (for only _USE_ERASE) */
/* Generic command */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
/* NAND specific ioctl command */
#define NAND_FORMAT 30 /* Create physical format */
/* Card type flags (CardType) */
#define CT_MMC 0x01 /* MMC ver 3 */
#define CT_SD1 0x02 /* SD ver 1 */
#define CT_SD2 0x04 /* SD ver 2 */
#define CT_SDC (CT_SD1|CT_SD2) /* SD */
#define CT_BLOCK 0x08 /* Block addressing */
#define _DISKIO
#endif

3980
filesystem/ff.c Normal file

File diff suppressed because it is too large Load Diff

335
filesystem/ff.h Normal file
View File

@ -0,0 +1,335 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include file R0.08b (C)ChaN, 2011
/----------------------------------------------------------------------------/
/ FatFs module is a generic FAT file system module for small embedded systems.
/ This is a free software that opened for education, research and commercial
/ developments under license policy of following trems.
/
/ Copyright (C) 2011, ChaN, all right reserved.
/
/ * The FatFs module is a free software and there is NO WARRANTY.
/ * No restriction on use. You can use, modify and redistribute it for
/ personal, non-profit or commercial product UNDER YOUR RESPONSIBILITY.
/ * Redistributions of source code must retain the above copyright notice.
/
/----------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 8237 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive# */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition# */
typedef struct {
BYTE pd; /* Physical drive# */
BYTE pt; /* Partition # (0-3) */
} PARTITION;
extern const PARTITION VolToPart[]; /* Volume - Physical location resolution table */
#else /* Single partition configuration */
#define LD2PD(vol) (vol) /* Logical drive# is bound to the same physical drive# */
#define LD2PT(vol) 0 /* Always mounts the 1st partition */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 in non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1,2) */
BYTE wflag; /* win[] dirty flag (1:must be written back) */
BYTE fsi_flag; /* fsinfo dirty flag (1:must be written back) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != 512
WORD ssize; /* Bytes per sector (512,1024,2048,4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
DWORD fsi_sector; /* fsinfo sector (FAT32) */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries (= number of clusters + 2) */
DWORD fsize; /* Sectors per FAT */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and Data on tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
BYTE flag; /* File status flags */
BYTE pad1;
DWORD fptr; /* File read/write pointer (0 on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0 when fsize==0) */
DWORD clust; /* Current cluster */
DWORD dsect; /* Current data sector */
#if !_FS_READONLY
DWORD dir_sect; /* Sector containing the directory entry */
BYTE* dir_ptr; /* Ponter to the directory entry in the window */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (null on file open) */
#endif
#if _FS_SHARE
UINT lockid; /* File lock ID (index of file semaphore table) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File data read/write buffer */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object */
WORD id; /* Owner file system mount ID */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
} DIR;
/* File status structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occured in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Acces denied due to prohibited access or directory full */
FR_EXIST, /* (8) Acces denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume on the physical drive */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file shareing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES /* (18) Number of open files > _FS_SHARE */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_mount (BYTE, FATFS*); /* Mount/Unmount a logical drive */
FRESULT f_open (FIL*, const TCHAR*, BYTE); /* Open or create a file */
FRESULT f_read (FIL*, void*, UINT, UINT*); /* Read data from a file */
FRESULT f_lseek (FIL*, DWORD); /* Move file pointer of a file object */
FRESULT f_close (FIL*); /* Close an open file object */
FRESULT f_opendir (DIR*, const TCHAR*); /* Open an existing directory */
FRESULT f_readdir (DIR*, FILINFO*); /* Read a directory item */
FRESULT f_stat (const TCHAR*, FILINFO*); /* Get file status */
FRESULT f_write (FIL*, const void*, UINT, UINT*); /* Write data to a file */
FRESULT f_getfree (const TCHAR*, DWORD*, FATFS**); /* Get number of free clusters on the drive */
FRESULT f_truncate (FIL*); /* Truncate file */
FRESULT f_sync (FIL*); /* Flush cached data of a writing file */
FRESULT f_unlink (const TCHAR*); /* Delete an existing file or directory */
FRESULT f_mkdir (const TCHAR*); /* Create a new directory */
FRESULT f_chmod (const TCHAR*, BYTE, BYTE); /* Change attriburte of the file/dir */
FRESULT f_utime (const TCHAR*, const FILINFO*); /* Change timestamp of the file/dir */
FRESULT f_rename (const TCHAR*, const TCHAR*); /* Rename/Move a file or directory */
FRESULT f_forward (FIL*, UINT(*)(const BYTE*,UINT), UINT, UINT*); /* Forward data to the stream */
FRESULT f_mkfs (BYTE, BYTE, UINT); /* Create a file system on the drive */
FRESULT f_chdrive (BYTE); /* Change current drive */
FRESULT f_chdir (const TCHAR*); /* Change current directory */
FRESULT f_getcwd (TCHAR*, UINT); /* Get current directory */
int f_putc (TCHAR, FIL*); /* Put a character to the file */
int f_puts (const TCHAR*, FIL*); /* Put a string to the file */
int f_printf (FIL*, const TCHAR*, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR*, int, FIL*); /* Get a string from the file */
#ifndef EOF
#define EOF (-1)
#endif
#define f_eof(fp) (((fp)->fptr == (fp)->fsize) ? 1 : 0)
#define f_error(fp) (((fp)->flag & FA__ERROR) ? 1 : 0)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR, UINT); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT); /* Allocate memory block */
void ff_memfree (void*); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE, _SYNC_t*);/* Create a sync object */
int ff_req_grant (_SYNC_t); /* Lock sync object */
void ff_rel_grant (_SYNC_t); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#define FA__ERROR 0x80
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek function */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

189
filesystem/ffconf.h Normal file
View File

@ -0,0 +1,189 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.08b (C)ChaN, 2011
/----------------------------------------------------------------------------/
/
/ CAUTION! Do not forget to make clean the project after any changes to
/ the configuration options.
/
/----------------------------------------------------------------------------*/
#ifndef _FFCONF
#define _FFCONF 8237 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function and Buffer Configurations
/----------------------------------------------------------------------------*/
#define _FS_TINY 1 /* 0:Normal or 1:Tiny */
/* When _FS_TINY is set to 1, FatFs uses the sector buffer in the file system
/ object instead of the sector buffer in the individual file object for file
/ data transfer. This reduces memory consumption 512 bytes each file object. */
#define _FS_READONLY 0 /* 0:Read/Write or 1:Read only */
/* Setting _FS_READONLY to 1 defines read only configuration. This removes
/ writing functions, f_write, f_sync, f_unlink, f_mkdir, f_chmod, f_rename,
/ f_truncate and useless f_getfree. */
#define _FS_MINIMIZE 1 /* 0 to 3 */
/* The _FS_MINIMIZE option defines minimization level to remove some functions.
/
/ 0: Full function.
/ 1: f_stat, f_getfree, f_unlink, f_mkdir, f_chmod, f_truncate and f_rename
/ are removed.
/ 2: f_opendir and f_readdir are removed in addition to 1.
/ 3: f_lseek is removed in addition to 2. */
#define _USE_STRFUNC 0 /* 0:Disable or 1/2:Enable */
/* To enable string functions, set _USE_STRFUNC to 1 or 2. */
#define _USE_MKFS 0 /* 0:Disable or 1:Enable */
/* To enable f_mkfs function, set _USE_MKFS to 1 and set _FS_READONLY to 0 */
#define _USE_FORWARD 0 /* 0:Disable or 1:Enable */
/* To enable f_forward function, set _USE_FORWARD to 1 and set _FS_TINY to 1. */
#define _USE_FASTSEEK 0 /* 0:Disable or 1:Enable */
/* To enable fast seek feature, set _USE_FASTSEEK to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/----------------------------------------------------------------------------*/
#define _CODE_PAGE 1
/* The _CODE_PAGE specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 932 - Japanese Shift-JIS (DBCS, OEM, Windows)
/ 936 - Simplified Chinese GBK (DBCS, OEM, Windows)
/ 949 - Korean (DBCS, OEM, Windows)
/ 950 - Traditional Chinese Big5 (DBCS, OEM, Windows)
/ 1250 - Central Europe (Windows)
/ 1251 - Cyrillic (Windows)
/ 1252 - Latin 1 (Windows)
/ 1253 - Greek (Windows)
/ 1254 - Turkish (Windows)
/ 1255 - Hebrew (Windows)
/ 1256 - Arabic (Windows)
/ 1257 - Baltic (Windows)
/ 1258 - Vietnam (OEM, Windows)
/ 437 - U.S. (OEM)
/ 720 - Arabic (OEM)
/ 737 - Greek (OEM)
/ 775 - Baltic (OEM)
/ 850 - Multilingual Latin 1 (OEM)
/ 858 - Multilingual Latin 1 + Euro (OEM)
/ 852 - Latin 2 (OEM)
/ 855 - Cyrillic (OEM)
/ 866 - Russian (OEM)
/ 857 - Turkish (OEM)
/ 862 - Hebrew (OEM)
/ 874 - Thai (OEM, Windows)
/ 1 - ASCII only (Valid for non LFN cfg.)
*/
#define _USE_LFN 0 /* 0 to 3 */
#define _MAX_LFN 255 /* Maximum LFN length to handle (12 to 255) */
/* The _USE_LFN option switches the LFN support.
/
/ 0: Disable LFN feature. _MAX_LFN and _LFN_UNICODE have no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT reentrant.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes. To enable LFN,
/ Unicode handling functions ff_convert() and ff_wtoupper() must be added
/ to the project. When enable to use heap, memory control functions
/ ff_memalloc() and ff_memfree() must be added to the project. */
#define _LFN_UNICODE 0 /* 0:ANSI/OEM or 1:Unicode */
/* To switch the character code set on FatFs API to Unicode,
/ enable LFN feature and set _LFN_UNICODE to 1. */
#define _FS_RPATH 0 /* 0 to 2 */
/* The _FS_RPATH option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path. f_chdrive() and f_chdir() are available.
/ 2: f_getcwd() is available in addition to 1.
/
/ Note that output of the f_readdir fnction is affected by this option. */
/*---------------------------------------------------------------------------/
/ Physical Drive Configurations
/----------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _MAX_SS 512 /* 512, 1024, 2048 or 4096 */
/* Maximum sector size to be handled.
/ Always set 512 for memory card and hard disk but a larger value may be
/ required for on-board flash memory, floppy disk and optical disk.
/ When _MAX_SS is larger than 512, it configures FatFs to variable sector size
/ and GET_SECTOR_SIZE command must be implememted to the disk_ioctl function. */
#define _MULTI_PARTITION 0 /* 0:Single partition or 1:Multiple partition */
/* When set to 0, each volume is bound to the same physical drive number and
/ it can mount only first primaly partition. When it is set to 1, each volume
/ is tied to the partitions listed in VolToPart[]. */
#define _USE_ERASE 0 /* 0:Disable or 1:Enable */
/* To enable sector erase feature, set _USE_ERASE to 1. CTRL_ERASE_SECTOR command
/ should be added to the disk_ioctl functio. */
/*---------------------------------------------------------------------------/
/ System Configurations
/----------------------------------------------------------------------------*/
#define _WORD_ACCESS 0 /* 0 or 1 */
/* Set 0 first and it is always compatible with all platforms. The _WORD_ACCESS
/ option defines which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access.
/ 1: Word access. Do not choose this unless following condition is met.
/
/ When the byte order on the memory is big-endian or address miss-aligned word
/ access results incorrect behavior, the _WORD_ACCESS must be set to 0.
/ If it is not the case, the value can also be set to 1 to improve the
/ performance and code size. */
/* A header file that defines sync object types on the O/S, such as
/ windows.h, ucos_ii.h and semphr.h, must be included prior to ff.h. */
#define _FS_REENTRANT 0 /* 0:Disable or 1:Enable */
#define _FS_TIMEOUT 1000 /* Timeout period in unit of time ticks */
#define _SYNC_t HANDLE /* O/S dependent type of sync object. e.g. HANDLE, OS_EVENT*, ID and etc.. */
/* The _FS_REENTRANT option switches the reentrancy (thread safe) of the FatFs module.
/
/ 0: Disable reentrancy. _SYNC_t and _FS_TIMEOUT have no effect.
/ 1: Enable reentrancy. Also user provided synchronization handlers,
/ ff_req_grant, ff_rel_grant, ff_del_syncobj and ff_cre_syncobj
/ function must be added to the project. */
#define _FS_SHARE 0 /* 0:Disable or >=1:Enable */
/* To enable file shareing feature, set _FS_SHARE to 1 or greater. The value
defines how many files can be opened simultaneously. */
#endif /* _FFCONFIG */

37
filesystem/integer.h Normal file
View File

@ -0,0 +1,37 @@
/*-------------------------------------------*/
/* Integer type definitions for FatFs module */
/*-------------------------------------------*/
#ifndef _INTEGER
#define _INTEGER
#ifdef _WIN32 /* FatFs development platform */
#include <windows.h>
#include <tchar.h>
#else /* Embedded platform */
/* These types must be 16-bit, 32-bit or larger integer */
typedef int INT;
typedef unsigned int UINT;
/* These types must be 8-bit integer */
typedef char CHAR;
typedef unsigned char UCHAR;
typedef unsigned char BYTE;
/* These types must be 16-bit integer */
typedef short SHORT;
typedef unsigned short USHORT;
typedef unsigned short WORD;
typedef unsigned short WCHAR;
/* These types must be 32-bit integer */
typedef long LONG;
typedef unsigned long ULONG;
typedef unsigned long DWORD;
#endif
#endif

21
filesystem/iobase.c Normal file
View File

@ -0,0 +1,21 @@
#include "diskio.h"
#include "core/ssp/ssp.h"
/*-----------------------------------------------------------------------*/
/* Transmit a byte via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
void xmit_spi(BYTE dat) {
sspSend(0, (uint8_t*) &dat, 1);
}
/*-----------------------------------------------------------------------*/
/* Receive a byte from MMC via SPI (Platform dependent) */
/*-----------------------------------------------------------------------*/
BYTE rcvr_spi (void) {
BYTE data = 0;
sspReceive(0, &data, 1);
return data;
}

12
filesystem/iobase.h Normal file
View File

@ -0,0 +1,12 @@
void xmit_spi(BYTE dat);
BYTE rcvr_spi (void);
/* Alternative macro to receive data fast */
#define rcvr_spi_m(dst) \
do { \
sspReceive(0, (uint8_t*)(dst), 1); \
} while(0)

640
filesystem/mmc.c Normal file
View File

@ -0,0 +1,640 @@
/*-----------------------------------------------------------------------*/
/* MMCv3/SDv1/SDv2 (in SPI mode) control module (C)ChaN, 2007 */
/*-----------------------------------------------------------------------*/
/* Only rcvr_spi(), xmit_spi(), disk_timerproc() and some macros */
/* are platform dependent. */
/*-----------------------------------------------------------------------*/
#include "projectconfig.h"
#include "diskio.h"
#include "iobase.h"
#include "core/gpio/gpio.h"
#include "core/ssp/ssp.h"
#include "core/systick/systick.h"
#include "basic/basic.h"
/* Definitions for MMC/SDC command */
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
#define CMD1 (0x40+1) /* SEND_OP_COND (MMC) */
#define ACMD41 (0xC0+41) /* SEND_OP_COND (SDC) */
#define CMD8 (0x40+8) /* SEND_IF_COND */
#define CMD9 (0x40+9) /* SEND_CSD */
#define CMD10 (0x40+10) /* SEND_CID */
#define CMD12 (0x40+12) /* STOP_TRANSMISSION */
#define ACMD13 (0xC0+13) /* SD_STATUS (SDC) */
#define CMD16 (0x40+16) /* SET_BLOCKLEN */
#define CMD17 (0x40+17) /* READ_SINGLE_BLOCK */
#define CMD18 (0x40+18) /* READ_MULTIPLE_BLOCK */
#define CMD23 (0x40+23) /* SET_BLOCK_COUNT (MMC) */
#define ACMD23 (0xC0+23) /* SET_WR_BLK_ERASE_COUNT (SDC) */
#define CMD24 (0x40+24) /* WRITE_BLOCK */
#define CMD25 (0x40+25) /* WRITE_MULTIPLE_BLOCK */
#define CMD55 (0x40+55) /* APP_CMD */
#define CMD58 (0x40+58) /* READ_OCR */
/* Port Controls (Platform dependent) */
#define CS_LOW() gpioSetValue(RB_SPI_SS0, 0)
#define CS_HIGH() gpioSetValue(RB_SPI_SS0, 1)
// #define FCLK_SLOW() /* Set slow clock (100k-400k) */
// #define FCLK_FAST() /* Set fast clock (depends on the CSD) */
#define FDELAY(ms) systickDelay(ms) // Assumes delay = 1ms, ugly
/*--------------------------------------------------------------------------
Module Private Functions
---------------------------------------------------------------------------*/
static volatile
DSTATUS Stat = STA_NOINIT; /* Disk status */
static volatile
BYTE Timer1, Timer2; /* 100Hz decrement timer */
static
BYTE CardType; /* Card type flags */
/**************************************************************************/
/*!
Set SSP clock to slow (400 KHz)
*/
/**************************************************************************/
static void FCLK_SLOW()
{
/* Divide by 10 (SSPCLKDIV also enables to SSP CLK) */
SCB_SSP0CLKDIV = SCB_SSP0CLKDIV_DIV10;
/* (PCLK / (CPSDVSR * [SCR+1])) = (7,200,000 / (2 x [8 + 1])) = 400 KHz */
uint32_t configReg = ( SSP_SSP0CR0_DSS_8BIT // Data size = 8-bit
| SSP_SSP0CR0_FRF_SPI // Frame format = SPI
| SSP_SSP0CR0_SCR_8); // Serial clock rate = 8
// Set clock polarity (low between frames)
// configReg &= ~SSP_SSP0CR0_CPOL_MASK;
// configReg |= SSP_SSP0CR0_CPOL_LOW;
// Set edge transition (leading edge)
// configReg &= ~SSP_SSP0CR0_CPHA_MASK;
// configReg |= SSP_SSP0CR0_CPHA_FIRST;
// Assign config values to SSP0CR0
SSP_SSP0CR0 = configReg;
/* Clock prescale register must be even and at least 2 in master mode */
SSP_SSP0CPSR = SSP_SSP0CPSR_CPSDVSR_DIV2;
}
/**************************************************************************/
/*!
Set SSP clock to fast (6.0 MHz)
*/
/**************************************************************************/
static void FCLK_FAST()
{
/* Divide by 1 (SSPCLKDIV also enables to SSP CLK) */
SCB_SSP0CLKDIV = SCB_SSP0CLKDIV_DIV1;
/* (PCLK / (CPSDVSR * [SCR+1])) = (72,000,000 / (2 * [5 + 1])) = 6.0 MHz */
uint32_t configReg = ( SSP_SSP0CR0_DSS_8BIT // Data size = 8-bit
| SSP_SSP0CR0_FRF_SPI // Frame format = SPI
| SSP_SSP0CR0_SCR_5); // Serial clock rate = 5
// Set clock polarity (low between frames)
// configReg &= ~SSP_SSP0CR0_CPOL_MASK;
// configReg |= SSP_SSP0CR0_CPOL_LOW;
// Set edge transition (leading edge)
// configReg &= ~SSP_SSP0CR0_CPHA_MASK;
// configReg |= SSP_SSP0CR0_CPHA_FIRST;
// Assign config values to SSP0CR0
SSP_SSP0CR0 = configReg;
/* Clock prescale register must be even and at least 2 in master mode */
SSP_SSP0CPSR = SSP_SSP0CPSR_CPSDVSR_DIV2;
}
/*-----------------------------------------------------------------------*/
/* Wait for card ready */
/*-----------------------------------------------------------------------*/
static
BYTE wait_ready (void)
{
BYTE res;
Timer2 = 50; /* Wait for ready in timeout of 500ms */
rcvr_spi();
do
res = rcvr_spi();
while ((res != 0xFF) && Timer2);
return res;
}
/*-----------------------------------------------------------------------*/
/* Deselect the card and release SPI bus */
/*-----------------------------------------------------------------------*/
static
void deselect (void)
{
CS_HIGH();
rcvr_spi();
}
/*-----------------------------------------------------------------------*/
/* Select the card and wait ready */
/*-----------------------------------------------------------------------*/
static
BOOL select (void) /* TRUE:Successful, FALSE:Timeout */
{
CS_LOW();
if (wait_ready() != 0xFF) {
deselect();
return FALSE;
}
return TRUE;
}
/*-----------------------------------------------------------------------*/
/* Power Control (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* When the target system does not support socket power control, there */
/* is nothing to do in these functions and chk_power always returns 1. */
static
void power_on (void)
{
}
static
void power_off (void)
{
}
static
int chk_power(void) /* Socket power state: 0=off, 1=on */
{
return 1;
}
/*-----------------------------------------------------------------------*/
/* Receive a data packet from MMC */
/*-----------------------------------------------------------------------*/
static
BOOL rcvr_datablock (
BYTE *buff, /* Data buffer to store received data */
UINT btr /* Byte count (must be multiple of 4) */
)
{
BYTE token;
Timer1 = 20;
do { /* Wait for data packet in timeout of 200ms */
token = rcvr_spi();
} while ((token == 0xFF) && Timer1);
if(token != 0xFE) return FALSE; /* If not valid data token, retutn with error */
do { /* Receive the data block into buffer */
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
rcvr_spi_m(buff++);
} while (btr -= 4);
rcvr_spi(); /* Discard CRC */
rcvr_spi();
return TRUE; /* Return with success */
}
/*-----------------------------------------------------------------------*/
/* Send a data packet to MMC */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
static
BOOL xmit_datablock (
const BYTE *buff, /* 512 byte data block to be transmitted */
BYTE token /* Data/Stop token */
)
{
BYTE resp, wc;
if (wait_ready() != 0xFF) return FALSE;
xmit_spi(token); /* Xmit data token */
if (token != 0xFD) { /* Is data token */
wc = 0;
do { /* Xmit the 512 byte data block to MMC */
xmit_spi(*buff++);
xmit_spi(*buff++);
} while (--wc);
xmit_spi(0xFF); /* CRC (Dummy) */
xmit_spi(0xFF);
resp = rcvr_spi(); /* Reveive data response */
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
return FALSE;
}
return TRUE;
}
#endif /* _READONLY */
/*-----------------------------------------------------------------------*/
/* Send a command packet to MMC */
/*-----------------------------------------------------------------------*/
static
BYTE send_cmd (
BYTE cmd, /* Command byte */
DWORD arg /* Argument */
)
{
BYTE n, res;
if (cmd & 0x80) { /* ACMD<n> is the command sequense of CMD55-CMD<n> */
cmd &= 0x7F;
res = send_cmd(CMD55, 0);
if (res > 1) return res;
}
/* Select the card and wait for ready */
deselect();
if (!select()) return 0xFF;
/* Send command packet */
xmit_spi(cmd); /* Start + Command index */
xmit_spi((BYTE)(arg >> 24)); /* Argument[31..24] */
xmit_spi((BYTE)(arg >> 16)); /* Argument[23..16] */
xmit_spi((BYTE)(arg >> 8)); /* Argument[15..8] */
xmit_spi((BYTE)arg); /* Argument[7..0] */
n = 0x01; /* Dummy CRC + Stop */
if (cmd == CMD0) n = 0x95; /* Valid CRC for CMD0(0) */
if (cmd == CMD8) n = 0x87; /* Valid CRC for CMD8(0x1AA) */
xmit_spi(n);
/* Receive command response */
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
n = 10; /* Wait for a valid response in timeout of 10 attempts */
do
res = rcvr_spi();
while ((res & 0x80) && --n);
return res; /* Return with the response value */
}
/*--------------------------------------------------------------------------
Public Functions
---------------------------------------------------------------------------*/
/*-----------------------------------------------------------------------*/
/* Initialize Disk Drive */
/*-----------------------------------------------------------------------*/
DSTATUS mmc_initialize ()
{
BYTE n, cmd, ty, ocr[4];
// Init SSP (clock low between frames, transition on leading edge)
sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
gpioSetDir( RB_SPI_SS0, gpioDirection_Output ); /* CS */
gpioSetPullup (&IOCON_PIO3_0, gpioPullupMode_Inactive);
// Wait 20ms for card detect to stabilise
systickDelay(20);
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
power_on(); /* Force socket power on */
FCLK_SLOW();
for (n = 100; n; n--) rcvr_spi(); /* 80 dummy clocks */
ty = 0;
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
Timer1 = 100; /* Initialization timeout of 1000 msec */
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDHC */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(); /* Get trailing return value of R7 resp */
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
while (Timer1 && send_cmd(ACMD41, 1UL << 30)); /* Wait for leaving idle state (ACMD41 with HCS bit) */
if (Timer1 && send_cmd(CMD58, 0) == 0) { /* Check CCS bit in the OCR */
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
ty = (ocr[0] & 0x40) ? CT_SD2 | CT_BLOCK : CT_SD2; /* SDv2 */
}
}
} else { /* SDSC or MMC */
if (send_cmd(ACMD41, 0) <= 1) {
ty = CT_SD1; cmd = ACMD41; /* SDv1 */
} else {
ty = CT_MMC; cmd = CMD1; /* MMCv3 */
}
while (Timer1 && send_cmd(cmd, 0)); /* Wait for leaving idle state */
if (!Timer1 || send_cmd(CMD16, 512) != 0) /* Set R/W block length to 512 */
ty = 0;
}
}
CardType = ty;
deselect();
if (ty) { /* Initialization succeded */
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
FCLK_FAST();
} else { /* Initialization failed */
power_off();
}
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Get Disk Status */
/*-----------------------------------------------------------------------*/
DSTATUS mmc_status ()
{
return Stat;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT mmc_read (
BYTE *buff, /* Pointer to the data buffer to store read data */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (!count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
if (count == 1) { /* Single block read */
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
&& rcvr_datablock(buff, 512))
count = 0;
}
else { /* Multiple block read */
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
do {
if (!rcvr_datablock(buff, 512)) break;
buff += 512;
} while (--count);
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
}
}
deselect();
return count ? RES_ERROR : RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _READONLY == 0
DRESULT mmc_write (
const BYTE *buff, /* Pointer to the data to be written */
DWORD sector, /* Start sector number (LBA) */
BYTE count /* Sector count (1..255) */
)
{
if (!count) return RES_PARERR;
if (Stat & STA_NOINIT) return RES_NOTRDY;
if (Stat & STA_PROTECT) return RES_WRPRT;
if (!(CardType & CT_BLOCK)) sector *= 512; /* Convert to byte address if needed */
if (count == 1) { /* Single block write */
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
&& xmit_datablock(buff, 0xFE))
count = 0;
}
else { /* Multiple block write */
if (CardType & CT_SDC) send_cmd(ACMD23, count);
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
do {
if (!xmit_datablock(buff, 0xFC)) break;
buff += 512;
} while (--count);
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
count = 1;
}
}
deselect();
return count ? RES_ERROR : RES_OK;
}
#endif /* _READONLY == 0 */
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL != 0
DRESULT mmc_ioctl (
BYTE ctrl, /* Control code */
void *buff /* Buffer to send/receive control data */
)
{
DRESULT res;
BYTE n, csd[16], *ptr = buff;
WORD csize;
res = RES_ERROR;
if (ctrl == CTRL_POWER) {
switch (*ptr) {
case 0: /* Sub control code == 0 (POWER_OFF) */
if (chk_power())
power_off(); /* Power off */
res = RES_OK;
break;
case 1: /* Sub control code == 1 (POWER_ON) */
power_on(); /* Power on */
res = RES_OK;
break;
case 2: /* Sub control code == 2 (POWER_GET) */
*(ptr+1) = (BYTE)chk_power();
res = RES_OK;
break;
default :
res = RES_PARERR;
}
}
else {
if (Stat & STA_NOINIT) return RES_NOTRDY;
switch (ctrl) {
case CTRL_SYNC : /* Make sure that no pending write process. Do not remove this or written sector might not left updated. */
if (select()) {
res = RES_OK;
deselect();
}
break;
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
*(DWORD*)buff = (DWORD)csize << 10;
} else { /* SDC ver 1.XX or MMC*/
n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
csize = (csd[8] >> 6) + ((WORD)csd[7] << 2) + ((WORD)(csd[6] & 3) << 10) + 1;
*(DWORD*)buff = (DWORD)csize << (n - 9);
}
res = RES_OK;
}
break;
case GET_SECTOR_SIZE : /* Get R/W sector size (WORD) */
*(WORD*)buff = 512;
res = RES_OK;
break;
case GET_BLOCK_SIZE : /* Get erase block size in unit of sector (DWORD) */
if (CardType & CT_SD2) { /* SDC ver 2.00 */
if (send_cmd(ACMD13, 0) == 0) { /* Read SD status */
rcvr_spi();
if (rcvr_datablock(csd, 16)) { /* Read partial block */
for (n = 64 - 16; n; n--) rcvr_spi(); /* Purge trailing data */
*(DWORD*)buff = 16UL << (csd[10] >> 4);
res = RES_OK;
}
}
} else { /* SDC ver 1.XX or MMC */
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) { /* Read CSD */
if (CardType & CT_SD1) { /* SDC ver 1.XX */
*(DWORD*)buff = (((csd[10] & 63) << 1) + ((WORD)(csd[11] & 128) >> 7) + 1) << ((csd[13] >> 6) - 1);
} else { /* MMC */
*(DWORD*)buff = ((WORD)((csd[10] & 124) >> 2) + 1) * (((csd[11] & 3) << 3) + ((csd[11] & 224) >> 5) + 1);
}
res = RES_OK;
}
}
break;
case MMC_GET_TYPE : /* Get card type flags (1 byte) */
*ptr = CardType;
res = RES_OK;
break;
case MMC_GET_CSD : /* Receive CSD as a data block (16 bytes) */
if (send_cmd(CMD9, 0) == 0 /* READ_CSD */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_CID : /* Receive CID as a data block (16 bytes) */
if (send_cmd(CMD10, 0) == 0 /* READ_CID */
&& rcvr_datablock(ptr, 16))
res = RES_OK;
break;
case MMC_GET_OCR : /* Receive OCR as an R3 resp (4 bytes) */
if (send_cmd(CMD58, 0) == 0) { /* READ_OCR */
for (n = 4; n; n--) *ptr++ = rcvr_spi();
res = RES_OK;
}
break;
case MMC_GET_SDSTAT : /* Receive SD statsu as a data block (64 bytes) */
if (send_cmd(ACMD13, 0) == 0) { /* SD_STATUS */
rcvr_spi();
if (rcvr_datablock(ptr, 64))
res = RES_OK;
}
break;
default:
res = RES_PARERR;
}
deselect();
}
return res;
}
#endif /* _USE_IOCTL != 0 */
/*-----------------------------------------------------------------------*/
/* Device Timer Interrupt Procedure (Platform dependent) */
/*-----------------------------------------------------------------------*/
/* This function must be called in period of 10ms */
/* Called from SysTick_Handler in systick.c */
void disk_timerproc (void)
{
// static BYTE pv;
BYTE n;
// BYTE s;
n = Timer1; /* 100Hz decrement timer */
if (n) Timer1 = --n;
n = Timer2;
if (n) Timer2 = --n;
/* we don't have a card dectect pin
n = pv;
pv = 0;
// Sample card detect pin
pv = gpioGetValue(CFG_SDCARD_CDPORT, CFG_SDCARD_CDPIN);
// Have contacts stabled?
if (n == pv)
{
s = Stat;
// write protect NOT supported
// check card detect
if (!pv) // (Socket empty)
s |= (STA_NODISK | STA_NOINIT);
else // (Card inserted)
s &= ~STA_NODISK;
Stat = s;
}
*/
}

10
filesystem/mmc.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef _MMC_H
#define _MMC_H 1
DSTATUS mmc_initialize();
DSTATUS mmc_status();
DRESULT mmc_read(BYTE *buff, DWORD sector, BYTE count);
DRESULT mmc_write(const BYTE *buff, DWORD sector, BYTE count);
DRESULT mmc_ioctl(BYTE ctrl, void *buff);
#endif /* _MMC_H */