Full Version : Butterfly LCD Driver (ASM)
avr >>BEGINNERS & BUTTERFLIES >>Butterfly LCD Driver (ASM)


AVR_Admin- 04-27-2006
A Butterfly LCD Driver in Assembler by SteveN:

QUOTE ("SteveN")

I have post below the applicable parts of my code that deals with the LCD display. I will attempt to explain why and how I do certain things certain ways. I cannot explain everything though because, to be honest, I have forgotten why certain things have to be done a certain way (or at least why I thought they had to be done that way). Such things as why do I have routines to determine whether the digit is odd or even, or why I swap nibbles in a byte. I used application notes AVR064 and AVR065 and the STK502 User Manual extensively when I was learning how to deal with the Butterfly LCD. You can find the application notes on Atmels web site but the STK502 User Manual is no longer there (I think). I do believe someone pointed out that the STK502 User Manual could be found on this site. I found it on an Atmel CD that came with one of my "toys" I bought from Atmel. Anyway, the code is cut and pasted from an application I did so it may seem chopped up. I hope I get everything.


CODE

; *****************************************************************************
; *****************************************************************************
;
;                        REGISTER DEFINITIONS - START
;
.def   TC_cntL      =   r0          ; Total Cycles count, low byte
.def   TC_cntH      =   r1          ; Total Cycles count, high byte
;
; Note: The LCD display used on the Butterfly has 7 alphanumeric digits
;       available (+ special symbols), BUT, the mega169 does not have enough
;       I/O available to drive all those segments. Thus, the Butterfly only
;       uses 6 of the digits. Reading from left to right on the display, the
;       first digit is not used...that is why I start with digit2 below.
;
.def   digit2      =   r2          ; = 100,000's digit on Butterfly display
.def   digit3      =   r3          ; = 10,000's digit on Butterfly display
.def   digit4      =   r4          ; = 1,000's digit on Butterfly display
.def   digit5      =   r5          ; = 100's digit on Butterfly display
.def   digit6      =   r6          ; = 10's digit on Butterfly display
.def   digit7      =   r7          ; = 1's digit on Butterfly display

.def   FC_cntL      =   r8          ; Failed Cycles count, low byte
.def   FC_cntH      =   r9          ; Failed Cycles count, high byte

.def   Delay_amt1   =   r10
.def   Delay_amt2   =   r11

.def   Byte_cnt   =   r12
.def   Bit_pntr   =   r13

.def   Rotate_cnt   =   r14

.def   PC_INT1_cnt   =   r15

.def   temp1L      =   r16
.def   temp1H      =   r17
.def   temp2L      =   r18
.def   temp2H      =   r19
;
.def   T0OF_cnt   =   r20          ; Timer0 overflow count
.def   T2OF_cnt   =   r21          ; Timer2 overflow count
;
.def   RangeE      =   r22          ; Range Exceeded
;
; -----------------------------------------------------------------------------
.def   Flags      =   r23
; --- bit definitions for Flags register ---
;
; bit0 = One second passed yet (OS)      1=Yes         0=No
; bit1 = Pass/Fail status (PF)         1=Fail         0=Pass
; bit2 = Even/Odd digit (EOD)         1=Odd digit,    0=Even digit
; bit3 = First time PE4 ISR   (FTPE4)      1=>than first   0=first time through
; bit4 = Out of range (OOR)            1=out of range   0=within range
; bit5 = TBA
; bit6 = TBA
; bit7 = TBA
; -----------------------------------------------------------------------------
;
.def   wtempL      =   r24    ; register pair to be used with adiw, sbiw
.def   wtempH      =   r25    ;  (for example to find when a 16 bit value
                     ;    equals zero)
;
;
;                         REGISTER DEFINITIONS - END
;
; *****************************************************************************
; *****************************************************************************



Code:

; *****************************************************************************
; *****************************************************************************
;
;                              EQUATES - START
;
.equ   OS_bn      =   0    ; One second flag bit number
.equ   OS_msk      =   (1<<0) ; One second flag bit mask (0b00000001)
;
.equ   PF_bn      =   1    ; Pass/Fail flag bit number
.equ   PF_msk      =   (1<<1) ; Pass/Fail flag bit mask (0b00000010)
;
.equ   EOD_bn      =   2    ; Even/Odd Digit flag bit number
.equ   EOD_msk      =   (1<<2) ; Even/Odd Digit flag bit mask (0b00000100)
;
.equ   FTPE4_bn   =   3    ; First time PE4 ISR status bit number
.equ   FTPE4_msk   =   (1<<3) ; First time PE4 ISR status bit mask
;
.equ   OOR_bn      =   4    ; Timer0 value Out Of Range flag bit number
.equ   OOR_msk      =   (1<<4) ; Timer0 value Out Of Range flag bit mask
;
;.equ   TBA         =   5    ;
;.equ   TBA         =   (1<<5) ;
;
;.equ   TBA         =   6    ;
;.equ   TBA         =   (1<<6) ;
;
.equ   PC_INT1_bn   =   7    ;
.equ   PC_INT1_msk   =   (1<<7) ;
;
;
;                               EQUATES - END
;
; *****************************************************************************
; *****************************************************************************
;
; *****************************************************************************
; *****************************************************************************
;
;                        Internal SRAM assignments - Start
;
.dseg
;
.org   0x0100             ; start of internal SRAM and an even address

LCDDRx_ptr: .byte   2       ; temp save of LCDDRx pointer (low byte=YL)

LCD_ptr:   .byte   2       ; temp save of LCD data pointer (low byte=ZL)

X_save:      .byte   2       ; save XH:XL pointer register value here

Cycle:      .byte   90       ; 90 x 8 = 720 possible Cycles - each bit of a
                     ; byte represents a completed Cycle. A "0" in
                     ; a bit represents a "Passed" Cycle, a "1" in
                     ; a bit represents a "Failed" Cycle
;
; Note: A cycle consists of (approximately) a 1 minute On and a 1 minute Off
;       period. Therefore it is possible to measure approximately 30 cycles
;       per hour. Over a 12 hour period the total number of cycles is
;       approximately 12 * 30 = 360. The above 720 possible cycles would
;       provide room for a 24 hour burn-in period.
;
;                         Internal SRAM assignments - End
;
; *****************************************************************************
; *****************************************************************************



Code:

; -----------------------------------------------------------------------------
;
;                      LCD Initialization - Start
;
; Use external 8MHz clock oscillator
; Setup for 1/3 Bias (LCD2B = 0)
; Setup for 1/4 duty and enable all COM (LCDMUX1,LCDMUX0 = 0b11) pins
; Enable all segment (LCDPM2,LCDPM1,LCDPM0 = 0b111) pins
;
ldi    temp1L, (0<<LCDCS) | (0<<LCD2B) | (3<<LCDMUX0) | (7<<LCDPM0)
sts    LCDCRB, temp1L
;
; Dividing LCD clock (8.00MHz) by 4096 (LCDPS2,LCDPS1,LCDPS0 = 0b111)
; and dividing output from prescaler by 8 (LCDCD2,LCDCD1,LCDCD0 = 0b111)
; gives a frame rate of 30.5 Hz
;
ldi    temp1L, (7<<LCDPS0) | (7<<LCDCD0)
sts    LCDFRR, temp1L
;
; Set LCD Contrast Control output voltage to 3.0 V
;
ldi    temp1L, (1<<LCDCC3)
sts    LCDCCR, temp1L
;
; Enable LCD
;
ldi    temp1L, (1<<LCDEN)
sts    LCDCRA, temp1L
                  ; setup to display "WAIT04" on the LCD display
                  ; "04" is the version of this code
ldi      temp1L,0x21       ; W
mov      digit2,temp1L
ldi      temp1L,0x0B       ; A
mov      digit3,temp1L
ldi      temp1L,0x13       ; I
mov      digit4,temp1L
ldi      temp1L,0x1E       ; T
mov      digit5,temp1L
ldi      temp1L,0x00       ; 0
mov      digit6,temp1L
ldi      temp1L,0x04       ; 4
mov      digit7,temp1L
call   LCD_Display
;
;                           LCD Initialization - End
;



Code:

; -----------------------------------------------------------------------------
; -----------------------------------------------------------------------------
;
;                     LCD_Display SUBROUTINE - START
;
; The purpose of this software is to take BCD coded values stored in r2-r7 and
; display them on the Butterfly LCD display. The BCD coded values are stored in
; registers R2 - R7. The first value stored is labeled
; digit2 and represents the 100,000's digit of a number (my end application
; for this routine will not actually use this digit...it is included here for
; possible future use).
;
; There are 6 registers reserved for these BCD values because there are 6
; digits on the Butterfly display (actually there are 7 digits available on the
; Butterfly display but because of limitations of the mega169 only 6 are
; available for use). Please see the "REGISTER DEFINITIONS" section of this
; code for further naming conventions for these SRAM locations.
;
; The digits on the Butterfly LCD display are numbered 2 - 7 going from left to
; right (the unused digit is the far left #1 digit). The code is, obviously,
; written to place the 100,000's digit in the far left LCD digit, the 10'000's
; digit in the next LCD digit to the right and so forth until the 1's digit is
; written to the far right LCD digit.
;
; It is up to the routine calling this routine to place the BCD values into the
; (correct) registers before calling this routine.
;
; I have utilized pointers (X, Y, and Z) so that I can use looping code instead
; of straight line code. Please see the "Pointer Initialization" section of this
; routine to see how I have assigned the pointers.
;
; I have utilized a look-up table located in Flash program memory as a means of
; converting the BCD values (stored in SRAM) into values that the mega169 LCD
; controller can use to activate the appropriate segments.
;
; *****************************************************************************
; *****************************************************************************
;
;                               Statistics
;
; Execution time = 626 cycles (78.25uS @ 8MHz clock)
; Registers used = 5
; SRAM used      = 9
;
;
; *****************************************************************************
; *****************************************************************************
;
;
; save registers used in this routine
LCD_Display:
push   XL
push   XH
push   YL
push   YH
push   ZL
push   ZH
push   wtempL
push   wtempH
push   temp2L
push   temp2H
push   temp1L
push   temp1H

ldi      temp1L,0x00          ; clear LCDDRx registers of previous data
ldi      YL,LCDDR0          ; Y points to LCDDRx registers
clr      YH
Clear_LCDDRx:
st      Y+,temp1L
cpi      YL,LCDDR18+1
brne   Clear_LCDDRx

; suppress leading zeroes if present and/or required in number to be displayed
; in 100's, 10's and 1's digits (r5, r6 and r7)
ldi      XL,0x05             ; X points to 100's (r5) digit
clr      XH                ; X will never be greater than 255
                     ; therefore XH will always be zero
Leading_zero:
ld      temp1L,X          ; temp1L = contents @ X (r5, r6 or r7)
tst      temp1L             ; is it = 0 ?
brne   Pointer_init       ; if not, go re-initialize pointer to r2
                     ; (r2 = leftmost digit of LCD)
ldi      temp1L,0x0A          ; otherwise save 0x0A offset (0x0A points to
                     ; value saved in the lookup table for a blank
                     ; digit)
st      X,temp1L          ; into location pointed to by X
adiw   XH:XL,0x01          ; point to next digit in SRAM
cpi      XL,0x08             ; compare X with address of r7 + 1
breq   Pointer_init       ; if 2 values compare r7 has been checked
rjmp   Leading_zero       ; if not, go check r6 or r7
                     ; X will never be greater than 255
                     ; therefore XH will always be zero
; end of leading zero suppression checking

; setting up the pointer registers
Pointer_init:
ldi      XL,0x02             ; X points to r2 (left most digit)
clr      XH

ldi      YL,LCDDR0          ; Y points to LCDDRx registers
clr      YH

ldi      ZL,low(2*LCD_data)    ; Z points to LCD data lookup table
ldi      ZH,high(2*LCD_data)

Save_seeds:
sts      LCDDRx_ptr,YL       ; save Y pointer

sts      LCD_ptr,ZL          ; save Z pointer
sts      LCD_ptr+1,ZH

sbrc   XL,0             ; if pointer = even digit - clear that flag bit
rjmp   Set_Odd             ; otherwise go set that flag bit
cbr      Flags,EOD_msk       ; clear Odd/Even Flags bit to indicate Even dig.
rjmp   Load_LCDDRx1
Set_Odd:
sbr      Flags,EOD_msk       ; set Odd/Even Flags bit to indicate Odd digit
;
Load_LCDDRx1:
ldi      wtempL,0x02          ; setup counter
ld      temp1L,X+          ; load digit value (X=BCD digit pointer)
lsl      temp1L             ; multiply digit value by 2
add      ZL,temp1L          ; add offset to Z (Z=Lookup table pointer)
clr      temp1L
adc      ZH,temp1L

Load_LCDDRx2:
                     ; X points to low byte first time thru
lpm      temp1L,Z+          ; X points to high byte second time thru
mov      temp1H,temp1L       ; copy temp1L into temp1H
sbrc   Flags,EOD_bn       ; if Odd/Even bit = even (0) then go do Even
rjmp   Odd                ; otherwise do Odd

Even:
swap   temp1H             ; swap nibbles for temp1H for even digits
andi   temp1H,0x0F          ; clear high nibble
andi   temp1L,0x0F          ; clear high nibble
rjmp   Continue_load
Odd:
swap   temp1L             ; swap nibbles for temp1L for odd digits
andi   temp1L,0xF0          ; clear low nibble
andi   temp1H,0xF0          ; clear low nibble

Continue_load:
ld      temp2L,Y          ; save whatever was in nibble that is not being
or      temp1L,temp2L       ; written this time
st      Y,temp1L          ; LCDDRx = low nibble of byte of LCD data code
adiw   YH:YL,0x05          ; go to next LCDDRx for this digit
ld      temp2L,Y          ; save whatever was in nibble that is not being
or      temp1H,temp2L       ; written this time
st      Y,temp1H          ; LCDDRx = hi nibble of byte of LCD data code
dec      wtempL             ; have we written all four registers ?
breq   Reload_seeds       ; if so go reload seeds and get next digit
adiw   YH:YL,0x05          ; if not, go to next LCDDRx for this digit
rjmp   Load_LCDDRx2

Reload_seeds:
cpi      XL,0x08             ; have we displayed all locations?
breq   LCD_Display_ret       ; if we have return to Main loop routine
; otherwise continue here
lds      YL,LCDDRx_ptr       ; reload Y pointer seed (Y=LCDDRx pointer)
sbrc   Flags,EOD_bn       ; if Odd/Even bit = Even (0) then don't inc YL
inc      YL                ; Odd/Even bit = Odd, point to next higher
                     ; LCDDRx
lds      ZL,LCD_ptr          ; reload Z pointer seed
lds      ZH,LCD_ptr+1

rjmp   Save_seeds          ; display next digit

LCD_Display_ret:
cbr      Flags,EOD_msk       ; clear Even/Odd Flags bit
pop      temp1H
pop      temp1L
pop      temp2H
pop      temp2L
pop      wtempH
pop      wtempL
pop      ZH
pop      ZL
pop      YH
pop      YL
pop      XH
pop      XL
ret
;
;
;
;                     LCD_Display SUBROUTINE - END
;
; -----------------------------------------------------------------------------



Code:

; *****************************************************************************
; *****************************************************************************
;
;
;                  LOOK-UP TABLES/FLASH CONSTANTS - START
;
LCD_data:

.dw       0x5559    ; (0x00) zero
.dw       0x0118    ; (0x01) one
.dw       0x1e11    ; (0x02) two
.dw       0x1b11    ; (0x03) three
.dw       0x0b50    ; (0x04) four
.dw       0x1b41    ; (0x05) five
.dw       0x1f41    ; (0x06) six
.dw       0x0111    ; (0x07) seven
.dw       0x1f51    ; (0x08) eight
.dw       0x1b51    ; (0x09) nine
.dw         0x0000    ; (0x0A) blank display, for leading zero suppression
.dw      0x0f51      ; (0x0B)'A'
.dw      0x3991      ; (0x0C)'B'
.dw       0x1441      ; (0x0D)'C'
.dw       0x3191      ; (0x0E)'D'
.dw       0x1e41      ; (0x0F)'E'
.dw       0x0e41      ; (0x10)'F'
.dw       0x1d41      ; (0x11)'G'
.dw       0x0f50      ; (0x12)'H'
.dw       0x2080      ; (0x13)'I'
.dw       0x1510      ; (0x14)'J'
.dw       0x8648      ; (0x15)'K'
.dw       0x1440      ; (0x16)'L'
.dw       0x0578      ; (0x17)'M'
.dw       0x8570      ; (0x18)'N'
.dw       0x1551      ; (0x19)'O'
.dw       0x0e51      ; (0x1A)'P'
.dw       0x9551      ; (0x1B)'Q'
.dw       0x8e51      ; (0x1C)'R'
.dw       0x9021      ; (0x1D)'S'
.dw       0x2081      ; (0x1E)'T'
.dw       0x1550      ; (0x1F)'U'
.dw       0x4448      ; (0x20)'V'
.dw       0xc550      ; (0x21)'W'
.dw       0xc028      ; (0x22)'X'
.dw       0x2028      ; (0x23)'Y'
.dw       0x5009      ; (0x24)'Z'
;



So, I am sorry that the above is sooooo long. I am too lazy to copy/paste, zip and attach as a separate file here. I am very sure there are things I could do better. One of the first things I would do if I had time would be to arrange the lookup table such that I could just use ASCII characters and numbers as the index into the table. I am sure I could shorten up the routine if I had time to really study it. My life and job aren't cooperating as far as time goes .

Regards,
Steve

chris- 08-02-2006
Hi!

Here is another Butterfly LCD-Routine. It works a bit different like the
routine above. This is my codesize optimized version, that means it runs a
little bit slower.


CODE

; ===============================================================
;
;  File........: lcd_driverCO.asm
;
;  Author(s)...: Christian Gaida  
;
;  Target(s)...: ATmega169 (Butterfly)
;
;  Compiler....: AVRASM
;
;  Description.: LCD-Routine for the AVR-Butterfly
;       codesize optimized
;
;  Revision....: 2.0
;
;  YYYYMMDD - VER. - COMMENT                         - SIGN.
;  
;  20050521 - 0.1  - created     - CG
;  20051105 - 0.2  -      - CG
;  20060729 - 1.0  - add some commentars   - CG
;  20060730 - 1.1  - codesize optimized version  - CG
; ===============================================================

; =========================================================
;  to optimize speed put all subroutines together to avoid
;  subroutine calls and returns
;  but i usually prefer one routine for one thing
; =========================================================

; =========================================================
;  Function name : lcdInit
;  Returns      : -
;  Parameters    : -
;  Purpose       : Initialize LCD_displayData buffer.
;    Set up the LCD (timing, contrast, etc.)
; =========================================================
lcdInit:

ldi r16, (1<<LCDCS) | (3<<LCDMUX0)| (7<<LCDPM0)
sts LCDCRB, r16

; Set LCD prescaler to give a framerate of 32,0 Hz
ldi r16, (0<<LCDPS0) | (7<<LCDCD0)
sts LCDFRR, r16

; Set segment drive time and output voltage
ldi r16, (1<<LCDDC1) | (1<<LCDCC3) | (1<<LCDCC2) | (1<<LCDCC1)
sts LCDCCR, r16

; Enable LCD, default waveform and interrupt enabled
ldi r16, (1<<LCDEN)  | (1<<LCDAB) | (1<<LCDIE)
sts LCDCRA, r16
ret


; =========================================================
;  Function name : lcd_out
;  Returns       : -
;  Parameters    : -
;  Purpose      : Call the subroutines getAddr and write_char      
; =========================================================
lcd_out:    ; to optimize speed:
rcall getAddr  ; don't use
rcall write_char  ; this subroutine
ret      


; =========================================================
;  Function name : getAddr
;  Returns       : Adress of the char (stored in the
;    Z-Register)
;  Parameters    : char (r21), r16
;  Purpose      : Set Pointer to the char        
; =========================================================
getAddr:

     ldi ZL, LOW(data*2) ;ZL -> r30
ldi ZH, HIGH(data*2)   ;ZH -> r31
    ;Adresse der Daten in Z-Register    
subi char, 0x30  ;('0'=0x30)
     ldi r16, 4    
mul r16, char

add ZL, r0   ;

brcc skip    ;Überlauf in ZL(r30)? (Carry-Flag in SREG gesetzt)
inc ZH   ;wenn ja erhoehe ZH(r31) um 1

skip:
ret


; =========================================================
;  Function name : write_char
;  Returns       : -
;  Parameters    : X, Z, r16, r17
;  Purpose      : write char on the display      
; =========================================================
write_char:    ;Erste Position im Display
ldi nibble, 0b11110000
rcall setDigit
loopy:
lpm r16, Z+   ;lade nibble aus Z-Register und auto-increment Z
ld r17, X   ;Inhalt von LCDDRx aus SRAM laden
and r17, nibble  ;und unteres (od. oberes) nibble auf 0 setze
sbrc digit, 0  ;Stelle 1,3 oder 5,
swap r16   ;dann vertausche die nibbles
or r16, r17   ;Beide nibble zusammenführen
st X, r16   ;store to sram LCDDRx -> Ausgabe

     adiw XL, 5   ; XL +5 -> LCDDR5, LCDDR10, etc.
cpi XH, 1   ; last segment?
brne loopy   ; no? then go on

ret

; =========================================================
;  Function name : setDigit
;  Returns       : XH, XL
;  Parameters    : digit(r22)
;  Purpose      : set digit (0-5) on the display
;         (0=first digit from left)      
; =========================================================
setDigit:
ldi XL, LOW(LCDDR0)
ldi XH, HIGH(LCDDR0)

cpi digit, 2
brlo digit0
cpi digit, 4
brlo digit2

adiw XL, 2
ldi r18, 4
cpse digit, r18
swap nibble
ret

digit2:
adiw XL, 1
ldi r18, 2
cpse digit, r18
swap nibble
ret

digit0:
ldi r18, 0
cpse digit, r18
swap nibble
ret


data:
.db 0x9, 0x5, 0x5, 0x5, 0x8, 0x1, 0x1, 0x0 ;Char '0', '1'
.db 0x1, 0x1, 0xE, 0x1,  0x1, 0x1, 0xB, 0x1 ; '2', '3'
.db 0x0, 0x5, 0xB, 0x0,  0x1, 0x4, 0xB, 0x1 ; '4', '5'
.db 0x1, 0x4, 0xF, 0x1,  0x1, 0x1, 0x1, 0x0 ;  '6', '7'
.db 0x1, 0x5, 0xF, 0x1,  0x1, 0x5, 0xB, 0x1 ; '8', '9'

.db 0x0, 0x0, 0x0, 0x0,  0x0, 0x0, 0x0, 0x0 ; dummy for        
.db 0x0, 0x0, 0x0, 0x0,  0x0, 0x0, 0x0, 0x0 ;    0x3a
.db 0x0, 0x0, 0x0, 0x0,  0x0, 0x0, 0x0, 0x0 ;     to
.db 0x0, 0x0, 0x0, 0x0      ;    0x4

.db 0x1, 0x5, 0xF, 0x0,  0x1, 0x9, 0x9, 0x3 ;Char 'A', 'B'
.db 0x1, 0x4, 0x4, 0x1,  0x1, 0x9, 0x1, 0x3 ; 'C', 'D'
.db 0x1, 0x4, 0xe, 0x1,  0x1, 0x4, 0xe, 0x0 ; 'E', 'F'
.db 0x1, 0x4, 0xd, 0x1,  0x0, 0x5, 0xf, 0x0 ; 'G', 'H'    
.db 0x0, 0x8, 0x0, 0x2,  0x0, 0x1, 0x5, 0x1 ; 'I', 'J'
.db 0x8, 0x4, 0x6, 0x8,  0x0, 0x4, 0x4, 0x1 ; 'K', 'L'
.db 0x8, 0x7, 0x5, 0x0,  0x0, 0x7, 0x5, 0x8 ; 'M', 'N'
.db 0x1, 0x5, 0x5, 0x1,  0x1, 0x5, 0xe, 0x0 ; 'O', 'P'
.db 0x1, 0x5, 0x5, 0x9,  0x1, 0x5, 0xe, 0x8 ; 'Q', 'R'
.db 0x1, 0x2, 0x0, 0x9,  0x1, 0x8, 0x0, 0x2 ; 'S', 'T'
.db 0x0, 0x5, 0x5, 0x1,  0x8, 0x4, 0x4, 0x4 ; 'U', 'V'
.db 0x0, 0x5, 0x5, 0xc,  0x8, 0x2, 0x0, 0xc ; 'W', 'X'
.db 0x8, 0x2, 0x0, 0x2,  0x9, 0x0, 0x0, 0x5 ; 'Y', 'Z'


And here a snippet that uses the lcr-routine:

CODE

.include "m169def.inc"

.def char   = r21   ; the character to be displayed  
.def digit  = r22   ; digit 0-5 (from left to right)
.def nibble = r23    

.org 0x00

.cseg

reset:
ldi r16, LOW(RAMEND)
out spl, r16
ldi r16, HIGH(RAMEND)
out sph, r16

main:
rcall lcdInit

ldi char, 'H'
ldi digit, 0
rcall lcd_out

ldi char, 'E'
inc digit
rcall lcd_out

ldi char, 'L'
inc digit
rcall lcd_out

ldi char, 'L'
inc digit
rcall lcd_out

ldi char, 'O'
inc digit
rcall lcd_out

ldi char, 'U'
inc digit
rcall lcd_out

infinite_loop:
rjmp infinite_loop


.include "lcd_driverCO.asm"



I hope this could be usefull to someone.
It is terrible to read, that is because of the AVR-Studio formatting.
Oh, and sorry for my english... ;-)

Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.