;=======================================================
; Проект 15. Вывод строк на LCD из памяти программ
; ATmega8, 8 МГц. PD4..PD7 — D4..D7, PD2 — RS, PD3 — E
;=======================================================
.include "m8def.inc"
.equ    LCD_RS = PD2
.equ    LCD_E  = PD3
.def    temp = r16
.def    chr  = r17
.def    d1   = r18
.def    d2   = r19

.cseg
.org    0x0000
        rjmp    RESET

STR1:   .db "AFON radio", 0, 0
STR2:   .db "ATmega8 asm", 0

RESET:
        ldi     temp, low(RAMEND)
        out     SPL, temp
        ldi     temp, high(RAMEND)
        out     SPH, temp
        ldi     temp, 0xFC
        out     DDRD, temp
        clr     temp
        out     PORTD, temp
        rcall   DELAY20MS
        rcall   LCD_INIT

        ldi     chr, 0x80               ; начало первой строки
        rcall   LCD_CMD
        ldi     ZL, low(STR1<<1)
        ldi     ZH, high(STR1<<1)
        rcall   PRINT

        ldi     chr, 0xC0               ; начало второй строки
        rcall   LCD_CMD
        ldi     ZL, low(STR2<<1)
        ldi     ZH, high(STR2<<1)
        rcall   PRINT
STOP:   rjmp    STOP

;--- печать строки из flash, адрес в Z, конец — нулевой байт ---
PRINT:
        lpm     chr, Z+
        tst     chr
        breq    PR_END
        rcall   LCD_DATA
        rjmp    PRINT
PR_END: ret

LCD_INIT:
        ldi     temp, 0x30
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x30
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x30
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x20
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     chr, 0x28
        rcall   LCD_CMD
        ldi     chr, 0x0C
        rcall   LCD_CMD
        ldi     chr, 0x06
        rcall   LCD_CMD
        ldi     chr, 0x01
        rcall   LCD_CMD
        rcall   DELAY5MS
        ret

LCD_CMD:
        cbi     PORTD, LCD_RS
        rjmp    SEND_BYTE
LCD_DATA:
        sbi     PORTD, LCD_RS
SEND_BYTE:
        mov     temp, chr
        andi    temp, 0xF0
        rcall   SEND_NIBBLE
        mov     temp, chr
        swap    temp
        andi    temp, 0xF0
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ret

SEND_NIBBLE:
        push    r20
        in      r20, PORTD
        andi    r20, 0x0F
        or      temp, r20
        out     PORTD, temp
        sbi     PORTD, LCD_E
        nop
        nop
        cbi     PORTD, LCD_E
        pop     r20
        ret

DELAY5MS:
        ldi     d2, 52
X2:     ldi     d1, 255
X1:     dec     d1
        brne    X1
        dec     d2
        brne    X2
        ret

DELAY20MS:
        rcall   DELAY5MS
        rcall   DELAY5MS
        rcall   DELAY5MS
        rcall   DELAY5MS
        ret
