华大半导体HC32F4A0系列ARM芯片EXMC并口通信时序的FPGA实现
EXMC简介
外部存储器控制器EXMC是一个用来访问各种片外存储器、实现数据交换的独立模块。EXMC通过配置可以把内部的AMBA协议接口转换为各种类型的专用片外存储器通信协议接口。
其中将 SRAM/PSRAM/NOR Flash 控制器定义为 SMC(Static Memory Controller)、SDRAM 控制器定义为 DMC(Dynamic Memory Controller)、NAND Flash 控制器定义为NFC(NAND Flash Memory Controller),本文章将在FPGA上实现三种模式中的SMC模式。
EXMC-SMC读时序分析
如图4-2为ARM芯片EXMC并口的读时序,其中并口与FPGA通信的数据位宽可分为8位、16位、32位。具体的,本文将以16位宽接收数据(一次接收2个字节数据)为例进行分析。
首先需要了解图中接口信号的含义。信号SMC_CS表示为片选信号、SMC_OE为读使能信号、SMC_BLS为字节选通信号(本设计中不用该信号)、SMC_ADD为地址信号、SMC_DATA为16位数据。
接下来就是对图中的时序进行分析了,由图可知,在整个读数据的过程中片选信号SMC_CS是一直保持低电平的,而在读使能信号SMC_OE的每个下降沿时将进行锁地址操作(每个下降沿锁一个地址),在SMC_OE的每一个上升沿将读取数据(每个上升沿读一个16bit数据),这样一来将上述分析内容转化为Verilog代码就比较简单了。
EXMC-SMC写时序分析
如图4-3为为ARM芯片EXMC并口的写时序,其中并口与FPGA通信的数据位宽可分为8位、16位、32位。同样本文将以16位宽发送数据(一次发送2个字节数据)为例进行分析。
其中信号SMC_CS表示为片选信号、SMC_WE为写使能信号、SMC_BLS为字节选通信号(本设计中不用该信号)、SMC_ADD为地址信号、SMC_DATA为16位数据。
由图可知,在整个写数据的过程中片选信号SMC_CS是一直保持低电平的,在写使能信号SMC_WE的下降沿将进行锁地址操作,在这里需要注意的是。在进行一次锁地址操作时它会连续给出4个地址(如图中的Add、Add+1、Add+2、Add+3),但此时只有第一个地址Add对应的数据有效,而后三个地址对应的数据全部都为不定态X,因此在写时序中,在每个写使能的下降沿我们只锁第一个地址,并且将此地址对应的数据写出。接下来为EXMC读写时序的Verilog实现。
EXMC-SMC读写时序Verilog实现
module HC32_EXMC_SMC #(
parameter AD_WIDTH = 12,
parameter DATA_WIDTH = 16,
)(
input wire clk,
input wire rst,
inout wire [15:0] ARM_DATA_Inout,
input wire [AD_WIDTH -1:0] ARM_ADDR_In,
input wire ARM_NOE_In,
input wire ARM_NWE_In,
input wire ARM_NCE_In,
output reg [AD_WIDTH -1:0] FPGA_ad,
input wire [DATA_WIDTH -1:0] FPGA_data_in,
output reg [DATA_WIDTH -1:0] FPGA_data_out
);
reg noe;
reg noe_dly1;
reg noe_diy2;
reg nwe_dly1;
reg nwe_diy2;
reg nce_dly1;
reg nce_diy2;
reg noe_neg;
reg nce_neg;
reg nwe_neg;
reg nwe_cnt;
//第一步:取片选、读写使能边沿、打拍防止亚稳态
always @(posedge clk)
begin
if(rst)
begin
noe_dly1 <= 1;
noe_dly2 <= 1;
end
else
begin
noe_dly1 <= ARM_NOE_In; //读使能打两拍
noe_dly2 <= noe_dly1 ;
noe_neg <= noe_dly2 & ~noe_dly1; //取读使能下降沿
noe_pos <= ~noe_dly2 & noe_dly1; //取读使能上升沿
end
end
always @(posedge clk)
begin
if(rst)
begin
nwe_dly1 <= 1;
nwe_dly2 <= 1;
nce_dly1 <= 1;
nce_dly2 <= 1;
end
else
begin
nce_dly1 <= ARM_NCE_In; //片选信号打两拍
nce_dly2 <= nce_dly1 ;
nce_neg <= nce_dly2 & ~nce_dly1; //取片选下降沿
nwe_dly1 <= ARM_NWE_In; //写使能打两拍
nwe_dly2 <= nwe_dly1 ;
nwe_neg <= nwe_dly2 & ~nwe_dly1; //取写使能下降沿
end
end
//第二步:锁读写地址
always @(posedge clk)
begin
if(rst)
nwe_cnt <= 2'b0;
else if(nce_neg)
nwe_cnt <= 2'b0;
else if(nwe_neg && !nce_dly1)
nwe_cnt <= nwe_cnt +1'b1;
else if(nwe_cnt== 2'd4) //会给出连续4个地址,只锁第一个地址,后三个地址无效
nwe_cnt <= 2'b0;
else
nwe_cnt <=nwe_cnt ;
end
always @(posedge clk)
begin
if(nce_dly1 == 0)
begin
if((noe_neg) || (nwe_neg && (nwe_cnt == 0))) //会给出连续4个地址,只锁第一个地址,后三个地址无效
begin
FPGA_ad <= ARM_ADDR_In;
end
end
end
//写数据
always @(posedge clk)
begin
if(nce_dly1 == 0)
begin
if(nwe_neg && (nwe_cnt == 0))
begin
FPGA_data_out<= ARM_DATA_Inout;
end
end
end
//读数据
always @(posedge clk)
begin
if(rst)
begin
noe <= 1;
end
else
begin
if(!nce_dly1 && noe_pos)
begin
noe <= 0;
end
else if(nce_dly1 && !noe_pos)
noe <= 1;
else
noe <= noe;
end
end
assign ARM_DATA_Inout = (ARM_NCE_In ==0 && noe == 0) ? FPGA_data_in :'bz;
endmodule
EXMC读写时序仿真波形图
如图即为EXMC接口的读写时序仿真波形图,与数据手册中的时序一致。