OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证

引言

前一段时间,我们对vga_enh模块进行了单独的仿真(http://blog.csdn.net/rill_zhen/article/details/8911727),初步确认了这个模块是没有问题的。

那么,到底这个模块能不能正常work呢?本小节就解决这个问题。


1,实验步骤

本小节,我们将vga_enh模块添加到ORPSoC,进行RTL仿真,并在ML501开发板上进行验证。大体过程如下:

1>修改RTL代码,将vga_enh模块挂到ORPSoC的wishbone总线上。

2>编写裸机测试程序

3>仿真

4>下板子测试


2,修改RTL代码

在修改代码之前,一定要先把ORPSoC的结构弄明白,关于ORPSoC的整体结构,我们之前曾加介绍过,请参考:http://blog.csdn.net/rill_zhen/article/details/9381557

如何将vga_enh挂到总线上呢,主要有两种方式:其中一种方式是将其master接口挂到dbus_arbiter上,另外一种方式是挂在ddr2的控制器上。两种不同的挂法,示意如下:

挂在dbus_arbiter上:

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证


直接挂在ddr2控制器上:

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证


这两种方式都算是DMA,我们这里两种方式都支持,两种方式通过define语句决定。暂时选择第二种方式。

当然,无论采用哪种方式,其总线地址都是唯一的,我们这里分配为0x97000000.


其实,对于ML501开发板而言,其本身并没有VGA接口,而是DVI接口,由于vga_enh这个模块不仅支持VGA输出,也支持DVI输出,但是需要注意的是,如果想利用ML501的DVI接口输出,就需要配置ML501板子上的CH7301这个芯片,由于配置CH7301需要I2C总线,所以我们除了想ORPSoC中增加vga_enh模块之外,还要增加i2c控制器模块。

ORPSoC本身包含两个i2c_master_slave,为了简单起见,我们将其中一个替换成i2c_master。


由于需要修改的代码较多,这里不一一列出,可以直接使用的工程,我已上传:

http://download.csdn.net/detail/rill_zhen/6897705


3,编写测试程序

无论是进行RTL仿真,还是下板验证,我们都要先编写相应的测试程序。

vga.c:


/*
* file name : vga.c
* function  : vga controller test
* date      : 2014-01-10
* author    : Rill
*/

#include "cpu-utils.h"
#include "board.h"
#include "int.h"
#include "uart.h"
#include "printf.h"

//---VGA defines
#define RILL_VGA_BASE 0x97000000
#define VGA_IRQ 22
#define FRAME_BUF_BASE 0x0  //30MB
#define FRAME_BUF_SIZE 0x1000


//---I2C core defines
#define RILL_IIC_BASE 0xa0000000
#define IIC_REG_ADR_PRER_LO 0x0
#define IIC_REG_ADR_PRER_HI 0x1
#define IIC_REG_ADR_CTR	    0x2

#define IIC_REG_ADR_RXR_W     0x3
#define IIC_REG_ADR_SR_W      0x4
#define IIC_REG_ADR_TXR_W     0x3
#define IIC_REG_ADR_CR_W      0x4

#define IIC_REG_ADR_RXR_R     0x3
#define IIC_REG_ADR_SR_R      0x4
#define IIC_REG_ADR_TXR_R     0x5
#define IIC_REG_ADR_CR_R      0x6

//-----CH7301 defines
#define CH7301_ADR 0x76

#define CH7301_REG_ADR0 	0x49
#define CH7301_REG_ADR1 	0x1f
#define CH7301_REG_ADR2 	0x21
#define CH7301_REG_ADR3 	0x33
#define CH7301_REG_ADR4		0x34
#define CH7301_REG_ADR5		0x36
#define CH7301_REG_ADR6		0x1c
#define CH7301_REG_ADR7		0x48

#define CH7301_REG_DATA0 	0xc0
#define CH7301_REG_DATA1 	0x98
#define CH7301_REG_DATA2	0x09
#define CH7301_REG_DATA3	0x08
#define CH7301_REG_DATA4	0x16
#define CH7301_REG_DATA5	0x60
#define CH7301_REG_DATA6	0x00
#define CH7301_REG_DATA7	0x19

//---VGA data structure
typedef struct vga_regs
{
	unsigned int ctrl; //0x0
	unsigned int stat; //0x4
	unsigned int htim; //0x8
	unsigned int vtim; //0xc
	unsigned int hvlen; //0x10
	unsigned int vbara; //0x14
	unsigned int vbarb; //0x18

}rill_vga_regs_s;


//----I2C core data structure 
#if 0
typedef struct i2c_regs
{
	unsigned char prer_lo;//3‘b000
	unsigned char prer_hi;//3‘b001
	unsigned char ctr;//3‘b010
	unsigned char rxr;//3‘b011
	unsigned char sr;//3‘b100
	unsigned char txr;//3‘b101
	unsigned char cr;//3‘b110
}rill_i2c_regs_s;

#endif
//===== funcs

/* The vga interrupt handler. */
void vga_interrupt(void)
{
	int i = 0;
	i = 1;
	return;
}


void my_vga_setup(void)
{
	volatile rill_vga_regs_s * vga_regs;
	unsigned int thsync = 127;
	unsigned int thgdel = 87;
	unsigned int thgate = 799;
	unsigned int thlen = 1056;
	unsigned int tvsync = 3;
	unsigned int tvgdel = 22;
	unsigned int tvgate = 599;
	unsigned int tvlen = 628;

	vga_regs = (rill_vga_regs_s*)(RILL_VGA_BASE);
	
	/* config vga regs*/
	//==1==-> stop vga core
	vga_regs->ctrl = 0x0;

	//==2==-> set vbara reg:0x 
	vga_regs->vbara = FRAME_BUF_BASE;

	//==3==-> set vbarb reg
	vga_regs->vbarb = FRAME_BUF_BASE + FRAME_BUF_SIZE;

	//==4==-> set htim reg
	vga_regs->htim = (thsync << 24) | (thgdel << 16) | thgate;

	//==5==-> set vtim reg
	vga_regs->vtim = (tvsync << 24) | (tvgdel << 16) | tvgate;

	//==6==-> set hvlen reg
	vga_regs->hvlen = (thlen << 16) | tvlen;

	//==7==-> start vga core:0000_0000_0000_0000_0000_0110_0000_0001
	vga_regs->ctrl = 0x621;


 	return;
}






void i2c_reg_write(unsigned int reg_wb_adr,unsigned char value)
{
	//volatile unsigned int * i2c_reg;
	//i2c_reg = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr);
	//i2c_reg = value;
	REG8(RILL_IIC_BASE + reg_wb_adr) = value;

	return;
}

unsigned char i2c_reg_read(unsigned int reg_wb_adr)
{
	unsigned char ret = 0;	
	//volatile unsigned int * i2c_reg;
	//ret = (unsigned int *)(RILL_IIC_BASE + reg_wb_adr);

	ret = REG8(RILL_IIC_BASE + reg_wb_adr);
	return ret;
}



void i2c_wait_ack(void)
{
	volatile unsigned int tip = 0;//SR:[ack_from_wr,busy,sl,0,0,0,tip,irq]
	
	do
	{	
		tip = (REG32(RILL_IIC_BASE+IIC_REG_ADR_SR_R) & 0x02000000);
	}while(tip);
}

void i2c_write(unsigned char i2c_adr,unsigned char data)
{
	i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit
	i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack]
	i2c_wait_ack();

	i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr);
	i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
	i2c_wait_ack();

	i2c_reg_write(IIC_REG_ADR_TXR_W,data);
	//i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
	//i2c_wait_ack();
	i2c_reg_write(IIC_REG_ADR_CR_W,0x50);//set commond (write,stop)
	i2c_wait_ack();

	return;
}


void i2c_read(unsigned char i2c_adr,unsigned char* data)
{
	i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) & 0xfe);//present slave addr(ch7301,0x76),set write bit
	i2c_reg_write(IIC_REG_ADR_CR_W,0x90);//set commond(start,write),CR:[sta,sto,rd,wr,ack2rd,0,0,iack]
	i2c_wait_ack();

	i2c_reg_write(IIC_REG_ADR_TXR_W,i2c_adr);
	i2c_reg_write(IIC_REG_ADR_CR_W,0x10);//set commond(write)
	i2c_wait_ack();

	i2c_reg_write(IIC_REG_ADR_TXR_W,(CH7301_ADR<<1) | 0x01);
	i2c_reg_write(IIC_REG_ADR_CR_W,0x90);
	i2c_wait_ack();

	i2c_reg_write(IIC_REG_ADR_CR_W,0x28);//set commond (read,nack_read),read comolete!
	i2c_wait_ack();
	* data = i2c_reg_read(IIC_REG_ADR_RXR_R);

	return;
}

void my_i2c_init(void)
{
	i2c_reg_write(IIC_REG_ADR_PRER_LO,0xff);//load prescaler lo-byte
	i2c_reg_write(IIC_REG_ADR_PRER_HI,0x00);//load prescaler hi-byte
	i2c_reg_write(IIC_REG_ADR_CTR,0x80);//enable core
	return;
}

void my_ch7301_init(void)
{
	unsigned char data = 0;

	i2c_write(CH7301_REG_ADR0,CH7301_REG_DATA0);
	i2c_write(CH7301_REG_ADR1,CH7301_REG_DATA1);
	i2c_write(CH7301_REG_ADR2,CH7301_REG_DATA2);
	i2c_write(CH7301_REG_ADR3,CH7301_REG_DATA3);
	i2c_write(CH7301_REG_ADR4,CH7301_REG_DATA4);
	i2c_write(CH7301_REG_ADR5,CH7301_REG_DATA5);
	i2c_write(CH7301_REG_ADR6,CH7301_REG_DATA6);
	i2c_write(CH7301_REG_ADR7,CH7301_REG_DATA7);

	//read ch7301 data back
	//i2c_read(CH7301_REG_ADR0,&data);

	return;
}




void delay(unsigned int delay)
{
	unsigned int time;

	time = delay;
	while(time--)
	{
		while(delay--);
	}

	return;
}


void my_i2c_setup(void)
{
	my_i2c_init();
	my_ch7301_init();
	
	return;
}


int main (void)
{

  	/* Initialise handler vector */
  	//int_init();

  	/* Install ethernet interrupt handler, it is enabled here too */
  	//int_add(VGA_IRQ, vga_interrupt, 0);

  	/* Enable interrupts in supervisor register */
  	//cpu_enable_user_interrupts();

	uart_init(0);
	printf("\n\t <1-> uart_init done!\n\0");

	my_i2c_setup();/* configure IIC & CH7301*/
	printf("\n\t <2-> i2c_setup done!\n\0");

  my_vga_setup(); /* Configure VGA */
	printf("\n\t <3-> vga_setup done!\n\0");

	return 0;
 // 	exit(0x8000000d);
  
}

makefile:

# Set the path to our board‘s root directory
BOARD_SW_ROOT=../../..

include $(BOARD_SW_ROOT)/Makefile.inc

%.dis: %.elf
	$(Q)$(OR32_OBJDUMP) -d $< > $@

%.bin: %.elf
	$(Q)$(OR32_OBJCOPY) -O binary $< $@

clean:
	$(Q)rm -f *.elf *.bin *.vmem *.flashin *.dis



4,RTL仿真

在下板验证之前,强烈建议先进行RTL仿真。

关于ORPSoC仿真环境的构建,我们之前已经介绍过了,请参考:

http://blog.csdn.net/rill_zhen/article/details/16880801

在搭建好仿真环境之后,我们就可以进行全系统仿真了,步骤如下:

a,创建软件仿真目录和软件程序


cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sw/tests/
mkdir vga
cd vga
mkdir sim
cp /path/to/vga.c /path/to/Makefile ./

效果如下所示:

其中vga.elf文件使用“make vga.elf”命令产生的,在下板验证时使用。

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证


b,开始仿真

cd ~/soc-designed/orpsocv2/boards/xilinx/ml501/sim/run/
make rtl-test TEST=vga VCD=1 PRELOAD_RAM=1 VCD_DELAY=xxx_ps END_TIME=yyy_ps
gtkwave ../out/vga.tar.gz

其中“TEST=vga”是指定本次仿真所使用的软件;“VCD=1”是指本次仿真将保存仿真波形数据到VCD文件;“PRELOAD_RAM=1”是指本次仿真将从RAM开始,具体请参考bootrom的相关代码(board.h中);“VCD_DELAY=xxx_ps”是指定VCD数据保存的开始时间,单位为ps;“END_TIME=yyy_ps”是指定仿真结束时间,当然如果软件指令执行完了,但是仿真时间还没到,也会结束仿真,可通过修改or1200_monitor.v中的相关代码来实现指令执行完之后等待END_TIME。

在仿真结束后,在../out/目录下会生成波形文件,通过gtkwave既可以打开,如果vcd文件太大,可利用modelsim的vcd2wlf工具将vcd文件转换成wlf格式,再用modelsim打开查看波形。仿真时间和转换时间都比较长,请耐心等待。


c,查看波形

通过gtkwave和modelsim,产看vga和i2c_master模块的相关寄存器和端口输出,确定没有任何问题。


6,下板验证

在RTL仿真并确认没有问题之后,我们就可以下板验证了,在用ise综合之前要先给vga和i2c模块分配对应的引脚。

并将板子的DVI接口连接到显示器。

综合完成之后,用iMPACT将bit文件下载到ML501开发板,运行adv_jtag_bridge,运行or32-elf-gdb,将vga.elf下载到内存,并运行。

这时,我们就可以看到显示器的输出了。下图就是我的运行结果:

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证


需要注意的是,如果这时你连接了ML501的串口到PC并打开putty的话,你还会看到如下打印信息:

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证


这说明,我们添加的vga_enh模块,和i2c_master模块都work了!!



7,小结

本小节,我们向ORPSoC中添加了vga_enh模块和i2c_master模块,并经过了仿真并最终下板验证。

Enjoy!

OpenRisc-64-添加VGA和I2C模块到ORPSoC并测试验证

上一篇:Rational Rose的问题


下一篇:HTTP协议探索之Cache-Control