Files
aqhomecontrol/avr/lcd.asm
2023-02-02 00:41:35 +01:00

691 lines
16 KiB
NASM

; ***************************************************************************
; LCD module
; (c) 2023 Martin Preuss
;
; Some code in this module is based on C-code in Tiny4kOLED (https://github.com/datacute/Tiny4kOLED/tree/master/src)
; by Stephen Denne (MIT license), rewritten in AVR assembler
;
; - page 0 is top line, page 7 ist bottom line
; - column 0 is the leftmost colum, column 127 is the rightmost column
; - a page has a height of 8 (->8 bits)
; - when writing a byte to a position (e.g. page 0, column 0)
; - writing to chip RAM is done in columns
;
; Page 0: col 0 col 1 ... col 127
; Row 0(LSB) 0/0 1/0 ... 127/0
; Row 1 0/1 1/1 ... 127/1
; Row 2 0/2 1/2 ... 127/2
; Row 3 0/3 1/3 ... 127/3
; ...
; Row 7(MSB) 0/7 1/7 ... 127/7
; and so one
; ***************************************************************************
; defines
.equ LCD_WIDTH = 128
.equ LCD_HEIGHT = 64
.equ LCD_PAGE_COUNT = 8
.equ LCD_CMD_MODE = 0x00
.equ LCD_DATA_MODE = 0x40
; ***************************************************************************
; data
.dseg
lcdDataBegin:
lcdDataEnd:
; ***************************************************************************
; code
.cseg
; ---------------------------------------------------------------------------
; LCD_Init
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
LCD_Init:
ldi zl, LOW(lcdInitCommandsBegin)
ldi zh, HIGH(lcdInitCommandsBegin)
ldi r16, 8
rcall lcdWriteCommandsFromFlash
ldi r16, 0
rcall LCD_Fill
ldi r16, 255
rcall LCD_Fill
ldi r16, 0
rcall LCD_Fill
ldi r18, 20
ldi r19, 0
rcall LCD_SetCursor
ldi zl, LOW(lcdHelloMsg)
ldi zh, HIGH(lcdHelloMsg)
rcall LCD_PrintFromFlash
; set cursor to next line here, sometimes this doesn't work correctly
; when called later. TODO: find out what goes wrong here...
ldi r18, 0
ldi r19, 2
rcall LCD_SetCursor
sec
ret
; ---------------------------------------------------------------------------
; LCD_Fini
;
; IN:
; - nothing
; OUT:
; - CFLAG: set if okay, clear on error
; USED:
LCD_Fini:
sec
ret
; ---------------------------------------------------------------------------
; LCD_SetCursor
;
; Set cursor. X is specified in pixels, Y is specified in character rows (8 pixels).
; Left upper corner is 0/0 (x/y), right lower corner is 127/7
;
; IN:
; - R18: X
; - R19: Y
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r1, r2, r15, r16 (R16, R17, R18, R22)
LCD_SetCursor:
in r15, SREG
cli
mov r1, r18
mov r2, r19
rcall twiStart ; (R22)
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
ldi r16, LCD_CMD_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r2
andi r16, 0x07
ori r16, 0xb0 ; Set Page Start Address for Page Addressing Mode
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r1
andi r16, 0x0f ; Set Lower Column Start Address
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
mov r16, r1
swap r16
andi r16, 0x0f
ori r16, 0x10 ; Set Higher Column Start Address
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_SetCursor_error
rcall twiStop ; (R22)
out SREG, r15
sec
ret
LCD_SetCursor_error:
rcall twiStop ; (R22)
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_Fill
;
; Fill display RAM with the given value.
;
; IN:
; - R16: data to write
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, r18, r19, r20, r21 (r17, r22)
LCD_Fill:
in r15, SREG
push r15
cli
mov r20, r16
ldi r21, 0 ; Y
LCD_Fill_loopY:
clr r18
mov r19, r21
rcall LCD_SetCursor
brcc LCD_Fill_error
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_Fill_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_Fill_error
ldi r19, 0
LCD_Fill_loopX:
mov r16, r20
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
rcall twiSendByte
brcc LCD_Fill_error
inc r19
cpi r19, LCD_WIDTH
brcs LCD_Fill_loopX
rcall twiStop
inc r21
cpi r21, LCD_PAGE_COUNT
brcs LCD_Fill_loopY
pop r15
out SREG, r15
sec
ret
LCD_Fill_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintFromFlash
;
; Print a string from flash at the current position.
;
; IN:
; - Z: position of string to print
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, Z (R17, R18, R22)
LCD_PrintFromFlash:
in r15, SREG
push r15
cli
lsl zl
rol zh
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintFromFlash_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintFromFlash_error
LCD_PrintFromFlash_loop:
lpm r16, z+
tst r16
breq LCD_PrintFromFlash_end
push zh
push zl
rcall lcdPrintOneChar
pop zl
pop zh
brcc LCD_PrintFromFlash_error
rjmp LCD_PrintFromFlash_loop
LCD_PrintFromFlash_end:
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintFromFlash_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintChar
;
; Print a character at the current position.
;
; IN:
; - R16: char
; OUT:
; REGS: r15, r16, r17, Z
LCD_PrintChar:
in r15, SREG
cli
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintChar_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintChar_error
rcall lcdPrintOneChar
brcc LCD_PrintChar_error
rcall twiStop
out SREG, r15
sec
ret
LCD_PrintChar_error:
rcall twiStop
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintHexByte
;
; Convert a given byte into HEX and write it to the current position.
;
; IN:
; - R16: byte to convert to hex
; OUT:
; REGS: r15, r16, r17, Z
LCD_PrintHexByte:
in r15, SREG
push r15
cli
mov r20, r16
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexByte_error
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexByte_error
mov r16, r20
rcall lcdPrintHexByte
brcc LCD_PrintHexByte_error
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintHexByte_error:
rcall twiStop
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; LCD_PrintHexWord
;
; Convert a give word into HEX and write it to the current position.
;
; IN:
; - r18: low byte of the word
; - r19: high byte of the word
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r15, r16, r17, Z
LCD_PrintHexWord:
in r15, SREG
push r15
cli
push r18
push r19
rcall twiStart
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexWord_errorPop
ldi r16, LCD_DATA_MODE
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc LCD_PrintHexWord_errorPop
pop r19
pop r18
rcall lcdPrintHexWord
brcc LCD_PrintHexWord_errorNoPop
rcall twiStop
pop r15
out SREG, r15
sec
ret
LCD_PrintHexWord_errorPop:
rcall twiStop
pop r19
pop r18
LCD_PrintHexWord_errorNoPop:
pop r15
out SREG, r15
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintHexWord
;
; Convert a give word into HEX and write it to the current position.
;
; IN:
; - r18: low byte of the word
; - r19: high byte of the word
; OUT:
; - CFLAG: set if okay, cleared otherwise
lcdPrintHexWord:
mov r16, r19
push r18
rcall lcdPrintHexByte
pop r18
brcc lcdPrintHexWord_error
mov r16, r18
rcall lcdPrintHexByte
brcc lcdPrintHexWord_error
sec
ret
lcdPrintHexWord_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintHexByte
;
; Convert a give byte into HEX and write it to the current position.
;
; IN:
; - R16: byte to convert to hex
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r16, r20 (r16, r17)
lcdPrintHexByte:
mov r20, r16
swap r16
rcall lcdNibbleToAscii ; write high nibble (r16, r17)
rcall lcdPrintOneChar ; (r16, r17, Z)
brcc lcdPrintHexByte_error
mov r16, r20
rcall lcdNibbleToAscii ; write low nibble
rcall lcdPrintOneChar
brcc lcdPrintHexByte_error
sec
ret
lcdPrintHexByte_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdNibbleToAscii
;
; Convert a nibble to an ASCII char.
; IN:
; - R16: byte (in bits 0-3)
; OUT:
; - R16: ASCII representation of that nibble (e.g. '0' for 0)
; REGS: r16, r17
lcdNibbleToAscii:
andi r16, 0xf
cpi r16, 10
brcs lcdNibbleToAscii_l1
ldi r17, 7
add r16, r17
lcdNibbleToAscii_l1:
ldi r17, '0'
add r16, r17
ret
; ---------------------------------------------------------------------------
; lcdWriteCommandsFromFlash
;
; IN:
; - R16: number of bytes to send
; - Z=pointer to data
; OUT:
; - CFLAG: set if okay, cleared otherwise
; REGS: r16, r20, Z (r17, r18, r22)
lcdWriteCommandsFromFlash:
rcall twiStart
lsl zl
rol zh
mov r20, r16 ; number of bytes
ldi r16, (LCD_TWI_ADDRESS*2)
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdWriteCommandsFromFlash_error
lcdWriteCommandsFromFlash_loop:
lpm r16, z+
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdWriteCommandsFromFlash_error
dec r20
brne lcdWriteCommandsFromFlash_loop
rcall twiStop ; (R22)
sec
ret
lcdWriteCommandsFromFlash_error:
rcall twiStop
clc
ret
; ---------------------------------------------------------------------------
; lcdPrintOneChar
;
; Print a character at the current position.
;
; IN:
; - R16: char
; OUT:
; REGS: r16, r19, Z (R17, R18, R22)
lcdPrintOneChar:
rcall lcdGetCharMatrix ; (r16, r17, Z)
ldi r16, 0 ; spacing between chars
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdPrintOneChar_error
ldi r19, 6
lcdPrintOneChar_loop:
lpm r16, z+
rcall twiSendByteExpectAck ; (R16, R17, R18, R22)
brcc lcdPrintOneChar_error
dec r19
brne lcdPrintOneChar_loop
sec
ret
lcdPrintOneChar_error:
clc
ret
; ---------------------------------------------------------------------------
; lcdGetCharMatrix
;
; Get pointer to matrix of given char.
;
; IN:
; - R16: char
; OUT:
; - Z: pos of character matrix (ready for LPM)
; REGS: r16, r17, Z
lcdGetCharMatrix:
cpi r16, 95+32
brcc lcdGetCharMatrix_l1
cpi r16, 32
brcc lcdGetCharMatrix_l2
lcdGetCharMatrix_l1:
ldi r16, 32
lcdGetCharMatrix_l2:
ldi r17, 32
sub r16, r17
mov zl, r16
clr zh
clr r17
lsl zl ; *2
rol zh
add zl, r16 ; *3
adc zh, r17
lsl zl ; *6
rol zh
ldi r16, LOW(lcdFont6x8*2)
ldi r17, HIGH(lcdFont6x8*2)
add zl, r16
adc zh, r17
ret
; TODO: set adressing mode??
lcdInitCommandsBegin: ; 28 bytes
.db LCD_CMD_MODE, 0xa8, ((LCD_PAGE_COUNT*8)-1), 0x8d, 0x14, 0xaf, 0xa1, 0xc8
lcdInitCommandsEnd:
lcdHelloMsg: .db "AqHOME 2023", 0
; font taken from Tiny4kOLED (https://github.com/datacute/Tiny4kOLED/tree/master/src) by Stephen Denne (MIT license),
; original by Neven Boyanov
lcdFont6x8:
.db 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 ; 0
.db 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00 ; ! 1
.db 0x00, 0x00, 0x07, 0x00, 0x07, 0x00 ; " 2
.db 0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14 ; # 3
.db 0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12 ; $ 4
.db 0x00, 0x62, 0x64, 0x08, 0x13, 0x23 ; % 5
.db 0x00, 0x36, 0x49, 0x55, 0x22, 0x50 ; & 6
.db 0x00, 0x00, 0x05, 0x03, 0x00, 0x00 ; ' 7
.db 0x00, 0x00, 0x1c, 0x22, 0x41, 0x00 ; ( 8
.db 0x00, 0x00, 0x41, 0x22, 0x1c, 0x00 ; ) 9
.db 0x00, 0x14, 0x08, 0x3E, 0x08, 0x14 ; * 10
.db 0x00, 0x08, 0x08, 0x3E, 0x08, 0x08 ; + 11
.db 0x00, 0x00, 0x00, 0xA0, 0x60, 0x00 ; , 12
.db 0x00, 0x08, 0x08, 0x08, 0x08, 0x08 ; - 13
.db 0x00, 0x00, 0x60, 0x60, 0x00, 0x00 ; . 14
.db 0x00, 0x20, 0x10, 0x08, 0x04, 0x02 ; / 15
.db 0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E ; 0 16
.db 0x00, 0x00, 0x42, 0x7F, 0x40, 0x00 ; 1 17
.db 0x00, 0x42, 0x61, 0x51, 0x49, 0x46 ; 2 18
.db 0x00, 0x21, 0x41, 0x45, 0x4B, 0x31 ; 3 19
.db 0x00, 0x18, 0x14, 0x12, 0x7F, 0x10 ; 4 20
.db 0x00, 0x27, 0x45, 0x45, 0x45, 0x39 ; 5 21
.db 0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30 ; 6 22
.db 0x00, 0x01, 0x71, 0x09, 0x05, 0x03 ; 7 23
.db 0x00, 0x36, 0x49, 0x49, 0x49, 0x36 ; 8 24
.db 0x00, 0x06, 0x49, 0x49, 0x29, 0x1E ; 9 25
.db 0x00, 0x00, 0x36, 0x36, 0x00, 0x00 ; : 26
.db 0x00, 0x00, 0x56, 0x36, 0x00, 0x00 ; ; 27
.db 0x00, 0x08, 0x14, 0x22, 0x41, 0x00 ; < 28
.db 0x00, 0x14, 0x14, 0x14, 0x14, 0x14 ; = 29
.db 0x00, 0x00, 0x41, 0x22, 0x14, 0x08 ; > 30
.db 0x00, 0x02, 0x01, 0x51, 0x09, 0x06 ; ? 31
.db 0x00, 0x32, 0x49, 0x59, 0x51, 0x3E ; @ 32
.db 0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C ; A 33
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x36 ; B 34
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x22 ; C 35
.db 0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C ; D 36
.db 0x00, 0x7F, 0x49, 0x49, 0x49, 0x41 ; E 37
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x01 ; F 38
.db 0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A ; G 39
.db 0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F ; H 40
.db 0x00, 0x00, 0x41, 0x7F, 0x41, 0x00 ; I 41
.db 0x00, 0x20, 0x40, 0x41, 0x3F, 0x01 ; J 42
.db 0x00, 0x7F, 0x08, 0x14, 0x22, 0x41 ; K 43
.db 0x00, 0x7F, 0x40, 0x40, 0x40, 0x40 ; L 44
.db 0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F ; M 45
.db 0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F ; N 46
.db 0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E ; O 47
.db 0x00, 0x7F, 0x09, 0x09, 0x09, 0x06 ; P 48
.db 0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E ; Q 49
.db 0x00, 0x7F, 0x09, 0x19, 0x29, 0x46 ; R 50
.db 0x00, 0x46, 0x49, 0x49, 0x49, 0x31 ; S 51
.db 0x00, 0x01, 0x01, 0x7F, 0x01, 0x01 ; T 52
.db 0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F ; U 53
.db 0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F ; V 54
.db 0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F ; W 55
.db 0x00, 0x63, 0x14, 0x08, 0x14, 0x63 ; X 56
.db 0x00, 0x07, 0x08, 0x70, 0x08, 0x07 ; Y 57
.db 0x00, 0x61, 0x51, 0x49, 0x45, 0x43 ; Z 58
.db 0x00, 0x00, 0x7F, 0x41, 0x41, 0x00 ; [ 59
.db 0x00, 0x02, 0x04, 0x08, 0x10, 0x20 ; \ 60
.db 0x00, 0x00, 0x41, 0x41, 0x7F, 0x00 ; ] 61
.db 0x00, 0x04, 0x02, 0x01, 0x02, 0x04 ; ^ 62
.db 0x00, 0x40, 0x40, 0x40, 0x40, 0x40 ; _ 63
.db 0x00, 0x00, 0x01, 0x02, 0x04, 0x00 ; ' 64
.db 0x00, 0x20, 0x54, 0x54, 0x54, 0x78 ; a 65
.db 0x00, 0x7F, 0x48, 0x44, 0x44, 0x38 ; b 66
.db 0x00, 0x38, 0x44, 0x44, 0x44, 0x20 ; c 67
.db 0x00, 0x38, 0x44, 0x44, 0x48, 0x7F ; d 68
.db 0x00, 0x38, 0x54, 0x54, 0x54, 0x18 ; e 69
.db 0x00, 0x08, 0x7E, 0x09, 0x01, 0x02 ; f 70
.db 0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C ; g 71
.db 0x00, 0x7F, 0x08, 0x04, 0x04, 0x78 ; h 72
.db 0x00, 0x00, 0x44, 0x7D, 0x40, 0x00 ; i 73
.db 0x00, 0x40, 0x80, 0x84, 0x7D, 0x00 ; j 74
.db 0x00, 0x7F, 0x10, 0x28, 0x44, 0x00 ; k 75
.db 0x00, 0x00, 0x41, 0x7F, 0x40, 0x00 ; l 76
.db 0x00, 0x7C, 0x04, 0x18, 0x04, 0x78 ; m 77
.db 0x00, 0x7C, 0x08, 0x04, 0x04, 0x78 ; n 78
.db 0x00, 0x38, 0x44, 0x44, 0x44, 0x38 ; o 79
.db 0x00, 0xFC, 0x24, 0x24, 0x24, 0x18 ; p 80
.db 0x00, 0x18, 0x24, 0x24, 0x18, 0xFC ; q 81
.db 0x00, 0x7C, 0x08, 0x04, 0x04, 0x08 ; r 82
.db 0x00, 0x48, 0x54, 0x54, 0x54, 0x20 ; s 83
.db 0x00, 0x04, 0x3F, 0x44, 0x40, 0x20 ; t 84
.db 0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C ; u 85
.db 0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C ; v 86
.db 0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C ; w 87
.db 0x00, 0x44, 0x28, 0x10, 0x28, 0x44 ; x 88
.db 0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C ; y 89
.db 0x00, 0x44, 0x64, 0x54, 0x4C, 0x44 ; z 90
.db 0x00, 0x08, 0x36, 0x41, 0x41, 0x00 ; { 91
.db 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00 ; | 92
.db 0x00, 0x00, 0x41, 0x41, 0x36, 0x08 ; } 93
.db 0x00, 0x08, 0x04, 0x08, 0x10, 0x08 ; ~ 94