summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2008-10-18 22:28:59 +0000
committerFrank Gevaerts <frank@gevaerts.be>2008-10-18 22:28:59 +0000
commit49ec9ea19013184d70bc1ad83eb0301fcce8d99b (patch)
tree2805f9f945dd14666bc28124c0dcd6f13a082694
parentd8b2645a641110d184fe72fd6a8f4a9442713c8d (diff)
downloadrockbox-49ec9ea19013184d70bc1ad83eb0301fcce8d99b.tar.gz
rockbox-49ec9ea19013184d70bc1ad83eb0301fcce8d99b.zip
Make the meizu m3 load from flash, so interrupts work. More work is needed to get the m6sl "working" again
(patch by Denes Balatoni, FS#9499) git-svn-id: svn://svn.rockbox.org/rockbox/trunk@18827 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--bootloader/meizu_m3.c45
-rw-r--r--firmware/SOURCES2
-rw-r--r--firmware/drivers/qt1106.c8
-rw-r--r--firmware/target/arm/s5l8700/boot.lds54
-rw-r--r--firmware/target/arm/s5l8700/crt0.S320
-rw-r--r--firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c42
6 files changed, 405 insertions, 66 deletions
diff --git a/bootloader/meizu_m3.c b/bootloader/meizu_m3.c
index 8e3a7f64c8..acd07d7c66 100644
--- a/bootloader/meizu_m3.c
+++ b/bootloader/meizu_m3.c
@@ -104,43 +104,32 @@ void bl_debug_int(unsigned int input,unsigned int count)
104void main(void) 104void main(void)
105{ 105{
106 char mystring[64]; 106 char mystring[64];
107 int tmpval;
108
109 /* set fclk = 200MHz, hclk = 100MHz, pclk = 50MHz, others off */
110 CLKCON = 0x00800080;
111 PLLCON = 0;
112 PLL0PMS = 0x1ad200;
113 PLL0LCNT = 8100;
114 PLLCON = 1;
115 while (!(PLLLOCK & 1)) ;
116 CLKCON2= 0x80;
117 CLKCON = 0x20803180;
118
119 /* mask all interrupts
120 this is done, because the lcd framebuffer
121 overwrites some stuff, which leads to a freeze
122 when an irq is generated after the dfu upload.
123 crt0 should have disabled irqs,
124 but the bootrom hands us execution in
125 user mode so we can't switch interrupts off */
126 INTMSK = 0;
127 107
128 //Set backlight pin to output and enable 108 //Set backlight pin to output and enable
129 int oldval = PCON0; 109 int oldval = PCON0;
130 PCON0 = ((oldval & ~(3 << 4)) | (1 << 4)); 110 PCON0 = ((oldval & ~(3 << 4)) | (1 << 4));
131 PDAT0 |= (1 << 2); 111 PDAT0 |= (1 << 2);
132 112
133 //Set PLAY to input 113 //power on
134 oldval = PCON1; 114// oldval = PCON1;
135 PCON1 = ((oldval & ~(0xf << 16)) | (0 << 16)); 115// PCON1 = ((oldval & ~(0xf << 12)) | (1 << 12));
116// PDAT1|=(1<<3);
136 117
137 asm volatile("mrs %0, cpsr \n\t" 118 //Set PLAY to EINT4
138 : "=r" (tmpval) 119 oldval = PCON1;
139 ); 120 PCON1 = ((oldval & ~(0xf << 16)) | (2 << 16));
140 121
122 //Set MENU to EINT0
123 oldval = PCON1;
124 PCON1 = (oldval & ~(0xf)) | 2;
125
126 // enable external interrupts
127 EINTPOL = 0x11;
128 INTMSK = 0x11;
129 EINTMSK = 0x11;
130 asm volatile("msr cpsr_c, #0x13\n\t"); // enable interrupts
131
141 lcd_init(); 132 lcd_init();
142 snprintf(mystring, 64, "tmpval: %x", tmpval);
143 lcd_puts(0,0,mystring);
144 lcd_update(); 133 lcd_update();
145 134
146 init_qt1106(); 135 init_qt1106();
diff --git a/firmware/SOURCES b/firmware/SOURCES
index 3de2077435..65bb2eb5b5 100644
--- a/firmware/SOURCES
+++ b/firmware/SOURCES
@@ -360,6 +360,8 @@ target/arm/tcc77x/crt0.S
360target/arm/tcc780x/crt0.S 360target/arm/tcc780x/crt0.S
361#elif CONFIG_CPU==IMX31L 361#elif CONFIG_CPU==IMX31L
362target/arm/imx31/crt0.S 362target/arm/imx31/crt0.S
363#elif CONFIG_CPU==S5L8700
364target/arm/s5l8700/crt0.S
363#elif defined(CPU_ARM) 365#elif defined(CPU_ARM)
364target/arm/crt0.S 366target/arm/crt0.S
365#endif /* defined(CPU_*) */ 367#endif /* defined(CPU_*) */
diff --git a/firmware/drivers/qt1106.c b/firmware/drivers/qt1106.c
index 8869fada22..67573fe0ae 100644
--- a/firmware/drivers/qt1106.c
+++ b/firmware/drivers/qt1106.c
@@ -75,10 +75,10 @@ unsigned int qt1106_io(unsigned int output)
75 75
76 while(!RDY) {} 76 while(!RDY) {}
77 77
78 delay(10); // < 470 us 78 delay(10*100); // < 470 us
79 79
80 CLRSS(); 80 CLRSS();
81 delay(13); // > 22 us 81 delay(13*100); // > 22 us
82 82
83 for (i = 0; i < 24; i++) { 83 for (i = 0; i < 24; i++) {
84 84
@@ -90,14 +90,14 @@ unsigned int qt1106_io(unsigned int output)
90 CLRMOSI(); 90 CLRMOSI();
91 output <<= 1; 91 output <<= 1;
92 92
93 delay(20); // >> 6.7 us 93 delay(20*100); // >> 6.7 us
94 94
95 SETCLK(); 95 SETCLK();
96 96
97 input <<= 1; 97 input <<= 1;
98 input |= MISO; 98 input |= MISO;
99 99
100 delay(20); // >> 6.7 us 100 delay(20*100); // >> 6.7 us
101 } 101 }
102 102
103 SETSS(); 103 SETSS();
diff --git a/firmware/target/arm/s5l8700/boot.lds b/firmware/target/arm/s5l8700/boot.lds
index 8ce942c9b2..2d2a686f9d 100644
--- a/firmware/target/arm/s5l8700/boot.lds
+++ b/firmware/target/arm/s5l8700/boot.lds
@@ -1,12 +1,12 @@
1#include "config.h" 1#include "config.h"
2 2
3ENTRY(start) 3ENTRY(_start)
4OUTPUT_FORMAT(elf32-bigarm) 4OUTPUT_FORMAT(elf32-bigarm)
5OUTPUT_ARCH(arm) 5OUTPUT_ARCH(arm)
6STARTUP(target/arm/crt0.o) 6STARTUP(target/arm/s5l8700/crt0.o)
7 7
8/* DRAMORIG is in fact 0x8000000 but remapped to 0x0 */ 8/* DRAMORIG is in fact 0x8000000 but remapped to 0x0 */
9#define DRAMORIG 0x0 9#define DRAMORIG 0x8000000
10#define DRAMSIZE 16M 10#define DRAMSIZE 16M
11 11
12#define IRAMORIG 0x22000000 12#define IRAMORIG 0x22000000
@@ -22,41 +22,67 @@ STARTUP(target/arm/crt0.o)
22#define FLASHORIG 0x24000000 22#define FLASHORIG 0x24000000
23#define FLASHSIZE 1M 23#define FLASHSIZE 1M
24 24
25MEMORY
26{
27 DRAM : ORIGIN = DRAMORIG, LENGTH = DRAMSIZE
28 IRAM : ORIGIN = IRAMORIG, LENGTH = IRAMSIZE
29 FLASH : ORIGIN = FLASHORIG, LENGTH = FLASHSIZE
30}
31
32
25SECTIONS 33SECTIONS
26{ 34{
27 /*. = IRAMORIG; */ 35 .intvect : {
28 /* As long as we don't flash the code, use the DFU load address */ 36 _intvectstart = . ;
29 . = DFULOADADDR; 37 *(.intvect)
38 _intvectend = _newstart ;
39 } >IRAM AT> FLASH
40 _intvectcopy = LOADADDR(.intvect) ;
30 41
31 .text : { 42 .text : {
32 *(.init.text) 43 *(.init.text)
33 *(.text*) 44 *(.text*)
34 } 45 *(.glue_7*)
46 } > FLASH
47
48 .rodata : {
49 *(.rodata*)
50 . = ALIGN(0x4);
51 } > FLASH
35 52
36 .data : { 53 .data : {
37 *(.icode) 54 _datastart = . ;
38 *(.irodata) 55 *(.irodata)
56 *(.icode)
39 *(.idata) 57 *(.idata)
40 *(.data*) 58 *(.data*)
41 *(.ncdata*); 59 *(.ncdata*);
60 . = ALIGN(0x4);
42 _dataend = . ; 61 _dataend = . ;
43 } 62 } > IRAM AT> FLASH
63 _datacopy = LOADADDR(.data) ;
44 64
45 .stack : 65 .stack :
46 { 66 {
47 *(.stack) 67 *(.stack)
48 _stackbegin = .; 68 _stackbegin = .;
49 stackbegin = .; 69 . += 0x2000;
50 . += 0x1000;
51 _stackend = .; 70 _stackend = .;
52 stackend = .; 71 _irqstackbegin = .;
53 } 72 . += 0x400;
73 _irqstackend = .;
74 _fiqstackbegin = .;
75 . += 0x400;
76 _fiqstackend = .;
77 } > IRAM
54 78
55 .bss : { 79 .bss : {
56 _edata = .; 80 _edata = .;
57 *(.bss*); 81 *(.bss*);
58 *(.ibss); 82 *(.ibss);
59 *(.ncbss*); 83 *(.ncbss*);
84 *(COMMON);
85 . = ALIGN(0x4);
60 _end = .; 86 _end = .;
61 } 87 } > IRAM
62} 88}
diff --git a/firmware/target/arm/s5l8700/crt0.S b/firmware/target/arm/s5l8700/crt0.S
new file mode 100644
index 0000000000..0dcc203844
--- /dev/null
+++ b/firmware/target/arm/s5l8700/crt0.S
@@ -0,0 +1,320 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id: crt0.S 18776 2008-10-11 18:32:17Z gevaerts $
9 *
10 * Copyright (C) 2008 by Marcoen Hirschberg
11 * Copyright (C) 2008 by Denes Balatoni
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ****************************************************************************/
22#include "config.h"
23#include "cpu.h"
24
25 .section .intvect,"ax",%progbits
26 .global _start
27 .global _newstart
28 /* Exception vectors */
29_start:
30 b _newstart
31 ldr pc, =undef_instr_handler
32 ldr pc, =software_int_handler
33 ldr pc, =prefetch_abort_handler
34 ldr pc, =data_abort_handler
35 ldr pc, =reserved_handler
36 ldr pc, =irq_handler
37 ldr pc, =fiq_handler
38#if CONFIG_CPU==S5L8700
39 .word 0x43554644 /* DFUC */
40#endif
41 .ltorg
42_newstart:
43 ldr pc, =newstart2 // we do not want to execute from 0x0 as iram will be mapped there
44 .section .init.text,"ax",%progbits
45newstart2:
46 msr cpsr_c, #0xd3 /* enter supervisor mode, disable IRQ/FIQ */
47
48 mov r1, #0x80
49 mrc 15, 0, r0, c1, c0, 0
50 orr r0, r0, r1
51 mcr 15, 0, r0, c1, c0, 0 // set bigendian
52
53 ldr r1, =0x3c800000 // disable watchdog
54 mov r0, #0xa5
55 str r0, [r1]
56
57 mov r0, #0
58 ldr r1, =0x39c00008
59 str r0, [r1] // mask all interrupts
60 ldr r1, =0x39c00020
61 str r0, [r1] // mask all external interrupts
62 mvn r0, #0
63 mov r1, #0x39c00000
64 str r0, [r1] // irq priority
65 ldr r1, =0x39c00010
66 str r0, [r1] // clear pending interrupts
67 ldr r1, =0x39c0001c
68 str r0, [r1] // clear pending external interrupts
69
70// ldr r1, =0x3cf00000
71// ldr r0, [r1]
72// mvn r2, #0x30
73// and r0, r0, r2
74// mov r2, #0x10
75// orr r0, r0, r2
76// str r0, [r1]
77// ldr r1, =0x3cf00004
78// ldr r0, [r1]
79// mov r2, #4
80// orr r0, r0, r2
81// str r0, [r1] // switch backlight on
82
83 ldr r1, =0x3c500000 // CLKCON
84 ldr r0, =0x00800080
85 str r0, [r1]
86 ldr r1, =0x3c500024 // PLLCON
87 mov r0, #0
88 str r0, [r1]
89 ldr r1, =0x3c500004 // PLL0PMS
90 ldr r0, =0x1ad200
91 str r0, [r1]
92 ldr r1, =0x3c500014 // PLL0LCNT
93 ldr r0, =8100
94 str r0, [r1]
95 ldr r1, =0x3c500024 // PLLCON
96 mov r0, #1
97 str r0, [r1]
98 ldr r1, =0x3c500020 // PLLLOCK
991:
100 ldr r0, [r1]
101 tst r0, #1
102 beq 1b
103 ldr r1, =0x3c50003c // CLKCON2
104 mov r0, #0x80
105 str r0, [r1]
106 ldr r1, =0x3c500000 // CLKCON
107 ldr r0, =0x20803180
108 str r0, [r1] // FCLK_CPU = 200MHz, HCLK = 100MHz, PCLK = 50MHz, other clocks off
109
110 ldr r2, =0xc0000078
111 mrc 15, 0, r0, c1, c0, 0
112 mvn r1, #0xc0000000
113 and r0, r0, r1
114 orr r0, r0, r2
115 mcr 15, 0, r0, c1, c0, 0 // asynchronous clocking mode
116 nop
117 nop
118 nop
119 nop
120
121// ldr r0, =0x10100000
122// ldr r1, =0x38200034
123// str r0, [r1] // SRAM0/1 data width 16 bit
124// ldr r0, =0x00220922
125// ldr r7, =0x38200038
126// str r0, [r7] // SRAM0/1 clocks
127// ldr r0, =0x00220922
128// ldr r9, =0x3820003c
129// str r0, [r9] // SRAM2/3 clocks
130// nop
131// nop
132// nop
133// nop
134
135 ldr r1, =0x3c500000
136 mov r0, #0 // 0x0
137 str r0, [r1, #40] // enable clock for all peripherals
138 mov r0, #0 // 0x0
139 str r0, [r1, #44] // do not enter any power saving mode
140
141 mov r1, #0x1
142 mrc 15, 0, r0, c1, c0, 0
143 bic r0, r0, r1
144 mcr 15, 0, r0, c1, c0, 0 // disable protection unit
145
146 mov r1, #0x4
147 mrc 15, 0, r0, c1, c0, 0
148 bic r0, r0, r1
149 mcr 15, 0, r0, c1, c0, 0 // dcache disable
150
151 mov r1, #0x1000
152 mrc 15, 0, r0, c1, c0, 0
153 bic r0, r0, r1
154 mcr 15, 0, r0, c1, c0, 0 // icache disable
155
156 mov r1, #0
1571:
158 mov r0, #0
1592:
160 orr r2, r1, r0
161 mcr 15, 0, r2, c7, c14, 2 // clean and flush dcache single entry
162 add r0, r0, #0x10
163 cmp r0, #0x40
164 bne 2b
165 add r1, r1, #0x4000000
166 cmp r1, #0x0
167 bne 1b
168 nop
169 nop
170 mov r0, #0
171 mcr 15, 0, r0, c7, c10, 4 // clean and flush whole dcache
172
173 mov r0, #0
174 mcr 15, 0, r0, c7, c5, 0 // flush icache
175
176 mov r0, #0
177 mcr 15, 0, r0, c7, c6, 0 // flush dcache
178
179 mov r0, #0x3f
180 mcr 15, 0, r0, c6, c0, 1
181 mov r0, #0x2f
182 mcr 15, 0, r0, c6, c1, 1
183 ldr r0, =0x0800002f
184 mcr 15, 0, r0, c6, c2, 1
185 ldr r0, =0x22000023
186 mcr 15, 0, r0, c6, c3, 1
187 ldr r0, =0x24000027
188 mcr 15, 0, r0, c6, c4, 1
189 mov r0, #0x3f
190 mcr 15, 0, r0, c6, c0, 0
191 mov r0, #0x2f
192 mcr 15, 0, r0, c6, c1, 0
193 ldr r0, =0x0800002f
194 mcr 15, 0, r0, c6, c2, 0
195 ldr r0, =0x22000023
196 mcr 15, 0, r0, c6, c3, 0
197 ldr r0, =0x24000029
198 mcr 15, 0, r0, c6, c4, 0
199 mov r0, #0x1e
200 mcr 15, 0, r0, c2, c0, 1
201 mov r0, #0x1e
202 mcr 15, 0, r0, c2, c0, 0
203 mov r0, #0x1e
204 mcr 15, 0, r0, c3, c0, 0
205 ldr r0, =0x0000ffff
206 mcr 15, 0, r0, c5, c0, 1
207 ldr r0, =0x0000ffff
208 mcr 15, 0, r0, c5, c0, 0 // set up protection and caching
209
210 mov r1, #0x4
211 mrc 15, 0, r0, c1, c0, 0
212 orr r0, r0, r1
213 mcr 15, 0, r0, c1, c0, 0 // dcache enable
214
215 mov r1, #0x1000
216 mrc 15, 0, r0, c1, c0, 0
217 orr r0, r0, r1
218 mcr 15, 0, r0, c1, c0, 0 // icache enable
219
220 mov r1, #0x1
221 mrc 15, 0, r0, c1, c0, 0
222 orr r0, r0, r1
223 mcr 15, 0, r0, c1, c0, 0 // enable protection unit
224
225
226 /* Copy interrupt vectors to iram */
227 ldr r2, =_intvectstart
228 ldr r3, =_intvectend
229 ldr r4, =_intvectcopy
2301:
231 cmp r3, r2
232 ldrhi r1, [r4], #4
233 strhi r1, [r2], #4
234 bhi 1b
235
236 /* Initialise bss section to zero */
237 ldr r2, =_edata
238 ldr r3, =_end
239 mov r4, #0
2401:
241 cmp r3, r2
242 strhi r4, [r2], #4
243 bhi 1b
244
245 /* Copy icode and data to ram */
246 ldr r2, =_datastart
247 ldr r3, =_dataend
248 ldr r4, =_datacopy
2491:
250 cmp r3, r2
251 ldrhi r1, [r4], #4
252 strhi r1, [r2], #4
253 bhi 1b
254
255 /* Set up some stack and munge it with 0xdeadbeef */
256 ldr sp, =_stackend
257 ldr r2, =_stackbegin
258 ldr r3, =0xdeadbeef
2591:
260 cmp sp, r2
261 strhi r3, [r2], #4
262 bhi 1b
263
264 /* Set up stack for IRQ mode */
265 msr cpsr_c, #0xd2
266 ldr sp, =_irqstackend
267
268 /* Set up stack for FIQ mode */
269 msr cpsr_c, #0xd1
270 ldr sp, =_fiqstackend
271
272 /* Let abort and undefined modes use IRQ stack */
273 msr cpsr_c, #0xd7
274 ldr sp, =_irqstackend
275 msr cpsr_c, #0xdb
276 ldr sp, =_irqstackend
277
278 /* Switch back to supervisor mode */
279 msr cpsr_c, #0xd3
280
281// if we did not switch remap on, device
282// would crash when MENU is pressed,
283// as that button is connected to BOOT_MODE pin
284 ldr r1, =0x38200000
285 ldr r0, [r1]
286 mvn r2, #0x10000
287 and r0, r0, r2
288 mov r2, #0x1
289 orr r0, r0, r2
290 str r0, [r1] // remap iram to address 0x0
291
292 bl main
293
294 .text
295/* .global UIE*/
296
297/* All illegal exceptions call into UIE with exception address as first
298 * parameter. This is calculated differently depending on which exception
299 * we're in. Second parameter is exception number, used for a string lookup
300 * in UIE. */
301undef_instr_handler:
302 mov r0, lr
303 mov r1, #0
304 b UIE
305
306/* We run supervisor mode most of the time, and should never see a software
307 * exception being thrown. Perhaps make it illegal and call UIE? */
308software_int_handler:
309reserved_handler:
310 movs pc, lr
311
312prefetch_abort_handler:
313 sub r0, lr, #4
314 mov r1, #1
315 b UIE
316
317data_abort_handler:
318 sub r0, lr, #8
319 mov r1, #2
320 b UIE
diff --git a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
index 624f2aa444..4b355302fd 100644
--- a/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
+++ b/firmware/target/arm/s5l8700/meizu-m3/lcd-m3.c
@@ -69,7 +69,7 @@ void lcd_set_flip(bool yesno)
69static void lcd_sleep(uint32_t t) 69static void lcd_sleep(uint32_t t)
70{ 70{
71 volatile uint32_t i; 71 volatile uint32_t i;
72 for(i=0;i<t;++i) t=t; 72 for(i=0;i<t;++i);
73} 73}
74 74
75static uint8_t lcd_readdata() 75static uint8_t lcd_readdata()
@@ -115,6 +115,7 @@ void lcd_off() {
115void lcd_init_device(void) 115void lcd_init_device(void)
116{ 116{
117 uint8_t data[5]; 117 uint8_t data[5];
118 int i;
118 119
119/* init basic things */ 120/* init basic things */
120 PWRCON &= ~0x800; 121 PWRCON &= ~0x800;
@@ -126,25 +127,26 @@ void lcd_init_device(void)
126 LCD_INTCON = 0; 127 LCD_INTCON = 0;
127 LCD_RST_TIME = 0x7ff; 128 LCD_RST_TIME = 0x7ff;
128 129
129/* detect lcd type */ 130/* detect lcd type, it's not detected the first time for some reason */
130 LCD_WCMD = 0x1; 131 for(i=0;i<3;++i) {
131 lcd_sleep(166670); 132 LCD_WCMD = 0x1;
132 LCD_WCMD = 0x11; 133 lcd_sleep(166670);
133 lcd_sleep(2000040); 134 LCD_WCMD = 0x11;
134 lcd_readdata(); 135 lcd_sleep(2000040);
135 LCD_WCMD = 0x4; 136 lcd_readdata();
136 lcd_sleep(100); 137 LCD_WCMD = 0x4;
137 data[0]=lcd_readdata(); 138 lcd_sleep(100);
138 data[1]=lcd_readdata(); 139 data[0]=lcd_readdata();
139 data[2]=lcd_readdata(); 140 data[1]=lcd_readdata();
140 data[3]=lcd_readdata(); 141 data[2]=lcd_readdata();
141 data[4]=lcd_readdata(); 142 data[3]=lcd_readdata();
142 143 data[4]=lcd_readdata();
143 lcd_type=0; 144
144 if (((data[1]==0x38) && ((data[2] & 0xf0) == 0x80)) || 145 lcd_type=0;
145 ((data[2]==0x38) && ((data[3] & 0xf0) == 0x80))) 146 if (((data[1]==0x38) && ((data[2] & 0xf0) == 0x80)) ||
146 lcd_type=1; 147 ((data[2]==0x38) && ((data[3] & 0xf0) == 0x80)))
147 148 lcd_type=1;
149 }
148/* init lcd */ 150/* init lcd */
149 if (lcd_type == 1) { 151 if (lcd_type == 1) {
150 LCD_WCMD = 0x3a; 152 LCD_WCMD = 0x3a;