首先是SD卡的初始化問題。SD卡的初始化很簡單,各個論壇上寫的也很詳細,,個人認為基本不存在太大問題。首先是
74個clk,,然后CS_LOW,;發(fā)送CMD0,收到的應答是0x01,;接著發(fā)送CMD1,,收到的應答應該是0x00;最后CS_HIGH,。至此,,初始化
完成。需要注意的問題:初始化的時鐘不宜太快,,可以在SD卡初始化完成后可提高數(shù)據(jù)讀寫速度,;在發(fā)送命令之前和收到應答位之后,,主控制器應該發(fā)送8個時鐘
完成相應操作;CMD0的CRC是0x95,,其余命令的CRC無所謂,。 讀取單塊數(shù)據(jù)流程:CS_LOW-->8個clk-->發(fā)送CMD17-->接收響應R1-->接收讀數(shù)據(jù)起始令牌0xFE-->接收數(shù)據(jù)-->接收CRC-->8個clk-->CS_HIGH; 寫入單塊數(shù)據(jù)流程:CS_LOW-->8個clk-->發(fā)送CMD24-->接收響應R1-->寫入讀數(shù)據(jù)起始令牌0xFE-->寫入數(shù)據(jù)-->接收CRC-->8個clk-->CS_HIGH,;
讀寫操作指令:單塊寫命令CMD24,多塊寫命令CMD25,;單塊讀命令 CMD17,,多塊讀命令CMD18。單塊讀寫時,,數(shù)據(jù)塊的長度為512字節(jié),,多塊讀寫時SD卡收到1個停止命令CMD12后停止讀寫。
本程序參考自bozai的SD卡驅(qū)動程序,, 增加了SD,、MMC卡判斷的功能,SD,、MMC初始化成功后能返回卡的類型參數(shù)供主程序使用,。
//--------SD_MMC.H------------------------
#ifndef __SD_MMC_H__ #define __SD_MMC_H__
// 數(shù)據(jù)宏定義 #define uint8 unsigned char #define int8 signed char #define uint16 unsigned int #define int16 signed int #define uint32 unsigned long #define int32 signed long
// C8051F015與SD_MMC 的接口定義 sbit SDCS = P3^0; sbit SDDET = P3^1; sbit SDWP = P3^2;
void SPI_SendWreit(uchar temp); // VS1003B DATA發(fā)送 uint8 SPI_SendByte(uint8 val); // SPI傳送一個字節(jié) uint8 MMC_SD_SendCmd(uint8 Cmd, uint32 arg); //發(fā)送卡命令 uint8 MMC_SD_ReadSingleBlock(uint32 sector, uint8 *buffer); //讀一個扇區(qū) uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8 *buffer); //寫一個扇區(qū) uint8 MMC_SD_init(); //mmc_sd卡初始化
#endif //---------SD_MMC.C-----------------
//--------------------------------------------------------- // SD_MMC 底層驅(qū)動函數(shù)庫 // 編譯環(huán)境:Keil C V2.40 // 編寫日期:2008-04-07 // 最后更新:2008-05-04 //--------------------------------------------------------- #include "main.h" #include "sd_mmc.h"
//--------------------------------------------------- // 函數(shù)名:SPI_SendByte // 功 能:SPI 數(shù)據(jù)發(fā)送 // 參 數(shù):uchar // 返回值: //---------------------------------------------------
void SPI_SendWreit(uchar temp) { SPI0DAT=temp; while(TXBSY); // 查詢發(fā)送標志位 }
//--------------------------------------------------- // 函數(shù)名:SPI_SendByte // 功 能:SPI傳送一個字節(jié) // 參 數(shù):uchar // 返回值:uchar //---------------------------------------------------
uint8 SPI_SendByte(uint8 val) // uint8= uchar { SPI0DAT = val; while(TXBSY); return SPI0DAT; }
//--------------------------------------------------- // 函數(shù)名:MMC_SD_SendCmd // 功 能:發(fā)送卡命令 // 參 數(shù):uint8,uint32 // 返回值:uint8 //---------------------------------------------------
uint8 MMC_SD_SendCmd(uint8 Cmd, uint32 arg) { uint8 r1; uint8 retry=0; SPI_SendWreit(0xFF); //發(fā)命令前先發(fā)送8個時鐘 SPI_SendWreit(Cmd | 0x40); //分別寫入命令 SPI_SendWreit(arg>>24); SPI_SendWreit(arg>>16); SPI_SendWreit(arg>>8); SPI_SendWreit(arg); SPI_SendWreit(0x95); //僅本次有效的 CRC值 while((r1 = SPI_SendByte(0xFF)) == 0xFF) //等待響應 if(retry++ > 8) break; //超時退出
return r1; //返回狀態(tài)值 }
//--------------------------------------------------- // 函數(shù)名:MMC_SD_ReadSingleBlock // 功 能:讀一個扇區(qū) // 參 數(shù):扇區(qū),數(shù)據(jù)緩沖區(qū) // 返回值: //---------------------------------------------------
uint8 MMC_SD_ReadSingleBlock(uint32 sector,uint8 *buffer) { uint8 r1; uint16 i;
SDCS=0; // 使能Card
r1 = MMC_SD_SendCmd(17, sector<<9); // 發(fā)讀扇區(qū)命令 if(r1 != 0x00) return r1;
while(SPI_SendByte(0xFF) != 0xFE); //--等待數(shù)據(jù)的起始令牌號--
for(i=0; i<512; i++) //讀512個數(shù)據(jù) { *buffer++ = SPI_SendByte(0xFF); }
SPI_SendWreit(0xFF); // 發(fā)送偽CRC SPI_SendWreit(0xFF); SDCS=1; // 關(guān)閉Card return 0; }
//--------------------------------------------------- // 函數(shù)名:MMC_SD_WriteSingleBlock // 功 能:寫一個扇區(qū) // 參 數(shù):扇區(qū),,數(shù)據(jù)緩沖區(qū) // 返回值: //---------------------------------------------------
uint8 MMC_SD_WriteSingleBlock(uint32 sector, uint8 *buffer) { uint8 r1; uint16 i;
SDCS=0; // 使能Card
r1 = MMC_SD_SendCmd(24, sector<<9); //寫命令 if(r1 != 0x00) return r1;
SPI_SendWreit(0xFF); SPI_SendWreit(0xFF); SPI_SendWreit(0xFF);
SPI_SendWreit(0xFE); //發(fā)送數(shù)據(jù)起始令牌號 for(i=0; i<512; i++) //以扇區(qū)為單位寫入數(shù)據(jù) { SPI_SendWreit(*buffer++); } SPI_SendWreit(0xFF); // 發(fā)送偽CRC SPI_SendWreit(0xFF); r1 = SPI_SendByte(0xFF); // 讀數(shù)據(jù)應答令牌號 if( (r1&0x1F) != 0x05) //等待是否成功 { SDCS=1; return r1; }
while(!SPI_SendByte(0xFF)); //--等待操作完成--
SDCS=1; // 關(guān)閉Card
return 0; }
//--------------------------------------------------- // 函數(shù)名:MMC_SD_Init // 功 能:sd卡初始化 // 參 數(shù):無 // 返回值:uint8 type // 卡類型返回值: 0x10 SD, 0x20 MMC //---------------------------------------------------
uint8 MMC_SD_init() { uint8 i; uint8 retry; uint8 r1=0; uint8 type=0; // 卡類型返回值:0xA0 SD 0xB0 MMC SDCS = 0; // 使能Card
SPI_speed=0x13; //低速 SPI=300k Fsystem=12Mhz retry = 0;
do { for(i=0;i<10;i++) SPI_SendByte(0xFF); //發(fā)送80個時鐘,,使卡同步 r1 = MMC_SD_SendCmd(0, 0); //發(fā)Cmd0(復位)命令 retry++; if(retry > 30) return (type=0x01); //超時退出,個別卡需要更多次循環(huán)才有反應 } while(r1 != 0x01); // MMC、SD卡成功轉(zhuǎn)到SPI模式
retry = 0;
//****** SD卡在進入SPI模式后,,激活命令和MMC卡一樣為Cmd1,,同時Cmd55+Cmd41 仍然有效******//
/* do { r1 = MMC_SD_SendCmd(1, 0); //發(fā)Cmd1(active激活)命令 retry++; if(retry > 100) return 1; //超時退出 } while(r1);*/ do { r1 = MMC_SD_SendCmd(55, 0); // 先發(fā)送 Cmd55 if(r1 == 0x01) // 如果有反應 { r1 = MMC_SD_SendCmd(41,0); // 再發(fā)送 Cmd41 進行激活 if(r1 == 0x00) type = 0x10; // 激活成功就是SD卡 }
else { // 如果發(fā)送 Cmd55無反應,改發(fā)送 Cmd1 r1 = MMC_SD_SendCmd(1,0); if(r1 == 0x00) type = 0x20; // 激活成功就是MMC卡 }
retry++; if(retry > 255) return (type=0x01); // 超時退出, 個別卡需要更多次循環(huán)才有反應 } while(r1 != 0x00); // MMC,、SD卡激活后的返回值均為0x00*/
// SPI_SendByte(0xFF); // 高速SPI前先發(fā)送8個時鐘 // SPI_speed = 0x07; // 切換到高速 SPI
r1 = MMC_SD_SendCmd(59, 0); //關(guān)CRC r1 = MMC_SD_SendCmd(16, 512); //設置讀取一次的字節(jié)數(shù)
SDCS = 1; // 關(guān)閉Card // SPI_speed=0x07; //切換到高速 SPI
return type; //參數(shù)返回,,1為初始化錯誤,10為SD卡,,20為MMC卡 }
//----------------------------------------------------------- // End of File //------------------------------------
|