📄 mmc.c
字号:
/* ----------------------------------------------------------- */
/* MMRs Bit position of command */
/* ----------------------------------------------------------- */
/* [47] (start bit) */
/* [46] (transmission bit) */
/* MMCCMD[5:0] [45:40] (command index) */
/* MMCARGH [39:24] (argument) */
/* MMCARGL [23:8] (argument) */
/* [7:1] (CRC7) */
/* [0] (end bit) */
/* ----------------------------------------------------------- */
/* */
/* NOTE: */
/* pMMC->cmd tells whether to transfer data or not (DATA), block are stream transfer */
/* data read or write (WRITE), the response format (read note) and busy signal expected*/
/* (BSYEXP). */
/* NOTE: For each command, I have already inserted the response expected and where or not*/
/* it expects a busy signal because those seem to be predefined. might do read/write and*/
/* data bit too as pre defined, but leaving out for debugging purposes??????? */
/**************************************************************************************** */
int MMC_Init(void);
void PLL_Init(int freq);
int write_single_block( unsigned long address );
static int read_single_block( unsigned long address );
static int send_status(unsigned short rca);
static int deselect_card( unsigned short rca );
int firstbit(unsigned short mask);
// Read and write from an address
#define Read(addr) addr
#define Write(addr,data) addr = data
// Set or clear all bits in the mask
#define ClearMask(addr,mask) addr = (addr & ~(mask))
#define SetMask(addr,mask) addr = (addr | (mask))
// Read and write data at addr, only bits in mask are affected
#define ReadMask(addr,mask) (addr & (mask))
#define WriteMask(addr,data,mask) addr = (addr & ~(mask)) | (data)
// Read and write data at addr, shift data so that bit 0 of data is aligned
// with lowest set bit in mask. Only bits in mask are modified. Example
// with address 0x1000 initial contents = 0x4007:
// WriteField(0x1000, 0x56, 0x0ff0) will set address 0x1000 to 0x4567.
#define ReadField(addr,mask) ((addr & (mask)) >> firstbit(mask))
#define WriteField(addr,data,mask) addr = (addr & ~(mask)) | (data << firstbit(mask))
main()
{
int TestFail;
int j;
unsigned long BlockAddr = 0;
/*系统初始化*/
/*设置系统的运行速度为144MHz*/
PLL_Init(120);
/*mmc初始化*/
if(MMC_Init())
{
for(;;)
{}
}
BlockAddr = 0;
for( j=0; j<4; j++ )
{
for( OpLoop=0; OpLoop<256; OpLoop++)
{
ReadBlock[OpLoop] = OpLoop + j;
}
OpLoop = 0;
// Set done to 0.
//If we get a DATADNE then this will be set to 1
// if DATDNE is working.
Done = 0;
TestFail = write_single_block( BlockAddr );
if(TestFail)
{
return(-1);
}
BlockAddr += 512;
}
BlockAddr = 0;
for( j=0; j<4; j++ )
{
// Set done to 0. If we get a DATADNE then this will be
// set to 1 if DATDNE is working.
Done = 0;
read_single_block(BlockAddr);
BlockAddr += 512;
}
if( TestFail = deselect_card( MmcAddr ))
{
return(-1);
}
/*测试完成,进入死循环*/
for(;;)
{}
}
void DelayUsec(int usec)
{
unsigned int i, j,k;
for (i=0;i<usec;i++)
{
for (j = 0; j < 10; j++);
{k = k+1;}
}
}
void PLL_Init(int freq)
{
PC55XX_CMOD pCMOD = (PC55XX_CMOD)C55XX_CLKMD_ADDR;
// Calculate PLL multiplier values (only integral multiples now)
dspclk.clkin = DSP_CLKIN;
dspclk.pllmult = freq / dspclk.clkin;
dspclk.freq = dspclk.pllmult * dspclk.clkin;
dspclk.plldiv = 0;
dspclk.nullloopclk = NULLLOOP_CLK;
// Turn the PLL off
ClearMask(pCMOD -> clkmd, CLKMD_PLLENABLE);
while(ReadMask(pCMOD -> clkmd, CLKMD_LOCK));
// Initialize PLL flags
ClearMask(pCMOD -> clkmd, CLKMD_IAI);
SetMask(pCMOD -> clkmd, CLKMD_IOB | CLKMD_BREAKLN);
// Set the multiplier/divisor
WriteMask(pCMOD -> clkmd,
CLKMD_PLLDIV_1 | CLKMD_BYPASSDIV_1,
CLKMD_PLLDIV_MASK | CLKMD_BYPASSDIV_MASK);
WriteField(pCMOD -> clkmd, dspclk.pllmult, CLKMD_PLLMULT_MASK);
// Enable the PLL and wait for lock
SetMask(pCMOD -> clkmd, CLKMD_PLLENABLE);
while(!ReadMask(pCMOD -> clkmd, CLKMD_LOCK));
}
int firstbit(unsigned short mask)
{
int shiftamt;
unsigned short bit;
// Find offset of first bit in mask
bit = 1;
for (shiftamt = 0; shiftamt < 16; shiftamt++) {
if (bit & mask)
break;
bit = bit << 1;
}
return shiftamt;
}
static void dump_regs( void )
{
Mmc.fckctl = pMMC->fckctl;
Mmc.ctl = pMMC->ctl;
Mmc.clk = pMMC->clk;
Mmc.st0 = pMMC->st0;
Mmc.st1 = pMMC->st1;
Mmc.im = pMMC->im;
Mmc.tor = pMMC->tor;
Mmc.tod = pMMC->tod;
Mmc.blen = pMMC->blen;
Mmc.nblk = pMMC->nblk;
Mmc.nblc = pMMC->nblc;
Mmc.ddr = pMMC->ddr;
Mmc.dxr = pMMC->dxr;
Mmc.cmd = pMMC->cmd;
Mmc.argl = pMMC->argl;
Mmc.argh = pMMC->argh;
Mmc.rsp0 = pMMC->rsp0;
Mmc.rsp1 = pMMC->rsp1;
Mmc.rsp2 = pMMC->rsp2;
Mmc.rsp3 = pMMC->rsp3;
Mmc.rsp4 = pMMC->rsp4;
Mmc.rsp5 = pMMC->rsp5;
Mmc.rsp6 = pMMC->rsp6;
Mmc.rsp7 = pMMC->rsp7;
Mmc.drsp = pMMC->drsp;
Mmc.etok = pMMC->etok;
Mmc.cidx = pMMC->cidx;
}
static void clear_rsp( void )
{
pMMC->rsp0 = 0;
pMMC->rsp1 = 0;
pMMC->rsp2 = 0;
pMMC->rsp3 = 0;
pMMC->rsp4 = 0;
pMMC->rsp5 = 0;
pMMC->rsp6 = 0;
pMMC->rsp7 = 0;
pMMC->drsp = 0;
pMMC->etok = 0;
pMMC->cidx = 0;
}
static void get_rsp( void )
{
Mmc.rsp0 = pMMC->rsp0;
Mmc.rsp1 = pMMC->rsp1;
Mmc.rsp2 = pMMC->rsp2;
Mmc.rsp3 = pMMC->rsp3;
Mmc.rsp4 = pMMC->rsp4;
Mmc.rsp5 = pMMC->rsp5;
Mmc.rsp6 = pMMC->rsp6;
Mmc.rsp7 = pMMC->rsp7;
Mmc.drsp = pMMC->drsp;
Mmc.etok = pMMC->etok;
Mmc.cidx = pMMC->cidx;
}
static void get_card_status( void )
{
Mmc.rsp6 = pMMC->rsp6;
Mmc.rsp7 = pMMC->rsp7;
CardStatus.busy = ((Mmc.rsp6 >> 8) & 1 );
CardStatus.state = (CARD_STATE)((Mmc.rsp6 >> 9) & 0xf );
CardStatus.erase_clrd = ((Mmc.rsp6 >> 13) & 1 );
CardStatus.erase_partial = ((Mmc.rsp6 >> 15) & 1 );
CardStatus.error_flags = Mmc.rsp7;
}
static void get_card_cid( void )
{
unsigned long temp;
get_rsp();
CardCid.year = (Mmc.rsp0 >> 8 ) & 0xF; // 11:8
CardCid.month = (Mmc.rsp0 >> 12 ) & 0xF; // 12:15
CardCid.serial = (unsigned long)(Mmc.rsp1);// 39:16
temp = (unsigned long)(Mmc.rsp2 & 0x00FF);
CardCid.serial |= (temp<<16);
CardCid.fw_rev = (Mmc.rsp2 >>8 ) & 0x000F; // 43:40
CardCid.hw_rev = (Mmc.rsp2 >>12 ) & 0x000F; // 47:44
CardCid.mfg_id = (Mmc.rsp6 >>8 ) & 0x00FF; //127:104
temp = (unsigned long)(Mmc.rsp7 );
CardCid.mfg_id |= temp << 16;
}
static void get_card_csd(void)
{
get_rsp();
CardCsd.ecc = (Mmc.rsp0 >> 8 ) & 3; // 9:8
CardCsd.tmp_wp = (Mmc.rsp0 >> 12 ) & 1; // 12:12
CardCsd.perm_wp = (Mmc.rsp0 >> 13 ) & 1; // 13:13
CardCsd.copy = (Mmc.rsp0 >> 14 ) & 1; // 14:14
CardCsd.wr_bl_part = (Mmc.rsp1 >> 5 ) & 1; // 21:21
CardCsd.wr_bl_len = (Mmc.rsp1 >> 6 ) & 0xF; // 25:22
CardCsd.r2w_factor = (Mmc.rsp1 >> 10 ) & 0x7; // 28:26
CardCsd.def_ecc = (Mmc.rsp1 >> 13 ) & 0x3; // 30:29
CardCsd.wp_brp_ena = (Mmc.rsp1 >> 15 ) & 1; // 31:31
CardCsd.wp_grp_size = (Mmc.rsp2 ) & 0x1f; // 36:32
CardCsd.er_grp_size = (Mmc.rsp2 >> 5 ) & 0x1f; // 41:37
CardCsd.sect_size = (Mmc.rsp2 >> 10 ) & 0x1f; // 46:42
CardCsd.c_size_mult = (Mmc.rsp2 >> 15 ) & 1; // 49:47
CardCsd.c_size_mult |=( (Mmc.rsp3 & 3 ) << 1);
CardCsd.vdd_w_curr_max = (Mmc.rsp3 >> 2 ) & 0x7; // 52:50
CardCsd.vdd_w_curr_min = (Mmc.rsp3 >> 5 ) & 0x7; // 55:53
CardCsd.vdd_r_curr_max = (Mmc.rsp3 >> 8 ) & 0x7; // 58:56
CardCsd.vdd_r_curr_min = (Mmc.rsp3 >> 11 ) & 0x7; // 61:59
CardCsd.c_size = (Mmc.rsp3 >> 14 ) & 0x3; // 73:62
CardCsd.c_size |=((Mmc.rsp4 & 0x3FF) << 2);
CardCsd.dsr_imp = (Mmc.rsp4 >> 12 ) & 1; // 76:76
CardCsd.rd_blk_misal = (Mmc.rsp4 >> 13 ) & 1; // 77:77
CardCsd.wr_blk_misal = (Mmc.rsp4 >> 14 ) & 1; // 78:78
CardCsd.rd_bl_part = (Mmc.rsp4 >> 15 ) & 1; // 79:79
CardCsd.rd_bl_len = (Mmc.rsp5 ) & 0xf; // 83:80
CardCsd.ccc = (Mmc.rsp5 >> 4 ) & 0xfff; // 895:84
CardCsd.tran_speed = (Mmc.rsp6 ) & 0xff; // 103:96
CardCsd.nsac = (Mmc.rsp6 >> 8 ) & 0xff; // 111:104
CardCsd.taac = (Mmc.rsp7 ) & 0xff; // 119:112
CardCsd.mmc_prot = (Mmc.rsp7 >> 10 ) & 0xf; // 125:122
CardCsd.csd_struct = (Mmc.rsp7 >> 14 ) & 0x3; // 127:126
}
// Tested, tnyc
static int wait_for( unsigned short event )
{
// This function assumes that a command will timeout
// otherwise we will get hung here forever.
volatile unsigned short stat;
do
{
stat = pMMC->st0;
stat &= (SPIERR | CRCRS | CRCRD | CRCWR | TOUTRS | TOUTRD | event);
}while( stat == 0 );
// If we got the event we were looking for then
// return pass. We may have gotten an event but
// maybe not the one we were expecting, i.e. a time our or crc.
SaveStat0 = stat;
return( ((stat & event) == event ) ? 0 : -1 );
}
// Tested, tnyc
static int go_idle_state(void)
{
pMMC->argh = STUFF_BITS;
pMMC->argl = STUFF_BITS;
// Add in the INIT bit so that we wait for the 80
// clocks before sending the intial command
pMMC->cmd = GO_IDLE_STATE | INIT | DCLR;
// Resp = NONE, just check for command sent
return( wait_for( RSPDNE ));
}
// Tested, tnyc
#define VDD_32_33 0x0010 // 0x007f
/*should have a wide range of voltage--
between 2.6 and 3.6, but 3.3 is the preferred*/
static int send_op_cond(void)
{
volatile unsigned short stat;
long op_timeout;
// Set flags to busy and fail
op_timeout = OP_TIMEOUT;
OpLoop = 0;
// You will go through this loop at least twice. The first time
// you will apply your requested voltage level and receive a
// busy. The second time you re-apply your voltage level and
// generaly get a not busy. This indicates the card has
// initialized.
//
// Clear status
stat = pMMC->st0;
do
{
// For debug. Want to know how many loops it takes.
OpLoop++;
// Set minimal voltage range
pMMC->argh = VDD_32_33;
pMMC->argl = 0;
pMMC->cmd = SEND_OP_COND;
// Break on response fail
if( wait_for( RSPDNE ))
break;
// Resp = R3
// Busy bit is in MSB of rsp7. If '1' (not busy) then we are done.
stat = pMMC->rsp7;
if( stat & 0x8000 )
return( 0 );
if( !Debug )
op_timeout--;
}while( op_timeout > 0 );
// Timed out
return( -1 );
}
// Tested, tnyc
static int all_send_cid( void )
{
volatile unsigned short stat;
stat = pMMC->st0;
if( Debug )
clear_rsp();
pMMC->argh = STUFF_BITS;
pMMC->argl = STUFF_BITS;
pMMC->cmd = ALL_SEND_CID;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -