com2w*: allow for higher frequencies than 8MHz

to be used with node S03, which is run at 20MHz.
This commit is contained in:
Martin Preuss
2025-08-18 18:04:30 +02:00
parent 9b1badb310
commit d9e7d4df81
7 changed files with 412 additions and 172 deletions

View File

@@ -100,7 +100,7 @@ com2wnInit:
rcall com2wSetMode ; (R17)
rcall com2wSetupLines
rcall com2wSetupIrq
rcall com2wnSetupIrq
ret
; @end

View File

@@ -34,7 +34,7 @@ com2wSetupLines:
.endif
; setup DATA line (as input, disable internal pull-up resistor)
rcall com2wDataSetHigh
rcall com2wnDataSetHigh
.ifdef COM_DATA_PUE
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA
com r16
@@ -75,12 +75,12 @@ com2wClkSetHigh:
; ---------------------------------------------------------------------------
; @routine com2wClkSetLow
; @routine com2wnClkSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wClkSetLow:
com2wnClkSetLow:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_CLK
@@ -102,12 +102,12 @@ com2wClkSetLow:
; ---------------------------------------------------------------------------
; @routine com2wDataSetHigh
; @routine com2wnDataSetHigh
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wDataSetHigh:
com2wnDataSetHigh:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA
@@ -129,12 +129,12 @@ com2wDataSetHigh:
; ---------------------------------------------------------------------------
; @routine com2wDataSetLow
; @routine com2wnDataSetLow
;
; @param Y pointer to interface data in SRAM
; @clobbers none
com2wDataSetLow:
com2wnDataSetLow:
push r16
push r17
ldd r16, Y+COM2W_IFACE_OFFS_PINMASK_DATA

View File

@@ -23,12 +23,16 @@ com2wnSetupIrq:
; setup pin-change interrupt for CLK
rcall com2wnEnableClkIrq
; enable and clear PCIE0/1 (@TODO put later into general setup)
inr r16, GIMSK ; enable pin change irq PCIE0 or PCIE1
sbr r16, (1<<COM_IRQ_GIMSK_CLK)
outr GIMSK, r16
ldi r16, (1<<COM_IRQ_GIFR_CLK) ; clear pending irq by writing 1 to GIFR bit
outr GIFR, r16
; enable PCIEn irq
inr r16, COM_IRQ_ADDR_M_CLK ; enable pin change irq PCIEn
sbr r16, (1<<COM_IRQ_BIT_M_CLK)
outr COM_IRQ_ADDR_M_CLK, r16
; clear PCIEn interrupt flag
inr r16, COM_IRQ_ADDR_F_CLK ; enable pin change irq PCIEn
sbr r16, (1<<COM_IRQ_BIT_F_CLK)
outr COM_IRQ_ADDR_F_CLK, r16
ret
; @end
@@ -74,14 +78,16 @@ com2wnDisableClkIrq:
; ---------------------------------------------------------------------------
; @routine COM2WN_ClkChangeOnePortIsr @global @isr
; @routine COM2WN_ClkChangeIsr @global @isr
;
; Interrupt service routine for single port (i.e. one port contains all
; CLOCK and DATA bits like in node R05).
; Interrupt service routine for dual or single port (i.e. one port contains all
; CLOCK and DATA bits like in node R05 and R06).
;
; @clobbers none
COM2WN_ClkChangeOnePortIsr:
COM2WN_ClkChangeIsr:
.if COM_DATA_INPUT == COM_CLK_INPUT
; routine for single port
push r15
in r15, SREG
push r16
@@ -95,11 +101,11 @@ COM2WN_ClkChangeOnePortIsr:
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
rcall RingBufferY_WriteByte ; (R17, R18, X)
brcs COM2WN_ClkChangeOnePortIsr_popRet
brcs COM2WN_ClkChangeIsr_popRet
lds r16, com2wnIoFlags
ori r16, (1<<COM2W_IO_FLAGS_BIT_OVR)
sts com2wnIoFlags, r16
COM2WN_ClkChangeOnePortIsr_popRet:
COM2WN_ClkChangeIsr_popRet:
pop yh
pop yl
pop xh
@@ -110,19 +116,8 @@ COM2WN_ClkChangeOnePortIsr_popRet:
out SREG, r15
pop r15
reti
; @end
; ---------------------------------------------------------------------------
; @routine COM2WN_ClkChangeTwoPortIsr @global @isr
;
; Interrupt service routine for single port (i.e. one port contains all
; CLOCK and DATA bits like in node R05).
;
; @clobbers none
COM2WN_ClkChangeTwoPortIsr:
.else
; routine for two port
push r15
in r15, SREG
push r16
@@ -139,14 +134,14 @@ COM2WN_ClkChangeTwoPortIsr:
push r17
rcall RingBufferY_WriteByte ; push clk state (R17, R18, X)
pop r16 ; pop DATA input into r16 (from r17)
brcc COM2WN_ClkChangeTwoPortIsr_ovr
brcc COM2WN_ClkChangeIsr_ovr
rcall RingBufferY_WriteByte ; push data state (R17, R18, X)
brcs COM2WN_ClkChangeTwoPortIsr_popRet
COM2WN_ClkChangeTwoPortIsr_ovr:
brcs COM2WN_ClkChangeIsr_popRet
COM2WN_ClkChangeIsr_ovr:
lds r16, com2wnIoFlags
ori r16, (1<<COM2W_IO_FLAGS_BIT_OVR)
sts com2wnIoFlags, r16
COM2WN_ClkChangeTwoPortIsr_popRet:
COM2WN_ClkChangeIsr_popRet:
pop yh
pop yl
pop xh
@@ -157,6 +152,8 @@ COM2WN_ClkChangeTwoPortIsr_popRet:
out SREG, r15
pop r15
reti
.endif
; @end

View File

@@ -18,15 +18,97 @@
; ---------------------------------------------------------------------------
; @routine COM2WN_Run
;
; @return CFLAG set if something done, cleared otherwise
; @clobbers all
COM2WN_Run:
clr r16
; first handle lowlevel (e.g. handle all CLK changes and DATA from ringbuffer)
COM2WN_Run_loop1:
push r16
rcall com2wnLowLevelRun
pop r16
brcc COM2WN_Run_handleRunModes
rcall com2wnSetR16OnCarrySet
rjmp COM2WN_Run_loop1
; then handle messages etc
COM2WN_Run_handleRunModes:
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
COM2WN_Run_loop2:
push r16
push r19
rcall com2wnRunMode ; (clobbers possibly all but Y)
pop r19
pop r16
rcall com2wnSetR16OnCarrySet
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne COM2WN_Run_loop2
tst r16
clc
breq COM2WN_Run_ret
sec
COM2WN_Run_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnSetR16OnCarrySet
;
com2wnSetR16OnCarrySet:
brcc com2wnSetR16OnCarrySet_ret
ldi r16, 1
com2wnSetR16OnCarrySet_ret:
ret
; @end
; ---------------------------------------------------------------------------
; @routine COM2WN_Periodically
;
COM2WN_Periodically:
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
COM2WN_Periodically_loop: ; loop through all interfaces
push r19
rcall com2wPeriodically ; (R16)
pop r19
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne COM2WN_Periodically_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wnLowLevelRun
;
com2wnLowLevelRunOnePort:
com2wnLowLevelRun:
.if COM_DATA_INPUT == COM_CLK_INPUT
; begin routine for single port
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
rcall RingBufferY_ReadByteGuarded ; (R17, R18, X)
brcc com2wnLowLevelRunOnePort_ret
brcc com2wnLowLevelRun_ret
lds r18, com2wnIoCurrentClockStates
eor r18, r16 ; r18: changed bits in clk states
@@ -35,11 +117,11 @@ com2wnLowLevelRunOnePort:
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
com2wnLowLevelRunOnePort_loop: ; loop through all interfaces
com2wnLowLevelRun_loop: ; loop through all interfaces
ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK
mov r21, r20
and r21, r18 ; CLK for interface changed?
breq com2wnLowLevelRunOnePort_nextIface
breq com2wnLowLevelRun_nextIface
push r16
push r18
push r19
@@ -48,29 +130,85 @@ com2wnLowLevelRunOnePort_loop: ; loop through all interfaces
pop r19
pop r18
pop r16
com2wnLowLevelRunOnePort_nextIface:
adiw yh:yl, COM2W_IFACE_SIZE
com2wnLowLevelRun_nextIface:
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne com2wnLowLevelRunOnePort_loop
brne com2wnLowLevelRun_loop
sec
com2wnLowLevelRunOnePort_ret:
com2wnLowLevelRun_ret:
ret
; end routine for single port
.else
; begin routine for double port
ldi yl, LOW(com2wnIoRingBuffer)
ldi yh, HIGH(com2wnIoRingBuffer)
push r15
in r15, SREG
cli
rcall RingBufferY_ReadByte ; (R17, R18, X)
brcc com2wnLowLevelRun_popr15Ret
push r16
rcall RingBufferY_ReadByte ; (R17, R18, X)
mov r17, r16
pop r16
out SREG, r15
pop r15
lds r18, com2wnIoCurrentClockStates
eor r18, r16 ; r18: changed bits in clk states
sts com2wnIoCurrentClockStates, r16 ; store new state
; r16=clock byte, r17=data byte, r18=clock change byte
ldi r19, COM_PORTS
ldi yl, LOW(com2w0_iface) ; first interface
ldi yh, HIGH(com2w0_iface)
com2wnLowLevelRun_loop: ; loop through all interfaces
ldd r20, Y+COM2W_IFACE_OFFS_PINMASK_CLK
mov r21, r20
and r21, r18 ; CLK for interface changed?
breq com2wnLowLevelRun_nextIface
push r16
push r18
push r19
rcall com2wnActOnClock ; (r16, r17, r18, X)
pop r19
pop r18
pop r16
com2wnLowLevelRun_nextIface:
ldi r20, COM2W_IFACE_SIZE
add yl, r20
adc yh, r20
sub yh, r20
dec r19
brne com2wnLowLevelRun_loop
sec
rjmp com2wnLowLevelRun_ret
com2wnLowLevelRun_popr15Ret:
out SREG, r15
pop r15
clc
com2wnLowLevelRun_ret:
ret
; end routine for double port
.endif
; @end
; ---------------------------------------------------------------------------
; @routine com2wPeriodically @global
;
; @clobbers R16, Y
; @param Y pointer to interface data
; @clobbers R16
com2wPeriodically:
push r15
in r15, SREG
cli
rcall NET_Interface_Periodically
rcall NET_Interface_Periodically ; (R16)
ldd r16, Y+COM2W_IFACE_OFFS_MODECOUNTER
inc r16
breq com2wPeriodically_end
@@ -193,7 +331,7 @@ com2wnRunIdle_haveMsg:
push r16
rcall NET_Buffer_Locate ; (R17)
adiw xh:xl, 1
rcall com2w0SendMsg ; (R16, R17, R22, R24, R25, X)
rcall com2wnSendMsg ; (R16, R17, R22, R24, R25, X)
push r15
in r15, SREG ; save SREG (no CLI, we want to save CFLAG only)
ldi r16, COM2W_MODE_IDLE

View File

@@ -20,22 +20,22 @@
; ---------------------------------------------------------------------------
; @routine com2wSendMsg
; @routine com2wnSendMsg
;
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @return CFLAG set if message sent, cleared otherwise
; @clobbers R16, R18 (R20, R22, R24, R25, X)
com2wSendMsg:
com2wnSendMsg:
ldi r20, 6 ; wait for about 60us for clock low
rcall com2wWaitForClockLowMulti10Us ; (R17, R20, R22)
brcs com2wSendMsg_busy ; CLK got low while waiting, so line is busy
brcs com2wnSendMsg_busy ; CLK got low while waiting, so line is busy
push r15
in r15, SREG
cli ; atomic disable irq and set CLK low
rcall com2wDisableClkIrq ; (none)
rcall com2wClkSetLow ; reserve bus (none)
rcall com2wnDisableClkIrq ; (none)
rcall com2wnClkSetLow ; reserve bus (none)
out SREG, r15
pop r15
adiw xh:xl, NETMSG_OFFS_MSGLEN
@@ -44,17 +44,17 @@ com2wSendMsg:
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 com2wnWaitTime1 ; longer wait period (R22)
rcall com2wnSendBytes ; (r16, r17, r18, r22, X)
rcall com2wClkSetHigh ; make sure bus is released
rcall com2wDataSetHigh
rcall com2wnDataSetHigh
rcall com2wEnableClkIrq ; (none)
rcall com2wnEnableClkIrq ; (none)
ldi r16, NET_IFACE_OFFS_PACKETSOUT_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
sec
ret
com2wSendMsg_busy:
com2wnSendMsg_busy:
ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW
rcall NET_Interface_IncCounter16 ; (R24, R25)
clc
@@ -64,68 +64,68 @@ com2wSendMsg_busy:
; ---------------------------------------------------------------------------
; @routine com2wSendBytes
; @routine com2wnSendBytes
;
; @param R18 number of bytes to send
; @param X pointer to bytes to send
; @param Y pointer to interface data in SRAM
; @clobbers: r16, r18, X (r17, r22)
com2wSendBytes:
com2wSendBytes_loop:
rcall com2wClkSetLow ; (none)
rcall com2wWaitTime1 ; longer wait period (R22)
com2wnSendBytes:
com2wnSendBytes_loop:
rcall com2wnClkSetLow ; (none)
rcall com2wnWaitTime1 ; longer wait period (R22)
ld r16, X+
rcall com2wSendByte ; (R16, R17, R22)
rcall com2wnSendByte ; (R16, R17, R22)
dec r18
brne com2wSendBytes_loop
brne com2wnSendBytes_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wSendByte
; @routine com2wnSendByte
;
; @param R16 byte to send
; @param Y pointer to interface data in SRAM
; @clobbers r16, r17 (r22)
com2wSendByte:
com2wnSendByte:
ldi r17, 8
com2wSendByte_loop:
rcall com2wClkSetLow
rcall com2wWaitTime1 ; longer wait period (R22)
com2wnSendByte_loop:
rcall com2wnClkSetLow
rcall com2wnWaitTime1 ; longer wait period (R22)
lsr r16
brcs com2wSendByte_send1
rcall com2wDataSetLow
rjmp com2wSendByte_sent
com2wSendByte_send1:
rcall com2wDataSetHigh
com2wSendByte_sent:
rcall com2wWaitTime2 ; shorter wait period (R22)
brcs com2wnSendByte_send1
rcall com2wnDataSetLow
rjmp com2wnSendByte_sent
com2wnSendByte_send1:
rcall com2wnDataSetHigh
com2wnSendByte_sent:
rcall com2wnWaitTime2 ; shorter wait period (R22)
push r15
in r15, SREG
cli ; ensure time period by disabling irqs
rcall com2wClkSetHigh
rcall com2wWaitTime1 ; longer wait period (R22)
rcall com2wnWaitTime1 ; longer wait period (R22)
out SREG, r15
pop r15
dec r17
brne com2wSendByte_loop
brne com2wnSendByte_loop
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2wWaitTime1
; @routine com2wnWaitTime1
;
; waits for longer period (e.g. 30ns)
;
; @clobbers R22
com2wWaitTime1:
com2wnWaitTime1:
Utils_WaitNanoSecs COM2W_WAITTIME1, 7, r22 ; wait for longer time (minus RCALL and RET)
ret
; @end
@@ -133,13 +133,13 @@ com2wWaitTime1:
; ---------------------------------------------------------------------------
; @routine com2wWaitTime2
; @routine com2wnWaitTime2
;
; waits for shorter period (e.g. 10ns)
;
; @clobbers R22
com2wWaitTime2:
com2wnWaitTime2:
Utils_WaitNanoSecs COM2W_WAITTIME2, 7, r22 ; wait for shorter time (minus RCALL and RET)
ret
; @end

View File

@@ -29,22 +29,44 @@
; @clobbers: r16, r20, r22
com2wWaitForClockHighMulti10Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r20, LOW(clock/1000000)
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockHighMulti10Us_loop0:
push r20 ; +2
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20 ; +2
dec r20 ; +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
.error "Unhandled clock speed"
.endif
; begin version for 1000000 Hz
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
brne com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
breq com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
@@ -53,12 +75,14 @@ com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
nop ; +1
dec r20 ; +1
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
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
@@ -68,22 +92,44 @@ com2wWaitForClockHighMulti10Us_stateReached:
;
; Wait for low CLK
;
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us, max: 32)
; @param R20 multiple of 10us to wait (e.g. "2" for "20" us)
; @return CFLAG set if okay (state reached), cleared on error
; @clobbers: r16, r20, r22
com2wWaitForClockLowMulti10Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r20, LOW(clock/1000000)
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockLowMulti10Us_loop0:
push r20 ; +2
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20 ; +2
dec r20 ; +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
.error "Unhandled clock speed"
.endif
; begin version for 1000000 Hz
ldd r22, Y+COM2W_IFACE_OFFS_PINMASK_CLK ; +2
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
@@ -103,6 +149,8 @@ com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
com2wWaitForClockLowMulti10Us_stateReached:
sec ; +1
ret ; +4
; end version for 1000000 Hz
.endif
; @end

View File

@@ -92,8 +92,8 @@ ioRawWaitForValidMsg_waitLowLoop1:
.endif
ldi r18, 5
ioRawWaitForValidMsg_waitLowLoop2:
ldi r20, 20 ; wait for about 100us for clock low
rcall com2wWaitForClockLowMulti5Us ; R20, R22
ldi r20, 10 ; wait for about 100us for clock low
rcall com2wWaitForClockLowMulti10Us ; R20, R22
brcs ioRawWaitForValidMsg_recvMsg
dec r18
brne ioRawWaitForValidMsg_waitLowLoop2
@@ -132,8 +132,8 @@ ioRawWaitForValidMsg_end:
; @clobbers R18, R20 (R16, R17, R20, R22, X)
com2wSendMsg:
ldi r20, 11 ; wait for about 55us for clock low
rcall com2wWaitForClockLowMulti5Us
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
@@ -267,21 +267,12 @@ com2wRecvByte:
ldi r17, 8
clr r16
com2wRecvByte_loop:
ldi r20, 31 ; wait up to 155us for clock low
rcall com2wWaitForClockLowMulti5Us ; (R20, R22)
brcs com2wRecvByte_waitForClkHigh
ldi r20, 31 ; wait up to 155us for clock low
rcall com2wWaitForClockLowMulti5Us ; (R20, R22)
ldi r20, 30 ; wait up to 300us for clock low
rcall com2wWaitForClockLowMulti10Us ; (R20, R22)
brcc com2wRecvByte_end
com2wRecvByte_waitForClkHigh:
ldi r20, 31 ; wait up to 155us for clock high
rcall com2wWaitForClockHighMulti5Us ; (R20, R22)
brcs com2wRecvByte_readBit
ldi r20, 31 ; wait up to 155us for clock high
rcall com2wWaitForClockHighMulti5Us ; (R20, R22)
ldi r20, 30 ; wait up to 300us for clock high
rcall com2wWaitForClockHighMulti10Us ; (R20, R22)
brcc com2wRecvByte_end
com2wRecvByte_readBit:
; handle received bit
inr r18, COM_DATA_INPUT
andi r18, (1<<COM_DATA_PIN)
@@ -360,71 +351,137 @@ com2wDataSetLow:
; ---------------------------------------------------------------------------
; @routine com2wWaitForClockHighMulti5Us
; @routine com2wWaitForClockLowMulti10Us
;
; Wait for high CLK
; Wait for low CLK
;
; @param R20 multiple of 5us to wait (e.g. "2" for "10" us, max: 64)
; @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
; @clobbers: r16, r20, r22
com2wWaitForClockHighMulti5Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
com2wWaitForClockLowMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r20, LOW(clock/1000000)
ldi r22, (1<<COM_CLK_PIN)
com2wWaitForClockLowMulti10Us_loop0:
push r20 ; +2
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20 ; +2
dec r20 ; +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
.error "Unhandled clock speed"
.endif
; begin version for 1000000 Hz
ldi r22, (1<<COM_CLK_PIN)
com2wWaitForClockLowMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
com2wWaitForClockHighMulti5Us_loop: ; 5 cycles per loop
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if not
rjmp com2wWaitForClockHighMulti5Us_stateReached ; +2
dec r20 ; +1
brne com2wWaitForClockHighMulti5Us_loop ; +2
clc ; +1
ret ; +4
com2wWaitForClockHighMulti5Us_stateReached:
sec ; +1
ret ; +4
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockLowMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
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 com2wWaitForClockLowMulti5Us
; @routine com2wWaitForClockHighMulti10Us
;
; Wait for low CLK
; Wait for high CLK
;
; @param R20 multiple of 5us to wait (e.g. "2" for "10" us, max: 64)
; @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
; @clobbers: r16, r20, r22
com2wWaitForClockLowMulti5Us:
.if clock == 8000000
add r20, r20 ; *2
add r20, r20 ; *4
add r20, r20 ; *8
.endif
.elif clock == 1000000
; nothing to do
com2wWaitForClockHighMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r20, LOW(clock/1000000)
ldi r22, (1<<COM_CLK_PIN)
com2wWaitForClockHighMulti10Us_loop0:
push r20 ; +2
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
brne com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
nop ; +1
dec r20 ; +1
brne com2wWaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20 ; +2
dec r20 ; +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
.error "Unhandled clock speed"
.endif
; begin version for 1000000 Hz
ldi r22, (1<<COM_CLK_PIN)
com2wWaitForClockHighMulti10Us_loop: ; 10 cycles per loop
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
breq com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
com2wWaitForClockLowMulti5Us_loop: ; 5 cycles per loop
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if not
rjmp com2wWaitForClockLowMulti5Us_stateReached ; +2
dec r20 ; +1
brne com2wWaitForClockLowMulti5Us_loop ; +2
clc ; +1
ret ; +4
com2wWaitForClockLowMulti5Us_stateReached:
sec ; +1
ret ; +4
inr r16, COM_CLK_INPUT ; +1 (if low port, +2 if high port)
and r16, r22 ; +1
brne com2wWaitForClockHighMulti10Us_stateReached ; +1 if FALSE, +2 if TRUE
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