一口气转两个文档,发现对不起原著啊.必须先把人家放头位.
在上一个文档中我给大家介绍了TI图形驱动库的结构,分为三层:显示驱动层,图形基元层,小工具层。其中显示驱动层是需要我们程序员自己补充的。现在我们来具体谈谈如果来补充和书写底层驱动函数。
ti的文档中我们可以看出,我们需要补充的就是tDisplay这样一个结构体。这个结构体的具体定义如下:
//*****************************************************************************
//
//! This structure defines the characteristics of a display driver.
//
//*****************************************************************************
typedef struct
{
//
//! The size of this structure.
//
int 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, int lX, int lY,
unsigned int ulValue);
//
//! A pointer to the function to draw multiple pixels on this display.
//
void (*pfnPixelDrawMultiple)(void *pvDisplayData, int lX, int lY,
int lX0, int lCount, int lBPP,
const unsigned char *pucData,
const unsigned char *pucPalette);
//
//! A pointer to the function to draw a horizontal line on this display.
//
void (*pfnLineDrawH)(void *pvDisplayData, int lX1, int lX2, int lY,
unsigned int ulValue);
//
//! A pointer to the function to draw a vertical line on this display.
//
void (*pfnLineDrawV)(void *pvDisplayData, int lX, int lY1, int lY2,
unsigned int ulValue);
//
//! A pointer to the function to draw a filled rectangle on this display.
//
void (*pfnRectFill)(void *pvDisplayData, const tRectangle *pRect,
unsigned int ulValue);
//
//! A pointer to the function to translate 24-bit RGB colors to
//! display-specific colors.
//
unsigned int (*pfnColorTranslate)(void *pvDisplayData,
unsigned int 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);
很显然,这是一个函数指针,指向了一个绘制多像素点的函数,这个函数使用补充的调色板来绘制水平像素序列。实际是被驱动库里绘制图像的函数调用(GrimageDraw()).
(7) void (*pfnLineDrawH)(void *pvDisplayData, long lX1, long lX2, long lY,unsigned long ulValue);
绘制水平线的函数指针,指向的函数需要传入的是这个线的起始x,y坐标,线的终止x坐标。以及绘制的颜色(ulValue)。
(8) void (*pfnLineDrawV)(void *pvDisplayData, long lX, long lY1, long lY2,unsigned long ulValue);
绘制竖直线的函数指针,指向的函数需要传入的是这个线的起始x,y坐标,线的终止y坐标。以及绘制的颜色(ulValue)。
(9) 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;
可以看出这个结构体里的参数就是这个矩形的四个顶点的确定,通过四个点,可以确定这个矩形的范围。
(10) unsigned long (*pfnColorTranslate)(void *pvDisplayData,unsigned long ulValue);
24-bit真彩的还是很少。以RGB565为多。也就是16bit位一个像素点,6.5k色。那么我们需要补充这样一个函数,可以实现颜色的转换。
(11) void (*pfnFlush)(void *pvDisplayData);
清出缓冲区的数据。这个函数出来清除屏外buffer中的数据。
重要说明:大家可能看到了有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);
#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);这个函数做一个说明。这个函数完成的是在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<pixelsize;count++)
{
LCD_WRITE_COLOR(ulValue);
}
}
可以看出这就是一个确定要写多少个像素点,在LCD上设置起始坐标,并做一个循环在lcd上把像素点打出来的过程。还是很容易理解的。
同时我还要向大家说明一下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提供的图形工具来生成自己的字库和图像。
//****************************************************************************
// 传输颜色数据到BUFFER 24bit to 18 bit
//****************************************************************************
#define DPYCOLORTRANSLATE(c) ((((c) & 0x00fc0000) >> 6) | \
(((c) & 0x0000fc00) >> 4) | \
(((c) & 0x000000fc) >> 2))
const tDisplay MyDisplay=
{
sizeof(tDisplay),
0,
320, // LCD width
240, // LCD height
LCDPixelDraw,//画点函数
LCDPixelDrawMultiple, //像素点子像素调色函数
LCDlineDrawH,
LCDlineDrawV,
LCDRectFill,
LCDColorTranslate,
LCDFlush,
};