原創(chuàng)聲明:
本原創(chuàng)教程由芯驛電子科技(上海)有限公司(ALINX)創(chuàng)作,版權(quán)歸本公司所有,如需轉(zhuǎn)載,需授權(quán)并注明出處(http://www.alinx.com)。
適用于板卡型號:
PGL22G/PGL12G
1. 實驗簡介
SD卡是現(xiàn)在嵌入式設(shè)備重要的存儲模塊,內(nèi)部集成了nand flash控制器,方便了主機(jī)的的管理。本實驗主要是練習(xí)對sd卡的扇區(qū)進(jìn)行讀寫,通常sd卡都有文件系統(tǒng),可以按照文件名和目錄路徑來讀寫文件,但文件系統(tǒng)非常復(fù)雜,本實驗不做講解,在后續(xù)的實驗中我們通過搜索特定的文件頭來讀特殊的文件,完成音頻播放、圖片讀取顯示等。
2. 實驗原理
2.1 硬件描述
開發(fā)板上裝有一個Micro SD卡座,FPGA通過SPI數(shù)據(jù)總線訪問Micro SD卡, SD卡座和FPGA的硬件電路連接如下:
開發(fā)板SD卡
在SD卡數(shù)據(jù)讀寫速度要求不高的情況下,選用SPI通信模式可以說是一種最佳的解決方案。因為在SPI模式下,通過四條線就可以完成所有的數(shù)據(jù)交換。本實驗將為大家介紹FPGA通過SPI總線讀寫SD卡。要完成SD卡的FPGA讀寫,用戶需要理解SD卡的命令協(xié)議。
2.1 SD卡協(xié)議簡介
SD卡的協(xié)議是一種簡單的命令/響應(yīng)的協(xié)議。全部命令由主機(jī)發(fā)起,SD卡接收到命令后并返回響應(yīng)數(shù)據(jù)。根據(jù)命令的不同,返回的數(shù)據(jù)內(nèi)容和長度也不同。SD卡命令是一個6字節(jié)組成的命令包,其中第一個字節(jié)為命令號, 命令號高位bit7和bit6為固定的“01“,其它6個bit為具體的命令號。第2個字節(jié)到第5個字節(jié)為命令參數(shù)。第6個字節(jié)為7個bit的CRC校驗加1個bit的結(jié)束位。如果在SPI模式的時候,CRC校驗位為可選。如下圖所示,Command表示命令,通常使用十進(jìn)制表示名稱,例如CMD17,這個時候Command就是十進(jìn)制的17。SD卡具體的協(xié)議本實驗不講解,可自行找相關(guān)資料學(xué)習(xí)。
SD卡對每個命令會返回一個響應(yīng),每個命令有一定的響應(yīng)格式。響應(yīng)的格式跟給它的命令號有關(guān)。在SPI模式中,有三種響應(yīng)格式:R1,R2,R3。
2.2 SD卡2.0版的初始化步驟
-
上電后延時至少74clock,等待SD卡內(nèi)部操作完成
-
片選CS低電平選中SD卡
-
發(fā)送CMD0,需要返回0x01,進(jìn)入Idle狀態(tài)
-
為了區(qū)別SD卡是2.0還是1.0,或是MMC卡,這里根據(jù)協(xié)議向上兼容的,首先發(fā)送只有SD2.0才有的命令CMD8,如果CMD8返回?zé)o錯誤,則初步判斷為2.0卡,進(jìn)一步循環(huán)發(fā)送命令CMD55+ACMD41,直到返回0x00,確定SD2.0卡
-
如果CMD8返回錯誤則判斷為1.0卡還是MMC卡,循環(huán)發(fā)送CMD55+ACMD41,返回?zé)o錯誤,則為SD1.0卡,到此SD1.0卡初始成功,如果在一定的循環(huán)次數(shù)下,返回為錯誤,則進(jìn)一步發(fā)送CMD1進(jìn)行初始化,如果返回?zé)o錯誤,則確定為MMC卡,如果在一定的次數(shù)下,返回為錯誤,則不能識別該卡,初始化結(jié)束。(通過CMD16可以改變SD卡一次性讀寫的長度)
6. CS拉高
2.3 SD卡的讀步驟
-
發(fā)送CMD17(單塊)或CMD18(多塊)讀命令,返回0X00
-
接收數(shù)據(jù)開始令牌fe(或fc)+正式數(shù)據(jù)512Bytes + CRC校驗2Bytes
默認(rèn)正式傳輸?shù)臄?shù)據(jù)長度是512Bytes
2.4 SD卡的寫步驟
-
發(fā)送CMD24(單塊)或CMD25(多塊)寫命令,返回0X00
-
發(fā)送數(shù)據(jù)開始令牌fe(或fc)+正式數(shù)據(jù)512Bytes + CRC校驗2Bytes
3. 程序設(shè)計
下面主要對sd_card_top及其子程序進(jìn)行介紹和說明。sd_card_top包含3個子程序,分別為sd_card_sec_read_write.v,sd_card_cmd.v和spi_master.v文件。它們的邏輯關(guān)系如下圖所示:
3.1 sd_card_sec_read_write
以下為sd_card_sec_read_write模塊端口說明:
信號名稱 | 方向 | 說明 |
clk | in | 時鐘輸入 |
rst | in | 異步復(fù)位輸入,高復(fù)位 |
sd_init_done | out | sd卡初始化完成 |
sd_sec_read | in | sd卡扇區(qū)讀請求 |
sd_sec_read_addr | in | sd卡扇區(qū)讀地址 |
sd_sec_read_data | out | sd卡扇區(qū)讀出的數(shù)據(jù) |
sd_sec_read_data_valid | out | sd卡扇區(qū)讀出的數(shù)據(jù)有效 |
sd_sec_read_end | out | sd卡扇區(qū)讀完成 |
sd_sec_write | in | sd卡扇區(qū)寫請求 |
sd_sec_write_addr | in | sd卡扇區(qū)寫請求應(yīng)答 |
sd_sec_write_data | in | sd卡扇區(qū)寫請求數(shù)據(jù) |
sd_sec_write_data_req | out | sd卡扇區(qū)寫請求數(shù)據(jù)讀取,提前sd_sec_write_data一個時鐘周期 |
sd_sec_write_end | out | sd卡扇區(qū)寫請求完成 |
spi_clk_div | in | SPI時鐘分頻,SPI時鐘頻率=系統(tǒng)時鐘/(( spi_clk_div + 2)*2) |
cmd_req | in | sd卡命令請求 |
cmd_req_ack | out | sd卡命令請求應(yīng)答 |
cmd_req_error | out | sd卡命令請求錯誤 |
cmd | in | sd卡命令,命令+參數(shù)+CRC,一共48bit |
cmd_r1 | in | sd卡命令期待的R1響應(yīng) |
cmd_data_len | in | sd卡命令后讀取的數(shù)據(jù)長度,大部分命令沒有讀取數(shù)據(jù) |
block_read_req | in | 塊數(shù)據(jù)讀取請求 |
block_read_valid | out | 塊數(shù)據(jù)讀取數(shù)據(jù)有效 |
block_read_data | out | 塊數(shù)據(jù)讀取數(shù)據(jù) |
block_read_req_ack | out | 塊數(shù)據(jù)讀取請求應(yīng)答 |
block_write_req | in | 塊數(shù)據(jù)寫請求 |
block_write_data | in | 塊數(shù)據(jù)寫數(shù)據(jù) |
block_write_data_rd | out | 塊數(shù)據(jù)寫數(shù)據(jù)請求,提前block_write_data一個時鐘周期 |
block_write_req_ack | out | 塊數(shù)據(jù)寫請求應(yīng)答 |
sd_card_sec_read_write模塊有一個狀態(tài)機(jī),首先完成SD卡初始化,下圖為模塊的初始化狀態(tài)機(jī)轉(zhuǎn)換圖,首先發(fā)送CMD0命令,然后發(fā)送CMD8命令,再發(fā)送CMD55,接著發(fā)送ACMD41和CMD16。如果應(yīng)答正常,sd卡初始化完成,等待SD卡扇區(qū)的讀寫命令。
然后等待扇區(qū)讀寫指令,并完成扇區(qū)的讀寫操作,下圖為模塊的讀寫狀態(tài)機(jī)轉(zhuǎn)換圖。
在此模塊中定義了兩個參數(shù),SD卡的初始化過程是需要先用慢時鐘來發(fā)送命令和配置,等待初始化成功后再用快時鐘來進(jìn)行數(shù)據(jù)讀寫。
parameter SPI_LOW_SPEED_DIV = 248 parameter SPI_HIGH_SPEED_DIV = 0 |
3.2 sd_card_cmd
sd_card_cmd模塊端口的說明如下:
信號名稱 | 方向 | 說明 |
sys_clk | in | 時鐘輸入 |
rst | in | 異步復(fù)位輸入,高復(fù)位 |
spi_clk_div | in | SPI時鐘分頻,SPI時鐘頻率=系統(tǒng)時鐘/(( spi_clk_div + 2)*2) |
cmd_req | in | sd卡命令請求 |
cmd_req_ack | out | sd卡命令請求應(yīng)答 |
cmd_req_error | out | sd卡命令請求錯誤 |
cmd | in | sd卡命令,命令+參數(shù)+CRC,一共48bit |
cmd_r1 | in | sd卡命令期待的R1響應(yīng) |
cmd_data_len | in | sd卡命令后讀取的數(shù)據(jù)長度,大部分命令沒有讀取數(shù)據(jù) |
block_read_req | in | 塊數(shù)據(jù)讀取請求 |
block_read_valid | out | 塊數(shù)據(jù)讀取數(shù)據(jù)有效 |
block_read_data | out | 塊數(shù)據(jù)讀取數(shù)據(jù) |
block_read_req_ack | out | 塊數(shù)據(jù)讀取請求應(yīng)答 |
block_write_req | in | 塊數(shù)據(jù)寫請求 |
block_write_data | in | 塊數(shù)據(jù)寫數(shù)據(jù) |
block_write_data_rd | out | 塊數(shù)據(jù)寫數(shù)據(jù)請求,提前block_write_data一個時鐘周期 |
block_write_req_ack | out | 塊數(shù)據(jù)寫請求應(yīng)答 |
nCS_ctrl | out | 到SPI master控制器,cs片選控制 |
clk_div | out | 到SPI Master控制器,時鐘分頻參數(shù) |
spi_wr_req | out | 到SPI Master控制器,寫一個字節(jié)請求 |
spi_wr_ack | in | 來自SPI Master控制器,寫請求應(yīng)答 |
spi_data_in | out | 到SPI Master控制器,寫數(shù)據(jù) |
spi_data_out | in | 來自SPI Master控制器,讀數(shù)據(jù) |
sd_card_cmd模塊主要實現(xiàn)sd卡基本命令操作,還有上電初始化的88個周期的時鐘,數(shù)據(jù)塊的命令和讀寫的狀態(tài)機(jī)如下。
從SD2.0的標(biāo)準(zhǔn)里我們可以看到,從主控設(shè)備寫命令到SD卡, 最高兩位47~46位必須為“01”,代表命令發(fā)送開始。
所以代碼中都是將48位命令的高八位與十六進(jìn)制0x40做或操作得到的結(jié)果再寫入,所以才有了如下一段代碼:
3.3 spi_master
spi_master模塊主要完成SPI一個字節(jié)的讀寫,當(dāng)SPI狀態(tài)機(jī)在idle的時候,檢測到wr_req的信號為高,會產(chǎn)生8個DCLK,并把datain的數(shù)據(jù)從高位依次輸出到MOSI信號線上。MOSI在8個DCLK的輸出數(shù)據(jù)為datain的值0x58。
同時spi_master程序也會讀取MISO輸入的數(shù)據(jù),轉(zhuǎn)換成8位的data_out數(shù)據(jù)輸出實現(xiàn)SPI的一個字節(jié)的數(shù)據(jù)讀取。
4. 實驗現(xiàn)象
下載實驗程序后,可以看到LED顯示一個二進(jìn)制數(shù)字,這個數(shù)字是存儲在sd卡中第一扇區(qū)的第一個數(shù)據(jù),數(shù)據(jù)是隨機(jī)的,這個時候按鍵KEY2按下,數(shù)字加一,并寫入了sd卡,再次下載程序,可以看到直接顯示更新后的數(shù)據(jù)。
開發(fā)板
-
FPGA
+關(guān)注
關(guān)注
1620文章
21510瀏覽量
598875 -
嵌入式
+關(guān)注
關(guān)注
5045文章
18816瀏覽量
298445 -
SD卡
+關(guān)注
關(guān)注
2文章
552瀏覽量
63511 -
SPI
+關(guān)注
關(guān)注
17文章
1666瀏覽量
90715 -
紫光同創(chuàng)
+關(guān)注
關(guān)注
5文章
78瀏覽量
27445
發(fā)布評論請先 登錄
相關(guān)推薦
評論