【FPGA】FPGA实现SPI协议读写FLASH(二)----- SPI接口驱动模块设计

news2024/12/30 2:57:33

SPI接口驱动模块设计

  • 一、功能分析
  • 二、状态机设计
  • 三、信号说明
  • 四、代码实现
  • 五、仿真测试

写在前面:
FPGA实现SPI协议读写FLASH系列相关文章:
SPI通信协议
【FPGA】FPGA实现SPI协议读写FLASH(一)----- M25P16操作概述
在上篇文章中对FLASH(M25P16)读写操作及指令等做了详细介绍,本文将通过SPI协议原理,设计SPI通信接口,实现FPGA与FLASH进行通信。
本项目中所使用的开发板型号:Cyclone IV E (EP4CE6F17C8),FLASH型号:M25P16。

一、功能分析

SPI接口驱动模块(spi_interface)主要根据SPI协议原理架起FPGA与FLASH数据传输的“桥梁”,将从SPI读写控制模块接收到的指令、地址、数据字节严格按照SPI协议传输给FLASH,并接收从FLASH读回的数据,发送给SPI读写控制模块。

二、状态机设计

状态转移图如下:
在这里插入图片描述
状态说明:
IDLE:空闲状态,等待读写控制模块发起数据传输请求。
READY:准备传输数据。
TRANS:数据传输状态,根据SPI协议发送或接收数据。
DONE:数据传输结束。

三、信号说明

PortI/O TypeDescription
clkinput时钟信号
rst_ninput复位信号
reqinput读/写数据请求
din[7:0]input要传输给FLASH的数据
rdout[7:0]output从FLASH读回的数据
rw_doneoutput读/写一字节数据完成标志
sclkoutput同步时钟
cs_noutput片选信号
mosioutput主机输出,从机输入信号
misoinput主机输入,从机输出信号

四、代码实现

//  **************************************************************
//  Author: Zhang JunYi
//  Create Date: 2022.11.15                        
//  Design Name: spi_flash    
//  Module Name: spi_interface         
//  Target Device: Cyclone IV E (EP4CE6F17C8), FLASH(M25P16)                
//  Tool versions: Quartus Prime 18.1             
//  Description: SPI读写FLASH工程SPI接口模块
//  **************************************************************

`include "param.v"

module spi_interface (
    input               clk             ,
    input               rst_n           ,
    //  flash_control
    input               req             ,       //  读/写数据请求
    input   [7:0]       din             ,       //  要写入的数据
    output  [7:0]       rdout           ,       //  读回的数据
    output              rw_done         ,       //  读写一字节数据完成标志
    //  M25P16
    output              sclk            ,
    output              cs_n            ,
    output              mosi            ,
    input               miso               
);
    //  参数定义
    localparam  IDLE    =   4'b0001 ,
                READY   =   4'b0010 ,
                TRANS   =   4'b0100 ,
                DONE    =   4'b1000 ;
    
    //  信号定义
    reg     [3:0]       state_c         ;
    reg     [3:0]       state_n         ; 

    reg     [4:0]       cnt_sclk        ;       //  sclk计数器
    wire                add_cnt_sclk    ;
    wire                end_cnt_sclk    ;

    reg     [4:0]       cnt_bit         ;       //  sclk计数器
    wire                add_cnt_bit     ;
    wire                end_cnt_bit     ;

    reg                 sclk_reg        ;       //  输出sclk寄存
    reg                 tx_data         ;       //  数据输出寄存
    reg     [7:0]       rx_data         ;       //  读回数据寄存

    //  状态转移条件
    wire                idle2ready      ;  
    wire                ready2trans     ;  
    wire                trans2done      ;  
    wire                done2idle       ;  


    //  状态机
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            state_c <= IDLE ;
        end
        else begin
            state_c <= state_n ;
        end
    end  

    always @(*)begin
        case (state_c)
            IDLE: begin
                if(idle2ready)
                    state_n = READY ;
                else
                    state_n = state_c ;
            end
            READY: begin
                if(ready2trans)
                    state_n = TRANS ;
                else
                    state_n = state_c ;
            end
            TRANS: begin
                if(trans2done)
                    state_n = DONE ;
                else
                    state_n = state_c ;
            end
            DONE: begin
                if(done2idle)
                    state_n = IDLE ;
                else
                    state_n = state_c ;
            end
            default: state_n = IDLE ;
        endcase
    end 

    //  状态转移条件
    assign idle2ready   = state_c == IDLE   && req          ;
    assign ready2trans  = state_c == READY  && (1'b1)       ;
    assign trans2done   = state_c == TRANS  && end_cnt_bit  ;
    assign done2idle    = state_c == DONE   && (1'b1)       ; 

    //  cnt_sclk
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_sclk <= 0 ;
        end
        else if(add_cnt_sclk)begin
            if(end_cnt_sclk)begin
                cnt_sclk <= 0 ;
            end				
            else begin	    
                cnt_sclk <= cnt_sclk + 1 ;
            end 		    
        end
    end                  
    assign	add_cnt_sclk = state_c == TRANS ;
    assign	end_cnt_sclk = add_cnt_sclk && (cnt_sclk == `SCLK_CYCLE - 1) ;

    //  sclk_reg
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            sclk_reg <= 1'b1 ;
        end
        else if(add_cnt_sclk && cnt_sclk == `SCLK_FALL)begin
            sclk_reg <= 1'b0 ;
        end
        else if(add_cnt_sclk && cnt_sclk == `SCLK_RISE)begin
            sclk_reg <= 1'b1 ;
        end
    end

    //  cnt_bit
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_bit <= 0 ;
        end
        else if(add_cnt_bit)begin
            if(end_cnt_bit)begin
                cnt_bit <= 0 ;
            end				
            else begin	    
                cnt_bit <= cnt_bit + 1 ;
            end 		    
        end
    end                  
    assign	add_cnt_bit =  end_cnt_sclk ;
    assign	end_cnt_bit = add_cnt_bit && (cnt_bit == 7) ;

    //  tx_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            tx_data <= 1'b1 ;
        end
        else if(state_c == TRANS && cnt_sclk == `TRANS_S)begin
            tx_data <= din[7 - cnt_bit] ;
        end
        else if(trans2done)begin
            tx_data <= 1'b1 ;
        end
    end

    //  rx_data
    always @(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            rx_data <= 0 ;
        end
        else if(state_c == TRANS && cnt_sclk == `SAMP_S)begin
            rx_data[7 - cnt_bit] <= miso ;
        end
    end

    //  输出
    assign rdout = rx_data ;   
    assign rw_done = trans2done ; 

    assign sclk = sclk_reg ;   
    assign cs_n = ~req ;  
    assign mosi = tx_data ;    
   
    
endmodule

五、仿真测试

SPI接口模块发送数据:
在这里插入图片描述
M25P16从机模型接收数据:
在这里插入图片描述
通过仿真分析,M25P16从机模型接收数据正确,SPI接口模块功能已实现。

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

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

相关文章

【MyBatis】框架特点,ORM思想,事务管理机制

1. Mybatis概述:1.1 基础知识:SSM三大框架: Spring SpringMVC MyBatis框架其实就是对通用代码的封装, 提前写好一堆接口和类, 在做项目的时候直接引入这些常用的借口和类(引入框架), 基于这些现有的接口和类进行开发, 可以大大提高开发效率.框架一般是以jar包的形式存在的, j…

Qt UDP

UDP是一种是一种轻量级、不可靠、面向数据报的无连接协议。当可靠性不重要时&#xff0c;可以使用它。 QUdpSocket 是 QAbstractSocket 的一个子类&#xff0c;所以拥有QAbstractSocket的各种方法&#xff0c;允许您发送和接收 UDP 数据报。 QAbstractSocket的各种函数已经在上…

【数据结构基础】树 - 前缀树(Trie Tree)

Trie&#xff0c;又称字典树、单词查找树或键树&#xff0c;是一种树形结构&#xff0c;是一种哈希树的变种。典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串&#xff09;&#xff0c;所以经常被搜索引擎系统用于文本词频统计。它的优点是…

Zabbix灾难备份多种方式分享(建议收藏)

感谢本文译者田川 ! 欢迎更多资深用户翻译原厂博文&#xff08;https://blog.zabbix.com/&#xff09;&#xff01; 田川 | 宏时数据技术工程师 Zabbix 5.0中文手册官方译者 2017-2018年Zabbix中国峰会演讲嘉宾 8年监控领域实施和管理工作经验 ►在这篇博文中&#xff…

mysql关系型数据库免安装包下载以及安装教程

对于大部分技算计技术相关的初学者而言&#xff0c;mysql关系型数据库无可厚非是最适合初学者学习使用的&#xff0c;但是对于安装mysql数据库来说可能就不是特别明确&#xff0c;到底如何安装。互联网上比较多都是官网的.msi安装包&#xff0c;自带mysql客户端和一些其他关联程…

2023年“华数杯”国际大学生数学建模A题赛题发布

MCM问题一&#xff1a;雅鲁藏布江综合发展规划背景雅鲁藏布江是中国最长的高原河流&#xff0c;也是世界上最高的高原河流之一。它起源 于喜马拉雅山脉的北部山麓&#xff0c;从西向东流&#xff0c;然后转向南部&#xff0c;流向印度。中国的雅鲁 藏布江全长2057公里&#xff…

诺依集成mybatis换成mybatis-plus(完美解决)

总结分析&#xff1a;问题1&#xff1a;mybatis与mybatis-plus能否共存&#xff1f;经过将近一天的搜索发现&#xff0c;mybatis与mybatis-plus的sql工厂不通&#xff0c;mybatis是SqlSessionFactoryBean&#xff0c;而mybatis-plus是MybatisSqlSessionFactoryBean&#xff0c;…

python下载油管、B站视频的方法

这是2023年的第一篇博客。但绝不是最后一篇。 今天的博客记录篇娱乐向。 今夜想让wh听我听的歌。 利用python的you-get实现听歌自由。&#xff08;虽然有音乐会员&#xff09; FFmpeg的下载与安装。 FFmpeg的下载地址 选择对应型号的操作系统。 本次演示采用windows操作系统…

ChatGPT的调用API被提前发现了?

前言 近日&#xff0c;有消息称ChatGPT的API已经被提前发现。作为一名技术爱好者&#xff0c;我决定亲自试试看。经过几次尝试&#xff0c;我发现这确实是真的&#xff01;&#xff08;不过OpenAI确实动作很快&#xff0c;如今已经修补了大部分的模型&#xff09;。 1. 如何调…

使用 4EVERLAND 将您的 Damus 配置文件存储到 IPFS/Arweave

真正控制您的社交网络&#xff01; 挑战Twitter的去中心化社交应用Damus已登陆App Store。它是第一个使用名为Nostr的开放式去中心化社交网络协议的移动应用程序&#xff0c;该协议由 Twitter 联合创始人 Jack Dorsey 资助&#xff0c;该协议基于加密密钥对。 Damus 的出现是…

001. SQL慢查询排查(字段类型不一致)

目录一&#xff1a;背景二&#xff1a;排查过程2.1: SQL慢查询定位2.2: Python层面分析将String翻译成Int类型的原因2.3: Python进行SQL执行时间检测出现的问题三&#xff1a;总结一&#xff1a;背景 新的业务上线后&#xff0c; 合作部门发现我们引擎执行完&#xff0c; 回调…

从用户到专家-Zabbix培训【优惠】通道开启

Q&#xff1a;我从2.0开始使用Zabbix&#xff0c;还用得着参加培训&#xff1f; A&#xff1a;相信我&#xff0c;多得是你不知道的事&#xff01; Zabbix与时俱进&#xff0c;6.0新增了很多功能&#xff0c;如何快速系统掌握&#xff1f; 培训内容是Zabbix原厂设计的系统课…

自学软件测试从哪里开始?给还在迷茫的人一条出路

这两天和朋友谈到软件测试的发展&#xff0c;其实软件测试已经在不知不觉中发生了非常大的改变&#xff0c;前几年的软件测试行业还是一个风口&#xff0c;随着不断地转行人员以及毕业的大学生疯狂地涌入软件测试行业&#xff0c;目前软件测试行业“缺口”已经基本饱和。当然&a…

JVM的垃圾回收机制GC

GC回收区域GC主要针对堆区回收&#xff0c;回收是以对象为单位。方法区的类对象加载后不太需要回收&#xff1b;栈区的释放时机确定&#xff0c;不必回收&#xff1b;程序计数器是固定内存地址&#xff0c;不必回收。找出垃圾的方法引用计数法&#xff08;jvm未采取&#xff09…

SAP 编号范围及BUFFER缓冲

一 前言 编号范围对象(NUMBER RANGE)是SAP ERP 软件中的一个重要概念. 主要用来获取流水号. 在标准功能及自开发功能中大量使用.系统中的几乎所有对象的号码都是通过编号范围对象获取的. 二 编号范围对象的创建 事务代码SNRO 用于创建编号范围对象 三 编号范围对象的配置…

几个关键字(final、static、权限修饰符、super、this、instanceof)

Java知识点总结&#xff1a;想看的可以从这里进入 目录5、关键字5.1、final5.2、static5.3、 权限修饰符5.4、 super、this5.5、instanceof5、关键字 5.1、final 1、final&#xff1a;最终的。 修饰局部变量时赋值后不可改&#xff0c;修饰成员变量时必须赋初值且不可改&#x…

基于AST的babel库实现js反混淆还原基础案例荟萃

基本概念 AST简介 AST全称Abstract Syntax Tree&#xff0c;即抽象语法树&#xff0c;简称语法树&#xff08;Syntax tree&#xff09;&#xff0c;树上的每个节点都表示源代码中的一种结构。 JavaScript 领域常用的 AST 解析库有 babel、esprima、espree 和 acorn 等&#…

【2023】Prometheus-先搭出来玩玩

找两台还没回收的服务器&#xff08;虚拟机&#xff09;&#xff0c;使用centos7.*系统 一台作为监控端&#xff0c;一台作为被监控端。目录1.快速部署Prometheus服务2.快速部署被监控端加入监控端3.使用grafana作为UI展示4.导入node_exporter模板监控node节点1.快速部署Promet…

【nodejs】脚手架从零开始搭建JBD

&#x1f6ce;️脚手架编写 脚手架框架&#xff1a; bin www.js src contant.js create.js main.js package-lock.json package.json &#x1f6e0;️插件安装 devDependencies & dependencies 脚本名称脚本作用commander读取版本&#xff0c;设定选项&#xff…

混合人机协同制造系统设计与控制中的运营管理问题:一项调查

S. Ehsan Hashemi-Petroodi , Simon Thevenin , Sergey Kovalev , Alexandre Dolgui 小于翻译摘要&#xff1a;能够执行多种任务的制造系统需要不同类型的资源。使用机器人的全自动系统具有高速、准确、不知疲倦和力量&#xff0c;但它们很昂贵。另一方面&#xff0c;人类工作者…