; *************************************************************************** ; copyright : (C) 2023 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. * ; *************************************************************************** ; --------------------------------------------------------------------------- ; com2SendByte ; ; Send a byte. ; We only set the data pin to low at the beginning for the startbit. After that ; we only change the pin direction (e.g. input vs output): ; - for 0 bit: set DDR to output, forcing the data line low ; - for 1 bit: set DDR to input, letting the external pullup R pull the data line to HIGH ; since the output pin is still set to 0 the internal pullup is disabled ; IN: ; - R16: byte to send ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGS: R16, R21, R22 com2SendByte: ldi r21, 8 ; +1 bits left ; send startbit cbi COM_PORT_DATA, COM_PINNUM_DATA ; +2 set DATA low sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output Utils_WaitNanoSecs COM_BIT_LENGTH, 5, r22 ; wait for one bit duration ; send data bits com2SendByte_loop: ; 9 for low bit lsr r16 ; 1+ bit to send -> CARRY brcs com2SendByte_setHigh ; HI: +2, LO: +1 com2SendByte_setLow: sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22 rjmp com2SendByte_loopEnd ; +2 com2SendByte_setHigh: cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE nop ; +1 (to make pin change available) Utils_WaitNanoSecs COM_BIT_LENGTH/2, 11, r22 ; wait for half a bit length for line to safely settle sbis COM_PIN_DATA, COM_PINNUM_DATA ; +1 if no skip, +2 if skipped rjmp com2SendByte_error ; +2 if error (collision: we wanted line to be high but it is low) Utils_WaitNanoSecs COM_BIT_LENGTH/2, 0, r22 com2SendByte_loopEnd: dec r21 ; +1 brne com2SendByte_loop ; +2, sum per loop: 10 cycles ; send stopbit cbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as input, pullup R makes it ONE Utils_WaitNanoSecs COM_BIT_LENGTH, 4, r22 ; wait for one bit length rjmp com2LowLevelSecRet com2SendByte_error: rjmp com2LowLevelClcRet ; --------------------------------------------------------------------------- ; com2ReceiveByte ; ; Receive a byte. ; ; IN: ; - nothing ; OUT: ; - CFLAG: set if okay, clear otherwise ; - R16: byte read (if CFLAG set) ; MODIFIED REGS: R16, R20, R21, R22 (R17) com2ReceiveByte: cbi COM_DDR_DATA, COM_PINNUM_DATA ; set DATA port as input cbi COM_PORT_DATA, COM_PINNUM_DATA ; disable internal pullup for DATA ldi r21, 8 ; bits left clr r20 ; byte currently receiving ; wait for startbit rcall com2WaitForDataLow ; (R16, R17, R22) brcc com2ReceiveByte_error Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability com2ReceiveByte_loop: Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits sec ; +1 sbic COM_PIN_DATA, COM_PINNUM_DATA ; LOW: +2, HIGH: +1 rjmp com2ReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG clc ; LOW: +1 com2ReceiveByte_shiftIn: ror r20 ; +1 dec r21 ; +1 brne com2ReceiveByte_loop ; +2, sum per loop: 8 cycles rcall com2WaitForDataHigh ; wait for start of stopbit brcc com2ReceiveByte_error mov r16, r20 rjmp com2LowLevelSecRet com2ReceiveByte_error: rjmp com2LowLevelClcRet ; --------------------------------------------------------------------------- ; com2WaitForDataLow ; ; Waits up to 1ms for low data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r16 (r17, r22) com2WaitForDataLow: clr r16 rjmp com2WaitForDataState1ms ; --------------------------------------------------------------------------- ; com2WaitForDataHigh ; ; Waits up to 1ms for high data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r16 (r17, r22) com2WaitForDataHigh: ldi r16, 0xff rjmp com2WaitForDataState1ms ; --------------------------------------------------------------------------- ; com2WaitForAttnHigh ; ; Waits up to 1ms for high ATTN line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; REGS: r16 (r17, r22) com2WaitForAttnHigh: ldi r16, 0xff rjmp com2WaitForAttnState1ms ; --------------------------------------------------------------------------- ; com2WaitForDataState1ms ; ; Waits up to 1ms for high DATA line ; IN: ; - R16: state to wait for (00 for low, 0xff for high) ; OUT: ; - CFLAG: set if state reached, cleared otherwise ; REGS: R17, R22 com2WaitForDataState1ms: ldi r17, 100 com2WaitForDataState1ms_loop: in r22, COM_PIN_DATA eor r22, r16 andi r22, (1<