; *************************************************************************** ; code .cseg ; --------------------------------------------------------------------------- ; comSendByte ; ; 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 comSendByte: 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 comSendByte_loop: ; 9 for low bit lsr r16 ; 1+ bit to send -> CARRY brcs comSendByte_setHigh ; HI: +2, LO: +1 comSendByte_setLow: sbi COM_DDR_DATA, COM_PINNUM_DATA ; +2 set DATA as output Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22 rjmp comSendByte_loopEnd ; +2 comSendByte_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 comSendByte_error ; +2 if error (collision: we wanted line to be high but it is low) Utils_WaitNanoSecs COM_BIT_LENGTH/2, 0, r22 comSendByte_loopEnd: dec r21 ; +1 brne comSendByte_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 sec ret comSendByte_error: clc ret ; --------------------------------------------------------------------------- ; comReceiveByte ; ; 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) comReceiveByte: 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 comWaitForDataLow ; (R17) brcc comReceiveByte_error Utils_WaitNanoSecs COM_BIT_LENGTH/2, 5, r22 ; goto middle of startbit to maximize sync stability comReceiveByte_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 comReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG clc ; LOW: +1 comReceiveByte_shiftIn: ror r20 ; +1 dec r21 ; +1 brne comReceiveByte_loop ; +2, sum per loop: 8 cycles rcall comWaitForDataHigh ; wait for start of stopbit brcc comReceiveByte_error mov r16, r20 sec ret comReceiveByte_error: clc ret ; --------------------------------------------------------------------------- ; comWaitForDataLow ; ; Waits up to COM_MAXWAIT loops for low data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22 comWaitForDataLow: ldi r17, COM_MAXWAIT comWaitForDataLow_loop: sbis COM_PIN_DATA, COM_PINNUM_DATA rjmp comWaitForDataLow_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForDataLow_loop clc ; timeout ret comWaitForDataLow_done: sec ; ok ret ; --------------------------------------------------------------------------- ; comWaitForDataHigh ; ; Waits up to COM_MAXWAIT loops for high data line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22, X comWaitForDataHigh: ldi r17, COM_MAXWAIT comWaitForDataHigh_loop: sbic COM_PIN_DATA, COM_PINNUM_DATA rjmp comWaitForDataHigh_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForDataHigh_loop clc ; timeout ret comWaitForDataHigh_done: sec ; ok ret ; --------------------------------------------------------------------------- ; comWaitForAttnHigh ; ; Waits up to COM_MAXWAIT loops for high ATTN line ; IN: ; OUT: ; - CFLAG: set if okay, clear otherwise ; MODIFIED REGISTERS: r17, r22, X comWaitForAttnHigh: ldi r17, COM_MAXWAIT comWaitForAttnHigh_loop: sbic COM_PIN_ATTN, COM_PINNUM_ATTN rjmp comWaitForAttnHigh_done Utils_WaitNanoSecs 100, 0, r22 ; wait for 100 nanosecs dec r17 brne comWaitForAttnHigh_loop clc ; timeout ret comWaitForAttnHigh_done: sec ; ok ret