📄 mmc.c
字号:
if( wait_for( RSPDNE ) == 0 )
{
// Resp = R2, Should probably check for something
get_rsp();
return( 0 );
}
return( -1 );
}
/*NOTE the default rca is 0x0001. 0x0000 is used by CMD7 to deselect
all the cards, so you cannot assign it to a card*/
// Tested, tnyc
static int set_relative_addr(unsigned short rca)
{
if( Debug )
clear_rsp();
pMMC->argh = rca;
pMMC->argl = STUFF_BITS;
pMMC->cmd = SET_RELATIVE_ADDR;
if( wait_for( RSPDNE ) == 0 )
{
// Resp = R1
get_card_status();
return(0);
}
return( -1 );
}
// Tested, tnyc
static int send_status(unsigned short rca)
{
if( Debug )
clear_rsp();
pMMC->argh = rca;
pMMC->argl = STUFF_BITS;
pMMC->cmd = SEND_STATUS;
if( wait_for( RSPDNE ) == 0 )
{
// Resp = R1
get_card_status();
return(0);
}
return( -1 );
}
// Tested, tnyc
static int send_cid(unsigned short rca)
{
pMMC->argh = rca;
pMMC->argl = STUFF_BITS;
pMMC->cmd = SEND_CID;
if( wait_for( RSPDNE ) == 0 )
{
// Resp = R2
get_card_cid();
return(0);
}
return( -1 );
}
// Tested, tync
static int send_csd(unsigned short rca)
{
pMMC->argh = rca;
pMMC->argl = STUFF_BITS;
pMMC->cmd = SEND_CSD;
if( wait_for( RSPDNE ) == 0 )
{
// Resp = R2
get_card_csd();
return(0);
}
return( -1 );
}
// Tested, tnyc
static int select_card(unsigned short rca)
{
// Select the card then check status to see if
// we are in the proper state
pMMC->argh = rca;
pMMC->argl = STUFF_BITS;
pMMC->cmd = SELECT_CARD;
if( wait_for( RSPDNE ) == 0 )
{
if( rca > 0 )
{
if( ( send_status( rca ) == 0 )
&& ( ( CardStatus.state == tran )
|| ( CardStatus.state == prg )))
return(0);
}
}
return( -1 );
}
// Tested, tnyc
static int deselect_card( unsigned short rca )
{
// Deselect the card then check status to see if
// we are in the proper state. Because we are
// using rca = 0 to deselect there will not be
// the typical R1 response.
pMMC->argh = 0;
pMMC->argl = STUFF_BITS;
pMMC->cmd = DESELECT_CARD;
if( wait_for( RSPDNE ) == 0 )
{
if( ( send_status( rca ) == 0 )
&& ( ( CardStatus.state == stby )
|| ( CardStatus.state == dis )))
return(0);
}
return( -1 );
}
static int set_blocklen( unsigned short block_len )
{
pMMC->argh = 0;
pMMC->argl = block_len;
pMMC->cmd = SET_BLOCKLEN;
if( wait_for( RSPDNE ) == 0 )
{
CurrentBlen = block_len;
return(0);
}
return( -1 );
}
// Tested, tnyc, just one block
static int read_single_block( unsigned long address )
{
unsigned short count = CurrentBlen/2;
unsigned short * pBuf = ReadBlock;
register volatile unsigned short stat;
int error;
int ddr;
// The nblk and blen parameters can be a little confusing.
// blen can be less then the CSD blen which is usually 512.
// Thus I can simply read 10 bytes.
pMMC->nblk = 1;
pMMC->blen = CurrentBlen;
pMMC->argl = (unsigned short)address;
pMMC->argh = (unsigned short)(address>>16);
pMMC->cmd = READ_SINGLE_BLOCK | DATA | DCLR;
// May want to check for a response. But for now
// we just check for data.
if( count < 1 )
return( -1 );
do
{
do
{
stat = pMMC->st0;
ddr = ((stat & DRRDY) != 0);
error = ((stat & ( CRCRD | TOUTRD)) != 0 );
// Checking for early DATDNE
Done |= (stat & 1);
}while( !error && !ddr );
if(ddr)
*pBuf++ = pMMC->ddr;
}while( !error && --count );
// Test to make sure that we see a DATDNE signal
if( (error == 0) && (Done == 0) )
{
if( (error = wait_for( DATDNE )) == 0 )
Done = 1;
}
// Check for errors.
return( error == 0 ? 0 : -1 );
}
// Tested, tnyc. Just one block
int write_single_block( unsigned long address )
{
/*设置一段的长度,为256,每次发送一个word*/
unsigned short count = CurrentBlen/2;
/*写入的源地址*/
unsigned short * pBuf = ReadBlock;
/*状态控制字*/
register volatile unsigned short stat;
/*错误暂存*/
int error;
/*发送缓冲区*/
int dxr;
/*等待时间设定*/
unsigned int sectime = 0 ;
int i;
// The nblk and blen parameters can be a little confusing.
// blen can be less then the CSD blen which is usually 512.
// Thus I can simply read 10 bytes.
pMMC->nblk = 1;
pMMC->blen = CurrentBlen;
pMMC->argl = (unsigned short)address;
pMMC->argh = (unsigned short)(address>>16);
pMMC->cmd = WRITE_BLOCK | DATA | WRITE| DCLR;
sectime = 2;
DelayUsec(sectime);
/*写入512Bytes*/
for(i = 0; i< count;i++)
{
do
{
/*读当前mmc的状态*/
stat = pMMC->st0;
/*判断是否准备好,可以发送数据*/
dxr = ((stat & DXRDY) != 0 );
error = ((stat & ( CRCWR ))!= 0 );
// Checking for early DATDNE
Done |= ( stat & 1 );
}while( !error && !dxr );
/*发送数据*/
if(dxr)
{
pMMC->dxr = *pBuf++;
}
}
DelayUsec(10);
/*读取CRC状态,判断数据是否被接收*/
do
{
stat = pMMC->drsp;
stat = stat & 0xf;
}while(stat != 0x5);
// Test to make sure that we see a DATDNE signal
if( (error == 0) && (Done == 0) )
{
if( (error = wait_for( DATDNE )) == 0 )
{
Done = 1;
}
}
/*读取MMCDRSP*/
do
{
TestFail = send_status( MmcAddr );
if(TestFail)
{
return(-1 );
}
}while( CardStatus.state == prg );
// Check for errors.
return( error == 0 ? 0 : -1 );
}
void MMC_InitClock()
{
// Reset the command/data
pMMC->ctl= CMDRST | DATRST;
// controls the MMC clock-- should be 20 Mhz for MMC mode and 5 Mhz for SPI mode
// MMC clock = function clock / (MMCCLK_RATE + 1)
//
pMMC->clk &= ~CLKEN; // Turn off the clock before switching to new rate
// This has no effect on the FPGA implementation. The functional clock
// equal to the C55xx clockout.
pMMC->fckctl = dspclk.pllmult - 1;
pMMC->clk = 0x000e; // Clock divide by 8 ~400KHz = 9
pMMC->im = 0; /*all interrupts are masked */
pMMC->tor = 16; /*response time out */
pMMC->tod = 0; /*no data read time out */
/*need to set the length of a block in bytes-- must be same as in CSD register*/
pMMC->blen = BLEN;
pMMC->ctl = 0; /*enable dat and cmd lines*/
/* enable the clock ???? where to put it ????? */
/*maybe put it before go idle state????*/
pMMC->clk |= CLKEN;
// Wait long enough MMC module to reset.
DelayUsec(10);
}
int MMC_Init(void)
{
PC55XX_EXTBUS pExtBus = (PC55XX_EXTBUS)C55XX_EXTBUS_ADDR;
volatile long delay = 1000;
int error = 0;
// Configure serial port 2 for MMC mode
WriteField(pExtBus -> exbussel, EXBUSSEL_SPMODE_MMC, EXBUSSEL_SP2MODE);
SaveStat0 = 0;
SaveStat1 = 0;
OpLoop = 0;
TestFail = 0;
Debug = 1; // Enable debug stuff
CurrentBlen = 512;
MmcAddr = 2; // Non-default address
MMC_InitClock();
if( go_idle_state() != 0 )
{
error = ERROR_IDLE;
return( error);
}
if( send_op_cond() != 0 )
{
error = ERROR_OP;
return( error);
}
// For simulation test there is only one card so skip
// multiple card stuff
if( all_send_cid() != 0 )
{
error = ERROR_ALL_CID;
return( error);
}
// Set the RCA to something other then the
// default of 0x0001
if( set_relative_addr( MmcAddr ) != 0 )
{
error = ERROR_ADDR;
return( error);
}
// Make sure the card is in Standby at this point
if( send_status( MmcAddr ) != 0 )
{
error = ERROR_STATUS;
return( error);
}
if( (CardStatus.state) != stby )
{
error = ERROR_STATUS;
// return( error);
}
// Read the CID via the CID command. Check for the Sandisk ID.
// Need to know the Siemens ID.
if( send_cid( MmcAddr ) != 0 )
{
error = ERROR_CID;
return( error);
}
// Read the CSD and verify that structure is for MMC protocol version 1.4
if( send_csd( MmcAddr ) != 0 )
{
error = ERROR_CSD;
return( error);
}
// if( CardCsd.csd_struct != 1 )
// {
// error = ERROR_CSD_VER;
// return( error);
// }
if( select_card( MmcAddr ))
{
error = -1;
return( error);
}
return( 0 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -