十五、串口发送图片数据到SRAM在TFT屏上显示
之前分享过rom存储图片数据在TFT屏上显示,该方法只能显示小点的图片,如果想显示TFT屏幕大小的图片上述方法rom内存大小不够。小梅哥给了个方案,利用串口将图片数据传给SRAM,传完后在从SRAM中读取图片数据进行显示。有了梅哥的提示后就开始动工了,首先是设计SRAM的控制程序。
SRAM(静态随机访问存储器)是一种半导体存储器。“静态”一词表明只要有电源供电,数据就会保存,而不会“动态”改变。
本实验平台是基于小梅哥出品的芯航线FPGA开发平台,该平台的SRAM芯片采用的是ISSI的IS61LV25616,它是一个256K*16位字长的高速率静态随机存取存储器。
通过查阅手册得知,除了地址总线和数据总线外,该芯片还包含五个控制信号(手册上的符号与这个有差别,手册是符号上一横线代表低电平有效)。
ce_n(芯片使能或芯片选择):禁止或使能芯片。
we_n(写使能):禁止或使能写操作。
oe_n(输出使能):禁止或使能输出。
lb_n(低字节使能):禁止或使能数据总线的低字节。
ub_n(高字节使能):禁止或使能数据总线的高字节。
所有这些信号都是低电平有效,后缀_n用于强调这一特性。功能表如表1所示:信号ce_n用于存储器扩展,信号we_n和oe_n用于写操作和读操作,lb_n和ub_n用于字节配置。
表1 SRAM控制信号的真值表
接下来分析SRAM的读写时序图,两种类型的读操作时序如图1(a)和图1(b)所示
(a)地址控制的读周期时序图(ce_n=0,we_n=1,oe_n=0)
(b)oe_n控制的读周期时序图
(c)部分时序参数的介绍
图1 读操作的时序图和部分参数
本实验数据用的是16位,所以lb_n和ub_n控制位我们一直给低电平即可。关于ce_n控制位在复位后一直给低电平即可。
芯片手册上关于写操作时序有四种类型,这里就简单介绍其中一种,其他的类似,写操作时序如图2所示:
(a)写操作时序图
(b)部分时序参数的介绍
图2 读操作的时序图和部分参数
根据上面的读操作和写操作时序,结合小梅哥的芯航线开发平台,取读写周期为20ns,这样可以直接采用平台已有的50Mhz的时钟,根据上面的时间限制,在读操作时,可以在使能读操作后,采用在时钟上升沿时改变地址,这样在下个时钟上升沿到来时就可以读取该地址的数据,也就是数据相对与给的地址是有一个时钟周期的延时。在写操作时,同样也是在时钟的上升沿给地址和待写入的数据,这样可以满足参数的时间要求。
SRAM控制器的设计如下:
1 module sram_ctrl( 2 clk50M, 3 rst_n, 4 address, 5 chipselect_n, 6 read_n, 7 write_n, 8 byteenable_n, 9 writedata, 10 readdata, 11 12 sram_addr, 13 sram_dq, 14 sram_ce_n, 15 sram_oe_n, 16 sram_we_n, 17 sram_lb_n, 18 sram_ub_n 19 ); 20 21 input clk50M; //系统时钟,默认50M 22 input rst_n; //异步复位,低电平有效 23 24 input [17:0] address; //数据传输地址 25 input chipselect_n; //SRAM片选信号,低电平有效 26 input read_n; //数据读控制信号,低电平有效 27 input write_n; //数据写控制信号,低电平有效 28 input [1:0]byteenable_n;//数据高低字节使能,低电平有效 29 input [15:0]writedata; //待写入RAM的数据 30 output [15:0]readdata; //读RAM的数据 31 32 output [17:0]sram_addr; //操作RAM数据的地址 33 inout [15:0]sram_dq; //RAM的数据端口 34 output sram_ce_n; //SRAM片选信号,低电平有效 35 output sram_oe_n; //SRAM读数据控制信号,低电平有效 36 output sram_we_n; //SRAM写数据控制信号,低电平有效 37 output sram_lb_n; //数据低字节有效 38 output sram_ub_n; //数据高字节有效 39 40 //signal declaration 41 reg [17:0]addr_reg; 42 reg [15:0]rdata_reg, wdata_reg; 43 reg ce_n_reg, lb_n_reg, ub_n_reg, oe_n_reg, we_n_reg; 44 45 //body 46 //registers 47 always@(posedge clk50M or negedge rst_n) 48 begin 49 if(!rst_n) 50 begin 51 addr_reg <= 18'd0; 52 rdata_reg <= 16'd0; 53 wdata_reg <= 16'd0; 54 ce_n_reg <= 1'b1; 55 oe_n_reg <= 1'b1; 56 we_n_reg <= 1'b1; 57 lb_n_reg <= 1'b1; 58 ub_n_reg <= 1'b1; 59 end 60 else 61 begin 62 addr_reg <= address; 63 rdata_reg <= sram_dq; 64 wdata_reg <= writedata; 65 ce_n_reg <= chipselect_n; 66 oe_n_reg <= read_n; 67 we_n_reg <= write_n; 68 lb_n_reg <= byteenable_n[0]; 69 ub_n_reg <= byteenable_n[1]; 70 end 71 end 72 73 //to fpga interface 74 assign readdata = rdata_reg; 75 76 //to SRAM 77 assign sram_addr = addr_reg; 78 assign sram_ce_n = ce_n_reg; 79 assign sram_oe_n = oe_n_reg; 80 assign sram_we_n = we_n_reg; 81 assign sram_ub_n = ub_n_reg; 82 assign sram_lb_n = lb_n_reg; 83 //SRAM tristate data bus 84 assign sram_dq = (~we_n_reg)?wdata_reg:16'bz; 85 86 endmodule
SRAM的数据线是输出输入数据共用的,要将其设计成三态门形式,具体如代码84行所示。接下就是编写tb文件来验证驱动程序,代码如下:
1 `timescale 1ns/1ns 2 `define PERIOD_CLK 20 3 4 module sram_tb; 5 reg clk50M; 6 reg rst_n; 7 8 reg [17:0]address; 9 reg read_n; 10 reg write_n; 11 12 reg [15:0]writedata; 13 wire [15:0]readdata; 14 15 wire [17:0]sram_addr; 16 wire [15:0]sram_dq; 17 wire sram_ce_n; 18 wire sram_oe_n; 19 wire sram_we_n; 20 wire sram_lb_n; 21 wire sram_ub_n; 22 23 integer i; 24 25 sram_ctrl sram_ctrl_u0( 26 .clk50M(clk50M), 27 .rst_n(rst_n), 28 .address(address), 29 .chipselect_n(1'b0), 30 .read_n(read_n), 31 .write_n(write_n), 32 .byteenable_n(2'b00), 33 .writedata(writedata), 34 .readdata(readdata), 35 36 .sram_addr(sram_addr), 37 .sram_dq(sram_dq), 38 .sram_ce_n(sram_ce_n), 39 .sram_oe_n(sram_oe_n), 40 .sram_we_n(sram_we_n), 41 .sram_lb_n(sram_lb_n), 42 .sram_ub_n(sram_ub_n) 43 ); 44 45 initial clk50M = 1'b1; 46 always #(`PERIOD_CLK/2) clk50M = ~clk50M; 47 48 initial 49 begin