CrazyBingo

8080时序的FPGA接收解码设计

1
阅读(10242)

1. 写在前面的话

很多人问我单片机和FPGA怎么通信,我告诉他,FPGA是万能的,你想怎么通信就怎么通信,或者你模拟UART,FSMC,I2C,自己看着办。呵呵。。。。。

纵然FPGA无所不能,也不能代替MCU的处理能力。很多系统中,都是FPGA与MCU的完美结合。因此难免有MCU与FPGA之间的数据交换。MCU与FPGA之间的通讯协议的稳定性,很大程序上决定了系统数据交换的成败率。在此设计了最基本的8080时序,并且通过STM32的FSMC模拟,借以奠定通讯的基础。

1. 8080时序详解

wps_clip_image-30268

如上所示,传说中的Intel 8080接口的通信协议!,左边Master,右边为Slave。数据通过一定的时序并行传输,实现片间通讯。既然FPGA是万能的,不妨设计一个基于FPGA的8080协议数据接收电路,通过STM32的FSMC模拟。

wps_clip_image-18401

注意,RS,WE,RD

CS(片选信号) :低电平片选有效,高电平失能(默认为高:失能)

RS(数据寄存器) :低电平写寄存器,高电平写数据(默认为高:写数据)

RD(读信号) :低电平有效,上升沿写入数据,高电平失能(默认为高,失能)

WR(写信号) :低电平有效,上升沿写入数据,高电平失能(默认为高,失能)

注意:FSMC中RS默认为低,其他为高

2. FSMC时序的FPGA接收解码设计

2.1. FSMC接收时序设计

wps_clip_image-5986

参照了ILI9325 LCD控制芯片的8080接口通信协议,如上图所示,STM32的FSMC硬件接口,设置成8080时序的输出时序。由于MCU与FPGA通信,设置为单向通信,因此省略了RD,Bingo版本的8080接口童鞋写入如下所示:

a) 写命令(单一或者连续写入)

wps_clip_image-1725

b) 写数据(单一或者连续写入)

wps_clip_image-23942

2.1.1. 异步数据同步化

由于MCU(或者其他外设)与FPGA是异步关系,为了达到数据的同步,以及边沿的采样,需要用几个寄存器,将异步数据同步化,实现时序系统稳定性。

其中片选,数据,以及时钟同步电路Verilog HDL代码如下所示:

//------------------------------------- //mcu data sync to fpga reg mcu_cs_r0, mcu_cs_r1, mcu_cs_r2; reg mcu_rs_r0, mcu_rs_r1, mcu_rs_r2; //fsmc default 0; 8080 default 1; reg mcu_we_r0, mcu_we_r1; //lag one clk reg [15:0] mcu_data_r0, mcu_data_r1, mcu_data_r2; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin mcu_cs_r0 <= 1; //chip enable mcu_cs_r1 <= 1; mcu_cs_r2 <= 1; mcu_rs_r0 <= 0; //record/statement mcu_rs_r1 <= 0; mcu_rs_r2 <= 0; mcu_data_r0 <= 0; //data bus mcu_data_r1 <= 0; mcu_data_r2 <= 0; mcu_we_r0 <= 1; //write enable(rising) mcu_we_r1 <= 1; //lag one clk end else begin mcu_cs_r0 <= mcu_cs; mcu_cs_r1 <= mcu_cs_r0; mcu_cs_r2 <= mcu_cs_r1; mcu_rs_r0 <= mcu_rs; mcu_rs_r1 <= mcu_rs_r0; mcu_rs_r2 <= mcu_rs_r1; mcu_data_r0 <= mcu_data; mcu_data_r1 <= mcu_data_r0; mcu_data_r2 <= mcu_data_r1; mcu_we_r0 <= mcu_we; mcu_we_r1 <= mcu_we_r0; end end wire fpga_cs = mcu_cs_r2; //lead one clk than fpga_we_flag wire fpga_rs = mcu_rs_r2; //lead one clk than fpga_we_flag wire [15:0] fpga_data = mcu_data_r2; //lead one clk than fpga_we_flag //To sure when fpga_we_flag = 1, cs & rs is valid, we lag one clk wire fpga_we_flag = (~mcu_we_r1 & mcu_we_r0) ? 1'b1 : 1'b0; //rising edge of we
2.1.2. FSMC数据接受解码

8080协议是为了实现命令以及数据的发送,因此接收数据的同时,需要进行数据的分配,以实现数据的解码电路,如下所示。

Reg_addr为接收到的命令。

Reg_data为接收到的数据。

Update_flag为接收到数据的标志位,便于在后续模块中的接收。

//------------------------------------- reg [7:0] reg_addr; reg [15:0] reg_data; reg update_flag; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin reg_addr <= 0; reg_data <= 0; update_flag <= 0; end else if(~fpga_cs) //chip enable begin if(~fpga_rs & fpga_we_flag) //write register begin reg_addr <= fpga_data[7:0]; reg_data <= reg_data; update_flag <= 0; end else if(fpga_rs & fpga_we_flag) //write data begin reg_addr <= reg_addr; reg_data <= fpga_data; update_flag <= 1; end else begin reg_addr <= reg_addr; reg_data <= reg_data; update_flag <= 0; end end else begin reg_addr <= reg_addr; reg_data <= reg_data; update_flag <= 0; end en
2.1.3. 命令数据解码电路

其实这一部也很重要,通过reg_addr以及reg_data,实现命令与数据的解码电路,也就是相当于模拟ILI9325内部的初始化协议。FPGA是万能的,这个功能用简单的case语句便能实现,如下以16h'FF的时候配置led_data为例。

//-------------------------------------//register and data trans always@(posedge clk or negedge rst_n) begin if(!rst_n) begin led_data <= 0; end else if(update_flag) //updata data flag begin case(reg_addr) 16'hFF : led_data <= reg_data[7:0]; default:; endcase end end
2.2. FSMC接收解码的Modelsim仿真
2.2.1. Testbench FSMC发送的设计

为了仿真电路的正确性,通过testbench模拟了STM32-FSMC的命令以及数据的发送时序,如下所示:

//--------------------------------------------- //mcu fsmc write cmd task task_write_cmd; input [15:0] fsmc_cmd; begin mcu_cs = 0; #100; mcu_rs = 0; #100; mcu_data = fsmc_cmd; mcu_we = 0; #100; mcu_we = 1; #100; mcu_rs = 1; #100; mcu_cs = 1; #100; end endtask //--------------------------------------------- //mcu fsmc write data task task_write_data; input [15:0] fsmc_data; begin mcu_cs = 0; #100; mcu_rs = 1; #100; mcu_data = fsmc_data; mcu_we = 0; #100; mcu_we = 1; #100; mcu_rs = 1; #100; mcu_cs = 1; #100; end endtask
2.2.2. FSMC时序仿真电路
initial begin task_sysinit; task_reset; task_write_cmd(16'hFF); task_write_data(16'h58); task_write_cmd(16'hFF); task_write_data(16'hA9); task_write_data(16'h6E); task_write_data(16'h8F); end

模拟MCU发送FSMC数据,经过FPGA的接收解码电路,最后的Modelsim仿真图如下所示:

wps_clip_image-28494

该代码已经应用在MCU2FPGA的VGA显示驱动中应用,经过长时间的测试校验,目前稳定可靠,希望能给大家在平时的设计中,带来一定的启发与帮助。我的设计永远是我的,除非你已经掌握了精髓,行云流水而自如。

Baidu
map