?? mmc_sd.c
字號(hào):
/*******************************************************************************
* 本文件為SPI操作SD卡的底層驅(qū)動(dòng)文件
* 包括SPI模塊及相關(guān)IO的初始化,SPI讀寫(xiě)SD卡(寫(xiě)指令,讀數(shù)據(jù)等)
*******************************************************************************/
#include "mmc_sd.h"
u8 SD_Type=0;//SD卡的類型
//SD卡驅(qū)動(dòng)部分代碼
//SD_Init去掉了電壓判斷,使其適應(yīng)更多的卡
//正點(diǎn)原子@SCUT
//CHECK:09/06/08
////////////////////////////////////////////////////////////////////////////////
// 以下是SPI模塊的初始化代碼,配置成主機(jī)模式,訪問(wèn)SD卡
////////////////////////////////////////////////////////////////////////////////
/*******************************************************************************
* Function Name : SPI2_Configuration
* Description : SPI模塊初始化,【包括相關(guān)IO口的初始化】
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void SPI2_Configuration(void)
{
RCC->APB2ENR|=1<<3; //PORTB時(shí)鐘使能
RCC->APB1ENR|=1<<14; //SPI2時(shí)鐘使能
//存儲(chǔ)器映射,不用理
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
GPIOB->CRH&=0X0000FFFF;//PB13.14.15復(fù)用輸出
GPIOB->CRH|=0XBBB30000;//PB12推挽輸出
GPIOB->ODR|=0XF000; //PB12.13.14.15上拉
SPI2->CR1|=0<<10;//全雙工模式
SPI2->CR1|=1<<9; //軟件nss管理
SPI2->CR1|=1<<8;
SPI2->CR1|=1<<2; //SPI主機(jī)
SPI2->CR1|=0<<11;//8bit數(shù)據(jù)格式
SPI2->CR1|=1<<1; //空閑模式下SCK為1 CPOL=1
SPI2->CR1|=1<<0; //數(shù)據(jù)采樣從第二個(gè)時(shí)間邊沿開(kāi)始,CPHA=1
SPI2->CR1|=6<<3; //Fsck=Fcpu/256
SPI2->CR1|=0<<7; //MSBfirst
SPI2->CR1|=1<<6; //SPI設(shè)備使能
}
/*******************************************************************************
* Function Name : SPI2_SetSpeed
* Description : SPI設(shè)置速度為高速
* Input : u8 SpeedSet
* 如果速度設(shè)置輸入0,則低速模式,非0則高速模式
* SPI_SPEED_HIGH 1
* SPI_SPEED_LOW 0
* Output : None
* Return : None
*******************************************************************************/
void SPI2_SetSpeed(u8 SpeedSet)
{
SPI2->CR1&=0XFFC7;//Fsck=Fcpu/256
if(SpeedSet==SPI_SPEED_HIGH)//高速
{
SPI2->CR1|=0<<3;//Fsck=Fpclk/2=18Mhz
}else//低速
{
SPI2->CR1|=6<<3; //Fsck=Fpclk/256=281.25Khz
}
SPI2->CR1|=1<<6; //SPI設(shè)備使能
/*******************************************************************************
* Function Name : SPI2_ReadWriteByte
* Description : SPI讀寫(xiě)一個(gè)字節(jié)(發(fā)送完成后返回本次通訊讀取的數(shù)據(jù))
* Input : u8 TxData 待發(fā)送的數(shù)
* Output : None
* Return : u8 RxData 收到的數(shù)
*******************************************************************************/
u8 SPI2_ReadWriteByte(u8 TxData)
{
while((SPI2->SR&1<<1)==0);//等待發(fā)送區(qū)空
SPI2->DR=TxData; //發(fā)送一個(gè)byte
while((SPI2->SR&1<<0)==0);//等待接收完一個(gè)byte
return SPI2->DR; //返回收到的數(shù)據(jù)
}
/*******************************************************************************
* Function Name : SD_WaitReady
* Description : 等待SD卡Ready
* Input : None
* Output : None
* Return : u8
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_WaitReady(void)
{
u8 r1;
u16 retry;
retry = 0;
do
{
r1 = SPI2_ReadWriteByte(0xFF);
if(retry==0xfffe)return 1;
}while(r1!=0xFF);
return 0;
}
/*******************************************************************************
* Function Name : SD_SendCommand
* Description : 向SD卡發(fā)送一個(gè)命令
* Input : u8 cmd 命令
* u32 arg 命令參數(shù)
* u8 crc crc校驗(yàn)值
* Output : None
* Return : u8 r1 SD卡返回的響應(yīng)
*******************************************************************************/
u8 SD_SendCommand(u8 cmd, u32 arg, u8 crc)
{
unsigned char r1;
unsigned char Retry = 0;
//????????
SPI2_ReadWriteByte(0xff);
//片選端置低,選中SD卡
SD_CS_ENABLE();
//發(fā)送
SPI2_ReadWriteByte(cmd | 0x40); //分別寫(xiě)入命令
SPI2_ReadWriteByte(arg >> 24);
SPI2_ReadWriteByte(arg >> 16);
SPI2_ReadWriteByte(arg >> 8);
SPI2_ReadWriteByte(arg);
SPI2_ReadWriteByte(crc);
//等待響應(yīng),或超時(shí)退出
while((r1 = SPI2_ReadWriteByte(0xFF))==0xFF)
{
Retry++;
if(Retry > 200)break;
}
//關(guān)閉片選
SD_CS_DISABLE();
//在總線上額外增加8個(gè)時(shí)鐘,讓SD卡完成剩下的工作
SPI2_ReadWriteByte(0xFF);
//返回狀態(tài)值
return r1;
}
/*******************************************************************************
* Function Name : SD_SendCommand_NoDeassert
* Description : 向SD卡發(fā)送一個(gè)命令(結(jié)束是不失能片選,還有后續(xù)數(shù)據(jù)傳來(lái))
* Input : u8 cmd 命令
* u32 arg 命令參數(shù)
* u8 crc crc校驗(yàn)值
* Output : None
* Return : u8 r1 SD卡返回的響應(yīng)
*******************************************************************************/
u8 SD_SendCommand_NoDeassert(u8 cmd, u32 arg, u8 crc)
{
unsigned char r1;
unsigned char Retry = 0;
//????????
SPI2_ReadWriteByte(0xff);
//片選端置低,選中SD卡
SD_CS_ENABLE();
//發(fā)送
SPI2_ReadWriteByte(cmd | 0x40); //分別寫(xiě)入命令
SPI2_ReadWriteByte(arg >> 24);
SPI2_ReadWriteByte(arg >> 16);
SPI2_ReadWriteByte(arg >> 8);
SPI2_ReadWriteByte(arg);
SPI2_ReadWriteByte(crc);
//等待響應(yīng),或超時(shí)退出
while((r1 = SPI2_ReadWriteByte(0xFF))==0xFF)
{
Retry++;
if(Retry > 200)break;
}
//返回響應(yīng)值
return r1;
}
/*******************************************************************************
* Function Name : SD_Init
* Description : 初始化SD卡
* Input : None
* Output : None
* Return : u8
* 0:NO_ERR
* 1:TIME_OUT
* 99:NO_CARD
*******************************************************************************/
u8 SD_Init(void)
{
u16 i; // 用來(lái)循環(huán)計(jì)數(shù)
u8 r1; // 存放SD卡的返回值
u16 retry; // 用來(lái)進(jìn)行超時(shí)計(jì)數(shù)
u8 buff[6];
SPI2_Configuration();
SPI2_SetSpeed(0);
SD_CS_ENABLE();
// 純延時(shí),等待SD卡上電完成
for(i=0;i<0xf00;i++);
//先產(chǎn)生>74個(gè)脈沖,讓SD卡自己初始化完成
for(i=0;i<10;i++)
{
SPI2_ReadWriteByte(0xFF);
}
//-----------------SD卡復(fù)位到idle開(kāi)始-----------------
//循環(huán)連續(xù)發(fā)送CMD0,直到SD卡返回0x01,進(jìn)入IDLE狀態(tài)
//超時(shí)則直接退出
retry = 0;
do
{
//發(fā)送CMD0,讓SD卡進(jìn)入IDLE狀態(tài)
r1 = SD_SendCommand(CMD0, 0, 0x95);
retry++;
}while((r1 != 0x01) && (retry<200));
//跳出循環(huán)后,檢查原因:初始化成功?or 重試超時(shí)?
if(retry==200) return 1; //超時(shí)返回1
//-----------------SD卡復(fù)位到idle結(jié)束-----------------
//獲取卡片的SD版本信息
r1 = SD_SendCommand_NoDeassert(8, 0x1aa, 0x87);
//如果卡片版本信息是v1.0版本的,即r1=0x05,則進(jìn)行以下初始化
if(r1 == 0x05)
{
//設(shè)置卡類型為SDV1.0,如果后面檢測(cè)到為MMC卡,再修改為MMC
SD_Type = SD_TYPE_V1;
//如果是V1.0卡,CMD8指令后沒(méi)有后續(xù)數(shù)據(jù)
//片選置高,結(jié)束本次命令
SD_CS_DISABLE();
//多發(fā)8個(gè)CLK,讓SD結(jié)束后續(xù)操作
SPI2_ReadWriteByte(0xFF);
//-----------------SD卡、MMC卡初始化開(kāi)始-----------------
//發(fā)卡初始化指令CMD55+ACMD41
// 如果有應(yīng)答,說(shuō)明是SD卡,且初始化完成
// 沒(méi)有回應(yīng),說(shuō)明是MMC卡,額外進(jìn)行相應(yīng)初始化
retry = 0;
do
{
//先發(fā)CMD55,應(yīng)返回0x01;否則出錯(cuò)
r1 = SD_SendCommand(CMD55, 0, 0);
if(r1 != 0x01)return r1;
//得到正確響應(yīng)后,發(fā)ACMD41,應(yīng)得到返回值0x00,否則重試200次
r1 = SD_SendCommand(ACMD41, 0, 0);
retry++;
}while((r1!=0x00) && (retry<400));
// 判斷是超時(shí)還是得到正確回應(yīng)
// 若有回應(yīng):是SD卡;沒(méi)有回應(yīng):是MMC卡
//----------MMC卡額外初始化操作開(kāi)始------------
if(retry==400)
{
retry = 0;
//發(fā)送MMC卡初始化命令(沒(méi)有測(cè)試)
do
{
r1 = SD_SendCommand(1, 0, 0);
retry++;
}while((r1!=0x00)&& (retry<400));
if(retry==400)return 1; //MMC卡初始化超時(shí)
//寫(xiě)入卡類型
SD_Type = SD_TYPE_MMC;
}
//----------MMC卡額外初始化操作結(jié)束------------
//設(shè)置SPI為高速模式
SPI2_SetSpeed(1);
SPI2_ReadWriteByte(0xFF);
//禁止CRC校驗(yàn)
r1 = SD_SendCommand(CMD59, 0, 0x95);
if(r1 != 0x00)return r1; //命令錯(cuò)誤,返回r1
//設(shè)置Sector Size
r1 = SD_SendCommand(CMD16, 512, 0x95);
if(r1 != 0x00)return r1;//命令錯(cuò)誤,返回r1
//-----------------SD卡、MMC卡初始化結(jié)束-----------------
}//SD卡為V1.0版本的初始化結(jié)束
//下面是V2.0卡的初始化
//其中需要讀取OCR數(shù)據(jù),判斷是SD2.0還是SD2.0HC卡
else if(r1 == 0x01)
{
//V2.0的卡,CMD8命令后會(huì)傳回4字節(jié)的數(shù)據(jù),要跳過(guò)再結(jié)束本命令
buff[0] = SPI2_ReadWriteByte(0xFF); //should be 0x00
buff[1] = SPI2_ReadWriteByte(0xFF); //should be 0x00
buff[2] = SPI2_ReadWriteByte(0xFF); //should be 0x01
buff[3] = SPI2_ReadWriteByte(0xFF); //should be 0xAA
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xFF);//the next 8 clocks
//判斷該卡是否支持2.7V-3.6V的電壓范圍
//if(buff[2]==0x01 && buff[3]==0xAA) //不判斷,讓其支持的卡更多
{
retry = 0;
//發(fā)卡初始化指令CMD55+ACMD41
do
{
r1 = SD_SendCommand(CMD55, 0, 0);
if(r1!=0x01)return r1;
r1 = SD_SendCommand(ACMD41, 0x40000000, 0);
if(retry>200)return r1; //超時(shí)則返回r1狀態(tài)
}while(r1!=0);
//初始化指令發(fā)送完成,接下來(lái)獲取OCR信息
//-----------鑒別SD2.0卡版本開(kāi)始-----------
r1 = SD_SendCommand_NoDeassert(CMD58, 0, 0);
if(r1!=0x00)return r1; //如果命令沒(méi)有返回正確應(yīng)答,直接退出,返回應(yīng)答
//讀OCR指令發(fā)出后,緊接著是4字節(jié)的OCR信息
buff[0] = SPI2_ReadWriteByte(0xFF);
buff[1] = SPI2_ReadWriteByte(0xFF);
buff[2] = SPI2_ReadWriteByte(0xFF);
buff[3] = SPI2_ReadWriteByte(0xFF);
//OCR接收完成,片選置高
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xFF);
//檢查接收到的OCR中的bit30位(CCS),確定其為SD2.0還是SDHC
//如果CCS=1:SDHC CCS=0:SD2.0
if(buff[0]&0x40)SD_Type = SD_TYPE_V2HC; //檢查CCS
else SD_Type = SD_TYPE_V2;
//-----------鑒別SD2.0卡版本結(jié)束-----------
//設(shè)置SPI為高速模式
SPI2_SetSpeed(1);
}
}
return r1;
}
/*******************************************************************************
* Function Name : SD_ReceiveData
* Description : 從SD卡中讀回指定長(zhǎng)度的數(shù)據(jù),放置在給定位置
* Input : u8 *data(存放讀回?cái)?shù)據(jù)的內(nèi)存>len)
* u16 len(數(shù)據(jù)長(zhǎng)度)
* u8 release(傳輸完成后是否釋放總線CS置高 0:不釋放 1:釋放)
* Output : None
* Return : u8
* 0:NO_ERR
* other:錯(cuò)誤信息
*******************************************************************************/
u8 SD_ReceiveData(u8 *data, u16 len, u8 release)
{
u16 retry;
u8 r1;
// 啟動(dòng)一次傳輸
SD_CS_ENABLE();
//等待SD卡發(fā)回?cái)?shù)據(jù)起始令牌0xFE
retry = 0;
do
{
r1 = SPI2_ReadWriteByte(0xFF);
retry++;
if(retry>2000) //2000次等待后沒(méi)有應(yīng)答,退出報(bào)錯(cuò)
{
SD_CS_DISABLE();
return 1;
}
}while(r1 != 0xFE);
while(len--)
{
*data = SPI2_ReadWriteByte(0xFF);
data++;
}
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -