GadgetSeed  0.9.6
ili9341_lcd.c
[詳解]
1 /** @file
2  @brief ILI9341 LCD GPIO 8bit接続 ドライバ
3  Kuman K60((Kuman 2.8inch TFT LCD Shield))
4 
5  http://www.kumantech.com/kuman-uno-r3-28-inch-tft-touch-screen-with-sd-card-socket-for-arduino-nano-mega2560-320x240-28quot-lcd-k60_p0278.html
6 
7  @date 2017.10.15
8  @author Takashi SHUDO
9 */
10 
11 #include "device.h"
12 #include "device/video_ioctl.h"
13 #include "device/vio_ioctl.h"
14 #include "timer.h"
15 #include "tkprintf.h"
16 #include "graphics.h"
17 
18 //#define DEBUGKBITS 0x03
19 #include "dkprintf.h"
20 
21 
22 //#define LCD_WIDTH 240 // 幅
23 //#define LCD_HEIGHT 320 // 高さ
24 #define LCD_WIDTH 320 // 幅
25 #define LCD_HEIGHT 240 // 高さ
26 //!!!#define LCD_ROTATION 1 // 0:240x320, 1:320x240
27 #define LCD_ROTATION 0 // 0:240x320, 1:320x240
28 
29 static int rotation = LCD_ROTATION;
30 
31 static struct st_device *gpio_dev;
32 static unsigned short lcd_width = LCD_WIDTH;
33 static unsigned short lcd_height = LCD_HEIGHT;
34 static unsigned short fore_color = 0;
35 static unsigned short back_color = 0;
36 #define FMEM_NOP 0
37 #define FMEM_WRITE 1
38 #define FMEM_READ 2
39 static int fmem_stat = FMEM_NOP;
40 
41 #define ILI9341_SOFTRESET 0x01
42 #define ILI9341_DISPLAYOFF 0x28
43 #define ILI9341_POWERCONTROL1 0xc0
44 #define ILI9341_POWERCONTROL2 0xc1
45 #define ILI9341_VCOMCONTROL1 0xc5
46 #define ILI9341_VCOMCONTROL2 0xc7
47 #define ILI9341_MEMCONTROL 0x36
48 #define ILI9341_PIXELFORMAT 0x3a
49 #define ILI9341_FRAMECONTROL 0xb1
50 #define ILI9341_ENTRYMODE 0xb7
51 #define ILI9341_SLEEPOUT 0x11
52 #define ILI9341_DISPLAYON 0x29
53 #define ILI9341_COLADDRSET 0x2a
54 #define ILI9341_PAGEADDRSET 0x2b
55 #define ILI9341_MEMORYWRITE 0x2c
56 #define ILI9341_MEMORYREAD 0x2e
57 #define ILI9341_READID4 0xd3
58 
59 #define ILI9341_MADCTL_MY 0x80
60 #define ILI9341_MADCTL_MX 0x40
61 #define ILI9341_MADCTL_MV 0x20
62 #define ILI9341_MADCTL_RGB 0x00
63 #define ILI9341_MADCTL_BGR 0x08
64 
65 static void set_cs(unsigned int cs)
66 {
67  ioctl_device(gpio_dev, IOCMD_VIO_SET_CS, cs, 0);
68 }
69 
70 static void reset_ili9341(void)
71 {
72  ioctl_device(gpio_dev, IOCMD_VIO_SET_RESET, 0, 0);
73  wait_time(100);
74  ioctl_device(gpio_dev, IOCMD_VIO_SET_RESET, 1, 0);
75 }
76 
77 static inline void write_reg8(unsigned char addr, unsigned char data)
78 {
80  (((int)addr) << 16) | (int)(data & 0xff), 0);
81 }
82 
83 static inline void write_reg16(unsigned char addr, unsigned short data)
84 {
86  (((int)addr) << 16) | (int)(data & 0xffff), 0);
87 }
88 
89 static inline void write_reg32(unsigned char addr, unsigned int data)
90 {
91  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, addr, 0);
92  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_DATA32, data, 0);
93 }
94 
95 static inline unsigned int read_reg32(unsigned char addr)
96 {
97  return ioctl_device(gpio_dev, IOCMD_VIO_READ_REG32, addr, 0);
98 }
99 
100 static void set_window(int x1, int y1, int x2, int y2)
101 {
102  int x, y, t;
103 
104  DKPRINTF(0x01, "WI %3d %3d %3d %3d\n", x1, y1, x2, y2);
105 
106  switch(rotation) {
107  default:
108  x = x1;
109  y = y1;
110  break;
111  case 1:
112  t = y1;
113  y1 = x1;
114  x1 = LCD_WIDTH - 1 - y2;
115  y2 = x2;
116  x2 = LCD_WIDTH - 1 - t;
117  x = x2;
118  y = y1;
119  break;
120  case 2:
121  t = x1;
122  x1 = LCD_WIDTH - 1 - x2;
123  x2 = LCD_WIDTH - 1 - t;
124  t = y1;
125  y1 = LCD_HEIGHT - 1 - y2;
126  y2 = LCD_HEIGHT - 1 - t;
127  x = x2;
128  y = y2;
129  break;
130  case 3:
131  t = x1;
132  x1 = y1;
133  y1 = LCD_HEIGHT - 1 - x2;
134  x2 = y2;
135  y2 = LCD_HEIGHT - 1 - t;
136  x = x1;
137  y = y2;
138  break;
139  }
140 
141  DKPRINTF(0x01, "WO %3d %3d %3d %3d\n", x1, y1, x2, y2);
142 
143  set_cs(0);
144 
145  write_reg32(ILI9341_COLADDRSET, ((x1<<16) | x2));
146  write_reg32(ILI9341_PAGEADDRSET, ((y1<<16) | y2));
147  (void)x;
148  (void)y;
149 
150  set_cs(1);
151 }
152 
153 static void init_ili9341(void)
154 {
155  reset_ili9341();
156 
157  set_cs(0);
158 
159  write_reg8(ILI9341_SOFTRESET, 0);
160  wait_time(50);
161  write_reg8(ILI9341_DISPLAYOFF, 0);
162 
163  unsigned int id4 = read_reg32(ILI9341_READID4);
164  tkprintf("ID4 : %08X\n", id4);
165 
166  write_reg8(ILI9341_POWERCONTROL1, 0x23);
167  write_reg8(ILI9341_POWERCONTROL2, 0x10);
168  write_reg16(ILI9341_VCOMCONTROL1, 0x2B2B);
169  write_reg8(ILI9341_VCOMCONTROL2, 0xC0);
170  write_reg8(ILI9341_MEMCONTROL, ILI9341_MADCTL_MV | ILI9341_MADCTL_BGR);
171  write_reg8(ILI9341_PIXELFORMAT, 0x55);
172  write_reg16(ILI9341_FRAMECONTROL, 0x001B);
173 
174  write_reg8(ILI9341_ENTRYMODE, 0x07);
175  /*write_reg32(ILI9341_DISPLAYFUNC, 0x0A822700);*/
176 
177  write_reg8(ILI9341_SLEEPOUT, 0);
178  wait_time(150);
179  write_reg8(ILI9341_DISPLAYON, 0);
180  //wait_time(500);
181 
182  set_cs(1);
183 
184  set_window(0, 0, lcd_width - 1, lcd_height - 1);
185 }
186 
187 static void fill_screen(unsigned short color)
188 {
189  set_window(0, 0, lcd_width - 1, lcd_height - 1);
190 
191  ioctl_device(gpio_dev, IOCMD_VIO_SET_WRITEDATA0, (unsigned int)color, 0);
192 
193  set_cs(0);
194  fmem_stat = FMEM_WRITE;
195  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
196  ioctl_device(gpio_dev, IOCMD_VIO_REPEAT_DATA, (unsigned int)LCD_WIDTH * LCD_HEIGHT, 0);
197  set_cs(1);
198 }
199 
200 static int ili9341_lcd_register(struct st_device *dev, char *param)
201 {
202  gpio_dev = open_device(param);
203  if(gpio_dev == 0) {
204  SYSERR_PRINT("Cannot open device \"%s\"\n", param);
205  return -1;
206  }
207 
208  init_ili9341();
209 
210  fill_screen(0);
211 
212  return 0;
213 }
214 
215 static int ili9341_lcd_read(struct st_device *dev, void *data, unsigned int size)
216 {
217  int rt;
218 
219  if(fmem_stat != FMEM_READ) {
220  set_cs(1);
221  set_cs(0);
222  fmem_stat = FMEM_READ;
223  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYREAD, 0);
224  ioctl_device(gpio_dev, IOCMD_VIO_READ_DATA8, 0, 0); // Dummy read
225  } else {
226  set_cs(0);
227  }
228 
229  rt = read_device(gpio_dev, data, size);
230 
231  set_cs(1);
232 
233  return rt;
234 }
235 
236 static int ili9341_lcd_write(struct st_device *dev, const void *data, unsigned int size)
237 {
238  int rt;
239 
240  if(fmem_stat != FMEM_WRITE) {
241  set_cs(0);
242  fmem_stat = FMEM_WRITE;
243  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
244  } else {
245  set_cs(0);
246  }
247 
248  rt = write_device(gpio_dev, data, size);
249 
250  set_cs(1);
251 
252  return rt;
253 }
254 
255 static int ili9341_lcd_ioctl(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
256 {
257  DKPRINTF(0x01, "LCD %08X %08X\n", com, arg);
258 
259  switch(IOCTL(com)) {
261  ioctl_device(gpio_dev, IOCMD_VIO_LOCK_BUS, 0, 0);
262  break;
263 
265  ioctl_device(gpio_dev, IOCMD_VIO_UNLOCK_BUS, 0, 0);
266  break;
267 
268  case IOCMD_VIDEO_SETRECT:
269  {
270  struct st_rect *rect = (struct st_rect *)param;
271  DKPRINTF(0x01, "RECT %3d %3d %3d %3d\n", rect->left, rect->top, rect->right, rect->bottom);
272  set_window(rect->left, rect->top, rect->right, rect->bottom);
273  fmem_stat = FMEM_NOP;
274  return 0;
275  }
276  break;
277 
279  {
280  set_window(0, 0, lcd_width - 1, lcd_height - 1);
281  fmem_stat = FMEM_NOP;
282  return 0;
283  }
284  break;
285 
286  case IOCMD_VIDEO_CLEAR:
287  fill_screen(0);
288  return 0;
289  break;
290 
291  case IOCMD_VIDEO_FILL:
292  fill_screen(arg);
293  return 0;
294  break;
295 
297  break;
298 
300  {
301  DKPRINTF(0x01, "WRITE_WORD %04X\n", arg);
302  if(fmem_stat != FMEM_WRITE) {
303  set_cs(0);
304  fmem_stat = FMEM_WRITE;
305  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
306  }
307  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_DATA16, arg & 0xffff, 0);
308  }
309  break;
310 
312  {
313  DKPRINTF(0x01, "WORD %04X\n", arg);
314  if(fmem_stat != FMEM_WRITE) {
315  set_cs(0);
316  fmem_stat = FMEM_WRITE;
317  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
318  }
319  ioctl_device(gpio_dev, IOCMD_VIO_NOLOCK_WRITE_DATA16, arg & 0xffff, 0);
320  }
321  break;
322 
324  {
325  fore_color = arg;
326  ioctl_device(gpio_dev, IOCMD_VIO_SET_WRITEDATA0, arg, 0);
327  }
328  break;
329 
331  {
332  back_color = arg;
333  ioctl_device(gpio_dev, IOCMD_VIO_SET_WRITEDATA1, arg, 0);
334  }
335  break;
336 
338  {
339  if(fmem_stat != FMEM_WRITE) {
340  set_cs(0);
341  fmem_stat = FMEM_WRITE;
342  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
343  }
344  ioctl_device(gpio_dev, IOCMD_VIO_REPEAT_DATA, arg, 0);
345  set_cs(1);
346  }
347  break;
348 
350  {
351  int x = ((arg >> 0) & 0xffff);
352  int y = ((arg >> 16) & 0xffff);
353  int dx;
354  int dy;
355 
356  DKPRINTF(0x01, "P %3d %3d\n", x, y);
357 
358  switch(rotation) {
359  default:
360  dx = x;
361  dy = y;
362  break;
363  case 1:
364  dx = LCD_WIDTH - 1 - y;
365  dy = x;
366  break;
367  }
368 
369  set_window(dx, dy, lcd_width - 1, lcd_height - 1);
370  set_cs(0);
371  fmem_stat = FMEM_NOP;
372  write_reg16(ILI9341_MEMORYWRITE, fore_color);
373  set_cs(1);
374  }
375  break;
376 
378  {
379  if(fmem_stat != FMEM_WRITE) {
380  set_cs(0);
381  fmem_stat = FMEM_WRITE;
382  ioctl_device(gpio_dev, IOCMD_VIO_WRITE_COMMAND, ILI9341_MEMORYWRITE, 0);
383  }
384  ioctl_device(gpio_dev, IOCMD_VIO_REPEAT_BITS | (com & 0xffff), arg, param);
385  }
386  break;
387 
388  default:
389  SYSERR_PRINT("Unknow command %08lX arg %08lX\n", com, arg);
390  return -1;
391  }
392 
393  return 0;
394 }
395 
396 static struct st_video_info lcd_info = {
398 #if (LCD_ROTATION == 1)
399  .width = LCD_HEIGHT,
400  .height = LCD_WIDTH,
401 #else
402  .width = LCD_WIDTH,
403  .height = LCD_HEIGHT,
404 #endif
405  .color_depth = VCOLORDEP_16,
406 };
407 
408 const struct st_device ili9341_lcd_device = {
410  .explan = "ILI9341(K60) LCD",
411  .info = (void *)&lcd_info,
412  .register_dev = ili9341_lcd_register,
413  .read = ili9341_lcd_read,
414  .write = ili9341_lcd_write,
415  .ioctl = ili9341_lcd_ioctl,
416 };
#define IOCTL(ioctl)
ioctlコマンド
Definition: std_ioctl.h:29
#define IOCMD_VIDEO_NOLOCK_WRITE_WORD
2バイト表示データを転送する(MUTEXロックは無視)
Definition: video_ioctl.h:62
#define IOCMD_VIO_READ_DATA8
コントローラデバイスから8ビットデータを読み出す
Definition: vio_ioctl.h:31
#define IOCMD_VIO_WRITE_REG16
コントローラデバイスのレジスタに16ビットデータを書き込む
Definition: vio_ioctl.h:34
#define IOCMD_VIO_REPEAT_BITS
指定のビットデータを描画データ0、1で描画する
Definition: vio_ioctl.h:46
#define IOCMD_VIDEO_CLEAR
全画面初期化
Definition: video_ioctl.h:52
#define IOCMD_VIO_LOCK_BUS
バスをMUTEXロックする
Definition: vio_ioctl.h:18
#define IOCMD_VIO_WRITE_DATA16
コントローラデバイスに16ビットデータを書き込む
Definition: vio_ioctl.h:26
画像表示デバイスドライバ ioctl 用マクロ定義
#define IOCMD_VIDEO_UNLOCK_DEVICE
デバイスをMUTEXアンロックする
Definition: video_ioctl.h:45
#define IOCMD_VIO_SET_RESET
デバイスのリセットを設定する
Definition: vio_ioctl.h:21
#define IOCMD_VIDEO_SETRECT
描画データ転送範囲を矩形で設定する
Definition: video_ioctl.h:55
矩形
Definition: graphics.h:64
画像表示デバイス情報
Definition: video_ioctl.h:30
#define IOCMD_VIO_WRITE_COMMAND
コントローラデバイスにコマンドを書き込む
Definition: vio_ioctl.h:24
struct st_device * open_device(char *name)
デバイスをオープンする
Definition: device.c:262
#define IOCMD_VIDEO_REPEAT_DATA
指定ドット数分フォアカラーで描画する
Definition: video_ioctl.h:66
int write_device(struct st_device *dev, const void *buf, unsigned int count)
デバイスにデータを書き込む
Definition: device.c:451
int read_device(struct st_device *dev, void *buf, unsigned int count)
デバイスよりデータを読み出す
Definition: device.c:378
short top
左上頂点のY座標
Definition: graphics.h:66
short bottom
右下頂点のY座標
Definition: graphics.h:68
#define VIDEOTYPE_CMDDRAW
コマンドによる描画(フレームバッファなし)
Definition: video_ioctl.h:20
short left
左上頂点のX座標
Definition: graphics.h:65
#define IOCMD_VIO_READ_REG32
コントローラデバイスのレジスタより32ビットデータを読み出す
Definition: vio_ioctl.h:41
#define IOCMD_VIDEO_DRAW_PIXEL
フォアカラーで1ドット描画する
Definition: video_ioctl.h:67
#define IOCMD_VIDEO_DRAW_BITS
ビットパターンを描画する
Definition: video_ioctl.h:68
#define IOCMD_VIO_REPEAT_DATA
描画データ0で指定ドット数描画する
Definition: vio_ioctl.h:45
カーネルタイマ
int tkprintf(const char *fmt,...)
非タスクコンテキスト実行用メッセージ出力
Definition: tkprintf.c:100
unsigned short type
ビデオデバイスタイプ(VIDEOTYPE_*)
Definition: video_ioctl.h:31
short right
右下頂点のX座標
Definition: graphics.h:67
カーネル用機能限定printf
#define LCD_ROTATION
!!#define LCD_ROTATION 1 // 0:240x320, 1:320x240
Definition: ili9341_lcd.c:27
#define IOCMD_VIO_SET_WRITEDATA0
描画データ0を設定する
Definition: vio_ioctl.h:43
#define IOCMD_VIO_NOLOCK_WRITE_DATA16
コントローラデバイスに16ビットデータを書き込む(ロックは無視)
Definition: vio_ioctl.h:29
#define IOCMD_VIO_SET_WRITEDATA1
描画データ1を設定する
Definition: vio_ioctl.h:44
#define IOCMD_VIO_SET_CS
CSを設定する
Definition: vio_ioctl.h:22
void wait_time(unsigned int time)
指定時間待つ
Definition: timer.c:216
#define IOCMD_VIO_WRITE_DATA32
コントローラデバイスに32ビットデータを書き込む
Definition: vio_ioctl.h:28
#define VCOLORDEP_16
16ビットカラー
Definition: video_ioctl.h:26
#define IOCMD_VIDEO_LOCK_DEVICE
デバイスをMUTEXロックする
Definition: video_ioctl.h:44
#define IOCMD_VIDEO_RESETRECT
描画データ転送範囲を全表示範囲にする
Definition: video_ioctl.h:56
#define IOCMD_VIDEO_SET_BACKCOLOR
バックカラーを設定する
Definition: video_ioctl.h:65
#define IOCMD_VIO_UNLOCK_BUS
バスをMUTEXアンロックする
Definition: vio_ioctl.h:19
映像関連ドライバIO ioctl 用マクロ定義
#define DEF_DEV_NAME_VIDEO
標準ビデオデバイス名
Definition: video_ioctl.h:16
#define IOCMD_VIO_WRITE_REG8
コントローラデバイスのレジスタに8ビットデータを書き込む
Definition: vio_ioctl.h:33
デバイスドライバAPI
デバイスドライバ構造体
Definition: device.h:25
カーネル、ドライバ(非タスク)デバッグ用マクロ
#define IOCMD_VIDEO_WRITE_WORD
2バイト表示データを転送する(未使用)
Definition: video_ioctl.h:59
int ioctl_device(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
デバイスを制御する
Definition: device.c:525
char name[MAX_DEVNAMELRN]
デバイス名文字列
Definition: device.h:26
#define IOCMD_VIDEO_SET_FORECOLOR
フォアカラーを設定する
Definition: video_ioctl.h:64
グラフィックライブラリ
#define IOCMD_VIDEO_BCKLIGHT
バックライトを制御する(未使用)
Definition: video_ioctl.h:70
#define IOCMD_VIDEO_FILL
全画面を任意の色に描画する
Definition: video_ioctl.h:54