avr: added com2w2 (slightly improved version of com2w).

- move IRQ control to main code (only the main code knows exactly which
  combination of pins is used for com2)
- split one big module into multiple smaller files (easier to maintain)
This commit is contained in:
Martin Preuss
2026-07-05 20:06:00 +02:00
parent b863e29612
commit db3f88f3af
11 changed files with 992 additions and 0 deletions

317
avr/modules/com2w2/io.asm Normal file
View File

@@ -0,0 +1,317 @@
; ***************************************************************************
; copyright : (C) 2026 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_COM2W2_IO_H
#define AVR_MODULES_COM2W2_IO_H
.cseg
; ---------------------------------------------------------------------------
; @routine com2w2EnableClkIrq
;
; @clobbers
com2w2EnableClkIrq:
.ifdef COM_ENABLEIRQ_FN
bigcall COM_ENABLEIRQ_FN
.else
push r16
inr r16, COM_IRQ_ADDR_CLK
sbr r16, (1<<COM_IRQ_BIT_CLK) ; enable pin change irq for CLK line
outr COM_IRQ_ADDR_CLK, r16
pop r16
.endif
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2DisableClkIrq
;
; @clobbers none
com2w2DisableClkIrq:
push r16
inr r16, COM_IRQ_ADDR_CLK
cbr r16, (1<<COM_IRQ_BIT_CLK) ; disable pin change irq for CLK line
outr COM_IRQ_ADDR_CLK, r16
pop r16
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2ClkSetHigh
;
; @clobbers none
com2w2ClkSetHigh:
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 com2w2ClkSetLow
;
; @clobbers none
com2w2ClkSetLow:
sbi COM_CLK_DDR, COM_CLK_PIN ; set CLK as output
cbi COM_CLK_OUTPUT, COM_CLK_PIN ; set CLK low
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2DataSetHigh
;
; @clobbers none
com2w2DataSetHigh:
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 com2w2DataSetLow
;
; @clobbers none
com2w2DataSetLow:
sbi COM_DATA_DDR, COM_DATA_PIN ; set DATA as output
cbi COM_DATA_OUTPUT, COM_DATA_PIN ; set DATA low
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2WaitForClockHighMulti10Us
;
; 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
com2w2WaitForClockHighMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r22, clock/1000000
com2w2WaitForClockHighMulti10Us_loop0:
push r20
com2w2WaitForClockHighMulti10Us_loop: ; 10 cycles per loop
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
nop ; +1
dec r20 ; +1
brne com2w2WaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20
dec r22 ; +1
brne com2w2WaitForClockHighMulti10Us_loop0 ; +1 if FALSE, +2 if TRUE
clc ; +1
ret ; +4
com2w2WaitForClockHighMulti10Us_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
com2w2WaitForClockHighMulti10Us_loop: ; 10 cycles per loop
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
sbic COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockHighMulti10Us_stateReached ; (+2 if taken)
nop ; +1
dec r20 ; +1
brne com2w2WaitForClockHighMulti10Us_loop ; +2 if TRUE, +1 if FALSE
clc ; +1
ret ; +4
com2w2WaitForClockHighMulti10Us_stateReached:
sec ; +1
ret ; +4
; end version for 1000000 Hz
.endif
; @end
; ---------------------------------------------------------------------------
; @routine com2w2WaitForClockLowMulti10Us
;
; 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
com2w2WaitForClockLowMulti10Us:
.if clock > 1000000
; begin version for > 1000000 Hz
ldi r22, clock/1000000
com2w2WaitForClockLowMulti10Us_loop0:
push r20
com2w2WaitForClockLowMulti10Us_loop: ; 10 cycles per loop
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
nop ; +1
dec r20 ; +1
brne com2w2WaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
pop r20
dec r22 ; +1
brne com2w2WaitForClockLowMulti10Us_loop0 ; +1 if FALSE, +2 if TRUE
clc ; +1
ret ; +4
com2w2WaitForClockLowMulti10Us_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
com2w2WaitForClockLowMulti10Us_loop: ; 10 cycles per loop
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
sbis COM_CLK_INPUT, COM_CLK_PIN ; +2 if skipped, +1 if taken
rjmp com2w2WaitForClockLowMulti10Us_stateReached ; (+2 if taken)
nop ; +1
dec r20 ; +1
brne com2w2WaitForClockLowMulti10Us_loop ; +2 if TRUE, +1 if FALSE
clc ; +1
ret ; +4
com2w2WaitForClockLowMulti10Us_stateReached:
sec ; +1
ret ; +4
; end version for 1000000 Hz
.endif
; @end
; ---------------------------------------------------------------------------
; @routine com2w2WaitTime1
;
; waits for longer period (e.g. 30ns)
;
; @clobbers R22
com2w2WaitTime1:
Utils_WaitNanoSecs COM2W2_WAITTIME1, 7, r22 ; wait for longer time (minus RCALL and RET)
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2WaitTime2
;
; waits for shorter period (e.g. 10ns)
;
; @clobbers R22
com2w2WaitTime2:
Utils_WaitNanoSecs COM2W2_WAITTIME2, 7, r22 ; wait for shorter time (minus RCALL and RET)
ret
; @end
; ---------------------------------------------------------------------------
; @routine com2w2PcintIsr @global @isr
;
; ISR for PCINT0/1
;
; @clobbers: none
com2w2PcintIsr:
push r15
in r15, SREG
sbic COM_CLK_INPUT, COM_CLK_PIN
rjmp com2w2PcintIsr_end
; low, read packet
push r16
push r17
push r18
push r19
push r20
push r21
push r22
push r24
push r25
push xl
push xh
push yl
push yh
ldi yl, LOW(com2w2_iface)
ldi yh, HIGH(com2w2_iface)
rcall com2w2ReceiveNextPkg ; (R16, R17, R18, R19, R20, R21, R22, R24, R25, X)
pop yh
pop yl
pop xh
pop xl
pop r25
pop r24
pop r22
pop r21
pop r20
pop r19
pop r18
pop r17
pop r16
com2w2PcintIsr_end:
out SREG, r15
pop r15
reti
; @end
#endif