Merge pull request #5 from tauonteilchen/master
[hackover2013-badge-firmware.git] / drivers / displays / tft / hw / hx8347d.c
1 /**************************************************************************/
2 /*!
3 @file hx8347d.c
4 @author Tauon {TauonTeilchen} Jabber ID Tauon[at]jabber.ccc.de
5
6 @section DESCRIPTION
7 Driver for hx8347h 240x320 pixel TFT LCD displays.
8 Is written for MI0283QT-2 LCD from watterott.com
9 More infos: http://www.watterott.com/de/MI0283QT-2-Adapter
10 http://www.watterott.com/index.php?page=product&info=1597&dl_media=3202
11
12 @section LICENSE
13
14 Software License Agreement (BSD License)
15
16 Copyright (c) 2012, TauonTeilchen
17 ----------------------------------------------------------------------------
18 "THE ClubMate-WARE LICENSE" (Revision 42):
19 JID: <Tauon@jabber.ccc.de> wrote this file. As long as you retain this notice you
20 can do whatever you want with this stuff. If we meet some day, and you think
21 this stuff is worth it, you can buy me a ClubMate in return Tauon
22 ----------------------------------------------------------------------------
23 ----------------------------------------------------------------------------
24 "THE ClubMate-WARE LICENSE" (Revision 42):
25 JID: <Tauon@jabber.ccc.de> schrieb diese Datei. Solange Sie diesen Vermerk nicht entfernen, k�nnen
26 Sie mit dem Material machen, was Sie m�chten. Wenn wir uns eines Tages treffen und Sie
27 denken, das Material ist es wert, k�nnen Sie mir daf�r ein ClubMate ausgeben. Tauon
28 ----------------------------------------------------------------------------
29
30 */
31 /**************************************************************************/
32 #include "drivers/displays/tft/hw/hx8347d.h"
33
34 #define LCD_ID (0x00)
35 #define LCD_DATA ((0x72)|(LCD_ID<<2))
36 #define LCD_REGISTER ((0x70)|(LCD_ID<<2))
37
38 #define LCD_BACK_LIGHT 6
39 #define LCD_RST 5
40 #define LCD_CS 4
41
42 // Macros for control line state
43 #define LCD_CS_ENABLE() GPIO_GPIO2DATA &= ~0x10 // gpioSetValue(2, 4, 0)
44 #define LCD_CS_DISABLE() GPIO_GPIO2DATA |= 0x10 // gpioSetValue(2, 4, 1)
45 #define LCD_RST_ENABLE() GPIO_GPIO2DATA &= ~0x20 // gpioSetValue(2, 5, 0)
46 #define LCD_RST_DISABLE() GPIO_GPIO2DATA |= 0x20 // gpioSetValue(2, 5, 1)
47
48 #define Himax ID 0x00
49 #define Display_Mode_Control 0x01
50
51 #define Column_Address_Start_2 0x02
52 #define Column_Address_Start_1 0x03
53 #define Column_Address_End_2 0x04
54 #define Column_Address_End_1 0x05
55
56 #define Row_Address_Start_2 0x06
57 #define Row_Address_Start_1 0x07
58 #define Row_Address_End_2 0x08
59 #define Row_Address_End_1 0x09
60
61 #define Partial_Area_Start_Row_2 0x0A
62 #define Partial_Area_Start_Row_1 0x0B
63 #define Partial_Area_End_Row_2 0x0C
64 #define Partial_Area_End_Row_1 0x0D
65
66 #define TFA_REGISTER 0x0E
67 #define VSA_REGISTER 0x10
68 #define BFA_REGISTER 0x12
69 #define VSP_REGISTER 0x14
70
71 #define COLMOD 0x17
72 #define OSC_Control_1 0x18
73 #define OSC_Control_2 0x19
74 #define Power_Control_1 0x1A
75 #define Power_Control_2 0x1B
76 #define Power_Control_3 0x1C
77 #define Power_Control_4 0x1D
78 #define Power_Control_5 0x1E
79 #define Power_Control_6 0x1F
80 #define VCOM_Control_1 0x23
81 #define VCOM_Control_2 0x24
82 #define VCOM_Control_3 0x25
83 #define Display_Control_1 0x26
84 #define Display_Control_2 0x27
85 #define Display_Control_3 0x28
86 #define Source_OP_Control_Normal 0xE8
87 #define Source_OP_Control_IDLE 0xE9
88 #define Power_Control_Internal_1 0xEA
89 #define Power_Control_Internal_2 0xEB
90 #define Source_Control_Internal_1 0xEC
91 #define Source_Control_Internal_2 0xED
92
93 #define OSC_Control_2_OSC_EN 0x01
94 #define Display_Control_3_GON 0x20
95 #define Display_Control_3_DTE 0x10
96 #define Display_Control_3_D0 0x04
97 #define Display_Control_3_D1 0x08
98 #define Power_Control_6_STB 0x01
99 #define Display_Mode_Control_DP_STB_S 0x40
100 #define Display_Mode_Control_DP_STB 0x80
101 uint16_t offset;
102
103 /*************************************************/
104 /* Private Methods */
105 /*************************************************/
106 void lcd_drawstart(void);
107 void lcd_cmd(uint16_t reg, uint16_t param);
108 void lcd_clear(uint16_t color);
109 void lcd_draw(uint16_t color);
110 void lcd_drawstart(void);
111 void lcd_drawstop(void);
112 void hx8347d_DisplayOnFlow(void);
113 void hx8347d_DisplayOffFlow(void);
114 void lcd_area(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1);
115
116
117 void hx8347d_Scroll(uint16_t tfa,uint16_t vsa,uint16_t bfa, uint16_t vsp)
118 {
119 lcd_cmd(TFA_REGISTER , tfa >> 8);
120 lcd_cmd(TFA_REGISTER + 1, tfa & 0xFF);
121
122 lcd_cmd(VSA_REGISTER , vsa >> 8);
123 lcd_cmd(VSA_REGISTER + 1, vsa & 0xFF);
124
125 lcd_cmd(BFA_REGISTER , bfa >> 8);
126 lcd_cmd(BFA_REGISTER + 1, bfa & 0xFF);
127
128 lcd_cmd(VSP_REGISTER , vsp>> 8);
129 lcd_cmd(VSP_REGISTER + 1, vsp & 0xFF);
130 lcd_cmd(0x01, 0x08); //scroll on
131 }
132
133 void displayOnFlow(void)
134 {
135 lcd_cmd(Display_Control_3, 0x0038);
136 systickDelay(4);
137 lcd_cmd(Display_Control_3, 0x003C);
138 }
139 void displayOffFlow(void)
140 {
141 lcd_cmd(Display_Control_3, Display_Control_3_GON | Display_Control_3_DTE | Display_Control_3_D1);
142 systickDelay(4);
143 lcd_cmd(Display_Control_3, Display_Control_3_D0);
144 }
145
146 void lcd_cmd(uint16_t reg, uint16_t param)
147 {
148 uint8_t b_first[2];
149 uint8_t b_sec[2];
150 LCD_CS_ENABLE();
151
152 b_first[0] = LCD_REGISTER;
153 b_first[1] = reg;
154
155 sspSend(0, b_first, 2);
156 LCD_CS_DISABLE();
157
158 b_sec[0] = LCD_DATA;
159 b_sec[1] = param;
160 LCD_CS_ENABLE();
161
162 sspSend(0, b_sec, 2);
163 LCD_CS_DISABLE();
164
165 return;
166 }
167 void lcd_clear(uint16_t color)
168 {
169 unsigned int i;
170
171 lcd_area(0, 0, (hx8347dProperties.width -1), (hx8347dProperties.height-1));
172
173 lcd_drawstart();
174 for(i=(hx8347dProperties.width*hx8347dProperties.height/8); i!=0; i--)
175 {
176 lcd_draw(color); //1
177 lcd_draw(color); //2
178 lcd_draw(color); //3
179 lcd_draw(color); //4
180 lcd_draw(color); //5
181 lcd_draw(color); //6
182 lcd_draw(color); //7
183 lcd_draw(color); //8
184 }
185 lcd_drawstop();
186
187 return;
188 }
189
190 void lcd_draw(uint16_t color)
191 {
192 // Writing data in 16Bit mode for saving a lot of time
193 /* Move on only if NOT busy and TX FIFO not full. */
194 while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_NOTFULL | SSP_SSP0SR_BSY_BUSY)) != SSP_SSP0SR_TNF_NOTFULL);
195 SSP_SSP0DR = color;
196
197 while ( (SSP_SSP0SR & (SSP_SSP0SR_BSY_BUSY|SSP_SSP0SR_RNE_NOTEMPTY)) != SSP_SSP0SR_RNE_NOTEMPTY );
198 /* Whenever a byte is written, MISO FIFO counter increments, Clear FIFO
199 on MISO. Otherwise, when SSP0Receive() is called, previous data byte
200 is left in the FIFO. */
201 uint8_t Dummy = SSP_SSP0DR;
202 return;
203 }
204
205 void lcd_drawstop(void)
206 {
207 while ((SSP_SSP0SR & SSP_SSP0SR_TFE_MASK ) != SSP_SSP0SR_TFE_EMPTY );
208 LCD_CS_DISABLE();
209
210 // init 8Bit SPI Mode
211 SSP_SSP0CR0 &= ~SSP_SSP0CR0_DSS_MASK;
212 SSP_SSP0CR0 |= SSP_SSP0CR0_DSS_8BIT;
213
214 return;
215 }
216 void lcd_drawstart(void)
217 {
218 LCD_CS_ENABLE();
219 uint8_t b_first[2];
220 uint8_t b_sec[1];
221 b_first[0] = LCD_REGISTER;
222 b_first[1] = 0x22;
223 sspSend(0, b_first, 2);
224 LCD_CS_DISABLE();
225
226 LCD_CS_ENABLE();
227 b_sec[0] = LCD_DATA;
228 sspSend(0, b_sec, 1);
229
230
231 // Assign config values to SSP0CR0
232 // init 16Bit SPI Mode for fast data transmitting
233 SSP_SSP0CR0 &= ~SSP_SSP0CR0_DSS_MASK;
234 SSP_SSP0CR0 |= SSP_SSP0CR0_DSS_16BIT;
235
236 return;
237 }
238
239
240 void lcd_area(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1)
241 {
242 if(hx8347dPOrientation == LCD_ORIENTATION_PORTRAIT)
243 {
244 y0 = ((320-offset)+ y0) % 320;
245 y1 = ((320-offset)+ y1) % 320;
246 }
247 else
248 {
249 x0 = ((320-offset)+ x0) % 320;
250 x1 = ((320-offset)+ x1) % 320;
251 }
252 lcd_cmd(Column_Address_Start_1, (x0>>0)); //set x0
253 lcd_cmd(Column_Address_Start_2, (x0>>8)); //set x0
254 lcd_cmd(Column_Address_End_1 , (x1>>0)); //set x1
255 lcd_cmd(Column_Address_End_2 , (x1>>8)); //set x1
256 lcd_cmd(Row_Address_Start_1 , (y0>>0)); //set y0
257 lcd_cmd(Row_Address_Start_2 , (y0>>8)); //set y0
258 lcd_cmd(Row_Address_End_1 , (y1>>0)); //set y1
259 lcd_cmd(Row_Address_End_2 , (y1>>8)); //set y1
260
261 return;
262 }
263 void lcd_cursor(uint16_t x, uint16_t y)
264 {
265 lcd_area(x, y, x, y);
266 return;
267 }
268 void lcd_data(uint16_t c)
269 {
270 LCD_CS_ENABLE();
271 uint8_t b[3];
272 b[0] = LCD_DATA;
273 b[1] = c>>8;
274 b[2] = c;
275 sspSend(0, b, 3);
276
277 LCD_CS_DISABLE();
278
279 return;
280 }
281
282
283 void fillRect(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color)
284 {
285 uint32_t size;
286 uint16_t tmp, i;
287
288 if(x0 > x1)
289 {
290 tmp = x0;
291 x0 = x1;
292 x1 = tmp;
293 }
294 if(y0 > y1)
295 {
296 tmp = y0;
297 y0 = y1;
298 y1 = tmp;
299 }
300
301 if(x1 >= hx8347dProperties.width)
302 {
303 x1 = hx8347dProperties.width-1;
304 }
305 if(y1 >= hx8347dProperties.height)
306 {
307 y1 = hx8347dProperties.height-1;
308 }
309
310 lcd_area(x0, y0, x1, y1);
311
312 lcd_drawstart();
313 size = (uint32_t)(1+(x1-x0)) * (uint32_t)(1+(y1-y0));
314 tmp = size/8;
315 if(tmp != 0)
316 {
317 for(i=tmp; i!=0; i--)
318 {
319 lcd_draw(color); //1
320 lcd_draw(color); //2
321 lcd_draw(color); //3
322 lcd_draw(color); //4
323 lcd_draw(color); //5
324 lcd_draw(color); //6
325 lcd_draw(color); //7
326 lcd_draw(color); //8
327 }
328 for(i=size-tmp; i!=0; i--)
329 {
330 lcd_draw(color);
331 }
332 }
333 else
334 {
335 for(i=size; i!=0; i--)
336 {
337 lcd_draw(color);
338 }
339 }
340 lcd_drawstop();
341
342 return;
343 }
344
345 /*************************************************/
346 /* Public Methods */
347 /*************************************************/
348
349 /**************************************************************************/
350 /*!
351 @brief Configures any pins or HW and initialises the LCD controller
352 */
353 /**************************************************************************/
354 void lcdInit(void)
355 {
356 sspInit(0,0,0);
357
358 gpioSetDir(2, LCD_CS, gpioDirection_Output);
359 gpioSetDir(2, LCD_RST, gpioDirection_Output);
360 gpioSetDir(2, LCD_BACK_LIGHT, gpioDirection_Output);
361
362 //reset
363 LCD_CS_DISABLE();
364 systickDelay(1);
365 LCD_RST_ENABLE();
366 systickDelay(50);
367 LCD_RST_DISABLE();
368 systickDelay(50);
369
370 //driving ability
371 lcd_cmd(Power_Control_Internal_1 , 0x0000);
372 lcd_cmd(Power_Control_Internal_2 , 0x0020);
373 lcd_cmd(Source_Control_Internal_1, 0x000C);
374 lcd_cmd(Source_Control_Internal_2, 0x00C4);
375 lcd_cmd(Source_OP_Control_Normal , 0x0040);
376 lcd_cmd(Source_OP_Control_IDLE , 0x0038);
377 lcd_cmd(0xF1, 0x0001);
378 lcd_cmd(0xF2, 0x0010);
379 lcd_cmd(0x27, 0x00A3);
380
381 //power voltage
382 lcd_cmd(Power_Control_2, 0x001B);
383 lcd_cmd(Power_Control_1, 0x0001);
384 lcd_cmd(VCOM_Control_2 , 0x002F);
385 lcd_cmd(VCOM_Control_3 , 0x0057);
386
387 //VCOM offset
388 lcd_cmd(VCOM_Control_1, 0x008D); //for flicker adjust
389
390 //power on
391 lcd_cmd(OSC_Control_1 , 0x0036);
392 lcd_cmd(OSC_Control_2 , 0x0001); //start osc
393 lcd_cmd(Display_Mode_Control, 0x0000); //wakeup
394 lcd_cmd(Power_Control_6 , 0x0088);
395 systickDelay(5);
396 lcd_cmd(Power_Control_6, 0x0080);
397 systickDelay(5);
398 lcd_cmd(Power_Control_6, 0x0090);
399 systickDelay(5);
400 lcd_cmd(Power_Control_6, 0x00D0);
401 systickDelay(5);
402
403 //color selection
404 lcd_cmd(COLMOD, 0x0005); //0x0005=65k, 0x0006=262k
405
406 //panel characteristic
407 lcd_cmd(0x36, 0x0000);
408
409 //display on
410 lcd_cmd(0x28, 0x0038);
411 systickDelay(40);
412 lcd_cmd(0x28, 0x003C);
413
414 lcdSetOrientation(hx8347dPOrientation);
415 offset = 0;
416 return;
417 }
418 /**************************************************************************/
419 /*!
420 @brief Enables or disables the LCD backlight
421 */
422 /**************************************************************************/
423 void lcdBacklight(bool state)
424 {
425 gpioSetValue(2, LCD_BACK_LIGHT, state);
426 }
427
428 /**************************************************************************/
429 /*!
430 @brief Renders a simple test pattern on the LCD
431 */
432 /**************************************************************************/
433 void lcdTest(void)
434 {
435 lcdFillRGB(COLOR_CYAN);
436
437 }
438
439 /**************************************************************************/
440 /*!
441 @brief Fills the LCD with the specified 16-bit color
442 */
443 /**************************************************************************/
444 void lcdFillRGB(uint16_t data)
445 {
446 lcd_clear(data);
447 }
448
449 /**************************************************************************/
450 /*!
451 @brief Draws a single pixel at the specified X/Y location
452 */
453 /**************************************************************************/
454 void lcdDrawPixel(uint16_t x, uint16_t y, uint16_t color)
455 {
456 if((x >= hx8347dProperties.width) ||
457 (y >= hx8347dProperties.height))
458 {
459 return;
460 }
461
462 fillRect(x,y,x,y,color);
463
464 return;
465 }
466
467 /**************************************************************************/
468 /*!
469 @brief Draws an array of consecutive RGB565 pixels (much
470 faster than addressing each pixel individually)
471 */
472 /**************************************************************************/
473 void lcdDrawPixels(uint16_t x, uint16_t y, uint16_t *data, uint32_t len)
474 {
475 lcd_area(x, y, x + len, y);
476 int i;
477 lcd_drawstart();
478 for(i = 0; i < len; i++)
479 {
480
481 lcd_draw(*data);
482 data++;
483 }
484 lcd_drawstop();
485 }
486
487 /**************************************************************************/
488 /*!
489 @brief Optimised routine to draw a horizontal line faster than
490 setting individual pixels
491 */
492 /**************************************************************************/
493 void lcdDrawHLine(uint16_t x0, uint16_t x1, uint16_t y, uint16_t color)
494 {
495
496 if (x1 < x0)
497 {
498 // Switch x1 and x0
499 uint16_t x;
500 x = x1;
501 x1 = x0;
502 x0 = x;
503 }
504
505 if(x0 >= hx8347dProperties.width)
506 {
507 x0 = hx8347dProperties.width-1;
508 }
509 if(x1 >= hx8347dProperties.width)
510 {
511 x1 = hx8347dProperties.width-1;
512 }
513 if(y >= hx8347dProperties.height)
514 {
515 y = hx8347dProperties.height-1;
516 }
517
518 fillRect(x0, y, x1, y, color);
519
520 }
521
522 /**************************************************************************/
523 /*!
524 @brief Optimised routine to draw a vertical line faster than
525 setting individual pixels
526 */
527 /**************************************************************************/
528 void lcdDrawVLine(uint16_t x, uint16_t y0, uint16_t y1, uint16_t color)
529 {
530
531 if (y1 < y0)
532 {
533 // Switch y1 and y0
534 uint16_t y;
535 y = y1;
536 y1 = y0;
537 y0 = y;
538 }
539
540 if(x >= hx8347dProperties.width)
541 {
542 x = hx8347dProperties.width-1;
543 }
544
545 if(y0 >= hx8347dProperties.height)
546 {
547 y0 = hx8347dProperties.height-1;
548 }
549 if(y1 >= hx8347dProperties.height)
550 {
551 y1 = hx8347dProperties.height-1;
552 }
553
554 fillRect(x, y0, x, y1, color);
555 }
556
557 /**************************************************************************/
558 /*!
559 @brief Gets the 16-bit color of the pixel at the specified location
560 */
561 /**************************************************************************/
562 uint16_t lcdGetPixel(uint16_t x, uint16_t y)
563 {
564 return 0;
565 }
566
567 /**************************************************************************/
568 /*!
569 @brief Sets the LCD orientation to horizontal and vertical
570 */
571 /**************************************************************************/
572 void lcdSetOrientation(lcdOrientation_t orientation)
573 {
574 if(orientation == LCD_ORIENTATION_LANDSCAPE)
575 {
576 lcd_cmd(0x16, 0x00A8); //MY=1 MX=0 MV=1 ML=0 BGR=1
577 hx8347dProperties.width = 320;
578 hx8347dProperties.height = 240;
579 }
580 else
581 {
582 //lcd_cmd(0x16, 0x0008); //MY=0 MX=0 MV=0 ML=0 BGR=1
583 lcd_cmd(0x16, 0x00C8); //MY=1 MX=0 MV=1 ML=0 BGR=1
584 hx8347dProperties.width = 240;
585 hx8347dProperties.height = 320;
586 }
587 hx8347dPOrientation = orientation;
588 lcd_area(0, 0, (hx8347dProperties.width-1), (hx8347dProperties.height-1));
589 }
590
591 /**************************************************************************/
592 /*!
593 @brief Gets the current screen orientation (horizontal or vertical)
594 */
595 /**************************************************************************/
596 lcdOrientation_t lcdGetOrientation(void)
597 {
598 return hx8347dPOrientation;
599 }
600
601 /**************************************************************************/
602 /*!
603 @brief Gets the width in pixels of the LCD screen (varies depending
604 on the current screen orientation)
605 */
606 /**************************************************************************/
607 uint16_t lcdGetWidth(void)
608 {
609 return hx8347dProperties.width;
610 }
611
612 /**************************************************************************/
613 /*!
614 @brief Gets the height in pixels of the LCD screen (varies depending
615 on the current screen orientation)
616 */
617 /**************************************************************************/
618 uint16_t lcdGetHeight(void)
619 {
620 return hx8347dProperties.height;
621 }
622
623 /**************************************************************************/
624 /*!
625 @brief Scrolls the contents of the LCD screen vertically the
626 specified number of pixels using a HW optimised routine
627 */
628 /**************************************************************************/
629
630 void lcdScroll(int16_t pixels, uint16_t fillColor)
631 {
632
633 hx8347d_Scroll(0,320,0,(offset + pixels) % 320);
634 if(hx8347dPOrientation == LCD_ORIENTATION_PORTRAIT)
635 {
636 fillRect(0, hx8347dProperties.height-pixels, hx8347dProperties.width, hx8347dProperties.height, fillColor);
637 }
638 else
639 {
640 fillRect(hx8347dProperties.width-pixels, 0, hx8347dProperties.width, hx8347dProperties.height, fillColor);
641 }
642 offset = (offset + pixels) % 320;
643 }
644 /**************************************************************************/
645 /*!
646 @brief Set LCD into standby
647 In deep standby: LCD has lower power consumption
648 */
649 /**************************************************************************/
650 void hx8347d_Standby(bool deep)
651 {
652 displayOffFlow();
653 lcd_cmd(Power_Control_6 , Power_Control_6_STB);
654 if(deep)
655 {
656 lcd_cmd(Display_Mode_Control,Display_Mode_Control_DP_STB_S);
657 lcd_cmd(Display_Mode_Control, Display_Mode_Control_DP_STB);
658 }
659 lcd_cmd(OSC_Control_2, ~OSC_Control_2_OSC_EN);
660 }
661 /**************************************************************************/
662 /*!
663 @brief Wakeup LCD from standby
664 Wakeup from deep standby you need min. 20ms
665 */
666 /**************************************************************************/
667 void hx8347d_Wakeup(bool deep)
668 {
669 lcd_cmd(OSC_Control_2, OSC_Control_2_OSC_EN);
670
671 if(deep)
672 {
673 lcd_cmd(Display_Mode_Control,0x0000);
674 systickDelay(20);
675 lcd_cmd(Display_Mode_Control, 0x0000);
676 }
677 else
678 {
679 systickDelay(5);
680 }
681
682 lcd_cmd(Power_Control_6, 0x00D0);
683 displayOnFlow();
684 }
685
686 /**************************************************************************/
687 /*!
688 @brief Gets the controller's 16-bit (4 hexdigit) ID
689 */
690 /**************************************************************************/
691 uint16_t lcdGetControllerID(void)
692 {
693 return 0x0;
694 }
695
696 /**************************************************************************/
697 /*!
698 @brief Returns the LCDs 'lcdProperties_t' that describes the LCDs
699 generic capabilities and dimensions
700 */
701 /**************************************************************************/
702 lcdProperties_t lcdGetProperties(void)
703 {
704 return hx8347dProperties;
705 }
706
This page took 0.110611 seconds and 5 git commands to generate.