FPGA project : flash_write

本实验重点学习了:

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 + 100parameter   ADR_SE    = 8'h00    , // 扇区地址 adress secterADR_PA    = 8'h04    , // 页地址   adress pageADR_BY    = 8'h00    ; // 字节地址 adress byteparameter   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指令和addrDATA      = 5'b10000 ; // instruct 传送要写入的数据。// wire signal deginewire                IDLEtoWREN; wire                WRENtoWEL ;  wire                WRENtoINST;   wire                INSTtoDATA;   wire                DATAtoIDLE;   // reg signal definereg     [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_calways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) state_c <= IDLE ;elsestate_c <= state_n ;end// state_nalways @(*) begincase (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 ;endcaseend// 状态转移描述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) beginif(~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==120nscnt_20ns <= 4'd0 ;elsecnt_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 ;endcaseend// reg     [3:0]       cnt_bit   ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;endcaseend// reg      [31:0]       cnt_bytealways @(posedge sys_clk or negedge sys_rst_n) beginif(~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) beginif(~sys_rst_n) flag_bit <= 1'b0 ;elsecase (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 ;endcaseend// reg                 f_b_reg   ;always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) beginf_b_reg <= 1'b0 ;end else beginf_b_reg <= flag_bit ;endend// reg  [19:0]   data_numalways @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;// mosialways @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n)mosi <= 1'b0 ;elsecase (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:  beginif(!cnt_bit)mosi <= COMD_P[7] ;else if(cnt_20ns && sck)mosi <= COMD_P[7 - cnt_bit] ;else mosi <= mosi ;  end2:  beginif(!cnt_bit)mosi <= ADR_SE[7] ;else if(cnt_20ns && sck)mosi <= ADR_SE[7 - cnt_bit] ;else mosi <= mosi ;  end3:  beginif(!cnt_bit)mosi <= ADR_PA[7] ;else if(cnt_20ns && sck)mosi <= ADR_PA[7 - cnt_bit] ;else mosi <= mosi ;  end4:  beginif(!cnt_bit)mosi <= ADR_BY[7] ;else if(cnt_20ns && sck)mosi <= ADR_BY[7 - cnt_bit] ;else mosi <= mosi ;  end5:  beginif(!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 ;  enddefault:        mosi <= 1'b0 ;endcaseDATA :  if(data_num <= 255) beginif(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 偶数。发送数据aif(!cnt_bit)mosi <= DATA_EVE[7] ;else if(cnt_20ns && sck)mosi <= DATA_EVE[7 - cnt_bit] ;else mosi <= mosi ;  endend else beginmosi <= 1'b1 ; // 大于256个数据之后,mosi就一直传递1.enddefault:    mosi <= 1'b0 ;endcaseend// reg             cs_n        ,always @(posedge sys_clk or negedge sys_rst_n) beginif(~sys_rst_n) begincs_n <= 1'b1 ;end else begincase (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 ;endcaseendend// reg             sck always @(posedge sys_clk or negedge sys_rst_n) beginif(~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 ;endcaseendendmodule

仿真波形: 

 

 

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目管理之生命周期管理

项目生命周期管理矩阵是项目管理中一个重要的概念&#xff0c;它包括了项目从准备到收尾的各个阶段。项目生命周期管理矩阵以四个主要管理阶段为基础&#xff0c;分别为准备阶段、启动阶段、执行阶段和收尾阶段。这四个阶段在项目管理中有着明确的目标和职责&#xff0c;贯穿了…

软件工程与计算总结(十六)详细设计的设计模式

一.设计模式基础 某种意义上来说&#xff0c;设计模式就是设计经验的总结~ 设计模式不是简单的经验总结&#xff0c;更不是无中生有&#xff0c;它是经过实践反复检验、能解决关键技术难题、有广泛应用前景和能够显著提高软件质量的有效的经验总结。 每个模式都不是独立的&a…

Linux小程序---进度条

一&#xff1a;\r 和 \n \r --- 回车 --- 使光标回到这一行的开头 \n --- 换行 --- 会来到下一行与之平行的位置 缓冲区的问题&#xff1a; <1>: \n 的示例 正常输出 hehehehe 。 <2>: \r 的示例 为了方便观察&#xff0c;加入一个 sleep &#xff08;休眠函数…

爬虫 | 基础模块了解

文章目录 &#x1f4da;http协议&#x1f4da;requests模块&#x1f4da;re模块&#x1f407; re.I 或 re.IGNORECASE&#x1f407;re.M或 re.MULTILINE&#x1f407;re.S 或 re.DOTALL&#x1f407; re.A 或 re.ASCII&#x1f407; re.X 或 re.VERBOSE&#x1f407;特殊字符类…

docker拉取镜像错误missing signature key

参考地址&#xff1a;docker拉取镜像错误 missing signature key-CSDN博客 linux系统&#xff0c;使用docker拉取的时候&#xff0c;报错如下 missing signature key 就一阵莫名其妙&#xff0c;之前还好好的&#xff0c;突然就不行了 按照网上说的方法&#xff0c;查看doc…

基于nodejs+vue学籍管理系统

目 录 摘 要 I ABSTRACT II 目 录 II 第1章 绪论 1 1.1背景及意义 1 1.2 国内外研究概况 1 1.3 研究的内容 1 第2章 相关技术 3 2.1 nodejs简介 4 2.2 express框架介绍 6 2.4 MySQL数据库 4 第3章 系统分析 5 3.1 需求分析 5 3.2 系统可行性分析 5 3.2.1技术可行性&#xff1a;…

git操作说明

SourceURL:file:///home/kingqi/桌面/git操作说明.doc 本地建立仓库 mkdir namebao cd namebao pwd git init 初始化 cd .git/ gedit config 本地存储 进入目录上传全部文件 git add . 提交 git commit -m “说明” 远程提交 复制gitee或者github仓库链接 可以直…

C复习-基础知识

参考&#xff1a; 里科《C和指针》Bryant, Hallaron 《深入理解计算机系统》何昊&#xff0c;叶向阳《程序员面试笔试宝典》 从hello.c到可执行文件hello 在Unix系统中&#xff0c;从源文件到目标文件的转化是由编译器驱动程序完成的&#xff1a; root> gcc -o hello hel…

检查两个数组在维度,形状以及元素值上是否均等价 numpy.array_equiv()

【小白从小学Python、C、Java】 【计算机等级考试500强双证书】 【Python-数据分析】 检查两个数组在维度,形状 以及元素值上是否均等价 numpy.array_equiv() [太阳]选择题 请问以下代码中执行语句输出结果依次是&#xff1f; import numpy as np a np.array([1, 2]) b np.ar…

【LeetCode】《LeetCode 101》第十三章:链表

文章目录 13.1 数据结构介绍13.2 链表的基本操作206. 反转链表&#xff08;简单&#xff09;21. 合并两个有序链表&#xff08;简单&#xff09;24.两两交换链表中的节点&#xff08;中等&#xff09; 13.3 其它链表技巧160. 相交链表&#xff08;简单&#xff09;234. 回文链表…

面向对象是一种艺术

目录 文章导读面向对象与面向过程是什么&#xff1f;两者的比较 面向对象的三大特性封装怎么理解优点&#xff1a;代码示例 继承怎么理解优点代码示例 多态怎么理解优点示例代码 总结 文章导读 本文不纠结语言的选择&#xff0c;仅仅介绍面向对象这一个编程思想的运用&#xf…

山西电力市场日前价格预测【2023-10-18】

日前价格预测 预测说明&#xff1a; 如上图所示&#xff0c;预测明日&#xff08;2023-10-18&#xff09;山西电力市场全天平均日前电价为348.72元/MWh。其中&#xff0c;最高日前电价为505.50元/MWh&#xff0c;预计出现在18: 00。最低日前电价为288.10元/MWh&#xff0c;预计…