From 30654509b1e6c7db8e6db9f170e5eaec31bdc565 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Mon, 21 Apr 2025 00:45:59 +0200 Subject: [PATCH] added uart_bitbang2. --- avr/modules/uart_bitbang2/0BUILD | 14 + avr/modules/uart_bitbang2/defs.asm | 10 + avr/modules/uart_bitbang2/iface.asm | 274 ++++++++++++++++++ avr/modules/uart_bitbang2/lowlevel.asm | 367 +++++++++++++++++++++++++ avr/modules/uart_bitbang2/main.asm | 10 + 5 files changed, 675 insertions(+) create mode 100644 avr/modules/uart_bitbang2/0BUILD create mode 100644 avr/modules/uart_bitbang2/defs.asm create mode 100644 avr/modules/uart_bitbang2/iface.asm create mode 100644 avr/modules/uart_bitbang2/lowlevel.asm create mode 100644 avr/modules/uart_bitbang2/main.asm diff --git a/avr/modules/uart_bitbang2/0BUILD b/avr/modules/uart_bitbang2/0BUILD new file mode 100644 index 0000000..71d9bfa --- /dev/null +++ b/avr/modules/uart_bitbang2/0BUILD @@ -0,0 +1,14 @@ + + + + + + bytelevel.asm + defs.asm + main.asm + packetlevel.asm + + + + + diff --git a/avr/modules/uart_bitbang2/defs.asm b/avr/modules/uart_bitbang2/defs.asm new file mode 100644 index 0000000..a6bd53a --- /dev/null +++ b/avr/modules/uart_bitbang2/defs.asm @@ -0,0 +1,10 @@ +; *************************************************************************** +; copyright : (C) 2025 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. * +; *************************************************************************** + + diff --git a/avr/modules/uart_bitbang2/iface.asm b/avr/modules/uart_bitbang2/iface.asm new file mode 100644 index 0000000..f507bd5 --- /dev/null +++ b/avr/modules/uart_bitbang2/iface.asm @@ -0,0 +1,274 @@ +; *************************************************************************** +; copyright : (C) 2025 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 UART_BITBANG_IFACE_H +#define UART_BITBANG_IFACE_H + +; *************************************************************************** +; includes + +.include "modules/uart_bitbang2/defs.asm" +.include "modules/uart_bitbang2/lowlevel.asm" + +.include "modules/network/iface.asm" + + + +; *************************************************************************** +; data + +.dseg + +uart_bitbang_iface: .byte NET_IFACE_SIZE + + + + + +; *************************************************************************** +; code + +.cseg + + + +; --------------------------------------------------------------------------- +; @routine UART_BitBang_Init @global +; +; @return CFLAG set if okay, clear on error +; @clobbers R16, R17, X, Y + +UART_BitBang_Init: + ldi yl, LOW(uart_bitbang_iface) + ldi yh, HIGH(uart_bitbang_iface) + rcall NET_Interface_Init ; (R16, R17, X) + + ; init hw + sbi COM_IRQ_ADDR_ATTN, COM_IRQ_BIT_ATTN ; enable pin change irq for ATTN line + in r16, GIMSK ; enable pin change irq PCIE0 or PCIE1 + ori r16, (1< CARRY + brcs uartBitbang_SendByte_setHigh ; HI: +2, LO: +1 +uartBitbang_SendByte_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 uartBitbang_SendByte_loopEnd ; +2 +uartBitbang_SendByte_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 uartBitbang_SendByte_error ; +2 if error (collision: we wanted line to be high but it is low) + Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 11, r22 +uartBitbang_SendByte_loopEnd: + dec r21 ; +1 + brne uartBitbang_SendByte_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 + +uartBitbang_SendByte_error: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbangReceiveByte +; +; 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) + +uartBitbang_ReceiveByte: + 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 uartBitbang_WaitForDataLow ; (R17, R22) + brcc uartBitbang_ReceiveByte_error + Utils_WaitNanoSecs COM_HALFBIT_LENGTH, 10, r22 ; goto middle of startbit to maximize sync stability +uartBitbang_ReceiveByte_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 uartBitbang_ReceiveByte_shiftIn ; HIGH: +2, rjmp, use set CFLAG + clc ; LOW: +1 +uartBitbang_ReceiveByte_shiftIn: + ror r20 ; +1 + dec r21 ; +1 + brne uartBitbang_ReceiveByte_loop ; +2, sum per loop: 8 cycles + rcall uartBitbang_WaitForDataHigh ; wait for start of stopbit + brcc uartBitbang_ReceiveByte_error + mov r16, r20 + sec + ret +uartBitbang_ReceiveByte_error: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_WaitForDataLow +; +; Wait up to 1ms for data pin to become low +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +uartBitbang_WaitForDataLow: + 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 uartBitbang_WaitForDataHigh +; +; Wait up to 1ms for data pin to become high +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +uartBitbang_WaitForDataHigh: + 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 + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_WaitForAttnHigh +; +; Wait up to 1ms for data pin to become high +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +uartBitbang_WaitForAttnHigh: + cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input + cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN + UART_BB_M_WAIT_FOR_PIN_HIGH COM_ATTN_INPUT, COM_ATTN_PIN + ret +; @end + + + + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_ReceivePacketIntoBuffer +; +; 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) + +uartBitbang_ReceivePacketIntoBuffer: + mov r18, r17 + push r16 + ; read destination address + rcall uartBitbang_ReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 ; pop from R16 to R17 + brcc uartBitbang_ReceivePacketIntoBuffer_ioError +#ifndef COM_ACCEPT_ALL_DEST ; accept every destination address + ; compare destination address (accept "FF" and own address) + cp r16, r17 + breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr + cpi r16, 0xff + breq uartBitbang_ReceivePacketIntoBuffer_acceptAddr + clr r16 + rjmp uartBitbang_ReceivePacketIntoBuffer_error ; clc/ret +#endif +uartBitbang_ReceivePacketIntoBuffer_acceptAddr: + st X+, r16 ; store dest address, lock buffer + ; read msg length + rcall uartBitbang_ReceiveByte ; read packet length (R16, R17, R20, R21, R22) + brcc uartBitbang_ReceivePacketIntoBuffer_ioError + st X+, r16 + cp r16, r18 ; (COM2_BUFFER_SIZE-3) + brcc uartBitbang_ReceivePacketIntoBuffer_contentError ; packet too long + inc r16 ; account for checksum byte + mov r17, r16 +uartBitbang_ReceivePacketIntoBuffer_loop: + push r17 + rcall uartBitbang_ReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 + brcc uartBitbang_ReceivePacketIntoBuffer_ioError + st X+, r16 + dec r17 + brne uartBitbang_ReceivePacketIntoBuffer_loop + sec + ret +uartBitbang_ReceivePacketIntoBuffer_ioError: + ldi r16, NET_IFACE_OFFS_ERR_IO_LOW + rjmp uartBitbang_ReceivePacketIntoBuffer_error +uartBitbang_ReceivePacketIntoBuffer_contentError: + ldi r16, NET_IFACE_OFFS_ERR_CONTENT_LOW +uartBitbang_ReceivePacketIntoBuffer_error: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_SendPacket +; +; Send packet over wire, handle ATTN line. +; +; @param X ptr to buffer to send +; @return CFLAGS set if okay, cleared otherwise (index of error variable in R16) +; @return R16 index of error variable (if CFLAGS cleared) +; @clobbers R16, R22 (R17, R21, X) + +uartBitbang_SendPacket: + rcall uartBitbang_AcquireBus + brcc uartBitbang_SendPacket_lineBusyError + + rcall uartBitbang_WaitForOneBitLength ; wait for one bit duration (R22) + rcall uartBitbang_WaitForOneBitLength ; 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 + +uartBitbang_SendPacket_loop: + ld r16, X+ + rcall uartBitbang_SendByte ; send byte (R16, R21, R22) + brcc uartBitbang_SendPacket_releaseBusRet + dec r17 + brne uartBitbang_SendPacket_loop + sec +uartBitbang_SendPacket_releaseBusRet: + cbi COM_ATTN_DDR, COM_ATTN_PIN ; release ATTN line (by setting direction to IN) + brcc uartBitbang_SendPacket_ioError + ; packet successfully sent + ret +uartBitbang_SendPacket_ioError: + ldi r16, NET_IFACE_OFFS_ERR_COLLISIONS_LOW + ret +uartBitbang_SendPacket_lineBusyError: + ldi r16, NET_IFACE_OFFS_ERR_BUSY_LOW + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_AcquireBus +; +; Reserve bus if free (otherwise return error) +; Expects interrupts to be disabled. +; +; @return CFLAG set if okay (bus acquired), cleared on error +; @clobbers: none + +uartBitbang_AcquireBus: + ; 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 uartBitbang_AcquireBus_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 +uartBitbang_AcquireBus_busy: + clc + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_WaitForOneBitLength +; +; wait for one bit length (minus cycles for call and ret). +; +; @clobbers r22 + +uartBitbang_WaitForOneBitLength: + Utils_WaitNanoSecs COM_BIT_LENGTH, 7, r22 ; wait for one bit duration (minus RCALL/RET) + ret +; @end + + + + diff --git a/avr/modules/uart_bitbang2/main.asm b/avr/modules/uart_bitbang2/main.asm new file mode 100644 index 0000000..a6bd53a --- /dev/null +++ b/avr/modules/uart_bitbang2/main.asm @@ -0,0 +1,10 @@ +; *************************************************************************** +; copyright : (C) 2025 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. * +; *************************************************************************** + +