From 85d0992ce912cebf79356816f95f075c038700c6 Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 20 Oct 2024 18:49:12 +0200 Subject: [PATCH] avr: added uart_bitbang module. Started reorganizing COM module by splitting into higher and lower level functions. --- avr/modules/uart_bitbang/0BUILD | 12 + avr/modules/uart_bitbang/bytelevel.asm | 186 +++++++++++ avr/modules/uart_bitbang/defs.asm | 13 + avr/modules/uart_bitbang/main.asm | 398 +++++++++++++++++++++++ avr/modules/uart_bitbang/packetlevel.asm | 159 +++++++++ 5 files changed, 768 insertions(+) create mode 100644 avr/modules/uart_bitbang/0BUILD create mode 100644 avr/modules/uart_bitbang/bytelevel.asm create mode 100644 avr/modules/uart_bitbang/defs.asm create mode 100644 avr/modules/uart_bitbang/main.asm create mode 100644 avr/modules/uart_bitbang/packetlevel.asm diff --git a/avr/modules/uart_bitbang/0BUILD b/avr/modules/uart_bitbang/0BUILD new file mode 100644 index 0000000..ac289d9 --- /dev/null +++ b/avr/modules/uart_bitbang/0BUILD @@ -0,0 +1,12 @@ + + + + + + main.asm + bytelevel.asm + + + + + diff --git a/avr/modules/uart_bitbang/bytelevel.asm b/avr/modules/uart_bitbang/bytelevel.asm new file mode 100644 index 0000000..caf5ffa --- /dev/null +++ b/avr/modules/uart_bitbang/bytelevel.asm @@ -0,0 +1,186 @@ +; *************************************************************************** +; copyright : (C) 2024 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. * +; *************************************************************************** + + + +; --------------------------------------------------------------------------- +; @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 +; @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 + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_SendByte +; +; 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 + +uartBitbang_SendByte: + ldi r21, 8 ; +1 bits left + ; send startbit + cbi COM_TXD_DATA, COM_TXD_PIN ; +2 set DATA low + sbi COM_TXD_DDR, COM_TXD_PIN ; +2 set DATA as output + Utils_WaitNanoSecs COM_BIT_LENGTH, 1, r22 ; wait for one bit duration + ; send data bits +uartBitbang_SendByte_loop: ; 9 for low bit + lsr r16 ; 1+ bit to send -> CARRY + brcs uartBitbang_SendByte_setHigh ; HI: +2, LO: +1 +uartBitbang_SendByte_setLow: + sbi COM_TXD_DDR, COM_TXD_PIN ; +2 set DATA as output + Utils_WaitNanoSecs COM_BIT_LENGTH, 9, r22 + rjmp uartBitbang_SendByte_loopEnd ; +2 +uartBitbang_SendByte_setHigh: + cbi COM_TXD_DDR, COM_TXD_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_RXD_DATA, COM_RXD_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_TXD_DDR, COM_TXD_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: + 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_RXD_DATA, COM_RXD_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 for data pin to become low +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +uartBitbang_WaitForDataLow: + UART_BB_M_WAIT_FOR_PIN_LOW COM_RXD_DATA, COM_RXD_PIN + ret +; @end + + + +; --------------------------------------------------------------------------- +; @routine uartBitbang_WaitForDataHigh +; +; Wait for data pin to become high +; @return CFLAG set if okay, clear otherwise +; @clobbers R17, R22 + +uartBitbang_WaitForDataHigh: + UART_BB_M_WAIT_FOR_PIN_LOW COM_RXD_DATA, COM_RXD_PIN + ret +; @end + + + + + diff --git a/avr/modules/uart_bitbang/defs.asm b/avr/modules/uart_bitbang/defs.asm new file mode 100644 index 0000000..9485944 --- /dev/null +++ b/avr/modules/uart_bitbang/defs.asm @@ -0,0 +1,13 @@ +; *************************************************************************** +; copyright : (C) 2024 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. * +; *************************************************************************** + + +.equ UART_BITBANG_BUFFER_NUM = 4 + + diff --git a/avr/modules/uart_bitbang/main.asm b/avr/modules/uart_bitbang/main.asm new file mode 100644 index 0000000..ca10971 --- /dev/null +++ b/avr/modules/uart_bitbang/main.asm @@ -0,0 +1,398 @@ +; *************************************************************************** +; copyright : (C) 2024 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. * +; *************************************************************************** + + + +; UART_BitBang_Init +; UART_BitBang_Fini +; UART_BitBang_Run +; UART_BitBang_SendPacket: +; UART_BitBang_GetNextReceivedPacket: +; UART_BitBang_ReleaseReceivedPacket: + + +.include "modules/com2/buffer.asm" + + + +.dseg + + +uartBitbangDataBegin: + uartBitbangRecvBuffersUsed: .byte 1 + uartBitbangMaxBuffersUsed: .byte 1 + uartBitbangRecvBuffersWritePos: .byte 1 + uartBitbangRecvBuffersReadPos: .byte 1 + uartBitbangRecvBuffers: .byte COM2_BUFFER_SIZE*UART_BITBANG_BUFFER_NUM +uartBitbangDataEnd: + + + + +.cseg + + + + +; --------------------------------------------------------------------------- +; @routine UART_BitBang_Init +; +; @return CFLAG set if okay, clear on error +; @clobbers R16, R17, X, Y + +UART_BitBang_Init: + ; preset SRAM data area + ldi xh, HIGH(uartBitbangDataBegin) + ldi xl, LOW(uartBitbangDataBegin) + clr r16 + ldi r17, (uartBitbangDataEnd-uartBitbangDataBegin) + rcall Utils_FillSram + + ; setup pins and interrupts + cbi COM_TXD_DATA, COM_TXD_PIN ; disable internal pullup for TXD + cbi COM_TXD_DDR, COM_TXD_PIN ; set TXD port as input + + cbi COM_RXD_DATA, COM_RXD_PIN ; disable internal pullup for RXD + cbi COM_RXD_DDR, COM_RXD_PIN ; set RXD port as input + + cbi COM_ATTN_OUTPUT, COM_ATTN_PIN ; disable internal pullup for ATTN + cbi COM_ATTN_DDR, COM_ATTN_PIN ; set ATTN port as input + + 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<