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

准备资料

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

编写驱动程序

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

image image

步骤2 编写驱动文件

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

代码2.1 ili932x.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
#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,否则会出现白屏现象。

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

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

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

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

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

步骤3 测试ILI9325驱动

代码3.1 main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#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¥的摄像头拍的,凑活看吧)。

image 

源码下载

lcd_at_nios_nii_part.zip

目录

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

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

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

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

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

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

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

posted @   _安德鲁  阅读(4150)  评论(2编辑  收藏  举报
点击右上角即可分享
微信分享提示