From 5f4260d60546f218a2b90190dae531064095ce0e Mon Sep 17 00:00:00 2001 From: Martin Preuss Date: Sun, 16 Apr 2023 23:23:06 +0200 Subject: [PATCH] avr: moved COM and COMPROTO defs and routines into dedicated files. --- avr/att84_base.asm | 217 +++----------- avr/att84_temp1.asm | 38 +-- avr/com2.asm | 663 +++--------------------------------------- avr/com2_buffer.asm | 170 +++++++++++ avr/com2_crc.asm | 60 ++++ avr/com2_defs.asm | 48 +++ avr/com2_lowlevel.asm | 203 +++++++++++++ avr/com2_packets.asm | 148 ++++++++++ avr/comproto.asm | 50 +--- avr/comproto_defs.asm | 71 +++++ avr/crc8.asm | 53 ++++ avr/flash.asm | 57 ++++ avr/flashproto.asm | 457 +++++++++++++++++++++++------ avr/utils.asm | 40 +-- avr/utils_wait.asm | 58 ++++ 15 files changed, 1332 insertions(+), 1001 deletions(-) create mode 100644 avr/com2_buffer.asm create mode 100644 avr/com2_crc.asm create mode 100644 avr/com2_defs.asm create mode 100644 avr/com2_lowlevel.asm create mode 100644 avr/com2_packets.asm create mode 100644 avr/comproto_defs.asm create mode 100644 avr/crc8.asm create mode 100644 avr/utils_wait.asm diff --git a/avr/att84_base.asm b/avr/att84_base.asm index 65a3950..3cc25bb 100644 --- a/avr/att84_base.asm +++ b/avr/att84_base.asm @@ -38,13 +38,17 @@ .equ clock=1000000 ; Define the clock frequency +.include "utils_wait.asm" +.include "com2_defs.asm" +.include "comproto_defs.asm" + + ; --------------------------------------------------------------------------- ; firmware settings including list of modules used -#define FW_TYPE AQHOME_FW_TYPE_ATT84_BASE -#define FW_MAIN_VERSION_HIGH 0 -#define FW_MAIN_VERSION_LOW 1 +#define FW_TYPE AQHOME_FW_TYPE_ATT84_BASE +#define FW_VERSION 0x0001 #define BASE_SYSTEM @@ -106,46 +110,23 @@ ; code segment .cseg -.org 000000 +.org 0x0000 ; --------------------------------------------------------------------------- ; Reset and interrupt vectors - rjmp PC+0x20 ; Reset vector - rjmp PC+0x20 ; EXT_INT0 - rjmp PC+0x20 ; PCI0 - rjmp PC+0x20 ; PCI1 - rjmp PC+0x20 ; WATCHDOG - rjmp PC+0x20 ; ICP1 - rjmp PC+0x20 ; OC1A - rjmp PC+0x20 ; OC1B - rjmp PC+0x20 ; OVF1 - rjmp PC+0x20 ; OC0A - rjmp PC+0x20 ; OC0B - rjmp PC+0x20 ; OVF0 - rjmp PC+0x20 ; ACI - rjmp PC+0x20 ; ADCC - rjmp PC+0x20 ; ERDY - rjmp PC+0x20 ; USI_STR - rjmp PC+0x20 ; USI_OVF - - -; --------------------------------------------------------------------------- -; maintenance system starts here. - -.org 0x20 - - rjmp main ; Reset vector +; rjmp start ; Reset vector + rjmp 0xe00 ; Reset vector reti ; EXT_INT0 - rjmp comIsrPcint0 ; PCI0 + reti ; PCI0 reti ; PCI1 reti ; WATCHDOG reti ; ICP1 reti ; OC1A reti ; OC1B reti ; OVF1 - rjmp timerIrqOC0A ; OC0A + reti ; OC0A reti ; OC0B reti ; OVF0 reti ; ACI @@ -155,160 +136,38 @@ reti ; USI_OVF +firmwareType: .dw FW_TYPE +firmwareVersion: .dw FW_VERSION +firmwareStart: .dw 0 ; will be overwritten when flashing + + + +; *************************************************************************** +; main code + + +.org 0xe00 + + +; TODO: +; - wait for a few seconds for an incoming flash message +; - if no such message received within that time period try starting the firmware +main: + rjmp main + + + + ; *************************************************************************** ; includes -.include "utils.asm" -.include "timer.asm" -.include "com.asm" -.include "comproto.asm" +.include "com2_lowlevel.asm" +.include "com2_crc.asm" +.include "com2_packets.asm" +.include "crc8.asm" .include "flash.asm" .include "flashproto.asm" -; *************************************************************************** -; data in SRAM - -.dseg - - -; *************************************************************************** -; data in FLASH - -.cseg - - - - -.include "main.asm" - - - -; --------------------------------------------------------------------------- -; Called on first time run, i.e. on system start. No arguments, no results. - -onSystemStart: - rcall Utils_SetupUid - ldi r16, COM_MAINTENANCE_ADDR ; use fixed address in base system, smaller code - sts comAddress, r16 -; rcall CPRO_StartReclaimAddrProcedure - ret - - - -; --------------------------------------------------------------------------- -; Called every 100ms. Add your routine calls here. No arguments, no results. - -onEvery100ms: - ret - - - -; --------------------------------------------------------------------------- -; Called every second. Add your routine calls here. No arguments, no results. - -onEverySecond: - rcall CPRO_OnEverySecond - ret - - - -; --------------------------------------------------------------------------- -; Called every 5 seconds. Add your routine calls here. No arguments, no results. - -onEvery5s: - ret - - - -; --------------------------------------------------------------------------- -; Called every 10 seconds. Add your routine calls here. No arguments, no results. - -onEvery10s: - ret - - - -; --------------------------------------------------------------------------- -; Called every 30 seconds. Add your routine calls here. No arguments, no results. - -onEvery30s: - ret - - - -; --------------------------------------------------------------------------- -; Called every minute. Add your routine calls here. No arguments, no results. - -onEvery1m: - ret - - - -; --------------------------------------------------------------------------- -; Called every 5 minutes. Add your routine calls here. No arguments, no results. - -onEvery5m: - ret - - - -; --------------------------------------------------------------------------- -; Called every 15 minutes. Add your routine calls here. No arguments, no results. - -onEvery15m: - ret - - - -; --------------------------------------------------------------------------- -; Called every 30 minutes. Add your routine calls here. No arguments, no results. - -onEvery30m: - ret - - - -; --------------------------------------------------------------------------- -; Called every hour. Add your routine calls here. No arguments, no results. - -onEvery1h: - ret - - - -; --------------------------------------------------------------------------- -; Called every 12 hours. Add your routine calls here. No arguments, no results. - -onEvery12h: - ret - - - -; --------------------------------------------------------------------------- -; Called every day. Add your routine calls here. No arguments, no results. - -onEvery1d: - ret - - - -; --------------------------------------------------------------------------- -; onPacketReceived: -; -; Called after a packet was received via COM module. Add your routine calls here. -; -; The packet will be removed from buffer in any case after return from this call. -; IN: -; - Y : pointer to received buffer -; OUT: -; - CFLAG: set if handled, cleared otherwise -; USED: depending on called routines - -onPacketReceived: - rcall CPRO_OnPacketReceived - ret - - diff --git a/avr/att84_temp1.asm b/avr/att84_temp1.asm index 13a409b..d6e3c24 100644 --- a/avr/att84_temp1.asm +++ b/avr/att84_temp1.asm @@ -54,9 +54,8 @@ ; --------------------------------------------------------------------------- ; firmware settings including list of modules used -#define FW_TYPE AQHOME_FW_TYPE_ATT84_TEMP1 -#define FW_MAIN_VERSION_HIGH 0 -#define FW_MAIN_VERSION_LOW 1 +#define FW_TYPE AQHOME_FW_TYPE_ATT84_TEMP1 +#define FW_VERSION 0x0001 #define MODULES_TIMER @@ -175,32 +174,8 @@ ; --------------------------------------------------------------------------- ; Reset and interrupt vectors (will be removed as soon as we can flash data over COM) - rjmp PC+0x500 ; Reset vector - rjmp PC+0x500 ; EXT_INT0 - rjmp PC+0x500 ; PCI0 - rjmp PC+0x500 ; PCI1 - rjmp PC+0x500 ; WATCHDOG - rjmp PC+0x500 ; ICP1 - rjmp PC+0x500 ; OC1A - rjmp PC+0x500 ; OC1B - rjmp PC+0x500 ; OVF1 - rjmp PC+0x500 ; OC0A - rjmp PC+0x500 ; OC0B - rjmp PC+0x500 ; OVF0 - rjmp PC+0x500 ; ACI - rjmp PC+0x500 ; ADCC - rjmp PC+0x500 ; ERDY - rjmp PC+0x500 ; USI_STR - rjmp PC+0x500 ; USI_OVF - - -; --------------------------------------------------------------------------- -; working system starts here. - -.org 0x0500 - - rjmp main ; Reset vector +; rjmp 0xe00 ; Reset vector ; use this for flashed system reti ; EXT_INT0 rjmp com2IsrPcint0 ; PCI0 reti ; PCI1 @@ -219,10 +194,17 @@ reti ; USI_OVF +firmwareType: .dw FW_TYPE +firmwareVersion: .dw FW_VERSION +firmwareStart: + rjmp main + + ; *************************************************************************** ; includes .include "utils.asm" +.include "crc8.asm" #ifdef MODULES_TIMER .include "timer.asm" #endif diff --git a/avr/com2.asm b/avr/com2.asm index a99fbc6..2cb84c0 100644 --- a/avr/com2.asm +++ b/avr/com2.asm @@ -12,33 +12,8 @@ ; *************************************************************************** ; defines -.equ COM2_BUFFER_SIZE = 24 ; CAVE: must change code in COM2_BufferPosToX when changing this! -.equ COM2_BUFFER_NUM = 4 +.include "com2_defs.asm" -.equ COM2_MAXWAIT_US = 100 ; maximum wait time in microseconds when waiting for rising/falling clock -.equ COM2_MAINTENANCE_ADDR = 0xc1 -.equ COM2_CRC_POLYNOMIAL = 0x97 - - -; flags for variable payload enqueue function -.equ COM2_PAYLOAD_FLAGS_SECONDS = 0x01 -.equ COM2_PAYLOAD_FLAGS_UID = 0x02 -.equ COM2_PAYLOAD_FLAGS_RESERVED1 = 0x04 -.equ COM2_PAYLOAD_FLAGS_NUM0 = 0x08 -.equ COM2_PAYLOAD_FLAGS_NUM1 = 0x10 -.equ COM2_PAYLOAD_FLAGS_NUM2 = 0x20 -.equ COM2_PAYLOAD_FLAGS_NUM3 = 0x40 -.equ COM2_PAYLOAD_FLAGS_NUM4 = 0x80 -.equ COM2_PAYLOAD_FLAGS_SHIFT_NUM = 3 - - - -.equ COM2_MSG_OFFS_DESTADDR = 0 -.equ COM2_MSG_OFFS_MSGLEN = 1 -.equ COM2_MSG_OFFS_MSGDATA = 2 -.equ COM2_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA -.equ COM2_MSG_OFFS_SRCADDR = 3 -.equ COM2_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here @@ -317,82 +292,44 @@ com2ReceivePacket: rcall Utils_IncrementCounter16 ; (r18, r19, 22) clc ret - com2ReceivePacket_bufferAvailable: push xl push xh - rcall com2ReceivePacketIntoX + lds r16, com2Address + rcall com2ReceivePacketRaw pop xh pop xl - brcs com2ReceivePacket_received - rcall COM2_BufferDeallocBack - clc - ret -com2ReceivePacket_received: + brcc com2ReceivePacket_error + rcall com2CheckMessageInBuffer ; (R16, R17, R18, R19, R20, X) - brcs com2ReceivePacket_crcOkay - ldi xl, LOW(com2StatsContentError) - ldi xh, HIGH(com2StatsContentError) - rcall Utils_IncrementCounter16 ; (r18, r19, 22) - clc - ret -com2ReceivePacket_crcOkay: + brcc com2ReceivePacket_dataError + + ; everything okay ldi xl, LOW(com2StatsPacketsIn) ldi xh, HIGH(com2StatsPacketsIn) rcall Utils_IncrementCounter16 ; (r18, r19, 22) sec ret - - -; --------------------------------------------------------------------------- -; receive packet into buffer pointed to by X. -; -; OUT: -; - CFLAG: set if okay (packet received), cleared on error -; REGS: r16, r17, x (r18, r19, r20, r21, r22) -com2ReceivePacketIntoX: - ; read destination address - rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22) - brcc com2ReceivePacket_ioError - ; compare destination address (accept "FF" and own address) - cpi r16, 0xff - breq com2ReceivePacket_acceptAddr - lds r17, com2Address - cp r16, r17 - breq com2ReceivePacket_acceptAddr - clc ; not for me - ret -com2ReceivePacket_acceptAddr: - st X+, r16 ; store dest address, lock buffer - ; read msg length - rcall com2ReceiveByte ; read packet length (R16, R17, R20, R21, R22) - brcc com2ReceivePacket_ioError - st X+, r16 - cpi r16, (COM2_BUFFER_SIZE-3) - brcc com2ReceivePacket_contentError ; packet too long - inc r16 ; account for checksum byte - mov r17, r16 -com2ReceivePacket_loop: - push r17 - rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22) - pop r17 - brcc com2ReceivePacket_ioError - st X+, r16 - dec r17 - brne com2ReceivePacket_loop - sec - ret +com2ReceivePacket_error: + cpi r16, COM2_ERROR_IOERROR + breq com2ReceivePacket_ioError + cpi r16, COM2_ERROR_DATAERROR + breq com2ReceivePacket_dataError + rjmp com2ReceivePacket_retnc com2ReceivePacket_ioError: ldi xl, LOW(com2StatsIoError) ldi xh, HIGH(com2StatsIoError) - rjmp com2ReceivePacket_incCounter -com2ReceivePacket_contentError: + rjmp com2ReceivePacket_incCounterDeallocNc +com2ReceivePacket_dataError: ldi xl, LOW(com2StatsContentError) ldi xh, HIGH(com2StatsContentError) - rjmp com2ReceivePacket_incCounter -com2ReceivePacket_incCounter: - rcall Utils_IncrementCounter16 ; (r18, r19, 22) + rjmp com2ReceivePacket_incCounterDeallocNc +com2ReceivePacket_incCounterDeallocNc: + rcall Utils_IncrementCounter16 ; (r18, r19, 22) +com2ReceivePacket_deallocRetnc: + rcall COM2_BufferDeallocBack +com2ReceivePacket_retnc: clc ret @@ -412,85 +349,31 @@ COM2_SendPacket: ldi xh, HIGH(com2SendBuffer) COM2_SendPacketAtX: - in r15, SREG - push r15 - cli - Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration - ; check for ATTN line: busy? - cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable pullup on ATTN - cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as input - nop ; needed to sample current input - sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; ATTN low? - rjmp COM2_SendPacket_lineBusyError ; jump if it is + rcall COM2_SendPacketWithAttn + brcs COM2_SendPacket_okay - cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low - sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output - Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration + cpi r16, COM2_ERROR_BUSY + breq COM2_SendPacket_busyError + cpi r16, COM2_ERROR_COLLISION + breq COM2_SendPacket_collError - adiw xh:xl, COM2_MSG_OFFS_MSGLEN - ld r16, X - sbiw xh:xl, COM2_MSG_OFFS_MSGLEN - inc r16 ; account for dest addr - inc r16 ; account for msglen byte - inc r16 ; account for crc byte - rcall com2SendPacketRaw - - cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line (by setting direction to IN) - brcc COM2_SendPacket_ioError - ; packet successfully sent - ldi xl, LOW(com2StatsPacketsOut) - ldi xh, HIGH(com2StatsPacketsOut) - rcall Utils_IncrementCounter16 ; (r18, r19, r22) - pop r15 - out SREG, r15 - sec - ret - -COM2_SendPacket_ioError: - ldi xl, LOW(com2StatsCollisions) - ldi xh, HIGH(com2StatsCollisions) - rjmp COM2_SendPacket_incCounter - -COM2_SendPacket_lineBusyError: - ldi xl, LOW(com2StatsBusyError) - ldi xh, HIGH(com2StatsBusyError) - rjmp COM2_SendPacket_incCounter - -COM2_SendPacket_incCounter: - rcall Utils_IncrementCounter16 ; (r18, r19, r22) - pop r15 - out SREG, r15 +COM2_SendPacket_busyError: + ldi xl, LOW(com2StatsBusyError) + ldi xh, HIGH(com2StatsBusyError) + rjmp COM2_SendPacket_incCounterRetNc +COM2_SendPacket_collError: + ldi xl, LOW(com2StatsCollisions) + ldi xh, HIGH(com2StatsCollisions) +COM2_SendPacket_incCounterRetNc: + rcall Utils_IncrementCounter16 ; (r18, r19, r22) clc ret - - - -; --------------------------------------------------------------------------- -; send packet over wire, expects ATTN to be low. -; -; IN: -; - r16: number of bytes to send -; - x : ptr to buffer to send -; OUT: -; - nothing -; REGS: r16, r17, x (r21, r22) - -com2SendPacketRaw: - mov r17, r16 -com2SendPacket_loop: - ld r16, X+ - rcall com2SendByte ; send byte (R16, R21, R22) - brcc com2SendPacket_ioError - dec r17 - brne com2SendPacket_loop +COM2_SendPacket_okay: + ldi xl, LOW(com2StatsPacketsOut) + ldi xh, HIGH(com2StatsPacketsOut) + rcall Utils_IncrementCounter16 ; (r18, r19, r22) sec ret -com2SendPacket_ioError: - clc - ret - - - @@ -544,466 +427,10 @@ com2IsrPcint0_end: - -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; Lowlevel IO -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - - -; --------------------------------------------------------------------------- -; 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 - sec - ret - -com2SendByte_error: - clc - ret - - - -; --------------------------------------------------------------------------- -; 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 ; (R17) - 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 - sec - ret -com2ReceiveByte_error: - clc - ret - - - -; --------------------------------------------------------------------------- -; com2WaitForDataLow -; -; Waits up to COM2_MAXWAIT_US loops for low data line -; IN: -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r17, r22 - -com2WaitForDataLow: - ldi r17, COM2_MAXWAIT_US - -com2WaitForDataLow_loop: - sbis COM_PIN_DATA, COM_PINNUM_DATA - rjmp com2WaitForDataLow_done - rcall com2WaitFor1000ns - dec r17 - brne com2WaitForDataLow_loop - clc ; timeout - ret - -com2WaitForDataLow_done: - sec ; ok - ret - - - -; --------------------------------------------------------------------------- -; com2WaitForDataHigh -; -; Waits up to COM2_MAXWAIT_US loops for high data line -; IN: -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r17, r22, X - -com2WaitForDataHigh: - ldi r17, COM2_MAXWAIT_US - -com2WaitForDataHigh_loop: - sbic COM_PIN_DATA, COM_PINNUM_DATA - rjmp com2WaitForDataHigh_done - rcall com2WaitFor1000ns - dec r17 - brne com2WaitForDataHigh_loop - clc ; timeout - ret - -com2WaitForDataHigh_done: - sec ; ok - ret - - - -; --------------------------------------------------------------------------- -; com2WaitForAttnHigh -; -; Waits up to COM2_MAXWAIT_US loops for high ATTN line -; IN: -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r17, r22, X - -com2WaitForAttnHigh: - ldi r17, COM2_MAXWAIT_US - -com2WaitForAttnHigh_loop: - sbic COM_PIN_ATTN, COM_PINNUM_ATTN - rjmp com2WaitForAttnHigh_done - rcall com2WaitFor1000ns - dec r17 - brne com2WaitForAttnHigh_loop - clc ; timeout - ret - -com2WaitForAttnHigh_done: - sec ; ok - ret - - - -; --------------------------------------------------------------------------- -; comWaitFor100ns -; -; Waits for 100 nanoseconds. -; IN: -; OUT: -; - CFLAG: set if okay, clear otherwise -; REGS: r17, r22 - -com2WaitFor1000ns: - Utils_WaitNanoSecs 1000, 7, r22 ; wait for 100 nanosecs (minus 3 cycles for rcall, 4 for ret) - ret - - - - - - - - - -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; CRC code -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - -; --------------------------------------------------------------------------- -; add checksum byte to buffer -; -; IN: -; - X : pointer to packet buffer -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R16, R17, R18, R19, X - -com2CalcAndAddChecksumByte: - adiw xh:xl, COM2_MSG_OFFS_MSGLEN - ld r18, X ; read msg len - sbiw xh:xl, COM2_MSG_OFFS_MSGLEN - inc r18 ; account for dest address - inc r18 ; account for msg len byte - ldi r19, COM2_CRC_POLYNOMIAL - rcall com2CalcCrc8 ; (R16, R17, R18, R20, X) - st X, r16 ; add checksum byte - sec - ret - - - -; --------------------------------------------------------------------------- -; check message in buffer -; -; IN: -; - X : pointer to packet buffer -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R16, R17, R18, R19, R20, X - -com2CheckMessageInBuffer: - adiw xh:xl, COM2_MSG_OFFS_MSGLEN - ld r18, X ; read msg len - sbiw xh:xl, COM2_MSG_OFFS_MSGLEN - inc r18 ; account for dest address - inc r18 ; account for msg len byte - ldi r19, COM2_CRC_POLYNOMIAL - rcall com2CalcCrc8 ; (R16, R17, R18, R20, X) - ld r17, X - cp r16, r17 ; should be equal - brne com2CheckMessageInBuffer_error - sec - ret -com2CheckMessageInBuffer_error: - clc - ret - - - -; --------------------------------------------------------------------------- -; calc crc8 checksum using given polynomial -; -; IN: -; - X : pointer to data to calc crc8 for -; - r18: number of bytes to calc crc8 for -; - r19: polynomial to use (e.g. 0x97: HD=4 up to 119 bytes, e.g. detects all 1 to 3 bit errors) -; OUT: -; - r16: crc8 checksum -; - X : point directly behind the checked area -; MODIFIED REGS: R16, R17, R18, R20, X - -com2CalcCrc8: - ldi r16, 0xff ; crc - -com2CalcCrc8_loop1: - ld r17, X+ ; running var - eor r16, r17 - ldi r20, 8 ; counter for loop2 -com2CalcCrc8_loop2: - lsl r16 - brcc com2CalcCrc8_l1 - eor r16, r19 -com2CalcCrc8_l1: - dec r20 - brne com2CalcCrc8_loop2 - dec r18 - brne com2CalcCrc8_loop1 - ret - - - - - - - - -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -; buffer code -; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ - - - - -; --------------------------------------------------------------------------- -; COM_BufferAlloc -; -; Allocate a transfer buffer. -; IN: -; - nothing -; OUT: -; - CFLAG: set if okay, clear otherwise -; - X: pointer to allocated buffer in SRAM -; MODIFIED REGISTERS: r16, r17, r21 - - -COM2_BufferAlloc: - in r21, SREG ; save global interrupt enable bit from SREG - cli - lds r17, com2RecvBuffersUsed - cpi r17, COM2_BUFFER_NUM - brcc COM2_AllocBuffer_error ; no buffer available - inc r17 ; increment number of buffers used - sts com2RecvBuffersUsed, r17 ; store new value - lds r16, com2MaxBuffersUsed ; calc max buffers used - cp r16, r17 - brcc COM2_AllocBuffer_l0 - sts com2MaxBuffersUsed, r17 -COM2_AllocBuffer_l0: - lds r16, com2RecvBuffersWritePos ; get current write pos - mov r17, r16 ; increment for next call - inc r17 - cpi r17, COM2_BUFFER_NUM ; CF set if COM_BUFFER_NUM > R17 - brcs COM2_AllocBuffer_l1 - clr r17 ; wraparound -COM2_AllocBuffer_l1: - sts com2RecvBuffersWritePos, r17 ; store new writepos for next caller - rcall COM2_BufferPosToX ; (R16, R17) - out SREG, r21 ; restore global interrupt enable bit in SREG - sec - ret -COM2_AllocBuffer_error: - out SREG, r21 - clc - ret - - - -; --------------------------------------------------------------------------- -; COM2_BufferDeallocBack -; -; Release a transfer buffer at the end of the list by decreasing the write pos. -; This releases the last allocated buffer! -; -; IN: -; - nothing -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r16, r17, r21 - -COM2_BufferDeallocBack: - in r21, SREG ; save global interrupt enable bit from SREG - cli - lds r17, com2RecvBuffersUsed - tst r17 - breq COM2_BufferDeallocBack_error ; no buffer allocated, nothing to release - dec r17 - sts com2RecvBuffersUsed, r17 ; store new value - lds r17, com2RecvBuffersWritePos - tst r17 ; 0? - brne COM2_BufferDeallocBack_l1 ; nope go directly decrement r17 - ldi r17, COM2_BUFFER_NUM ; wrap-around -COM2_BufferDeallocBack_l1: - dec r17 - sts com2RecvBuffersWritePos, r17 - out SREG, r21 - sec - ret -COM2_BufferDeallocBack_error: - out SREG, r21 - clc - ret - - - -; --------------------------------------------------------------------------- -; COM2_BufferDeallocFront -; -; Release a transfer buffer by increasing the read pos. -; -; IN: -; - nothing -; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGISTERS: r16, r17, r21 - -COM2_BufferDeallocFront: - in r21, SREG ; save global interrupt enable bit from SREG - cli - lds r17, com2RecvBuffersUsed - tst r17 - breq COM2_BufferDeallocFront_error ; no buffer allocated, nothing to release - dec r17 - sts com2RecvBuffersUsed, r17 ; store new value - lds r17, com2RecvBuffersReadPos - inc r17 - cpi r17, COM2_BUFFER_NUM - brcs COM2_BufferDeallocFront_l1 - clr r17 ; wrap-around -COM2_BufferDeallocFront_l1: - sts com2RecvBuffersReadPos, r17 - out SREG, r21 - sec - ret -COM2_BufferDeallocFront_error: - out SREG, r21 - clc - ret - - - -; --------------------------------------------------------------------------- -; COM2_BufferPosToX -; -; Get a pointer to the SRAM position of the given buffer. -; CAVE: Code must correspond to COM2_BUFFER_SIZE!! -; IN: -; - R16: buffer number (starting with 0) -; OUT: -; - X: pointer to buffer in SRAM -; MODIFIED REGISTERS: R16, R17 - -COM2_BufferPosToX: - ; calculate offset - clr r17 - mov xl, r16 - clr xh - - lsl xl - rol xh ; *2 - - add xl, r16 - adc xh, r17 ; *3 - - lsl xl - rol xh ; *6 - - lsl xl - rol xh ; *12 - - lsl xl - rol xh ; *24 - - ; add base position of buffers - ldi r16, LOW(com2RecvBuffers) - ldi r17, HIGH(com2RecvBuffers) - add xl, r16 - adc xh, r17 - ret - - +.include "com2_packets.asm" +.include "com2_lowlevel.asm" +.include "com2_buffer.asm" +.include "com2_crc.asm" diff --git a/avr/com2_buffer.asm b/avr/com2_buffer.asm new file mode 100644 index 0000000..25b6a1d --- /dev/null +++ b/avr/com2_buffer.asm @@ -0,0 +1,170 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + +; --------------------------------------------------------------------------- +; COM_BufferAlloc +; +; Allocate a transfer buffer. +; IN: +; - nothing +; OUT: +; - CFLAG: set if okay, clear otherwise +; - X: pointer to allocated buffer in SRAM +; MODIFIED REGISTERS: r16, r17, r21 + + +COM2_BufferAlloc: + in r21, SREG ; save global interrupt enable bit from SREG + cli + lds r17, com2RecvBuffersUsed + cpi r17, COM2_BUFFER_NUM + brcc COM2_AllocBuffer_error ; no buffer available + inc r17 ; increment number of buffers used + sts com2RecvBuffersUsed, r17 ; store new value + lds r16, com2MaxBuffersUsed ; calc max buffers used + cp r16, r17 + brcc COM2_AllocBuffer_l0 + sts com2MaxBuffersUsed, r17 +COM2_AllocBuffer_l0: + lds r16, com2RecvBuffersWritePos ; get current write pos + mov r17, r16 ; increment for next call + inc r17 + cpi r17, COM2_BUFFER_NUM ; CF set if COM_BUFFER_NUM > R17 + brcs COM2_AllocBuffer_l1 + clr r17 ; wraparound +COM2_AllocBuffer_l1: + sts com2RecvBuffersWritePos, r17 ; store new writepos for next caller + rcall COM2_BufferPosToX ; (R16, R17) + out SREG, r21 ; restore global interrupt enable bit in SREG + sec + ret +COM2_AllocBuffer_error: + out SREG, r21 + clc + ret + + + +; --------------------------------------------------------------------------- +; COM2_BufferDeallocBack +; +; Release a transfer buffer at the end of the list by decreasing the write pos. +; This releases the last allocated buffer! +; +; IN: +; - nothing +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r16, r17, r21 + +COM2_BufferDeallocBack: + in r21, SREG ; save global interrupt enable bit from SREG + cli + lds r17, com2RecvBuffersUsed + tst r17 + breq COM2_BufferDeallocBack_error ; no buffer allocated, nothing to release + dec r17 + sts com2RecvBuffersUsed, r17 ; store new value + lds r17, com2RecvBuffersWritePos + tst r17 ; 0? + brne COM2_BufferDeallocBack_l1 ; nope go directly decrement r17 + ldi r17, COM2_BUFFER_NUM ; wrap-around +COM2_BufferDeallocBack_l1: + dec r17 + sts com2RecvBuffersWritePos, r17 + out SREG, r21 + sec + ret +COM2_BufferDeallocBack_error: + out SREG, r21 + clc + ret + + + +; --------------------------------------------------------------------------- +; COM2_BufferDeallocFront +; +; Release a transfer buffer by increasing the read pos. +; +; IN: +; - nothing +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r16, r17, r21 + +COM2_BufferDeallocFront: + in r21, SREG ; save global interrupt enable bit from SREG + cli + lds r17, com2RecvBuffersUsed + tst r17 + breq COM2_BufferDeallocFront_error ; no buffer allocated, nothing to release + dec r17 + sts com2RecvBuffersUsed, r17 ; store new value + lds r17, com2RecvBuffersReadPos + inc r17 + cpi r17, COM2_BUFFER_NUM + brcs COM2_BufferDeallocFront_l1 + clr r17 ; wrap-around +COM2_BufferDeallocFront_l1: + sts com2RecvBuffersReadPos, r17 + out SREG, r21 + sec + ret +COM2_BufferDeallocFront_error: + out SREG, r21 + clc + ret + + + +; --------------------------------------------------------------------------- +; COM2_BufferPosToX +; +; Get a pointer to the SRAM position of the given buffer. +; CAVE: Code must correspond to COM2_BUFFER_SIZE!! +; IN: +; - R16: buffer number (starting with 0) +; OUT: +; - X: pointer to buffer in SRAM +; MODIFIED REGISTERS: R16, R17 + +COM2_BufferPosToX: + ; calculate offset + clr r17 + mov xl, r16 + clr xh + + lsl xl + rol xh ; *2 + + add xl, r16 + adc xh, r17 ; *3 + + lsl xl + rol xh ; *6 + + lsl xl + rol xh ; *12 + + lsl xl + rol xh ; *24 + + ; add base position of buffers + ldi r16, LOW(com2RecvBuffers) + ldi r17, HIGH(com2RecvBuffers) + add xl, r16 + adc xh, r17 + ret + + + diff --git a/avr/com2_crc.asm b/avr/com2_crc.asm new file mode 100644 index 0000000..5cd136f --- /dev/null +++ b/avr/com2_crc.asm @@ -0,0 +1,60 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + +; --------------------------------------------------------------------------- +; add checksum byte to buffer +; +; IN: +; - X : pointer to packet buffer +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGS: R16, R17, R18, R19, X + +com2CalcAndAddChecksumByte: + adiw xh:xl, COM2_MSG_OFFS_MSGLEN + ld r18, X ; read msg len + sbiw xh:xl, COM2_MSG_OFFS_MSGLEN + inc r18 ; account for dest address + inc r18 ; account for msg len byte + rcall crc8Calc ; (R16, R17, R18, R20, X) + st X, r16 ; add checksum byte + sec + ret + + + +; --------------------------------------------------------------------------- +; check message in buffer +; +; IN: +; - X : pointer to packet buffer +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGS: R16, R17, R18, R19, R20, X + +com2CheckMessageInBuffer: + adiw xh:xl, COM2_MSG_OFFS_MSGLEN + ld r18, X ; read msg len + sbiw xh:xl, COM2_MSG_OFFS_MSGLEN + inc r18 ; account for dest address + inc r18 ; account for msg len byte + rcall crc8Calc ; (R16, R17, R18, R20, X) + ld r17, X + cp r16, r17 ; should be equal + brne com2CheckMessageInBuffer_error + sec + ret +com2CheckMessageInBuffer_error: + clc + ret + + diff --git a/avr/com2_defs.asm b/avr/com2_defs.asm new file mode 100644 index 0000000..56caa7a --- /dev/null +++ b/avr/com2_defs.asm @@ -0,0 +1,48 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + + +.equ COM2_BUFFER_SIZE = 24 ; CAVE: must change code in COM2_BufferPosToX when changing this! +.equ COM2_BUFFER_NUM = 4 + +.equ COM2_MAXWAIT_US = 100 ; maximum wait time in microseconds when waiting for rising/falling clock +.equ COM2_MAINTENANCE_ADDR = 0xc1 + + +; flags for variable payload enqueue function +.equ COM2_PAYLOAD_FLAGS_SECONDS = 0x01 +.equ COM2_PAYLOAD_FLAGS_UID = 0x02 +.equ COM2_PAYLOAD_FLAGS_RESERVED1 = 0x04 +.equ COM2_PAYLOAD_FLAGS_NUM0 = 0x08 +.equ COM2_PAYLOAD_FLAGS_NUM1 = 0x10 +.equ COM2_PAYLOAD_FLAGS_NUM2 = 0x20 +.equ COM2_PAYLOAD_FLAGS_NUM3 = 0x40 +.equ COM2_PAYLOAD_FLAGS_NUM4 = 0x80 +.equ COM2_PAYLOAD_FLAGS_SHIFT_NUM = 3 + + + +.equ COM2_MSG_OFFS_DESTADDR = 0 +.equ COM2_MSG_OFFS_MSGLEN = 1 +.equ COM2_MSG_OFFS_MSGDATA = 2 +.equ COM2_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA +.equ COM2_MSG_OFFS_SRCADDR = 3 +.equ COM2_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here + + +.equ COM2_ERROR_NOTFORME = 1 ; receiption errors +.equ COM2_ERROR_IOERROR = 2 +.equ COM2_ERROR_DATAERROR = 3 +.equ COM2_ERROR_BUSY = 4 ; send errors +.equ COM2_ERROR_COLLISION = 5 + + diff --git a/avr/com2_lowlevel.asm b/avr/com2_lowlevel.asm new file mode 100644 index 0000000..839bf62 --- /dev/null +++ b/avr/com2_lowlevel.asm @@ -0,0 +1,203 @@ +; *************************************************************************** +; 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 + sec + ret + +com2SendByte_error: + clc + ret + + + +; --------------------------------------------------------------------------- +; 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 ; (R17) + 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 + sec + ret +com2ReceiveByte_error: + clc + ret + + + +; --------------------------------------------------------------------------- +; com2WaitForDataLow +; +; Waits up to COM2_MAXWAIT_US loops for low data line +; IN: +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r17, r22 + +com2WaitForDataLow: + ldi r17, COM2_MAXWAIT_US + +com2WaitForDataLow_loop: + sbis COM_PIN_DATA, COM_PINNUM_DATA + rjmp com2WaitForDataLow_done + rcall com2WaitFor1000ns + dec r17 + brne com2WaitForDataLow_loop + clc ; timeout + ret + +com2WaitForDataLow_done: + sec ; ok + ret + + + +; --------------------------------------------------------------------------- +; com2WaitForDataHigh +; +; Waits up to COM2_MAXWAIT_US loops for high data line +; IN: +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r17, r22, X + +com2WaitForDataHigh: + ldi r17, COM2_MAXWAIT_US + +com2WaitForDataHigh_loop: + sbic COM_PIN_DATA, COM_PINNUM_DATA + rjmp com2WaitForDataHigh_done + rcall com2WaitFor1000ns + dec r17 + brne com2WaitForDataHigh_loop + clc ; timeout + ret + +com2WaitForDataHigh_done: + sec ; ok + ret + + + +; --------------------------------------------------------------------------- +; com2WaitForAttnHigh +; +; Waits up to COM2_MAXWAIT_US loops for high ATTN line +; IN: +; OUT: +; - CFLAG: set if okay, clear otherwise +; MODIFIED REGISTERS: r17, r22, X + +com2WaitForAttnHigh: + ldi r17, COM2_MAXWAIT_US + +com2WaitForAttnHigh_loop: + sbic COM_PIN_ATTN, COM_PINNUM_ATTN + rjmp com2WaitForAttnHigh_done + rcall com2WaitFor1000ns + dec r17 + brne com2WaitForAttnHigh_loop + clc ; timeout + ret + +com2WaitForAttnHigh_done: + sec ; ok + ret + + +; --------------------------------------------------------------------------- +; comWaitFor100ns +; +; Waits for 100 nanoseconds. +; IN: +; OUT: +; - CFLAG: set if okay, clear otherwise +; REGS: r22 + +com2WaitFor1000ns: + Utils_WaitNanoSecs 1000, 7, r22 ; wait for 100 nanosecs (minus 3 cycles for rcall, 4 for ret) + ret + + + + diff --git a/avr/com2_packets.asm b/avr/com2_packets.asm new file mode 100644 index 0000000..282a2d7 --- /dev/null +++ b/avr/com2_packets.asm @@ -0,0 +1,148 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + +; --------------------------------------------------------------------------- +; receive packet into buffer pointed to by X. +; +; IN: +; - R16: COM address to listen to +; - X : buffer to receive to +; OUT: +; - CFLAG: set if okay (packet received), cleared on error +; - R16: error code if CFLAG is cleared +; REGS: r16, r17, X (r18, r19, r20, r21, r22) +com2ReceivePacketRaw: + push r16 + ; read destination address + rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 ; pop from R16 to R17 + brcc com2ReceivePacketRaw_ioError + ; compare destination address (accept "FF" and own address) + cp r16, r17 + breq com2ReceivePacketRaw_acceptAddr + cpi r16, 0xff + breq com2ReceivePacketRaw_acceptAddr + ldi r16, COM2_ERROR_NOTFORME + clc ; not for me + ret +com2ReceivePacketRaw_acceptAddr: + st X+, r16 ; store dest address, lock buffer + ; read msg length + rcall com2ReceiveByte ; read packet length (R16, R17, R20, R21, R22) + brcc com2ReceivePacketRaw_ioError + st X+, r16 + cpi r16, (COM2_BUFFER_SIZE-3) + brcc com2ReceivePacketRaw_contentError ; packet too long + inc r16 ; account for checksum byte + mov r17, r16 +com2ReceivePacketRaw_loop: + push r17 + rcall com2ReceiveByte ; read byte (R16, R17, R20, R21, R22) + pop r17 + brcc com2ReceivePacketRaw_ioError + st X+, r16 + dec r17 + brne com2ReceivePacketRaw_loop + sec + ret +com2ReceivePacketRaw_ioError: + ldi r16, COM2_ERROR_IOERROR + rjmp com2ReceivePacketRaw_error +com2ReceivePacketRaw_contentError: + ldi r16, COM2_ERROR_DATAERROR +com2ReceivePacketRaw_error: + clc + ret + + + +; --------------------------------------------------------------------------- +; send packet over wire, handle ATTN line. +; +; IN: +; - x : ptr to buffer to send +; OUT: +; - CFLAGS: set if okay, cleared otherwise (errorcode in R16) +; REGS: R15, R16, R22 (R17, R21, X) + +COM2_SendPacketWithAttn: + in r15, SREG + push r15 + cli + Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration + ; check for ATTN line: busy? + cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; disable pullup on ATTN + cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as input + nop ; needed to sample current input + sbis COM_PIN_ATTN, COM_PINNUM_ATTN ; ATTN low? + rjmp COM2_SendPacketWithAttn_lineBusyError ; jump if it is + + cbi COM_PORT_ATTN, COM_PINNUM_ATTN ; set ATTN low + sbi COM_DDR_ATTN, COM_PINNUM_ATTN ; set ATTN as output + Utils_WaitNanoSecs COM_BIT_LENGTH, 0, r22 ; wait for one bit duration + + adiw xh:xl, COM2_MSG_OFFS_MSGLEN + ld r16, X + sbiw xh:xl, COM2_MSG_OFFS_MSGLEN + inc r16 ; account for dest addr + inc r16 ; account for msglen byte + inc r16 ; account for crc byte + rcall com2SendPacketRaw ; (r16, r17, r21, r22, X) + + cbi COM_DDR_ATTN, COM_PINNUM_ATTN ; release ATTN line (by setting direction to IN) + brcc COM2_SendPacketWithAttn_ioError + ; packet successfully sent + pop r15 + out SREG, r15 + sec + ret + +COM2_SendPacketWithAttn_ioError: + ldi r16,COM2_ERROR_COLLISION + rjmp COM2_SendPacketWithAttn_retNc + +COM2_SendPacketWithAttn_lineBusyError: + ldi r16,COM2_ERROR_BUSY +COM2_SendPacketWithAttn_retNc: + pop r15 + out SREG, r15 + clc + ret + + + +; --------------------------------------------------------------------------- +; send packet over wire, expects ATTN to be low. +; +; IN: +; - r16: number of bytes to send +; - x : ptr to buffer to send +; OUT: +; - nothing +; REGS: r16, r17, x (r21, r22) + +com2SendPacketRaw: + mov r17, r16 +com2SendPacket_loop: + ld r16, X+ + rcall com2SendByte ; send byte (R16, R21, R22) + brcc com2SendPacket_ioError + dec r17 + brne com2SendPacket_loop + sec + ret +com2SendPacket_ioError: + clc + ret + + + diff --git a/avr/comproto.asm b/avr/comproto.asm index 8af1c06..c47f6e8 100644 --- a/avr/comproto.asm +++ b/avr/comproto.asm @@ -15,56 +15,8 @@ ; *************************************************************************** ; defines +.include "comproto_defs.asm" -.equ CPRO_CMD_PING = 10 -.equ CPRO_CMD_PONG = 11 -.equ CPRO_CMD_COMSENDSTATS = 20 -.equ CPRO_CMD_COMRECVSTATS = 21 -.equ CPRO_CMD_TWIBUSMEMBER = 30 -.equ CPRO_CMD_DEBUG = 40 -.equ CPRO_CMD_VALUE = 51 ; was 50 when sending timestamp instead of uid -.equ CPRO_CMD_NEED_ADDRESS = 60 -.equ CPRO_CMD_HAVE_ADDRESS = 61 -.equ CPRO_CMD_CLAIM_ADDRESS = 62 -.equ CPRO_CMD_DENY_ADDRESS = 63 -.equ CPRO_CMD_ADDRESS_RANGE = 64 - -.equ CPRO_CMD_FLASH_START = 70 -.equ CPRO_CMD_FLASH_END = 71 -.equ CPRO_CMD_FLASH_ADDR = 72 -.equ CPRO_CMD_FLASH_DATA = 73 -.equ CPRO_CMD_FLASH_RSP = 74 - -.equ CPRO_CMD_DEVICE = 80 -.equ CPRO_CMD_MEMSTATS = 81 -.equ CPRO_CMD_SYSSTATS = 82 - - -.equ CPRO_PACKET_HAVEADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 -.equ CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 -.equ CPRO_PACKET_DENYADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 - - -.equ CPRO_WAITTIME_INITIAL = 10 -.equ CPRO_WAITTIME_GETADDR = 130 -.equ CPRO_WAITTIME_CLAIMADDR = 17 -.equ CPRO_WAITTIME_RECLAIMADDR = 10 - - -; current mode of operation -.equ CPRO_MODE_NOADDRESS = 0x00 ; no address, yet -.equ CPRO_MODE_NORMAL = 0x01 ; normal operation -.equ CPRO_MODE_SEND_NEED_ADDR = 0x02 ; wait to send need address -.equ CPRO_MODE_GETADDRSTARTED = 0x03 ; waiting for HAVE_ADDRESS and ADDRESS_RANGE packets to arrive -.equ CPRO_MODE_SEND_CLAIM_ADDR1 = 0x04 ; send CLAIM_ADDRESS as part of reclaiming procedure -.equ CPRO_MODE_CLAIMING_ADDR1 = 0x05 ; CLAIM_ADDRESS sent, waiting for HAVE_ADDRESS packet to reject the claim -.equ CPRO_MODE_CLAIMING_ADDR2 = 0x06 ; CLAIM_ADDRESS sent, 2nd try -.equ CPRO_MODE_CLAIMING_ADDR3 = 0x07 ; CLAIM_ADDRESS sent, 3rd try -.equ CPRO_MODE_SENDING_HAVE_ADDR = 0x08 ; waiting for our turn to send HAVE_ADDRESS packet -.equ CPRO_MODE_SEND_RECLAIM_ADDR = 0x09 ; send CLAIM_ADDRESS as part of reclaiming procedure -.equ CPRO_MODE_RECLAIMING_ADDR = 0x0a ; CLAIM_ADDRESS with the previously used address sent after bootup -.equ CPRO_MODE_SEND_DENY_ADDR = 0x0b ; someone claimed our address, send a DENY_ADDR message -.equ CPRO_MODE_NEXT_FREE = 0x0c ; next free mode ; *************************************************************************** diff --git a/avr/comproto_defs.asm b/avr/comproto_defs.asm new file mode 100644 index 0000000..75c2d4f --- /dev/null +++ b/avr/comproto_defs.asm @@ -0,0 +1,71 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + + + +; *************************************************************************** +; defines + + +.equ CPRO_CMD_PING = 10 +.equ CPRO_CMD_PONG = 11 +.equ CPRO_CMD_COMSENDSTATS = 20 +.equ CPRO_CMD_COMRECVSTATS = 21 +.equ CPRO_CMD_TWIBUSMEMBER = 30 +.equ CPRO_CMD_DEBUG = 40 +.equ CPRO_CMD_VALUE = 51 ; was 50 when sending timestamp instead of uid +.equ CPRO_CMD_NEED_ADDRESS = 60 +.equ CPRO_CMD_HAVE_ADDRESS = 61 +.equ CPRO_CMD_CLAIM_ADDRESS = 62 +.equ CPRO_CMD_DENY_ADDRESS = 63 +.equ CPRO_CMD_ADDRESS_RANGE = 64 + +.equ CPRO_CMD_FLASH_START = 70 +.equ CPRO_CMD_FLASH_END = 71 +.equ CPRO_CMD_FLASH_READY = 72 +.equ CPRO_CMD_FLASH_DATA = 73 +.equ CPRO_CMD_FLASH_RSP = 74 + +.equ CPRO_CMD_DEVICE = 80 +.equ CPRO_CMD_MEMSTATS = 81 +.equ CPRO_CMD_SYSSTATS = 82 + + +.equ CPRO_PACKET_HAVEADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 +.equ CPRO_PACKET_CLAIMADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 +.equ CPRO_PACKET_DENYADDR_OFFS_ADDRESS = COM2_MSG_OFFS_PAYLOAD+4 + + +.equ CPRO_WAITTIME_INITIAL = 10 +.equ CPRO_WAITTIME_GETADDR = 130 +.equ CPRO_WAITTIME_CLAIMADDR = 17 +.equ CPRO_WAITTIME_RECLAIMADDR = 10 + + +; current mode of operation +.equ CPRO_MODE_NOADDRESS = 0x00 ; no address, yet +.equ CPRO_MODE_NORMAL = 0x01 ; normal operation +.equ CPRO_MODE_SEND_NEED_ADDR = 0x02 ; wait to send need address +.equ CPRO_MODE_GETADDRSTARTED = 0x03 ; waiting for HAVE_ADDRESS and ADDRESS_RANGE packets to arrive +.equ CPRO_MODE_SEND_CLAIM_ADDR1 = 0x04 ; send CLAIM_ADDRESS as part of reclaiming procedure +.equ CPRO_MODE_CLAIMING_ADDR1 = 0x05 ; CLAIM_ADDRESS sent, waiting for HAVE_ADDRESS packet to reject the claim +.equ CPRO_MODE_CLAIMING_ADDR2 = 0x06 ; CLAIM_ADDRESS sent, 2nd try +.equ CPRO_MODE_CLAIMING_ADDR3 = 0x07 ; CLAIM_ADDRESS sent, 3rd try +.equ CPRO_MODE_SENDING_HAVE_ADDR = 0x08 ; waiting for our turn to send HAVE_ADDRESS packet +.equ CPRO_MODE_SEND_RECLAIM_ADDR = 0x09 ; send CLAIM_ADDRESS as part of reclaiming procedure +.equ CPRO_MODE_RECLAIMING_ADDR = 0x0a ; CLAIM_ADDRESS with the previously used address sent after bootup +.equ CPRO_MODE_SEND_DENY_ADDR = 0x0b ; someone claimed our address, send a DENY_ADDR message +.equ CPRO_MODE_NEXT_FREE = 0x0c ; next free mode + + + + diff --git a/avr/crc8.asm b/avr/crc8.asm new file mode 100644 index 0000000..b48f930 --- /dev/null +++ b/avr/crc8.asm @@ -0,0 +1,53 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + +; *************************************************************************** +; defines + + +.equ CRC8_POLYNOMIAL = 0x97 ; HD=4 up to 119 bytes, e.g. detects all 1 to 3 bit errors + + + +.cseg + + +; --------------------------------------------------------------------------- +; calc crc8 checksum using given polynomial +; +; IN: +; - X : pointer to data to calc crc8 for +; - r18: number of bytes to calc crc8 for +; OUT: +; - r16: crc8 checksum +; - X : point directly behind the checked area +; MODIFIED REGS: R16, R17, R18, R19, R20, X + +crc8Calc: + ldi r16, 0xff ; crc + ldi r19, CRC8_POLYNOMIAL + +crc8Calc_loop1: + ld r17, X+ ; running var + eor r16, r17 + ldi r20, 8 ; counter for loop2 +crc8Calc_loop2: + lsl r16 + brcc crc8Calc_l1 + eor r16, r19 +crc8Calc_l1: + dec r20 + brne crc8Calc_loop2 + dec r18 + brne crc8Calc_loop1 + ret + + + diff --git a/avr/flash.asm b/avr/flash.asm index cac5699..ed5516b 100644 --- a/avr/flash.asm +++ b/avr/flash.asm @@ -174,6 +174,63 @@ wait: ; wait for possibly previous SPM to complete ret + +; --------------------------------------------------------------------------- +; flashReadEepromIncr +; +; Read a byte from EEPROM (see example in ATtiny24/44/84 manual p.19). +; +; IN: +; - X: EEPROM Address to read from +; OUT: +; - R16: byte read +; - X: EEPROM Address incremented +; MODIFIED REGISTERS: R16 + +flashReadEepromIncr: + sbic EECR, EEPE ; wait for previous write to complete (if any) + rjmp flashReadEepromIncr + out EEARH, xh ; set EEPROM address + out EEARL, xl + sbi EECR, EERE ; start EEPROM read by writing EERE + in r16, EEDR ; read data from data register + adiw xh:xl, 1 + ret + + + +; --------------------------------------------------------------------------- +; flashReadUid +; +; Read UID from EEPROM. +; +; IN: +; OUT: +; - R18:R19:R20:R21: UID +; REGS: R16, X + +flashReadUid: + in r15, SREG + push r15 + cli + ldi xl, LOW(EEPROM_OFFS_UUID) + ldi xh, HIGH(EEPROM_OFFS_UUID) + rcall flashReadEepromIncr ; (R16) + mov r18, r16 + rcall flashReadEepromIncr ; (R16) + mov r19, r16 + rcall flashReadEepromIncr ; (R16) + mov r20, r16 + rcall flashReadEepromIncr ; (R16) + mov r21, r16 + pop r15 + out SREG, r15 + ret + + + + + FLASH_END: .equ MODULE_SIZE_FLASH = FLASH_END-FLASH_BEGIN diff --git a/avr/flashproto.asm b/avr/flashproto.asm index c0c4240..cf36f8c 100644 --- a/avr/flashproto.asm +++ b/avr/flashproto.asm @@ -9,21 +9,24 @@ +.equ FLASH_ERROR_NONE = 0 +.equ FLASH_ERROR_BAD_MSGNUM = 1 +.equ FLASH_ERROR_BAD_ADDR = 2 + +.equ FLASH_CMD_FLASH_RSP = 74 +.equ FLASH_MSG_OFFS_DESTADDR = 0 +.equ FLASH_MSG_OFFS_MSGLEN = 1 +.equ FLASH_MSG_OFFS_MSGDATA = 2 +.equ FLASH_MSG_OFFS_CMD = 2 ; first at COM2_MSG_OFFS_MSGDATA +.equ FLASH_MSG_OFFS_SRCADDR = 3 +.equ FLASH_MSG_OFFS_PAYLOAD = 4 ; payload for the cmd follows here -.equ CPRO_PACKET_FLASH_START_OFFS_MSGNUM = COM_MSG_OFFS_PAYLOAD+0 ; 2 bytes -.equ CPRO_PACKET_FLASH_START_OFFS_ADDR = COM_MSG_OFFS_PAYLOAD+2 ; 2 bytes -.equ CPRO_PACKET_FLASH_ADDR_OFFS_MSGNUM = COM_MSG_OFFS_PAYLOAD+0 ; 2 bytes -.equ CPRO_PACKET_FLASH_ADDR_OFFS_ADDR = COM_MSG_OFFS_PAYLOAD+2 ; 2 bytes +.equ FLASH_PACKET_DATA_OFFS_ADDR = FLASH_MSG_OFFS_PAYLOAD+0 ; 2 bytes +.equ FLASH_PACKET_DATA_OFFS_DATA = FLASH_MSG_OFFS_PAYLOAD+2 ; n bytes -.equ CPRO_PACKET_FLASH_DATA_OFFS_MSGNUM = COM_MSG_OFFS_PAYLOAD+0 ; 2 bytes -.equ CPRO_PACKET_FLASH_DATA_OFFS_DATA = COM_MSG_OFFS_PAYLOAD+2 ; 2 bytes - -.equ CPRO_FLASH_ERROR_NONE = 0 -.equ CPRO_FLASH_ERROR_BAD_MSGNUM = 1 -.equ CPRO_FLASH_ERROR_BAD_ADDR = 2 @@ -34,8 +37,9 @@ .dseg flashDataBegin: - flashCurrentAddress: .byte 2 - flashLastReceivedMsg: .byte 2 + flashUid: .byte 4 + flashSendBuffer: .byte 64 + flashRecvBuffer: .byte 64 flashDataEnd: @@ -49,104 +53,371 @@ flashDataEnd: +FLASH_PROTO_BEGIN: + + + + +bootLoader: + cli ; disable interrupts throughout the whole process + + ; setup stack + .ifdef SPH ; if SPH is defined + ldi r16, High(RAMEND) + out SPH, r16 ; init MSB stack pointer + .endif + ldi r16, Low(RAMEND) + out SPL, r16 ; init LSB stack pointer + + sbi DDRA, PORTA3 ; out +; sbi PINA, PORTA3 ; toggle + cbi PORTA, PORTA3 ; on +; sbi PORTA, PORTA3 ; off + rcall flashReadUid + sts flashUid, r18 + sts flashUid+1, r19 + sts flashUid+2, r20 + sts flashUid+3, r21 + + ; send flash ready message + ldi xl, LOW(flashSendBuffer) + ldi xh, HIGH(flashSendBuffer) + rcall flashWriteFlashReady + rcall flashSendPacketUntilSuccess + + ; wait up to 10s for incoming FLASH_START message + ldi r16, CPRO_CMD_FLASH_START + ldi r17, 100 ; 100*100ms=10s + rcall flashWaitForSpecificMessageWithLed + brcc bootLoader_startFirmware + ; either FLASH_START or FLASH_END received + cpi r16, CPRO_CMD_FLASH_START ; not FLASH_START, no flashing requested + brne bootLoader_startFirmware + ; receive and flash new firmware + + ; try to start firmware +bootLoader_startFirmware: + lds r20, firmwareStart + lds r21, firmwareStart+1 + mov r16, r20 + or r16, r21 + breq bootLoader ; restart boot loader + ; jmp via stack + push r20 + push r21 + ret + + ; --------------------------------------------------------------------------- -; Enqueue a FLASHDATA_ACK packet. +; wait for a specific message to arrive within given time, flashing LED ; ; IN: -; - R16: destination address -; - R17: response code (0 if ok, error code otherwise) -; - R19:R18: msg num +; - R16: message type to receive +; - R17: wait time in 100ms (1=100ms, 2=200ms etc.) ; OUT: -; - CFLAG: set if okay, clear otherwise -; MODIFIED REGS: R6, R7, R8, R9, R10, R11, R12, R16, R17, X, Y (R3, R4, R15, R16, R17, R18, R19, R20, R21) +; - CFLAG: set if msg received (either expected msg or FLASH_END), cleared otherwise +; - R16: message type received (if CFLAG set) +; REGS: R2, R16, R17 (R1, R24, R25, X) -CPRO_EnqueueFlashRsp: - mov r6, r16 - mov r7, r17 - mov r8, r18 - mov r9, r19 +flashWaitForSpecificMessageWithLed: + mov r2, r16 + sbi PORTA, PORTA3 ; LED off - rcall COM_AllocBufferAndGetXY ; (r16, r17, r21) - brcc CPRO_EnqueueFlashRsp_error - - push xh - push xl - mov r16, r6 - ldi r17, CPRO_PAYLOAD_FLAGS_SECONDS | (3< (255 * 3 + 2)) - .error "MACRO Utils_WaitNanoSecs - too many cycles to burn" - .else - .if (cycles > 6) - .set loop_cycles = (cycles / 3) - ldi @2,loop_cycles - dec @2 - brne pc-1 - .set cycles = (cycles - (loop_cycles * 3)) - .endif - .if (cycles > 0) - .if (cycles & 4) - rjmp pc+1 - rjmp pc+1 - .endif - .if (cycles & 2) - rjmp pc+1 - .endif - .if (cycles & 1) - nop - .endif - .endif - .endif -.endmacro +.include "utils_wait.asm" diff --git a/avr/utils_wait.asm b/avr/utils_wait.asm new file mode 100644 index 0000000..0d664e7 --- /dev/null +++ b/avr/utils_wait.asm @@ -0,0 +1,58 @@ +; *************************************************************************** +; 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. * +; *************************************************************************** + + + + + +; *************************************************************************** +; macros + + + +; --------------------------------------------------------------------------- +; Utils_WaitNanoSecs waittime_in_ns , cyles_already_used , waitcount_register +; +; cycles already used will be subtracted from the delay +; the waittime resolution is 1 cycle (delay from exact to +1 cycle) +; the maximum delay at 20MHz (50ns/clock) is 38350ns +; waitcount register must specify an immediate register +; taken from https://www.mikrocontroller.net/articles/AVR_Assembler_Makros#Verz%C3%B6gerung_um_X_Nanosekunden +; +.set Osc_Hz = clock ; 1 MHz +.set cycle_time_ns = (1000000000 / Osc_Hz) ; clock duration +.macro Utils_WaitNanoSecs + .set cycles = ((@0 + cycle_time_ns - 1) / cycle_time_ns - @1) + .if (cycles > (255 * 3 + 2)) + .error "MACRO Utils_WaitNanoSecs - too many cycles to burn" + .else + .if (cycles > 6) + .set loop_cycles = (cycles / 3) + ldi @2,loop_cycles + dec @2 + brne pc-1 + .set cycles = (cycles - (loop_cycles * 3)) + .endif + .if (cycles > 0) + .if (cycles & 4) + rjmp pc+1 + rjmp pc+1 + .endif + .if (cycles & 2) + rjmp pc+1 + .endif + .if (cycles & 1) + nop + .endif + .endif + .endif +.endmacro + + +