[原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分) - TFT-LCD(控制器为ILI9325)驱动
准备资料
编写驱动程序
步骤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 <stdio.h> // printf() #include <unistd.h> // 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¥的摄像头拍的,凑活看吧)。
源码下载
目录
1 [原创][连载].基于SOPC的简易数码相框 - Quartus II部分(硬件部分)
2 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 配置工作
3 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- SD卡(SPI模式)驱动
4 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- TFT-LCD(控制器为ILI9325)驱动
5 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 从SD卡内读取图片文件,然后显示在TFT-LCD上
6 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- 优化工作
7 [原创][连载].基于SOPC的简易数码相框 - Nios II SBTE部分(软件部分)- ADS7843触摸屏驱动测试