8d2d29c91f11d8cb88b33811423ca6d2757ef0e9
[hackover2013-badge-firmware.git] / lcd / display_r0ket.c
1 #include <string.h>
2
3 #include <display.h>
4 #include <sysdefs.h>
5 #include "lpc134x.h"
6 #include "core/ssp/ssp.h"
7 #include "gpio/gpio.h"
8 #include "basic/basic.h"
9 #include "basic/config.h"
10 #include "usb/usbmsc.h"
11
12
13 #define DISPLAY_N1200 0
14 #define DISPLAY_N1600 1
15
16 #define MODE 8 /* 8 or 16 */
17
18 #if MODE == 8
19 #define putpix(x) _helper_pixel8(x)
20 #define px_INIT_MODE 2
21 #define px_PACK(r,g,b) COLORPACK_RGB332(r,g,b)
22 #define px_type uint8_t
23 #else
24 #if MODE == 12
25 #define putpix(x) _helper_pixel12(x)
26 #define px_INIT_MODE 3
27 #define px_PACK(r,g,b) COLORPACK_RGB444(r,g,b)
28 #define px_type uint16_t
29 #else
30 #define putpix(x) _helper_pixel16(x)
31 #define px_INIT_MODE 5
32 #define px_PACK(r,g,b) COLORPACK_RGB565(r,g,b)
33 #define px_type uint16_t
34 #endif
35 #endif
36
37 /**************************************************************************/
38 /* Utility routines to manage nokia display */
39 /**************************************************************************/
40
41 uint8_t lcdBuffer[RESX*RESY_B];
42 uint32_t intstatus; // Caches USB interrupt state
43 // (need to disable MSC while displaying)
44 uint8_t displayType;
45
46 #define TYPE_CMD 0
47 #define TYPE_DATA 1
48
49 static void lcd_select() {
50 #if CFG_USBMSC
51 if(usbMSCenabled){
52 intstatus=USB_DEVINTEN;
53 USB_DEVINTEN=0;
54 };
55 #endif
56 /* the LCD requires 9-Bit frames */
57 uint32_t configReg = ( SSP_SSP0CR0_DSS_9BIT // Data size = 9-bit
58 | SSP_SSP0CR0_FRF_SPI // Frame format = SPI
59 | SSP_SSP0CR0_SCR_8); // Serial clock rate = 8
60 SSP_SSP0CR0 = configReg;
61 gpioSetValue(RB_LCD_CS, 0);
62 }
63
64 static void lcd_deselect() {
65 gpioSetValue(RB_LCD_CS, 1);
66 /* reset the bus to 8-Bit frames that everyone else uses */
67 uint32_t configReg = ( SSP_SSP0CR0_DSS_8BIT // Data size = 8-bit
68 | SSP_SSP0CR0_FRF_SPI // Frame format = SPI
69 | SSP_SSP0CR0_SCR_8); // Serial clock rate = 8
70 SSP_SSP0CR0 = configReg;
71 #if CFG_USBMSC
72 if(usbMSCenabled){
73 USB_DEVINTEN=intstatus;
74 };
75 #endif
76 }
77
78 static void lcdWrite(uint8_t cd, uint8_t data) {
79 uint16_t frame = 0x0;
80
81 frame = cd << 8;
82 frame |= data;
83
84 while ((SSP_SSP0SR & (SSP_SSP0SR_TNF_NOTFULL | SSP_SSP0SR_BSY_BUSY)) != SSP_SSP0SR_TNF_NOTFULL);
85 SSP_SSP0DR = frame;
86 while ((SSP_SSP0SR & (SSP_SSP0SR_BSY_BUSY|SSP_SSP0SR_RNE_NOTEMPTY)) != SSP_SSP0SR_RNE_NOTEMPTY);
87 /* clear the FIFO */
88 frame = SSP_SSP0DR;
89 }
90
91 #define CS 2,1
92 #define SCK 2,11
93 #define SDA 0,9
94 #define RST 2,2
95
96 uint8_t lcdRead(uint8_t data)
97 {
98 uint32_t op211cache=IOCON_PIO2_11;
99 uint32_t op09cache=IOCON_PIO0_9;
100 uint32_t dircache=GPIO_GPIO2DIR;
101 IOCON_PIO2_11=IOCON_PIO2_11_FUNC_GPIO|IOCON_PIO2_11_MODE_PULLUP;
102 IOCON_PIO0_9=IOCON_PIO0_9_FUNC_GPIO|IOCON_PIO0_9_MODE_PULLUP;
103 gpioSetDir(SCK, 1);
104
105 uint8_t i;
106
107 gpioSetDir(SDA, 1);
108 gpioSetValue(SCK, 0);
109 gpioSetValue(CS, 0);
110 delayms(1);
111
112 gpioSetValue(SDA, 0);
113 gpioSetValue(SCK, 1);
114 delayms(1);
115
116 for(i=0; i<8; i++){
117 gpioSetValue(SCK, 0);
118 delayms(1);
119 if( data & 0x80 )
120 gpioSetValue(SDA, 1);
121 else
122 gpioSetValue(SDA, 0);
123 data <<= 1;
124 gpioSetValue(SCK, 1);
125 delayms(1);
126 }
127 uint8_t ret = 0;
128
129 gpioSetDir(SDA, 0);
130 for(i=0; i<8; i++){
131 gpioSetValue(SCK, 0);
132 delayms(1);
133 ret <<= 1;
134 ret |= gpioGetValue(SDA);
135 gpioSetValue(SCK, 1);
136 delayms(1);
137 }
138 gpioSetValue(SCK, 0);
139
140 gpioSetValue(CS, 1);
141 gpioSetDir(SDA, 1);
142 IOCON_PIO2_11=op211cache;
143 IOCON_PIO0_9=op09cache;
144 GPIO_GPIO2DIR=dircache;
145 delayms(1);
146 return ret;
147 }
148
149
150 void lcdInit(void) {
151 int id;
152
153 sspInit(0, sspClockPolarity_Low, sspClockPhase_RisingEdge);
154
155 gpioSetValue(RB_LCD_CS, 1);
156 gpioSetValue(RB_LCD_RST, 1);
157
158 gpioSetDir(RB_LCD_CS, gpioDirection_Output);
159 gpioSetDir(RB_LCD_RST, gpioDirection_Output);
160
161 delayms(100);
162 gpioSetValue(RB_LCD_RST, 0);
163 delayms(100);
164 gpioSetValue(RB_LCD_RST, 1);
165 delayms(100);
166
167 id=lcdRead(220); // ID3
168
169 if(id==14)
170 displayType=DISPLAY_N1600;
171 else /* ID3 == 48 */
172 displayType=DISPLAY_N1200;
173
174 /* Small Nokia 1200 LCD docs:
175 * clear/ set
176 * on 0xae / 0xaf
177 * invert 0xa6 / 0xa7
178 * mirror-x 0xA0 / 0xA1
179 * mirror-y 0xc7 / 0xc8
180 *
181 * 0x20+x contrast (0=black - 0x2e)
182 * 0x40+x offset in rows from top (-0x7f)
183 * 0x80+x contrast? (0=black -0x9f?)
184 * 0xd0+x black lines from top? (-0xdf?)
185 *
186 */
187 lcd_select();
188
189 if(displayType==DISPLAY_N1200){
190 /* Decoded:
191 * E2: Internal reset
192 * AF: Display on/off: DON = 1
193 * A1: undefined?
194 * A4: all on/normal: DAL = 0
195 * 2F: charge pump on/off: PC = 1
196 * B0: set y address: Y[0-3] = 0
197 * 10: set x address (upper bits): X[6-4] = 0
198 */
199 static uint8_t initseq[]= { 0xE2,0xAF, // Display ON
200 0xA1, // Mirror-X
201 0xA4, 0x2F, 0xB0, 0x10};
202 int i = 0;
203 while(i<sizeof(initseq)){
204 lcdWrite(TYPE_CMD,initseq[i++]);
205 delayms(5); // actually only needed after the first
206 }
207 }else{ /* displayType==DISPLAY_N1600 */
208 static uint8_t initseq_d[] = {
209 /* The controller is a PCF8833 -
210 documentation can be found online.
211 * CMD 01: Soft-reset
212 * CMD 11: Sleep-out
213 * CMD 29: Display ON
214 * CMD 03: Booster voltage ON
215 * CMD 13: Normal display mode
216 * CMD 3A: interface pixel format
217 * DAT 02 | 02: 8 bit/pixel (3:3:2)
218 * | 03: 12 bit/pixel (4:4:4)
219 * | 05: 16 bit/pixel (5:6:5)
220 * CMD 2A: column address set
221 * DAT 1 : xs
222 * DAT 98-2 : xe
223 * CMD 2B: page address set
224 * DAT 1 : ys
225 * DAT 70-2 : ye
226 */
227 0x11,
228 0x29,
229 0x03,
230 0x13,
231 0x3A, px_INIT_MODE,
232 0x2A, 1, 98-2,
233 0x2B, 1, 70-2
234 };
235 uint16_t initseq_c = ~ ( /* comands: 1, data: 0 */
236 (1<<0) |
237 (1<<1) |
238 (1<<2) |
239 (1<<3) |
240 (1<<4) | (0<< 5) |
241 (1<<6) | (0<< 7) | (0<< 8) |
242 (1<<9) | (0<<10) | (0<<11) |
243 0);
244 int i = 0;
245
246 lcdWrite(0, 0x01); /* most color displays need the pause */
247 delayms(10);
248
249 while(i<sizeof(initseq_d)){
250 lcdWrite(initseq_c&1, initseq_d[i++]);
251 initseq_c = initseq_c >> 1;
252 }
253 }
254 lcd_deselect();
255 }
256
257 void lcdFill(char f){
258 memset(lcdBuffer,f,RESX*RESY_B);
259 #if 0
260 int x;
261 for(x=0;x<RESX*RESY_B;x++) {
262 lcdBuffer[x]=f;
263 }
264 #endif
265 }
266
267 void lcdSetPixel(char x, char y, bool f){
268 if (x<0 || x> RESX || y<0 || y > RESY)
269 return;
270 char y_byte = (RESY-(y+1)) / 8;
271 char y_off = (RESY-(y+1)) % 8;
272 char byte = lcdBuffer[y_byte*RESX+(RESX-(x+1))];
273 if (f) {
274 byte |= (1 << y_off);
275 } else {
276 byte &= ~(1 << y_off);
277 }
278 lcdBuffer[y_byte*RESX+(RESX-(x+1))] = byte;
279 }
280
281 bool lcdGetPixel(char x, char y){
282 char y_byte = (RESY-(y+1)) / 8;
283 char y_off = (RESY-(y+1)) % 8;
284 char byte = lcdBuffer[y_byte*RESX+(RESX-(x+1))];
285 return byte & (1 << y_off);
286 }
287
288 // Color display helper functions
289 static inline void _helper_pixel8(uint8_t color1){
290 lcdWrite(TYPE_DATA, color1);
291 }
292
293 static void _helper_pixel12(uint16_t color){
294 static char odd=0;
295 static char rest;
296 if(odd){
297 lcdWrite(TYPE_DATA,(rest<<4) | (color>>8));
298 lcdWrite(TYPE_DATA,color&0xff);
299 }else{
300 lcdWrite(TYPE_DATA,(color>>4)&0xff);
301 rest=(color&0x0f);
302 };
303 odd=1-odd;
304 }
305
306 static void _helper_pixel16(uint16_t color){
307 lcdWrite(TYPE_DATA,color>>8);
308 lcdWrite(TYPE_DATA,color&0xFF);
309 }
310
311 #define COLORPACK_RGB565(r,g,b) (((r&0xF8) << 8) | ((g&0xFC)<<3) | ((b&0xF8) >> 3))
312 #define COLORPACK_RGB444(r,g,b) ( ((r&0xF0)<<4) | (g&0xF0) | ((b&0xF0)>>4) )
313 #define COLORPACK_RGB332(r,g,b) ( (((r>>5)&0x7)<<5) | (((g>>5)&0x7)<<2) | ((b>>6)&0x3) )
314
315 static const px_type COLOR_FG = px_PACK(0x00, 0x00, 0x00);
316 static const px_type COLOR_BG = px_PACK(0xff, 0xff, 0xff);
317
318 void lcdDisplay(void) {
319 char byte;
320 lcd_select();
321
322 if(displayType==DISPLAY_N1200){
323 lcdWrite(TYPE_CMD,0xB0);
324 lcdWrite(TYPE_CMD,0x10);
325 lcdWrite(TYPE_CMD,0x00);
326 uint16_t i,page;
327 for(page=0; page<RESY_B;page++) {
328 for(i=0; i<RESX; i++) {
329 if (GLOBAL(lcdmirror))
330 byte=lcdBuffer[page*RESX+RESX-1-(i)];
331 else
332 byte=lcdBuffer[page*RESX+(i)];
333
334 if (GLOBAL(lcdinvert))
335 byte=~byte;
336
337 lcdWrite(TYPE_DATA,byte);
338 }
339 }
340 } else { /* displayType==DISPLAY_N1600 */
341 uint16_t x,y;
342 bool px;
343
344 lcdWrite(TYPE_CMD,0x2C);
345
346 for(y=RESY;y>0;y--){
347 for(x=RESX;x>0;x--){
348 if(GLOBAL(lcdmirror))
349 px=lcdGetPixel(RESX-x,y-1);
350 else
351 px=lcdGetPixel(x-1,y-1);
352
353 if((!px)^(!GLOBAL(lcdinvert))) {
354 putpix(COLOR_FG); /* foreground */
355 } else {
356 putpix(COLOR_BG); /* background */
357 }
358 }
359 }
360 };
361 lcd_deselect();
362 }
363
364 void lcdRefresh() __attribute__ ((weak, alias ("lcdDisplay")));
365
366 inline void lcdInvert(void) {
367 GLOBAL(lcdinvert)=!GLOBAL(lcdinvert);
368 }
369
370 void lcdSetContrast(int c) {
371 lcd_select();
372 if(displayType==DISPLAY_N1200){
373 if(c<0x1F)
374 lcdWrite(TYPE_CMD,0x80+c);
375 }else{ /* displayType==DISPLAY_N1600 */
376 if(c<0x40) {
377 lcdWrite(TYPE_CMD,0x25);
378 lcdWrite(TYPE_DATA,4*c);
379 };
380 }
381 lcd_deselect();
382 }
383
384 void lcdSetInvert(int c) {
385 lcd_select();
386 /* it doesn't harm N1600, save space */
387 // if(displayType==DISPLAY_N1200)
388 lcdWrite(TYPE_CMD,(c&1)+0xa6);
389 lcd_deselect();
390 }
391
392 /* deprecated */
393 void __attribute__((__deprecated__)) lcdToggleFlag(int flag) {
394 if(flag==LCD_MIRRORX)
395 GLOBAL(lcdmirror)=!GLOBAL(lcdmirror);
396 if(flag==LCD_INVERTED)
397 GLOBAL(lcdinvert)=!GLOBAL(lcdinvert);
398 }
399
400 void lcdShiftH(bool right, bool wrap) {
401 uint8_t tmp;
402 for (int yb = 0; yb<RESY_B; yb++) {
403 if (right) {
404 tmp = lcdBuffer[yb*RESX];
405 memmove(lcdBuffer + yb*RESX,lcdBuffer + yb*RESX+1 ,RESX-1);
406 lcdBuffer[yb*RESX+(RESX-1)] = wrap?tmp:0;
407 } else {
408 tmp = lcdBuffer[yb*RESX+(RESX-1)];
409 memmove(lcdBuffer + yb*RESX+1,lcdBuffer + yb*RESX ,RESX-1);
410 lcdBuffer[yb*RESX] = wrap?tmp:0;
411 }
412 }
413 }
414
415 void lcdShiftV8(bool up, bool wrap) {
416 uint8_t tmp[RESX];
417 if (!up) {
418 if (wrap)
419 memmove(tmp, lcdBuffer, RESX);
420 else
421 memset(tmp,0,RESX);
422 memmove(lcdBuffer,lcdBuffer+RESX ,RESX*(RESY_B-1));
423 memmove(lcdBuffer+RESX*(RESY_B-1),tmp,RESX);
424 } else {
425 if (wrap)
426 memmove(tmp, lcdBuffer+RESX*(RESY_B-1), RESX);
427 else
428 memset(tmp,0,RESX);
429 memmove(lcdBuffer+RESX,lcdBuffer ,RESX*(RESY_B-1));
430 memmove(lcdBuffer,tmp,RESX);
431 }
432 }
433
434 void lcdShiftV(bool up, bool wrap) {
435 uint8_t tmp[RESX];
436 if (up) {
437 if (wrap)
438 memmove(tmp,lcdBuffer+((RESY_B-1)*RESX),RESX);
439 else
440 memset(tmp,0,RESX);
441 for (int x = 0; x<RESX; x++){
442 for (int y = RESY_B-1; y > 0; y--){
443 lcdBuffer[x+(y*RESX)] = (lcdBuffer[x+(y*RESX)] << 1) |( lcdBuffer[x+((y-1)*RESX)] >> 7);
444 }
445 lcdBuffer[x] = ( lcdBuffer[x] << 1) | ((tmp[x]>>3)&1);
446 }
447
448 } else {
449 if (wrap)
450 memmove(tmp,lcdBuffer,RESX);
451 else
452 memset(tmp,0,RESX);
453 for (int x = 0; x<RESX; x++){
454 for (int y = 0; y < (RESY_B-1); y++){
455 lcdBuffer[x+(y*RESX)] = (lcdBuffer[x+(y*RESX)] >> 1) |( lcdBuffer[x+((y+1)*RESX)] << 7);
456 }
457 lcdBuffer[x+((RESY_B-1)*RESX)] = ( lcdBuffer[x+((RESY_B-1)*RESX)] >> 1) | ((tmp[x]<<3)&8);
458 }
459 }
460 }
461
462 void lcdShift(int x, int y, bool wrap) {
463 bool dir=true;
464
465 if(x<0){
466 dir=false;
467 x=-x;
468 };
469
470 while(x-->0)
471 lcdShiftH(dir, wrap);
472
473 if(y<0){
474 dir=false;
475 y=-y;
476 }else{
477 dir=true;
478 };
479
480 while(y>=8){
481 y-=8;
482 lcdShiftV8(dir, wrap);
483 };
484
485 while(y-->0)
486 lcdShiftV(dir, wrap);
487 }
488
This page took 0.154851 seconds and 3 git commands to generate.