FPGA project : flash_write

news2025/2/23 11:15:06

本实验重点学习了:

flash的页编程指令pp。

在写之前要先进行擦除(全擦除和页擦除);

本实验:先传写指令,然后进入写锁存周期,然后传页编程指令,+3个地址;

然后传数据,奇数传55,偶数传aa。

在之前扇区擦除的代码上改改就行了。加一个功能就是传入数据大于256个时候,mosi一直拉高。

模块框图:

状态机:

代码:

只放spi模块的。因为其他代码和扇区擦除指令是一样的。

module spi (
    input       wire            sys_clk     ,
    input       wire            sys_rst_n   , 
    input       wire            key_start   ,

    output      wire            miso        ,
    output      reg             mosi        ,
    output      reg             cs_n        ,
    output      reg             sck 
);
    // parameter 
    parameter   COMD_W    = 8'h06    , // 写指令, 先发送写指令,进入写锁存周期
                COMD_P    = 8'h02    , // 页写指令
                MAX_NUM   = 32'd270  ; // 要发送指令+地址+数据的字节数。 2 + 3 + 100
    parameter   ADR_SE    = 8'h00    , // 扇区地址 adress secter
                ADR_PA    = 8'h04    , // 页地址   adress page
                ADR_BY    = 8'h00    ; // 字节地址 adress byte
    parameter   DATA_ODD  = 8'h55    , // odd  奇数
                DATA_EVE  = 8'haa    ; // even 偶数
    parameter   IDLE      = 5'b00001 ,
                WREN      = 5'b00010 ,
                WEL       = 5'b00100 ,
                INST      = 5'b01000 , // instruct 传送pp指令和addr
                DATA      = 5'b10000 ; // instruct 传送要写入的数据。
    // wire signal degine
    wire                IDLEtoWREN; 
    wire                WRENtoWEL ;  
    wire                WRENtoINST;   
    wire                INSTtoDATA;   
    wire                DATAtoIDLE;   
    // reg signal define
    reg     [19:0]      data_num  ; // 记录传递的数据,如果超过256个,那么mosi将会一直拉高(传1).
    reg     [4:0]       state_c   ;
    reg     [4:0]       state_n   ;
    reg     [3:0]       cnt_20ns  ;
    reg     [3:0]       cnt_bit   ;
    reg     [31:0]      cnt_byte  ;
    reg                 flag_bit  ;
    reg                 f_b_reg   ; // flag_bit_reg的缩写
/****************************************************************************/
    // 三段式状态机
    // 现态与次态描述
    // state_c
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            state_c <= IDLE ;
        else
            state_c <= state_n ;
    end
    // state_n
    always @(*) begin
        case (state_c)
        IDLE   :if(IDLEtoWREN)
                    state_n <= WREN ;
                else 
                    state_n <= IDLE ;
        WREN   :if(WRENtoWEL)
                    state_n <= WEL  ;
                else 
                    state_n <= WREN ;
        WEL    :if(WRENtoINST)
                    state_n <= INST ;
                else 
                    state_n <= WEL  ;
        INST   :if(INSTtoDATA)
                    state_n <= DATA ;
                else 
                    state_n <= INST ;
        DATA   :if(DATAtoIDLE)
                    state_n <= IDLE ;
                else 
                    state_n <= DATA ;
        default:    state_n <= IDLE ;
        endcase
    end
    // 状态转移描述
    assign  IDLEtoWREN  = ( state_c == IDLE) && ( key_start     ) ;
    assign  WRENtoWEL   = ( state_c == WREN) && ( f_b_reg       ) ;
    assign  WRENtoINST  = ( state_c == WEL ) && ( cnt_20ns == 6 ) ;
    assign  INSTtoDATA  = ( state_c == INST) && ( f_b_reg       ) ;
    assign  DATAtoIDLE  = ( state_c == DATA) && ( f_b_reg && cnt_byte != 5) ; // 至少传递一个数据。否则会卡死在这个状态。
    // 相关信号描述
    // reg     [3:0]       cnt_20ns  ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_20ns <= 4'd0 ;
        else 
        case (state_c)
        IDLE :  cnt_20ns <= 4'd0 ;
        WREN :  if(cnt_20ns || f_b_reg)
                    cnt_20ns <= 4'd0 ;
                else 
                    cnt_20ns <= cnt_20ns + 1'b1 ;
        WEL  :  if(cnt_20ns == 6) // 60x20ns==120ns
                    cnt_20ns <= 4'd0 ;
                else
                    cnt_20ns <= cnt_20ns + 1'b1 ;
        INST :  if(cnt_20ns) // 由于下一个状态是发送数据,sck和cnt_20_ns的变换规律与INST相同。所以不需要f_b_reg。
                    cnt_20ns <= 4'd0 ;
                else 
                    cnt_20ns <= cnt_20ns + 1'b1 ;
        DATA :  if(cnt_20ns || (f_b_reg && cnt_byte != 5))
                    cnt_20ns <= 4'd0 ;
                else 
                    cnt_20ns <= cnt_20ns + 1'b1 ;
        default:    cnt_20ns <= 4'd0 ;
        endcase
    end
    // reg     [3:0]       cnt_bit   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            cnt_bit <= 4'd0 ;
        else 
        case (state_c)
        IDLE :  cnt_bit <= 4'd0 ;
        WREN :  if(!cnt_20ns && sck && cnt_bit == 7)
                    cnt_bit <= 4'd0 ;
                else if(!cnt_20ns && sck)
                    cnt_bit <= cnt_bit + 1'b1 ;
        WEL  :  cnt_bit <= 4'd0 ;
        INST :  if(!cnt_20ns && sck && cnt_bit == 7)
                    cnt_bit <= 4'd0 ;
                else if(!cnt_20ns && sck)
                    cnt_bit <= cnt_bit + 1'b1 ;
        DATA :  if(!cnt_20ns && sck && cnt_bit == 7)
                    cnt_bit <= 4'd0 ;
                else if(!cnt_20ns && sck)
                    cnt_bit <= cnt_bit + 1'b1 ;
        default:    cnt_bit <= 4'd0 ;
        endcase
    end
    // reg      [31:0]       cnt_byte
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            cnt_byte <= 32'd0 ;
        else if(cnt_bit == 7 && !cnt_20ns && sck && cnt_byte == MAX_NUM - 1) // 计数到传送字节的最大值。
            cnt_byte <= 32'd0 ;
        else if(cnt_bit == 7 && !cnt_20ns && sck)
            cnt_byte <= cnt_byte + 1'b1 ;
        else 
            cnt_byte <= cnt_byte ;
    end
    // reg                 flag_bit  ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) 
            flag_bit <= 1'b0 ;
        else
        case (state_c)
        IDLE :  flag_bit <= 1'b0 ;
        WREN :  if(cnt_bit == 7 && sck && !cnt_20ns)
                    flag_bit <= 1'b1 ;
                else 
                    flag_bit <= flag_bit ;
        WEL  :  flag_bit <= 1'b0 ;
        INST :  if(cnt_bit == 7 && sck && !cnt_20ns && cnt_byte == 4)
                    flag_bit <= 1'b1 ;
                else 
                    flag_bit <= flag_bit ;
        DATA :  if(cnt_bit == 0 && cnt_byte == 5)
                    flag_bit <= 1'b0 ;
                else if(cnt_bit == 7 && sck && !cnt_20ns && cnt_byte == MAX_NUM - 1)
                    flag_bit <= 1'b1 ;
                else 
                    flag_bit <= flag_bit ;
        default: flag_bit <= 1'b0 ;
        endcase
    end
    // reg                 f_b_reg   ;
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            f_b_reg <= 1'b0 ;
        end else begin
            f_b_reg <= flag_bit ;
        end
    end
    // reg  [19:0]   data_num
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            data_num <= 20'd0 ;
        else if(state_c == DATA && cnt_bit == 7 && !cnt_20ns && sck)
            data_num <= data_num + 1'b1 ;
        else if(state_c != DATA)
            data_num <= 20'd0 ;
        else 
            data_num <= data_num ;
    end
    // output signal
    // wire            miso        ,
    assign miso = 1'bz ;
    // mosi
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            mosi <= 1'b0 ;
        else
        case (state_c)
        IDLE :  mosi <= 1'b0 ;
        WREN :  if(!cnt_bit) // (cnt_bit == 0)
                    mosi <= COMD_W[7] ;
                else if(cnt_20ns && sck)
                    mosi <= COMD_W[7 - cnt_bit] ;
                else 
                    mosi <= mosi ;
        WEL  :  mosi <= 1'b0 ;
        INST :  case (cnt_byte)
                    1:  
                        begin
                            if(!cnt_bit)
                                mosi <= COMD_P[7] ;
                            else if(cnt_20ns && sck)
                                mosi <= COMD_P[7 - cnt_bit] ;
                            else 
                                mosi <= mosi ;  
                        end
                    2:  
                        begin
                            if(!cnt_bit)
                                mosi <= ADR_SE[7] ;
                            else if(cnt_20ns && sck)
                                mosi <= ADR_SE[7 - cnt_bit] ;
                            else 
                                mosi <= mosi ;  
                        end
                    3:  
                        begin
                            if(!cnt_bit)
                                mosi <= ADR_PA[7] ;
                            else if(cnt_20ns && sck)
                                mosi <= ADR_PA[7 - cnt_bit] ;
                            else 
                                mosi <= mosi ;  
                        end
                    4:  
                        begin
                            if(!cnt_bit)
                                mosi <= ADR_BY[7] ;
                            else if(cnt_20ns && sck)
                                mosi <= ADR_BY[7 - cnt_bit] ;
                            else 
                                mosi <= mosi ;  
                        end
                    5:  
                        begin
                            if(!cnt_bit) // 由于当cnt_byte == 5 时,有一段state_c没有立即跳转到data状态。
                                mosi <= DATA_ODD[7] ;
                            else if(cnt_20ns && sck)
                                mosi <= DATA_ODD[7 - cnt_bit] ;
                            else 
                                mosi <= mosi ;  
                        end
                default:        mosi <= 1'b0 ;
                endcase
        DATA :  if(data_num <= 255) begin
                    if(cnt_byte[0]) begin // 二进制最低为奇偶标志位,1表示奇位,发送数据5。
                        if(!cnt_bit)
                            mosi <= DATA_ODD[7] ;
                        else if(cnt_20ns && sck)
                            mosi <= DATA_ODD[7 - cnt_bit] ;
                        else 
                            mosi <= mosi ;  
                    end else begin // cnt_byte[0] == 0 偶数。发送数据a
                        if(!cnt_bit)
                            mosi <= DATA_EVE[7] ;
                        else if(cnt_20ns && sck)
                            mosi <= DATA_EVE[7 - cnt_bit] ;
                        else 
                            mosi <= mosi ;  
                    end
        end else begin
            mosi <= 1'b1 ; // 大于256个数据之后,mosi就一直传递1.
        end
        default:    mosi <= 1'b0 ;
        endcase
    end
    // reg             cs_n        ,
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n) begin
            cs_n <= 1'b1 ;
        end else begin
            case (state_c)
            IDLE :  if(key_start)
                        cs_n <= 1'b0 ;
                    else 
                        cs_n <= 1'b1 ;
            WREN :  if(f_b_reg)
                        cs_n <= 1'b1 ;
                    else 
                        cs_n <= cs_n ;
            WEL  :  if(cnt_20ns == 6) 
                        cs_n <= 1'b0 ;
                    else 
                        cs_n <= cs_n ;
            INST :  cs_n <= 1'b0 ;
            DATA :  if(f_b_reg && cnt_byte != 5 )
                        cs_n <= 1'b1 ;
                    else 
                        cs_n <= cs_n ;
            default:    cs_n <= 1'b1 ;
            endcase
        end
    end
    // reg             sck 
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(~sys_rst_n)
            sck <= 1'b0 ;
        else 
        case (state_c)
        IDLE :  sck <= 1'b0 ;
        WREN :  if(cnt_20ns)
                    sck <= ~sck ;
                else 
                    sck <= sck  ;
        WEL  :  sck <= 1'b0 ;
        INST :  if(cnt_20ns)
                    sck <= ~sck ;
                else 
                    sck <= sck  ;
        DATA :  if(cnt_20ns)
                    sck <= ~sck ;
                else 
                    sck <= sck  ;
        default:    sck <= 1'b0 ;
        endcase
    end

endmodule

仿真波形: 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1095025.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

分布式事务协调中间件---seata快速入门

分布式事务 Seata&#xff0c;之前叫做Fescar&#xff0c;是一个开源的分布式事务解决方案&#xff0c;它主要致力于提供高效和简单的分布式事务服务。Seata主要用于解决微服务架构下的数据一致性问题。 Seata 的基本原理是基于两阶段提交 (2PC) 以及三阶段提交 (3PC)&#xff…

Linux 学习的六个过程

Linux 上手难&#xff0c;学习曲线陡峭&#xff0c;所以它的学习过程更像一个爬坡模式。这些坡看起来都很陡&#xff0c;但是一旦爬上一阶&#xff0c;就会一马平川。 1、抛弃旧的思维习惯&#xff0c;熟练使用 Linux 命令行 在 Linux 中&#xff0c;无论我们做什么事情&…

快速排序、归并排序、基数排序

快速排序 算法思想 图 1-1 即确定一个基准值&#xff08;一般为数组中间位置的元素&#xff0c;或者自定义&#xff09;&#xff0c;让待排序数组中所有比基准值小的元素放到基准值左边的位置&#xff0c;所有比基准值大的元素放到基准值右边的位置&#xff0c;这样一趟排序下…

Rxjava3 全新详解及常用操作符

简介 RxJava 是一个基于 Java 的响应式编程库&#xff0c;用于处理异步事件流和数据流。它是由 Netflix 开发并开源&#xff0c;现在广泛用于 Android 和 Java 后端开发。RxJava 提供了一种用于组合和处理异步数据的丰富工具集&#xff0c;它的核心思想是将数据流视为一系列事…

Hadoop3教程(十):MapReduce中的InputFormat

文章目录 &#xff08;87&#xff09;切片机制与MapTask并行度决定机制&#xff08;90&#xff09; 切片源码总结&#xff08;91&#xff09;FileInputFormat切片机制&#xff08;92&#xff09;TextInputFormat及其他实现类一览&#xff08;93&#xff09; CombineTextInputFo…

深入解析C语言中的strstr函数

目录 一&#xff0c;strstr函数简介 二&#xff0c;strstr函数实现原理 三&#xff0c;strstr函数的用法 四&#xff0c;strstr函数的注意事项 五&#xff0c;strstr函数的模拟实现 一&#xff0c;strstr函数简介 strstr函数是在一个字符串中查找另一个字符串的第一次出现&…

QT6集成CEF3--01 准备工作

QT6集成CEF3--01 准备工作 一、所有使用到的工具软件清单:二、准备工作三、cefclient示例程序四、特别注意 一、所有使用到的工具软件清单: CEF 二进制发行包 cef_binary_117.2.5gda4c36achromium-117.0.5938.152_windows64.tar.bz2 CMake 编译工具 cmake-3.22.6-windows-x86_…

实践笔记-docker安装及配置镜像源

docker安装及配置镜像源 1.卸载旧版本docker2. 安装yum工具3. 设置镜像仓库4.安装docker5. 启动docker服务6.docker镜像源配置 当前环境linux为centos7 1.卸载旧版本docker 如果以前安装过旧版本可以先执行卸载&#xff0c;下面的截图是没有安装过。 yum remove docker \ do…

DID赛道前列的生物识别技术,开启Web3时代的大门—MXT

互联网发展的十字路口 互联网从上世纪90年代初发展至今&#xff0c;历经30年&#xff0c;她改变了整个人类的生活方式、沟通形式以及社会发展模式&#xff0c;她的影响早已渗透到了世界的各个角落。而如今&#xff0c;我们似乎正站在一个新的十字路口&#xff0c;一个互联网将…

端口被谁占用如何解决?

## 如何查看端口被谁占用了&#xff1f;你好,我是Hasity 今天分享的内容是&#xff1a;Windows/Linux端口被占用如何解决? 问题出现 Description:Web server failed to start. Port 8082 was already in use.Action:Identify and stop the process thats listening on port 8…

mp4文件怎样提取mp3音频文件

Mp4视频文件怎样提取mp3等音频文件呢&#xff1f; 推荐一个免费网址&#xff0c;且不用任何注册&#xff0c;直接可以使用 https://audio-extractor.net/cn/ 上传视频&#xff0c;选择转换的音频格式&#xff0c; 更多格式&#xff0c;包括如下&#xff1a; 转换文件完成后…

【JavaEE】初识网络

网络初识 文章目录 网络初识网络发展史独立模式网络互连局域网LAN广域网 网络通信基础IP地址端口号格式 协议五元组协议分层OSI七层模型TCP/IP五&#xff08;四&#xff09;层协议1.物理层2.数据链路层3.网络层4.传输层5.应用程序 网络设备所在的分层封装和分用例子发送方接收方…

PyTorch入门教学——dir()函数和help()函数的应用

1、简介 已知PyTorch是一个工具包&#xff0c;其中包含许多功能函数。dir()函数和help()函数是学习PyTorch包的重要法宝。 dir()&#xff1a;能让我们知道工具包以及工具包中的分隔区有什么东西。help()&#xff1a;能让我们知道每个工具是如何使用的&#xff0c;即工具的使用…

Redis数据序列化器

Redis序列化 Redis 数据序列化器用于将数据在存储到 Redis 中时进行序列化&#xff08;编码&#xff09;和反序列化&#xff08;解码&#xff09;。 RedisTemplate的两种序列化实践方案&#xff1a; 方案一&#xff1a; 自定义RedisTemplate 修改RedisTemplate的序列化器为…

从一到无穷大 #18 时序数据库运营SLI思考

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作)&#xff0c;由 李兆龙 确认&#xff0c;转载请注明版权。 公有云时序数据库SLA 运营商产品每服务周期服务可用率不低于99.9%衡量服务不可用数据指标从采…

SpringAOP是什么?为什么要有SpringAOP?

SpringAOP是什么&#xff1f;为什么要有SpringAOP&#xff1f; 原文&#xff1a;SpringAOP是什么&#xff1f;为什么要有SpringAOP&#xff1f; 一、有SpringAOP之前 简单的开发场景&#xff0c;只需要写简单的业务逻辑&#xff0c;比如CRUD 但是在执行具体的逻辑之前&…

【论文精读】NMP: End-to-end Interpretable Neural Motion Planner

toc 1 背景信息 团队&#xff1a;Uber&#xff0c;多伦大大学 年份&#xff1a;2019 论文链接&#xff1a;https://arxiv.org/abs/2101.06679 2 Motivation 深度学习方案受限于累积误差suffers from the compounding error&#xff0c;而且可解释性差interpretability is d…

如何设计一个ToC的弹窗

本文主要分享了如何设计一个具有高可扩展性的弹窗功能。 本设计参考了优惠券功能的设计思路&#xff0c;有兴趣的朋友可以看看优惠券的分享&#xff1a;如何设计一个可扩展的优惠券功能_java优惠券系统设计-CSDN博客 一、需求介绍 假如你的项目需要实现以下弹窗&#xff0c;…

排序算法-合并排序法(MergeSort)

排序算法-合并排序法&#xff08;MergeSort&#xff09; 1、说明 合并排序法&#xff08;MergeSort&#xff09;是针对已排序好的两个或两个以上的数列&#xff08;或数据文件&#xff09;&#xff0c;通过合并的方式将其组合成一个大的且已排好序的数列&#xff08;或数据文…

debian9换源存在的问题

今天租借了云服务器搭建了debian9&#xff0c;给apt-get换源过程中出现了很多问题&#xff0c;主要有两个问题&#xff1a; 问题1&#xff1a; sudo apt-get update 0% [Working]问题2&#xff1a; W: The repository http://mirrors.aliyun.com/debian stretch Release doe…