在FPGA上實現SD卡連續多塊讀的命令
CMD17命令一次只能讀取1個塊
CMD18命令一次可以連續讀取多個塊,直到停止命令CMD12
CMD18命令讀的塊數程序可任意設置
目錄
前言
一、SD卡多塊讀命令CMD18
二、停止讀命令CMD12
三、SD卡初始化+SD卡連續塊讀操作的verilog代碼
總結
前言
? ? ? ? 在用FPGA驅動LCD顯示屏播放視頻時,視頻數據是存到SD卡里面的,播放視頻對數據量的讀需求非常大。如果用單塊讀CMD17命令顯然無法滿足我屏幕320*320的分辨率單像素16bit 24幀的需求,因為實測發現SD卡每次發單塊讀CMD17命令后,中間都要等很長一段時間,SD卡才會開始返回數據,這個等的時間比返回512個字節的時間還要多。所以得發送CMD18命令,改命令發一次可以連續讀取多個塊,直到發送停止命令CMD12,SD卡停止讀,這樣方可滿足播放視頻的需求。以下內容是對SD卡連續多塊讀操作的說明,同時也給出了相應的時序波形圖,方便理解。
提示:以下是本篇文章正文內容,均為作者本人原創,寫文章實屬不易,希望各位在引用時附上本文鏈接。
一、SD卡多塊讀命令CMD18
? ? ? ? 關于SD的初始化,單塊讀寫操作見文章,基于FPGA的SD卡音樂播放器之SD卡篇_sdio verilog-CSDN博客本文不再敘述。
CMD18命令芯片手冊描述如下:
可見,發一次命令返回多個塊,發送CMD18命令格式如下:
cmd_rd <= {8'h52,rd_sec_addr_buf,8'hff}; ? ?//寫入連續讀多個快CMD18
其中rd_sec_addr_buf是讀的32位起始扇區地址,由于SD卡在SPI模式下默認不開啟CRC校驗,所以校驗字節直接填的8'hff。發完命令后等8bit R1的響應,正常情況下響應的8bit為全0,然后準備開始解析SD卡返回的數據頭0xfe, 解析到數據頭0xfe后,接下來接收SD卡返回的512個字節的數據,緊接著又會有下一塊,依然是先解析到數據頭0xfe后,再接收SD卡返回的512個字節的數據,如此循環直到發送CMD12這個停止命令。由此可見一次讀多少個塊是由主機什么時候發停止命令決定的。為了方便,我在編程的時候定義了一個參數,即一次連續讀多少個塊,讀夠后即發送停止命令,該參數可隨意設置,設置成1就和單塊讀沒區別。
該命令的實測波形圖如下,注意由于MISO下降沿穩定,所以ILA抓取時注意用clk的下降沿取抓數據。
觀察這張波形圖,就能明白為什么我開始說的發命令后等的時間比返回512個字節的時間還要多了。放大發命令的部分如下圖所示,可見發完命令后,SD卡會返回R1數據8‘h00。
返回數據部分放大如下:
下面是抓取的解析后的數據,解析時是每兩個字節湊成16bit,和winhex中的數據完全對得上。
下圖是兩個塊交界處的時序,可見第一個塊數據返回完后,會接著有兩字節的CRC,然后又去解析FE,之后便是下一個塊的數據。
可見塊連續讀,一個塊的數據返回完后,過24個CLK(圖中9793-9769,2個FF+1個FE)就會接著返回下一個塊的數據,比單塊讀效率高多了。
二、停止讀命令CMD12
CMD12命令芯片手冊描述如下:
R1b和R1類似,只是其帶有忙信號。發送CMD18命令格式如下:
cmd_rd <= {8'h4C,32'b0,8'hff}; ? ?//停止讀命令CMD12
parameter RD_BLOCKS = 20'd400; ? ? //SD卡連讀讀一次的塊數
我在程序中定義了SD卡連讀讀一次的塊數,支持修改為任意值,這里400是因為320*320的16bit像素一幀需要連續讀400個塊的數據。
三、SD卡初始化+SD卡連續塊讀操作的verilog代碼
????????代碼已經完成了SD卡的初始化,設置RD_BLOCKS后,連續讀只需要將sd_rd_start_en拉高一個電平,在電平拉高的同時,給sd_rd_sec_addr復制塊讀開始讀的扇區地址后,接下來sd_rd_val_en和sd_rd_val_data就會返回數據,其中sd_rd_val_en是是數據有效標志。
sd_ctrl_top
#(
? ? .RD_BLOCKS(RD_BLOCKS)
)
u_sd_ctrl_top(
? ? .clk_ref ? ? ? ? ? (clk),
? ? .clk_ref_180deg ? ?(!clk),
? ? .rst_n ? ? ? ? ? ? (rst_n),
? ? //SD卡接口
? ? .sd_miso ? ? ? ? ? (sd_miso),
? ? .sd_clk ? ? ? ? ? ?(sd_clk),
? ? .sd_cs ? ? ? ? ? ? (sd_cs),
? ? .sd_mosi ? ? ? ? ? (sd_mosi),
? ? //用戶讀SD卡接口
? ? .rd_start_en ? ? ? (sd_rd_start_en),
? ? .rd_sec_addr ? ? ? (sd_rd_sec_addr),
? ? .rd_busy ? ? ? ? ? (sd_rd_busy),
? ? .rd_val_en ? ? ? ? (sd_rd_val_en),
? ? .rd_val_data ? ? ? (sd_rd_val_data), ? ?
? ?
? ? .sd_init_done ? ? ?(sd_init_done)
);
?? ? ? ?https://download.csdn.net/download/m0_66360845/90601476https://download.csdn.net/download/m0_66360845/90601476?
總結
? ? ? ? 以上就是本文全部內容,給出了每個步驟的時序圖,對理解塊讀操作很有幫助。寫這篇文章的目的一是為了分享知識,二是為了記錄實現方法,方便自己回顧。