?? mmc_sd.c
字號:
//下面是2個偽CRC(dummy CRC)
SPI2_ReadWriteByte(0xFF);
SPI2_ReadWriteByte(0xFF);
//按需釋放總線,將CS置高
if(release == RELEASE)
{
//傳輸結束
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xFF);
}
return 0;
}
/*******************************************************************************
* Function Name : SD_GetCID
* Description : 獲取SD卡的CID信息,包括制造商信息
* Input : u8 *cid_data(存放CID的內存,至少16Byte)
* Output : None
* Return : u8
* 0:NO_ERR
* 1:TIME_OUT
* other:錯誤信息
*******************************************************************************/
u8 SD_GetCID(u8 *cid_data)
{
u8 r1;
//發CMD10命令,讀CID
r1 = SD_SendCommand(CMD10, 0, 0xFF);
if(r1 != 0x00)return r1; //沒返回正確應答,則退出,報錯
//接收16個字節的數據
SD_ReceiveData(cid_data, 16, RELEASE);
return 0;
}
/*******************************************************************************
* Function Name : SD_GetCSD
* Description : 獲取SD卡的CSD信息,包括容量和速度信息
* Input : u8 *cid_data(存放CID的內存,至少16Byte)
* Output : None
* Return : u8
* 0:NO_ERR
* 1:TIME_OUT
* other:錯誤信息
*******************************************************************************/
u8 SD_GetCSD(u8 *csd_data)
{
u8 r1;
//發CMD9命令,讀CSD
r1 = SD_SendCommand(CMD9, 0, 0xFF);
if(r1 != 0x00)return r1; //沒返回正確應答,則退出,報錯
//接收16個字節的數據
SD_ReceiveData(csd_data, 16, RELEASE);
return 0;
}
/*******************************************************************************
* Function Name : SD_GetCapacity
* Description : 獲取SD卡的容量(字節)
* Input : None
* Output : None
* Return : u32 capacity
* 0: 取容量出錯
*******************************************************************************/
u32 SD_GetCapacity(void)
{
u8 csd[16];
u32 Capacity;
u8 r1;
u16 i;
u16 temp;
//取CSD信息,如果期間出錯,返回0
if(SD_GetCSD(csd)!=0) return 0;
//如果為SDHC卡,按照下面方式計算
if((csd[0]&0xC0)==0x40)
{
Capacity=((u32)csd[8])<<8;
Capacity+=(u32)csd[9]+1;
Capacity = (Capacity)*1024;//得到扇區數
Capacity*=512;//得到字節數
//for(i=0;i<2;i++)printf("csd[%d]:%d\n",i+8,csd[8+i]);
}
else
{
//for(i=0;i<5;i++)printf("csd[%d]:%d\n",i+5,csd[5+i]);
i = csd[6]&0x03;
i<<=8;
i += csd[7];
i<<=2;
i += ((csd[8]&0xc0)>>6);
//C_SIZE_MULT
r1 = csd[9]&0x03;
r1<<=1;
r1 += ((csd[10]&0x80)>>7);
r1+=2;//BLOCKNR
temp = 1;
while(r1)
{
temp*=2;
r1--;
}
Capacity = ((u32)(i+1))*((u32)temp);
// READ_BL_LEN
i = csd[5]&0x0f;
//BLOCK_LEN
temp = 1;
while(i)
{
temp*=2;
i--;
}
//The final result
Capacity *= (u32)temp;//字節為單位
}
return (u32)Capacity;
}
/*******************************************************************************
* Function Name : SD_ReadSingleBlock
* Description : 讀SD卡的一個block
* Input : u32 sector 取地址(sector值,非物理地址)
* u8 *buffer 數據存儲地址(大小至少512byte)
* Output : None
* Return : u8 r1
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_ReadSingleBlock(u32 sector, u8 *buffer)
{
u8 r1;
//設置為高速模式
SPI2_SetSpeed(SPI_SPEED_HIGH);
//如果不是SDHC,將sector地址轉成byte地址
sector = sector<<9;
r1 = SD_SendCommand(CMD17, sector, 0);//讀命令
if(r1 != 0x00)return r1;
r1 = SD_ReceiveData(buffer, 512, RELEASE);
if(r1 != 0)return r1; //讀數據出錯!
else return 0;
}
/*******************************************************************************
* Function Name : SD_WriteSingleBlock
* Description : 寫入SD卡的一個block
* Input : u32 sector 扇區地址(sector值,非物理地址)
* u8 *buffer 數據存儲地址(大小至少512byte)
* Output : None
* Return : u8 r1
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_WriteSingleBlock(u32 sector, const u8 *data)
{
u8 r1;
u16 i;
u16 retry;
//設置為高速模式
SPI2_SetSpeed(SPI_SPEED_HIGH);
//如果不是SDHC,給定的是sector地址,將其轉換成byte地址
if(SD_Type!=SD_TYPE_V2HC)
{
sector = sector<<9;
}
r1 = SD_SendCommand(CMD24, sector, 0x00);
if(r1 != 0x00)
{
return r1; //應答不正確,直接返回
}
//開始準備數據傳輸
SD_CS_ENABLE();
//先放3個空數據,等待SD卡準備好
SPI2_ReadWriteByte(0xff);
SPI2_ReadWriteByte(0xff);
SPI2_ReadWriteByte(0xff);
//放起始令牌0xFE
SPI2_ReadWriteByte(0xFE);
//放一個sector的數據
for(i=0;i<512;i++)
{
SPI2_ReadWriteByte(*data++);
}
//發2個Byte的dummy CRC
SPI2_ReadWriteByte(0xff);
SPI2_ReadWriteByte(0xff);
//等待SD卡應答
r1 = SPI2_ReadWriteByte(0xff);
if((r1&0x1F)!=0x05)
{
SD_CS_DISABLE();
return r1;
}
//等待操作完成
retry = 0;
while(!SPI2_ReadWriteByte(0xff))
{
retry++;
if(retry>0xfffe) //如果長時間寫入沒有完成,報錯退出
{
SD_CS_DISABLE();
return 1; //寫入超時返回1
}
}
//寫入完成,片選置1
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xff);
return 0;
}
/*******************************************************************************
* Function Name : SD_ReadMultiBlock
* Description : 讀SD卡的多個block
* Input : u32 sector 取地址(sector值,非物理地址)
* u8 *buffer 數據存儲地址(大小至少512byte)
* u8 count 連續讀count個block
* Output : None
* Return : u8 r1
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_ReadMultiBlock(u32 sector, u8 *buffer, u8 count)
{
u8 r1;
SPI2_SetSpeed(SPI_SPEED_HIGH);//設置為高速模式
sector = sector<<9;//如果不是SDHC,將sector地址轉成byte地址
//SD_WaitReady();
//發讀多塊命令
r1 = SD_SendCommand(CMD18, sector, 0);//讀命令
if(r1 != 0x00)return r1;
do//開始接收數據
{
if(SD_ReceiveData(buffer, 512, NO_RELEASE) != 0x00)
{
break;
}
buffer += 512;
} while(--count);
//全部傳輸完畢,發送停止命令
SD_SendCommand(CMD12, 0, 0);
//釋放總線
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xFF);
if(count != 0)return count; //如果沒有傳完,返回剩余個數
else return 0;
}
/*******************************************************************************
* Function Name : SD_WriteMultiBlock
* Description : 寫入SD卡的N個block
* Input : u32 sector 扇區地址(sector值,非物理地址)
* u8 *buffer 數據存儲地址(大小至少512byte)
* u8 count 寫入的block數目
* Output : None
* Return : u8 r1
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_WriteMultiBlock(u32 sector, const u8 *data, u8 count)
{
u8 r1;
u16 i;
SPI2_SetSpeed(SPI_SPEED_HIGH);//設置為高速模式
if(SD_Type != SD_TYPE_V2HC)sector = sector<<9;//如果不是SDHC,給定的是sector地址,將其轉換成byte地址
if(SD_Type != SD_TYPE_MMC) r1 = SD_SendCommand(ACMD23, count, 0x00);//如果目標卡不是MMC卡,啟用ACMD23指令使能預擦除
r1 = SD_SendCommand(CMD25, sector, 0x00);//發多塊寫入指令
if(r1 != 0x00)return r1; //應答不正確,直接返回
SD_CS_ENABLE();//開始準備數據傳輸
SPI2_ReadWriteByte(0xff);//先放3個空數據,等待SD卡準備好
SPI2_ReadWriteByte(0xff);
//--------下面是N個sector寫入的循環部分
do
{
//放起始令牌0xFC 表明是多塊寫入
SPI2_ReadWriteByte(0xFC);
//放一個sector的數據
for(i=0;i<512;i++)
{
SPI2_ReadWriteByte(*data++);
}
//發2個Byte的dummy CRC
SPI2_ReadWriteByte(0xff);
SPI2_ReadWriteByte(0xff);
//等待SD卡應答
r1 = SPI2_ReadWriteByte(0xff);
if((r1&0x1F)!=0x05)
{
SD_CS_DISABLE(); //如果應答為報錯,則帶錯誤代碼直接退出
return r1;
}
//等待SD卡寫入完成
if(SD_WaitReady()==1)
{
SD_CS_DISABLE(); //等待SD卡寫入完成超時,直接退出報錯
return 1;
}
}while(--count);//本sector數據傳輸完成
//發結束傳輸令牌0xFD
r1 = SPI2_ReadWriteByte(0xFD);
if(r1==0x00)
{
count = 0xfe;
}
if(SD_WaitReady()) //等待準備好
{
SD_CS_DISABLE();
return 1;
}
//寫入完成,片選置1
SD_CS_DISABLE();
SPI2_ReadWriteByte(0xff);
return count; //返回count值,如果寫完則count=0,否則count=1
}
/*******************************************************************************
* Function Name : SD_Read_Bytes
* Description : 在指定扇區,從offset開始讀出bytes個字節
* Input : u32 address 扇區地址(sector值,非物理地址)
* u8 *buf 數據存儲地址(大小<=512byte)
* u16 offset 在扇區里面的偏移量
u16 bytes 要讀出的字節數
* Output : None
* Return : u8 r1
* 0: 成功
* other:失敗
*******************************************************************************/
u8 SD_Read_Bytes(unsigned long address,unsigned char *buf,unsigned int offset,unsigned int bytes)
{
u8 r1;u16 i=0;
r1=SD_SendCommand(CMD17,address<<9,0);//發送讀扇區命令
if(r1!=0x00)return r1; //應答不正確,直接返回
SD_CS_ENABLE();//選中SD卡
while (SPI2_ReadWriteByte(0xff)!= 0xFE)//直到讀取到了數據的開始頭0XFE,才繼續
{
i++;
if(i>2000)
{
SD_CS_DISABLE();//關閉SD卡
return 1;//讀取失敗
}
};
for(i=0;i<offset;i++)SPI2_ReadWriteByte(0xff);//跳過offset位
for(;i<offset+bytes;i++)*buf++=SPI2_ReadWriteByte(0xff);//讀取有用數據
for(;i<512;i++) SPI2_ReadWriteByte(0xff); //讀出剩余字節
SPI2_ReadWriteByte(0xff);//發送偽CRC碼
SPI2_ReadWriteByte(0xff);
SD_CS_DISABLE();//關閉SD卡
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -