589 lines
12 KiB
NASM
589 lines
12 KiB
NASM
; ***************************************************************************
|
|
; copyright : (C) 2025 by Martin Preuss
|
|
; email : martin@libchipcard.de
|
|
;
|
|
; ***************************************************************************
|
|
; * This file is part of the project "AqHome". *
|
|
; * Please see toplevel file COPYING of that project for license details. *
|
|
; ***************************************************************************
|
|
|
|
#ifndef AQH_AVR_XPT2046_MAIN_ASM
|
|
#define AQH_AVR_XPT2046_MAIN_ASM
|
|
|
|
|
|
; ***************************************************************************
|
|
; Module implementing DISPLAY_INPUT using displays with XPT2046 touch
|
|
; controllers.
|
|
;
|
|
; Implements:
|
|
; - Display_InputGetState
|
|
; Defines:
|
|
; - DISPLAY_IFLAGS_PRESSED_BIT
|
|
; - DISPLAY_IFLAGS_CHGCOORD_BIT
|
|
; - DISPLAY_IFLAGS_CHGPRESS_BIT
|
|
; Needs:
|
|
; - DISPLAY_WIDTH
|
|
; - DISPLAY_HEIGHT
|
|
; ***************************************************************************
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; defines
|
|
|
|
.equ DISPLAY_IFLAGS_PRESSED_BIT = 7
|
|
.equ DISPLAY_IFLAGS_CHGCOORD_BIT = 6
|
|
.equ DISPLAY_IFLAGS_CHGPRESS_BIT = 5
|
|
|
|
|
|
|
|
.equ XPT2046_SPIMODE = (0<<SPIHW_MODE_SPEED0_BIT) | \
|
|
(0<<SPIHW_MODE_SPEED1_BIT) | \
|
|
(1<<SPIHW_MODE_DOUBLESPEED_BIT) | \
|
|
(0<<SPIHW_MODE_DATAORDER_BIT) | \
|
|
(0<<SPIHW_MODE_CPOL_BIT) | \
|
|
(0<<SPIHW_MODE_CPHA_BIT)
|
|
|
|
|
|
.equ XPT2046_CMD_READ_X = 0xd1
|
|
.equ XPT2046_CMD_READ_Y = 0x91
|
|
.equ XPT2046_CMD_READ_Z1 = 0xb1
|
|
.equ XPT2046_CMD_READ_Z2 = 0xc1
|
|
|
|
.equ XPT2046_AVERAGE = 2
|
|
.equ XPT2046_Z_THRESHOLD = 50
|
|
.equ XPT2046_TIMER_VALUE = 3 ; every 300ms
|
|
|
|
.equ XPT2046_CALIB_XLEFT = 0x0c0
|
|
.equ XPT2046_CALIB_XRIGHT = 0x780
|
|
|
|
.equ XPT2046_CALIB_YTOP = 0x0c0
|
|
.equ XPT2046_CALIB_YBOTTOM = 0x7a0
|
|
|
|
|
|
; ***************************************************************************
|
|
; data
|
|
|
|
.dseg
|
|
|
|
xpt2046ValueBuffer: .byte (XPT2046_AVERAGE*2)
|
|
xpt2046RawX: .byte 2
|
|
xpt2046RawY: .byte 2
|
|
xpt2046CurrentX: .byte 2
|
|
xpt2046CurrentY: .byte 2
|
|
xpt2046CurrentZ: .byte 2
|
|
xpt2046Flags: .byte 1
|
|
xpt2046Timer: .byte 1
|
|
|
|
xpt2046LeftX: .byte 2
|
|
xpt2046FactorX: .byte 2
|
|
|
|
xpt2046TopY: .byte 2
|
|
xpt2046FactorY: .byte 2
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine XPT2046_Init @global
|
|
|
|
XPT2046_Init:
|
|
clr r16
|
|
sts xpt2046CurrentX, r16
|
|
sts xpt2046CurrentX+1, r16
|
|
|
|
sts xpt2046CurrentY, r16
|
|
sts xpt2046CurrentY+1, r16
|
|
|
|
sts xpt2046CurrentZ, r16
|
|
sts xpt2046CurrentZ+1, r16
|
|
|
|
sts xpt2046Flags, r16
|
|
|
|
sts xpt2046Timer, r16
|
|
|
|
rcall xpt2046CalcCalibration
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine XPT2046_Every100ms @global
|
|
|
|
XPT2046_Every100ms:
|
|
lds r16, xpt2046Timer
|
|
inc r16
|
|
cpi r16, XPT2046_TIMER_VALUE
|
|
brcs XPT2046_Every100ms_store
|
|
rcall xpt2046UpdateValues
|
|
clr r16
|
|
XPT2046_Every100ms_store:
|
|
sts xpt2046Timer, r16
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine Display_InputGetState @global
|
|
;
|
|
; Get current state, clears stored flags DISPLAY_IFLAGS_CHGCOORD_BIT
|
|
; and DISPLAY_IFLAGS_CHGPRESS_BIT.
|
|
;
|
|
; @return r16 flags
|
|
; @return r5:r4 X
|
|
; @return r7:r6 Y
|
|
; @clobber r17
|
|
|
|
Display_InputGetState:
|
|
lds r16, xpt2046Flags
|
|
mov r17, r16
|
|
cbr r17, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT) | (1<<DISPLAY_IFLAGS_CHGPRESS_BIT)
|
|
sts xpt2046Flags, r17
|
|
lds r4, xpt2046CurrentX
|
|
lds r5, xpt2046CurrentX+1
|
|
lds r6, xpt2046CurrentY
|
|
lds r7, xpt2046CurrentY+1
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046CalcCalibration
|
|
;
|
|
xpt2046CalcCalibration:
|
|
; calibrate X (hardcoded for now)
|
|
ldi r18, LOW(XPT2046_CALIB_XLEFT)
|
|
ldi r19, HIGH(XPT2046_CALIB_XLEFT)
|
|
ldi r20, LOW(XPT2046_CALIB_XRIGHT)
|
|
ldi r21, HIGH(XPT2046_CALIB_XRIGHT)
|
|
ldi r22, LOW(DISPLAY_HEIGHT)
|
|
ldi r23, HIGH(DISPLAY_HEIGHT)
|
|
rcall xpt2046CalcCalibX
|
|
|
|
; calibrate Y (hardcoded for now)
|
|
ldi r18, LOW(XPT2046_CALIB_YTOP)
|
|
ldi r19, HIGH(XPT2046_CALIB_YTOP)
|
|
ldi r20, LOW(XPT2046_CALIB_YBOTTOM)
|
|
ldi r21, HIGH(XPT2046_CALIB_YBOTTOM)
|
|
ldi r22, LOW(DISPLAY_WIDTH)
|
|
ldi r23, HIGH(DISPLAY_WIDTH)
|
|
rcall xpt2046CalcCalibY
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046CalcCalibX
|
|
;
|
|
; @param r19:r18: xLeft
|
|
; @param r21:r20 xRight
|
|
; @param r23:r22 display hardware width
|
|
|
|
xpt2046CalcCalibX:
|
|
sts xpt2046LeftX, r18
|
|
sts xpt2046LeftX+1, r19
|
|
|
|
mov r24, r20
|
|
mov r25, r21
|
|
sub r24, r18
|
|
sbc r25, r19
|
|
lsl r24 ; *2
|
|
rol r25
|
|
lsl r24 ; *4
|
|
rol r25
|
|
lsl r24 ; *8
|
|
rol r25
|
|
mov r20, r24
|
|
mov r21, r25
|
|
bigcall Utils_Divu16_16_16 ; R17:R16=result
|
|
sts xpt2046FactorX, r16
|
|
sts xpt2046FactorX+1, r17
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046CalcCalibY
|
|
;
|
|
; @param r19:r18: yTop
|
|
; @param r21:r20 yBottom
|
|
; @param r23:r22 display hardware height
|
|
|
|
xpt2046CalcCalibY:
|
|
sts xpt2046TopY, r18
|
|
sts xpt2046TopY+1, r19
|
|
|
|
mov r24, r20
|
|
mov r25, r21
|
|
sub r24, r18
|
|
sbc r25, r19
|
|
lsl r24 ; *2
|
|
rol r25
|
|
lsl r24 ; *4
|
|
rol r25
|
|
lsl r24 ; *8
|
|
rol r25
|
|
mov r20, r24
|
|
mov r21, r25
|
|
bigcall Utils_Divu16_16_16 ; R17:R16=result
|
|
sts xpt2046FactorY, r16
|
|
sts xpt2046FactorY+1, r17
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046UpdateValues
|
|
|
|
xpt2046UpdateValues:
|
|
push r15
|
|
in r15, SREG
|
|
cli
|
|
|
|
lds r23, xpt2046Flags
|
|
rcall xpt2046BeginSpi ; (R16, R17)
|
|
|
|
rcall xpt2046UpdateZ
|
|
|
|
mov r16, r23
|
|
andi r16, (1<<DISPLAY_IFLAGS_PRESSED_BIT) ; only read coords if pressed
|
|
breq xpt2046UpdateValues_storeFlags
|
|
|
|
rcall xpt2046UpdateRawX
|
|
rcall xpt2046UpdateRawY
|
|
|
|
rcall xpt2046CalcX
|
|
rcall xpt2046CalcY
|
|
|
|
xpt2046UpdateValues_storeFlags:
|
|
sts xpt2046Flags, r23
|
|
rcall xpt2046EndSpi ; (R16, R17)
|
|
|
|
out SREG, r15
|
|
pop r15
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046CalcX
|
|
;
|
|
; @param r23 current xpt2046Flag (modified by routine)
|
|
; @clobbers (r16, r17, r18, r19, r20, r21, r22)
|
|
|
|
xpt2046CalcX:
|
|
push r23
|
|
lds r20, xpt2046RawY
|
|
lds r21, xpt2046RawY+1
|
|
lds r16, xpt2046TopY
|
|
lds r17, xpt2046TopY+1
|
|
sub r20, r16
|
|
sbc r21, r17
|
|
brcc xpt2046CalcX_trans
|
|
clr r20
|
|
clr r21
|
|
xpt2046CalcX_trans:
|
|
lsl r20 ; *2
|
|
rol r21
|
|
lsl r20 ; *4
|
|
rol r21
|
|
lsl r20 ; *8
|
|
rol r21
|
|
lds r22, xpt2046FactorY
|
|
lds r23, xpt2046FactorY+1
|
|
bigcall Utils_Divu16_16_16
|
|
lds r18, xpt2046CurrentX
|
|
lds r19, xpt2046CurrentX+1
|
|
sts xpt2046CurrentX, r16
|
|
sts xpt2046CurrentX+1, r17
|
|
pop r23
|
|
sub r16, r18
|
|
sbc r17, r19
|
|
breq xpt2046CalcX_ret
|
|
ori r23, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT)
|
|
xpt2046CalcX_ret:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046CalcY
|
|
;
|
|
; @param r23 current xpt2046Flag (modified by routine)
|
|
; @clobbers (r16, r17, r18, r19, r20, r21, r22)
|
|
|
|
xpt2046CalcY:
|
|
push r23
|
|
lds r20, xpt2046RawX
|
|
lds r21, xpt2046RawX+1
|
|
lds r16, xpt2046LeftX
|
|
lds r17, xpt2046LeftX+1
|
|
sub r20, r16
|
|
sbc r21, r17
|
|
brcc xpt2046CalcY_trans
|
|
clr r20
|
|
clr r21
|
|
xpt2046CalcY_trans:
|
|
lsl r20 ; *2
|
|
rol r21
|
|
lsl r20 ; *4
|
|
rol r21
|
|
lsl r20 ; *8
|
|
rol r21
|
|
lds r22, xpt2046FactorX
|
|
lds r23, xpt2046FactorX+1
|
|
bigcall Utils_Divu16_16_16
|
|
lds r18, xpt2046CurrentY
|
|
lds r19, xpt2046CurrentY+1
|
|
sts xpt2046CurrentY, r16
|
|
sts xpt2046CurrentY+1, r17
|
|
pop r23
|
|
sub r16, r18
|
|
sbc r17, r19
|
|
breq xpt2046CalcY_ret
|
|
ori r23, (1<<DISPLAY_IFLAGS_CHGCOORD_BIT)
|
|
xpt2046CalcY_ret:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046UpdateRawX
|
|
;
|
|
; @clobbers (r16, r17, r18, r19, r20, r21)
|
|
|
|
xpt2046UpdateRawX:
|
|
; dummy read
|
|
ldi r16, XPT2046_CMD_READ_X
|
|
rcall xpt2046SendCommandRecv12Bit ; (R16)
|
|
|
|
ldi r16, XPT2046_CMD_READ_X
|
|
rcall xpt2046ReadAvgValues ; (r16, r18, r19, r20, r21)
|
|
rcall xpt2046AverageValues ; (r16, r17, r21)
|
|
|
|
sts xpt2046RawX, r18
|
|
sts xpt2046RawX+1, r19
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046UpdateRawY
|
|
;
|
|
; @param r23 current xpt2046Flag (modified by routine)
|
|
; @clobbers (r16, r18, r19, r20, r21)
|
|
|
|
xpt2046UpdateRawY:
|
|
; read Y
|
|
ldi r16, XPT2046_CMD_READ_Y
|
|
rcall xpt2046ReadAvgValues ; (r16, r18, r19, r20, r21)
|
|
rcall xpt2046AverageValues ; (r16, r17, r21)
|
|
sts xpt2046RawY, r18
|
|
sts xpt2046RawY+1, r19
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046UpdateZ
|
|
;
|
|
; @param r23 current xpt2046Flag (modified by routine)
|
|
; @clobbers (r16, r18, r19, r20, r21)
|
|
|
|
xpt2046UpdateZ:
|
|
ldi r16, XPT2046_CMD_READ_Z1
|
|
rcall xpt2046SendCommandRecv12Bit ; (R16)
|
|
sts xpt2046CurrentZ, r18
|
|
sts xpt2046CurrentZ+1, r19
|
|
|
|
ldi r16, LOW(XPT2046_Z_THRESHOLD)
|
|
ldi r17, HIGH(XPT2046_Z_THRESHOLD)
|
|
sub r18, r16
|
|
sbc r19, r17
|
|
mov r16, r23
|
|
brcc xpt2046UpdateZ_aboveThreshold
|
|
cbr r23, (1<<DISPLAY_IFLAGS_PRESSED_BIT) ; Z below threshold, not pressed
|
|
rjmp xpt2046UpdateZ_checkPressChg
|
|
xpt2046UpdateZ_aboveThreshold:
|
|
ori r23, (1<<DISPLAY_IFLAGS_PRESSED_BIT)
|
|
xpt2046UpdateZ_checkPressChg:
|
|
eor r16, r23
|
|
andi r16, (1<<DISPLAY_IFLAGS_PRESSED_BIT)
|
|
breq xpt2046UpdateZ_ret
|
|
ori r23, (1<<DISPLAY_IFLAGS_CHGPRESS_BIT)
|
|
xpt2046UpdateZ_ret:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046AverageValues
|
|
;
|
|
; @return r19:r18 averaged value
|
|
; @clobbers r16, r17, r21
|
|
|
|
xpt2046AverageValues:
|
|
ldi xl, LOW(xpt2046ValueBuffer)
|
|
ldi xh, HIGH(xpt2046ValueBuffer)
|
|
ldi r21, XPT2046_AVERAGE
|
|
clr r18
|
|
clr r19
|
|
xpt2046AverageValues_loop:
|
|
ld r16, X+
|
|
ld r17, X+
|
|
add r18, r16
|
|
adc r19, r17
|
|
dec r21
|
|
brne xpt2046AverageValues_loop
|
|
|
|
.if (XPT2046_AVERAGE == 2)
|
|
lsr r19
|
|
ror r18
|
|
.elif (XPT2046_AVERAGE == 4)
|
|
lsr r19
|
|
ror r18
|
|
lsr r19
|
|
ror r18
|
|
.else
|
|
.error "XPT2046_AVERAGE is not 4"
|
|
.endif
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046ReadAvgValues
|
|
;
|
|
; @param r16 command
|
|
; @clobbers r16, r18, r19, r20, r21
|
|
|
|
xpt2046ReadAvgValues:
|
|
ldi xl, LOW(xpt2046ValueBuffer)
|
|
ldi xh, HIGH(xpt2046ValueBuffer)
|
|
mov r20, r16
|
|
ldi r21, XPT2046_AVERAGE
|
|
xpt2046ReadAvgValues_loop:
|
|
mov r16, r20
|
|
rcall xpt2046SendCommandRecv12Bit ; (R16)
|
|
st X+, r18
|
|
st X+, r19
|
|
dec r21
|
|
brne xpt2046ReadAvgValues_loop
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046BeginSpi
|
|
;
|
|
; @clobbers r16, r17
|
|
|
|
xpt2046BeginSpi:
|
|
ldi r16, XPT2046_SPIMODE
|
|
ldi r17, XPT2046_DEVICENUM
|
|
rjmp SPIHW_MasterStart ; (R17)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046EndSpi
|
|
;
|
|
; @clobbers r16
|
|
|
|
xpt2046EndSpi:
|
|
rjmp SPIHW_MasterStop ; (R16)
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046SendCommandRecv12Bit
|
|
;
|
|
; @param r16 command
|
|
; @return r19:18 data
|
|
; @clobbers r16
|
|
|
|
xpt2046SendCommandRecv12Bit:
|
|
rcall xpt2046SendCommandRecv16Bit
|
|
lsr r19 ; >>1
|
|
ror r18
|
|
lsr r19 ; >>2
|
|
ror r18
|
|
lsr r19 ; >>3
|
|
ror r18
|
|
lsr r19 ; >>4
|
|
ror r18
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046SendCommandRecv16Bit
|
|
;
|
|
; @param r16 command
|
|
; @return r19:18 data
|
|
; @clobbers r16
|
|
|
|
xpt2046SendCommandRecv16Bit:
|
|
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
|
|
rcall SPIHW_MasterTransfer ; (R16)
|
|
|
|
clr r16
|
|
rcall SPIHW_MasterTransfer ; (R16)
|
|
mov r19, r16
|
|
clr r16
|
|
rcall SPIHW_MasterTransfer ; (R16)
|
|
mov r18, r16
|
|
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine xpt2046SendCommandRecv8Bit
|
|
;
|
|
; @param r16 command
|
|
; @return r16 data
|
|
; @clobbers r16
|
|
|
|
xpt2046SendCommandRecv8Bit:
|
|
cbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS low
|
|
rcall SPIHW_MasterTransfer ; (R16)
|
|
mov r18, r16
|
|
sbi SPIHW_SS_OUTPUT, SPIHW_SS_PIN ; SS high
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#endif ; AQH_AVR_XPT2046_MAIN_ASM
|
|
|