怀揣少年梦 发表于 2021-12-28 13:54

【国产FPGA高云GW1N-4系列开发板测评】FLASH操作

本帖最后由 怀揣少年梦 于 2021-12-28 14:12 编辑

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">一、目的</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">使用高云</font><font face="Calibri">GW1N-4</font><font face="宋体">系列开发板</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">来</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">擦除、页写</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">FLASH</font><font face="宋体">,</font><font face="Calibri">FLASH</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">使用的</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">型号为</font><font face="Calibri">W25Q</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">64JV</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">。</font></span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">二、</font><font face="Calibri">W25Q64JVSSIQ</font><font face="宋体">的特征</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">1</font><font face="宋体">、</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">支持</font><font face="Calibri">3</font><font face="宋体">种通信方式,</font><font face="Calibri">SPI</font><font face="宋体">、</font><font face="Calibri">Dual SPI</font><font face="宋体">和</font><font face="Calibri">Quad SPI</font><font face="宋体">。</font><font face="Calibri">FLASH</font><font face="宋体">的存储单元无法写入</font><font face="Calibri">bit 1</font><font face="宋体">,只能写入</font><font face="Calibri">bit 0</font><font face="宋体">,所以写入数据之前要将原来的数据擦除(</font><font face="Calibri">FFh</font><font face="宋体">),遇到写入</font><font face="Calibri">bit 1</font><font face="宋体">的情况不作处理。</font><font face="Calibri">W25QQ</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">64JV</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">的特征为如下图所示</font></span></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">:</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify">&nbsp;</p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">2</font><font face="宋体">、</font><font face="Calibri">FLASH</font><font face="宋体">的存储结构</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">W25Q64JV </font><font face="宋体">由</font><font face="Calibri">Block0~Block127</font><font face="宋体">共</font><font face="Calibri">128</font><font face="宋体">个</font><font face="Calibri">Block</font><font face="宋体">组成,容量大小为</font><font face="Calibri">64M-bit,</font><font face="宋体">即</font><font face="Calibri">64M=128*64*1024*8bit/1024/1024</font><font face="宋体">。每个</font><font face="Calibri">Block</font><font face="宋体">由</font><font face="Calibri">Sector0~Sector15</font><font face="宋体">共</font><font face="Calibri">16</font><font face="宋体">个</font><font face="Calibri">Sector</font><font face="宋体">组成,每个</font><font face="Calibri">Sector</font><font face="宋体">大小为</font><font face="Calibri">4KB</font><font face="宋体">,由</font><font face="Calibri">16</font><font face="宋体">个</font><font face="Calibri">Page</font><font face="宋体">组成。以第一个</font><font face="Calibri">Sector</font><font face="宋体">为例,第</font><font face="Calibri">1</font><font face="宋体">个</font><font face="Calibri">Page</font><font face="宋体">地址从</font><font face="Calibri">xx0000h~xx00FF</font><font face="宋体">开始,第</font><font face="Calibri">2</font><font face="宋体">个</font><font face="Calibri">Page</font><font face="宋体">地址从</font><font face="Calibri">xx0100~xx01FF</font><font face="宋体">开始,第</font><font face="Calibri">3</font><font face="宋体">个</font><font face="Calibri">Page</font><font face="宋体">地址从</font><font face="Calibri">xx0200~xx02FF</font><font face="宋体">开始,以此类推</font><font face="Calibri">...</font><font face="宋体">,第</font><font face="Calibri">16</font><font face="宋体">个</font><font face="Calibri">Page</font><font face="宋体">地址从</font><font face="Calibri">xx0F00~xx0FFF</font><font face="宋体">开始。每个</font><font face="Calibri">Page</font><font face="宋体">的大小为</font><font face="Calibri">256</font><font face="宋体">个</font><font face="Calibri">Byte</font><font face="宋体">组成,后面会看到</font><font face="Calibri">Page Programd</font><font face="宋体">最大支持</font><font face="Calibri">256</font><font face="宋体">个</font><font face="Calibri">Byte</font><font face="宋体">。说明框图如下:</font></span></span></span></span></p>

<p style="text-align:justify">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</p>

<ol start="3"><br />
        <li><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">FLASH</font><font face="宋体">的相关操作时序图</font></span></span></span></span></li>
</ol>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">1</font><font face="宋体">)写使能时序</font></span></span></span></span><br />
</p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">2</font><font face="宋体">)全擦除时序</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">3</font><font face="宋体">)页写时序</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">根据以上的时序绘制波形图,也就是</font><font face="Calibri">SPI</font><font face="宋体">模拟时序波形图。因为</font><font face="Calibri">FPGA</font><font face="宋体">时钟</font><font face="Calibri">50MHz</font><font face="宋体">,所以把</font><font face="Calibri">50M</font><font face="宋体">进行四分频,并且</font><font face="Calibri">32</font><font face="宋体">个时钟周期延时</font><font face="Calibri">640ns</font><font face="宋体">。正好可以作为两次数据间隔的延时周期。</font></span></span></span></span></p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">三、程序编写</font></span></span></span></span></p>

<p align="justify" style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="text-justify:inter-ideograph"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">1、全擦除程序</font></span></span></span></span></span></p>

<p align="justify" style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="text-justify:inter-ideograph"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">1)全擦除波形图绘制</font></span></span></span></span></span></p>

<p align="justify" style="text-indent:21.0000pt; text-align:justify"></p>

<p align="justify" style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="text-justify:inter-ideograph"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">2)编写代码</font></span></span></span></span></span></p>

<pre>
<code>//`timescale  1ns/1ns
/*
Module Name   : flash_ce
Project Name  : flash
Description   : flash全擦除模块
把主时钟四分频成12.5MHz,作为spi的输入时钟。
写一次数据与下一次数据之间必须等待50ns,每个时钟周期只能写入1bit数据,写一个字节即需要8个spi时钟周期,即32个系统时钟周期,说明一条完整指令需要640ns

*/

module flash_ce(
    input wire sys_clk,      //系统时钟,频率50MHz         
    input wire sys_rst_n,    //复位信号,低电平有效
    input wire key,          //按键输入信号

    output reg spi_cs_n,    //片选信号           
    output reg spi_clk,     //串行时钟           
    output reg spi_mosi     //主输出从输入数据  
);



//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter   IDLE    =   4'b0001 ,   //初始状态 状态机四个状态
            WR_EN   =   4'b0010 ,   //写状态
            DELAY   =   4'b0100 ,   //等待状态
            CE      =   4'b1000 ;   //全擦除状态
parameter   WR_EN_INST  =   8'b0000_0110,   //写使能指令  06
            CE_INST     =   8'b1100_0111;   //全擦除指令  C7



//reg   define
reg        cnt_byte;   //字节计数器   记录输出字节个数和等待时间
reg        state   ;   //状态机状态
reg        cnt_clk ;   //系统时钟计数器,用以记录单子字节
reg        cnt_sck ;   //串行时钟计数器,生成系统时钟
reg        cnt_bit ;   //比特计数器,产生高低位,控制MOSI输出

//除了在空闲状态,其他状态都进行系统时钟计数器,如果只使用cnt_clk作为状态跳转的约束条件不充分,
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        cnt_clk &lt;= 5'd0;
    else if(state != IDLE)
        cnt_clk &lt;= cnt_clk + 1'b1;
end

//由于状态跳转的约束条件不充分,所以使用cnt_byte 计数器对cnt_clk的计数周期进行计数,同时使用cnt_byte增加一次表示延时640ns
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        cnt_byte &lt;= 3'd0;
    else if((cnt_clk == 5'd31) &amp;&amp; (cnt_byte == 3'd6))//当写完擦除指令后,等待640ns,片选拉高,此时cnt_byte = 6,并且刚好cnt_clk进行一个计数循环,就清零
        cnt_byte &lt;= 3'd0;
    else if(cnt_clk == 5'd31)//cnt_clk每完成一个循环周期cnt_byte就加1,其他不变
        cnt_byte &lt;= cnt_byte + 1'b1;
end

//在进行写使能指令以及全擦除指令,并且已经发送一个字节时,记录系统时钟的个数
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        cnt_sck &lt;= 2'd0;
    else if((state == WR_EN) &amp;&amp; (cnt_byte == 1'b1)) // 当进行写使能时,先等待640ns,即cnt_byte =1
        cnt_sck &lt;= cnt_sck + 1'b1;
    else if((state == CE) &amp;&amp; (cnt_byte == 3'd5)) //当写完使能信号,等待640ns,再片选拉高,继续等待640ns,再片选拉低,继续等待640ns,此时cnt_byte =5,此时又开始写擦除指令
        cnt_sck &lt;= cnt_sck + 1'b1;
end

//进行四分频,产生12.5MHz时钟.根据cnt_sck 记录系统时钟的个数,2个cnt_sck为低,2个cnt_sck为高
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        spi_clk &lt;= 1'b0;
    else if(cnt_sck == 2'd0)
        spi_clk &lt;= 1'b0;
    else if(cnt_sck == 2'd2)
        spi_clk &lt;= 1'b1;

end

//片选信号输出
always@(posedge sys_clk or negedge sys_rst_n)
begin
    if(!sys_rst_n)
        spi_cs_n &lt;= 1;
    else if(key == 1'b1)
        spi_cs_n &lt;= 0;
    else if((cnt_byte == 3'd2) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == WR_EN))
        spi_cs_n &lt;= 1;
    else if((cnt_byte == 3'd3) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == DELAY))
        spi_cs_n &lt;= 0;   
    else if((cnt_byte == 3'd6) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == CE))
        spi_cs_n &lt;= 1;  
end

//cnt_bit 高低位对调,控制MOSI输出。用于输出MOSI的哪一位
always@(posedge sys_clk or negedge sys_rst_n)
begin   
    if(!sys_rst_n)
        cnt_bit &lt;= 3'd0;
    else if(cnt_clk == 2'd2)
        cnt_bit &lt;= cnt_bit + 1'b1;
end

//state 状态机跳转
always@(posedge sys_clk or negedge sys_rst_n)
begin   
    if(!sys_rst_n)
        state &lt;= IDLE;
    else
        case(state)
            IDLE:if(key == 1'b1)
                state &lt;= WR_EN;
            WR_EN:if((cnt_byte == 3'd2) &amp;&amp; (cnt_clk == 5'd31))
                state &lt;= DELAY;
            DELAY:if((cnt_byte == 3'd3) &amp;&amp; (cnt_clk == 5'd31))
                state &lt;= CE;
            CE:if((cnt_byte == 3'd6) &amp;&amp; (cnt_clk == 5'd31))
                state &lt;= IDLE;
            default:
                state &lt;= IDLE;
        endcase
end


//MOSI输出
always@(posedge sys_clk or negedge sys_rst_n)
begin   
    if(!sys_rst_n)
        spi_mosi &lt;= 1'b0;
    else if((state == WR_EN) &amp;&amp; (cnt_byte == 3'd2))
        spi_mosi &lt;= 1'b0;
    else if((state == CE) &amp;&amp; (cnt_byte == 3'd6))
        spi_mosi &lt;= 1'b0;
    else if((state == WR_EN) &amp;&amp; (cnt_byte == 3'd1) &amp;&amp; (cnt_sck == 5'd0))
        spi_mosi &lt;= WR_EN_INST;
    else if((state == CE) &amp;&amp; (cnt_byte == 3'd5) &amp;&amp; (cnt_sck == 5'd0))
        spi_mosi &lt;= CE_INST;
end


endmodule</code></pre>

<p>&nbsp;</p>

<p style="text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">&nbsp; &nbsp; 3)和</font><font face="Calibri">Modelsim</font><font face="宋体">联合仿真。(联合仿真视频可以参考B站高云半导体视频教程</font></span></span></span></span><a href="https://www.bilibili.com/video/BV1UK4y1A7ak?p=4&amp;share_medium=android&amp;share_plat=android&amp;share_session_id=a8efd765-9b16-4b7c-995f-ebb924bd1128&amp;share_source=WEIXIN&amp;share_tag=s_i&amp;timestamp=1640671755&amp;unique_k=OUMOKoO">高云半导体FPGA课程 - 软件篇_哔哩哔哩_bilibili</a></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">创建工程文件,把相关文件添加工程,取消优化。这个仿真使用了</font><font face="Calibri">M25P16</font><font face="宋体">仿真模块进行仿真。仿真波形如图:</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="宋体">写使能</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify">擦除指令</p>

<p style="text-indent:21.0000pt; text-align:justify">擦除完成</p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><font face="Calibri">4</font><font face="宋体">)在线逻辑仪波形</font></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">a</font><font face="宋体">、设置引脚时,</font></span></span></span><span style="color:#16a085;"><b><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="font-weight:bold"><font face="宋体">使用的是</font><font face="Calibri">MSPI</font><font face="宋体">引脚,所以注意在</font><font face="Calibri">Process</font><font face="宋体">页面右键选中</font><font face="Calibri">configraion</font><font face="宋体">,如图,在</font><font face="Calibri">Dual-purpose </font><font face="宋体">中选择</font><font face="Calibri">MSPI </font><font face="宋体">作为常规引脚</font></span></span></span></b></span><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="宋体">。否则编译时就会出现如图示错误。</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify">编译错误</p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">b</font><font face="宋体">、建立</font><font face="Calibri">GAO</font><font face="宋体">文件;详细步骤参考论坛大佬的教程。链接如下:</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><a href="https://bbs.eeworld.com.cn/thread-1189515-1-1.html#pid3113128">【国产FPGA高云GW1N-4系列开发板测评】&mdash;&mdash;4、内嵌逻辑分析仪的使用 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn)</a></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-size: 10.5pt;"><span style="color: rgb(0, 0, 0);"><font face="Calibri" style="font-family: 宋体;">c</font><font face="宋体" style="font-family: 宋体;">、在线逻辑分析页面,在这个自己犯了一个打错,就是提前把跳线帽跳到</font><font face="Calibri" style="font-family: 宋体;">JTAG</font><font face="宋体" style="font-family: 宋体;">模式,而此时还是使用</font><font face="Calibri" style="font-family: 宋体;">USB</font><font face="宋体" style="font-family: 宋体;">下载,结果出现下载不了程序,并且提示</font><font face="Calibri" style="font-family: 宋体;">code </font><font face="宋体" style="font-family: 宋体;">不匹配。实际上</font><font face="Calibri" style="font-family: 宋体;">GWIN1-4B MINI</font><font face="宋体" style="font-family: 宋体;">开发板已经有</font><font face="Calibri" style="font-family: 宋体;">JTAG</font><font face="宋体" style="font-family: 宋体;">下载,就是使用</font><font face="Calibri" style="font-family: 宋体;">FT232H</font><font face="宋体" style="font-family: 宋体;">芯片来支持</font><font face="Calibri" style="font-family: 宋体;">JTAG</font><font face="宋体" style="font-family: 宋体;">下载模式。这个错误让自己停滞了几天。感谢论坛大佬</font></span></span></span><span class="mentions"><a href="home.php?mod=space&amp;uid=449420" target="_blank">@gs001588</a> </span>&nbsp;<span style="font-size:10.5pt"><span style="font-size: 10.5pt;"><span style="color: rgb(0, 0, 0);"><font face="宋体"><font style="font-family:宋体">提供了帮助</font></font><font face="宋体" style="font-family: 宋体;">。多谢大佬。</font></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">d</font><font face="宋体">、在线逻辑波形由于没有截图就不上传了</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">2</font><font face="宋体">、页写代码编写</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">1</font><font face="宋体">)页写波形图绘制,参考时序绘制</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">2</font><font face="宋体">)根据波形图进行代码编写</font></span></span></span></span></span></p>

<pre>
<code>module  flash_pp_ctrl(

    input   wire            sys_clk     ,   //系统时钟,频率50MHz
    input   wire            sys_rst_n   ,   //复位信号,低电平有效
    input   wire            key         ,   //按键输入信号

    output  reg             cs_n        ,   //片选信号
    output  reg             sck         ,   //串行时钟
    output  reg             mosi            //主输出从输入数据

);

//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//

//parameter define
parameter   IDLE    =   4'b0001 ,   //初始状态
            WR_EN   =   4'b0010 ,   //写状态
            DELAY   =   4'b0100 ,   //等待状态
            PP      =   4'b1000 ;   //页写状态
parameter   WR_EN_INST      =   8'b0000_0110,   //写使能指令
            PP_INST         =   8'b0000_0010;   //页写指令
parameter   SECTOR_ADDR     =   8'b0000_0000,   //扇区地址
            PAGE_ADDR       =   8'b0000_0100,   //页地址
            BYTE_ADDR       =   8'b0010_0101;   //字节地址
parameter   NUM_DATA        =   8'd100      ;   //页写数据个数(0-99)

//reg   define
reg        cnt_byte        ;   //字节计数器
reg        state           ;   //状态机状态
reg        cnt_clk         ;   //系统时钟计数器
reg        cnt_sck         ;   //串行时钟计数器
reg        cnt_bit         ;   //比特计数器
reg        data            ;   //页写入数据

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//cnt_clk:系统时钟计数器,用以记录单个字节
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_clk  &lt;=  5'd0;
    else    if(state != IDLE)
        cnt_clk  &lt;=  cnt_clk + 1'b1;

//cnt_byte:记录输出字节个数和等待时间
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_byte    &lt;=  8'd0;
    else    if((cnt_clk == 5'd31) &amp;&amp; (cnt_byte == NUM_DATA + 8'd9))
        cnt_byte    &lt;=  8'd0;
    else    if(cnt_clk == 5'd31)
        cnt_byte    &lt;=  cnt_byte + 1'b1;

//cnt_sck:串行时钟计数器,用以生成串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_sck &lt;=  2'd0;
    else    if((state == WR_EN) &amp;&amp; (cnt_byte == 8'd1))
        cnt_sck &lt;=  cnt_sck + 1'b1;
    else    if((state == PP) &amp;&amp; (cnt_byte &gt;= 8'd5)
                &amp;&amp; (cnt_byte &lt;= NUM_DATA + 8'd9 - 1'b1))
        cnt_sck &lt;=  cnt_sck + 1'b1;

//cs_n:片选信号
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cs_n    &lt;=  1'b1;
    else    if(key == 1'b1)
        cs_n    &lt;=  1'b0;
    else    if((cnt_byte == 8'd2) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == WR_EN))
        cs_n    &lt;=  1'b1;
    else    if((cnt_byte == 8'd3) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == DELAY))
        cs_n    &lt;=  1'b0;
    else    if((cnt_byte == NUM_DATA + 8'd9) &amp;&amp; (cnt_clk == 5'd31) &amp;&amp; (state == PP))
        cs_n    &lt;=  1'b1;

//sck:输出串行时钟
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        sck &lt;=  1'b0;
    else    if(cnt_sck == 2'd0)
        sck &lt;=  1'b0;
    else    if(cnt_sck == 2'd2)
        sck &lt;=  1'b1;

//cnt_bit:高低位对调,控制mosi输出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_bit &lt;=  3'd0;
    else    if(cnt_sck == 2'd2)
        cnt_bit &lt;=  cnt_bit + 1'b1;

//data:页写入数据
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data &lt;=  8'd0;
    else    if((cnt_clk == 5'd31) &amp;&amp; ((cnt_byte &gt;= 8'd9)
                &amp;&amp; (cnt_byte &lt; NUM_DATA + 8'd9 - 1'b1)))
        data &lt;=  data + 1'b1;

//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        state   &lt;=  IDLE;
    else
    case(state)
        IDLE:   if(key == 1'b1)
                state   &lt;=  WR_EN;
        WR_EN:  if((cnt_byte == 8'd2) &amp;&amp; (cnt_clk == 5'd31))
                state   &lt;=  DELAY;
        DELAY:  if((cnt_byte == 8'd3) &amp;&amp; (cnt_clk == 5'd31))
                state   &lt;=  PP;
        PP:     if((cnt_byte == NUM_DATA + 8'd9) &amp;&amp; (cnt_clk == 5'd31))
                state   &lt;=  IDLE;
        default:    state   &lt;=  IDLE;
    endcase

//mosi:两段式状态机第二段,逻辑输出
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        mosi    &lt;=  1'b0;
    else    if((state == WR_EN) &amp;&amp; (cnt_byte== 8'd2))
        mosi    &lt;=  1'b0;
    else    if((state == PP) &amp;&amp; (cnt_byte == NUM_DATA + 8'd9))
        mosi    &lt;=  1'b0;
    else    if((state == WR_EN) &amp;&amp; (cnt_byte == 8'd1) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  WR_EN_INST;  //写使能指令
    else    if((state == PP) &amp;&amp; (cnt_byte == 8'd5) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  PP_INST;    //页写指令
    else    if((state == PP) &amp;&amp; (cnt_byte == 8'd6) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  SECTOR_ADDR;  //扇区地址
    else    if((state == PP) &amp;&amp; (cnt_byte == 8'd7) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  PAGE_ADDR;    //页地址
    else    if((state == PP) &amp;&amp; (cnt_byte == 8'd8) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  BYTE_ADDR;    //字节地址
    else    if((state == PP) &amp;&amp; ((cnt_byte &gt;= 8'd9)
                &amp;&amp; (cnt_byte &lt;= NUM_DATA + 8'd9 - 1'b1)) &amp;&amp; (cnt_sck == 5'd0))
        mosi    &lt;=  data;  //页写入数据

endmodule</code></pre>

<p>&nbsp;</p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="Calibri">3</font><font face="宋体">)</font><font face="宋体">在线逻辑图波形</font></span></span></span></span></span></p>

<p style="text-indent:21.0000pt; text-align:justify"><span style="font-size:10.5pt"><span style="font-family:Calibri"><span style="font-size:10.5000pt"><span style="font-family:宋体"><span style="color:#000000"><font face="宋体">写使能</font></span></span></span></span></span></p>

<p>&nbsp;</p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify">写指令</p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p style="text-indent:21.0000pt; text-align:justify">写地址</p>

<p style="text-indent:21.0000pt; text-align:justify"></p>

<p>&nbsp;</p>

<p>&nbsp;</p>

<p style="text-indent:21.0000pt; text-align:justify">&nbsp;</p>

<p>&nbsp;</p>

<p>&nbsp;</p>

RCSN 发表于 2021-12-28 16:50

<p>清晰明了,羡慕会fpga的</p>

gs001588 发表于 2021-12-28 21:38

<p>不错,说干就干,这效率杠杠的呀!</p>

<p>时序图是用啥软件画的,效果很好啊</p>

Jacktang 发表于 2021-12-29 07:17

<p>时序图很专业</p>

怀揣少年梦 发表于 2021-12-29 08:12

gs001588 发表于 2021-12-28 21:38
不错,说干就干,这效率杠杠的呀!

时序图是用啥软件画的,效果很好啊

<p>还是得益于大佬您的帮助啊。使用visio软件画的</p>

怀揣少年梦 发表于 2021-12-29 08:12

Jacktang 发表于 2021-12-29 07:17
时序图很专业

<p>过奖过奖</p>

soso 发表于 2021-12-30 09:36

怀揣少年梦 发表于 2021-12-29 08:12
还是得益于大佬您的帮助啊。使用visio软件画的

<p>赞,赞,评测文章帮助到其他坛友了:)</p>
页: [1]
查看完整版本: 【国产FPGA高云GW1N-4系列开发板测评】FLASH操作