FPGA解析串口指令控制spi flash完成连续写、读、擦除数据

前言

最近在收拾抽屉时找到一个某宝的spi flash模块,如下图所示,我就想用能不能串口来读写flash,大致过程就是,串口向fpga发送一条指令,fpga解析出指令控制flah,这个指令协议目前就是:
55 + AA + CMD + LEN_h + LEN_m + LEN_l + DATA
CMD:01 写;02 读;03 擦除(片擦除);
LEN_h/m/l:三个字节表示读写长度,高字节在前低字节灾后;
DATA:如果是写flah,DATA则为需要写入的数据,其它两种状态可以不填;

1. 串口指令解析

软件使用序列式状态机完成串口指令解析,最后解析出三个使能信号,以及相应的数据、长度、地址。

复制代码
always@(posedge clk,negedge rst_n)
	if(!rst_n)
		state<=S0;
	else begin
		case(state)
			S0:
				if(uart_vld)begin
					if(uart_dat == 8'h55)
						state<=S1;
					else
						state<=S0;					
				end else 
					state<=S0;					
			S1:
				if(uart_vld)begin
					if(uart_dat == 8'hAA)
						state<=S2;
					else
						state<=S0;					
				end else 
					state<=S1;
					
			S2:
				if(uart_vld)
					state<=S3;
				else
					state<=S2;
			S3://命令字
				if(uart_vld)
					state<=S4;
				else
					state<=S3;		
			S4://长度h
				if(uart_vld)
					state<=S5;
				else
					state<=S4;	
			S5://长度m
				if(uart_vld)
					state<=S6;
				else
					state<=S5;
			S6://长度l
				if(uart_vld)
					state<=S7;
				else
					state<=S6;
			S7:
				state<=S7;
			default:state<=S0;	
		endcase
	end

2. flash 控制

对于flash三个功能(读、写、擦书)分别设计了三个模块,每个模块完成对应功能以及输出flash的cs、sclk、sdi等信号,但是flash接口只有一组控制信号,因此需要对三个模块输出的flash控制信号进行选择输出,如下所示。

复制代码
always@(posedge clk,negedge rst_n)
	if(!rst_n)begin
		o_spi_cen	<=1'b1;		
	   o_spi_sclk	<=1'b0; 		
	   o_spi_sdi	<=1'b0; 	
	end else begin
		case(work_state)
			3'b001:begin//xie
				o_spi_cen	<= wr_flash_csn		;
			   o_spi_sclk	<= wr_flash_sclk		;
			   o_spi_sdi	<= wr_flash_sdi		;
				end
			3'b010:begin//du
				o_spi_cen	<= rd_flash_csn		;
			   o_spi_sclk	<= rd_flash_sclk		;
			   o_spi_sdi	<= rd_flash_sdi		;
				end	
			3'b100:begin//cachu
				o_spi_cen	<= er_flash_csn		;
			   o_spi_sclk	<= er_flash_sclk		;
			   o_spi_sdi	<= er_flash_sdi		;
				end	
			default:begin
				o_spi_cen	<=1'b1;		
				o_spi_sclk	<=1'b0; 		
				o_spi_sdi	<=1'b0; 
			end
		endcase
	end

assign 	work_state	={spi_flash_erctl,spi_flash_rdctl,spi_flash_wrctl};			

2.1 flash写控制

软件对flash写控制的基本方法是收到一个串口数据就写进flash,并不是先缓存256个字节然后直接进行页编程,这样搞控制逻辑比较复杂。方法确定后就是软件实现,上级输出了vld和data(vld和data上上沿对齐,vld只有一个时钟宽度),使用vld作为触发条件,完成数据写入。

同样软件使用序列式状态机器进行流程控制。然后先写使能,然后正常写指令(02)、地址数据。

复制代码
always@(posedge clk,negedge rst_n)
	if(!rst_n)
		state<=S0;
	else if(clken)begin
		case(state)
			S0:
				if(spi_flash_ctlr[2] && vld_zk)
					state<=S1;
				else
					state<=S0;
			S1://xieshineng  function code 06
				if(&cnt && cnt_bit=='d7)
					state<=S2;
				else	
					state<=S1;
			S2://delay
				if(&cnt && cnt_bit==WIDTH-1)
					state<=S3;
				else	
					state<=S2;
			S3://xie gongneng ma 02
				if(&cnt && cnt_bit=='d7)
					state<=S4;
				else 
					state<=S3;
			S4://xie dizhi
				if(&cnt && cnt_bit=='d23)
					state<=S5;
				else 
					state<=S4;
			S5://xie shuju 
				if(&cnt && cnt_bit=='d7)
					state<=S6;
				else 
					state<=S5;
			S6:
				if(&cnt)
					state<=S7;
				else 
					state<=S6;
			S7:
				if(cnt_byte == wr_len)
					state<=S8;
				else
					state<=S0;
			S8:
				state<=S8;
			default:state<=S0;
		endcase
	end

2.2 flash擦除

直接在写控制上面改,前面有个写使能,下图是擦除指令(C7/60)

复制代码
always@(posedge clk,negedge rst_n)
	if(!rst_n)
		state<=S0;
	else if(clken)begin
		case(state)
			S0:
				if(spi_flash_ctlr[2:1]==2'b01)
					state<=S1;
				else
					state<=S0;
			S1://xieshineng  function code 06
				if(&cnt && cnt_bit=='d7)
					state<=S2;
				else	
					state<=S1;
			S2://delay
				if(&cnt && cnt_bit==WIDTH-1)
					state<=S3;
				else	
					state<=S2;
			S3://
				if(&cnt && cnt_bit=='d7)
					state<=S6;
				else 
					state<=S3;
			S6:
				if(&cnt)
					state<=S7;
				else 
					state<=S6;
			S7:
					state<=S8;
			S8:
				state<=S8;
			default:state<=S0;
		endcase
	end

2.3 flash读控制

从falsh读数据比较简单,接口时序如下图,软件实现同样还是序列式状态机,根据传入的长度决定读取的字节数。

因为数据从flash读出后需要通过串口发送,因此为了减少工作量,从flash读出一个数据,串口就发送一个数据,因此为了避免flash两个数据都读出来了串口一个都没发完,需要控制flash读数间隔,使得这个间隔大于串口发完一个字节的时间,举个栗子,假设现在串口波特率为115200,那么发完一个字节的时间约为86.8us(10位),那么flash读数间隔要大于86.9us。

复制代码
always@(posedge clk,negedge rst_n)
	if(!rst_n)
		state<=S0;
	else if(clken)begin
		case(state)
			S0:
				if(spi_flash_ctlr[2:1]==2'b01)
					state<=S1;
				else
					state<=S0;
			S1:
				state<=S2;
			S2://cs xian ladi 		
				if(&cnt)	
					state<=S3;
				else 
					state<=S2;
			S3://xie gongneng ma 02
				if(&cnt && cnt_bit=='d7)
					state<=S4;
				else 
					state<=S3;
			S4://xie dizhi
				if(&cnt && cnt_bit=='d23)
					state<=S5;
				else 
					state<=S4;
			S5://xie shuju 
				if(&cnt && cnt_bit=='d7)
					state<=S6;
				else 
					state<=S5;
			S6:
				if(&cnt)
					state<=S7;
				else 
					state<=S6;
			S7:
				if(cnt_byte == rd_len)
					state<=S8;
				else
					state<=S9;
			S9:
				if(dly_end)
					state<=S1;
				else 
					state<=S9;
			S8:
				state<=S8;
			default:state<=S0;
		endcase
	end

3. 实物测试

开始我设置的波特率为921600,擦除和写没问题,至少在时序上是很完美的,但是回读出来的数据如下图前十个字节一样,本来写入是01~0a,现在读出的数据中第2、3、5、7、9都是FF,后来我把波特率降到9600,然后就好了,下图最后10个字节。中间10个ff是擦除完后读出来数据。

软件工程链接:
软件工程、源码、仿真、数据手册、fllash仿真模型

最后来张全家福

相关推荐
ALINX技术博客13 小时前
【ALINX 教程】FPGA Multiboot 功能实现——基于 ALINX Artix US+ AXAU25 开发板
fpga开发·fpga
Genevieve_xiao15 小时前
【verilog】如何一小时成为verilog高手(并非
fpga开发
从此不归路16 小时前
FPGA 结构与 CAD 设计(第3章)上
ide·fpga开发
Aaron158818 小时前
基于VU13P在人工智能高速接口传输上的应用浅析
人工智能·算法·fpga开发·硬件架构·信息与通信·信号处理·基带工程
碎碎思18 小时前
在 FPGA 上实现并行脉冲神经网络(Spiking Neural Net)
人工智能·深度学习·神经网络·机器学习·fpga开发
集芯微电科技有限公司20 小时前
替代HT6310/KP3310离线式AC-DC无感线性稳压器
数据结构·人工智能·单片机·嵌入式硬件·fpga开发
minglie121 小时前
Zynq上UART/IIC/SPI的24个实验-第0课:目录
fpga开发
FPGA小c鸡1 天前
FPGA摄像头到屏幕完整链路:从OV5640采集到HDMI实时显示(附完整工程代码)
fpga开发
dai8910111 天前
使用紫光同创FPGA实现HSSTLP IP支持的线速率
fpga开发
s09071361 天前
XIlinx FPGA使用LVDS的电源与电平关键指南
fpga开发·xilinx·lvds