Files
aqhomecontrol/avr/modules/com2w/com2wi.asm
Martin Preuss 81669a5442 avr: first try irq driven com2w interface.
probably doesn't work like that but that's for later.
2025-09-01 23:24:15 +02:00

580 lines
14 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. *
; ***************************************************************************
; work in progress!
#ifndef AVR_MODULES_COM2W_COM2WI_H
#define AVR_MODULES_COM2W_COM2WI_H
.equ COM2WI_BUFFER_SIZE = NET_BUFFERS_SIZE-1
.equ COM2WI_R_MAX_WAIT_HI_TIME = 50 ; max 1ms
.equ COM2WI_S_MAX_WAIT_HI_TIME = 50 ; max 1ms
.equ COM2WI_S_MAX_WAIT_LO_TIME = 50 ; max 1ms
.equ COM2WI_STATE_IDLE = 0
.equ COM2WI_STATE_R_WAITFORCLOCKLO = 1
.equ COM2WI_STATE_R_WAITFORCLOCKHI = 2
.equ COM2WI_STATE_R_MSGRECVD = 3
.equ COM2WI_STATE_S_WAITFORCLOCKLO = 4
.equ COM2WI_STATE_S_WAITFORCLOCKHI = 5
.equ COM2WI_STATE_W_WAITFREELINE = 6
.equ COM2WI_STATE_W_SENDCLOCKLO = 7
.equ COM2WI_STATE_W_SENDCLOCKHI = 8
.equ COM2WI_STATE_W_WAITBETWEENBITS = 9
.equ COM2WI_STATE_W_WAITBETWEENBYTES = 10
.equ COM2WI_STATE_W_MSGSENT = 11
.equ COM2WI_STATE_COUNT = 12
.equ COM2WI_IFACE_OFFS_BEGIN = NET_IFACE_SIZE
.equ COM2WI_IFACE_OFFS_STATE = COM2WI_IFACE_OFFS_BEGIN+0
.equ COM2WI_IFACE_OFFS_STATETIMER = COM2WI_IFACE_OFFS_BEGIN+1
.equ COM2WI_IFACE_OFFS_STATECOUNTER = COM2WI_IFACE_OFFS_BEGIN+2
.equ COM2WI_IFACE_OFFS_PINMASK_CLK = COM2WI_IFACE_OFFS_BEGIN+3
.equ COM2WI_IFACE_OFFS_PINMASK_DATA = COM2WI_IFACE_OFFS_BEGIN+4
.equ COM2WI_IFACE_OFFS_BITCOUNTER = COM2WI_IFACE_OFFS_BEGIN+5
.equ COM2WI_IFACE_OFFS_CURRBYTE = COM2WI_IFACE_OFFS_BEGIN+6
.equ COM2WI_IFACE_OFFS_BUFPOS_LOW = COM2WI_IFACE_OFFS_BEGIN+7
.equ COM2WI_IFACE_OFFS_BUFPOS_HIGH = COM2WI_IFACE_OFFS_BEGIN+8
.equ COM2WI_IFACE_OFFS_BUFUSED = COM2WI_IFACE_OFFS_BEGIN+9
.equ COM2WI_IFACE_OFFS_BUFLEFT = COM2WI_IFACE_OFFS_BEGIN+10
.equ COM2WI_IFACE_OFFS_BUFFER = COM2WI_IFACE_OFFS_BEGIN+11
.equ COM2WI_IFACE_SIZE = COM2WI_IFACE_OFFS_BUFFER+COM2WI_BUFFER_SIZE
; ---------------------------------------------------------------------------
; @macro mCOM2WI_INIT
;
; @param @0 interface number (beginning with 0)
.macro mCOM2WI_INIT
ldi yl, LOW(com2wi@0_iface)
ldi yh, HIGH(com2wi@0_iface)
rcall com2wiInit
ldi r16, COM_MASK_CLK@0
std Y+COM2WI_IFACE_OFFS_PINMASK_CLK, r16
ldi r16, COM_MASK_DATA@0
std Y+COM2WI_IFACE_OFFS_PINMASK_DATA, r16
ldi r16, COM_MASK_IRQ@0
std Y+COM2WI_IFACE_OFFS_PINMASK_IRQ, r16
.endmacro
; @end
.dseg
com2wi0_iface: .byte COM2WI_IFACE_SIZE
.cseg
; ---------------------------------------------------------------------------
; @routine COM2WI_Init
COM2WI_Init:
mCOM2WI_INIT 0
rcall com2wiSetupTimer1
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiInit
com2wiInit:
rcall com2wiSetupLines
ldi r16, COM2WI_STATE_IDLE
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiSetupLines
com2wiSetupLines:
; setup CLK line (as input, disable internal pull-up resistor)
.ifdef COM_CLK_PUE
ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
com r16
inr r17, COM_CLK_PUE
and r17, r16
outr COM_CLK_PUE, r17
.endif
rcall com2wiClkSetHigh
; setup DATA line (as input, disable internal pull-up resistor)
.ifdef COM_DATA_PUE
ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
com r16
inr r17, COM_DATA_PUE
and r17, r16
outr COM_DATA_PUE, r17
.endif
rcall com2wiDataSetHigh
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiSetupTimer1
;
; setup timer for IRQ every 20us
com2wiSetupTimer1:
; CTC mode, no prescaler, OCR1A=100 (every 20us at 20MHz)
ldi r16, 0
outr TCCR1A, r16 ; WGM11=0, WGM10=0
ldi r16, (0<<CS12) | (0<<CS11) | (1<<CS10) | (0<<WGM13) | (1<<WGM12)
clr r17 HIGH(400)
ldi r16, LOW(400)
outr OCR1AH, r17
outr OCR1AL, r16
ldi r16, (1<<OCF1A) ; clear pending interrupts
outr TIFR1, r16
inr r16, TIMSK1
sbr r16, (1<<OCIE1A) ; Timer/Counter1 Output Compare Match A Interrupt Enable
outr TIMSK1, r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiClkSetHigh
;
; @clobbers none
com2wiClkSetHigh:
push r16
push r17
ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
; clear bit in io reg (AND with complement)
com r16
inr r17, COM_CLK_DDR
and r17, r16
outr COM_CLK_DDR, r17 ; make pin input
.ifndef COM_CLK_PUE
inr r17, COM_CLK_OUTPUT
and r17, r16 ; disable pullup
outr COM_CLK_OUTPUT, r17
.endif
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiDataSetHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wiDataSetHigh:
push r16
push r17
ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
; clear bit in io reg (AND with complement)
com r16
inr r17, COM_DATA_DDR
and r17, r16
outr COM_DATA_DDR, r17 ; make pin input
.ifndef COM_DATA_PUE
inr r17, COM_DATA_OUTPUT
and r17, r16 ; disable pullup
outr COM_DATA_OUTPUT, r17
.endif
pop r17
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wiDataSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wiDataSetLow:
push r16
push r17
ldd r16, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
; set bit in io reg
inr r17, COM_DATA_DDR
or r17, r16
outr COM_DATA_DDR, r17 ; make pin output
com r16
inr r17, COM_DATA_OUTPUT
and r17, r16
outr COM_DATA_OUTPUT, r17 ; set pin low
pop r17
pop r16
ret
; @end
com2wiHandleIrq:
ldi zl, LOW(com2wiIrqJumpTable)
ldi zh, HIGH(com2wiIrqJumpTable)
ldd r16, Y+COM2WI_IFACE_OFFS_STATE
cpi r16, COM2WI_STATE_COUNT
brcc com2wiHandleIrq_ret
add zl, r16
adc zh, r16
sub zh, r16
ijmp
com2wiHandleIrq_ret:
ret
com2wiIrqJumpTable:
rjmp com2wiHandleStateIdle ; 0: COM2WI_STATE_IDLE
rjmp com2wiHandleRWaitForClockLo ; 1: COM2WI_STATE_R_WAITFORCLOCKLO
rjmp com2wiHandleRWaitForClockHi ; 2: COM2WI_STATE_R_WAITFORCLOCKHI
rjmp com2wiHandleRMsgRecvd ; 3: COM2WI_STATE_R_MSGRECVD
rjmp com2wiHandleSWaitForClockLo ; 4: COM2WI_STATE_S_WAITFORCLOCKLO
rjmp com2wiHandleSWaitForClockHi ; 5: COM2WI_STATE_S_WAITFORCLOCKHI
rjmp com2wiHandleWWaitFreeLine ; 6: COM2WI_STATE_W_WAITFREELINE
rjmp com2wiHandleWSendClockLo ; 7: COM2WI_STATE_W_SENDCLOCKLO
rjmp com2wiHandleWSendClockHi ; 8: COM2WI_STATE_W_SENDCLOCKHI
rjmp com2wiHandleWWaitBetweenBits ; 9: COM2WI_STATE_W_WAITBETWEENBITS
rjmp com2wiHandleWWaitBetweenBytes ; 10: COM2WI_STATE_W_WAITBETWEENBYTES
rjmp com2wiHandleWMsgSent ; 11: COM2WI_STATE_W_MSGSENT
com2wiHandleStateIdle:
inr r16, COM_CLK_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
and r16, r17
brne com2wiHandleStateIdle_ret
; CLK became low, start reading
ldi r16, COM2WI_R_MAX_WAIT_HI_TIME
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
ldi r16, COM2WI_STATE_R_WAITFORCLOCKHI
std Y+COM2WI_IFACE_OFFS_STATE, r16
clr r16
std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
com2wiHandleStateIdle_ret:
ret
; @clobbers r16, r17
com2wiHandleRWaitForClockLo:
inr r16, COM_CLK_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
and r16, r17
breq com2wiHandleRWaitForClockLo_isLow
; CLK still high, check timer
ldd r16, Y+COM2WI_IFACE_OFFS_STATETIMER
dec r16
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
brne com2wiHandleRWaitForClockLo_ret
; timer ran out, enter idle mode
ldi r16, COM2WI_STATE_IDLE
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
com2wiHandleRWaitForClockLo_isLow:
; CLK became low, wait for CLK HI
ldi r16, COM2WI_R_MAX_WAIT_HI_TIME
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
ldi r16, COM2WI_STATE_R_WAITFORCLOCKHI
std Y+COM2WI_IFACE_OFFS_STATE, r16
com2wiHandleRWaitForClockLo_ret:
ret
; @clobbers r16, r17, r18
com2wiHandleRWaitForClockHi:
inr r16, COM_CLK_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
and r16, r17
brne com2wiHandleRWaitForClockHi_isHi
push xl
push xh
rcall com2wiHandleRWaitForClockHi_savedRegs
pop xh
pop xl
ret
com2wiHandleRWaitForClockHi_savedRegs: ; (r16, r17, r18, X)
; CLK still low, check timer
ldd r16, Y+COM2WI_IFACE_OFFS_STATETIMER
dec r16
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
brne com2wiHandleRWaitForClockHi_ret
; timer ran out, enter skipping mode
com2wiHandleRWaitForClockHi_enterSkipMode:
ldi r16, COM2WI_STATE_S_WAITFORCLOCKHI
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
com2wiHandleRWaitForClockHi_isHi:
inr r16, COM_DATA_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_DATA
and r16, r17
clc
breq com2wiHandleRWaitForClockHi_dataInCarry
sec
com2wiHandleRWaitForClockHi_dataInCarry:
ldd r16, Y+COM2WI_IFACE_OFFS_CURRBYTE
ror r16
std Y+COM2WI_IFACE_OFFS_CURRBYTE, r16
ldd r16, Y+COM2WI_IFACE_OFFS_BITCOUNTER
inc r16
std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
cpi r16, 8
brne com2wiHandleRWaitForClockHi_ret
; 8 bits received, store byte
ldd xl, Y+COM2WI_IFACE_OFFS_BUFPOS_LOW
ldd xh, Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH
ldd r17, Y+COM2WI_IFACE_OFFS_BUFLEFT
tst r17
breq com2wiHandleRWaitForClockHi_overrun
dec r17
std Y+COM2WI_IFACE_OFFS_BUFLEFT
st X+, r16
std Y+COM2WI_IFACE_OFFS_BUFPOS_LOW, xl
std Y+COM2WI_IFACE_OFFS_BUFPOS_HIGH, xh
ldd r18, Y+COM2WI_IFACE_OFFS_BUFUSED
inc r18
std Y+COM2WI_IFACE_OFFS_BUFUSED, r18
tst r17
breq com2wiHandleRWaitForClockHi_msgRecvd
cpi r18, 2
brne com2wiHandleRWaitForClockHi_prepareNextByte
; determine message size
inc r16 ; last byte was payload length, add byte for crc
cp r17, r16 ; compare remaining length against remaining space
brcs com2wiHandleRWaitForClockHi_badMsgSize
std Y+UARTFD_IFACE_OFFS_RBUFLEFT, r16
rjmp com2wiHandleRWaitForClockHi_prepareNextByte
com2wiHandleRWaitForClockHi_msgRecvd:
ldi r16, COM2WI_STATE_R_MSGRECVD
std Y+COM2WI_IFACE_OFFS_STATE, r16
#ifdef MODULES_LED_ACTIVITY
rcall LedActivity_Trigger ; (r16) [DEBUG]
#endif
ret
com2wiHandleRWaitForClockHi_overrun:
ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
rjmp com2wiHandleRWaitForClockHi_error
com2wiHandleRWaitForClockHi_badMsgSize:
ldi r16, NET_IFACE_OFFS_ERR_MSGSIZE_LOW
com2wiHandleRWaitForClockHi_error:
push r24
push r25
rcall NET_Interface_IncCounter16
pop r25
pop r24
rjmp com2wiHandleRWaitForClockHi_enterSkipMode
com2wiHandleRWaitForClockHi_prepareNextByte:
; prepare for next byte
clr r16
std Y+COM2WI_IFACE_OFFS_BITCOUNTER, r16
ldi r16, COM2WI_R_MAX_WAIT_LO_TIME
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
ldi r16, COM2WI_STATE_R_WAITFORCLOCKLO
std Y+COM2WI_IFACE_OFFS_STATE, r16
com2wiHandleRWaitForClockHi_ret:
ret
; @clobbers r16, r17, r18
com2wiHandleRMsgRecvd:
push r19
push r20
push xl
push xh
push zl
push zh
rcall com2wiHandleRMsgRecvd_savedRegs
pop zh
pop zl
pop xh
pop xl
pop r20
pop r19
ret
com2wiHandleRMsgRecvd_savedRegs: ; (r16, r17, r18, r19, r20, X, Z)
; check message
mov xl, yl
mov xh, yh
adiw xh:xl, UARTFD_IFACE_OFFS_RBUFFER
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
brcc com2wiHandleRMsgRecvd_errorCrc
; allocate buffer for storage
rcall NET_Buffer_Alloc ; R16=number, X=ptr (R16, R17, X)
brcc com2wiHandleRMsgRecvd_errorMem
ldd r18, Y+NET_IFACE_OFFS_IFACENUM
andi r18, 0x0f
ld r17, X
andi r17, 0xf0
or r17, r18
st X+, r17 ; store interface number
; copy to newly allocated buffer
mov zl, yl
mov zh, yh
adiw zh:zl, UARTFD_IFACE_OFFS_RBUFFER
ldd r17, Y+UARTFD_IFACE_OFFS_RBUFUSED
com2wiHandleRMsgRecvd_copyLoop:
ld r18, Z+
st X+, r18
dec r17
brne com2wiHandleRMsgRecvd_copyLoop
; add new buffer to incoming list
; DEBUG
; rcall NET_AddIncomingMsgNum
; brcs com2wiHandleRMsgRecvd_msgSaved
rcall NET_Buffer_ReleaseByNum ; (R16, X)
rjmp com2wiHandleRMsgRecvd_errorMem
com2wiHandleRMsgRecvd_msgSaved:
#ifdef MODULES_LED_ACTIVITY
rcall LedActivity_Trigger ; (r16)
#endif
ldi r16, NET_IFACE_OFFS_PACKETSIN_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
ldi r16, COM2WI_STATE_IDLE
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
com2wiHandleRMsgRecvd_errorCrc:
ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW
rjmp com2wiHandleRMsgRecvd_incCounter
com2wiHandleRMsgRecvd_errorMem:
ldi r16, NET_IFACE_OFFS_ERR_NOBUF_LOW
com2wiHandleRMsgRecvd_incCounter:
rcall NET_Interface_IncCounter16 ; (R24, R25)
ldi r16, COM2WI_S_MAX_WAIT_HI_TIME
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
ldi r16, COM2WI_STATE_S_WAITFORCLOCKHI
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
; @end
; @clobbers r16, r17
com2wiHandleSWaitForClockLo:
inr r16, COM_CLK_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
and r16, r17
breq com2wiHandleSWaitForClockLo_isLow
; is still high, check timer
ldd r16, Y+COM2WI_IFACE_OFFS_STATETIMER
dec r16
std Y+COM2WI_IFACE_OFFS_STATETIMER, r16
brne com2wiHandleSWaitForClockLo_ret
; timer ran out, enter idle mode
ldi r16, COM2WI_STATE_IDLE
std Y+COM2WI_IFACE_OFFS_STATE, r16
ret
com2wiHandleSWaitForClockLo_isLow:
; CLK became low, wait for HIGH again
ldi r16, COM2WI_STATE_S_WAITFORCLOCKHI
std Y+COM2WI_IFACE_OFFS_STATE, r16
com2wiHandleSWaitForClockLo_ret:
ret
com2wiHandleSWaitForClockHi:
inr r16, COM_CLK_INPUT
ldd r17, Y+COM2WI_IFACE_OFFS_PINMASK_CLK
and r16, r17
breq com2wiHandleSWaitForClockHi_ret
; enter COM2WI_STATE_S_WAITFORCLOCKLO
ldi r16, COM2WI_STATE_S_WAITFORCLOCKLO
std Y+COM2WI_IFACE_OFFS_STATE, r16
ldi r16, COM2WI_S_MAX_WAIT_LO_TIME
std Y+COM2WI_IFACE_OFFS_STATETIMER
com2wiHandleSWaitForClockHi_ret:
ret
com2wiHandleWWaitFreeLine:
ret
com2wiHandleWSendClockLo:
ret
com2wiHandleWSendClockHi:
ret
com2wiHandleWWaitBetweenBits:
ret
com2wiHandleWWaitBetweenBytes:
ret
com2wiHandleWMsgSent:
ret
#endif