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