📄 spi_mmc.c
字号:
/*-------------------------------------------------------------------------------------------
* Name: SPI_MMC.C
* Purpose: SD卡接口部分程序
* Version: V1.00
*------------------------------------------------------------------------------------------*/
#include "config.h"
#include "spi_mmc.h"
uint8 MMCCmd[MMC_CMD_SIZE]; //状态
uint8 MMCStatus = 0;
/**************************************SPI相关函数******************************************/
/*SPI初始化函数*/
void SPI_Init( void )
{
uint32 portConfig;
uint8 i,Dummy;
//相关引脚连接定义
//P0.17--SCK1 P0.18--MISO1 P0.19--MOSI1 P0.20 SSEL1 CS1
SSPCR1 = 0x00; //正常工作 主机模式 SSP禁能
portConfig = PINSEL1;
PINSEL1 = portConfig | 0x02A8; //定义相关引脚为SPI模式
IO0DIR = SPI_SEL; //SSEL输出
IO0DIR = SPI_PWR;
IO0SET = SPI_SEL; //SSEL置高
IO0SET = SPI_PWR;
for(i = 0; i <100; i++);
IO0CLR = SPI_PWR;
//设置PCLK为1/2的CCLK
VPBDIV = 0x02; //10-->1/2
// SSPCR0 = 0x0F07; //0111->8位 00->SPI格式 CPOL:CPHA0->00 SCR->15
SSPCR0 = 0x0707; //0111->8位 00->SPI格式 CPOL:CPHA0->00 SCR->7
SSPCPSR = 0x02; //SSP在主控模式下操作SSPCPSR最小为2
SSPCR1 = 0x02; //正常工作 主机模式 SSP使能
for ( i = 0; i < 8; i++ )
{
Dummy = SSPDR; //清空收缓冲区
}
return;
}
/*******************************************************************************************/
/*SPI发送函数*/
void SPI_Send( uint8 *buf, uint32 Length )
{
// uint8 Dummy;
if ( Length == 0 )
return;
while (!(SSPSR & 0x02));
while ( Length != 0 )
{
// while (!(SSPSR & 0x02)); //TNF位 发送缓冲区未满
SSPDR = *buf; //数据寄存器
while (!(SSPSR & 0x01)); //等待总线空闲
// Dummy = SSPDR; //清空收缓冲区
Length--;
buf++;
}
return;
}
/*******************************************************************************************/
/*SPI接收函数*/
void SPI_Receive( uint8 *buf, uint32 Length )
{
uint32 i;
for ( i = 0; i < Length; i++ )
{
*buf = SPI_ReceiveByte();
buf++;
}
return;
}
/*******************************************************************************************/
/*SPI字节接收函数*/
uint8 SPI_ReceiveByte( void )
{
uint8 data;
while (!(SSPSR & 0x02));
//TNF位 发送缓冲区满
SSPDR = 0xFF; //虚写 产生时钟信号 从MISO独数据
while (!(SSPSR & 0x04)); //等待总线空闲
data = SSPDR; //数据寄存器
return ( data );
}
/*******************************************************************************************/
/*************************************SD卡相关函数******************************************/
/*SD卡初始化*/
int mmc_init()
{
uint32 i;
uint8 Ini[10];
MMCStatus = 0;
IO0SET = SPI_SEL; //SSEL CS位->1
//初始化SD卡 进入SPI模式 80个时钟周期
for(i=0; i<10; i++) //MMCRDData做临时发送缓冲区
{
Ini[i] = 0xFF; //8X10=80
}
SPI_Send( Ini, 10 );
IO0CLR = SPI_SEL; //SSEL CS位->0
MMCCmd[0] = 0x40; //发送CMD0
MMCCmd[1] = 0x00; //卡设置为空闲状态
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0x95;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( mmc_response(0x01) == 1 )
{
MMCStatus = IDLE_STATE_TIMEOUT; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
//发送几个时钟
IO0SET = SPI_SEL; //SSEL CS->1
SPI_ReceiveByte();
IO0CLR = SPI_SEL; //SSEL CS->0
i = MAX_TIMEOUT; //持续发送CMD1 直到响应0x00
do
{ //发送CMD1
MMCCmd[0] = 0x41;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
i--;
} while ( (mmc_response(0x00) != 0) && (i>0) );
if ( i == 0 ) //超时
{
MMCStatus = OP_COND_TIMEOUT;
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
IO0SET = SPI_SEL; //发送几个时钟
SPI_ReceiveByte();
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x77; //发送CDM16 设置块长度
MMCCmd[1] = 0x00; //0x0020->512B
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 )
{
MMCStatus = 28; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
IO0SET = SPI_SEL; //发送几个时钟
SPI_ReceiveByte();
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x69; //发送CDM16 设置块长度
MMCCmd[1] = 0x00; //0x0020->512B
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 )
{
MMCStatus = 29; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
IO0SET = SPI_SEL; //发送几个时钟
SPI_ReceiveByte();
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x50; //??CDM16 ?????
MMCCmd[1] = 0x00; //0x5000->512B
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x02;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 )
{
MMCStatus = 66; //??
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
IO0SET = SPI_SEL; //??????
SPI_ReceiveByte();
return 0;
}
/*******************************************************************************************/
/*SD卡块写入函数*/
int mmc_write_block(uint32 block_number,uint8 buf[512])
{
uint8 Status;
uint16 cc;
block_number+=39;
block_number=block_number<<9; //block_number*512
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x58; //发送CMD24 块写入操作
MMCCmd[1] = (block_number & 0xFF000000) >>24;
MMCCmd[2] = (block_number & 0x00FF0000) >>16; //块地址高位
MMCCmd[3] = (block_number & 0x0000FF00) >>8;
MMCCmd[4] = 0x00; //块地址低位
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
if((mmc_response(0x00))==1)
{
MMCStatus = WRITE_BLOCK_TIMEOUT; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
MMCCmd[0] = 0xFF;
MMCCmd[1] = 0xFF;
MMCCmd[2] = 0xFE;
SPI_Send( MMCCmd, 3 ); //数据起始
SPI_Send( buf, MMC_DATA_SIZE ); //写数据
MMCCmd[0] = 0xFF;
MMCCmd[1] = 0xFF;
SPI_Send( MMCCmd,2 );
do
{
Status=SPI_ReceiveByte();
}
while(Status==0xFF);
if ( (Status & 0x0F) != 0x05 )
{
MMCStatus = WRITE_BLOCK_FAIL; //写入失败
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
cc=2000;
while(cc--);
while((SPI_ReceiveByte())!=0xFF);
IO0SET = SPI_SEL; //发送几个时钟
SPI_ReceiveByte();
return 0;
}
/*SD卡读数据*/
int mmc_read_block(uint32 block_number,uint8 buf[512])
{
uint8 Checksum;
block_number+=39;
block_number=block_number<<9; //block_number*512
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x51; //发送CMD17 读数
MMCCmd[1] = (block_number & 0xFF000000) >>24;
MMCCmd[2] = (block_number & 0x00FF0000) >>16; //块地址高位
MMCCmd[3] = (block_number & 0x0000FF00) >>8;
MMCCmd[4] = 0x00; //块地址低位
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
SPI_ReceiveByte();
if((mmc_response(0x00))==1)
{
MMCStatus = 30;
IO0SET = SPI_SEL; //令牌丢失 SSEL CS->1
return MMCStatus;
}
if((mmc_response(0xFE))==1)
{ //令牌
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
IO0SET = SPI_SEL; //令牌丢失 SSEL CS->1
return MMCStatus;
}
SPI_Receive( buf, MMC_DATA_SIZE );
Checksum = SPI_ReceiveByte(); //和校验
Checksum = Checksum << 0x08 | SPI_ReceiveByte();
IO0SET = SPI_SEL; //SSEL CS->1
SPI_ReceiveByte();
return 0;
}
/*******************************************************************************************/
/*SD卡响应函数*/
int mmc_response( uint8 response)
{
uint32 count = 0xFFFF;
uint8 result;
while( count > 0 )
{
result = SPI_ReceiveByte(); //接收数据
if ( result == response )
{
break;
}
count--;
}
if ( count == 0 )
return 1; //超时无响应
else
return 0; //正常响应
}
/*******************************************************************************************/
/*SD卡读数据*/
int mmc_read_state(uint8 st[1])
{
IO0CLR = SPI_SEL; //SSEL CS->0
MMCCmd[0] = 0x4D;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send( MMCCmd, MMC_CMD_SIZE );
if( (mmc_response(0x00))==1 )
{
MMCStatus = 23; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
SPI_Receive( st, 1 );
IO0SET = SPI_SEL; //发送几个时钟
SPI_ReceiveByte();
return 0;
}
/*******************************************************************************************/
/*SD卡读数据*/
int mmc_read_csd(uint8 reg[16])
{
uint16 Checksum;
IO0CLR = SPI_SEL;
MMCCmd[0] = 0x49;
MMCCmd[1] = 0x00;
MMCCmd[2] = 0x00;
MMCCmd[3] = 0x00;
MMCCmd[4] = 0x00;
MMCCmd[5] = 0xFF;
SPI_Send(MMCCmd, MMC_CMD_SIZE );
if((mmc_response(0x00))==1)
{
MMCStatus = READ_BLOCK_TIMEOUT; //超时
IO0SET = SPI_SEL; //SSEL CS->1
return MMCStatus;
}
if((mmc_response(0xFE))==1)
{ //令牌
MMCStatus = READ_BLOCK_DATA_TOKEN_MISSING;
IO0SET = SPI_SEL; //令牌丢失 SSEL CS->1
return MMCStatus;
}
SPI_Receive( reg, 16 );
Checksum = SPI_ReceiveByte(); //和校验
Checksum = Checksum << 0x08 | SPI_ReceiveByte();
IO0SET = SPI_SEL; //SSEL CS->1
SPI_ReceiveByte();
return 0;
}
/*******************************************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -