diff --git a/avr/modules/flash/io.asm b/avr/modules/flash/io.asm index 5e48948..dae9c22 100644 --- a/avr/modules/flash/io.asm +++ b/avr/modules/flash/io.asm @@ -28,9 +28,11 @@ ioWaitForGivenMsg: ldi r20, 10 ; number of tries ioWaitForGivenMsg_loop: push r16 - rcall ioRawWaitForValidMsg ; (r16, r17, r18, r19, r22, X) - pop r17 ; pop into r17 (from r16) - brcc ioWaitForGivenMsg_end + push r20 + rcall ioRawWaitForValidMsg ; (r16, r17, r18, r19, r20, r21, r22, X) + pop r20 + pop r17 ; pop expected code to r17! + brcc ioWaitForGivenMsg_loopEnd ldi xl, LOW(flashRecvBuffer) ldi xh, HIGH(flashRecvBuffer) adiw xh:xl, COM2_MSG_OFFS_CMD @@ -40,7 +42,8 @@ ioWaitForGivenMsg_loop: breq ioWaitForGivenMsg_gotIt cpi r16, CPRO_CMD_FLASH_END breq ioWaitForGivenMsg_gotIt - mov r16, r17 ; put expected msg code back into r16 for next loop +ioWaitForGivenMsg_loopEnd: + mov r17, r16 ; move expected code back to r16 dec r20 brne ioWaitForGivenMsg_loop clc @@ -52,6 +55,3 @@ ioWaitForGivenMsg_end: ; @end - - - diff --git a/avr/modules/flash/io_attn.asm b/avr/modules/flash/io_attn.asm index 388f753..5454b19 100644 --- a/avr/modules/flash/io_attn.asm +++ b/avr/modules/flash/io_attn.asm @@ -23,6 +23,8 @@ ; @clobbers R17 (R22, R24) ioWaitForAttnState100ms: + cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input + cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN ioWaitForAttnState100ms_loop: push r17 ldi r17, 100 @@ -32,7 +34,6 @@ ioWaitForAttnState100ms_loop: dec r17 brne ioWaitForAttnState100ms_loop clc - ret ioWaitForAttnState100ms_stateReached: ret ; @end @@ -53,7 +54,6 @@ ioWaitForAttnStateMilliSeconds_loop: dec r17 brne ioWaitForAttnStateMilliSeconds_loop clc - ret ioWaitForAttnStateMilliSeconds_stateReached: ret ; @end @@ -70,8 +70,6 @@ ioWaitForAttnStateMilliSeconds_stateReached: ; @clobbers R24 (R22) ioWaitForAttnState1ms: - cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input - cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN ldi r24, 100 ioWaitForAttnState1ms_loop: push r17 diff --git a/avr/modules/flash/io_bitbang.asm b/avr/modules/flash/io_bitbang.asm index f5c64e8..d372382 100644 --- a/avr/modules/flash/io_bitbang.asm +++ b/avr/modules/flash/io_bitbang.asm @@ -8,6 +8,65 @@ ; *************************************************************************** +; *************************************************************************** +; macros + +; --------------------------------------------------------------------------- +; @macro UART_BB_M_WAIT_FOR_PIN_LOW IN_REG_DATA, IN_PINNUM +; 0 1 +; Wait for a pin to become low +; @param %0 DATA register for input pin (e.g. PINB) +; @param %1 pin number for input (e.g. PORTB1) +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +.macro UART_BB_M_WAIT_FOR_PIN_LOW + ldi r17, 200 +l_loop: + sbis @0, @1 + rjmp l_reached + Utils_WaitNanoSecs 5000, 0, r22 ; wait for 5us + dec r17 + brne l_loop + clc + rjmp l_end +l_reached: + sec +l_end: +.endmacro +; @end + + + +; --------------------------------------------------------------------------- +; @macro UART_BB_M_WAIT_FOR_PIN_HIGH IN_REG_DATA, IN_PINNUM +; 0 1 +; Wait for a pin to become high (up to 1ms) +; @param %0 DATA register for input pin (e.g. PINB) +; @param %1 pin number for input (e.g. PORTB1) +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +.macro UART_BB_M_WAIT_FOR_PIN_HIGH + ldi r17, 200 +l_loop: + sbic @0, @1 + rjmp l_reached + Utils_WaitNanoSecs 5000, 0, r22 ; wait for 5us + dec r17 + brne l_loop + clc + rjmp l_end +l_reached: + sec +l_end: +.endmacro +; @end + + + + + ; *************************************************************************** ; code @@ -49,7 +108,7 @@ ioRawSendMsg_loop: ioRawSendMsg_attnHigh: ldi xl, LOW(flashSendBuffer) ldi xh, HIGH(flashSendBuffer) - rcall uartBitbang_SendPacket ; R16, R22 (R17, R21, X) + rcall ioRawSendPacket ; R16, R22 (R17, R21, X) brcc ioRawSendMsg_loop ret ; @end @@ -61,7 +120,7 @@ ioRawSendMsg_attnHigh: ; Wait for valid incoming msg ; ; @return CFLAG set if okay (packet received), cleared on error -; @clobbers: +; @clobbers: r16, r17 (r18, r19, r20, r21, r22, X) ioRawWaitForValidMsg: ldi r16, 0 ; expect ATTN low @@ -74,14 +133,301 @@ ioRawWaitForValidMsg_attnLow: ldi xh, HIGH(flashRecvBuffer) ldi r16, COM2_MAINTENANCE_ADDR ldi r17, FLASH_RECVBUFFER_MAXLEN-3 - rcall uartBitbang_ReceivePacketIntoBuffer + rcall ioRawReceivePacketIntoBuffer brcs ioRawWaitForValidMsg_packetReceived ret ioRawWaitForValidMsg_packetReceived: ldi r16, 0xff ; expect ATTN high ldi r17, 100 - rjmp ioWaitForAttnState100ms ; wait for up to 10s + rcall ioWaitForAttnState100ms ; wait for up to 10s + brcc ioRawWaitForValidMsg_end + ldi xl, LOW(flashRecvBuffer) + ldi xh, HIGH(flashRecvBuffer) + rcall com2CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X) +ioRawWaitForValidMsg_end: + ret ; @end +; --------------------------------------------------------------------------- +; @routine ioRawReceivePacketIntoBuffer +; +; Receive a packet into buffer pointed to by X. +; Expects interrupts to be disabled. +; +; @param R16 COM address to listen to +; @param R17 maximum value for accepted msg data (i.e. buffersize minus 3) +; @param X buffer to receive to +; @return CFLAG set if okay (packet received), cleared on error +; @return R16 error code if CFLAG is cleared (COM2_ERROR_NOTFORME, COM2_ERROR_IOERROR, COM2_ERROR_DATAERROR) +; @clobbers: r16, r17, r18, X (r19, r20, r21, r22) + +ioRawReceivePacketIntoBuffer: + mov r18, r17 + push r16 + ; read destination address + rcall ioRawReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 ; pop from R16 to R17 + brcc ioRawReceivePacketIntoBuffer_ioError +#ifndef COM_ACCEPT_ALL_DEST ; accept every destination address + ; compare destination address (accept "FF" and own address) + cp r16, r17 + breq ioRawReceivePacketIntoBuffer_acceptAddr + cpi r16, 0xff + breq ioRawReceivePacketIntoBuffer_acceptAddr + ldi r16, COM2_ERROR_NOTFORME + rjmp ioRawReceivePacketIntoBuffer_error ; clc/ret +#endif +ioRawReceivePacketIntoBuffer_acceptAddr: + st X+, r16 ; store dest address, lock buffer + ; read msg length + rcall ioRawReceiveByte ; read packet length (R16, R17, R20, R21, R22) + brcc ioRawReceivePacketIntoBuffer_ioError + st X+, r16 + cp r16, r18 ; (COM2_BUFFER_SIZE-3) + brcc ioRawReceivePacketIntoBuffer_contentError ; packet too long + inc r16 ; account for checksum byte + mov r17, r16 +ioRawReceivePacketIntoBuffer_loop: + push r17 + rcall ioRawReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 + brcc ioRawReceivePacketIntoBuffer_ioError + st X+, r16 + dec r17 + brne ioRawReceivePacketIntoBuffer_loop + sec + ret +ioRawReceivePacketIntoBuffer_ioError: + ldi r16, COM2_ERROR_IOERROR + rjmp ioRawReceivePacketIntoBuffer_error +ioRawReceivePacketIntoBuffer_contentError: + ldi r16, COM2_ERROR_DATAERROR +ioRawReceivePacketIntoBuffer_error: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawReceiveByte +; +; Read a byte. +; Expects interrupts to be disabled. +; +; @return CFLAG set if okay, clear otherwise +; @return R16 byte received +; @clobbers R16, R20, R21, R22 (R17) + +ioRawReceiveByte: + cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for RXD + ldi r21, 8 ; bits left + clr r20 ; byte currently receiving + ; wait for startbit + rcall ioRawWaitForDataLow ; (R17, R22) + brcc ioRawReceiveByte_error + Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 10, r22 ; goto middle of startbit to maximize sync stability +ioRawReceiveByte_loop: + Utils_WaitNanoSecs COM_BIT_LENGTH, 8, r22 ; 8 cycles used in the complete loop between waits + sec ; +1 + sbic COM_DATA_INPUT, COM_DATA_PIN ; LOW: +2, HIGH: +1 + rjmp ioRawReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG + clc ; LOW: +1 +ioRawReceiveByte_shiftIn: + ror r20 ; +1 + dec r21 ; +1 + brne ioRawReceiveByte_loop ; +2, sum per loop: 8 cycles + rcall ioRawWaitForDataHigh ; wait for start of stopbit + brcc ioRawReceiveByte_error + mov r16, r20 + sec + ret +ioRawReceiveByte_error: + clc + ret +; @end + + + + + + + + +; --------------------------------------------------------------------------- +; @routine ioRawSendPacket +; +; Send packet over wire, handle ATTN line. +; +; @param X ptr to buffer to send +; @return CFLAGS set if okay, cleared otherwise (errorcode in R16) +; @clobbers R16, R22 (R17, R21, X) + +ioRawSendPacket: + rcall ioRawAcquireBus + brcc ioRawSendPacket_lineBusyError + + rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22) + rcall ioRawWaitForOneBitLength ; wait for one bit duration (R22) + + adiw xh:xl, COM2_MSG_OFFS_MSGLEN + ld r17, X + sbiw xh:xl, COM2_MSG_OFFS_MSGLEN + inc r17 ; account for dest addr + inc r17 ; account for msglen byte + inc r17 ; account for crc byte + +ioRawSendPacket_loop: + ld r16, X+ + rcall ioRawSendByte ; send byte (R16, R21, R22) + brcc ioRawSendPacket_releaseBusRet + dec r17 + brne ioRawSendPacket_loop + sec +ioRawSendPacket_releaseBusRet: + cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN) + brcc ioRawSendPacket_ioError + ; packet successfully sent + ret +ioRawSendPacket_ioError: + ldi r16,COM2_ERROR_COLLISION + ret +ioRawSendPacket_lineBusyError: + ldi r16,COM2_ERROR_BUSY + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawAcquireBus +; +; Reserve bus if free (otherwise return error) +; Expects interrupts to be disabled. +; +; @return CFLAG set if okay (bus acquired), cleared on error +; @clobbers: none + +ioRawAcquireBus: + ; check for ATTN line: busy? + cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as input + cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable pullup on ATTN + nop ; needed to sample current input + sbis COM_ATTN_INPUT, COM_ATTN_PIN ; ATTN low? + rjmp ioRawAcquireBus_busy ; jump if it is + sbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN as output + cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; set ATTN low + sec + ret +ioRawAcquireBus_busy: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawWaitForOneBitLength +; +; wait for one bit length (minus cycles for call and ret). +; +; @clobbers r22 + +ioRawWaitForOneBitLength: + Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22 ; wait for one bit duration (minus RCALL/RET) + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawSendByte +; +; 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 +; Expects interrupts to be disabled. +; +; @param R16 byte to send +; @return CFLAG set if okay, clear otherwise +; @clobbers R16, R21, R22 + +ioRawSendByte: + cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for DATA + ldi r21, 8 ; +1 bits left + ; send startbit + sbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as output + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; +2 set DATA low + Utils_WaitNanoSecs COM_BIT_LENGTH, 1, r22 ; wait for one bit duration + ; send data bits +ioRawSendByte_loop: ; 9 for low bit + lsr r16 ; 1+ bit to send -> CARRY + brcs ioRawSendByte_setHigh ; HI: +2, LO: +1 +ioRawSendByte_setLow: + sbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as output + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; +2 set DATA low + Utils_WaitNanoSecs COM_BIT_LENGTH, 11, r22 + rjmp ioRawSendByte_loopEnd ; +2 +ioRawSendByte_setHigh: + cbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as input, pullup R makes it ONE + nop ; +1 (to make pin change available) + Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 0, r22 ; wait for half a bit length for line to safely settle + sbis COM_DATA_INPUT, COM_DATA_PIN ; +1 if no skip, +2 if skipped + rjmp ioRawSendByte_error ; +2 if error (collision: we wanted line to be high but it is low) + Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 11, r22 +ioRawSendByte_loopEnd: + dec r21 ; +1 + brne ioRawSendByte_loop ; +2, sum per loop: 10 cycles + ; send stopbit + cbi COM_DATA_DDR, COM_DATA_PIN ; +2 set DATA as input, pullup R makes it ONE + Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit length + sec + ret + +ioRawSendByte_error: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawWaitForDataLow +; +; Wait up to 1ms for data pin to become low +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +ioRawWaitForDataLow: + cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for TXD + UART_BB_M_WAIT_FOR_PIN_LOW COM_DATA_INPUT, COM_DATA_PIN + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine ioRawWaitForDataHigh +; +; Wait up to 1ms for data pin to become high +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +ioRawWaitForDataHigh: + cbi COM_DATA_DDR, COM_DATA_PIN ; set DATA port as input + cbi COM_DATA_OUTPUT, COM_DATA_PIN ; disable internal pullup for TXD + UART_BB_M_WAIT_FOR_PIN_HIGH COM_DATA_INPUT, COM_DATA_PIN + ret +; @end + + + +