• 沒有找到結果。

SD Bus 模式的資料傳輸

第三章 SD 記憶卡

Card is lock Set when the card is locked by the user. Reset when it is unlocked

3.3 SD Bus 傳輸模式

3.3.4 SD Bus 模式的資料傳輸

由於SD 記憶卡在特定時間內只能有一個卡可以為傳輸狀態,因此命令 CMD7 被使用來選擇特定的 SD 記憶卡,使它處於傳輸狀態下。如果上次選 擇的SD 記憶卡還處於傳輸狀態,則其與主裝置的連線會被釋放,且會回到 待機狀態。當主裝置發出RCA 位址為“0x0000"的 CMD7 命令時,所有的 SD 記憶卡都會返回待機狀態 [6],圖 3-44 為 SD 記憶卡的資料傳輸模式流 程圖。

圖 3-44 資料傳輸模式狀態圖 [6]

單區塊資料讀取 (CMD17 與 CMD18)

SD Bus 傳輸模式的讀取資料命令有 CMD17 與 CMD18 兩個,CMD17 READ_SINGLE_BLOCK)為啟動單次讀取數據塊的運作,在傳輸結束後記 憶卡回到等待狀態。CMD18 (READ_MULTIPLE_BLOCK)則是啟動多個數 據塊的讀取運作。CMD17 與 CMD18 的操作時序如圖 3-45,主裝置在 CMD 訊號線發送命令與接收回應,其中任何時候發送CMD12 停止傳輸命令即可 中止多個數據塊讀取的運作。

圖 3-45 SD bus 讀取數據塊操作時序 [4]

圖 3-46 為 SD Bus 的單一區塊資料讀取的範例程序,首先清除資料通 道狀態機(DPSM),再使用 CMD16(SET_BLOCKLEN)命令來設定區塊容 量,接著設定 SDIO 模組的資料通道狀態機(DPSM),最後下達 CMD17 (READ SINGLE BLOCK)命令,並接收一個區塊大小的資料。當資料接收完 成以後,檢查SDIO_STA 暫存器的各個旗標,來判斷接收資料的正確性。

程式名稱:SD_ReadBlock ( )

功能敘述:SD Bus 模式讀取單個區塊資料

輸 入:u32 addr,u32 *readbuff,u16 BlockSize 輸 出:錯誤狀態訊息 

SD_Error SD_ReadBlock(u32 addr, u32 *readbuff, u16 BlockSize) { SD_Error errorstatus = SD_OK;

u32 count = 0, *tempbuff = readbuff;

u8 power = 0;

if (NULL == readbuff)

{ errorstatus = SD_INVALID_PARAMETER;

return(errorstatus); }

SDIO_DPSM_Setup_Value(&SDIO_DataInitStructure, 0x00, 1, ToCard, Disable); // 清除 DPSM 設定 SDIO_DataConfig(&SDIO_DataInitStructure);

SDIO_DMACmd(DISABLE);

if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED) { errorstatus = SD_LOCK_UNLOCK_FAILED;

return(errorstatus); }

if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0)) { power = convert_from_bytes_to_power_of_two(BlockSize);

if (errorstatus != SD_OK) { return(errorstatus); } // 檢查命令回應 } else

{ errorstatus = SD_INVALID_PARAMETER;

return(errorstatus); }

SDIO_DPSM_Setup_Value(&SDIO_DataInitStructure, BlockSize, (power<<4), ToSDIO, Enable);

SDIO_DataConfig(&SDIO_DataInitStructure); // 設定 DPSM SDIO_CMD (CMD17, addr, RESP_S, Enable); // 發送 CMD17 errorstatus = CmdResp1Error(SDIO_READ_SINGLE_BLOCK);

if (errorstatus != SD_OK) { return(errorstatus); } // 檢查命令回應 if (DeviceMode == SD_POLLING_MODE)

{ while (!(SDIO->STA &(SDIO_FLAG_RXOVERR | SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_DBCKEND | SDIO_FLAG_STBITERR))) { if (SDIO_GetFlagStatus(SDIO_FLAG_RXFIFOHF) != RESET)

{ for (count = 0; count < 8; count++)

*(tempbuff + count) = SDIO_ReadData();

tempbuff += 8;

} }

if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET) return (errorstatus);

while (SDIO_GetFlagStatus(SDIO_FLAG_RXDAVL) != RESET) { *tempbuff = SDIO_ReadData();

tempbuff++; }

SDIO_ClearFlag(SDIO_STATIC_FLAGS); // Clear all the static flags }

else if (DeviceMode == SD_DMA_MODE)

{ SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_RXOVERR | SDIO_IT_STBITERR, ENABLE);

SDIO_DMACmd(ENABLE);

DMA_RxConfiguration(readbuff, BlockSize);

while (DMA_GetFlagStatus(DMA2_FLAG_TC4) == RESET) {}

}

return(errorstatus);

圖 3-46 SD bus 讀取資料磁區副程式

區塊資料寫入 (CMD24 與 CMD25)

SDIO 在寫入資料模式下是由寫資料塊命令(CMD24-27)來執行,圖 3-47 為寫入資料磁區的操作時序,主裝置把一個或多個資料區塊傳送到記憶卡 中,同時在每個資料區塊的尾端傳送 16 位元的 CRC 碼,資料區塊的大小 一樣由 CMD16 來設定。如果在寫入資料塊時發生 CRC 校驗錯誤,此時記 憶卡會通過SDIO_DAT0 訊號線返回錯誤狀態,而傳送的資料被丟棄不被寫 入,所有後續(在多區塊寫入模式)傳送的資料塊將被忽略。

圖 3-47 SD bus 寫入資料磁區操作時序 [4]

圖 3-48 為 SD Bus 的單一區塊資料寫入的範常式,首先清除資料通道 狀態機(DPSM),再使用 CMD16(SET_BLOCKLEN)命令來設定區塊大小,

然後用 CMD13(SEND_STATUS)確認記憶卡狀態,接著為 CMD24 (WRITE SINGLE BLOCK)命令,當記憶卡正確回應後,設定資料通道狀態 (DPSM),然後就可傳遞一個區塊大小的資料給記憶卡。當資料傳遞完成以 後,檢查SDIO_STA 暫存器的各個旗標,來判斷傳遞資料的正確性。

程式名稱:SD_WriteBlock ( )

功能敘述:SD Bus 模式寫入單個區塊資料

輸 入:u32 addr,u32 *writebuff,u16 BlockSize 輸 出:錯誤狀態訊息 

SD_Error SD_WriteBlock(u32 addr, u32 *writebuff, u16 BlockSize)

u32 timeout = 0, bytestransferred = 0;

cardstatus = 0, count = 0, restwords = 0; *tempbuff = writebuff;

if (writebuff == NULL)

{ errorstatus = SD_INVALID_PARAMETER; return(errorstatus); } TransferError = SD_OK; TransferEnd = 0; TotalNumberOfBytes = 0;

SDIO_DPSM_Setup_Value(&SDIO_DataInitStructure, 0, 1, ToCard, Disable);

SDIO_DataConfig(&SDIO_DataInitStructure);

SDIO_DMACmd(DISABLE);

if (SDIO_GetResponse(SDIO_RESP1) & SD_CARD_LOCKED)

{ errorstatus = SD_LOCK_UNLOCK_FAILED; return(errorstatus); } if (CardType == SDIO_HIGH_CAPACITY_SD_CARD)

{ BlockSize = 512; addr /= 512; }

if ((BlockSize > 0) && (BlockSize <= 2048) && ((BlockSize & (BlockSize - 1)) == 0)) { power = convert_from_bytes_to_power_of_two(BlockSize);

SDIO_CMD (CMD16, BlockSize, RESP_S, Enable); // 發送 CMD16 errorstatus = CmdResp1Error(SDIO_SET_BLOCKLEN);

if (errorstatus != SD_OK) { return(errorstatus); } // 檢查命令回應 } else

{ errorstatus = SD_INVALID_PARAMETER; return(errorstatus); } timeout = SD_DATATIMEOUT;

do { timeout--;

SDIO_CMD (CMD?, (RCA<<16), RESP_S, Enable); // 發送 CMD?

errorstatus = CmdResp1Error(SDIO_SEND_STATUS);

if (errorstatus != SD_OK) { return(errorstatus); } // 檢查命令回應 cardstatus = SDIO_GetResponse(SDIO_RESP1);

} while (((cardstatus & 0x00000100) == 0) && (timeout > 0));

if (timeout == 0) { return(SD_ERROR); }

SDIO_CMD (CMD24, addr, RESP_S, Enable); // 發送 CMD24 errorstatus = CmdResp1Error(SDIO_WRITE_SINGLE_BLOCK);

if (errorstatus != SD_OK) { return(errorstatus); } // 檢查命令回應 TotalNumberOfBytes = BlockSize; StopCondition = 0; SrcBuffer = writebuff;

SDIO_DPSM_Setup_Value(&SDIO_DataInitStructure, BlockSize, (power<<4), ToCard, Enable);

SDIO_DataConfig(&SDIO_DataInitStructure);

if (DeviceMode == SD_POLLING_MODE)

{ while (!(SDIO->STA & (SDIO_FLAG_DBCKEND | SDIO_FLAG_TXUNDERR |

SDIO_FLAG_DCRCFAIL | SDIO_FLAG_DTIMEOUT | SDIO_FLAG_STBITERR))) { if (SDIO_GetFlagStatus(SDIO_FLAG_TXFIFOHE) != RESET)

{ if ((TotalNumberOfBytes - bytestransferred) < 32)

{ restwords = ((TotalNumberOfBytes - bytestransferred) % 4 == 0) ?

if (SDIO_GetFlagStatus(SDIO_FLAG_DTIMEOUT) != RESET)

{ errorstatus = SD_DATA_TIMEOUT; return(errorstatus); } } else if (DeviceMode == SD_INTERRUPT_MODE)

{ SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_FLAG_TXFIFOHE | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);

while ((TransferEnd == 0) && (TransferError == SD_OK)) {}

if (TransferError != SD_OK) { return(TransferError); } } else if (DeviceMode == SD_DMA_MODE)

{ SDIO_ITConfig(SDIO_IT_DCRCFAIL | SDIO_IT_DTIMEOUT | SDIO_IT_DATAEND | SDIO_IT_TXUNDERR | SDIO_IT_STBITERR, ENABLE);

DMA_TxConfiguration(writebuff, BlockSize);

SDIO_DMACmd(ENABLE);

while (DMA_GetFlagStatus(DMA2_FLAG_TC4) == RESET) {}

while ((TransferEnd == 0) && (TransferError == SD_OK)) {}

if (TransferError != SD_OK) { return(TransferError); } }

SDIO_ClearFlag(SDIO_STATIC_FLAGS); /* Clear all the static flags */

errorstatus = IsCardProgramming(&cardstate); /* Wait till the card is in programming state */

while ((errorstatus == SD_OK) && ((cardstate == SD_CARD_PROGRAMMING) ||

(cardstate == SD_CARD_RECEIVING))) { errorstatus = IsCardProgramming(&cardstate); } return(errorstatus);

圖 3-48 SD bus 寫入資料磁區副程式

相關文件