⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 spi_mmc.c

📁 LPC2148 SD读写源代码,这个程序实现了对 SD卡的读写操作
💻 C
字号:
/*----------------------------------------------------------------------------
www.mcu123.com
--------------------------------------------------------------------------*/

#include <LPC214X.H>                        /* LPC214x definitions */

#include "type.h"
#include "spi_mmc.h"

BYTE MMCWRData[MMC_DATA_SIZE];
BYTE MMCRDData[MMC_DATA_SIZE];
BYTE MMCCmd[MMC_CMD_SIZE];
BYTE MMCStatus = 0;
/*
 *  SPI and MMC commands related modules.
 *  
 */
void SPI_Init( void )
{
  DWORD portConfig;
  BYTE i, Dummy;

  /* Configure PIN connect block */
  /* bit 32, 54, 76 are 0x10, bit 98 are 0x00
  port 0 bits 17, 18, 19, 20 are SSP port SCK1, MISO1, MOSI1, 
  and SSEL1 set SSEL to GPIO pin that you will have the totoal 
  freedom to set/reset the SPI chip-select pin */
   
  SSPCR1 = 0x00; /* SSP master (off) in normal mode */

  portConfig = PINSEL1;
  PINSEL1 = portConfig | 0x00A8;
  IODIR0 = SPI_SEL;	/* SSEL is output */
  IOSET0 = SPI_SEL;	/* set SSEL to high */
		
  /* Set PCLK 1/2 of CCLK */
  VPBDIV = 0x02;
  //VPBDIV =0x00;  //1/4
  /* Set data to 8-bit, Frame format SPI, CPOL = 0, CPHA = 0, 
  and SCR is 15 */
  SSPCR0 = 0x0707;

  /* SSPCPSR clock prescale register, master mode, minimum divisor 
  is 0x02*/
  SSPCPSR = 0x2;

  /* Device select as master, SSP Enabled, normal operational mode */
  SSPCR1 = 0x02;

  for ( i = 0; i < 8; i++ )
  {
	Dummy = SSPDR;		/* clear the RxFIFO */
  }
  return;

}

/* 
 * 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 )
  {
	/* 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 ); 
}
/************************** 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;
  }

  MMCStatus = 0;
  IOSET0 = SPI_SEL; /* set SPI SSEL */

  /* 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 */
  /* 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 */
  	return MMCStatus;
  }

  /* Send some dummy clocks after GO_IDLE_STATE */
  IOSET0 = SPI_SEL; /* set SPI SSEL */
  SPI_ReceiveByte();
  IOCLR0 = SPI_SEL; /* clear SPI SSEL */

  /* 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 */
	return MMCStatus;
  }

  /* Send some dummy clocks after SEND_OP_COND */
  IOSET0 = SPI_SEL; /* set SPI SSEL */
  SPI_ReceiveByte();
  IOCLR0 = SPI_SEL; /* clear SPI SSEL */
  /* 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 */
	return MMCStatus;
  }

  IOSET0 = SPI_SEL;		/* set SPI SSEL */
  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 */  
  /* 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 */
	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 */
	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 */
	return MMCStatus;
  }

  IOSET0 = SPI_SEL;			/* set SPI SSEL */
  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 */
  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 */ 
	return MMCStatus;
  }
  /* wait for data token */  if((mmc_response(0xFE))==1)
  {
  	MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
	IOSET0 = SPI_SEL;
	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 */
  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 + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -