; nokia_test.asm ; -------------- ; Author: J. Selbing. ; URL: http://www.selbing.com/_jakob/index.htm ; ; Atmel ATmega8 test program for PCD8544-based LCDs, ; like the ones in many Nokia cellular phones. The bus ; speed can become an isue if you run the ATmega8 at ; frequencies higher than 1 MHz. This can be fixed by ; inserting NOP's around LCD clock transitions. ; ; The program assumes that the LCD signals are all connected ; to PORTB, pin 0 through 5, in the following matter: ; ; Pin 0 = not connected ; Pin 1 = LCD /RST (reset, active low) ; Pin 2 = LCD /SCE (chip enable, active low) ; Pin 3 = LCD SDIN (serial data) ; Pin 4 = LCD SCLK (serial clock) ; Pin 5 = LCD D/C (Data or /Command) ; ; LCD Vdd is supplied with 3.3 V, and LCD Vss is connected ; to common ground. ; ; WARNING: THE ATMEGA8 MUST ALSO RUN FROM 3.3 V! .device ATmega8 .equ SPH =$3e .equ SPL =$3d .equ PORTB =$18 .equ DDRB =$17 .equ RAMEND =$45F ; PORTB ; ----- .EQU LCD_INVRST = 1 .EQU LCD_INVCE = 2 .EQU LCD_SDA = 3 .EQU LCD_SCL = 4 .EQU LCD_DINVC = 5 .EQU DDRB_init = 0b00111111 .EQU PORTB_init = 0b00000100 .EQU send_data = 1 .EQU send_command = 0 .CSEG .ORG 0x00 rjmp RESET RESET: ldi r16, high(RAMEND) ; Initialize stack out SPH, r16 ldi r16, low(RAMEND) out SPL, r16 ldi r16, DDRB_init ; Initialize ports out DDRB, r16 ldi r16, PORTB_init out PORTB, r16 ldi r16, 100 rcall delay ; Wait for a little while sbi PORTB, LCD_INVCE ; Bus reset cbi PORTB, LCD_INVRST ; Reset LCD - VERY IMPORTANT! ldi r16, 100 rcall delay sbi PORTB, LCD_INVRST ldi r16, 100 rcall delay cbi PORTB, LCD_INVCE ; Enable bus ldi r16, 0x21 ; Function set - extended set rcall LCD_send_command ldi r16, 0x80 + 70 ; Set Vop = 3.06 + 0.06*66 = 7.02 V rcall LCD_send_command ldi r16, 0x13 ; Set bias system, MUX = 1:48 rcall LCD_send_command ldi r16, 0x20 ; Function set - basic set rcall LCD_send_command ldi r16, 0x0C ; Display control - normal mode rcall LCD_send_command sbi PORTB, LCD_INVCE ; Bus reset ldi r20, high(84*6) ldi r21, low(84*6) cbi PORTB, LCD_INVCE ; Enable bus ; Write some stuff to LCD lcd_loop: mov r16, r21 ; Output lower byte of counter rcall LCD_send_data ldi r23, 0 ; Decrease counter ldi r24, 1 sub r21, r24 sbc r20, r23 mov r0, r20 ; Check if zero mov r1, r21 or r0, r1 brne lcd_loop sbi PORTB, LCD_INVCE ; Bus reset ldi r17, 250 rcall long_delay ldi r19, 70 ldi r18, 0xff ; This loop swings the contrast up & down contrast_loop: cbi PORTB, LCD_INVCE ; Enable bus ldi r16, 0x21 ; Function set - extended set rcall LCD_send_command ldi r16, 0x80 add r16, r19 rcall LCD_send_command sbi PORTB, LCD_INVCE ; Bus reset ldi r17, 20 rcall long_delay add r19, r18 ; Increase or decrease contrast breq contrast_up ; If 0, start counting up cpi r19, 80 ; If too large, start counting down breq contrast_down rjmp contrast_loop contrast_down: ldi r18, 0xff rjmp contrast_loop contrast_up: ldi r18, 1 rjmp contrast_loop ; Routine for sending data or command to LCD LCD_send_data: sbi PORTB, LCD_DINVC rjmp LCD_send_setup LCD_send_command: cbi PORTB, LCD_DINVC LCD_send_setup: cbi PORTB, LCD_SCL ldi r17, 8 LCD_send_bitloop: cbi PORTB, LCD_SDA ; Set data = 0 sbrc r16, 7 sbi PORTB, LCD_SDA ; If MSB = 1, set data = 1 rol r16 sbi PORTB, LCD_SCL ; Clock = 1 dec r17 cbi PORTB, LCD_SCL ; Clock = 0 brne LCD_send_bitloop ret delay: nop nop dec r16 brne delay ret long_delay: ldi r16, 255 rcall delay dec r17 brne long_delay ret