注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
liufan的个人空间 https://home.eeworld.com.cn/space-uid-53362.html [收藏] [复制] [分享] [RSS]
日志

[原创]嵌入式平台LCD 液晶屏底层时序调试的一种方法

已有 1716 次阅读2014-2-1 01:36 |个人分类:ARM| 液晶屏, 控制器, 寄存器, 嵌入式, 时序

嵌入式平台LCD 液晶屏底层时序调试的一种方法---原创(转载请留出处)

在用ARM的驱动LCD的时候,首先要做的就是将一块全新的屏进行驱动时序的调试,如果每次都将修改好了参数再烧录,一操作繁琐,二不直观。想到一个比较好的方法,说一说,其实很简单,就是在单步调试的状态下,手工修改LCD相关寄存器的值,实时看效果。是用ADS的朋友,可能知道,在ADS下,设备外设寄存器只能通过MEM窗口查看,需要手工输入寄存器地址,很是繁琐,而且不直观,也容易看错。方法如下:

定义一个基于寄存器字段的位定义联合体类型,以S3C2440LCD控制器为例,和LCD时序相关的寄存器是,LCDCON2LCDCON3LCDCON4,定义如下。

/*** LCDCON2 - LCDCON2 Register; 0x4d000004 ***/

typedef union {

  int Word;

  struct {

      int bVSPW:              6;   // 低位

      int bVFPD:              8;

      int bLINEVAL:           10;

      int bVBPD:              8;   //  高位

  } Bits;

} LCDCON2STR;

如果用过飞思卡尔MCU的朋友,对这个应该不会陌生,这是参照了飞思卡尔MCU寄存器定义的方式做的。用起来很爽的,呵呵。有兴趣的朋友可以找找飞思卡尔MCU的芯片头文件看看。可以学到不少东西。接着往下,LCDCON3LCDCON4 的定义如下:

/*** LCDCON3 - LCDCON3 Register; 0x4d000008 ***/

typedef union {

  int Word;

  struct {

      int bLineblank_hfpd:    8;

      int bHozval:            11;

      int bWdly_hbpd:         7;

         int rev1:               6;  //  未定义的位

  } Bits;

} LCDCON3STR;

/*** LCDCON4 - LCDCON4 Register; 0x4d00000C ***/

typedef union {

  int Word;

  struct {

      int bWLH_HSPW:    8;

      int bMVAL:            8;

         int rev1:                  16; 

  } Bits;

} LCDCON4STR;

如何使用呢?有经验的朋友,肯定能想到使用指针,是的,哈哈,卖关子啦。就是指针啦。通过定义一个相关联合体指针,然后赋予寄存器绝对地址,如下:

volatile LCDCON2STR* LcdC_2 = (volatile LCDCON2STR *)&rLCDCON2;

volatile LCDCON3STR* LcdC_3 = (volatile LCDCON3STR *)&rLCDCON3;

volatile LCDCON4STR* LcdC_4 = (volatile LCDCON4STR *)&rLCDCON4;

或者如下:

volatile LCDCON2STR* LcdC_2 = (volatile LCDCON2STR *)0x4d000004 ;

volatile LCDCON3STR* LcdC_3 = (volatile LCDCON3STR *)0x4d000008 ;

volatile LCDCON4STR* LcdC_4 = (volatile LCDCON4STR *)0x4d00000C ;

那么在调试的时候,就可以在ADS中通过添加变量的方式来查看相关寄存器的值,在调试挂起状态的时候,就可以方便的用手工修改相关寄存器位域的值,很简单,很直观,见下图的变量显示:

 

 在挂起调试的时候,通过实时修改这些值,能实时的看到LCD上面的显示是否正确。

直到显示正确,然后记录下那些位域的值,再回写到你的底层驱动配置代码中去。一次就搞定啦。呵呵。我这里使用的是TQ2440的板子,我这里以官方发布的裸奔测试进行了添加,文件名是TQ2440_Test_20100607,通过宏开关来使能调试功能,限于篇幅,我只把变动的部分贴上来。很简单。只需要改改main.c文件就可以了。

main.c文件中添加:

 

#define DEBUG_LCD  // 调试LCD开关,不用的话,注释掉就可了。

 

#ifdef DEBUG_LCD

#include "lcd_tft.h"

/* 联合体定义的外设寄存器 */

/*** LCDCON2 - LCDCON2 Register; 0x4d000004 ***/

typedef union {

  int Word;

  struct {

      int bVSPW:              6;

      int bVFPD:              8;

      int bLINEVAL:           10;

      int bVBPD:              8;

  } Bits;

} LCDCON2STR;

//#define _LCDCON2      (*(volatile LCDCON2STR *)0x4d000004)

#define LCDCON2                         _LCDCON2.Word

#define LCDCON2_VBPD                    _LCDCON2.Bits.bVBPD

#define LCDCON2_LINEVAL                 _LCDCON2.Bits.bLINEVAL

#define LCDCON2_VFPD                       _LCDCON2.Bits.bVFPD

#define LCDCON2_VSPW                       _LCDCON2.Bits.bVSPW

/*** LCDCON3 - LCDCON3 Register; 0x4d000008 ***/

typedef union {

  int Word;

  struct {

      int bLineblank_hfpd:    8;

      int bHozval:            11;

      int bWdly_hbpd:         7;

         int rev1:               6;

  } Bits;

} LCDCON3STR;

//#define _LCDCON3      (*(volatile LCDCON3STR *)0x4d000008)

#define LCDCON3                         _LCDCON3.Word

#define LCDCON3_LINEBLANK               _LCDCON3.Bits.bLineblank_hfpd

#define LCDCON3_HFPD                        _LCDCON3.Bits.bLineblank_hfpd

#define LCDCON3_HOZVAL                  _LCDCON3.Bits.bHozval

#define LCDCON3_HBPD                       _LCDCON3.Bits.bWdly_hbpd

#define LCDCON3_WDLY                      _LCDCON3.Bits.bWdly_hbpd

 

/*** LCDCON4 - LCDCON4 Register; 0x4d00000C ***/

typedef union {

  int Word;

  struct {

      int bWLH_HSPW:    8;

      int bMVAL:            8;

         int rev1:                  16;

  } Bits;

} LCDCON4STR;

//#define _LCDCON4      (*(volatile LCDCON4STR *)0x4d00000C)

#define LCDCON4                         _LCDCON4.Word

#define LCDCON4_WLH                           _LCDCON4.Bits.bWLH_HSPW

#define LCDCON4_HSPW                        _LCDCON4.Bits.bWLH_HSPW

#define LCDCON4_MVAL                       _LCDCON4.Bits.bMVAL

 

#define GUI_BLUE          0xFF0000

#define GUI_GREEN         0x00FF00

#define GUI_RED           0x0000FF

#define GUI_CYAN          0xFFFF00    // 青色

#define GUI_MAGENTA       0xFF00FF  // 品红

#define GUI_YELLOW        0x00FFFF

#define GUI_WHITE         0xFFFFFF

#define GUI_BLACK         0x000000

 

#define RGB2RGB565(rgb)       ((WORD)(((((WORD)((rgb)>>3))&(0x1F))<<11) \

|((((WORD)((rgb)>>10))&(0x3F))<<5) \

|(((WORD)((rgb)>>19))&(0x1F))))

//===================================================================//

volatile LCDCON2STR* LcdC_2;

volatile LCDCON3STR* LcdC_3;

volatile LCDCON4STR* LcdC_4;

extern void Glib_FilledRectangle(int x1,int y1,int x2,int y2,int color);

 

#define RECT_BOX_WITHD                    3

#define RECT_BOX_COLOR                    RGB2RGB565(GUI_YELLOW)  

#define RECT_COLOR                        RGB2RGB565(GUI_BLUE)

//===================================================================//

#endif

main函数修改如下:只添加了红色部分代码

void Main(void)

{

       char *mode;

       int i;

       U8 key;

       U32 mpll_val = 0 ;

       //U32 divn_upll = 0 ;

   

       #if ADS10  

//     __rt_lib_init(); //for ADS 1.0

       #endif

 

       Port_Init();

      

       Isr_Init();

      

       i = 2 ;     //don't use 100M!

       switch ( i ) {

       case 0:   //200

              key = 12;

              mpll_val = (92<<12)|(4<<4)|(1);

              break;

       case 1:   //300

              key = 13;

              mpll_val = (67<<12)|(1<<4)|(1);

              break;

       case 2:   //400

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       case 3:   //440!!!

              key = 14;

              mpll_val = (102<<12)|(1<<4)|(1);

              break;

       default:

              key = 14;

              mpll_val = (92<<12)|(1<<4)|(1);

              break;

       }

      

       //init FCLK=400M, so change MPLL first

       ChangeMPllValue((mpll_val>>12)&0xff, (mpll_val>>4)&0x3f, mpll_val&3);

       ChangeClockDivider(key, 12);

       cal_cpu_bus_clk();

      

       consoleNum = 0; // Uart 1 select for debug.

       Uart_Init( 0,115200 );

       Uart_Select( consoleNum );

      

       Beep(2000, 100);

      

       Uart_SendByte('\n');

       Uart_Printf("<***************************************>\n");

       Uart_Printf("               TQ2440 Test Program\n");

       Uart_Printf("                www.embedsky.net\n");

//     Uart_Printf("      Build time is: %s  %s\n", __DATE__ , __TIME__  );

       Uart_Printf("<***************************************>\n");

 

       rMISCCR=rMISCCR&~(1<<3); // USBD is selected instead of USBH1

       rMISCCR=rMISCCR&~(1<<13); // USB port 1 is enabled.

 

 

       rDSC0 = 0x2aa;

       rDSC1 = 0x2aaaaaaa;

       //Enable NAND, USBD, PWM TImer, UART0,1 and GPIO clock,

       //the others must be enabled in OS!!!

       rCLKCON = 0xfffff0;

 

       MMU_Init();       //

 

       pISR_SWI=(_ISR_STARTADDRESS+0xf0);   //for pSOS

 

       Led_Display(0x66);

 

       mode="DMA";

 

       Clk0_Disable();

       Clk1_Disable();

      

       mpll_val = rMPLLCON;

      

//=============================================================================

#ifndef DEBUG_LCD

       Lcd_TFT_Init() ;        // LCD initial

#else

       Lcd_Init();  

       Lcd_PowerEnable(0, 1);

       Lcd_EnvidOnOff(1);              //turn on vedio

       Glib_FilledRectangle(0,0,LCD_XSIZE_TFT-1,LCD_YSIZE_TFT-1,RECT_BOX_COLOR);

       Glib_FilledRectangle(       RECT_BOX_WITHD,

                                                 RECT_BOX_WITHD,

                                                 LCD_XSIZE_TFT-1-RECT_BOX_WITHD,

                                                 LCD_YSIZE_TFT-1-RECT_BOX_WITHD,

                                                 RECT_COLOR);

      

       LcdC_2 = (volatile LCDCON2STR *)&rLCDCON2;

       LcdC_3 = (volatile LCDCON3STR *)&rLCDCON3;

       LcdC_4 = (volatile LCDCON4STR *)&rLCDCON4;

#endif

 

//=============================================================================

       download_run=1; //The default menu is the Download & Run mode.

      

       while(1)

       {

#ifndef DEBUG_LCD

 

              U8 idx;

             

              Uart_Printf("\nPlease select function : \n");

              for(i=0; CmdTip[i].fun!=0; i++)

                     Uart_Printf("%d : %s\n", i, CmdTip[i].tip);

              idx = Uart_GetIntNum_GJ() ;

              if(idx<i)

              {

                     (*CmdTip[idx].fun)();

                     Delay(20);

                     Uart_Init( 0,115200 );

              }

#endif

       }         

}

 

编译后,加载进SDRAM或者FALSH,将3个指针变量添加进变量表中,然后全速运行,再点击挂起。进入单步运行模式,然后就可以直接修改相关位域进行LCD的时序的调试了。程序不要运行。

 

关于联合体位域的其他应用说明

 

/* 联合体定义的外设寄存器 */

/*** LCDCON2 - LCDCON2 Register; 0x4d000004 ***/

typedef union {

  int Word;

  struct {

      int bVSPW:              6;

      int bVFPD:              8;

      int bLINEVAL:           10;

      int bVBPD:              8;

  } Bits;

} LCDCON2STR;

#define _LCDCON2        (*(volatile LCDCON2STR *)0x4d000004)

#define LCDCON2                         _LCDCON2.Word

#define LCDCON2_VBPD                    _LCDCON2.Bits.bVBPD

#define LCDCON2_LINEVAL                 _LCDCON2.Bits.bLINEVAL

#define LCDCON2_VFPD                       _LCDCON2.Bits.bVFPD

#define LCDCON2_VSPW                       _LCDCON2.Bits.bVSPW

 

这个联合体下方的定义,可以在应用中,方便我们编程和调试,很直观。把2种应用方式列一下:

方式1

LCDCON2_VBPD = VBPD;

LCDCON2_LINEVAL = LINEVAL_TFT;

LCDCON2_VFPD = VFPD;

LCDCON2_VSPW = VSPW;

方式2

rLCDCON2 = (VBPD << 24)|(LINEVAL_TFT << 14)|(VFPD << 6)|(VSPW);

 

方式12实现了同样的功能。很明显,方式1非常直观和方便。

 

朋友,由此你是否想将你的MCU的寄存器头文件都定义成这样子呢?呵呵。

 

如果你真那么干的话,千万不要忘记给我传一份你定义好的头文件啊!

 

 

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章