1 | ; Display Test for LCD DEM120064
|
2 | ; (C) Mario Latzig 2017
|
3 | ;
|
4 | ; on ATtiny2313(A), 4 MHz ext. Crystal
|
5 | ;
|
6 | ; PB0: CS (Chip Select, active Low)
|
7 | ; PB1: RES (Reset, active Low)
|
8 | ; PB2: DC (Data=High / Command=Low)
|
9 | ; PB3: SCK (Serial Clock, Data is triggered on Low-High-Edge)
|
10 | ; PB4: SDA (Serial Data)
|
11 | ;
|
12 | ; PD2: LED (Test LED, active High)
|
13 |
|
14 | ; *****************************************************************************
|
15 | ; *** Definitions ***
|
16 | ; *****************************************************************************
|
17 | .def temp = r0 ; Temporary Register (Memory load)
|
18 | .def zero = r1 ; (always Zero)
|
19 | .def stat = r2 ; Temporary Status Register
|
20 | .def a = r16 ; Temporary Register (a)
|
21 | .def b = r17 ; Temporary Register (b)
|
22 | .def c = r18 ; Temporary Register (c)
|
23 | .def d = r19 ; Temporary Register (d)
|
24 | .def e = r20 ; Temporary Register (e)
|
25 | .def f = r21 ; Temporary Register (f)
|
26 | .def g = r22 ; Temporary Register (g)
|
27 | .def pdat = r23 ; Temporary Port Register
|
28 | .def ol = r24 ; Counter Register (LO)
|
29 | .def oh = r25 ; Counter Register (HI)
|
30 |
|
31 | ; --- General -----------------------------------------------------------------
|
32 | .equ FC = 4000000 ; Clock = 4 MHz (ext. Crystal)
|
33 |
|
34 | ; --- Pins --------------------------------------------------------------------
|
35 | .equ PINB_CS = (1<<0) ; PB0: CS (Chip Select, active Low)
|
36 | .equ PINB_RES = (1<<1) ; PB1: RES (Reset, active Low)
|
37 | .equ PINB_DC = (1<<2) ; PB2: DC (Data=High / Command=Low)
|
38 | .equ PINB_SCK = (1<<3) ; PB3: SCK (Serial Clock, Data is triggered on Low-High-Edge)
|
39 | .equ PINB_SDA = (1<<4) ; PB4: SDA (Serial Data)
|
40 |
|
41 | .equ PIND_LED = (1<<2) ; PD2: LED (Test LED, active High)
|
42 |
|
43 | ; === LCD =====================================================================
|
44 | ; $00: Set Lower Column Address
|
45 | .equ LCD_SET_COL_LO = 0x00
|
46 | ; $10: Set Higher Column Address
|
47 | .equ LCD_SET_COL_HI = 0x10
|
48 | ; $20: Set Internal Regulator Resistor Ratio (X0-X2: Internal regulator gain increases as X2X1X0 increased from 000b to 111b. At POR = 100b)
|
49 | .equ LCD_SET_INT_REG_RES_RATIO = 0x20
|
50 | ; $28: Set Power Control Register (X0: Output op-amp buffer, X1: internal regulator,X2: internal voltage booster)
|
51 | .equ LCD_SET_POWER_CTRL = 0x28
|
52 | ; $81: Set Contrast
|
53 | .equ LCD_SET_CONTRAST = 0x81
|
54 | ; $A0: Set Segment Re-map (X0=0: Col Addr $00=SEG0 (POR), X0=1: Col Addr $83=SEG0)
|
55 | .equ LCD_CMD_SEGMENT_REMAP = 0xA0
|
56 | ; $A2: Set LCD Bias (X0=0: 1/9 Bias, X0=1: 1/7 Bias)
|
57 | .equ LCD_CMD_BIAS = 0xA2
|
58 | ; $A6: Set Normal/Reverse Display (X0=0: normal display (POR), X0=1: reverse display)
|
59 | .equ LCD_SET_NORMAL_DISPLAY = 0xA6
|
60 | ; $A9: Set Bias Ratio / Set TC Value / Modify Osc. Freq.
|
61 | .equ LCD_SET_BIAS_TC_OSC = 0xA9
|
62 | ; $AE: Set Entire Display On/Off (X0=0: normal display (POR), X0=1: entire display on)
|
63 | .equ LCD_SET_DISPLAY = 0xAE
|
64 | ; $B0: Set Set Page Address
|
65 | .equ LCD_SET_PAGE = 0xB0
|
66 | ; $C0: Set COM Output Scan Direction (X3=0: COM0 to COM[N-1] (POR), X3=1: COM[N-1] to COM0)
|
67 | .equ LCD_SET_COM_OUTPUT_SCAN_DIR = 0xC0
|
68 |
|
69 | .equ LCD_COLS = 20 ; Number of Chars per Row
|
70 | .equ LCD_ROWS = 8 ; Number of Rows
|
71 |
|
72 | ; *****************************************************************************
|
73 | ; *** SRAM ***
|
74 | ; *****************************************************************************
|
75 | .dseg
|
76 |
|
77 | ; *****************************************************************************
|
78 | ; *** Vectors ***
|
79 | ; *****************************************************************************
|
80 | .cseg
|
81 | .org 0x0000
|
82 | rjmp init
|
83 | .org INT_VECTORS_SIZE
|
84 |
|
85 | ; *****************************************************************************
|
86 | ; *** Main ***
|
87 | ; *****************************************************************************
|
88 | .include "font.inc"
|
89 |
|
90 | ; ### INIT ####################################################################
|
91 |
|
92 | init:
|
93 | cli ; Disable interrupts
|
94 |
|
95 | clr zero ; Reset Zero Register
|
96 | ldi a,LOW(RAMEND) ; Init Stack Pointer
|
97 | out SPL,a
|
98 |
|
99 | rcall led_init ; Inits Test LED
|
100 | rcall lcd_init ; Inits LCD
|
101 |
|
102 | sei ; Enable interrupts
|
103 |
|
104 | ; ### TEST ####################################################################
|
105 |
|
106 | test:
|
107 | ldi a,'!'
|
108 | ldi oh,0
|
109 | test_loop_row:
|
110 | ldi ol,0
|
111 | test_loop_col:
|
112 | rcall lcd_char
|
113 | inc a
|
114 | cpi a,0x7F
|
115 | brne test_loop_cnt
|
116 | ldi a,'!'|0x80
|
117 | test_loop_cnt:
|
118 | inc ol
|
119 | cpi ol,LCD_COLS
|
120 | brlo test_loop_col
|
121 | inc oh
|
122 | cpi oh,LCD_ROWS
|
123 | brlo test_loop_row
|
124 |
|
125 | test_hold:
|
126 | rjmp test_hold
|
127 |
|
128 | ; *****************************************************************************
|
129 | ; *** LCD ***
|
130 | ; *****************************************************************************
|
131 |
|
132 | ; ### Inits LCD
|
133 | lcd_init:
|
134 | push a
|
135 | push b
|
136 | push pdat
|
137 |
|
138 | in pdat,PORTB
|
139 | sbr pdat,PINB_RES|PINB_CS
|
140 | cbr pdat,PINB_SCK|PINB_SDA|PINB_DC
|
141 | out PORTB,pdat
|
142 | in a,DDRB
|
143 | sbr a,PINB_SCK|PINB_SDA|PINB_DC|PINB_CS|PINB_RES
|
144 | out DDRB,a
|
145 |
|
146 | ser a ; Enable Test LED
|
147 | rcall led_set
|
148 |
|
149 | cbr pdat,PINB_RES ; Trigger HW Reset of LCD
|
150 | out PORTB,pdat
|
151 | rcall util_delay_10us
|
152 | sbr pdat,PINB_RES
|
153 | out PORTB,pdat
|
154 |
|
155 | ldi a,LCD_CMD_BIAS|0 ; Init Sequence
|
156 | rcall lcd_cmd
|
157 | ldi a,LCD_CMD_SEGMENT_REMAP|0
|
158 | rcall lcd_cmd
|
159 | ldi a,LCD_SET_COM_OUTPUT_SCAN_DIR|8
|
160 | rcall lcd_cmd
|
161 | ldi a,LCD_SET_INT_REG_RES_RATIO|5
|
162 | rcall lcd_cmd
|
163 | ldi a,LCD_SET_NORMAL_DISPLAY
|
164 | rcall lcd_cmd
|
165 | ldi a,LCD_SET_POWER_CTRL|7
|
166 | rcall lcd_cmd
|
167 | ldi a,LCD_SET_DISPLAY|1
|
168 | rcall lcd_cmd
|
169 | ldi a,LCD_SET_CONTRAST
|
170 | ldi b,0x20
|
171 | rcall lcd_cmd2
|
172 |
|
173 | clr a ; Disable Test LED
|
174 | rcall led_set
|
175 |
|
176 | pop pdat
|
177 | pop b
|
178 | pop a
|
179 | ret
|
180 |
|
181 | ; ### Draw Char
|
182 | ; >a: The ASCII Char (0-127), Bit7: Invert Flag
|
183 | ; >ol: The Column (0-19)
|
184 | ; >oh: The Row (0-7)
|
185 | lcd_char:
|
186 | push temp
|
187 | push a
|
188 | push b
|
189 | push pdat
|
190 | push ol
|
191 | push oh
|
192 | push zl
|
193 | push zh
|
194 |
|
195 | lcd_char_chk:
|
196 | mov temp,a
|
197 | cpi ol,LCD_COLS ; ### Check Range
|
198 | brsh lcd_char_exit
|
199 | cpi oh,LCD_ROWS
|
200 | brsh lcd_char_exit
|
201 |
|
202 | lcd_char_col: ; ### Set LCD Column
|
203 | lsl ol
|
204 | mov b,ol ; (Multiply Char Column by 6)
|
205 | lsl ol
|
206 | add b,ol
|
207 | subi b,-6
|
208 | mov a,b
|
209 | andi a,0x0F
|
210 | ori a,LCD_SET_COL_LO
|
211 | rcall lcd_cmd
|
212 | mov a,b
|
213 | swap a
|
214 | andi a,0x0F
|
215 | ori a,LCD_SET_COL_HI
|
216 | rcall lcd_cmd
|
217 | lcd_char_row: ; ### Set LCD Page Address
|
218 | mov a,oh ; (Using Char Row)
|
219 | ori a,LCD_SET_PAGE
|
220 | rcall lcd_cmd
|
221 |
|
222 | lcd_char_font: ; ### Calculate Font Address
|
223 | ldi zl,LOW(2*FONT5X7) ; Offset = (ASCII Char - 0x20) * 5
|
224 | ldi zh,HIGH(2*FONT5X7)
|
225 | mov a,temp
|
226 | andi a,0x7F
|
227 | cpi a,' '
|
228 | brsh lcd_char_font_cnt
|
229 | ldi a,' '
|
230 | lcd_char_font_cnt:
|
231 | subi a,' '
|
232 | clr b
|
233 | add zl,a
|
234 | adc zh,b
|
235 | lsl a
|
236 | rol b
|
237 | lsl a
|
238 | rol b
|
239 | add zl,a
|
240 | adc zh,b
|
241 |
|
242 | lcd_char_draw: ; ### Draw Char
|
243 | in pdat,PORTB ; Enable Chip Select
|
244 | cbr pdat,PINB_CS
|
245 | out PORTB,pdat
|
246 |
|
247 | ldi ol,5 ; Set 5 Bytes as Data
|
248 | lcd_char_draw_loop:
|
249 | lpm a,z+
|
250 | sbrc temp,7
|
251 | com a
|
252 | ser b
|
253 | rcall lcd_byte
|
254 | dec ol
|
255 | brne lcd_char_draw_loop
|
256 | clr a ; Add 1 Byte as Space
|
257 | sbrc temp,7
|
258 | com a
|
259 | rcall lcd_byte
|
260 |
|
261 | in pdat,PORTB ; Disable Chip Select
|
262 | sbr pdat,PINB_CS
|
263 | out PORTB,pdat
|
264 |
|
265 | lcd_char_exit:
|
266 | pop zh
|
267 | pop zl
|
268 | pop oh
|
269 | pop ol
|
270 | pop pdat
|
271 | pop b
|
272 | pop a
|
273 | pop temp
|
274 | ret
|
275 |
|
276 | ; ### Send 2-Byte Command
|
277 | ; >a: The Command
|
278 | ; >b: The Data
|
279 | lcd_cmd2:
|
280 | push temp
|
281 | push a
|
282 | push b
|
283 | push pdat
|
284 |
|
285 | in pdat,PORTB ; Enable Chip Select
|
286 | cbr pdat,PINB_CS
|
287 | out PORTB,pdat
|
288 |
|
289 | mov temp,b ; Send Command
|
290 | clr b
|
291 | rcall lcd_byte
|
292 | mov a,temp ; Send Data
|
293 | rcall lcd_byte
|
294 |
|
295 | in pdat,PORTB ; Disable Chip Select
|
296 | sbr pdat,PINB_CS
|
297 | out PORTB,pdat
|
298 |
|
299 | pop pdat
|
300 | pop b
|
301 | pop a
|
302 | pop temp
|
303 | ret
|
304 |
|
305 | ; ### Send Single Command Byte
|
306 | ; >a: The Command
|
307 | lcd_cmd:
|
308 | push b
|
309 | push pdat
|
310 |
|
311 | in pdat,PORTB ; Enable Chip Select
|
312 | cbr pdat,PINB_CS
|
313 | out PORTB,pdat
|
314 |
|
315 | clr b ; Send Byte
|
316 | rcall lcd_byte
|
317 |
|
318 | in pdat,PORTB ; Disable Chip Select
|
319 | sbr pdat,PINB_CS
|
320 | out PORTB,pdat
|
321 |
|
322 | pop pdat
|
323 | pop b
|
324 | ret
|
325 |
|
326 | ; ### Shift Byte
|
327 | ; >a: The Byte
|
328 | ; >b: The DC Flag
|
329 | lcd_byte:
|
330 | push a
|
331 | push b
|
332 | push pdat
|
333 |
|
334 | in pdat,PORTB ; Set DC Pin
|
335 | cbr pdat,PINB_DC
|
336 | cpse b,zero
|
337 | sbr pdat,PINB_DC
|
338 | out PORTB,pdat
|
339 |
|
340 | lcd_byte_shift: ; Bit-Banging Input Byte (MSB first)
|
341 | ldi b,8
|
342 | lcd_byte_shift_loop:
|
343 | cbr pdat,PINB_SDA
|
344 | lsl a
|
345 | brcc lcd_byte_shift_cnt
|
346 | sbr pdat,PINB_SDA
|
347 | lcd_byte_shift_cnt:
|
348 | out PORTB,pdat
|
349 | sbr pdat,PINB_SCK
|
350 | out PORTB,pdat
|
351 | cbr pdat,PINB_SCK
|
352 | out PORTB,pdat
|
353 | dec b
|
354 | brne lcd_byte_shift_loop
|
355 |
|
356 | pop pdat
|
357 | pop b
|
358 | pop a
|
359 | ret
|
360 |
|
361 | ; *****************************************************************************
|
362 | ; *** Test LED ***
|
363 | ; *****************************************************************************
|
364 |
|
365 | ; ### Inits LED
|
366 | led_init:
|
367 | push a
|
368 |
|
369 | in a,DDRD ; Set LED Pins to Output
|
370 | sbr a,PIND_LED
|
371 | out DDRD,a
|
372 |
|
373 | ser a ; Flash LED
|
374 | rcall led_set
|
375 | ldi a,250
|
376 | rcall util_delay_Xms
|
377 | clr a
|
378 | rcall led_set
|
379 | ldi a,250
|
380 | rcall util_delay_Xms
|
381 |
|
382 | pop a
|
383 | ret
|
384 |
|
385 |
|
386 | ; ### Switch LED
|
387 | ; >a: The enabled flag
|
388 | led_set:
|
389 | push pdat
|
390 |
|
391 | in pdat,PORTD
|
392 | cbr pdat,PIND_LED
|
393 | cpse a,zero
|
394 | sbr pdat,PIND_LED
|
395 | out PORTD,pdat
|
396 |
|
397 | pop pdat
|
398 | ret
|
399 |
|
400 | ; *****************************************************************************
|
401 | ; *** Core Utility ***
|
402 | ; *****************************************************************************
|
403 |
|
404 | ; ### Delay 10us
|
405 | .equ CLK10US = ((FC/100000)-12)/3 ; Constant for 10us including RCALL
|
406 | util_delay_10us:
|
407 | push a ; 1 x push = 2 clocks
|
408 |
|
409 | ldi a,CLK10US ; 1 x load = 1 clock
|
410 | util_delay_10us_loop:
|
411 | dec a ; N * 3 clocks
|
412 | brne util_delay_10us_loop
|
413 |
|
414 | pop a ; 1 x pop + ret = 6 clocks
|
415 | ret
|
416 |
|
417 | ; ### Delay 1ms
|
418 | .equ CLK1MS = ((FC/1000)-17)/4 ; Constant for 1ms including RCALL
|
419 | util_delay_1ms:
|
420 | push ol ; 2 x push = 4 clocks
|
421 | push oh
|
422 |
|
423 | ldi oh,HIGH(CLK1MS) ; 2 x load = 2 clocks
|
424 | ldi ol,LOW(CLK1MS)
|
425 | util_delay_1ms_loop:
|
426 | sbiw ol,1 ; N * 4 clocks
|
427 | brne util_delay_1ms_loop
|
428 |
|
429 | pop oh ; 2 x pop + ret = 8 clocks
|
430 | pop ol
|
431 | ret
|
432 |
|
433 | ; ### Delay X*0-255 ms
|
434 | ; (tolerance by additional 2+X*(0+1+2)+2+4
|
435 | ; >a: value of ms
|
436 | util_delay_Xms:
|
437 | push a
|
438 |
|
439 | util_delay_Xms_loop: ; Delays X times for one millisecond
|
440 | rcall util_delay_1ms ; Cycles for RCALL are already included in calculation here
|
441 | dec a
|
442 | brne util_delay_Xms_loop
|
443 |
|
444 | pop a
|
445 | ret
|