关键词:
系统整体框图如图:
顶层模块的设计:
flash页写模块的设计:
时序图:
页写的时序:
各个代码块如下:
`timescale 1ns/1ns
module key_filter
#(
parameter CNT_MAX = 20'd999_999 //计数器计数最大值
)
(
input wire sys_clk , //系统时钟50Mhz
input wire sys_rst_n , //全局复位
input wire key_in , //按键输入信号
output reg key_flag //key_flag为1时表示消抖后检测到按键被按下
//key_flag为0时表示没有检测到按键被按下
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//reg define
reg [19:0] cnt_20ms ; //计数器
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_20ms:如果时钟的上升沿检测到外部按键输入的值为低电平时,计数器开始计数
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_20ms <= 20'b0;
else if(key_in == 1'b1)
cnt_20ms <= 20'b0;
else if(cnt_20ms == CNT_MAX && key_in == 1'b0)
cnt_20ms <= cnt_20ms;
else
cnt_20ms <= cnt_20ms + 1'b1;
//key_flag:当计数满20ms后产生按键有效标志位
//且key_flag在999_999时拉高,维持一个时钟的高电平
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
key_flag <= 1'b0;
else if(cnt_20ms == CNT_MAX - 1'b1)
key_flag <= 1'b1;
else
key_flag <= 1'b0;
endmodule
`timescale 1ns/1ns
module spi_flash_pp
(
input wire sys_clk , //系统时钟,频率50MHz
input wire sys_rst_n , //复位信号,低电平有效
input wire pi_key , //按键输入信号
output wire cs_n , //片选信号
output wire sck , //串行时钟
output wire mosi //主输出从输入数据
);
//********************************************************************//
//****************** Parameter and Internal Signal *******************//
//********************************************************************//
//parameter define
parameter CNT_MAX = 20'd999_999; //计数器计数最大值
//wire define
wire po_key ;
//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//
//------------- key_filter_inst -------------
key_filter
#(
.CNT_MAX (CNT_MAX ) //计数器计数最大值
)
key_filter_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.key_in (pi_key ), //按键输入信号
.key_flag (po_key ) //消抖后信号
);
//------------- flash_pp_ctrl_inst -------------
flash_pp_ctrl flash_pp_ctrl_inst
(
.sys_clk (sys_clk ), //系统时钟,频率50MHz
.sys_rst_n (sys_rst_n ), //复位信号,低电平有效
.key (po_key ), //按键输入信号
.sck (sck ), //片选信号
.cs_n (cs_n ), //串行时钟
.mosi (mosi ) //主输出从输入数据
);
endmodule
`timescale 1ns/1ns
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 [7:0] cnt_byte ; //字节计数器
reg [3:0] state ; //状态机状态
reg [4:0] cnt_clk ; //系统时钟计数器
reg [1:0] cnt_sck ; //串行时钟计数器
reg [2:0] cnt_bit ; //比特计数器
reg [7:0] data ; //页写入数据
//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//
//cnt_clk:系统时钟计数器,用以记录单个字节
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_clk <= 5'd0;
else if(state != IDLE)
cnt_clk <= cnt_clk + 1'b1;
//cnt_byte:记录输出字节个数和等待时间
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_byte <= 8'd0;
else if((cnt_clk == 5'd31) && (cnt_byte == NUM_DATA + 8'd9))
cnt_byte <= 8'd0;
else if(cnt_clk == 5'd31)
cnt_byte <= cnt_byte + 1'b1;
//cnt_sck:串行时钟计数器,用以生成串行时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_sck <= 2'd0;
else if((state == WR_EN) && (cnt_byte == 8'd1))
cnt_sck <= cnt_sck + 1'b1;
else if((state == PP) && (cnt_byte >= 8'd5)
&& (cnt_byte <= NUM_DATA + 8'd9 - 1'b1))
cnt_sck <= cnt_sck + 1'b1;
//cs_n:片选信号
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cs_n <= 1'b1;
else if(key == 1'b1)
cs_n <= 1'b0;
else if((cnt_byte == 8'd2) && (cnt_clk == 5'd31) && (state == WR_EN))
cs_n <= 1'b1;
else if((cnt_byte == 8'd3) && (cnt_clk == 5'd31) && (state == DELAY))
cs_n <= 1'b0;
else if((cnt_byte == NUM_DATA + 8'd9) && (cnt_clk == 5'd31) && (state == PP))
cs_n <= 1'b1;
//sck:输出串行时钟
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
sck <= 1'b0;
else if(cnt_sck == 2'd0)
sck <= 1'b0;
else if(cnt_sck == 2'd2)
sck <= 1'b1;
//cnt_bit:高低位对调,控制mosi输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
cnt_bit <= 3'd0;
else if(cnt_sck == 2'd2)
cnt_bit <= cnt_bit + 1'b1;
//data:页写入数据
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
data <= 8'd0;
else if((cnt_clk == 5'd31) && ((cnt_byte >= 8'd9)
&& (cnt_byte < NUM_DATA + 8'd9 - 1'b1)))
data <= data + 1'b1;
//state:两段式状态机第一段,状态跳转
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
state <= IDLE;
else
case(state)
IDLE: if(key == 1'b1)
state <= WR_EN;
WR_EN: if((cnt_byte == 8'd2) && (cnt_clk == 5'd31))
state <= DELAY;
DELAY: if((cnt_byte == 8'd3) && (cnt_clk == 5'd31))
state <= PP;
PP: if((cnt_byte == NUM_DATA + 8'd9) && (cnt_clk == 5'd31))
state <= IDLE;
default: state <= IDLE;
endcase
//mosi:两段式状态机第二段,逻辑输出
always@(posedge sys_clk or negedge sys_rst_n)
if(sys_rst_n == 1'b0)
mosi <= 1'b0;
else if((state == WR_EN) && (cnt_byte== 8'd2))
mosi <= 1'b0;
else if((state == PP) && (cnt_byte == NUM_DATA + 8'd9))
mosi <= 1'b0;
else if((state == WR_EN) && (cnt_byte == 8'd1) && (cnt_sck == 5'd0))
mosi <= WR_EN_INST[7 - cnt_bit]; //写使能指令
else if((state == PP) && (cnt_byte == 8'd5) && (cnt_sck == 5'd0))
mosi <= PP_INST[7 - cnt_bit]; //页写指令
else if((state == PP) && (cnt_byte == 8'd6) && (cnt_sck == 5'd0))
mosi <= SECTOR_ADDR[7 - cnt_bit]; //扇区地址
else if((state == PP) && (cnt_byte == 8'd7) && (cnt_sck == 5'd0))
mosi <= PAGE_ADDR[7 - cnt_bit]; //页地址
else if((state == PP) && (cnt_byte == 8'd8) && (cnt_sck == 5'd0))
mosi <= BYTE_ADDR[7 - cnt_bit]; //字节地址
else if((state == PP) && ((cnt_byte >= 8'd9)
&& (cnt_byte <= NUM_DATA + 8'd9 - 1'b1)) && (cnt_sck == 5'd0))
mosi <= data[7 - cnt_bit]; //页写入数据
endmodule
flash学习笔记
最近升级FPGA程序遇到校验失败的问题,进一步接触了flash,升级的过程是上位机软件将hex文件通过usb发到RK3188,RK3188通过串口一帧一帧(每帧1kb的数据)地将数据发到fpga,由fpga最终将程序通过SPI写到flash中。升... 查看详情
基于fpga的spi协议接口的verilog设计(代码片段)
1.简介与仿真结论 SPI是一种三线同步接口,分别为同步时钟信号、数据输入信号和数据输出信号。另外每个扩展芯片还需要一个片选信号,主器件通过片选信号选通与其通信的从器件。它允许处理器与各种外围设备... 查看详情
fpga教程案例81接口案例1——基于fpga的spi接口实现
FPGA教程目录MATLAB教程目录---------------------------------------------------------------------------------------目录1.软件版本2.SPI原理概述3.SPI的FPGA实现 查看详情
fpga作为从机与stm32进行spi协议通信---verilog实现
一.SPI协议简要介绍SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上... 查看详情
spi—读写串行flash
SPI协议简介SPI协议是由摩托罗拉公司提出的通讯协议(SerialPeripheralInterface),即串行外围设备接口,是一种高速全双工的通信总线。它被广泛地使用在ADC、LCD等设备与MCU间,要求通讯速率较高的场合。 ?标号1处,NSS信号线... 查看详情
fpga/数字ic手撕代码11——基于pwm驱动的蜂鸣器verilog开发
深度学习/机器视觉/数字IC/FPGA/算法手撕代码目录总汇目录基于PWM驱动的蜂鸣器verilog开发1.程序2.测试3.仿真结果4.分析 查看详情
基于fpga的以太网tcp/ip协议实现过程记录
基于FPGA的以太网的TCP/IP协议的学习笔记一、完整的以太网数据部分包括以下几部分:前导码帧起始界定符以太网帧头IP首部UDP首部UDP数据(有效数据)CRC校验字节二、针对每一部分的格式如下:MAC数据包格式:... 查看详情
基于fpga的以太网tcp/ip协议实现过程记录
基于FPGA的以太网的TCP/IP协议的学习笔记一、完整的以太网数据部分包括以下几部分:前导码帧起始界定符以太网帧头IP首部UDP首部UDP数据(有效数据)CRC校验字节二、针对每一部分的格式如下:MAC数据包格式:... 查看详情
fpga--spi通信(代码片段)
...控制,没有应答机制确认是否接收到数据,所以跟IIC总线协议比较在数据可靠性上有一定的缺陷。4、特点1):高速、同步、全双工 查看详情
zynq之fpga学习----iic协议驱动模块仿真实验(代码片段)
1IIC通信协议简介IIC通信协议基础知识学习:硬件设计基础----通信协议IIC2实验任务设计IIC驱动模块,并进行仿真验证,观察仿真波形3实验设计3.1创建工程新建工程,操作如图所示:输入工程名和路径,如... 查看详情
spi通信协议(spi总线)学习
1、什么是SPI?SPI是串行外设接口(SerialPeripheralInterface)的缩写。是Motorola公司推出的一 种同步串行接口技术,是一种高速的,全双工,同步的通信总线。2、SPI优点支持全双工通信通信简单数据传输速率块3、缺点没有指定的流... 查看详情
基于fpga驱动vga显示图片的小问题
学习VGA显示图片的过程中,遇到了一个小问题,我在显示屏上开了一个60x60的框,放了一张图片进去显示,但是最终的结果如下图所示。 出现了一个竖黑边,看了看代码,分析了一下逻辑没问题,然而... 查看详情
用于非基于 I2C/SPI 的传感器的 Linux 内核驱动程序(用于模拟传感器)
...【发布时间】:2019-12-1222:31:57【问题描述】:我最近开始学习IIO子系统,现在对IIO子系统中基于SPI/I2C的传感器非常熟悉(也使用RegmapAPI)。不过,今天我遇到了一个电位器传感器:http://w 查看详情
固件远程更新之startupe2原语(fpga控制flash)
...CCLK_0连接,当使用远程更新时,首先fpga内部有控制flash的驱动(即逻辑控制flash时序),当然flash时钟也需要控制了,但这时时钟管脚已经连接到CCLK_0,那该如何操作啊,你直接约束分配管脚试试,是通不过的,这时STARTUPE2就派... 查看详情
spimaster接口的fpga实现
...serialperipheralinterface串行外围接口大致了解:spi是个同步协议,数据在master和slaver间交换通过时钟sck,由于它是同步协议,时钟速率就可以各种变换。sck:主机提供,从机不能操控,从器件由主机产生的时钟控制。数据只有在sck 查看详情
spimaster接口的fpga实现
...serialperipheralinterface串行外围接口大致了解:spi是个同步协议,数据在master和slaver间交换通过时钟sck,由于它是同步协议,时钟速率就可以各种变换。sck:主机提供,从机不能操控,从器件由主机产生的时钟控制。数据只有在sck 查看详情
基于basys2驱动lcdqc12864b的verilog设计图片显示
...动LCD显示,确实用单片机驱动是要简单不少,记得在FPGA学习交流群里问问题的时候,被前辈指教,说给我最好的指教便是别在玩这个了,多看看关于FPGA方面的书籍,比做这个单片机做的东西价值强多了。现在想来确实,自从学... 查看详情
stm32学习笔记(15)——spi协议(代码片段)
STM32学习笔记(15)——SPI协议一、SPI协议简介1.物理层2.协议层(1)通讯的开始与停止(2)时钟极性CPOL、时钟相位CPHA二、STM32的SPI外设1.通讯引脚2.时钟控制逻辑3.数据控制逻辑4.整体控制逻辑5.STM32的SPI通... 查看详情