after sending a byte wait for the same time when sending the last bit as with the other bits (otherwise the last bit might get lost by slower devices).
526 lines
16 KiB
NASM
526 lines
16 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 AVR_MODULES_FLASH_IO_COM2W_H
|
|
#define AVR_MODULES_FLASH_IO_COM2W_H
|
|
|
|
|
|
|
|
.equ COM2W_WAITTIME1 = 25000
|
|
.equ COM2W_WAITTIME2 = 15000
|
|
|
|
|
|
|
|
|
|
; ***************************************************************************
|
|
; code
|
|
|
|
.cseg
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine ioRawInit
|
|
;
|
|
; Init raw message subsystem.
|
|
;
|
|
|
|
ioRawInit:
|
|
; setup CLK line (as input, disable internal pull-up resistor)
|
|
cbi COM_CLK_DDR, COM_CLK_PIN ; set CLK as input
|
|
.ifdef COM_CLK_PUE
|
|
inr r16, COM_CLK_PUE
|
|
cbr r16, (1<<COM_CLK_PIN) ; disable pullup on CLK
|
|
outr COM_CLK_PUE, r16
|
|
.else
|
|
cbi COM_CLK_OUTPUT, COM_CLK_PIN ; disable pullup on CLK
|
|
.endif
|
|
|
|
; setup DATA line (as input, disable internal pull-up resistor)
|
|
cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA as input
|
|
.ifdef COM_DATA_PUE
|
|
inr r16, COM_DATA_PUE
|
|
cbr r16, (1<<COM_DATA_PIN) ; disable pullup on DATA
|
|
outr COM_DATA_PUE, r16
|
|
.else
|
|
cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable pullup on DATA
|
|
.endif
|
|
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine ioRawSendMsg
|
|
;
|
|
; Send a message
|
|
;
|
|
|
|
ioRawSendMsg:
|
|
ioRawSendMsg_loop:
|
|
ldi xl, LOW(flashSendBuffer)
|
|
ldi xh, HIGH(flashSendBuffer)
|
|
ldi r19, FLASH_RECVBUFFER_MAXLEN
|
|
rcall com2wSendMsg
|
|
brcc ioRawSendMsg_loop
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine ioRawWaitForValidMsg
|
|
;
|
|
; Wait for valid incoming msg
|
|
;
|
|
; @return CFLAG set if okay (packet received), cleared on error
|
|
|
|
ioRawWaitForValidMsg:
|
|
; wait for CLK low
|
|
ldi r17, 20 ; wait for up to 10s
|
|
ioRawWaitForValidMsg_waitLowLoop:
|
|
.ifdef LED_PIN
|
|
sbi LED_PIN, LED_PINNUM ; toggle
|
|
.endif
|
|
ldi r18, 5 ; wait up to 500ms
|
|
rcall com2wWaitForClockLowMulti100ms ; (r18, r19, r20, r22)
|
|
brcs ioRawWaitForValidMsg_recvMsg
|
|
dec r17
|
|
brne ioRawWaitForValidMsg_waitLowLoop
|
|
clc ; no msg received
|
|
rjmp ioRawWaitForValidMsg_end
|
|
ioRawWaitForValidMsg_recvMsg:
|
|
; receive message
|
|
ldi xl, LOW(flashRecvBuffer)
|
|
ldi xh, HIGH(flashRecvBuffer)
|
|
ldi r18, NET_MAINTENANCE_ADDR
|
|
ldi r19, FLASH_RECVBUFFER_MAXLEN
|
|
rcall com2wRecvMsg
|
|
brcc ioRawWaitForValidMsg_end
|
|
; validate CRC
|
|
ldi xl, LOW(flashRecvBuffer)
|
|
ldi xh, HIGH(flashRecvBuffer)
|
|
rcall NETMSG_CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X)
|
|
ioRawWaitForValidMsg_end:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wWaitForClockLowMulti100ms
|
|
;
|
|
; wait for multiple of 100ms
|
|
;
|
|
; @param R18 number of 100ms to wait
|
|
; @return CFLAG set if okay (state reached), cleared on error
|
|
; @clobbers r18, r19, r20, r22
|
|
|
|
com2wWaitForClockLowMulti100ms:
|
|
com2wWaitForClockLowMulti100ms_loop1:
|
|
ldi r19, 100
|
|
com2wWaitForClockLowMulti100ms_loop2:
|
|
ldi r20, 100 ; wait for 1ms for clock low
|
|
rcall com2wWaitForClockLowMulti10Us ; (R20, R22)
|
|
brcs com2wWaitForClockLowMulti100ms_ret
|
|
dec r19
|
|
brne com2wWaitForClockLowMulti100ms_loop2
|
|
dec r18
|
|
brne com2wWaitForClockLowMulti100ms_loop1
|
|
clc
|
|
com2wWaitForClockLowMulti100ms_ret:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wSendMsg
|
|
;
|
|
; @param X pointer to bytes to send
|
|
; @return CFLAG set if message sent, cleared otherwise
|
|
; @clobbers R18, R20 (R16, R17, R20, R22, X)
|
|
|
|
com2wSendMsg:
|
|
ldi r20, 6 ; wait for about 60us for clock low
|
|
rcall com2wWaitForClockLowMulti10Us
|
|
brcs com2wSendMsg_busy ; CLK got low while waiting, so line is busy
|
|
rcall com2wClkSetLow ; reserve bus (none)
|
|
adiw xh:xl, NETMSG_OFFS_MSGLEN
|
|
ld r18, X
|
|
sbiw xh:xl, NETMSG_OFFS_MSGLEN
|
|
inc r18 ; adjust for DESTADDR
|
|
inc r18 ; adjust for MSGLEN
|
|
inc r18 ; adjust for CRCBYTE
|
|
rcall com2wWaitTime1 ; longer wait period (R22)
|
|
rcall com2wSendBytes ; (r16, r17, r18, r22, X)
|
|
rcall com2wClkSetHigh ; make sure bus is released
|
|
rcall com2wDataSetHigh
|
|
sec
|
|
ret
|
|
com2wSendMsg_busy:
|
|
clc
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wSendBytes
|
|
;
|
|
; @param R18 number of bytes to send
|
|
; @param X pointer to bytes to send
|
|
; @clobbers: r16, r18, X (r17, r22)
|
|
|
|
com2wSendBytes:
|
|
com2wSendBytes_loop:
|
|
rcall com2wClkSetLow ; (none)
|
|
rcall com2wWaitTime1 ; longer wait period (R22)
|
|
ld r16, X+
|
|
rcall com2wSendByte ; (R16, R17, R22)
|
|
dec r18
|
|
brne com2wSendBytes_loop
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wSendByte
|
|
;
|
|
; @param R16 byte to send
|
|
; @clobbers: r16, r17 (r22)
|
|
|
|
com2wSendByte:
|
|
ldi r17, 8
|
|
com2wSendByte_loop:
|
|
rcall com2wClkSetLow
|
|
rcall com2wWaitTime2 ; shorter wait period (R22)
|
|
lsr r16
|
|
brcs com2wSendByte_send1
|
|
rcall com2wDataSetLow
|
|
rjmp com2wSendByte_sent
|
|
com2wSendByte_send1:
|
|
rcall com2wDataSetHigh
|
|
com2wSendByte_sent:
|
|
Utils_WaitNanoSecs 5000, 0, r22 ; wait for very short time to ensure data is stable when clock rises
|
|
rcall com2wClkSetHigh
|
|
rcall com2wWaitTime2 ; shorter wait period (R22)
|
|
dec r17
|
|
brne com2wSendByte_loop
|
|
rcall com2wWaitTime2 ; shorter wait period (R22)
|
|
rcall com2wDataSetHigh
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wRecvMsg
|
|
;
|
|
; Receive a packet into buffer pointed to by X.
|
|
; Expects interrupts to be disabled.
|
|
;
|
|
; @param R18 COM address to listen to
|
|
; @param R19 max buffer size
|
|
; @param X buffer to receive to
|
|
; @return CFLAG set if msg received, cleared on error (see R16)
|
|
; @return R16 if CFLAG cleared: 0=message not for this node, otherwise error
|
|
; @clobbers r16, r17, r18, r19, r20, r22, r24, r25, X
|
|
|
|
com2wRecvMsg:
|
|
mov r21, r18 ; address
|
|
; read destination address
|
|
rcall com2wRecvByte ; (r17, r18, r20, r22)
|
|
brcc com2wRecvMsg_eIo
|
|
; store in buffer
|
|
subi r19, 1
|
|
brcs com2wRecvMsg_eBadSize
|
|
st X+, r16
|
|
|
|
; read remaining msg size
|
|
rcall com2wRecvByte ; (r17, r18, r20, r22)
|
|
brcc com2wRecvMsg_eIo
|
|
; store in buffer
|
|
subi r19, 1
|
|
brcs com2wRecvMsg_eBadSize
|
|
st X+, r16
|
|
|
|
inc r16 ; account for CRC byte
|
|
sub r19, r16
|
|
brcs com2wRecvMsg_eBadSize
|
|
mov r19, r16
|
|
com2wRecvMsg_loop:
|
|
rcall com2wRecvByte ; (r17, r18, r20, r22)
|
|
brcc com2wRecvMsg_eIo
|
|
st X+, r16
|
|
dec r19
|
|
brne com2wRecvMsg_loop
|
|
sec
|
|
rjmp com2wRecvMsg_end
|
|
com2wRecvMsg_eBadSize:
|
|
com2wRecvMsg_eIo:
|
|
com2wRecvMsg_clcRet:
|
|
clc
|
|
com2wRecvMsg_end:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wRecvByte
|
|
;
|
|
; @return CFLAG set if byte received, cleared on error
|
|
; @return r16 byte received
|
|
; @clobbers r17, r18, r20, r22
|
|
|
|
com2wRecvByte:
|
|
ldi r17, 8
|
|
clr r16
|
|
com2wRecvByte_loop:
|
|
ldi r20, 70 ; wait up to 700us for clock low
|
|
rcall com2wWaitForClockLowMulti10Us ; (R20, R22)
|
|
brcc com2wRecvByte_end
|
|
ldi r20, 70 ; wait up to 700us for clock high
|
|
rcall com2wWaitForClockHighMulti10Us ; (R20, R22)
|
|
brcc com2wRecvByte_end
|
|
; handle received bit
|
|
inr r18, COM_DATA_INPUT
|
|
andi r18, (1<<COM_DATA_PIN)
|
|
clc
|
|
breq com2wRecvByte_clockData
|
|
sec
|
|
com2wRecvByte_clockData:
|
|
ror r16
|
|
dec r17
|
|
brne com2wRecvByte_loop
|
|
sec
|
|
com2wRecvByte_end:
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wClkSetHigh
|
|
;
|
|
; @clobbers none
|
|
|
|
com2wClkSetHigh:
|
|
cbi COM_CLK_DDR, COM_CLK_PIN ; set CLK as input
|
|
.ifdef COM_CLK_PUE
|
|
; cbi COM_CLK_PUE, COM_CLK_PIN ; disable pullup on CLK
|
|
.else
|
|
cbi COM_CLK_OUTPUT, COM_CLK_PIN ; disable pullup on CLK
|
|
.endif
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wClkSetLow
|
|
;
|
|
; @clobbers none
|
|
|
|
com2wClkSetLow:
|
|
sbi COM_CLK_DDR, COM_CLK_PIN ; set CLK as output
|
|
cbi COM_CLK_OUTPUT, COM_CLK_PIN ; set CLK low
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wDataSetHigh
|
|
;
|
|
; @clobbers none
|
|
|
|
com2wDataSetHigh:
|
|
cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA as input
|
|
.ifdef COM_DATA_PUE
|
|
; cbi COM_DATA_PUE, COM_CLK_PIN ; disable pullup on DATA
|
|
.else
|
|
cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable pullup on DATA
|
|
.endif
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wDataSetLow
|
|
;
|
|
; @clobbers none
|
|
|
|
com2wDataSetLow:
|
|
sbi COM_DATA_DDR, COM_DATA_PIN ; set DATA as output
|
|
cbi COM_DATA_OUTPUT, COM_DATA_PIN ; set DATA low
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wWaitForClockLowMulti10Us
|
|
;
|
|
; Wait for low CLK
|
|
;
|
|
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us)
|
|
; @return CFLAG set if okay (state reached), cleared on error
|
|
; @clobbers: r20, r22
|
|
|
|
com2wWaitForClockLowMulti10Us:
|
|
.if clock > 1000000
|
|
; begin version for > 1000000 Hz
|
|
ldi r22, clock/1000000
|
|
com2wWaitForClockLowMulti10Us_loop0:
|
|
push r20
|
|
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
nop ; +1
|
|
dec r20 ; +1
|
|
brne com2wWaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
|
|
pop r20
|
|
dec r22 ; +1
|
|
brne com2wWaitForClockLowMulti10Us_loop0 ; +1 if FALSE, +2 if TRUE
|
|
clc ; +1
|
|
ret ; +4
|
|
com2wWaitForClockLowMulti10Us_stateReached:
|
|
pop r20
|
|
sec ; +1
|
|
ret ; +4
|
|
; end version for > 1000000 Hz
|
|
.elif clock < 1000000
|
|
.error "Clock speed too low"
|
|
.else
|
|
; begin version for 1000000 Hz
|
|
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockLowMulti10Us_stateReached ; (+2 if taken)
|
|
nop ; +1
|
|
dec r20 ; +1
|
|
brne com2wWaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
|
|
clc ; +1
|
|
ret ; +4
|
|
com2wWaitForClockLowMulti10Us_stateReached:
|
|
sec ; +1
|
|
ret ; +4
|
|
; end version for 1000000 Hz
|
|
.endif
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wWaitForClockHighMulti10Us
|
|
;
|
|
; Wait for high CLK
|
|
;
|
|
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us)
|
|
; @return CFLAG set if okay (state reached), cleared on error
|
|
; @clobbers: r20, r22
|
|
|
|
com2wWaitForClockHighMulti10Us:
|
|
.if clock > 1000000
|
|
; begin version for > 1000000 Hz
|
|
ldi r22, clock/1000000
|
|
com2wWaitForClockHighMulti10Us_loop0:
|
|
push r20
|
|
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
nop ; +1
|
|
dec r20 ; +1
|
|
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
|
|
pop r20
|
|
dec r22 ; +1
|
|
brne com2wWaitForClockHighMulti10Us_loop0 ; +1 if FALSE, +2 if TRUE
|
|
clc ; +1
|
|
ret ; +4
|
|
com2wWaitForClockHighMulti10Us_stateReached:
|
|
pop r20
|
|
sec ; +1
|
|
ret ; +4
|
|
; end version for > 1000000 Hz
|
|
.elif clock < 1000000
|
|
.error "Clock speed too low"
|
|
.else
|
|
; begin version for 1000000 Hz
|
|
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
|
|
rjmp com2wWaitForClockHighMulti10Us_stateReached ; (+2 if taken)
|
|
nop ; +1
|
|
dec r20 ; +1
|
|
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
|
|
clc ; +1
|
|
ret ; +4
|
|
com2wWaitForClockHighMulti10Us_stateReached:
|
|
sec ; +1
|
|
ret ; +4
|
|
; end version for 1000000 Hz
|
|
.endif
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wWaitTime1
|
|
;
|
|
; waits for longer period (e.g. 30ns)
|
|
;
|
|
; @clobbers R22
|
|
|
|
com2wWaitTime1:
|
|
Utils_WaitNanoSecs COM2W_WAITTIME1, 7, r22 ; wait for longer time (minus RCALL and RET)
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
; ---------------------------------------------------------------------------
|
|
; @routine com2wWaitTime2
|
|
;
|
|
; waits for shorter period (e.g. 10ns)
|
|
;
|
|
; @clobbers R22
|
|
|
|
com2wWaitTime2:
|
|
Utils_WaitNanoSecs COM2W_WAITTIME2, 7, r22 ; wait for shorter time (minus RCALL and RET)
|
|
ret
|
|
; @end
|
|
|
|
|
|
|
|
|
|
#endif ; AVR_MODULES_FLASH_IO_COM2W_H
|
|
|