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:
parent
1c8ddada00
commit
05791efb05
9
Makefile
9
Makefile
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
/*=========================================================================*/
|
||||
|
||||
|
|
|
@ -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.
|
|
@ -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
|
||||
|
|
@ -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 *) ®_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 *) ®_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 */
|
||||
|
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -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 */
|
|
@ -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 */
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
|
@ -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;
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
Loading…
Reference in New Issue