SD卡是嵌入式設(shè)備中很常用的一種存儲設(shè)備,體積小,容量大,通訊簡單,電路簡單所以受到很多設(shè)備廠商的歡迎,主要用來記錄設(shè)備運行過程中的各種信息,以及程序的各種配置信息,很是方便,有這樣幾點是需要知道的
SD卡是基于flash的存儲卡。
SD卡和MMC卡的區(qū)別在于初始化過程不同。SD卡并不是我們通常意義上的手機擴展卡,那種卡叫做TF卡,但是通訊以及驅(qū)動模式是類似的.
SD卡的通信協(xié)議包括SD和SPI兩類,SD卡上電之后默認(rèn)處于SD狀態(tài)。
SD卡使用卡內(nèi)智能控制模塊進(jìn)行FLASH操作控制,包括協(xié)議、安全算法、
數(shù)據(jù)存取、ECC算法、缺陷處理和分析、電源管理、時鐘管理。這些都不需要用戶關(guān)系,這是SD卡廠商做的事情
驅(qū)動SD卡主要要實現(xiàn)讀扇區(qū),寫扇區(qū),初始化,獲取SD卡相關(guān)配置信息這幾個就可以了,
另外.SD卡本身只是一種數(shù)據(jù)介質(zhì),它不含有文件系統(tǒng),文件系統(tǒng)是一種文件的組織格式,是獨立于存儲介質(zhì)的一種規(guī)范
標(biāo)準(zhǔn)SD卡引腳序列
SD卡引腳功能表
TF卡引腳排序
TF卡引腳功能表
由此可見,TF卡比SD卡少了一個VSS引腳,也就是少了一個供電引腳
另外電路設(shè)計時若SD卡使用SPI模式,那么不用的幾根數(shù)據(jù)線應(yīng)加上上拉電阻,否者會因為這幾根數(shù)據(jù)線的電流震蕩引起電流損耗,造成電路上的不穩(wěn)定
SD卡電路SPI驅(qū)動模式
SD卡內(nèi)部有五個我們可以讀取的寄存器,分別如下
要讀取這些信息就需要與卡通訊,SD通訊是用命令+數(shù)據(jù)的形式進(jìn)行的,命令格式如下
也就是說,一次SD卡命令發(fā)送一共要發(fā)送6個字節(jié),對于SPI通訊而言,就是SPI總線上傳送六個字節(jié)
字節(jié)1的最高2位固定為01,低6位為命令號(比如CMD16,
為10000即16進(jìn)制的0X10,完整的CMD16,第一個字節(jié)為01010000,即0X10+0X40)。
字節(jié)2~5為命令參數(shù),有些命令是沒有參數(shù)的。對于沒有參數(shù)的命令默認(rèn)發(fā)送0即可
字節(jié)6的高七位為CRC值,最低位恒定為1,crc計算遵循以下規(guī)律
GX為生成多項式,具體計算方法請查看CRC計算相關(guān),不過有一點好處就是,在SPI驅(qū)動模式下,不需要CRC校驗(默認(rèn)SD卡在SPI模式下不開啟CRC校驗,在SD模式下默認(rèn)開始CRC校驗),所以我們只需要對CMD0進(jìn)行CRC就可以了,后面的CRC都可以不管(因為在CMD0之前是SD模式,所以第一個命令需要,切換之后就不用了),而CMD0的CRC為0x95(加上了之后的一位1)
注:SPI模式下打開crc校驗需要用到CMD59的保留命令,請查閱相關(guān)資料
SD卡的命令表如下所示(以下僅寫出SPI模式的CMD)
CMD0復(fù)位SD卡,重置所有卡到Idle狀態(tài),參數(shù)為0
CMD1設(shè)置SD卡到ACTIVATE模式,也就是推出IDLE模式
CMD8發(fā)送接口狀態(tài)命令
CMD9讀取CSD寄存器
CMD10讀取CID寄存器
CMD12在多塊讀取的時候請求停止讀取
CMD13讀取SD卡狀態(tài)寄存器
CMD16設(shè)置單個扇區(qū)的大小一般都設(shè)置為512字節(jié)一個扇區(qū)
CMD17讀取扇區(qū)命令
CMD18讀取多個扇區(qū)知道發(fā)送停止命令
CMD24寫扇區(qū)命令
CMD25寫多個扇區(qū)命令
CMD27編輯CSD位
CMD28設(shè)置地址組保護(hù)位。寫保護(hù)由卡配置數(shù)據(jù)的WP_GRP_SIZE指定
CMD29清除保護(hù)位
CMD30要求卡發(fā)送寫保護(hù)狀態(tài),參數(shù)中有要查詢的地址
CMD32設(shè)置要擦除的第一個寫數(shù)據(jù)塊地址
CMD33設(shè)置要擦除的最后一個寫數(shù)據(jù)塊地址
CMD38擦除所有選中的塊
CMD42設(shè)置SD卡的解鎖或者上鎖
CMD55告訴SD卡下一個命令式卡應(yīng)用命令,不是標(biāo)準(zhǔn)命令
CMD56應(yīng)用相關(guān)的數(shù)據(jù)塊讀寫命令
CMD58讀取OCR信息
CMD59設(shè)置crc校驗的使能與關(guān)閉(前面說到過)
ACMD13發(fā)送SD卡狀態(tài)
ACMD18保留作為SD安全應(yīng)用(也就是這命令沒用)
ACMD22發(fā)送寫數(shù)據(jù)塊的數(shù)目。響應(yīng)為32位+CRC
ACMD23設(shè)置寫前預(yù)擦除的數(shù)據(jù)塊數(shù)目(用來加速多數(shù)據(jù)塊寫操作)?!?”=默認(rèn)(一個塊)(1)
不管是否使用ACMD23,在多數(shù)據(jù)塊寫操作中都需要STOP_TRAN(CMD12)命令
ACMD25 26 38保留作為安全應(yīng)用
ACMD41要求訪問的卡發(fā)送它的操作條件寄存器(OCR)內(nèi)容
ACMD42連接[1]/斷開[0]卡上CD/DAT3(pin 1]的50K歐姆上拉電阻。上拉電阻可用來檢測卡
ACMD43-49保留作為安全應(yīng)用
ACMD51讀取SD配置寄存器SCR
ACMD命令,全稱應(yīng)該是application CMD,所以使用ACMD都需要在發(fā)送CMD55之后
發(fā)出命令后會收到相應(yīng)的響應(yīng),所有響應(yīng)通過CMD線傳輸,響應(yīng)以MSB開始,不同類型的響應(yīng)長度根據(jù)類型不同而不同。
響應(yīng)以起始位開始(通常為“0”),接著這是傳輸方向的位(卡為0)。除了R3外其他
響應(yīng)都有CRC。每個響應(yīng)都以結(jié)束位(通常為“1”)結(jié)束。,SD卡響應(yīng)格式有多種
1.R1響應(yīng)
2.R1b響應(yīng)
多了一個忙數(shù)據(jù)
3.R2響應(yīng)
4.R3響應(yīng)(針對于read ocr的響應(yīng)CMD58)
5.響應(yīng)R4和R5都是正對于SD mode的響應(yīng)
6.針對CMD8命令的響應(yīng)R7
SD卡的初始化以及識別過程(為了方便起見,我們只檢測響應(yīng)的R1狀態(tài))
1.初始化與SD卡連接的硬件條件(MCU的SPI配置,IO口配置);
2.上電延時(>74個CLK)(為了讓卡正常啟動)
3.復(fù)位卡(CMD0),進(jìn)入IDLE狀態(tài),檢測R1的最低位,是否為閑置狀態(tài)
4.發(fā)送CMD8,檢查是否支持2.0協(xié)議,因為這個命令是在2.0的協(xié)議里面才添加的
5.根據(jù)不同協(xié)議檢查SD卡(命令包括:CMD55、CMD41、CMD58和CMD1等);
6.取消片選,發(fā)多8個CLK,結(jié)束初始化
具體請查看下圖
以下是網(wǎng)絡(luò)上找到的一份經(jīng)我修改之后的SD卡驅(qū)動,不完全符合SD卡標(biāo)準(zhǔn)驅(qū)動,但是我用著一直還蠻正常,大家有興趣可以看看改改
Spisd.c
#include"spisd.h"
//預(yù)定義SD卡類型
u8SD_Type=0;//SD卡的類型
//這部分應(yīng)根據(jù)具體的連線來修改!
#defineSD_CSPAout(4)//SD卡片選引腳
//data:要寫入的數(shù)據(jù)
//返回值:讀到的數(shù)據(jù)
staticu8SdSpiReadWriteByte(u8data)
{
returnSpi1ReadWriteByte(data);
}
//SD卡初始化的時候,需要低速
staticvoidSdSpiSpeedLow(void)
{
Spi1SetSpeed(SPI_SPEED_256);//設(shè)置到低速模式用于初始化,最高spi速度為400k
}
//SD卡正常工作的時候,可以高速了
staticvoidSdSpiSpeedHigh(void)
{
Spi1SetSpeed(SPI_SPEED_4);//設(shè)置到高速模式初始化完成之后進(jìn)行,最高可到25M,不過一般不用
}
staticvoidSdIOInit(void)
{
GPIO_InitTypeDefGPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP;//推挽輸出
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);//初始化A4
SD_CS=1;
Spi1Init();//初始化SPI接口
SdSpiSpeedLow();//初始化設(shè)置為低速
}
//等待卡準(zhǔn)備好
//返回值:0,準(zhǔn)備好了;其他,錯誤代碼
staticu8SdWaitReady(void)
{
u32t=0;
do
{
if(SdSpiReadWriteByte(0XFF)==0XFF)return0;//OK
t++;
}while(t<0XFFFFFF);//等待
return1;
}
//取消選擇,釋放SPI總線
voidSD_DisSelect(void)
{
SD_CS=1;
SdSpiReadWriteByte(0xff);//提供額外的8個時鐘
}
//選擇sd卡,并且等待卡準(zhǔn)備OK
//返回值:0,成功;1,失敗;
u8SdSelect(void)
{
SD_CS=0;
if(SdWaitReady()==0)return0;//等待成功
SD_DisSelect();
return 1;//等待失敗