?? spi_mmc.c
字號:
/**********************************************************************************************
**
** Copyright(c) Semitek
**
** 模 塊 名:spi_mmc.c
**
** 模塊功能:SPI和MMC的接口模塊
**
** 修改日期:2007年4月5日
**
**********************************************************************************************/
#include <LPC213X.H>
#include "spi_mmc.h"
#include "string.h"
BYTE MMCWRData[MMC_DATA_SIZE];//寫數據緩沖區(qū)
BYTE MMCRDData[MMC_DATA_SIZE];//讀數據緩沖區(qū)
BYTE MMCCmd[MMC_CMD_SIZE];//MMC操作命令
BYTE MMCStatus = 0;//MMC讀寫狀態(tài)
/************************** SPI Init **********************************************
**
** 函數名稱:spi_init()
**
** 函數功能:初始化SPI
**
** 輸入參數:無
**
** 輸出參數:無
**
** 函數說明:無
**
**********************************************************************************/
void SPI_Init( void )
{
DWORD portConfig;
BYTE i, Dummy;
SSPCR1 = 0x00; //設置SPI為主機模式
portConfig = PINSEL1;
PINSEL1 = portConfig | 0x00A8;//設置引腳功能寄存器
IODIR0 = SPI_SEL; //SSEL 設置為輸出
IOSET0 = SPI_SEL; //SSEL 置高
VPBDIV = 0x02;// 設置 PCLK = CCLK /2
SSPCR0 = 0x0707;// 設置數據位為8為,幀格式位SPI, CPOL = 0, CPHA = 0, SCR = 15
SSPCPSR = 0x2;// 設置時鐘預分頻寄存器(SSPCPSR)
SSPCR1 = 0x02;// 設備作為主機,使能SSP,處于正常工作模式
for ( i = 0; i < 8; i++ )
{
Dummy = SSPDR; // 清除接收寄存器
}
return;
}
/************************** SPI Send ********************************************
**
** 函數名稱:SPI_Send()
**
** 函數功能:SPI發(fā)送Length字節(jié)的數據
**
** 輸入參數:*buf--待發(fā)數據,Length--待發(fā)數據的字節(jié)數
**
** 輸出參數:無
**
** 函數說明:無
**
**********************************************************************************/
void SPI_Send( BYTE *buf, DWORD Length )
{
BYTE Dummy;
if ( Length == 0 ) return;
while ( Length != 0 )
{
while ( !(SSPSR & 0x02) );//等到TNF置位說明TxFIFO為空,說明可以開始發(fā)送
SSPDR = *buf;
while ( !(SSPSR & 0x04) );//等到忙狀態(tài)為被清0
Dummy = SSPDR; //清除RxFIFO數據
Length--;
buf++;
}
return;
}
/************************** SPI Receive *****************************************
**
** 函數名稱:SPI_Receive()
**
** 函數功能:SPI接收Length字節(jié)的數據
**
** 輸入參數:*buf--接收緩沖器,Length--接收數據的字節(jié)數
**
** 輸出參數:無
**
** 函數說明:無
**
**********************************************************************************/
void SPI_Receive( BYTE *buf, DWORD Length )
{
DWORD i;
for ( i = 0; i < Length; i++ )
{
*buf = SPI_ReceiveByte();
buf++;
}
return;
}
/************************** SPI ReceiveByte *************************************
**
** 函數名稱:SPI_ReceiveByte()
**
** 函數功能:SPI接收1字節(jié)的數據
**
** 輸入參數:無
**
** 輸出參數:接收到的數據
**
** 函數說明:無
**
**********************************************************************************/
BYTE SPI_ReceiveByte( void )
{
BYTE data;
SSPDR = 0xFF;//向寄存器中寫入0xFF來生成時鐘,然后讀數據
while ( SSPSR & 0x10 );//等到忙狀態(tài)為被清0
data = SSPDR;
return ( data );
}
/************************** MMC Init **********************************************
**
** 函數名稱:mmc_init()
**
** 函數功能:初始化MMC卡為SPI模式并設置數據塊大小為512bytes
**
** 輸入參數:無
**
** 輸出參數:0或者錯誤代碼
**
** 函數說明:返回0則初始化成功
**
**********************************************************************************/
int mmc_init()
{
DWORD i;
for(i=0;i<MMC_DATA_SIZE;i++)//將寫數據緩沖區(qū)全部設置為0xFF
{
MMCWRData[i] = 0xFF;
}
MMCStatus = 0;
IOSET0 = SPI_SEL; //SPI引腳置位
for(i=0; i<10; i++) //發(fā)送80個脈沖使MMC卡為SPI模式
{
MMCRDData[i] = 0xFF;
}
SPI_Send( MMCRDData, 10 );
IOCLR0 = SPI_SEL; //SPI引腳清零
//發(fā)送CMD0命令復位MMC卡
MMCCmd[0] = 0x40;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0x95;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
//如果為1說明在等待MMC響應0x01的時候超時
if( mmc_response(0x01) == 1 ) {
MMCStatus = IDLE_STATE_TIMEOUT;
IOSET0 = SPI_SEL;//SPI引腳置位
return MMCStatus;
}
IOSET0 = SPI_SEL; //SPI引腳置位
SPI_ReceiveByte();
IOCLR0 = SPI_SEL; //SPI引腳清零
i = MAX_TIMEOUT;//一直發(fā)送命令直到返回響應數據為0x00或者超時
do
{
//發(fā)送CMD1命令讓MMC卡調處IDLE狀態(tài)
MMCCmd[0] = 0x41;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;//在SPI模式下,效驗數據可以隨便設置
SPI_Send( MMCCmd, MMC_CMD_SIZE );
i--;
} while ( (mmc_response(0x00) != 0) && (i>0) );
//如果為1說明在等待MMC響應0x00的時候超時
if ( i == 0 ) {
MMCStatus = OP_COND_TIMEOUT;
IOSET0 = SPI_SEL;
return MMCStatus;
}
IOSET0 = SPI_SEL;//SPI引腳置位
SPI_ReceiveByte();
IOCLR0 = SPI_SEL;//SPI引腳清零
//發(fā)送命令16來設置數據塊的長度
MMCCmd[0] = 0x50;
MMCCmd[1] = 0x00;//此處的4字節(jié)代表數據塊的長度,如:00 00 00 10 set to 16 bytes,00 00 02 00 set to 512 bytes
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x02;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 ) {
MMCStatus = SET_BLOCKLEN_TIMEOUT;
IOSET0 = SPI_SEL;//SPI引腳置位
return MMCStatus;
}
IOSET0 = SPI_SEL;//SPI引腳置位
SPI_ReceiveByte();
return 0;
}
/************************** MMC Write Block ****************************************
**
** 函數名稱:mmc_write_block()
**
** 函數功能:向MMC卡中寫入1個扇區(qū)(512bytes)的數據
**
** 輸入參數:扇區(qū)號,待寫數據
**
** 輸出參數:0或者錯誤代碼
**
** 函數說明:返回0則寫入成功
**
**********************************************************************************/
int mmc_write_block(DWORD block_number,BYTE *buffer)
{
BYTE Status;
IOCLR0 = SPI_SEL;//SPI引腳清零
block_number <<= 9;//將扇區(qū)號乘以512轉換為地址
//發(fā)送命令24向MMC中寫入一個扇區(qū)的數據
MMCCmd[0] = 0x58;
MMCCmd[1] = (block_number & 0xFF000000) >> 24;//扇區(qū)地址
MMCCmd[2] = (block_number & 0x00FF0000) >> 16;
MMCCmd[3] = (block_number & 0x0000FF00) >> 8;
MMCCmd[4] = (block_number & 0x000000FF);
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
if((mmc_response(0x00))==1) {
MMCStatus = WRITE_BLOCK_TIMEOUT;
IOSET0 = SPI_SEL;
return MMCStatus;
}
MMCCmd[0] = 0xFE;//發(fā)送數據的開始位,通常為0
SPI_Send( MMCCmd, 1 );
SPI_Send(buffer,MMC_DATA_SIZE);//發(fā)送數據
//發(fā)送效驗和,當最后的效驗和被發(fā)送的時候,響應馬上就會返回,檢查返回的數據是否為0xX5,
MMCCmd[0] = 0xFF;
MMCCmd[1] = 0xFF;
SPI_Send( MMCCmd, 2);
Status = SPI_ReceiveByte();
if ( (Status & 0x0F) != 0x05 ) {
MMCStatus = WRITE_BLOCK_FAIL;
IOSET0 = SPI_SEL;
return MMCStatus;
}
//等到寫數據結束
if(mmc_wait_for_write_finish()==1) {
MMCStatus = WRITE_BLOCK_FAIL;
IOSET0 = SPI_SEL;
return MMCStatus;
}
IOSET0 = SPI_SEL;
SPI_ReceiveByte();
return 0;
}
/************************** MMC Read Block ****************************************
**
** 函數名稱:mmc_Read_block()
**
** 函數功能:從MMC卡中讀出1個扇區(qū)(512bytes)的數據
**
** 輸入參數:扇區(qū)號
**
** 輸出參數:0或者錯誤代碼
**
** 函數說明:返回0則讀取成功
**
**********************************************************************************/
int mmc_read_block(DWORD block_number)
{
WORD Checksum;
IOCLR0 = SPI_SEL;
block_number <<= 9;//將扇區(qū)號乘以512轉換為地址
//發(fā)送命令17從MMC中讀出一個扇區(qū)的數據
MMCCmd[0] = 0x51;
MMCCmd[1] = (block_number & 0xFF000000) >> 24;
MMCCmd[2] = (block_number & 0x00FF0000) >> 16;
MMCCmd[3] = (block_number & 0x0000FF00) >> 8;
MMCCmd[4] = (block_number & 0x000000FF);
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
if((mmc_response(0x00))==1) {
MMCStatus = READ_BLOCK_TIMEOUT;
IOSET0 = SPI_SEL;
return MMCStatus;
}
//等待數據令牌
if((mmc_response(0xFE))==1) {
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
IOSET0 = SPI_SEL;
return MMCStatus;
}
SPI_Receive( MMCRDData, MMC_DATA_SIZE );//讀一扇區(qū)的數據
//進行CRC效驗,但不是必須
Checksum = SPI_ReceiveByte();
Checksum = Checksum << 0x08 | SPI_ReceiveByte();
IOSET0 = SPI_SEL;
SPI_ReceiveByte();
return 0;
}
/************************** MMC Response ****************************************
**
** 函數名稱:mmc_response()
**
** 函數功能:不斷的讀MMC直到得到所需數據或者超時退出
**
** 輸入參數:所需的響應數據
**
** 輸出參數:讀寫是否成功
**
** 函數說明:返回0則讀取成功
**
**********************************************************************************/
int mmc_response( unsigned char response)
{
DWORD count = 0xFFF;
while( (SPI_ReceiveByte() != response) && count )
{
count--;
}
if ( count == 0 )
return 1; //由于超時而失敗
else
return 0; //在超時之前得到數據,成功響應
}
/************************** MMC Wait for Write finish ***************************
**
** 函數名稱:mmc_wait_for_write_finish()
**
** 函數功能:不斷的讀MMC直到得到非0數據標志寫入完成或者超時退出
**
** 輸入參數:暫無
**
** 輸出參數:讀寫是否成功
**
** 函數說明:返回0則讀取成功
**
**********************************************************************************/
int mmc_wait_for_write_finish( void )
{
DWORD count = 0xFFFF;
BYTE result = 0;
while( (result == 0) && count )
{
result = SPI_ReceiveByte();
count--;
}
if ( count == 0 )
return 1; //由于超時而失敗
else
return 0; //在超時之前得到數據
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -