[原创] 基于 LM3S的图形驱动库开发之底层驱动函数的编写

zhengjiewen   2010-11-19 08:23 楼主


在上一个文档中我给大家介绍了TI图形驱动库的结构,分为三层:显示驱动层,图形基元层,小工具层。其中显示驱动层是需要我们程序员自己补充的。现在我们来具体谈谈如果来补充和书写底层驱动函数。


ti的文档中我们可以看出,我们需要补充的就是tDisplay这样一个结构体。这个结构体的具体定义如下:

typedef struct



{


//


//! The size of this structure.


//

    long lSize;

   
//


//! A pointer to display driver-specific data.


//

 

    void *pvDisplayData;


//



//! The width of this display.


//


unsigned short usWidth;


//


//! The height of this display.


//

 

    unsigned short usHeight;


//



//! A pointer to the function to draw a pixel on this display.


//


void (*pfnPixelDraw)(void *pvDisplayData, long lX, long lY,

                       unsigned long
ulValue);

   
//


//! A pointer to the function to draw multiple pixels on this display.


//

   void (*pfnPixelDrawMultiple)(void
*pvDisplayData, long lX, long lY,

                                 long lX0, long
lCount, long lBPP,

                                 const unsigned
char *pucData,

                                 const unsigned
char *pucPalette);

   
//



[ 本帖最后由 zhengjiewen 于 2010-11-19 08:31 编辑 ]

回复评论 (30)

//! A pointer to the function to draw a horizontal line on this display.
    //
    void (*pfnLineDrawH)(void *pvDisplayData, long lX1, long lX2, long lY,
                         unsigned long ulValue);

    //
    //! A pointer to the function to draw a vertical line on this display.
    //
    void (*pfnLineDrawV)(void *pvDisplayData, long lX, long lY1, long lY2,
                         unsigned long ulValue);

    //
    //! A pointer to the function to draw a filled rectangle on this display.
    //
    void (*pfnRectFill)(void *pvDisplayData, const tRectangle *pRect,
                        unsigned long ulValue);

    //
    //! A pointer to the function to translate 24-bit RGB colors to
    //! display-specific colors.
    //
    unsigned long (*pfnColorTranslate)(void *pvDisplayData,
                                       unsigned long ulValue);

    //
    //! A pointer to the function to flush any cached drawing operations on
    //! this display.
    //
    void (*pfnFlush)(void *pvDisplayData);
}
tDisplay;

每个成员的具体含义如下:
(1)        long lSize  这是一个存储这个结构体大小的数据,通常我们直接赋值为sizeof(tDisplay).
(2)        void *pvDisplayData; 指向驱动层的数据指针。这个可以先跳过。
(3)        unsigned short usWidth; LCD的水平方向像素值。
(4)        unsigned short usHeight; LCD垂直方向像素值。
(5)        void *pvDisplayData 一个指向驱动层数据的指针,这个指针可以用来做lcd显示RAM外buffer之用。但是我们没有用到这种方式,所以在结构里可以直接赋值为0.
(6)            void (*pfnPixelDrawMultiple)(void *pvDisplayData, long lX, long lY,
                                 long lX0, long lCount, long lBPP,
                                    const unsigned char *pucData,
                                 const unsigned char *pucPalette);
点赞  2010-11-19 08:27
很显然,这是一个函数指针,指向了一个绘制多像素点的函数,这个函数使用补充的调色板来绘制水平像素序列。实际是被驱动库里绘制图像的函数调用(GrimageDraw()).

(4)    void (*pfnLineDrawH)(void *pvDisplayData, long lX1, long lX2, long lY,
                         unsigned long ulValue);
绘制水平线的函数指针,指向的函数需要传入的是这个线的起始x,y坐标,线的终止x坐标。以及绘制的颜色(ulValue)。

(5)void (*pfnLineDrawV)(void *pvDisplayData, long lX, long lY1, long lY2,
                         unsigned long ulValue);
绘制竖直线的函数指针,指向的函数需要传入的是这个线的起始x,y坐标,线的终止y坐标。以及绘制的颜色(ulValue)。
(6)    void (*pfnRectFill)(void *pvDisplayData, const tRectangle *pRect,
                        unsigned long ulValue);
绘制矩形填充的函数指针。指向的函数需要传入一个指向tRectangle的结构指针。同时传入这个矩形的绘制颜色ulValue.其中tRectangle的定义如下:
typedef struct
{
    //
    //! The minimum X coordinate of the rectangle.
    //
    short sXMin;

    //
    //! The minimum Y coordinate of the rectangle.
    //
    short sYMin;

    //
    //! The maximum X coordinate of the rectangle.
    //
    short sXMax;

    //
    //! The maximum Y coordinate of the rectangle.
    //
    short sYMax;
}
tRectangle;
可以看出这个结构体里的参数就是这个矩形的四个顶点的确定,通过四个点,可以确定这个矩形的范围。
(6)unsigned long (*pfnColorTranslate)(void *pvDisplayData,
                                       unsigned long ulValue);
点赞  2010-11-19 08:27
这个函数指针指向的函数实现了颜色的转换,为何要转换?原因是上层API传来的颜色数据都是24BIT的RGB888,但是现在我们用的lcd用24BIT真彩的还是很少。以RGB565为多。也就是16bit位一个像素点,6.5k色。那么我们需要补充这样一个函数,可以实现颜色的转换。


(7)void (*pfnFlush)(void *pvDisplayData);

清出缓冲区的数据。这个函数出来清除屏外buffer中的数据。

重要说明:1.大家可能看到了有void *pvDisplayData这个参数。这个实用于把lcd直接映射到CPU的清况。因为现在8962或6911上没有引出内部总线。不能完成LCD存储映射。所以,这个参数可以以0直接代替。


那么以上是对tDisplay这个结构体的一个介绍。那么现在让我以LM3S8962为例子,说明具体的函数如何编写

我的lcd是SSD1963的驱动。控制和数据接口为: RS、RD、WR、CS、RST、DB0-DB18。由于8962上I/O资源有限。所以我选用了8位接口方式。我们建立320x240_lcd_ssd1963.h和
320x240_lcd_ssd1963.c这个两个文件。在320x240_lcd_ssd1963.h中对硬件的接口做一个描述:
//****************************************************************************
//                              LCD接口定义
//****************************************************************************

#define  TFT_RST                GPIO_PORTB_BASE
#define  TFT_RST_PIN            GPIO_PIN_0

#define  TFT_RS                 GPIO_PORTE_BASE
#define  TFT_RS_PIN             GPIO_PIN_7

#define  TFT_CS                 GPIO_PORTE_BASE
#define  TFT_CS_PIN             GPIO_PIN_6

#define  TFT_WR                 GPIO_PORTE_BASE
#define  TFT_WR_PIN             GPIO_PIN_5

#define  TFT_RD                 GPIO_PORTE_BASE
#define  TFT_RD_PIN             GPIO_PIN_4


#define  LCD_RST_H              //GPIOPinWrite(TFT_RST, TFT_RST_PIN, 0xff);
#define  LCD_RST_L              //GPIOPinWrite(TFT_RST, TFT_RST_PIN, 0);
点赞  2010-11-19 08:27
#define  LCD_RD_H               GPIOPinWrite(TFT_RD, TFT_RD_PIN, 0xff);
#define  LCD_RD_L               GPIOPinWrite(TFT_RD, TFT_RD_PIN, 0);

#define  LCD_WR_H               GPIOPinWrite(TFT_WR, TFT_WR_PIN, 0xff);
#define  LCD_WR_L               GPIOPinWrite(TFT_WR, TFT_WR_PIN, 0);

#define  LCD_RS_H               GPIOPinWrite(TFT_RS, TFT_RS_PIN, 0xff);
#define  LCD_RS_L               GPIOPinWrite(TFT_RS, TFT_RS_PIN, 0);

#define  LCD_CS_H               GPIOPinWrite(TFT_CS, TFT_CS_PIN, 0xff);
#define  LCD_CS_L               GPIOPinWrite(TFT_CS, TFT_CS_PIN, 0);

#define  TFT_DATA_PORT          GPIO_PORTD_BASE      
#define  TFT_DATA               0x000000FF

强烈建议大家做开发的时候把硬件接口的定义以宏的形式保存在头文件中,这样以后的硬 件连接变了就只需要改变宏定义就可以了。非常方便。

同时在这个文件中对我们要定义的函数做extern 声明。这要那个c文件中包含这个头文件,就可以引用这里的函数了。声明如下:

extern void SSD1963_SetBacklight(unsigned char Brightness);

extern void LCDClearScreen(unsigned long color);

extern void SetPosition(unsigned long ulX,unsigned long ulY);

extern void LCDPixelDraw(void *pvDisplayData,long lX,
                         long lY, unsigned long ulValue);

extern void LCDlineDrawH(void *pvDisplayData,long lX1, long lX2,
                   long lY, unsigned long ulValue);

extern void LCDlineDrawV(void *pvDisplayData,long lX, long lY1,
                  long lY2, unsigned long ulValue);
extern void LCDRectFill(void *pvDisplayData, const tRectangle *pRect,
                                  unsigned long ulValue);

其中SSD1963_SetBacklight和LCDClearScreen这是自己补充的一个函数,对硬件初始化的时候很用得着。SetPosition也是补充的一个函数,可以对lcd当前绘制坐标进行设置。

现在我就以一个void LCDRectFill(void *pvDisplayData, const tRectangle *pRect,
                                  unsigned long ulValue);
点赞  2010-11-19 08:28
这个函数做一个说明。

这个函数完成的是在lcd上以指定的颜色完成矩形填充。在SSD1963上具体驱动代码如下:
//*****************************************************************************
//画一个填充的矩形
//*****************************************************************************
void LCDRectFill(void *pvDisplayData, const tRectangle *pRect,
                                  unsigned long ulValue)
{  
   
unsigned long count;  
unsigned long pixelsize=((pRect->sXMax)-(pRect->sXMin)+1)\
                        *((pRect->sYMax)-(pRect->sYMin)+1);



//设置x坐标
LCD_WRITE_CMD(0x2A);       
        LCD_WRITE_DATA(((pRect->sXMin)>>8)&0xff);            
        LCD_WRITE_DATA(pRect->sXMin);
        LCD_WRITE_DATA(((pRect->sXMax)>>8)&0xff);            
        LCD_WRITE_DATA(pRect->sXMax);

//设置y坐标
LCD_WRITE_CMD(0x2b);       
        LCD_WRITE_DATA(((pRect->sYMin)>>8)&0xff);            
        LCD_WRITE_DATA(pRect->sYMin);
        LCD_WRITE_DATA(((pRect->sYMax)>>8)&0xff);            
        LCD_WRITE_DATA(pRect->sYMax);  

   LCD_WRITE_CMD(0x2c); //准备写数据  

   for(count=0;count   {
  
     LCD_WRITE_COLOR(ulValue);
  
  }

  

}

可以看出这就是一个确定要写多少个像素点,在LCD上设置起始坐标,并做一个循环在lcd
点赞  2010-11-19 08:28

 上把像素点打出来的过程。还是很容易理解的。
同时我还要向大家说明一下unsigned long (*pfnColorTranslate)(void *pvDisplayData,
                                       unsigned long ulValue);
这个函数。在我这个LCD上是完成RGB888到RGB66的转换,函数体如下:
unsigned long
LCDColorTranslate(void *pvDisplayData,
                                        unsigned long ulValue)
{
    //
    // Translate from a 24-bit RGB color to a 5-6-5 RGB color.
    //
    return(DPYCOLORTRANSLATE(ulValue));
}

而DPYCOLORTRANSLATE是一个宏。原型如下:
//****************************************************************************
//              传输颜色数据到BUFFER 24bit to 18 bit
//****************************************************************************
#define DPYCOLORTRANSLATE(c)    ((((c) & 0x00fc0000) >> 6) |               \
                                 (((c) & 0x0000fc00) >> 4) |               \
                                 (((c) & 0x000000fc) >> 2))

可以看到通过这个宏,就可以实现RGB888到RGB66的转换。

其他的部分直接依此编写就好。

当大家完成了这些驱动函数的编写,那么你离使用驱动库还有一步之遥。就是把这些函数的指针添加到tDisplay这样的结构体来。那么我自己命名了一个MyDisplay这个结构体,并以函数指针和其他的一些参数做为填充。如下:

const tDisplay MyDisplay=
{
sizeof(tDisplay),
0,
320,       // LCD width
240,       // LCD height
LCDPixelDraw,//画点函数
LCDPixelDrawMultiple, //像素点子像素调色函数
LCDlineDrawH,
LCDlineDrawV,
LCDRectFill,
LCDColorTranslate,
LCDFlush,
};

 

 

只要补充好这个结构体,恭喜你,你已经可以使用TI的图形驱动库了。在下个文档里。我会向大家讲述如何用ti的库在lcd上显示基本的图形和字符。同时教会大家用ti提供的图形工具来生成自己的字库和图像。



 

[ 本帖最后由 zhengjiewen 于 2010-11-19 08:29 编辑 ]
点赞  2010-11-19 08:28
支持,支持~~~~~~~~~~~~~~~:D
点赞  2010-11-20 23:17

回复 8楼 0212009623 的帖子

:( 终于看到有兄弟支持我了。。感动中。。。。
点赞  2010-11-21 15:58
学习了!改天有时间试试
点赞  2010-11-21 22:13
:D 顶!
juchina
点赞  2010-11-22 19:05

回复 11楼 juchina 的帖子

点赞  2010-11-23 12:34
楼主,能否解释下PixelDrawMultiple函数的参数,及此函数的编写,没有看明白。谢谢了
点赞  2010-12-9 15:26

学习了!改天有时间试试

学习了!改天有时间试试
hj
点赞  2010-12-21 13:39

回复 13楼 hl14 的帖子

PixelDrawMultiple就是一个用调色板画像素电的过程,1BPP,4BPP,8BPP不太一样。你可以结合TI驱动库代码研究一下,也就明白了。
点赞  2011-1-16 17:30
支持 呵呵 谢谢,看了楼主不少帖,写的很好,赞一个
zhuyingchun
点赞  2011-1-18 21:13

讲的不错

支持......................
学习中
http://www.tdhj.cn
点赞  2011-1-19 15:06
贊,頂起
追尋沒有止境
点赞  2011-1-19 15:06
楼主牛人那!在这里支持一下!!
点赞  2011-5-27 21:16

忍不住赞美一下

感谢楼主讲的如此清晰,虽然还没有完全明白,不过已经有些思路了
相信自己,相信未来
点赞  2011-7-20 11:26
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复