⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 skyeye硬件模拟平台,第三部分 硬件仿真实现之五.htm

📁 你想没有硬件就跑μc OS吗
💻 HTM
📖 第 1 页 / 共 4 页
字号:
      <P><A name=IDAIDQTB><B>图 0-2 SkyEye中基于ep7312的LCD模拟流程图</B></A><BR><IMG 
      height=325 alt="图 0-2 SkyEye中基于ep7312的LCD模拟流程图" 
      src="SkyEye硬件模拟平台,第三部分 硬件仿真实现之五.files/image005.gif" width=559 border=0 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"></P>
      <P>LCD模拟模块的实现先后采用了两种方案,在第一种方案中,在SkyEye的内存模拟模块中,在每一次的写内存操作之后判断其地址是否属于LCD显示内存的地址范围,如果在该范围之内则调用LCD模拟模块中的GTK+画点函数gdk_draw_point(),根据由像素值查找彩色查找表CLUT得到的RGB值(对于真彩色,颜色深度为16,24,32时,RGB值可以直接由像素值得到),在模拟屏幕窗口的相应位置画一个相应灰度或颜色的点。</P>
      <P>该方案的优点在于实现起来简单,且模拟了真实的LCD最基本的画点动作,对于图像随时间流逝而只有小范围变化的情况具有一定的优势,因为对显存有写操作时才有画点操作,但是也有两个方面的缺点,其一,与SkyEye模拟器的内存模拟模块耦合紧密,破坏了模块间的独立性;其二,对于图像随时间流逝而大范围变化的情况,本方案效率低下,在LCD驱动程序连续的每两次写显存操作中,都要经历一个单位延迟时间,其长度等于一次地址范围的判断,一次CLUT查找及一次GTK+画点函数的调用所耗费的时间,对于一次全屏操作,以320x240x8为例,若以字节为单位写显存,则额外的时间延迟将320x240x8/8=76800倍于单位延迟时间。</P>
      <P>而第二种方案则直接定时(时间间隔可调,例如设置成200ms) 
      调用GTK+的绘图函数gdk_draw_rgb_image()将显存中的数据一次性绘制到窗口中。该方案模拟了DMA的定时扫描方式,与真实的DMA方式不同的是,在真实的硬件上,DMA方式无须CPU参与,可与CPU并行工作,而用软件模拟的硬件无法做到这一点,只能串行地定时扫描显示内存,其时间延迟不可避免的比真实硬件大。</P>
      <P>第二方案降低了LCD模拟模块与内存模拟模块之间的耦合度,其缺点是不能实时地反映显存的快速变化。如果将定时间隔设置得过大,则增大了窗口内容刷新时的闪烁;如果定时间隔设置得过小,定时扫描过于频繁地发生,对系统资源是一种浪费。</P>
      <P><A name=IDAZDQTB><SPAN class=atitle3>2. 
      SkyEye中的LCD模拟分析</SPAN></A><BR>SkyEye的lcd仿真首先是在模拟ep7312时实现的,所以在本文分析lcd仿真时是以ep7312的lcd模块为例,对于模拟其它的开发板时添加lcd模块的方法是一样的。在SkyEye源码中的clps7110.h文件中有如下定义:</P><A 
      name=IDA5DQTB><B></B></A><BR>
      <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc 
        border=1><TBODY>
        <TR>
          <TD><PRE><CODE>
//lcd控制寄存器地址
#define LCDCON	0x02c0	/* LCD Control register */

#define VBUFSIZ	0x00001fff  /* Video buffer size (bits/128-1) */
#define LINELEN	0x0007e000  /* Line length (pix/16-1) */
#define LINELEN_SHIFT	13
#define PIXPSC	0x01f80000  /* Pixel prescale (526628/pixels-1) */
#define PIXPSC_SHIFT	19
#define ACPSC	0x3e000000  /* AC prescale */
#define ACPSC_SHIFT	25

//下面两个控制lcd是单色、4级灰度或16级灰度(每个像素点有几位决定灰度级)
#define GSEN	0x40000000  /* Grayscale enable (0: monochrome) */
#define GSMD	0x80000000  /* Grayscale mode (0: 2 bit, 1: 4 bit) */

//SYSCON寄存器的一位,控制lcd是否enable(SYSCON就是state-&gt;io.syscon)
#define	LCDEN	0x00001000  /* LCD enable */
</CODE></PRE></TD></TR></TBODY></TABLE>
      <P>在SkyEye源码中的skyeye_lcd. c文件中有如下定义:</P>
      <P><CODE>#define LCD_BASE 0xC0000000 // lcd显示内存起始地址</CODE></P>
      <P>在SkyEye源码中的skyeye_mach_ep7312.c文件中有:</P><A 
name=IDAMEQTB><B></B></A><BR>
      <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc 
        border=1><TBODY>
        <TR>
          <TD><PRE><CODE>
state-&gt;mach_io.lcdcon			=(ARMword *)&amp;io.lcdcon;        // lcd控制寄存器
state-&gt;mach_io.lcd_is_enable		=(ARMword *)&amp;io.lcd_is_enable;	  // 是否打开lcd
state-&gt;mach_io.lcd_addr_begin	=(ARMword *)&amp;io.lcd_addr_begin; // lcd显示内存起始地址
state-&gt;mach_io.lcd_addr_end		=(ARMword *)&amp;io.lcd_addr_end;	  // lcd显示内存结束地址
</CODE></PRE></TD></TR></TBODY></TABLE>
      <P>在ep7312_io_do_cycle函数中也就是每个时钟后会调用:</P>
      <P>skyeye_config.mach-&gt;mach_io_do_cycle(state);<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">SkyEye模拟ep7312时,会在skyeye_mach_ep7312.c中的函数ep7312_mach_init注册<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">this_mach-&gt;mach_io_do_cycle 
      = ep7312_io_do_cycle;<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">在ep7312_io_do_cycle中调用lcd_cycle,这里<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">lcd_cycle(state)=gtk_main_iteration_do(FALSE);<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">检查gtk窗口是否有事件需要处理,没有则立即返回。</P>
      <P>ep7312_io_read_word函数中:<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">   如果读LCDCON寄存器的地址<BR 
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">    返回 data = 
      state-&gt;io.lcdcon;</P><A name=IDAGFQTB><B></B></A><BR>
      <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc 
        border=1><TBODY>
        <TR>
          <TD><PRE><CODE>
switch (addr - 0x80000000) {
//如果用户写系统控制寄存器,让lcd的状态从关闭变为打开,则重新初始化lcd。
	case SYSCON:
		tmp = io.syscon;
		io.syscon = data;
                //chy 2004-03-11
                if ((tmp &amp; LCDEN) != (data &amp; LCDEN)) {
                        ep7312_update_lcd(state);
                }
		break;
   … …
//如果用户改写lcd控制寄存器,改变lcd的控制参数,则重新初始化lcd
	case LCDCON:
		tmp = io.lcdcon;
		io.lcdcon = data;
		//chy 2004-03-11 tmp compare with data
                if ((tmp &amp; (VBUFSIZ|LINELEN|GSEN|GSMD)) != (data &amp; (VBUFSIZ|LINELEN|GSEN|GSMD))) {
                        ep7312_update_lcd(state);
                }
		break;
    … …
}

//在应用程序改写SYSCON或LCDCON时,重新初始化LCD时被调用
static void ep7312_update_lcd(ARMul_State *state)
{
        ep7312_lcd_disable(state);
        if (io.syscon &amp; LCDEN) {
                ARMword lcdcon = io.lcdcon;
                ARMword vbufsiz = lcdcon &amp; VBUFSIZ;
                ARMword linelen = (lcdcon &amp; LINELEN) &gt;&gt; LINELEN_SHIFT;
                int width, height, depth;
                switch (lcdcon &amp; (GSEN|GSMD)) {
                case GSEN:
                        depth = 2;
                        break;
                case GSEN|GSMD:
                        depth = 4;
                        break;
                default:
                        depth = 1;
                        break;
                }
                width = (linelen + 1) * 16;
                height = (vbufsiz + 1) * 128 / depth / width;
//以上是取得lcd的高,宽,像素位数(都从LCDCON寄存器中来)
		        //使用以上参数重新初始化lcd
                ep7312_lcd_enable(state, width, height, depth);
        }
}
</CODE></PRE></TD></TR></TBODY></TABLE>
      <P><A name=IDANFQTB><SPAN class=atitle3>3. 
      LCD相关函数分析</SPAN></A><BR>skyeye_lcd.c中的函数:</P><A 
      name=IDATFQTB><B></B></A><BR>
      <TABLE cellSpacing=0 cellPadding=5 width="100%" bgColor=#cccccc 
        border=1><TBODY>
        <TR>
          <TD><PRE><CODE>
//当LCDCON寄存器被改写时,调用lcd_enable重新初始化lcd仿真屏幕窗口
void lcd_enable(ARMul_State *state, int width, int height, int depth)
{
   	int i;
	static int once = 0;
	GdkColor tmpColor;
	char * title;
	char mode[100];
		
if(skyeye_config.no_lcd){
		return;
	}//如果不使用lcd,则返回
	if (!once) {
		once++;
		gtk_init(&amp;global_argc, &amp;global_argv);
	}//只在第一次运行时初始化一个gtk模拟出的lcd屏幕窗口

	lcd_width = width;    //lcd仿真屏幕宽度
	lcd_height = height;   //lcd仿真屏幕高度
	lcd_depth = depth;    //表示一个象素所用的bit数(决定颜色深度)
   	*(state-&gt;mach_io.lcd_is_enable)=1;

//根据显示模式计算lcd显示内存的结束地址
	*(state-&gt;mach_io.lcd_addr_end) = *(state-&gt;mach_io.lcd_addr_begin) + (width * height * depth / 8);

printf("SKYEYE:  lcd_addr_begin 0x%x,lcd_addr_end 0x%x, width %d, height %d, depth %d\n",*(state-&gt;mach_io.lcd_addr_end), 
*(state-&gt;mach_io.lcd_addr_begin),width, height,depth);	
//建立顶层窗口
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
//初始化gtk窗口,包括窗口标题,窗口大小等
    title="SkyEye_LcdScreen_TouchScreen ";
    sprintf(mode,"%s%dx%dx%d",title,lcd_width,lcd_height,lcd_depth);
    gtk_window_set_title(window, mode);
	gtk_widget_set_usize(window, width, height);

   //把"expose_event"和顶层窗口的信号处理器联系起来
	gtk_signal_connect(GTK_OBJECT(window), "expose_event",
						(GtkSignalFunc)expose_event, NULL);
	gtk_widget_set_events(window, GDK_EXPOSURE_MASK);
	
//建立触摸屏仿真事件盒容器,这在skyeye的触摸屏仿真中会用到,此处不进行详细分析
	TouchScreen = gtk_event_box_new ( );	
    gtk_container_add (GTK_CONTAINER (window), TouchScreen);
	gtk_widget_set_events(GTK_OBJECT(TouchScreen), GDK_ENTER_NOTIFY_MASK
				        | GDK_LEAVE_NOTIFY_MASK
						 | GDK_BUTTON_PRESS_MASK
						 | GDK_BUTTON_RELEASE_MASK
						 | GDK_POINTER_MOTION_HINT_MASK);
 
	gtk_signal_connect (GTK_OBJECT(TouchScreen), "button-press-event",
                    GTK_SIGNAL_FUNC (callback_button_press), NULL);
	gtk_signal_connect (GTK_OBJECT(TouchScreen), "button-release-event",
                    GTK_SIGNAL_FUNC (callback_button_release), NULL);
	gtk_signal_connect (GTK_OBJECT(TouchScreen), "motion-notify-event",
                    GTK_SIGNAL_FUNC (callback_motion_notify), NULL);
    gtk_widget_show (TouchScreen);
	gtk_widget_realize (TouchScreen);
    gdk_window_set_cursor (TouchScreen-&gt;window,gdk_cursor_new (GDK_HAND2)); 
   
   //建立LCD屏幕仿真绘图窗口
	LCD = gtk_drawing_area_new ();
	gtk_container_add (GTK_CONTAINER (TouchScreen), LCD);
    //显示LCD屏幕仿真绘图窗口
    gtk_widget_show (LCD);
	//显示顶层窗口
	gtk_widget_show(window);

	colormap = gdk_window_get_colormap(LCD-&gt;window);
    /*单色,4色,16色,256色都需要调色板调出RGB颜色*/
    switch (lcd_depth) {
                case 1: 
 for (i = 0; i &lt; 2; i++){
                            tmpColor= color2[i];	
			                  gdk_color_alloc (colormap, &amp;tmpColor);
			                  gc[i] = gdk_gc_new(LCD-&gt;window);
		                      gdk_gc_set_foreground(gc[i], &amp;tmpColor);
		                 }                     
                        break;
                case 2:  
                        for (i = 0; i &lt; 4; i++){
                            tmpColor= color4[i];	
			                  gdk_color_alloc (colormap, &amp;tmpColor);
			                  gc[i] = gdk_gc_new(LCD-&gt;window);
		                     gdk_gc_set_foreground(gc[i], &amp;tmpColor);
		                 }                      
                        break;
                case 4:
                        for (i = 0; i &lt; 16; i++){
                            tmpColor= color16[i];	
			                  gdk_color_alloc (colormap, &amp;tmpColor);
			                  gc[i] = gdk_gc_new(LCD-&gt;window);
		                     gdk_gc_set_foreground(gc[i], &amp;tmpColor);
		                  }
		                  break;
                case 8: 
                         for (i = 0; i &lt; 256; i++){
                            tmpColor= color256[i];                        	
			                  gdk_color_alloc (colormap, &amp;tmpColor);
			                 gc[i] = gdk_gc_new(LCD-&gt;window);
		                     gdk_gc_set_foreground(gc[i], &amp;tmpColor);
		                  }
                         break;              
                default:                        
                        break;
                }
}
//对lcd屏幕仿真窗口重新初始化时,要先调用lcd_disable释放资源并关闭原来的窗口

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -