CrazyBingo

MCU2FPGA 8080通信协议设计

0
阅读(9682)

MCU2FPGA 8080通信协议设计

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

一般MCU和FPGA通信,一般就是配置参数,或者传递数据,有些人将FPGA设计成SRAM时钟,有些人用串口来传输数据,但是除了通信,还得配置数据啊。。。。想起LCD的初始化,那个时序,就可以用来配置寄存器,又可以用来初始化,如下图,若能拿过来用,那不爽死。

wps_clip_image-31787

这便是Intel 8080接口的通信协议!

既然FPGA是万能的,那还是设计一个吧,反正项目中也要用到。

以后你们再问我,我就可以说:“简单的说就是看彬哥的博客”!O(∩_∩)O哈哈~

1. 协议介绍

wps_clip_image-24560

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

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

wps_clip_image-82

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

wps_clip_image-27784

2. RTL设计

代码其实很简单,就是捕获cs,rs,we,data等接口的时序,边沿检测,在verilog中设计状态机,来实现数据的读写,太简单的不累赘了,直接上代码。。。

 

/*-------------------------------------------------------------------------
This confidential and proprietary software may be only used as authorized
by a licensing agreement from CrazyBingo.
(C) COPYRIGHT 2012 CrazyBingo. ALL RIGHTS RESERVED
Filename			:		mcu8080_com.v
Author				:		CrazyBingo
Data				:		2012-06-26
Version				:		1.0
Description			:		Universal LCD Controller register control
Modification History	:
Data			By			Version			Change Description
===========================================================================
12/06/26		CrazyBingo	1.0				Original
12/06/29		CrazyBingo	1.1				Complete
--------------------------------------------------------------------------*/
`timescale 1ns/1ns
module mcu8080_com
(
	//global clock
	input			clk,
	input			rst_n,
	
	//mcu 8080 interface
	input			mcu_cs,			//mcu chip enable
	input			mcu_rs,			//mcu record/statement
	input			mcu_we,			//mcu write enable
	input	[15:0]	mcu_data,		//mcu data input
	
	output	reg[7:0]	led_data
);

//-------------------------------------
//data sync
reg	mcu_cs_r0,	mcu_cs_r1;
reg	mcu_rs_r0,	mcu_rs_r1;
reg	mcu_we_r0,	mcu_we_r1;
reg	[15:0]	mcu_data_r0,mcu_data_r1;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		mcu_cs_r0 <= 1;	
		mcu_cs_r1 <= 1;
		mcu_rs_r0 <= 0;			
		mcu_rs_r1 <= 0;
		mcu_we_r0 <= 0;			
		mcu_we_r1 <= 0;
		mcu_data_r0 <= 0;		
		mcu_data_r1 <= 0;
		end
	else
		begin
		mcu_cs_r0 <= mcu_cs;	
		mcu_cs_r1 <= mcu_cs_r0;
		mcu_rs_r0 <= mcu_rs;    
		mcu_rs_r1 <= mcu_rs_r0;
		mcu_we_r0 <= mcu_we;    
		mcu_we_r1 <= mcu_we_r0;
		mcu_data_r0 <= mcu_data;
		mcu_data_r1 <= mcu_data_r0;
		end
end
wire	sys_cs = mcu_cs_r1;
wire	sys_rs = mcu_rs_r1;
wire	sys_we = (~mcu_we_r1 & mcu_we_r0) ? 1'b1 : 1'b0;	//rising edge valid
wire	[15:0]		sys_data = mcu_data_r1;

//-------------------------------------
reg	[7:0]	sys_reg_addr;
reg	[15:0]	sys_reg_data;
reg	update_flag;
always@(posedge clk or negedge rst_n)
begin
	if(!rst_n)
		begin
		sys_reg_addr <= 0;
		sys_reg_data <= 0;
		update_flag <= 0;
		end
	else if(~sys_cs)	//chip enable
		begin
		if(~sys_rs & sys_we)		//write register
			begin
			sys_reg_addr <= sys_data[7:0];
			update_flag <= 0;
			end
		else if(sys_rs & sys_we)	//write data
			begin
			sys_reg_data <= sys_data;
			update_flag <= 1;
			end
		else
			update_flag <= 0;
		end
	else
		begin
		sys_reg_addr <= 0;
		sys_reg_data <= 0;
		update_flag <= 0;
		end	
end


//-------------------------------------
reg	[15:0]	led_data_reg;
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(sys_reg_addr)	//addr registers	
		8'hFA	:	led_data <= sys_reg_data[7:0];
		8'hFB	:	led_data <= sys_reg_data[7:0];
		8'hFC	:	led_data <= sys_reg_data[15:8];
		8'hFD	:	led_data <= sys_reg_data[15:8];
		default:;
		endcase
		end
end

endmodule

 

wps_clip_image-28290

wps_clip_image-18608

3. Testbench测试代码设计

`timescale 1ns/1ns
module mcu8080_tb;
wire	[7:0]	led_data;


//-------------------------------
//时钟控制模块
reg				clk;  
reg				rst_n;
parameter PERIOD = 20;	//50MHz
initial	
begin
	clk = 0;
	forever	#(PERIOD/2)	clk = ~clk;
end

task task_reset;
begin
	rst_n = 0;
	repeat(2) @(negedge clk);
	rst_n = 1;
end
endtask

reg	mcu_cs;
reg	mcu_rs;
reg mcu_we;
reg	[15:0]	mcu_data;
mcu8080_test	u_mcu8080_test
(
	.clk		(clk),
	.rst_n		(rst_n),
	
	//mcu 8080 interface
	.mcu_cs		(mcu_cs),		//mcu chip enable
	.mcu_rs		(mcu_rs),		//mcu record/statement
	.mcu_we		(mcu_we),		//mcu write enable
	.mcu_data	(mcu_data),		//mcu data input
	
	.led_data	(led_data)
);

task mcu8080_init;
begin
	mcu_cs = 1;
	mcu_rs = 0;
	mcu_we = 0;
	mcu_data = 0;
end
endtask

task task_writecmd;
input	[15:0]	cmd;
begin
	mcu_cs = 0;
	mcu_rs = 0;
	#30;
	mcu_data = cmd;
	#30;
	mcu_we = 1;
	#30;
	mcu_we = 0;
	#30;
	mcu_rs = 0;
	mcu_cs = 1;
	#30;
end
endtask

task task_writedata;
input	[15:0]	data;
begin
	mcu_cs = 0;
	mcu_rs = 1;
	#30;
	mcu_data = data;
	#30;
	mcu_we = 1;
	#30;
	mcu_we = 0;
	#30;
	mcu_rs = 0;
	mcu_cs = 1;
	#30;
end
endtask

task test_writereg;
input	[15:0]	cmd;
input	[15:0]	data;
begin
	task_writecmd(cmd);
	task_writedata(data);
end
endtask

initial
begin
	mcu8080_init;
	task_reset;
	@(posedge clk);
	test_writereg(8'hFA,16'h1234);
	test_writereg(8'hFB,16'h55aa);
	test_writereg(8'hFC,16'h1234);
	test_writereg(8'hFD,16'h55aa);


end

endmodule

 

wps_clip_image-15877

4. 单片机代码设计

这个,哎。。。。对于单片机玩家而言,那岂不是太简单了。。。。在此bingo就不班门弄斧了,悄悄附上代码,俺单片机不太行,忘斧正

/*Write Command*/

#define LCD_WriteCmd(command) { LCD_CS_L;\

LCD_RS_L;\

GPIOD->ODR = command;\

LCD_WR_H;\

LCD_WR_L;\

LCD_CS_H;\

}

/*Write Data*/

#define LCD_WriteData(data) { LCD_CS_L;\

LCD_RS_H;\

GPIOD->ODR = data;\

LCD_WR_H;\

LCD_WR_L;\

LCD_RS_L;\

LCD_CS_H;\

}

//写寄存器

void LCD_WriteReg(u8 LCD_Reg,u16 LCD_RegValue)

{

LCD_WriteCmd(LCD_Reg);

LCD_WriteData(LCD_RegValue);

}

 

5. 结论总结

经过测试,目前Bingo版本的8080接口通信协议非常的稳定,目前已经完成MCU对FPGA的LCD参数配置以及数据传输等操作,惊喜才开始,美好不只是那么一瞬间!!!看图看真相:

wps_clip_image-9692

很重要的一点

(1)数据的同步

(2)边沿的检测

(3)寄存器的更新需要uodate_flag,否则,更新的时候会有冲突,这个非常重要,否则会导致数据的错乱,读写不准确。

如有问题,欢迎矫正哈哈!