📄 mmc.c
字号:
/* a write to MMCCMD triggers the sending of the command. therefore, the argument
registers (MMCARGx) need to be written to before the MMCCMD is written to*/
/* command bit positions:
* -----------------------------------------------------------
* 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 (STREAM)
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???????
*/
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;
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 )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -