📄 mmc_samplecode.txt
字号:
MultiMediaCard device access sample code:
All communication between the host and MultiMediaCards is controlled by the host.
GO_IDLE_STATE(CMD0) is the software reset command and sets all MultiMediaCards
to Idle State.
SEND_OP_COND(CMD1) is designed to provide MultiMediaCard hosts with a mechanism
to identify and reject cards which do not match the host's desired Vdd range.
The following sample code will give you an idea about how to initialize the card
by sending CMD0 and CMD1 to MultiMediaCard in SPI mode and MMC mode.
I) In SPI mode
The MultiMediaCard wakes up in the MMC mode. It will enter SPI mode if the CS
signal is asserted during the reception of the reset command(CMD0) and the card
will respond with the SPI mode R1 response. The default command structure/protocol
for SPI mode is that CRC checking is disabled. Since the card powers up in
MMC mode, CMD0 must be followed by a valid CRC byte. Once in SPI mode, CRCs are
disabled by default.
/*************************************************
A Test program to test UART0 Sync. function
and CMD0 and CMD1 of MMC card in SPI mode on
Mitsubishi M16C MAS0654 Evaluation Board.
P60--SPI_CS, P61--CLK, P62--RxD, P63--TxD
(c) SanDisk Corporation
Nov., 1999
*************************************************/
#include "sfr62.h"
/* Register & I/O Assignments */
#define SPI_MODE_REG u0mr
#define SPI_CTRL0_REG u0c0
#define SPI_CTRL1_REG u0c1
#define SPI_BRG_REG u0brg
#define SPI_UCON_NUM 2
#define SPI_TB_REG u0tbl
#define SPI_RB_REG u0rbl
#define SPI_TXIRQ_REG s0tic
#define SPI_RXIRQ_REG s0ric
#define SPI_CS p6_0
#define TXREG u0tbl
#define RCREG u0rbl
#define DUMMY 0xff
/* Function Prototypes */
int main(void);
int sendcmd0(void);
int sendcmd1(void);
int initSPI(void);
void setdelay(int numdelay);
/* Global variables */
volatile int resp1 = 0xff; /* Contains the response byte from MMC */
/***************************************
The main function will initialize the
SIO3 sync. port and enable interrupt,
then it'll initialize the MMC card. If
successful, a 0x01(R1) response can
be read back.
***************************************/
int main(void)
{
int count1 = 16;
int count2 = 0x6fff;
/*
Initilize a timer to delay 1/2 clock hold for the last serial bit
1/2 clock period = 400ns/2 = 200ns when transfer rate is 2.5Mhz
to be safe, 300ns is used here using TA0(timer) interrupt. As the SIO3
interrupt req.bit gets set in the middle of the last transferred bit.
So a deay is implemented to prevent writing to the TXREG before the delay
expires. Delay function is not activated here, as the interrupt service
routine takes time. It can be activated if necessary.
*/
ta0ic = 0x04; /* TIMER A0 Interrupt control reg set, ILVL = 4 */
ta0mr = 0x00; /* f1 = 100 nsec */
ta0 = 0x02; /* make 300 nsec */
tabsr = 0x00; /* TIMER A0 stop */
pur1 |= 0x80; /* Apply pull-ups to P74-7 */
SPI_CS = 0x1; /* SPI_CS = "H" before pd7 is open */
pd7_7 = 0x1; /* Set p7.7 as CS from HOST to MMC */
pur2 |= 0x04; /* Apply Pull-ups to P90 to P93 */
p9 = 0xff; /* Output "H" first */
prc2 = 0x1; /* Enable writing to PD9 and SIO3/4 CTL register, clear protect. Bit symbol */
pd9 = 0x05;
prc2 = 0x0; /* Disenable writing, recover protect */
ifsr = 0x00; /* Maybe ok, reset value is 0x00, SIO3 instead of INT4 is the interrupt cause */
s3ic = 0x05; /* Clear Int. Request bit, set ILVL = 5 before write to xmit/rcv reg.
The debugger uses level 7! */
prc2 = 0x1; /* Enable writing to PD9 and SIO3/4 CTL register */
s3c = 0xe8; /*
Confusing, may need change!!
MSB first, Internal clock, f1, ??
*/
prcr &= 0x00; /* Disenable writing to P9 and SIO3/4 */
s3brg = 0x01; /* 10/(2(n+1)) = 2.5Mhz */
asm("fset i"); /* flg |= 0x40; */ /* KD30 debugger also Enables all Maskable Interrupts */
/* Note: "-" edge sent out data by SIO3 */
if( initSPI() ) /* Send out 80 clocks */
{
SPI_CS = 0x0; /* Enable CS */
/***************************************************
CMD0, sent once, then pulling until R1 = 0x01
***************************************************/
if ( !sendcmd0() )
return(0);
/* argu 1 == 8 clock pulses delay before response, 2 == 16... */
setdelay(1);
while (count1) /* Wait for limited clock cycles,16 cycles here. */
{
TXREG = DUMMY;
while( sioflag != 0x55 );
sioflag = 0x00; /* Else Clear flag */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
/* tabsr |= 0x01;*/ /* TIMER A0 start */
/* while ( ta0flag != 0x00aa )
asm("nop");
ta0flag = 0x00; */ /* Else Clear flag */
/* Read the RCV register */
resp1 = RCREG;
count1--;
if(resp1 == 0x01)
break;
}
if (count1 == 0) /* report error */
exit(0);
/* Delay between CMD0 and CMD1 */
setdelay(1);
/***********************************************************
Repeat sending CMD1 until R1 is clear, delay between CMD1s
************************************************************/
while(count2)
{
if ( !sendcmd1() )
return(0);
/* A delay before dealing with response */
setdelay(1);
/* After the delay, send a dummy byte to read the RCV buffer. */
TXREG = DUMMY;
while( sioflag != 0x55 );
sioflag = 0x00; /* Else Clear flag */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
/* tabsr |= 0x01; */ /* TIMER A0 start */
/*while ( ta0flag != 0x00aa )
asm("nop");*/
/*ta0flag = 0x00;*/ /* Else Clear flag */
/* Read the RCV register */
resp1 = RCREG;
count2--;
if (resp1 == 0x00)
break;
setdelay(1); /* A dummy byte delay between any two commands */
}
if (count2 == 0x00) /* Counter out, exit */
exit(0);
} /* if(initSPI()) */
SPI_CS = 0x1; /* Disenable CS */
return (1);
}
/*********************************
SIO3 Interrupt Service Routine.
This routine does nothing more
than setting a global flag.
*********************************/
void sio3_isr(void)
{
/* asm("fclr i"); */ /* KD30 won't allow, Disenable interrupt */
sioflag = 0x55;
/* asm("fset i"); */ /* Reenable interrupt */
}
/*********************************
Timer A0 Interrupt Service Routine.
This routine does nothing more
than setting a global flag.
*********************************/
void ta0_isr(void)
{
/* asm("fclr i"); */ /* KD30 won't allow, Disenable interrupt */
tabsr = 0x00; /* TIMER A0 stop */
ta0flag = 0xaa;
ta0 = 0x02; /* Readload, make 300 nsec */
/* asm("fset i"); */ /* Reenable interrupt */
}
/********************************
This routine will send out
80 clocks to MMC card for init.
If successful, a "1" will be
returned.
********************************/
int initSPI(void)
{
/*
Send data directly to transmit/receive register, no buffer any more.
Expecting an interrupt after each send.
*/
int j;
SPI_CS = 0x1;
/* Send out 80 clocks to MMC card */
for(j = 0; j < 10; j++)
{
TXREG = DUMMY; /* Send out 8 clock pulses and cause an interrupt */
/* Wait till transmit buffer is empty */
while ( sioflag != 0x0055 );
sioflag = 0x00; /* Else Clear flag */
/* Use timer int. instead of loops
Then wait for a 1/2 transfer clk period delay caused by timer A0 */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
//tabsr |= 0x01; /* TIMER A0 start */
//while ( ta0flag != 0x00aa );
/*asm("nop"); */
//ta0flag = 0x00; /* Else Clear flag */
}
return(1);
}
/**********************************
Send COMMAND0 function.
A return value of "1" indicates
success.
**********************************/
int sendcmd0(void)
{
char cmd0buf[6] = {0x40,0x00,0x00,0x00,0x00,0x95};
int k;
for(k = 0; k < 6; k++)
{
TXREG = cmd0buf[k]; /* Send out a byte of CMD0 */
/* Wait till transmit buffer is empty */
while ( sioflag != 0x55 );
sioflag = 0x00; /* Else Clear flag */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
//tabsr |= 0x01; /* TIMER A0 start */
//while ( ta0flag != 0x00aa )
// asm("nop");
//ta0flag = 0x00; /* Else Clear flag */
}
return(1);
}
/**********************************
Send COMMAND1 function.
A return value of "1" indicates
success.
**********************************/
int sendcmd1(void)
{
char cmd1buf[6] = {0x41,0x00,0x00,0x00,0x00,0xff};
int jj;
for(jj = 0; jj < 6; jj++)
{
TXREG = cmd1buf[jj]; /* Send out a byte of CMD1 */
/* Wait till transmit buffer is empty */
while ( sioflag != 0x55 );
sioflag = 0x00; /* Else Clear flag */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
//tabsr |= 0x01; /* TIMER A0 start */
//while ( ta0flag != 0xaa )
// asm("nop");
//ta0flag = 0x00; /* Else Clear flag */
}
return(1);
}
/*************************************
A delay function which can give
1.. delaynum times of 8 clock pulses.
At least 8 clocks.
*************************************/
void setdelay(int number)
{
int ii;
for(ii = 0; ii < number; ii++)
{
/* A delay */
TXREG = DUMMY;
while( sioflag != 0x55 );
sioflag = 0x00; /* Else Clear flag */
/* Wait for a 1/2 transfer clk period delay caused by timer A0 */
//tabsr |= 0x01; /* TIMER A0 start */
//while ( ta0flag != 0x00aa );
// asm("nop");
//ta0flag = 0x00; /* Else Clear flag */
}
}
II) In MMC mode
The following code snippet demonstrates the procedure of initialize MMC card
through SanDisk verilog controller.
/**************************************************************************
* Name: startMMC80Clocks - Start the MMC devices
*
* Description:
* The 80 clocks is required to start initializing the
* devices.
*
* Input:
* ctrlNo Controller number
*
* Output:
* Sending out 80 clocks.
*
* Return:
* None
*
**************************************************************************/
SDVOID startMMC80Clocks(INT16 ctrlNo)
{
UINT16 ij, dStatus;
ctrlNo = ctrlNo ; /* get rid of warning */
/* Send the 80 clocks to start all devices */
SDWRITE_DATA16((portAddress+CMD_DAT_CONT_REG), SEND_80_CLOCKS);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -