雷龙发展 发表于 2023-12-22 17:49

基于Zynq FPGA对雷龙SD NAND的测试

<div class='showpostmsg'><h1 data-pm-slice="0 0 []" data-track="1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245" spellcheck="false">文章目录</h1>

<p data-track="246">一、SD NAND特征</p>

<p data-track="247">1.1 SD卡简介</p>

<p data-track="248">1.2 SD卡Block图</p>

<p data-track="249">二、SD卡样片</p>

<p data-track="250">三、Zynq测试平台搭建</p>

<p data-track="251">3.1 测试流程</p>

<p data-track="252">3.2 SOC搭建</p>

<p data-track="253">四、软件搭建</p>

<p data-track="254">五、测试结果</p>

<p data-track="255">六、总结</p>

<h1 data-track="256" spellcheck="false">一、SD NAND特征</h1>

<p data-track="257">1.1 SD卡简介</p>

<p data-track="258">&emsp;&emsp;雷龙的SD NAND有很多型号,在测试中使用的是CSNP4GCR01-AWM与CSNP32GCR01-AOW。芯片是基于<strong>NAND FLASH</strong>和 SD控制器实现的SD卡。具有强大的坏块管理和纠错功能,并且在意外掉电的情况下同样能保证数据的安全。</p>

<p data-track="259">&emsp;&emsp;其特点如下:</p>

<p data-track="260">接口支持SD2.0 2线或4线;</p>

<p data-track="261">电压支持:2.7V-3.6V;</p>

<p data-track="262">默认模式:可变时钟速率0 - 25MHz,高达12.5 MB/s的接口速度(使用4条并行数据线)</p>

<p data-track="263">高速模式:可变时钟速率0 - 50MHz,高达25 MB/s的接口速度(使用4条并行数据线)</p>

<p data-track="264">工作温度:-40&deg;C ~ +85&deg;C</p>

<p data-track="265">存储温度:-55&deg;C ~ +125&deg;C</p>

<p data-track="266">待机电流小于250uA</p>

<p data-track="267">修正内存字段错误;</p>

<p data-track="268">内容保护机制&mdash;&mdash;符合SDMI最高安全标准</p>

<p data-track="269">SDNAND密码保护(CMD42 - LOCK_UNLOCK)</p>

<p data-track="270">采用机械开关的写保护功能</p>

<p data-track="271">内置写保护功能(永久和临时)</p>

<p data-track="272">应用程序特定命令</p>

<p data-track="273">舒适擦除机制</p>

<p data-track="274">&emsp;&emsp;该SD卡支持SDIO读写和SPI读写,最高读写速度可达25MB/s,实际读写速度要结合MCU和接口情况实测获得。通常在简单嵌入式系统并对读写速度要求不高的情况下,会使用SPI协议进行读写。但不管使用SDIO还是SPI都需要符合相关的协议规范,才能建立相应的文件系统;</p>

<p data-track="275">1.2 SD卡Block图</p>

<p>EEWORLDIMGTK0</p>

<p data-track="276">&emsp;该SD卡封装为LGA-8;引脚分配与定义如下;在这里插入图片描述:</p>

<p>EEWORLDIMGTK1</p>

<h1 data-track="277" spellcheck="false">二、SD卡样片</h1>

<p data-track="278">&emsp;&emsp;与样片同时寄来的还有转接板,转接板将LGA-8封装的芯片转接至SD卡封装,这样只需将转接板插入SD卡卡槽即可使用。</p>

<p data-track="279">在这里插入图片描述:</p>

<p>EEWORLDIMGTK2</p>

<h1 data-track="280" spellcheck="false">三、Zynq测试平台搭建</h1>

<ul>
        <li data-track="281">&emsp;&emsp;测试平台为 Xilinx 的Zynq 7020 FPGA芯片;</li>
        <li data-track="282">&emsp;&emsp;板卡:Digilent Zybo Z7</li>
        <li data-track="283">&emsp;&emsp;Vivado版本:2018.3</li>
        <li data-track="284">&emsp;&emsp;文件系统:FATFS</li>
        <li data-track="285">&emsp;&emsp;SD卡接口:SD2.0</li>
</ul>

<p data-track="286">3.1 测试流程</p>

<p data-track="287">&emsp;&emsp;本次测试主要针对4G和32G两个不同容量的SD卡,在Zynq FPGA上搭建<strong>SD卡</strong>读写回路,从而对SD卡读写速度进行测试,并检验读写一致性;</p>

<p data-track="288">测试流程:</p>

<p data-track="289">&emsp;&emsp;进入测试程序前,首先会对SD卡初始化并初始化建立FATFS文件系统,随后进入测试SD卡测试程序,在测试程序中,会写入一定大小的文件,然后对写入文件的时间进行测量,得到写入时间;然后再将写入的文件读出,测量获得读出时间,并将读出数据与写入数据相比较,检测是否读写出错。</p>

<p data-track="290">&emsp;&emsp;通过写入时间、读出时间可计算得到写入速度、读出速度;将以上过程重复100次并打印报告。</p>

<p>EEWORLDIMGTK3</p>

<p data-track="291">3.2 SOC搭建</p>

<p data-track="292">&emsp;&emsp;硬件搭建框图如下,我们在本次系统中使用PS端的SDIO接口来驱动SD NAND芯片,并通过UART向PC打印报告;</p>

<p data-track="293">&emsp;&emsp;PL端的硬件搭建也很简单,只需一个Timer定时器来做时间测量;</p>

<p>EEWORLDIMGTK4</p>

<p data-track="294">我们直接使用Zybo板卡文件创建一个工程,工程会将Zybo具有的硬件资源配置好;</p>

<p>EEWORLDIMGTK5</p>

<p data-track="295">首先点击setting-&gt;IP-&gt;Repository-&gt;+;添加Timer IP核的路径,Timer IP核会在工程中给出;</p>

<p>EEWORLDIMGTK6</p>

<p data-track="296">&emsp;点击Create Block Design创建BD工程</p>

<p>EEWORLDIMGTK7</p>

<p data-track="297">&emsp;在创建的过程中添加Zynq 内核;</p>

<p>EEWORLDIMGTK8</p>

<p data-track="298">由于我们使用了板卡文件,所以内核IP是配置好的,我们只需稍作修改即可,如果是其他板卡,则需要自行配置DDR等配置;</p>

<p data-track="299">&emsp;&emsp;双击内核IP,点击Clock Configuration-&gt;PL Fabric Clocks,将FCLK_CLK0的时钟频率修改为100Mhz</p>

<p>EEWORLDIMGTK9</p>

<p data-track="300">&emsp;添加TimerA IP;</p>

<p>EEWORLDIMGTK10</p>

<p data-track="301">依次点击上方的自动设计,完成SOC搭建;</p>

<p>EEWORLDIMGTK11</p>

<p data-track="302">&emsp;点击BD设计,并创建顶层文件</p>

<p>EEWORLDIMGTK12</p>

<p data-track="303">生成比特流文件;</p>

<p>EEWORLDIMGTK13</p>

<p data-track="304">在生成比特流文件后,将其导入SDK;</p>

<p data-track="305">&emsp;&emsp;点击Export-&gt;Export Hardware,导出硬件;然后点击Launch SDK打开SDK进行软件设计;</p>

<p>EEWORLDIMGTK14</p>

<p>EEWORLDIMGTK15</p>

<h1 data-track="306" spellcheck="false">四、软件搭建</h1>

<p data-track="307">&emsp;&emsp;在SDK中新建一个空白工程;</p>

<p data-track="308">&emsp;&emsp;点击file -&gt; new -&gt; Application project;</p>

<p>EEWORLDIMGTK16</p>

<p data-track="309">在新建的过程中创建一个main.c文件,并在里面编写测试程序如下:</p>

<p data-track="310">&emsp;&emsp;在每次读写开始前,通过TimerA0_start()函数开始计时,在读写结束后可以通过TimerA0_stop()结束计时,从而测得消耗时间。</p>

<p data-track="311">&emsp;&emsp;相应的Timer驱动函数在user/TimerA_user.c中定义;</p>

<ol start="1">
        <li data-track="312">#include &quot;xparameters.h&quot; /* SDK generated parameters */</li>
        <li data-track="313">#include &quot;xsdps.h&quot; /* SD device driver */</li>
        <li data-track="314">#include &quot;xil_printf.h&quot;</li>
        <li data-track="315">#include &quot;ff.h&quot;</li>
        <li data-track="316">#include &quot;xil_cache.h&quot;</li>
        <li data-track="317">#include &quot;xplatform_info.h&quot;</li>
        <li data-track="318">#include &quot;time.h&quot;</li>
        <li data-track="319">#include &quot;../user/headfile.h&quot;</li>
        <li data-track="320">&nbsp;</li>
        <li data-track="321">#define PACK_LEN 32764</li>
        <li data-track="322">&nbsp;</li>
        <li data-track="323">static FIL fil; /* File object */</li>
        <li data-track="324">static FATFS fatfs;</li>
        <li data-track="325">&nbsp;</li>
        <li data-track="326">static char FileName = &quot;Test.txt&quot;;</li>
        <li data-track="327">static char *SD_File;</li>
        <li data-track="328">&nbsp;</li>
        <li data-track="329">char DestinationAddress ;</li>
        <li data-track="330">&nbsp;</li>
        <li data-track="331">char txt;</li>
        <li data-track="332">char test_buffer;</li>
        <li data-track="333">&nbsp;</li>
        <li data-track="334">void TimerA0_init()</li>
        <li data-track="335">{</li>
        <li data-track="336">TimerA_reset(TimerA0);//reset timerA device</li>
        <li data-track="337">TimerA_Set_Clock_Division(TimerA0,100);//divide clock as 100000000/100 = 1Mhz</li>
        <li data-track="338">TimerA_Stop_Counter(TimerA0);//stop timerA</li>
        <li data-track="339">}</li>
        <li data-track="340">&nbsp;</li>
        <li data-track="341">void TimerA0_start()</li>
        <li data-track="342">{</li>
        <li data-track="343">TimerA_SetAs_CONTINUS_Mode(TimerA0);</li>
        <li data-track="344">}</li>
        <li data-track="345">&nbsp;</li>
        <li data-track="346">void TimerA0_stop()</li>
        <li data-track="347">{</li>
        <li data-track="348">TimerA_Stop_Counter(TimerA0);</li>
        <li data-track="349">}</li>
        <li data-track="350">&nbsp;</li>
        <li data-track="351">&nbsp;</li>
        <li data-track="352">&nbsp;</li>
        <li data-track="353">&nbsp;</li>
        <li data-track="354">uint32 SDCard_test()</li>
        <li data-track="355">{</li>
        <li data-track="356">uint8 Res;</li>
        <li data-track="357">uint32 NumBytesRead;</li>
        <li data-track="358">uint32 NumBytesWritten;</li>
        <li data-track="359">uint32 BuffCnt;</li>
        <li data-track="360">uint8 work;</li>
        <li data-track="361">uint32 take_time=0;</li>
        <li data-track="362">uint32 speed = 0;</li>
        <li data-track="363">uint32 test_time = 0;</li>
        <li data-track="364">uint32 w_t=0;</li>
        <li data-track="365">uint32 r_t=0;</li>
        <li data-track="366">float wsum = 0;</li>
        <li data-track="367">float rsum = 0;</li>
        <li data-track="368">&nbsp;</li>
        <li data-track="369">&nbsp;</li>
        <li data-track="370">TCHAR *Path = &quot;0:/&quot;;</li>
        <li data-track="371">&nbsp;</li>
        <li data-track="372">for(int i=0;i</li>
        <li data-track="373">{</li>
        <li data-track="374">test_buffer = &#39;a&#39;;</li>
        <li data-track="375">}</li>
        <li data-track="376">&nbsp;</li>
        <li data-track="377">Res = f_mount(&amp;fatfs, Path, 0);</li>
        <li data-track="378">&nbsp;</li>
        <li data-track="379">if (Res != FR_OK) {</li>
        <li data-track="380">return XST_FAILURE;</li>
        <li data-track="381">}</li>
        <li data-track="382">&nbsp;</li>
        <li data-track="383">Res = f_mkfs(Path, FM_FAT32, 0, work, sizeof work);</li>
        <li data-track="384">if (Res != FR_OK) {</li>
        <li data-track="385">return XST_FAILURE;</li>
        <li data-track="386">}</li>
        <li data-track="387">&nbsp;</li>
        <li data-track="388">SD_File = (char *)FileName;</li>
        <li data-track="389">&nbsp;</li>
        <li data-track="390">Res = f_open(&amp;fil, SD_File, FA_CREATE_ALWAYS | FA_WRITE | FA_READ);</li>
        <li data-track="391">if (Res) {</li>
        <li data-track="392">return XST_FAILURE;</li>
        <li data-track="393">}</li>
        <li data-track="394">&nbsp;</li>
        <li data-track="395">Res = f_lseek(&amp;fil, 0);</li>
        <li data-track="396">if (Res) {</li>
        <li data-track="397">return XST_FAILURE;</li>
        <li data-track="398">}</li>
        <li data-track="399">&nbsp;</li>
        <li data-track="400">while(1)</li>
        <li data-track="401">{</li>
        <li data-track="402">TimerA_reset(TimerA0);</li>
        <li data-track="403">TimerA0_start();</li>
        <li data-track="404">Res = f_write(&amp;fil, (const void*)test_buffer, PACK_LEN,</li>
        <li data-track="405">&amp;NumBytesWritten);</li>
        <li data-track="406">TimerA0_stop();</li>
        <li data-track="407">take_time = TimerA_Read_Counter_Register(TimerA0);</li>
        <li data-track="408">w_t+=take_time;</li>
        <li data-track="409">xil_printf(&quot;--------------------------------\n&quot;);</li>
        <li data-track="410">xil_printf(&quot;take time:%d us\n&quot;,take_time);</li>
        <li data-track="411">speed = PACK_LEN*(1000000/((float)(take_time)));</li>
        <li data-track="412">sprintf(txt,&quot;write speed:%.2f MB/s\n&quot;,(float)(speed)/1024/1024);</li>
        <li data-track="413">wsum = wsum+speed;</li>
        <li data-track="414">xil_printf(txt);</li>
        <li data-track="415">xil_printf(&quot;--------------------------------\n&quot;);</li>
        <li data-track="416">if (Res) {</li>
        <li data-track="417">return XST_FAILURE;</li>
        <li data-track="418">}</li>
        <li data-track="419">&nbsp;</li>
        <li data-track="420">Res = f_lseek(&amp;fil, 0);</li>
        <li data-track="421">if (Res) {</li>
        <li data-track="422">return XST_FAILURE;</li>
        <li data-track="423">}</li>
        <li data-track="424">&nbsp;</li>
        <li data-track="425">TimerA_reset(TimerA0);</li>
        <li data-track="426">TimerA0_start();</li>
        <li data-track="427">Res = f_read(&amp;fil, (void*)DestinationAddress, PACK_LEN,</li>
        <li data-track="428">&amp;NumBytesRead);</li>
        <li data-track="429">TimerA0_stop();</li>
        <li data-track="430">take_time = TimerA_Read_Counter_Register(TimerA0);</li>
        <li data-track="431">r_t+=take_time;</li>
        <li data-track="432">xil_printf(&quot;--------------------------------\n&quot;);</li>
        <li data-track="433">xil_printf(&quot;take time:%d us\n&quot;,take_time);</li>
        <li data-track="434">speed = PACK_LEN*(1000000/((float)(take_time)));</li>
        <li data-track="435">sprintf(txt,&quot;read speed:%.2f MB/s\n&quot;,(float)(speed)/1024/1024);</li>
        <li data-track="436">rsum = rsum+speed;</li>
        <li data-track="437">xil_printf(txt);</li>
        <li data-track="438">xil_printf(&quot;--------------------------------\n&quot;);</li>
        <li data-track="439">if (Res) {</li>
        <li data-track="440">return XST_FAILURE;</li>
        <li data-track="441">}</li>
        <li data-track="442">&nbsp;</li>
        <li data-track="443">&nbsp;</li>
        <li data-track="444">for(BuffCnt = 0; BuffCnt &lt; PACK_LEN; BuffCnt++){</li>
        <li data-track="445">if(test_buffer != DestinationAddress){</li>
        <li data-track="446">xil_printf(&quot;%dno&quot;,BuffCnt);</li>
        <li data-track="447">return XST_FAILURE;</li>
        <li data-track="448">}</li>
        <li data-track="449">}</li>
        <li data-track="450">xil_printf(&quot;test num:%d data check right!\n&quot;,test_time+1);</li>
        <li data-track="451">test_time++;</li>
        <li data-track="452">if(test_time==100)</li>
        <li data-track="453">{</li>
        <li data-track="454">sprintf(txt,&quot;Total write: %.2f KB,Take time:%.2f ms, Write speed:%.2f MB/s\n&quot;,PACK_LEN*100/1024.0,w_t/100.0/1000.0,wsum/100/1024/1024);</li>
        <li data-track="455">xil_printf(txt);</li>
        <li data-track="456">sprintf(txt,&quot;Total read: %.2f KB,Take time:%.2f ms, Read speed:%.2f MB/s\n&quot;,PACK_LEN*100/1024.0,r_t/100.0/1000.0,rsum/100/1024/1024);</li>
        <li data-track="457">xil_printf(txt);</li>
        <li data-track="458">Res = f_close(&amp;fil);</li>
        <li data-track="459">if (Res) {</li>
        <li data-track="460">return XST_FAILURE;</li>
        <li data-track="461">}</li>
        <li data-track="462">return 0;</li>
        <li data-track="463">}</li>
        <li data-track="464">}</li>
        <li data-track="465">&nbsp;</li>
        <li data-track="466">}</li>
        <li data-track="467">&nbsp;</li>
        <li data-track="468">int main(void)</li>
        <li data-track="469">{</li>
        <li data-track="470">TimerA0_init();</li>
        <li data-track="471">&nbsp;</li>
        <li data-track="472">SDCard_test();</li>
        <li data-track="473">xil_printf(&quot;finish&quot;);</li>
        <li data-track="474">return 0;</li>
        <li data-track="475">}</li>
</ol>

<h1 data-track="476" spellcheck="false">五、测试结果</h1>

<p data-track="477">&emsp;&emsp;经测试,两种型号的芯片读写速度如下图表所示。</p>

<p data-track="478">&emsp;&emsp;其SD NAND的读写速度随着读写数据量的增加而增加,并且读速率大于写速率,这符合SD卡的特性;</p>

<p data-track="479">&emsp;&emsp;对比两种型号SD NAND芯片,发现CSNP32GCR01-AOW型号具有更高的读写速度;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>7</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<p>&nbsp;</p>

<div style="text-align: center;"></div>

<p>&nbsp;</p>

<h1 data-track="480" spellcheck="false">六、总结</h1>

<p data-track="481">&emsp;&emsp;本来打算拿这些样片去试试信息安全领域是否有所应用,但发现其似乎内置了复位或初始化,导致无法提取上电时的不确定值,故无法提取该SD NAND的物理不可克隆特性,所以这方面的测试无法进行;</p>

<p data-track="482">&emsp;&emsp;对于芯片正常读写的测试结果,还是很让人满意的,芯片的价格也很合理。并且LGA-8封装更适合无卡槽的嵌入式开发板设计,在一定的应用领域有着简化硬件设计、减小硬件面积的功能。</p>

<p data-track="483">&emsp;&emsp;最后贴上测试工程的链接,还迎复现实验: <a href="https://gitee.com/gewenjie_host/sd_-nand_-zynq700_test" target="_blank">https://gitee.com/gewenjie_host/sd_-nand_-zynq700_test</a></p>

<p data-track="484">&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;&mdash;</p>

<p data-track="485">【本文转载自CSDN,作者:PPRAM】</p>

<p>&nbsp;</p>
</div><script>                                        var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;"   style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
                                       
                                        if(parseInt(discuz_uid)==0){
                                                                                                (function($){
                                                        var postHeight = getTextHeight(400);
                                                        $(".showpostmsg").html($(".showpostmsg").html());
                                                        $(".showpostmsg").after(loginstr);
                                                        $(".showpostmsg").css({height:postHeight,overflow:"hidden"});
                                                })(jQuery);
                                        }                </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script>
页: [1]
查看完整版本: 基于Zynq FPGA对雷龙SD NAND的测试