📄 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];//写数据缓冲区
BYTE MMCRDData[MMC_DATA_SIZE];//读数据缓冲区
BYTE MMCCmd[MMC_CMD_SIZE];//MMC操作命令
BYTE MMCStatus = 0;//MMC读写状态
/************************** 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发送Length字节的数据
**
** 输入参数:*buf--待发数据,Length--待发数据的字节数
**
** 输出参数:无
**
** 函数说明:无
**
**********************************************************************************/
void SPI_Send( BYTE *buf, DWORD Length )
{
BYTE Dummy;
if ( Length == 0 ) return;
while ( Length != 0 )
{
while ( !(SSPSR & 0x02) );//等到TNF置位说明TxFIFO为空,说明可以开始发送
SSPDR = *buf;
while ( !(SSPSR & 0x04) );//等到忙状态为被清0
Dummy = SSPDR; //清除RxFIFO数据
Length--;
buf++;
}
return;
}
/************************** SPI Receive *****************************************
**
** 函数名称:SPI_Receive()
**
** 函数功能:SPI接收Length字节的数据
**
** 输入参数:*buf--接收缓冲器,Length--接收数据的字节数
**
** 输出参数:无
**
** 函数说明:无
**
**********************************************************************************/
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字节的数据
**
** 输入参数:无
**
** 输出参数:接收到的数据
**
** 函数说明:无
**
**********************************************************************************/
BYTE SPI_ReceiveByte( void )
{
BYTE data;
SSPDR = 0xFF;//向寄存器中写入0xFF来生成时钟,然后读数据
while ( SSPSR & 0x10 );//等到忙状态为被清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++)//将写数据缓冲区全部设置为0xFF
{
MMCWRData[i] = 0xFF;
}
MMCStatus = 0;
IOSET0 = SPI_SEL; //SPI引脚置位
for(i=0; i<10; i++) //发送80个脉冲使MMC卡为SPI模式
{
MMCRDData[i] = 0xFF;
}
SPI_Send( MMCRDData, 10 );
IOCLR0 = SPI_SEL; //SPI引脚清零
//发送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;//一直发送命令直到返回响应数据为0x00或者超时
do
{
//发送CMD1命令让MMC卡调处IDLE状态
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引脚清零
//发送命令16来设置数据块的长度
MMCCmd[0] = 0x50;
MMCCmd[1] = 0x00;//此处的4字节代表数据块的长度,如: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个扇区(512bytes)的数据
**
** 输入参数:扇区号,待写数据
**
** 输出参数:0或者错误代码
**
** 函数说明:返回0则写入成功
**
**********************************************************************************/
int mmc_write_block(DWORD block_number,BYTE *buffer)
{
BYTE Status;
IOCLR0 = SPI_SEL;//SPI引脚清零
block_number <<= 9;//将扇区号乘以512转换为地址
//发送命令24向MMC中写入一个扇区的数据
MMCCmd[0] = 0x58;
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 = WRITE_BLOCK_TIMEOUT;
IOSET0 = SPI_SEL;
return MMCStatus;
}
MMCCmd[0] = 0xFE;//发送数据的开始位,通常为0
SPI_Send( MMCCmd, 1 );
SPI_Send(buffer,MMC_DATA_SIZE);//发送数据
//发送效验和,当最后的效验和被发送的时候,响应马上就会返回,检查返回的数据是否为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个扇区(512bytes)的数据
**
** 输入参数:扇区号
**
** 输出参数:0或者错误代码
**
** 函数说明:返回0则读取成功
**
**********************************************************************************/
int mmc_read_block(DWORD block_number)
{
WORD Checksum;
IOCLR0 = SPI_SEL;
block_number <<= 9;//将扇区号乘以512转换为地址
//发送命令17从MMC中读出一个扇区的数据
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 );//读一扇区的数据
//进行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 + -