;=======================================================
; Проект 14. LCD HD44780 в 4-битном режиме
; ATmega8, 8 МГц
; PD4..PD7 — шина данных D4..D7, PD2 — RS, PD3 — E
; Вывод RW дисплея — на GND
;=======================================================
.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

RESET:
        ldi     temp, low(RAMEND)
        out     SPL, temp
        ldi     temp, high(RAMEND)
        out     SPH, temp
        ldi     temp, 0xFC              ; PD2..PD7 — выходы
        out     DDRD, temp
        clr     temp
        out     PORTD, temp
        rcall   DELAY20MS               ; ждём готовности дисплея
        rcall   LCD_INIT

        ldi     chr, 'A'
        rcall   LCD_DATA
        ldi     chr, 'V'
        rcall   LCD_DATA
        ldi     chr, 'R'
        rcall   LCD_DATA
STOP:   rjmp    STOP

LCD_INIT:
        ldi     temp, 0x30              ; трижды 8-битная команда
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x30
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x30
        rcall   SEND_NIBBLE
        rcall   DELAY5MS
        ldi     temp, 0x20              ; переход в 4-битный режим
        rcall   SEND_NIBBLE
        rcall   DELAY5MS

        ldi     chr, 0x28               ; 4 бита, 2 строки, шрифт 5x8
        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

;--- выдать полубайт из старших бит temp ---
SEND_NIBBLE:
        push    r20
        in      r20, PORTD
        andi    r20, 0x0F               ; сохраняем RS и E
        or      temp, r20
        out     PORTD, temp
        sbi     PORTD, LCD_E            ; строб
        nop
        nop
        cbi     PORTD, LCD_E
        pop     r20
        ret

DELAY5MS:
        ldi     d2, 52
W2:     ldi     d1, 255
W1:     dec     d1
        brne    W1
        dec     d2
        brne    W2
        ret

DELAY20MS:
        rcall   DELAY5MS
        rcall   DELAY5MS
        rcall   DELAY5MS
        rcall   DELAY5MS
        ret
