安德鲁

[原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分) - TFT-LCD(控制器为ILI9325)驱动

0
阅读(4799)

准备资料

[整理].ILI9325 TFT驱动中文资料

编写驱动程序

步骤1 将ili9325的文件夹加入APP路径

 

步骤2 编写驱动文件

时间比较紧张,我就贴出来代码,挑重点的讲几句。

代码2.1 ili932x.h

#ifndef ILI932X_H_
	#define ILI932X_H_
	//
	#include "my_types.h"
	#include "my_regs.h"
	//
	#define White          0xFFFF
	#define Black          0x0000
	#define Blue           0x001F
	#define Blue2          0x051F
	#define Red            0xF800
	#define Magenta        0xF81F
	#define Green          0x07E0
	#define Cyan           0x7FFF
	#define Yellow         0xFFE0
	//
	#define ID_AM    110
	//
	#define DB_o_EN  ili_DB->DIRECTION=0xFF
	#define DB_i_EN  ili_DB->DIRECTION=0x00
	//
	void ili_WrDB_2x8b(u8 DH, u8 DL);
	void ili_WrCmd(u8 DH, u8 DL);
	void ili_WrData(u8 DH, u8 DL);
	void ili_WrReg(u8 cmd, u16 data);
	void ili_WrDB_16b(u16 data);
	//
	void ili_DelayMs(u32 n);
	void ili_Initial(void);
	void ili_SetCursor(u8 x, u16 y);
        void ili_SetDispArea(u16 x0, u16 y0, u8 xLength, u16 yLength, u16 xOffset, u16 yOffset);
	void ili_ClearScreen(u32 bColor);
	//
	void ili_PlotPoint(u8 x, u16 y, u16 color);
	void ili_PlotPixel(u8 x, u16 y, u16 color);
	void ili_PlotBigPoint(u8 x, u16 y, u16 color);
	//
	void ili_PutAscii_8x16(u16 x, u16 y, uc8 c, u32 fColor, u32 bColor);
	void ili_PutGb_16x16(u16 x, u16 y, uc8 c[2], u32 fColor, u32 bColor);
	void ili_PutString(u16 x, u16 y, uc8 *s, u32 fColor, u32 bColor);
	//
	void ili_DispColorBar(void);
	//
	#endif /* ILI932X_H_ */

注意第19~20行,定义两个宏来操纵8位DB双向总线的方向。

 

代码2.2 ili_932x.c

#include "ili932x.h"
	#include "unistd.h"       // usleep()
	#include "ascii_8x16.h"   // ascii码字库
	#include "GB16.h"         // 汉字字库
	 
	 
	// 8位总线模式,通过两次写操作写入高8位和低8位
	void ili_WrDB_2x8b(u8 DH, u8 DL)
	{   
	  ili_DB->DATA=DH;   
	  ili_nWR=0;
	    ili_nWR=1;
	    ili_DB->DATA=DL;   
	  ili_nWR=0;
	    ili_nWR=1;
	}
	 
	 
	// 写命令
	void ili_WrCmd(u8 DH, u8 DL)
	{
	  ili_RS=0; 
	  ili_WrDB_2x8b(DH, DL);
	}
	 
	 
	// 写数据
	void ili_WrData(u8 DH, u8 DL)
	{
	  ili_RS=1;
	  ili_WrDB_2x8b(DH, DL);
	}
	 
	 
	// 向DB总线写数据
	void ili_WrDB_16b(u16 data)
	{
	  ili_WrData(data>>8, data);
	}
	 
	 
	// 写寄存器
	void ili_WrReg(u8 cmd, u16 data)
	{
	  ili_WrCmd(0x00, cmd);
	  ili_WrDB_16b(data);
	}
	 
	 
	// 延时ms
	void ili_DelayMs(u32 n)
	{
	  usleep(n*1000);
	}
	 
	 
	// ILI93525初始化
	void ili_Initial(void)
	{
	  // 硬件复位
	  ili_nRST=0;
	  ili_DelayMs(1);
	  ili_nRST=1;
	  // 打开片选,输出使能
	  ili_nCS=0;
	  DB_o_EN;
	  //
	  ili_WrReg(0xE3, 0x3008);
	  ili_WrReg(0xE7, 0x0012);
	  ili_WrReg(0xEF, 0x1231); // Set the internal timing
	  ili_WrReg(0x01, 0x0000); // Set SS and SM bit
	  ili_WrReg(0x02, 0x0700); // Set 1 line inversion
	  // 屏幕旋转控制
	#if   ID_AM==000
	  ili_WrReg(0x03, 0x1000); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=00, AM=0
	#elif ID_AM==001
	  ili_WrReg(0x03, 0x1008); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=00, AM=0
	#elif ID_AM==010
	  ili_WrReg(0x03, 0x1010); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=01, AM=0
	#elif ID_AM==011
	  ili_WrReg(0x03, 0x1018); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=01, AM=1
	#elif ID_AM==100
	  ili_WrReg(0x03, 0x1020); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=10, AM=0
	#elif ID_AM==101
	  ili_WrReg(0x03, 0x1028); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=10, AM=1
	#elif ID_AM==110
	  ili_WrReg(0x03, 0x1030); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=11, AM=0
	#elif ID_AM==111
	  ili_WrReg(0x03, 0x1038); // TRI=0, DFM=x, BGR=0, HWM=0, ORG=0, I/D[1:0]=11, AM=1
	#endif
	  ili_WrReg(0x04, 0x0000); // Resize register
	  ili_WrReg(0x08, 0x0404); // Set the back porch and front porch
	  ili_WrReg(0x09, 0x0000); // Set non-display area refresh cycle ISC[3:0]
	  ili_WrReg(0x0A, 0x0000); // FMARK function
	  ili_WrReg(0x0C, 0x0000); // RGB interface setting
	  ili_WrReg(0x0D, 0x0000); // Frame marker Position
	  ili_WrReg(0x0F, 0x0000); // RGB interface polarity
	  // Power on sequence VGHVGL
	  ili_WrReg(0x10, 0x0000); // SAP, BT[3:0], AP, DSTB, SLP, STB
	  ili_WrReg(0x11, 0x0007); // DC1[2:0], DC0[2:0], VC[2:0]
	  ili_WrReg(0x12, 0x0000); // VREG1OUT voltage
	  ili_WrReg(0x13, 0x1300); // VDV[4:0] for VCOM amplitude
	  ili_WrReg(0x07, 0x0001);
	  ili_DelayMs(50);         // Dis-charge capacitor power voltage
	  ili_WrReg(0x10, 0x1590); // SAP, BT[3:0], AP, DSTB, SLP, STB
	  ili_WrReg(0x11, 0x0227); // DC1[2:0], DC0[2:0], VC[2:0]
	  ili_DelayMs(50);
	  ili_WrReg(0x12, 0x001E); // Internal reference voltage= Vci;
	  ili_DelayMs(50);
	  ili_WrReg(0x13, 0x1500); // Set VDV[4:0] for VCOM amplitude
	  ili_WrReg(0x29, 0x0026); // Set VCM[5:0] for VCOMH
	  ili_WrReg(0x2B, 0x000F); // Set Frame Rate
	  ili_DelayMs(50);
	  ili_WrReg(0x20, 0x0000);
	  ili_WrReg(0x21, 0x013f);
	  // GRAM起始位置
	#if   ID_AM==000
	  ili_WrReg(0x20, 0x00EF);
	  ili_WrReg(0x21, 0x013F);
	#elif ID_AM==001
	  ili_WrReg(0x20, 0x00EF);
	  ili_WrReg(0x21, 0x013F);
	#elif ID_AM==010
	  ili_WrReg(0x20, 0x0000);
	  ili_WrReg(0x21, 0x013F);
	#elif ID_AM==011
	  ili_WrReg(0x20, 0x0000);
	  ili_WrReg(0x21, 0x013F);
	#elif ID_AM==100
	  ili_WrReg(0x20, 0x00EF);
	  ili_WrReg(0x21, 0x0000);
	#elif ID_AM==101
	  ili_WrReg(0x20, 0x00EF);
	  ili_WrReg(0x21, 0x0000);
	#elif ID_AM==110
	  ili_WrReg(0x20, 0x0000);
	  ili_WrReg(0x21, 0x0000);
	#elif ID_AM==111
	  ili_WrReg(0x20, 0x0000);
	  ili_WrReg(0x21, 0x0000);
	#endif
	  // Adjust the Gamma Curve
	  ili_WrReg(0x30, 0x0007);
	  ili_WrReg(0x31, 0x0007);
	  ili_WrReg(0x32, 0x0107);
	  ili_WrReg(0x35, 0x0206);
	  ili_WrReg(0x36, 0x0406);
	  ili_WrReg(0x37, 0x0101);
	  ili_WrReg(0x38, 0x0101);
	  ili_WrReg(0x39, 0x0207);
	  ili_WrReg(0x3C, 0x0504);
	  ili_WrReg(0x3D, 0x0806);
	  // Set GRAM area
	  ili_WrReg(0x50, 0x0000); // Horizontal GRAM Start Address
	  ili_WrReg(0x51, 0x00EF); // Horizontal GRAM End Address
	  ili_WrReg(0x52, 0x0000); // Vertical GRAM Start Address
	  ili_WrReg(0x53, 0x013F); // Vertical GRAM Start Address
	  ili_WrReg(0x60, 0x2700); // Gate Scan Line
	  ili_WrReg(0x61, 0x0001); // NDL,VLE, REV
	  ili_WrReg(0x6A, 0x0000); // Set scrolling line
	  // Partial Display Control
	  ili_WrReg(0x80, 0x0000);
	  ili_WrReg(0x81, 0x0000);
	  ili_WrReg(0x82, 0x0000);
	  ili_WrReg(0x83, 0x0000);
	  ili_WrReg(0x84, 0x0000);
	  ili_WrReg(0x85, 0x0000);
	  // Panel Control
	  ili_WrReg(0x90, 0x0010);
	  ili_WrReg(0x92, 0x0600);
	  ili_WrReg(0x93, 0x0003);
	  ili_WrReg(0x95, 0x0110);
	  ili_WrReg(0x97, 0x0000);
	  ili_WrReg(0x98, 0x0000);
	  ili_WrReg(0x07, 0x0173); // 262K color and display ON
	  // 关闭片选
	  ili_nCS=1;
	}
	 
	 
	// 设定Cursor
	void ili_SetCursor(u8 x, u16 y)
	{
	  ili_WrReg(0x20, x);
	  ili_WrReg(0x21, y);
	}
	 
	 
	// 设定显示区域
	void ili_SetDispArea(u16 x0, u16 y0, u8 xLength, u16 yLength, u16 xOffset, u16 yOffset)
	{
	#if ID_AM==000
	  ili_SetCursor(x0+xLength-1+xOffset, y0+yLength-1+yOffset);
	#elif ID_AM==001
	  ili_SetCursor(x0+xLength-1+xOffset, y0+yLength-1+yOffset);
	#elif ID_AM==010
	  ili_SetCursor(x0+xOffset, y0+yLength-1+yOffset);
	#elif ID_AM==011
	  ili_SetCursor(x0+xOffset, y0+yLength-1+yOffset);
	#elif ID_AM==100
	  ili_SetCursor(x0+xLength-1+xOffset, y0+yOffset);
	#elif ID_AM==101
	  ili_SetCursor(x0+xLength-1+xOffset, y0+yOffset);
	#elif ID_AM==110
	  ili_SetCursor(x0+xOffset, y0+yOffset);
	#elif ID_AM==111
	  ili_SetCursor(x0+xOffset, y0+yOffset);
	#endif
	  ili_WrReg(0x50, x0+xOffset);             // 水平 GRAM起始位置
	  ili_WrReg(0x51, x0+xLength-1+xOffset);   // 水平GRAM终止位置
	  ili_WrReg(0x52, y0+yOffset);             // 垂直GRAM起始位置
	  ili_WrReg(0x53, y0+yLength-1+yOffset);   // 垂直GRAM终止位置
	  ili_WrCmd(0x00, 0x22);
	}         
	 
	 
	// 清屏
	void ili_ClearScreen(u32 bColor)
	{
	  u32 i;
	 
	  ili_nCS=0;
	  DB_o_EN;
	 
	  ili_SetDispArea(0, 0, 240, 320, 0, 0);
	  for (i=0; i<76800; i++) ili_WrDB_16b(bColor);
	 
         ili_nCS=1;
	}
	 
	 
	// 画点(单次操作)
	void ili_PlotPoint(u8 x, u16 y, u16 color)
	{
	  ili_nCS=0;
	  DB_o_EN;
	 
	  ili_SetCursor(x, y);
	  ili_WrCmd(0x00, 0x22);
	  ili_WrDB_16b(color);
	 
	  ili_nCS=1;
	}
	 
	 
	// 画点(连续操作的一部分)
	void ili_PlotPixel(u8 x, u16 y, u16 color)
	{
	  ili_SetCursor(x, y);
	  ili_WrCmd(0x00, 0x22);
	  ili_WrDB_16b(color);
	}
	 
	 
	// 画一个大点
	void ili_PlotBigPoint(u8 x, u16 y, u16 color)
	{
	  u8 i, j;
	  ili_nCS=0;
	  DB_o_EN;
	  for(i=0; i<3; i++)
	  {
	    for(j=0; j<3; j++) ili_PlotPixel(x+i, y+j, color);
	  }
	  ili_nCS=1;
	}
	 
	 
	// 打印ASCII码(8x16)
	void ili_PutAscii_8x16(u16 x, u16 y, uc8 c, u32 fColor, u32 bColor)
	{
	  u32 i, j;
	  u8 temp;
	 
	  ili_nCS=0;
	  DB_o_EN;
	 
	  ili_SetDispArea(x, y, 8, 16, 0, 0);
	  for(i=0; i<16; i++)
	  {
	    temp = ascii_8x16_tab[c*16+i];
	    for(j=0; j<8; j++)
	    {
	      if((temp&0x80) == 0x80)
	        ili_WrDB_16b(fColor);
	      else
	        ili_WrDB_16b(bColor);
	      temp <<= 1;
	    }
	  }
	 
	  ili_nCS=1;
	}
	 
	 
	// 打印汉字(16x16)
	void ili_PutGB16(u16 x, u16 y, uc8 c[2], u32 fColor, u32 bColor)
	{
	  u32 i, j, k;
	  u16 temp;
	 
	  ili_nCS=0;
	  DB_o_EN;
	 
	  ili_SetDispArea(x, y, 16, 16, 0, 0);
	  for(k=0; k<64; k++) // 64表示自建汉字库中的个数,循环查询内码
	  {
	    if ( (GB16[k].Index[0]==c[0])
	      && (GB16[k].Index[1]==c[1]) )
	    {
	      for(i=0; i<32; i++)
	      {
	        temp = GB16[k].Msk[i];
	        for(j=0; j<8; j++)
	        {
	          if((temp&0x80)==0x80)
	            ili_WrDB_16b(fColor);
	          else
	            ili_WrDB_16b(bColor);
	          temp <<= 1;
	        }
	      }
	    } 
	  }
	 
	  ili_nCS=1;
	}
	 
	 
	// 打印字符串
	void ili_PutString(u16 x, u16 y, uc8 *s, u32 fColor, u32 bColor)
	{
	  u8 l=0;
	  while(*s != '\0')
	  {
	    if(*s < 0x80)
	    {
	      ili_PutAscii_8x16(x+l*8, y, *s, fColor, bColor);
	      s++;
	      l++;
	    }
	    else
	    {
	      ili_PutGB16(x+l*8, y, (u8*)s, fColor, bColor);
	      s+=2;
	      l+=2;
	    }
	  }
	}
	 
	 
	// 彩条测试
	void ili_DispColorBar(void)
	{
	  u16 V, H;
	 
	  ili_nCS=0;
	  DB_o_EN;
	 
	  ili_SetDispArea(0, 0, 240, 320, 0, 0);
	  for(H=0; H<240; H++)
	  {
	    for(V=0; V<40; V++) ili_WrDB_16b(White);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=40; V<80; V++) ili_WrDB_16b(Black);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=80; V<120; V++) ili_WrDB_16b(Blue);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=120; V<160; V++) ili_WrDB_16b(Red);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=160; V<200; V++) ili_WrDB_16b(Magenta);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=200; V<240; V++) ili_WrDB_16b(Green);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=240; V<280; V++) ili_WrDB_16b(Cyan);
	  }
	  for(H=0;H<240;H++)
	  {
	    for(V=280;V<320;V++) ili_WrDB_16b(Yellow);
	  }
	 
	     ili_nCS=1;
          }

注意几个地方:

1. 初始化函数内的void ili_Initial(void)的硬件复位,nRST一定要拉低足够长时间再拉高,此处取1ms,否则会出现白屏现象。

ili_nRST=0;
	ili_DelayMs(1);
	ili_nRST=1;

2. 为了减少DB双向总线的方向切换次数及打开关闭nCS片选的此处,每次操作中只设定一次DB方向,且只打开关闭片选一次。比方在初始化函数内的void ili_Initial(void)内。

// 打开片选,输出使能
	ili_nCS=0;
	DB_o_EN;
// 关闭片选
	ili_nCS=1;

因此,特别需要注意,写一组或一个寄存器前后,或写一个或一组数据到DB总线前后,只做一次设定DB方向和打开关闭片选动作。此外,千万不要将nCS永远拉低,浪费功率,最好用的时候打开,不用的时候关断。

3. 连续重复某个动作的时候,也执行第2条。比方说第246~266行,ili_PlotPixel()函数的引用。

步骤3 测试ILI9325驱动

代码3.1 main.c

#include                     // printf()
	#include                    // usleep()
	#include "my_types.h"                 // 数据类型
	#include "debug.h"                    // debug
	#include "sd_card.h"                  // sd卡
	#include "ili932x.h"                  // ili9325
	 
	 
	//#define ENABLE_APP_DEBUG // turn on debug message
	#ifdef ENABLE_APP_DEBUG
	    #define APP_DEBUG(x)    DEBUG(x)
	#else
	    #define APP_DEBUG(x)
	#endif
	 
	 
	int main(void)
	{
	  ili_Initial();            // 初始化ILI9325
	  ili_DispColorBar();       // 彩条测试
	  while(1);
	  return 0;
        }

测试效果如下(50¥的摄像头拍的,凑活看吧)。


源码下载

451079388734.zip

目录

[原创][连载].基于SOPC的简易数码相框 -  Quartus II部分(硬件部分)

[原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  配置工作

[原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  SD卡(SPI模式)驱动

4 [原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  TFT-LCD(控制器为ILI9325)驱动

5 [原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  从SD卡内读取图片文件,然后显示在TFT-LCD上

[原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  优化工作

7 [原创][连载].基于SOPC的简易数码相框 -  Nios II SBTE部分(软件部分)-  ADS7843触摸屏驱动测试