mirror of
https://github.com/elua/elua.git
synced 2025-01-25 01:02:54 +08:00
Added support for multiple SD cards
The MMCFS implementation can now handle more than one MMC card. To use this feature, define these macros in platform_conf.h: PLATFORM_MMC_NUM_CARDS - the total number of cards MMCFS_CS_PORT_ARRAY - array of CS ports MMCFS_CS_PIN_ARRAY - array of CS pins MMCFS_SPI_NUM_ARRAY - array of SPI port numbers For example: defines a system with 2 MMC cards. The first one uses SPI0 and has its CS on PG0. The second one also uses SPI0 (this is perfectly possible) but has its CS on PC5. This was the configuration used to test this feature on a EK-LM3S8962 board.
This commit is contained in:
parent
d05a3ae0e9
commit
ea6e38f26e
284
src/elua_mmc.c
284
src/elua_mmc.c
@ -9,6 +9,13 @@
|
||||
#if defined( BUILD_MMCFS ) && !defined( ELUA_SIMULATOR )
|
||||
#include "platform.h"
|
||||
#include "diskio.h"
|
||||
#include "mmcfs.h"
|
||||
|
||||
#ifndef PLATFORM_MMC_NUM_CARDS
|
||||
#define NUM_CARDS 1
|
||||
#else
|
||||
#define NUM_CARDS PLATFORM_MMC_NUM_CARDS
|
||||
#endif
|
||||
|
||||
/* Definitions for MMC/SDC command */
|
||||
#define CMD0 (0x40+0) /* GO_IDLE_STATE */
|
||||
@ -27,22 +34,32 @@
|
||||
#define CMD55 (0x40+55) /* APP_CMD */
|
||||
#define CMD58 (0x40+58) /* READ_OCR */
|
||||
|
||||
#ifndef MMCFS_SPI_NUM
|
||||
#if !defined( MMCFS_SPI_NUM ) && !defined( MMCFS_SPI_NUM_ARRAY )
|
||||
#error "MMC not supported on this board"
|
||||
#endif
|
||||
|
||||
#if defined( MMCFS_CS_PORT )
|
||||
const u8 mmcfs_cs_ports[ NUM_CARDS ] = { MMCFS_CS_PORT };
|
||||
static const u8 mmcfs_cs_pins[ NUM_CARDS ] = { MMCFS_CS_PIN };
|
||||
static const u8 mmcfs_spi_nums[ NUM_CARDS ] = { MMCFS_SPI_NUM };
|
||||
#elif defined( MMCFS_CS_PORT_ARRAY )
|
||||
const u8 mmcfs_cs_ports[ NUM_CARDS ] = MMCFS_CS_PORT_ARRAY;
|
||||
static const u8 mmcfs_cs_pins[ NUM_CARDS ] = MMCFS_CS_PIN_ARRAY;
|
||||
static const u8 mmcfs_spi_nums[ NUM_CARDS ] = MMCFS_SPI_NUM_ARRAY;
|
||||
#endif
|
||||
|
||||
// asserts the CS pin to the card
|
||||
static
|
||||
void SELECT (void)
|
||||
void SELECT (BYTE id)
|
||||
{
|
||||
platform_pio_op( MMCFS_CS_PORT , ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_CLEAR );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ] , ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_CLEAR );
|
||||
}
|
||||
|
||||
// de-asserts the CS pin to the card
|
||||
static
|
||||
void DESELECT (void)
|
||||
void DESELECT (BYTE id)
|
||||
{
|
||||
platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_SET );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ], ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_SET );
|
||||
}
|
||||
|
||||
|
||||
@ -52,20 +69,13 @@ void DESELECT (void)
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
static volatile
|
||||
DSTATUS Stat = STA_NOINIT; /* Disk status */
|
||||
static volatile DSTATUS Stat[ NUM_CARDS ]; /* Disk status */
|
||||
|
||||
static volatile timer_data_type Timer1 = 0;
|
||||
static volatile timer_data_type Timer2 = 0;
|
||||
static BYTE TriesLeft[ NUM_CARDS ];
|
||||
|
||||
static
|
||||
BYTE TriesLeft = 2;
|
||||
static BYTE CardType[ NUM_CARDS ]; /* b0:MMC, b1:SDC, b2:Block addressing */
|
||||
|
||||
static
|
||||
BYTE CardType; /* b0:MMC, b1:SDC, b2:Block addressing */
|
||||
|
||||
static
|
||||
BYTE PowerFlag = 0; /* indicates if "power" is on */
|
||||
static BYTE PowerFlag[ NUM_CARDS ]; /* indicates if "power" is on */
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -74,9 +84,9 @@ BYTE PowerFlag = 0; /* indicates if "power" is on */
|
||||
|
||||
|
||||
static
|
||||
void xmit_spi (BYTE dat)
|
||||
void xmit_spi (BYTE id, BYTE dat)
|
||||
{
|
||||
platform_spi_send_recv( MMCFS_SPI_NUM, dat );
|
||||
platform_spi_send_recv( mmcfs_spi_nums[ id ], dat );
|
||||
}
|
||||
|
||||
|
||||
@ -85,20 +95,20 @@ void xmit_spi (BYTE dat)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE rcvr_spi (void)
|
||||
BYTE rcvr_spi (BYTE id)
|
||||
{
|
||||
DWORD rcvdat;
|
||||
|
||||
rcvdat = platform_spi_send_recv( MMCFS_SPI_NUM, 0xFF );
|
||||
rcvdat = platform_spi_send_recv( mmcfs_spi_nums[ id ], 0xFF );
|
||||
|
||||
return ( BYTE )rcvdat;
|
||||
}
|
||||
|
||||
|
||||
static
|
||||
void rcvr_spi_m (BYTE *dst)
|
||||
void rcvr_spi_m (BYTE id, BYTE *dst)
|
||||
{
|
||||
*dst = rcvr_spi();
|
||||
*dst = rcvr_spi( id );
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -106,14 +116,15 @@ void rcvr_spi_m (BYTE *dst)
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BYTE wait_ready (void)
|
||||
BYTE wait_ready (BYTE id)
|
||||
{
|
||||
BYTE res;
|
||||
timer_data_type Timer2;
|
||||
|
||||
Timer2 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
rcvr_spi();
|
||||
rcvr_spi( id );
|
||||
do
|
||||
res = rcvr_spi(); /* Wait for ready in timeout of 500ms. */
|
||||
res = rcvr_spi( id ); /* Wait for ready in timeout of 500ms. */
|
||||
while ( ( res != 0xFF ) && ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer2 ) < 500000 ) );
|
||||
|
||||
return res;
|
||||
@ -124,16 +135,16 @@ BYTE wait_ready (void)
|
||||
/* required after card power up to get it into SPI mode */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
static
|
||||
void send_initial_clock_train(void)
|
||||
void send_initial_clock_train(BYTE id)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Ensure CS is held high. */
|
||||
DESELECT();
|
||||
DESELECT(id);
|
||||
|
||||
/* Send 10 bytes over the SSI. This causes the clock to wiggle the */
|
||||
/* required number of times. */
|
||||
for(i = 0 ; i < 10 ; i++)
|
||||
rcvr_spi();
|
||||
rcvr_spi(id);
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
@ -143,7 +154,7 @@ void send_initial_clock_train(void)
|
||||
/* is nothing to do in these functions and chk_power always returns 1. */
|
||||
|
||||
static
|
||||
void power_on (void)
|
||||
void power_on (BYTE id)
|
||||
{
|
||||
/*
|
||||
* This doesn't really turn the power on, but initializes the
|
||||
@ -151,23 +162,23 @@ void power_on (void)
|
||||
*/
|
||||
|
||||
// Setup CS pin & deselect
|
||||
platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_DIR_OUTPUT );
|
||||
platform_pio_op( mmcfs_cs_ports[ id ], ( ( u32 ) 1 << mmcfs_cs_pins[ id ] ), PLATFORM_IO_PIN_DIR_OUTPUT );
|
||||
//platform_pio_op( MMCFS_CS_PORT, ( ( u32 ) 1 << MMCFS_CS_PIN ), PLATFORM_IO_PIN_PULLUP );
|
||||
DESELECT();
|
||||
DESELECT( id );
|
||||
|
||||
// Setup SPI
|
||||
platform_spi_setup( MMCFS_SPI_NUM, PLATFORM_SPI_MASTER, 400000, 0, 0, 8 );
|
||||
platform_spi_setup( mmcfs_spi_nums[ id ], PLATFORM_SPI_MASTER, 400000, 0, 0, 8 );
|
||||
|
||||
/* Set DI and CS high and apply more than 74 pulses to SCLK for the card */
|
||||
/* to be able to accept a native command. */
|
||||
send_initial_clock_train();
|
||||
send_initial_clock_train(id);
|
||||
|
||||
PowerFlag = 1;
|
||||
PowerFlag[id] = 1;
|
||||
}
|
||||
|
||||
// set the SSI speed to the max setting
|
||||
static
|
||||
void set_max_speed(void)
|
||||
void set_max_speed(BYTE id)
|
||||
{
|
||||
unsigned long i;
|
||||
|
||||
@ -177,48 +188,49 @@ void set_max_speed(void)
|
||||
i = 12500000;
|
||||
|
||||
/* Configure the SPI port */
|
||||
platform_spi_setup( MMCFS_SPI_NUM, PLATFORM_SPI_MASTER, i, 0, 0, 8 );
|
||||
platform_spi_setup( mmcfs_spi_nums[ id ], PLATFORM_SPI_MASTER, i, 0, 0, 8 );
|
||||
}
|
||||
|
||||
static
|
||||
void power_off (void)
|
||||
void power_off (BYTE id)
|
||||
{
|
||||
PowerFlag = 0;
|
||||
PowerFlag[ id ] = 0;
|
||||
}
|
||||
|
||||
static
|
||||
int chk_power(void) /* Socket power state: 0=off, 1=on */
|
||||
int chk_power(BYTE id) /* Socket power state: 0=off, 1=on */
|
||||
{
|
||||
return PowerFlag;
|
||||
return PowerFlag[ id ];
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Receive a data packet from MMC */
|
||||
/*-----------------------------------------------------------------------*/
|
||||
|
||||
static
|
||||
BOOL rcvr_datablock (
|
||||
BYTE id, /* Disk ID */
|
||||
BYTE *buff, /* Data buffer to store received data */
|
||||
UINT btr /* Byte count (must be even number) */
|
||||
)
|
||||
{
|
||||
BYTE token;
|
||||
timer_data_type Timer1;
|
||||
|
||||
Timer1 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
do { /* Wait for data packet in timeout of 100ms */
|
||||
token = rcvr_spi();
|
||||
token = rcvr_spi(id);
|
||||
} while ( ( token == 0xFF ) &&
|
||||
platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 100000 );
|
||||
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(id, buff++);
|
||||
rcvr_spi_m(id, buff++);
|
||||
} while (btr -= 2);
|
||||
rcvr_spi(); /* Discard CRC */
|
||||
rcvr_spi();
|
||||
rcvr_spi(id); /* Discard CRC */
|
||||
rcvr_spi(id);
|
||||
|
||||
return TRUE; /* Return with success */
|
||||
}
|
||||
@ -232,6 +244,7 @@ BOOL rcvr_datablock (
|
||||
#if _READONLY == 0
|
||||
static
|
||||
BOOL xmit_datablock (
|
||||
BYTE id, /* Disk ID */
|
||||
const BYTE *buff, /* 512 byte data block to be transmitted */
|
||||
BYTE token /* Data/Stop token */
|
||||
)
|
||||
@ -239,18 +252,18 @@ BOOL xmit_datablock (
|
||||
BYTE resp, wc;
|
||||
|
||||
|
||||
if (wait_ready() != 0xFF) return FALSE;
|
||||
if (wait_ready(id) != 0xFF) return FALSE;
|
||||
|
||||
xmit_spi(token); /* Xmit data token */
|
||||
xmit_spi(id,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++);
|
||||
xmit_spi(id,*buff++);
|
||||
xmit_spi(id,*buff++);
|
||||
} while (--wc);
|
||||
xmit_spi(0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(0xFF);
|
||||
resp = rcvr_spi(); /* Reveive data response */
|
||||
xmit_spi(id,0xFF); /* CRC (Dummy) */
|
||||
xmit_spi(id,0xFF);
|
||||
resp = rcvr_spi(id); /* Reveive data response */
|
||||
if ((resp & 0x1F) != 0x05) /* If not accepted, return with error */
|
||||
return FALSE;
|
||||
}
|
||||
@ -267,6 +280,7 @@ BOOL xmit_datablock (
|
||||
|
||||
static
|
||||
BYTE send_cmd (
|
||||
BYTE id, /* Disk ID */
|
||||
BYTE cmd, /* Command byte */
|
||||
DWORD arg /* Argument */
|
||||
)
|
||||
@ -274,24 +288,24 @@ BYTE send_cmd (
|
||||
BYTE n, res;
|
||||
|
||||
|
||||
if (wait_ready() != 0xFF) return 0xFF;
|
||||
if (wait_ready(id) != 0xFF) return 0xFF;
|
||||
|
||||
/* Send command packet */
|
||||
xmit_spi(cmd); /* Command */
|
||||
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] */
|
||||
xmit_spi(id,cmd); /* Command */
|
||||
xmit_spi(id,(BYTE)(arg >> 24)); /* Argument[31..24] */
|
||||
xmit_spi(id,(BYTE)(arg >> 16)); /* Argument[23..16] */
|
||||
xmit_spi(id,(BYTE)(arg >> 8)); /* Argument[15..8] */
|
||||
xmit_spi(id,(BYTE)arg); /* Argument[7..0] */
|
||||
n = 0;
|
||||
if (cmd == CMD0) n = 0x95; /* CRC for CMD0(0) */
|
||||
if (cmd == CMD8) n = 0x87; /* CRC for CMD8(0x1AA) */
|
||||
xmit_spi(n);
|
||||
xmit_spi(id,n);
|
||||
|
||||
/* Receive command response */
|
||||
if (cmd == CMD12) rcvr_spi(); /* Skip a stuff byte when stop reading */
|
||||
if (cmd == CMD12) rcvr_spi(id); /* Skip a stuff byte when stop reading */
|
||||
n = 10; /* Wait for a valid response in timeout of 10 attempts */
|
||||
do
|
||||
res = rcvr_spi();
|
||||
res = rcvr_spi(id);
|
||||
while ((res & 0x80) && --n);
|
||||
|
||||
return res; /* Return with the response value */
|
||||
@ -305,6 +319,16 @@ BYTE send_cmd (
|
||||
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
void elua_mmc_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
for( i = 0; i < NUM_CARDS; i ++ )
|
||||
{
|
||||
Stat[ i ] = STA_NOINIT;
|
||||
TriesLeft[ i ] = 2;
|
||||
}
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/* Initialize Disk Drive */
|
||||
@ -315,62 +339,61 @@ DSTATUS disk_initialize (
|
||||
)
|
||||
{
|
||||
BYTE n, ty, ocr[4];
|
||||
timer_data_type Timer1;
|
||||
|
||||
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
if (Stat & STA_NODISK) return Stat; /* No card in the socket */
|
||||
if (Stat[drv] & STA_NODISK) return Stat[drv]; /* No card in the socket */
|
||||
|
||||
do
|
||||
{
|
||||
power_on(); /* Force socket power on */
|
||||
power_on(drv); /* Force socket power on */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
ty = 0;
|
||||
if (send_cmd(CMD0, 0) == 1) { /* Enter Idle state */
|
||||
if (send_cmd(drv,CMD0, 0) == 1) { /* Enter Idle state */
|
||||
Timer1 = platform_timer_read( PLATFORM_TIMER_SYS_ID );
|
||||
if (send_cmd(CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
if (send_cmd(drv,CMD8, 0x1AA) == 1) { /* SDC Ver2+ */
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(drv);
|
||||
if (ocr[2] == 0x01 && ocr[3] == 0xAA) { /* The card can work at vdd range of 2.7-3.6V */
|
||||
do {
|
||||
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
|
||||
if (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 1UL << 30) == 0) break; /* ACMD41 with HCS bit */
|
||||
} while ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 );
|
||||
if ( ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 )
|
||||
&& send_cmd(CMD58, 0) == 0) { /* Check CCS bit (it seems pointless to check the timer here*/
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi();
|
||||
&& send_cmd(drv,CMD58, 0) == 0) { /* Check CCS bit (it seems pointless to check the timer here*/
|
||||
for (n = 0; n < 4; n++) ocr[n] = rcvr_spi(drv);
|
||||
ty = (ocr[0] & 0x40) ? 6 : 2;
|
||||
}
|
||||
}
|
||||
} else { /* SDC Ver1 or MMC */
|
||||
ty = (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
|
||||
ty = (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 0) <= 1) ? 2 : 1; /* SDC : MMC */
|
||||
do {
|
||||
if (ty == 2) {
|
||||
if (send_cmd(CMD55, 0) <= 1 && send_cmd(CMD41, 0) == 0) break; /* ACMD41 */
|
||||
if (send_cmd(drv,CMD55, 0) <= 1 && send_cmd(drv,CMD41, 0) == 0) break; /* ACMD41 */
|
||||
} else {
|
||||
if (send_cmd(CMD1, 0) == 0) break; /* CMD1 */
|
||||
if (send_cmd(drv,CMD1, 0) == 0) break; /* CMD1 */
|
||||
}
|
||||
} while ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) < 1000000 );
|
||||
if ( ( platform_timer_get_diff_crt( PLATFORM_TIMER_SYS_ID, Timer1 ) >= 1000000 )
|
||||
|| send_cmd(CMD16, 512) != 0 ) /* Select R/W block length */
|
||||
|| send_cmd(drv,CMD16, 512) != 0 ) /* Select R/W block length */
|
||||
ty = 0;
|
||||
}
|
||||
}
|
||||
CardType = ty;
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
CardType[drv] = ty;
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
if (TriesLeft)
|
||||
TriesLeft--;
|
||||
if (TriesLeft[drv])
|
||||
TriesLeft[drv]--;
|
||||
|
||||
if (ty) { /* Initialization succeded */
|
||||
Stat &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
set_max_speed();
|
||||
Stat[drv] &= ~STA_NOINIT; /* Clear STA_NOINIT */
|
||||
set_max_speed(drv);
|
||||
} else { /* Initialization failed */
|
||||
power_off();
|
||||
power_off(drv);
|
||||
}
|
||||
|
||||
} while( TriesLeft > 0 && ty == 0 );
|
||||
} while( TriesLeft[drv] > 0 && ty == 0 );
|
||||
|
||||
return Stat;
|
||||
return Stat[drv];
|
||||
}
|
||||
|
||||
|
||||
@ -383,8 +406,7 @@ DSTATUS disk_status (
|
||||
BYTE drv /* Physical drive nmuber (0) */
|
||||
)
|
||||
{
|
||||
if (drv) return STA_NOINIT; /* Supports only single drive */
|
||||
return Stat;
|
||||
return Stat[drv];
|
||||
}
|
||||
|
||||
|
||||
@ -400,30 +422,30 @@ DRESULT disk_read (
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (!count) return RES_PARERR;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
if (!(CardType & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
if (!(CardType[drv] & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
if (count == 1) { /* Single block read */
|
||||
if ((send_cmd(CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(buff, 512))
|
||||
if ((send_cmd(drv,CMD17, sector) == 0) /* READ_SINGLE_BLOCK */
|
||||
&& rcvr_datablock(drv,buff, 512))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block read */
|
||||
if (send_cmd(CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
if (send_cmd(drv,CMD18, sector) == 0) { /* READ_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!rcvr_datablock(buff, 512)) break;
|
||||
if (!rcvr_datablock(drv,buff, 512)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
send_cmd(CMD12, 0); /* STOP_TRANSMISSION */
|
||||
send_cmd(drv,CMD12, 0); /* STOP_TRANSMISSION */
|
||||
}
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
@ -442,35 +464,35 @@ DRESULT disk_write (
|
||||
BYTE count /* Sector count (1..255) */
|
||||
)
|
||||
{
|
||||
if (drv || !count) return RES_PARERR;
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat & STA_PROTECT) return RES_WRPRT;
|
||||
if (!count) return RES_PARERR;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat[drv] & STA_PROTECT) return RES_WRPRT;
|
||||
|
||||
if (!(CardType & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
if (!(CardType[drv] & 4)) sector *= 512; /* Convert to byte address if needed */
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
if (count == 1) { /* Single block write */
|
||||
if ((send_cmd(CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(buff, 0xFE))
|
||||
if ((send_cmd(drv, CMD24, sector) == 0) /* WRITE_BLOCK */
|
||||
&& xmit_datablock(drv, buff, 0xFE))
|
||||
count = 0;
|
||||
}
|
||||
else { /* Multiple block write */
|
||||
if (CardType & 2) {
|
||||
send_cmd(CMD55, 0); send_cmd(CMD23, count); /* ACMD23 */
|
||||
if (CardType[drv] & 2) {
|
||||
send_cmd(drv, CMD55, 0); send_cmd(drv, CMD23, count); /* ACMD23 */
|
||||
}
|
||||
if (send_cmd(CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
if (send_cmd(drv, CMD25, sector) == 0) { /* WRITE_MULTIPLE_BLOCK */
|
||||
do {
|
||||
if (!xmit_datablock(buff, 0xFC)) break;
|
||||
if (!xmit_datablock(drv, buff, 0xFC)) break;
|
||||
buff += 512;
|
||||
} while (--count);
|
||||
if (!xmit_datablock(0, 0xFD)) /* STOP_TRAN token */
|
||||
if (!xmit_datablock(drv, 0, 0xFD)) /* STOP_TRAN token */
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
|
||||
return count ? RES_ERROR : RES_OK;
|
||||
}
|
||||
@ -493,23 +515,21 @@ DRESULT disk_ioctl (
|
||||
WORD csize;
|
||||
|
||||
|
||||
if (drv) return RES_PARERR;
|
||||
|
||||
res = RES_ERROR;
|
||||
|
||||
if (ctrl == CTRL_POWER) {
|
||||
switch (*ptr) {
|
||||
case 0: /* Sub control code == 0 (POWER_OFF) */
|
||||
if (chk_power())
|
||||
power_off(); /* Power off */
|
||||
if (chk_power(drv))
|
||||
power_off(drv); /* Power off */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 1: /* Sub control code == 1 (POWER_ON) */
|
||||
power_on(); /* Power on */
|
||||
power_on(drv); /* Power on */
|
||||
res = RES_OK;
|
||||
break;
|
||||
case 2: /* Sub control code == 2 (POWER_GET) */
|
||||
*(ptr+1) = (BYTE)chk_power();
|
||||
*(ptr+1) = (BYTE)chk_power(drv);
|
||||
res = RES_OK;
|
||||
break;
|
||||
default :
|
||||
@ -517,13 +537,13 @@ DRESULT disk_ioctl (
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (Stat & STA_NOINIT) return RES_NOTRDY;
|
||||
if (Stat[drv] & STA_NOINIT) return RES_NOTRDY;
|
||||
|
||||
SELECT(); /* CS = L */
|
||||
SELECT(drv); /* CS = L */
|
||||
|
||||
switch (ctrl) {
|
||||
case GET_SECTOR_COUNT : /* Get number of sectors on the disk (DWORD) */
|
||||
if ((send_cmd(CMD9, 0) == 0) && rcvr_datablock(csd, 16)) {
|
||||
if ((send_cmd(drv,CMD9, 0) == 0) && rcvr_datablock(drv,csd, 16)) {
|
||||
if ((csd[0] >> 6) == 1) { /* SDC ver 2.00 */
|
||||
csize = csd[9] + ((WORD)csd[8] << 8) + 1;
|
||||
*(DWORD*)buff = (DWORD)csize << 10;
|
||||
@ -542,26 +562,26 @@ DRESULT disk_ioctl (
|
||||
break;
|
||||
|
||||
case CTRL_SYNC : /* Make sure that data has been written */
|
||||
if (wait_ready() == 0xFF)
|
||||
if (wait_ready(drv) == 0xFF)
|
||||
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))
|
||||
if (send_cmd(drv,CMD9, 0) == 0 /* READ_CSD */
|
||||
&& rcvr_datablock(drv, 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))
|
||||
if (send_cmd(drv, CMD10, 0) == 0 /* READ_CID */
|
||||
&& rcvr_datablock(drv, 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 */
|
||||
if (send_cmd(drv, CMD58, 0) == 0) { /* READ_OCR */
|
||||
for (n = 0; n < 4; n++)
|
||||
*ptr++ = rcvr_spi();
|
||||
*ptr++ = rcvr_spi(drv);
|
||||
res = RES_OK;
|
||||
}
|
||||
|
||||
@ -574,8 +594,8 @@ DRESULT disk_ioctl (
|
||||
res = RES_PARERR;
|
||||
}
|
||||
|
||||
DESELECT(); /* CS = H */
|
||||
rcvr_spi(); /* Idle (Release DO) */
|
||||
DESELECT(drv); /* CS = H */
|
||||
rcvr_spi(drv); /* Idle (Release DO) */
|
||||
}
|
||||
|
||||
return res;
|
||||
|
@ -120,7 +120,11 @@
|
||||
/ Physical Drive Configurations
|
||||
/----------------------------------------------------------------------------*/
|
||||
|
||||
#ifndef PLATFORM_MMC_NUM_CARDS
|
||||
#define _DRIVES 1
|
||||
#else
|
||||
#define _DRIVES PLATFORM_MMC_NUM_CARDS
|
||||
#endif
|
||||
/* Number of volumes (logical drives) to be used. */
|
||||
|
||||
|
||||
|
65
src/mmcfs.c
65
src/mmcfs.c
@ -20,8 +20,16 @@
|
||||
static FIL mmcfs_fd_table[ MMCFS_MAX_FDS ];
|
||||
static int mmcfs_num_fd;
|
||||
|
||||
extern void elua_mmc_init();
|
||||
|
||||
#ifndef PLATFORM_MMC_NUM_CARDS
|
||||
#define NUM_CARDS 1
|
||||
#else
|
||||
#define NUM_CARDS PLATFORM_MMC_NUM_CARDS
|
||||
#endif
|
||||
|
||||
// Data structures used by FatFs
|
||||
static FATFS mmc_fs;
|
||||
static FATFS mmc_fs[ NUM_CARDS ];
|
||||
static FIL mmc_fileObject;
|
||||
//static DIR mmc_dir;
|
||||
//static FILINFO mmc_fileInfo;
|
||||
@ -31,9 +39,6 @@ typedef struct
|
||||
struct dm_dirent *pdm;
|
||||
} MMCFS_DIRENT_DATA;
|
||||
|
||||
#define PATH_BUF_SIZE 40
|
||||
static char mmc_pathBuf[PATH_BUF_SIZE];
|
||||
|
||||
static int mmcfs_find_empty_fd( void )
|
||||
{
|
||||
int i;
|
||||
@ -48,6 +53,8 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
{
|
||||
int fd;
|
||||
int mmc_mode;
|
||||
char *mmc_pathBuf;
|
||||
int drv_num = *( int* )pdata;
|
||||
|
||||
if (mmcfs_num_fd == MMCFS_MAX_FDS)
|
||||
{
|
||||
@ -56,10 +63,15 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
}
|
||||
|
||||
// Default to top directory if none given
|
||||
mmc_pathBuf[0] = 0;
|
||||
if (strchr(path, '/') == NULL)
|
||||
strcat(mmc_pathBuf, "/");
|
||||
strcat(mmc_pathBuf, path);
|
||||
asprintf( &mmc_pathBuf, "%d:/%s", drv_num, path );
|
||||
else
|
||||
asprintf( &mmc_pathBuf, "%d:%s", drv_num, path );
|
||||
if( mmc_pathBuf == NULL )
|
||||
{
|
||||
r->_errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Scrub binary flag, if defined
|
||||
#ifdef O_BINARY
|
||||
@ -70,6 +82,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
if ((flags & O_ACCMODE) != O_RDONLY)
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
mmc_mode = FA_OPEN_EXISTING & FA_READ;
|
||||
@ -86,6 +99,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
else
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -98,6 +112,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
else
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
#endif // _FS_READONLY
|
||||
@ -106,6 +121,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
if (f_open(&mmc_fileObject, mmc_pathBuf, mmc_mode) != FR_OK)
|
||||
{
|
||||
r->_errno = ENOENT;
|
||||
free( mmc_pathBuf );
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -114,6 +130,7 @@ static int mmcfs_open_r( struct _reent *r, const char *path, int flags, int mode
|
||||
fd = mmcfs_find_empty_fd();
|
||||
memcpy(mmcfs_fd_table + fd, &mmc_fileObject, sizeof(FIL));
|
||||
mmcfs_num_fd ++;
|
||||
free( mmc_pathBuf );
|
||||
return fd;
|
||||
}
|
||||
|
||||
@ -196,6 +213,8 @@ static void* mmcfs_opendir_r( struct _reent *r, const char* dname, void *pdata )
|
||||
{
|
||||
void* res = NULL;
|
||||
MMCFS_DIRENT_DATA *pd = ( MMCFS_DIRENT_DATA* )malloc( sizeof( MMCFS_DIRENT_DATA ) );
|
||||
int drv_num = *( int* )pdata;
|
||||
char *pname = NULL;
|
||||
|
||||
if( !pd )
|
||||
return NULL;
|
||||
@ -205,9 +224,10 @@ static void* mmcfs_opendir_r( struct _reent *r, const char* dname, void *pdata )
|
||||
if( ( pd->pdm = ( struct dm_dirent* )malloc( sizeof( struct dm_dirent ) ) ) == NULL )
|
||||
goto out;
|
||||
if( !dname || strlen( dname ) == 0 )
|
||||
res = f_opendir( pd->dir, "/" ) != FR_OK ? NULL : pd;
|
||||
asprintf( &pname, "%d:/", drv_num );
|
||||
else
|
||||
res = f_opendir( pd->dir, dname ) != FR_OK ? NULL : pd;
|
||||
asprintf( &pname, "%d:%s", drv_num, dname );
|
||||
res = f_opendir( pd->dir, pname ) != FR_OK ? NULL : pd;
|
||||
out:
|
||||
if( res == NULL )
|
||||
{
|
||||
@ -217,6 +237,8 @@ out:
|
||||
free( pd->pdm );
|
||||
free( pd );
|
||||
}
|
||||
if( pname )
|
||||
free( pname );
|
||||
return res;
|
||||
}
|
||||
|
||||
@ -292,10 +314,29 @@ static const DM_DEVICE mmcfs_device =
|
||||
|
||||
int mmcfs_init()
|
||||
{
|
||||
// Mount the MMC file system using logical disk 0
|
||||
if ( f_mount( 0, &mmc_fs ) != FR_OK )
|
||||
elua_mmc_init();
|
||||
#if NUM_CARDS == 1
|
||||
static int cid = 0;
|
||||
// A single MMCFS
|
||||
if ( f_mount( 0, mmc_fs ) != FR_OK )
|
||||
return DM_ERR_INIT;
|
||||
return dm_register( "/mmc", NULL, &mmcfs_device );
|
||||
return dm_register( "/mmc", &cid, &mmcfs_device );
|
||||
#else // #if NUM_CARDS == 1
|
||||
int i;
|
||||
static char names[ NUM_CARDS ][ 6 ];
|
||||
static int ids[ NUM_CARDS ];
|
||||
|
||||
// [TODO] add more error checking!
|
||||
for( i = 0; i < NUM_CARDS; i ++ )
|
||||
if( f_mount( i, mmc_fs + i ) == FR_OK )
|
||||
{
|
||||
printf( "MOUNTED %d\n", i );
|
||||
ids[ i ] = i;
|
||||
sprintf( names[ i ], "/mmc%d", i );
|
||||
dm_register( names[ i ], ids + i, &mmcfs_device );
|
||||
}
|
||||
return DM_OK;
|
||||
#endif // #if NUM_CARDS == 1
|
||||
}
|
||||
|
||||
#else // #ifdef BUILD_MMCFS
|
||||
|
Loading…
x
Reference in New Issue
Block a user