分享一下通過SPI方式讀寫SD卡的驅動源碼,只需要修改SPI讀寫函數(shù)以及片選口就可以投入使用,可自行搭配FATFS文件系統(tǒng)。
SD.c
- #include "SD.h"
- #include "Basic_cfg.h"
- u8 SD_Type = 0;
- /***************************/
- //SD讀寫函數(shù),便于替換SPI接口
- /***************************/
- u8 SD_ReadWriteByte(u8 TxData)
- {
- SPI3_ReadWriteByte(TxData);
- }
- /***************************/
- //忙檢測,等待SD卡
- /***************************/
- u8 SD_WaitReady(void)
- {
- u32 t=0;
- u8 reg;
- for(t=0; t<0xffff; t++)
- {
- reg=SD_ReadWriteByte(0XFF);//獲取返回值
- if(reg==0XFF)
- break;
- }
- if(t<0xffffff)
- return 0;
- else
- return 1;
- }
- /***************************/
- //取消卡選擇
- /***************************/
- void SD_DisSelect(void)
- {
- SD_CS=1;
- SD_ReadWriteByte(0xff);//提供額外的8個時鐘
- }
- /***************************/
- //卡選擇,選擇SD卡
- /***************************/
- u8 SD_Select(void)
- {
- SD_CS=0;
- if(SD_WaitReady()==0) //等待成功
- return 0;
- SD_DisSelect(); //等待失敗
- return 1;
- }
- /***************************/
- //向SD卡發(fā)送一個命令
- //CMD:命令
- //arg:命令參數(shù)
- //crc:校驗
- /***************************/
- u8 SD_SendCmd(u8 cmd, u32 arg, u8 crc)
- {
- u8 r1=0;
- u8 Retry=0;
- SD_DisSelect(); //取消上次片選
- if(SD_Select()) //片選失效
- {
- return 0XFF;
- }
- //發(fā)送
- //分別寫入命令
- SD_ReadWriteByte(cmd | 0x40);
- SD_ReadWriteByte(arg >> 24);
- SD_ReadWriteByte(arg >> 16);
- SD_ReadWriteByte(arg >> 8);
- SD_ReadWriteByte(arg);
- SD_ReadWriteByte(crc);
- if(cmd==CMD12)SD_ReadWriteByte(0xff);
- //等待響應,或超時退出
- Retry=0X1F;
- do
- {
- r1=SD_ReadWriteByte(0xFF);
- }
- while((r1&0X80) && Retry--);
- //返回狀態(tài)值
- return r1;
- }
- /***************************/
- //等待SD卡回應
- //Response:要得到的回應值
- //返回值:0,成功得到了該回應值
- // 其他,得到回應值失敗
- /***************************/
- u8 SD_GetResponse(u8 Response)
- {
- //等待次數(shù)
- u16 Count=0xFFFF;
- //等待得到準確的回應
- while ((SD_ReadWriteByte(0XFF)!=Response)&&Count)
- {
- Count--;
- }
- if (Count==0)
- {
- //得到回應失敗
- return MSD_RESPONSE_FAILURE;
- }
- else
- {
- //正確回應
- return MSD_RESPONSE_NO_ERROR;
- }
- }
- //初始化SD卡
- u8 SD_Init(void)
- {
- u8 r1=0; // 存放SD卡的返回值
- u16 retry; // 用來進行超時計數(shù)
- u8 buf[4];
- u16 i;
- SPI3_Init(); //初始化SPI3
- SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_256); //配置為低速度模式
- for(i=0; i<10; i++) //發(fā)送至少74個脈沖
- {
- SD_ReadWriteByte(0xff);
- }
- retry=20;
- do
- {
- //進入IDLE狀態(tài)
- r1=SD_SendCmd(CMD0,0,0x95);
- }
- while((r1!=0X01) && (retry--));
- //默認無卡
- SD_Type=0;
- //識別卡類型
- if(r1==0X01)
- {
- //SD V2.0
- if(SD_SendCmd(CMD8,0x1AA,0x87)==1)
- {
- //Get trailing return value of R7 resp
- for(i=0; i<4; i++)
- buf[i]=SD_ReadWriteByte(0XFF);
- //卡是否支持2.7~3.6V
- if(buf[2]==0X01&&buf[3]==0XAA)
- {
- retry=0XFFFE;
- do
- {
- //發(fā)送CMD55
- SD_SendCmd(CMD55,0,0X01);
- //發(fā)送CMD41
- r1=SD_SendCmd(CMD41,0x40000000,0X01);
- }
- while(r1&&retry--);
- //鑒別SD2.0卡版本開始
- if(retry&&SD_SendCmd(CMD58,0,0X01)==0)
- {
- //得到OCR值
- for(i=0; i<4; i++)
- buf[i]=SD_ReadWriteByte(0XFF);
- //檢查CCS
- if(buf[0]&0x40)
- {
- SD_Type=SD_TYPE_V2HC;
- }
- else
- {
- SD_Type=SD_TYPE_V2;
- }
- }
- }
- }
- }
- //SD V1.x/ MMC V3
- else
- {
- //發(fā)送CMD55
- SD_SendCmd(CMD55,0,0X01);
- //發(fā)送CMD41
- r1=SD_SendCmd(CMD41,0,0X01);
- if(r1<=1)
- {
- SD_Type=SD_TYPE_V1;
- retry=0XFFFE;
- //等待退出IDLE模式
- do
- {
- //發(fā)送CMD55
- SD_SendCmd(CMD55,0,0X01);
- //發(fā)送CMD41
- r1=SD_SendCmd(CMD41,0,0X01);
- } while(r1&&retry--);
- }
- //MMC卡不支持CMD55+CMD41識別
- else
- {
- //MMC V3
- SD_Type=SD_TYPE_MMC;
- retry=0XFFFE;
- //等待退出IDLE模式
- do
- {
- //發(fā)送CMD1
- r1=SD_SendCmd(CMD1,0,0X01);
- } while(r1&&retry--);
- }
- //錯誤的卡
- if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)
- {
- SD_Type=SD_TYPE_ERR;
- }
- }
- //取消片選
- SD_DisSelect();
- //配置為高速度模式
- SPI3_SetSpeed(SPI_BAUDRATEPRESCALER_4);
- if(SD_Type)
- {
- return 0;
- }
- else if(r1)
- {
- return r1;
- }
- //其他錯誤
- return 0xaa;
- }
- /***************************/
- //從sd卡讀取一個數(shù)據(jù)包的內(nèi)容
- //buf:數(shù)據(jù)緩存區(qū)
- //len:要讀取的數(shù)據(jù)長度.
- //返回值:0,成功;其他,失敗;
- /***************************/
- u8 SD_RecvData(u8*buf,u16 len)
- {
- //等待SD卡發(fā)回數(shù)據(jù)起始令牌0xFE
- if(SD_GetResponse(0xFE))
- {
- return 1;
- }
- //開始接收數(shù)據(jù)
- while(len--)
- {
- *buf=SD_ReadWriteByte(0xFF);
- buf++;
- }
- //下面是2個偽CRC(dummy CRC)
- SD_ReadWriteByte(0xFF);
- SD_ReadWriteByte(0xFF);
- //讀取成功
- return 0;
- }
- /***************************/
- //獲取SD卡的CSD信息,包括容量和速度信息
- //輸入:u8 *cid_data(存放CID的內(nèi)存,至少16Byte)
- //返回值:0:NO_ERR
- // 1:錯誤
- /***************************/
- u8 SD_GetCSD(u8 *csd_data)
- {
- u8 r1;
- //發(fā)CMD9命令,讀CSD
- r1=SD_SendCmd(CMD9,0,0x01);
- if(r1==0)
- {
- //接收16個字節(jié)的數(shù)據(jù)
- r1=SD_RecvData(csd_data, 16);
- }
- //取消片選
- SD_DisSelect();
- if(r1)
- {
- return 1;
- }
- else
- {
- return 0;
- }
- }
- /***************************/
- //獲取SD卡的總扇區(qū)數(shù)(扇區(qū)數(shù))
- //返回值:0: 取容量出錯
- // 其他:SD卡的容量(扇區(qū)數(shù)/512字節(jié))
- //每扇區(qū)的字節(jié)數(shù)必為512,因為如果不是512,則初始化不能通過.
- /***************************/
- u32 SD_GetSectorCount(void)
- {
- u8 csd[16];
- u32 Capacity;
- u8 n;
- u16 csize;
- //取CSD信息,如果期間出錯,返回0
- if(SD_GetCSD(csd)!=0)
- {
- return 0;
- }
- //如果為SDHC卡,按照下面方式計算
- //V2.00的卡
- if((csd[0]&0xC0)==0x40)
- {
- csize = csd[9] + ((u16)csd[8] << 8) + 1;
- //得到扇區(qū)數(shù)
- Capacity = (u32)csize << 10;
- }
- //V1.XX的卡
- else
- {
- n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
- csize = (csd[8] >> 6) + ((u16)csd[7] << 2) + ((u16)(csd[6] & 3) << 10) + 1;
- //得到扇區(qū)數(shù)
- Capacity= (u32)csize << (n - 9);
- }
- return Capacity;
- }
- u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt)
- {
- u8 r1;
- //轉換為字節(jié)地址
- if(SD_Type!=SD_TYPE_V2HC)
- {
- sector <<= 9;
- }
- if(cnt==1)
- {
- //讀命令
- r1=SD_SendCmd(CMD17,sector,0X01);
- //指令發(fā)送成功
- if(r1==0)
- {
- //接收512個字節(jié)
- r1=SD_RecvData(buf,512);
- }
- }
- else
- {
- //連續(xù)讀命令
- r1=SD_SendCmd(CMD18,sector,0X01);
- do
- {
- //接收512個字節(jié)
- r1=SD_RecvData(buf,512);
- buf+=512;
- }
- while(--cnt && r1==0);
- //發(fā)送停止命令
- SD_SendCmd(CMD12,0,0X01);
- }
- //取消片選
- SD_DisSelect();
- return r1;
- }
- /***************************/
- //讀取SD卡的指定扇區(qū)的內(nèi)容,并通過串口1輸出
- //sec:扇區(qū)物理地址編號
- /***************************/
- void SD_Read_Sectorx(u32 sec)
- {
- //存儲扇區(qū)數(shù)據(jù)
- u8 buf[512];
- u16 i;
-
- //讀取0扇區(qū)的內(nèi)容
- if(SD_ReadDisk(buf,sec,1)==0)
- {
- printf("SECTOR 0 DATA:\r\n");
- //打印sec扇區(qū)數(shù)據(jù)
- for(i=0;i<512;i++)
- printf("%X ",buf[i]);
- printf("\r\nDATA ENDED\r\n");
- }
- }
- /***************************/
- //獲取SD卡的CID信息,包括制造商信息
- //輸入: u8 *cid_data(存放CID的內(nèi)存,至少16Byte)
- //返回值:0:NO_ERR
- // 1:錯誤
- /***************************/
- u8 SD_GetCID(u8 *cid_data)
- {
- u8 r1;
- //發(fā)CMD10命令,讀CID
- r1=SD_SendCmd(CMD10,0,0x01);
- if(r1==0x00)
- {
- //接收16個字節(jié)的數(shù)據(jù)
- r1=SD_RecvData(cid_data,16);
- }
- //取消片選
- SD_DisSelect();
- if(r1)
- return 1;
- else
- return 0;
- }
- /***************************/
- //向sd卡寫入一個數(shù)據(jù)包的內(nèi)容 512字節(jié)
- //buf:數(shù)據(jù)緩存區(qū)
- //cmd:指令
- //返回值:0,成功;其他,失敗;
- /***************************/
- u8 SD_SendBlock(u8*buf,u8 cmd)
- {
- u16 t;
- //等待準備失效
- if(SD_WaitReady())
- {
- return 1;
- }
- SD_ReadWriteByte(cmd);
- //不是結束指令
- if(cmd!=0XFD)
- {
- //提高速度,減少函數(shù)傳參時間
- for(t=0;t<512;t++)
- {
- SD_ReadWriteByte(buf[t]);
- }
- //忽略crc
- SD_ReadWriteByte(0xFF);
- SD_ReadWriteByte(0xFF);
- //接收響應
- t=SD_ReadWriteByte(0xFF);
- if((t&0x1F)!=0x05)
- {
- //響應錯誤
- return 2;
- }
- }
- //寫入成功
- return 0;
- }
- /***************************/
- //寫SD卡
- //buf:數(shù)據(jù)緩存區(qū)
- //sector:起始扇區(qū)
- //cnt:扇區(qū)數(shù)
- //返回值:0,ok;其他,失敗.
- /***************************/
- u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt)
- {
- u8 r1;
- //轉換為字節(jié)地址
- if(SD_Type!=SD_TYPE_V2HC)
- {
- sector *= 512;
- }
- if(cnt==1)
- {
- //讀命令
- r1=SD_SendCmd(CMD24,sector,0X01);
- //指令發(fā)送成功
- if(r1==0)
- {
- //寫512個字節(jié)
- r1=SD_SendBlock(buf,0xFE);
- }
- }
- else
- {
- if(SD_Type!=SD_TYPE_MMC)
- {
- SD_SendCmd(CMD55,0,0X01);
- //發(fā)送指令
- SD_SendCmd(CMD23,cnt,0X01);
- }
- //連續(xù)讀命令
- r1=SD_SendCmd(CMD25,sector,0X01);
- if(r1==0)
- {
- do
- {
- //接收512個字節(jié)
- r1=SD_SendBlock(buf,0xFC);
- buf+=512;
- }
- while(--cnt && r1==0);
- //接收512個字節(jié)
- r1=SD_SendBlock(0,0xFD);
- }
- }
- //取消片選
- SD_DisSelect();
- return r1;
- }
復制代碼
sd.h
- #ifndef __SD_H
- #define __SD_H
- #include "sys.h"
- #define SD_CS PAout(15)
- // SD卡類型定義
- #define SD_TYPE_ERR 0X00
- #define SD_TYPE_MMC 0X01
- #define SD_TYPE_V1 0X02
- #define SD_TYPE_V2 0X04
- #define SD_TYPE_V2HC 0X06
- // SD卡指令表
- #define CMD0 0 //卡復位
- #define CMD1 1
- #define CMD8 8 //命令8 ,SEND_IF_COND
- #define CMD9 9 //命令9 ,讀CSD數(shù)據(jù)
- #define CMD10 10 //命令10,讀CID數(shù)據(jù)
- #define CMD12 12 //命令12,停止數(shù)據(jù)傳輸
- #define CMD16 16 //命令16,設置SectorSize 應返回0x00
- #define CMD17 17 //命令17,讀sector
- #define CMD18 18 //命令18,讀Multi sector
- #define CMD23 23 //命令23,設置多sector寫入前預先擦除N個block
- #define CMD24 24 //命令24,寫sector
- #define CMD25 25 //命令25,寫Multi sector
- #define CMD41 41 //命令41,應返回0x00
- #define CMD55 55 //命令55,應返回0x01
- #define CMD58 58 //命令58,讀OCR信息
- #define CMD59 59 //命令59,使能/禁止CRC,應返回0x00
- //數(shù)據(jù)寫入回應字意義
- #define MSD_DATA_OK 0x05
- #define MSD_DATA_CRC_ERROR 0x0B
- #define MSD_DATA_WRITE_ERROR 0x0D
- #define MSD_DATA_OTHER_ERROR 0xFF
- //SD卡回應標記字
- #define MSD_RESPONSE_NO_ERROR 0x00
- #define MSD_IN_IDLE_STATE 0x01
- #define MSD_ERASE_RESET 0x02
- #define MSD_ILLEGAL_COMMAND 0x04
- #define MSD_COM_CRC_ERROR 0x08
- #define MSD_ERASE_SEQUENCE_ERROR 0x10
- #define MSD_ADDRESS_ERROR 0x20
- #define MSD_PARAMETER_ERROR 0x40
- #define MSD_RESPONSE_FAILURE 0xFF
- void SD_Read_Sectorx(u32 sec);
- u8 SD_Init(void);
- u8 SD_WaitReady(void);
- u8 SD_GetResponse(u8 Response);
- u32 SD_GetSectorCount(void);
- u8 SD_GetCID(u8 *cid_data);
- u8 SD_GetCSD(u8 *csd_data);
- u8 SD_ReadDisk(u8*buf,u32 sector,u8 cnt);
- u8 SD_WriteDisk(u8*buf,u32 sector,u8 cnt);
- #endif
復制代碼
原理圖: 無
仿真: 無
|