spi_mmc.c
来自「DSP2808例程。TMS320F2808DSP的各个模块的应用例程」· C语言 代码 · 共 396 行
C
396 行
/*----------------------------------------------------------------------------
www.51usb.com
--------------------------------------------------------------------------*/
#include "DSP280x_Device.h" // DSP280x Headerfile Include File
#include "DSP280x_Examples.h" // DSP280x Examples Include File
#include "type.h"
#include "spi_mmc.h"
#define SD_cs_Hi GpioDataRegs.GPASET.bit.GPIO27 = 1
#define SD_cs_Lo GpioDataRegs.GPACLEAR.bit.GPIO27 = 1
BYTE MMCWRData[MMC_DATA_SIZE];
BYTE MMCRDData[MMC_DATA_SIZE];
BYTE MMCCmd[MMC_CMD_SIZE];
BYTE MMCStatus = 0;
/*
* SPI and MMC commands related modules.
*
*/
/*
* SPI Send a block of data based on the length
*/
void SPI_Send( BYTE *buf, DWORD Length )
{
BYTE Dummy;
if ( Length == 0 )
return;
while ( Length != 0 )
{
SpibRegs.SPITXBUF = ((*buf)<<8);
while ( !(SpibRegs.SPISTS.bit.INT_FLAG) ) {}
Dummy = SpibRegs.SPIRXBUF;
/*
// as long as TNF bit is set, TxFIFO is not full, I can write
while ( !(SSPSR & 0x02) );
SSPDR = *buf;
// Wait until the Busy bit is cleared
while ( !(SSPSR & 0x04) );
Dummy = SSPDR; // Flush the RxFIFO
*/
Length--;
buf++;
}
return;
}
/*
* SPI receives a block of data based on the length
*/
void SPI_Receive( BYTE *buf, DWORD Length )
{
DWORD i;
for ( i = 0; i < Length; i++ )
{
*buf = SPI_ReceiveByte();
buf++;
}
return;
}
/*
* SPI Receive Byte, receive one byte only, return Data byte
* used a lot to check the status.
*/
BYTE SPI_ReceiveByte( void )
{
BYTE data;
/*
// wrtie dummy byte out to generate clock, then read data from MISO
SSPDR = 0xFF;
// Wait until the Busy bit is cleared
while ( SSPSR & 0x10 );
data = SSPDR;
return ( data );
*/
SpibRegs.SPITXBUF=0xff00;
while ( !(SpibRegs.SPISTS.bit.INT_FLAG) ) {}
data = SpibRegs.SPIRXBUF;
return data ;
}
/************************** MMC Init *********************************//*
* Initialises the MMC into SPI mode and sets block size(512), returns
* 0 on success
*
*/int mmc_init(){
DWORD i;
/* Generate a data pattern for write block */
for(i=0;i<MMC_DATA_SIZE;i++) {
MMCWRData[i] = i&&0xff;
}
MMCStatus = 0;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
/* initialise the MMC card into SPI mode by sending 80 clks on */
/* Use MMCRDData as a temporary buffer for SPI_Send() */ for(i=0; i<10; i++)
{
MMCRDData[i] = 0xFF;
}
SPI_Send( MMCRDData, 10 );
//IOCLR0 = SPI_SEL; /* clear SPI SSEL */
SD_cs_Lo; /* send CMD0(RESET or GO_IDLE_STATE) command, all the arguments
are 0x00 for the reset command, precalculated checksum */
MMCCmd[0] = 0x40;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0x95;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
/* if = 1 then there was a timeout waiting for 0x01 from the mmc */ if( mmc_response(0x01) == 1 )
{
MMCStatus = IDLE_STATE_TIMEOUT;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
/* Send some dummy clocks after GO_IDLE_STATE */
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
SPI_ReceiveByte();
//IOCLR0 = SPI_SEL; /* clear SPI SSEL */
SD_cs_Lo;
/* must keep sending command until zero response ia back. */ i = MAX_TIMEOUT; do
{
/* send mmc CMD1(SEND_OP_COND) to bring out of idle state */
/* all the arguments are 0x00 for command one */
MMCCmd[0] = 0x41;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
/* checksum is no longer required but we always send 0xFF */
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
i--; } while ( (mmc_response(0x00) != 0) && (i>0) );
/* timeout waiting for 0x00 from the mmc */ if ( i == 0 )
{
MMCStatus = OP_COND_TIMEOUT;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
/* Send some dummy clocks after SEND_OP_COND */
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
SPI_ReceiveByte();
//IOCLR0 = SPI_SEL; /* clear SPI SSEL */
SD_cs_Lo; /* send mmc CMD16(SET_BLOCKLEN) to set the block length */
MMCCmd[0] = 0x50;
MMCCmd[1] = 0x00; /* 4 bytes from here is the block length */
/* LSB is first */
/* 00 00 00 10 set to 16 bytes */
/* 00 00 02 00 set to 512 bytes */
MMCCmd[2] = 0x00;
/* high block length bits - 512 bytes */
MMCCmd[3] = 0x02;
/* low block length bits */
MMCCmd[4] = 0x00;
/* checksum is no longer required but we always send 0xFF */
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 )
{
MMCStatus = SET_BLOCKLEN_TIMEOUT;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
SPI_ReceiveByte(); return 0;}
/************************** MMC Write Block ***************************/
/* write a block of data based on the length that has been set
* in the SET_BLOCKLEN command.
* Send the WRITE_SINGLE_BLOCK command out first, check the
* R1 response, then send the data start token(bit 0 to 0) followed by
* the block of data. The test program sets the block length to 512
* bytes. When the data write finishs, the response should come back
* as 0xX5 bit 3 to 0 as 0101B, then another non-zero value indicating
* that MMC card is in idle state again.
*
*/int mmc_write_block(WORD block_number){
WORD varl, varh;
BYTE Status;
//IOCLR0 = SPI_SEL; /* clear SPI SSEL */ SD_cs_Lo;
/* block size has been set in mmc_init() */ varl=((block_number&0x003F)<<9); varh=((block_number&0xFFC0)>>7);
/* send mmc CMD24(WRITE_SINGLE_BLOCK) to write the data to
MMC card */
MMCCmd[0] = 0x58;
/* high block address bits, varh HIGH and LOW */
MMCCmd[1] = varh >> 0x08;
MMCCmd[2] = varh & 0xFF;
/* low block address bits, varl HIGH and LOW */
MMCCmd[3] = varl >> 0x08;
MMCCmd[4] = varl & 0xFF;
/* checksum is no longer required but we always send 0xFF */
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
/* if mmc_response returns 1 then we failed to get a 0x00
response */ if((mmc_response(0x00))==1)
{
MMCStatus = WRITE_BLOCK_TIMEOUT;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
/* Set bit 0 to 0 which indicates the beginning of the data block */
MMCCmd[0] = 0xFE;
SPI_Send( MMCCmd, 1 );
/* send data, pattern as 0x00,0x01,0x02,0x03,0x04,0x05 ...*/
SPI_Send( MMCWRData, MMC_DATA_SIZE );
/* Send dummy checksum */
/* when the last check sum is sent, the response should come back
immediately. So, check the SPI FIFO MISO and make sure the status
return 0xX5, the bit 3 through 0 should be 0x05 */
MMCCmd[0] = 0xFF;
MMCCmd[1] = 0xFF;
SPI_Send( MMCCmd, 2 );
Status = SPI_ReceiveByte();
if ( (Status & 0x0F) != 0x05 )
{
MMCStatus = WRITE_BLOCK_FAIL;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
/* if the status is already zero, the write hasn't finished
yet and card is busy */
if(mmc_wait_for_write_finish()==1)
{
MMCStatus = WRITE_BLOCK_FAIL;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
SPI_ReceiveByte(); return 0;}/************************** MMC Read Block ****************************//*
* Reads a 512 Byte block from the MMC
* Send READ_SINGLE_BLOCK command first, wait for response come back
* 0x00 followed by 0xFE. The call SPI_Receive() to read the data
* block back followed by the checksum.
*
*/int mmc_read_block(WORD block_number){
WORD Checksum;
WORD varh,varl;
//IOCLR0 = SPI_SEL; /* clear SPI SSEL */
SD_cs_Lo; varl=((block_number&0x003F)<<9); varh=((block_number&0xFFC0)>>7);
/* send mmc CMD17(READ_SINGLE_BLOCK) to read the data from MMC
card */
MMCCmd[0] = 0x51;
/* high block address bits, varh HIGH and LOW */
MMCCmd[1] = varh >> 0x08;
MMCCmd[2] = varh & 0xFF;
/* low block address bits, varl HIGH and LOW */
MMCCmd[3] = varl >> 0x08;
MMCCmd[4] = varl & 0xFF;
/* checksum is no longer required but we always send 0xFF */
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
/* if mmc_response returns 1 then we failed to get a 0x00 response */ if((mmc_response(0x00))==1)
{
MMCStatus = READ_BLOCK_TIMEOUT;
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
return MMCStatus;
}
/* wait for data token */ if((mmc_response(0xFE))==1)
{
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
//IOSET0 = SPI_SEL;
SD_cs_Hi;
return MMCStatus;
}
/* Get the block of data based on the length */
SPI_Receive( MMCRDData, MMC_DATA_SIZE ); /* CRC bytes that are not needed */
Checksum = SPI_ReceiveByte();
Checksum = Checksum << 0x08 | SPI_ReceiveByte();
//IOSET0 = SPI_SEL; /* set SPI SSEL */
SD_cs_Hi;
SPI_ReceiveByte(); return 0;}/***************** MMC get response *******************//*
* Repeatedly reads the MMC until we get the
* response we want or timeout
*/int mmc_response( BYTE response ){ DWORD count = 0xFFF;
BYTE result;
while( count > 0 )
{
result = SPI_ReceiveByte();
if ( result == response )
{
break;
}
count--;
}
if ( count == 0 )
return 1; /* Failure, loop was exited due to timeout */
else
return 0; /* Normal, loop was exited before timeout */}
/***************** MMC wait for write finish *******************//*
* Repeatedly reads the MMC until we get a non-zero value (after
* a zero value) indicating the write has finished and card is no
* longer busy.
*
*/int mmc_wait_for_write_finish( void ){ DWORD count = 0xFFFF; /* The delay is set to maximum considering
the longest data block length to handle */
BYTE result = 0;
while( (result == 0) && count )
{
result = SPI_ReceiveByte();
count--;
}
if ( count == 0 )
return 1; /* Failure, loop was exited due to timeout */
else
return 0; /* Normal, loop was exited before timeout */}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?