- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
摘要: 本篇博客具体包括SPI协议的基本原理、模式选择以及时序逻辑要求,采用FPGA(EPCE4),通过SPI通信协议,对flash(W25Q16BV)存储的固化程序进行芯片擦除操作.
关键词:SPI;Verilog HDL;Flash 。
SPI是Motorola公司推出的一种同步串行接口,是一种高速、全双工、同步的通信总线,广泛应用于存储器,数模转换器,实时时钟等.
SPI协议通过四根线进行数据传输,即SCK(Serial Clock)、MOSI(Master Output Slave Input)、MISO(Master Input Slave Output)、/SS(Slave Select,低电平有效)(或/CS).
接口处理方式:一主一从(左)、一主多从【星型链式】(右)SPI通信要求主机和从机具有同步的时钟信号,传输速率直接受到时钟频率(SCLK)的影响.
信号线说明:
MOSI、MISO数据在SCK同步信号下传输,每个时钟周期传输一位数据,输入输出同步进行,要保证MSB或LSB先行需一致。/SS从设备信号选择线,由高变低,是SPI通讯的起始信号。当从设备/SS线检测到起始信号后,即为选中使能与主机通讯。/SS信号由低变高,为停止信号,从设备的选中状态被取消.
注:SPI每次数据传输可以8位或16位为单位,每次传输的单位数不受限制.
SPI通信时钟模式:
SPI通信加入了时钟相位(CPHA)和时钟极性(CPOL)的设置,通过组合CPOL和CPHA的不同设置,SPI共支持四种常见的时钟配置模式.
CPOL | CPHA |
---|---|
时钟极性,定义时钟信号在空闲状态下的电平 | 时钟相位,定义数据采样和转换的时钟边沿 |
CPOL=0:SCK空闲为低电平 | CPHA=0:SCK的第一个边沿采样数据并转换输出信号 |
CPOL=1:SCK空闲为高电平 | CPHA=1:SCK的第二个边沿采样数据并转换输出信号 |
在CPHA指示为l时, 数据就会在SCLK的第二个有效边沿被采样(/SS拉低后,空闲为高,为上升沿;空闲为低,下降沿),同时被锁存到寄存器中;如果CPHA 清零,数据就会在SCLK的第一个有效边沿被采样(/SS拉低后,空闲为高,为下降沿;空闲为低,为上升沿),同时被锁存起来。SPI的主从设备须配置相同的时序模式,见下图.
板载Flash芯片型号:W25Q16BV;总容量为16M bit,即2M字节;存储阵列被分成8192个可编程页,每页容量256字节;支持Standard SPI、Dual SPI和Quad SPI三种SPI通信协议,最大读/写传输速率达50MB/s。它支持多种擦除操作,包括扇区擦除(4KB)、块擦除(32KB或64KB)以及全芯片擦除.
上图可以看到,除SPI经典的四个引脚外,还有/WP和/HOLD,分别用于写保护和输入保持。对于不同倍率SPI协议,引脚使用搭配是有区别的.
W25Q16BV内部存储结构的逻辑和功能组织见下图,SPI接口负责接收命令和地址,并通过控制逻辑进行解析和执行。状态寄存器(Status Register)用于存储设备的状态信息,如是否忙碌(BUSY位);写控制通过IO2引脚控制,用于启动写操作;高电平生成器(High Voltage Generators)用于执行如擦除等操作;控制逻辑(Control Logic)负责解析SPI接口接收到的命令,并根据需要控制存储器的读/写操作。列解码(Column Decode)和页面缓冲(256-Byte Page Buffer)用于支持页面的读/写操作.
存储器部分被分割成32个块(Block),单个块区包含16个扇区(Sector),每个扇区又由16个页组成,单页存储256字节数据,共计32 x 16 x 16 x 256 ≈ 2M 字节。存储器通过页地址和字节地址来定位特定的数据位置.
24位地址线通过上述的层次结构来映射整个存储器的地址空间,具体见下面表格.
分区 | 地址位 |
---|---|
块(Block)地址 | 23~16位(0x1F0000到0x1FFFFF) |
扇区(Sector)地址 | 15~12位(0x00F000到0x00FFFF) |
页(Page)地址 | 11~8位 |
字节(Byte)地址 | 7~0位 |
软件命令:W25Q16BV的指令集由30条基本指令组成,指令完全通过SPI总线控制。指令的启动是通过/CS的下降边缘来触发的,/CS拉高前须完成指令输入,否则无效。DI输入的第一个字节提供指令代码,DI输入上的数据是在时钟的上升沿采样的,首先采样的是最高有效位(MSB)。指令的长度从单个字节到几个字节不等,后面可能跟着地址字节、数据字节、虚拟字节(可选),在某些情况下,还可能是它们组合。所有的读指令都可以在任何一个时钟位之后完成.
指令 | 编码 | 指令 | 编码 |
---|---|---|---|
Write Enable | 06h | Write Disable | 04h |
Sector Erase (4KB) | 20h | Block Erase (32KB) | 52h |
Block Erase (64KB) | D8h | Chip Erase | C7h/60h |
Continuous Read Mode Reset | FFh | Read Data | 03h |
Fast Read | 0Bh | Write Status Register | 01h |
所有写、编程或擦除指令必须在字节边界上完成(即,在完整的8位数据被时钟同步后,/CS被驱动为高)。如果不在字节边界上完成,该指令将被终止。这一特性旨在保护设备免受意外写入的影响.
当内存正在被编程或擦除,或者当状态寄存器正在被写入时,除了读状态寄存器指令之外的所有指令都将被忽略,直到编程或擦除周期完成.
电平切换时序要求:
下图为Serial Input Timing,其中片选线/CS待输入完成后拉高电平保持时间(tSHSL) (for Array Read Array Read / Erase or Program Read Status Registers) :至少7/40 ns;片选信号有效建立时间(tSLCH):至少为5ns;片选信号有效保持时间(tCHSH):至少为5ns。注意:读指令/写指令时钟频率最大为50Mhz.
写使能(Write Enable ):该指令用于设置(状态寄存器中)写使能锁存器(WEL)位为1,确保存储器处于可写状态.
首先,将/CS(Chip Select)引脚拉低,SPI通信启动。在CLK上升沿,将数据输入(DI)引脚上的数据位设置为指令代码“06h”,即0000 0110。完成后,将/CS引脚拉高,SPI通信的结束和写使能完成.
读操作(Read Data):这个指令允许从存储器中顺序地读取一个或多个数据字节。首先,通过将/CS引脚拉低来启动指令,将指令代码“03h”(0000 0011)和一个24位地址(A23-A0)通过DI引脚移位输入,代码和地址位在CLK上升沿时被锁定。最后,通过将/CS引脚拉高完成指令.
如果在擦除、编程或写入周期正在进行时(BUSY=1)发出读取数据指令,该指令将被忽略.
芯片全擦除操作(Chip Erase):Chip Erase 指令会将设备内的所有存储器设置为擦除状态,即所有位都设为1.
①擦除启动:在执行芯片擦除指令之前,必须先执行一个“写使能”指令,使设备能够接受芯片擦除指令(状态寄存器的WEL位必须等于1)。将/CS引脚拉低来启动指令,移位输入指令代码“C7h”或“60h”,在第八位被锁定后,/CS引脚须被拉高.
②擦除过程:/CS被拉高后,自计时的芯片擦除指令将开始执行。芯片擦除周期(典型3s,最大10s)进行期间,仍然可以通过“读取状态寄存器”指令来检查BUSY位的状态(BUSY位在芯片擦除周期期间为1).
③擦除后的状态:WEL位会被置0,注意:存储数据的任何部分受到块保护(BP2、BP1和BP0)位的保护,则不会执行芯片擦除指令.
烧录程序方式:①将程序下载到FPGA内部的SRAM之中,烧录过程耗时较短,但掉电后程序丢失;②将程序固化到FPGA外部挂载的非易失性存储器Flash芯片,掉电后程序不丢失.
在Quartus II的主界面中,选择“File”菜单下的“Convert Programming Files”选项,用于将编译生成的特定文件(如sof文件)转换为其他格式的文件,如jic文件,以便下载到FPGA板载的flash或其他目标设备中,流程见下图.
下载程序时,目标.jic文件后,右下指示框很明显看到下载至Flash(这里是EPCS16类似W25Q16),仅勾选Program/Configure 进行程序固化下载,仅勾选Erase表示擦除Flash操作.
根据Flash读/写时序要求,片选信号拉低后,需进行5ns(tSLCH≥5ns)等待时间,及后写入写使能指令。写入完成后,再次进行5ns(tCHSH≥5ns)等待,拉高片选线维持≥100ns,接续完成写入操作指令流程.
Flash芯片数据读操作的时钟频率(SCK)上限为50MHz,这里通过四分频设定SCK频率为12.5Mhz。单个时钟周期写入1 bit数据,完整的单字节指令需要8个完整的SCK时钟周期,即32个完整的系统时钟,系统时钟频率为50MHz,完整指令的写入需要640ns.
mosi信号输出采用了状态机转移的逻辑方法:
状态 | 说明 | 状态 | 说明 |
---|---|---|---|
IDLE |
空闲初始状态,等待触发信号 | WR_EN |
发送写使能指令 |
DELAY |
等待状态,保持时序 | CH_ER |
芯片擦除指令发送 |
当key_flag信号有效时,从IDLE转移到WR_EN状态,在WR_EN和CH_ER状态中,分别写入相应的写使能和指令后,等待tCHSH时间,然后拉高片选信号。在WR_EN状态写入指令后,转移到DELAY状态等待tSHSL时间。在DELAY状态等待完成后,转移到CH_ER状态,返回IDLE状态。相关代码如下:
parameter IDLE = 4'b0001, WREN = 4'b0010, DELAY= 4'b0100, CH_ER= 4'b1000;
parameter WREN_CODE = 8'b0000_0110, CH_ER_CODE = 8'b1100_0111;
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) state <= IDLE;
else case(state)
IDLE :if(key_flag)state <= WREN;
WREN :if((cnt_byte == 3'd2)&&(cnt_clk == 5'd31))state <= DELAY;
DELAY:if((cnt_byte == 3'd3)&&(cnt_clk == 5'd31))state <= CH_ER;
CH_ER:if((cnt_byte == 3'd6)&&(cnt_clk == 5'd31))state <= IDLE;
default:state <= IDLE;
endcase
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) mosi <= 1'b0;
else if((state == WREN)&&(cnt_byte == 3'd2)) mosi <= 1'b0;
else if((state == CH_ER)&&(cnt_byte == 3'd6)) mosi <= 1'b0;
else if((state == WREN)&&(cnt_byte == 3'd1)&&(cnt_sck == 2'd0))
mosi <= WREN_CODE[7 - cnt_bit];
else if((state == CH_ER) && (cnt_byte == 3'd5) && (cnt_sck == 2'd0))
mosi <= CH_ER_CODE[7 - cnt_bit];
end
而对于其他的信号逻辑处理:cnt_clk作为预期设定单位间距(640ns)的计数器,cnt_byte根据其完成7个阶段的转换。sck为写操作的时钟信号,cnt_sck作为其在有效时间段内计数器,使得sck按sys_clk四分配输出.
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) cnt_clk <= 5'd0;
else if(state != IDLE) cnt_clk <= cnt_clk + 1'b1; //位宽清零
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) cnt_byte <= 3'd0;
else if((cnt_byte == 3'd6)&&(cnt_clk == 5'd31)) cnt_byte <= 3'd0;
else if(cnt_clk == 5'd31) cnt_byte <= cnt_byte + 1'b1;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) cnt_sck <= 2'd0;
else if((state == WREN)&&(cnt_byte == 3'd1)) cnt_sck <= cnt_sck + 1'b1; //位宽清零
else if((state == CH_ER)&&(cnt_byte == 3'd5)) cnt_sck <= cnt_sck + 1'b1; //位宽清零
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) cnt_bit <= 3'd0;
else if(cnt_sck == 2'd2) cnt_bit <= cnt_bit + 1'b1;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) ss_n <= 1'b1;
else if(key_flag) ss_n <= 1'b0;
else if((cnt_byte == 3'd2)&&(cnt_clk == 5'd31)&&(state == WREN)) ss_n <= 1'b1;
else if((cnt_byte == 3'd3)&&(cnt_clk == 5'd31)&&(state == DELAY)) ss_n <= 1'b0;
else if((cnt_byte == 3'd6)&&(cnt_clk == 5'd31)&&(state == CH_ER)) ss_n <= 1'b1;
end
always @(posedge sys_clk or negedge sys_rst)begin
if(!sys_rst) sck <= 1'b0;
else if(cnt_sck == 2'd0) sck <= 1'b0;
else if(cnt_sck == 2'd2) sck <= 1'b1;
end
导入仿真文件,对芯片擦除操作进行仿真,由于该操作耗时长,仿真前在Flash参数文件缩放擦除周期至4000ns。从上图仿真结果可以看到,在4710ns处,Flash启动芯片擦除,在8710ns结束擦除操作.
根据仿真结果显示,sys_clk拉高后,程序正常工作,当检测到key_flag为高电平后,片选线SS_n拉低,指令操作开启。等待一个有效建立时间后(这里是640ns,便于编写代码),sck正式输出八段时钟切换(12.5Mhz)。首先,按写使能指令,输出一个时序(0000_0110,06h)。等待一个片选线建立时间后拉高,进入等待状态(≥100ns,640ns)接续完成芯片擦除指令的录入。cnt_byte和state的状态,随cnt_clk时钟计数变换.
文献参考:
[1]刘满. SPI协议接口的设计与实现[D]. 陕西:西安电子科技大学,2020; 。
[2]基于spi协议的flash驱动控制(https://doc.embedfire.com/fpga/altera/ep4ce10_pro/zh/latest/code/spi_flash.html); 。
[3] W25Q16BV Datasheet(PDF) - Winbond (alldatasheet.com); 。
本篇文章中使用的Verilog程序模块,若有需见网页左栏Gitee仓库链接:https://gitee.com/silly-big-head/little-mouse-funnyhouse/tree/FPGA-Verilog/ 。
最后此篇关于Flash驱动控制--芯片擦除(SPI协议)的文章就讲到这里了,如果你想了解更多关于Flash驱动控制--芯片擦除(SPI协议)的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
您好,在我的 android 项目中,我计划使用 TwinLinx Mymax NFC 芯片来启用任何手机的 nfc。但我不知道手机如何使用蓝牙与 nfc 芯片通信。我认为他们会为此提供一些 sdk
我想在我的应用程序中实现一个带有芯片的自动完成编辑文本,我想以一种在这里完成的方式来完成它:material design chips .首先,我想问一下是否有某种小部件(可能是新支持库的一部分)或我
我想知道不同种类的复位以及芯片中的定义。最好冷,暖,系统,应用,开机复位。 同样,对于它们每个的简单示例也受到高度赞赏。 谢谢。 最佳答案 不知道您到底想了解什么。重置可以并且可以以多种不同的方式和方
是否可以在按下按钮后开始从 nfc 芯片读取数据。按下按钮后,应该会出现一条消息,例如“请将您的 nfc 芯片靠近设备……”。我只看到教程,它展示了如何在设备上拿着 nfc 芯片时启动应用程序 (on
我看到一些问题在垂直堆叠 md-chips 的同时保持输入顶部,但我想将 md-chips 堆叠在输入行下方,就像它在 google 和 pinterest 中的情况一样 我希望输入字段位于顶部,筹码
我的应用程序中有一个表单,我在其中使用了来自 Primafaces 的以下代码: ...other inputs... Tags 我能够正确显示 Chip 元素,但我想设置其宽度为 100% 和高度
我正在使用 primefaces 并使用元素“chips”引入多封电子邮件,我验证了它们的格式,如果验证是,我试图将“气泡”的样式更改为 ui-state-error错了 我的筹码:
您好,我是android新手,正在学习使用material chips。我创建了一个测试项目并添加了以下内容 我添加到我的 gradle 文件中 implementation 'com.android
我尝试在 Apple M1 chip 上运行 android 模拟器MacBook 但它不起作用,并且 AVD 管理器显示错误消息:无法启动 AVD .这个问题的根源似乎是 M1 芯片不支持虚拟化,而
我想使用material-ui chips在我的 react 应用程序中。问题是我想通过拖放来移动芯片。 material ui 不支持此功能。是否有解决方法/扩展来使芯片可拖动? 查看完整示例:h
我正在使用materializecss编写一个表单字段,其中包含带有自动完成选项的mat-chips。这个想法是每当添加新芯片时就发出 PATCH 请求。以下是我当前使用的代码片段: $('#tag-
我正在使用materializecss编写一个表单字段,其中包含带有自动完成选项的mat-chips。这个想法是每当添加新芯片时就发出 PATCH 请求。以下是我当前使用的代码片段: $('#tag-
继续:EMV Reading PAN Code 我正在使用 C 语言,所以我没有 Java 工具和自动解析 APDU 命令响应的所有函数。我想读取所有类型的智能卡。我必须解析 GET PROCESSI
我正在寻找与 NDEF 兼容并为大多数运行 Android 4.x 的设备所支持的 NFC 芯片,不知何故我只能找到很少的相关信息。谁能说出制造商/芯片型号或提供一些有用的链接? 最佳答案 参见 ht
我不知疲倦地尝试在表格 View 单元格中创建一个“芯片”布局,其中单元格的高度会扩展以填充内容,但没有成功。 我的研究让我找到了这个图书馆 https://github.com/zoonooz/ZF
我已经开始在我的应用程序中使用 Angular Material。我正在使用 md-chips 控件,我想以从右到左的方向显示它。(右侧的筹码和左侧的占位符)我查看了 angular-material
我在 android 上遇到芯片组件问题。我尝试实现这样的芯片: 但是当我启动我的应用程序时出现此错误: android.view.InflateException: Binary XML
我有一个 CRUD,我想更改 inputTexArea: 新的 Primefaces chips 组件: 实体类摘录: @Lob @Size(max = 2147483647) @Column(n
我有一堆由 ngFor 循环生成的 ionic 芯片。我使用 tagDefaultColor 添加了选择所有 ionic 芯片功能多变的。现在,当我想选择单个 ionic 芯片时,它会选择所有这些。
我已经在网上查看过,讨论/示例似乎是针对传统软件开发的。由于Verilog和VHDL(用于芯片设计,例如FPGA和ASIC)与软件开发C和C++类似,因此似乎很有意义。但是,它们在本质上是并行的并且需
我是一名优秀的程序员,十分优秀!